blob: 87ba64f54c16d77b3b86c5038982bc92e402c49a [file] [log] [blame]
// Copyright 2013 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 "content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
#include "content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h"
#include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/socket_permission_request.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/c/private/ppb_net_address_private.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/error_conversion.h"
#include "ppapi/host/ppapi_host.h"
#include "ppapi/host/resource_host.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/api_id.h"
#include "ppapi/shared_impl/ppb_tcp_socket_shared.h"
#include "ppapi/shared_impl/private/net_address_private_impl.h"
using ppapi::NetAddressPrivateImpl;
using ppapi::host::NetErrorToPepperError;
namespace {
size_t g_num_instances = 0;
} // namespace
namespace content {
PepperTCPServerSocketMessageFilter::PepperTCPServerSocketMessageFilter(
ContentBrowserPepperHostFactory* factory,
BrowserPpapiHostImpl* host,
PP_Instance instance,
bool private_api)
: ppapi_host_(host->GetPpapiHost()),
factory_(factory),
instance_(instance),
state_(STATE_BEFORE_LISTENING),
external_plugin_(host->external_plugin()),
private_api_(private_api),
render_process_id_(0),
render_frame_id_(0) {
++g_num_instances;
DCHECK(factory_);
DCHECK(ppapi_host_);
if (!host->GetRenderFrameIDsForInstance(
instance, &render_process_id_, &render_frame_id_)) {
NOTREACHED();
}
}
PepperTCPServerSocketMessageFilter::~PepperTCPServerSocketMessageFilter() {
--g_num_instances;
}
// static
size_t PepperTCPServerSocketMessageFilter::GetNumInstances() {
return g_num_instances;
}
scoped_refptr<base::TaskRunner>
PepperTCPServerSocketMessageFilter::OverrideTaskRunnerForMessage(
const IPC::Message& message) {
switch (message.type()) {
case PpapiHostMsg_TCPServerSocket_Listen::ID:
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
case PpapiHostMsg_TCPServerSocket_Accept::ID:
case PpapiHostMsg_TCPServerSocket_StopListening::ID:
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
}
return NULL;
}
int32_t PepperTCPServerSocketMessageFilter::OnResourceMessageReceived(
const IPC::Message& msg,
ppapi::host::HostMessageContext* context) {
PPAPI_BEGIN_MESSAGE_MAP(PepperTCPServerSocketMessageFilter, msg)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_TCPServerSocket_Listen,
OnMsgListen)
PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(PpapiHostMsg_TCPServerSocket_Accept,
OnMsgAccept)
PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
PpapiHostMsg_TCPServerSocket_StopListening, OnMsgStopListening)
PPAPI_END_MESSAGE_MAP()
return PP_ERROR_FAILED;
}
int32_t PepperTCPServerSocketMessageFilter::OnMsgListen(
const ppapi::host::HostMessageContext* context,
const PP_NetAddress_Private& addr,
int32_t backlog) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
DCHECK(context);
SocketPermissionRequest request =
pepper_socket_utils::CreateSocketPermissionRequest(
content::SocketPermissionRequest::TCP_LISTEN, addr);
if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_,
private_api_,
&request,
render_process_id_,
render_frame_id_)) {
return PP_ERROR_NOACCESS;
}
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&PepperTCPServerSocketMessageFilter::DoListen,
this,
context->MakeReplyMessageContext(),
addr,
backlog));
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperTCPServerSocketMessageFilter::OnMsgAccept(
const ppapi::host::HostMessageContext* context) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(context);
if (state_ != STATE_LISTENING)
return PP_ERROR_FAILED;
state_ = STATE_ACCEPT_IN_PROGRESS;
ppapi::host::ReplyMessageContext reply_context(
context->MakeReplyMessageContext());
int net_result = socket_->Accept(
&accepted_socket_,
&accepted_address_,
base::Bind(&PepperTCPServerSocketMessageFilter::OnAcceptCompleted,
base::Unretained(this),
reply_context));
if (net_result != net::ERR_IO_PENDING)
OnAcceptCompleted(reply_context, net_result);
return PP_OK_COMPLETIONPENDING;
}
int32_t PepperTCPServerSocketMessageFilter::OnMsgStopListening(
const ppapi::host::HostMessageContext* context) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(context);
state_ = STATE_CLOSED;
socket_.reset();
return PP_OK;
}
void PepperTCPServerSocketMessageFilter::DoListen(
const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& addr,
int32_t backlog) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
net::IPAddressNumber address;
int port;
if (state_ != STATE_BEFORE_LISTENING ||
!NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) {
SendListenError(context, PP_ERROR_FAILED);
state_ = STATE_CLOSED;
return;
}
state_ = STATE_LISTEN_IN_PROGRESS;
socket_.reset(new net::TCPSocket(NULL, net::NetLog::Source()));
int net_result = net::OK;
do {
net::IPEndPoint ip_end_point(address, port);
net_result = socket_->Open(ip_end_point.GetFamily());
if (net_result != net::OK)
break;
net_result = socket_->SetDefaultOptionsForServer();
if (net_result != net::OK)
break;
net_result = socket_->Bind(ip_end_point);
if (net_result != net::OK)
break;
net_result = socket_->Listen(backlog);
} while (false);
if (net_result != net::ERR_IO_PENDING)
OnListenCompleted(context, net_result);
}
void PepperTCPServerSocketMessageFilter::OnListenCompleted(
const ppapi::host::ReplyMessageContext& context,
int net_result) {
if (state_ != STATE_LISTEN_IN_PROGRESS) {
SendListenError(context, PP_ERROR_FAILED);
state_ = STATE_CLOSED;
return;
}
if (net_result != net::OK) {
SendListenError(context, NetErrorToPepperError(net_result));
state_ = STATE_BEFORE_LISTENING;
return;
}
DCHECK(socket_.get());
net::IPEndPoint end_point;
PP_NetAddress_Private addr;
int32_t pp_result =
NetErrorToPepperError(socket_->GetLocalAddress(&end_point));
if (pp_result != PP_OK) {
SendListenError(context, pp_result);
state_ = STATE_BEFORE_LISTENING;
return;
}
if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
end_point.address(), end_point.port(), &addr)) {
SendListenError(context, PP_ERROR_FAILED);
state_ = STATE_BEFORE_LISTENING;
return;
}
SendListenReply(context, PP_OK, addr);
state_ = STATE_LISTENING;
}
void PepperTCPServerSocketMessageFilter::OnAcceptCompleted(
const ppapi::host::ReplyMessageContext& context,
int net_result) {
if (state_ != STATE_ACCEPT_IN_PROGRESS) {
SendAcceptError(context, PP_ERROR_FAILED);
state_ = STATE_CLOSED;
return;
}
state_ = STATE_LISTENING;
if (net_result != net::OK) {
SendAcceptError(context, NetErrorToPepperError(net_result));
return;
}
DCHECK(accepted_socket_.get());
net::IPEndPoint ip_end_point_local;
PP_NetAddress_Private local_addr = NetAddressPrivateImpl::kInvalidNetAddress;
PP_NetAddress_Private remote_addr = NetAddressPrivateImpl::kInvalidNetAddress;
int32_t pp_result = NetErrorToPepperError(
accepted_socket_->GetLocalAddress(&ip_end_point_local));
if (pp_result != PP_OK) {
SendAcceptError(context, pp_result);
return;
}
if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
ip_end_point_local.address(),
ip_end_point_local.port(),
&local_addr) ||
!NetAddressPrivateImpl::IPEndPointToNetAddress(
accepted_address_.address(),
accepted_address_.port(),
&remote_addr)) {
SendAcceptError(context, PP_ERROR_FAILED);
return;
}
scoped_ptr<ppapi::host::ResourceHost> host =
factory_->CreateAcceptedTCPSocket(instance_,
ppapi::TCP_SOCKET_VERSION_PRIVATE,
accepted_socket_.Pass());
if (!host) {
SendAcceptError(context, PP_ERROR_NOSPACE);
return;
}
int pending_resource_id = ppapi_host_->AddPendingResourceHost(host.Pass());
if (pending_resource_id) {
SendAcceptReply(
context, PP_OK, pending_resource_id, local_addr, remote_addr);
} else {
SendAcceptError(context, PP_ERROR_NOSPACE);
}
}
void PepperTCPServerSocketMessageFilter::SendListenReply(
const ppapi::host::ReplyMessageContext& context,
int32_t pp_result,
const PP_NetAddress_Private& local_addr) {
ppapi::host::ReplyMessageContext reply_context(context);
reply_context.params.set_result(pp_result);
SendReply(reply_context,
PpapiPluginMsg_TCPServerSocket_ListenReply(local_addr));
}
void PepperTCPServerSocketMessageFilter::SendListenError(
const ppapi::host::ReplyMessageContext& context,
int32_t pp_result) {
SendListenReply(
context, pp_result, NetAddressPrivateImpl::kInvalidNetAddress);
}
void PepperTCPServerSocketMessageFilter::SendAcceptReply(
const ppapi::host::ReplyMessageContext& context,
int32_t pp_result,
int pending_resource_id,
const PP_NetAddress_Private& local_addr,
const PP_NetAddress_Private& remote_addr) {
ppapi::host::ReplyMessageContext reply_context(context);
reply_context.params.set_result(pp_result);
SendReply(reply_context,
PpapiPluginMsg_TCPServerSocket_AcceptReply(
pending_resource_id, local_addr, remote_addr));
}
void PepperTCPServerSocketMessageFilter::SendAcceptError(
const ppapi::host::ReplyMessageContext& context,
int32_t pp_result) {
SendAcceptReply(context,
pp_result,
0,
NetAddressPrivateImpl::kInvalidNetAddress,
NetAddressPrivateImpl::kInvalidNetAddress);
}
} // namespace content