Chromium Code Reviews| Index: content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc |
| diff --git a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..321b01b1cb0a8b1413b77bc9ca739a3271ac7d22 |
| --- /dev/null |
| +++ b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc |
| @@ -0,0 +1,300 @@ |
| +// 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/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 "net/socket/tcp_client_socket.h" |
| +#include "net/socket/tcp_server_socket.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/proxy/ppapi_messages.h" |
| +#include "ppapi/shared_impl/api_id.h" |
| +#include "ppapi/shared_impl/private/net_address_private_impl.h" |
| + |
| +using ppapi::NetAddressPrivateImpl; |
| +using ppapi::host::NetErrorToPepperError; |
| + |
| +namespace content { |
| + |
| +PepperTCPServerSocketMessageFilter::PepperTCPServerSocketMessageFilter( |
| + BrowserPpapiHostImpl* host, |
| + PP_Instance instance, |
| + bool private_api, |
| + const scoped_refptr<PepperMessageFilter>& pepper_message_filter) |
| + : state_(STATE_BEFORE_LISTENING), |
| + external_plugin_(host->external_plugin()), |
| + private_api_(private_api), |
| + pepper_message_filter_(pepper_message_filter), |
| + render_process_id_(0), |
| + render_view_id_(0) { |
| + DCHECK(host); |
| + if (!host->GetRenderViewIDsForInstance(instance, |
| + &render_process_id_, |
| + &render_view_id_)) { |
| + NOTREACHED(); |
| + } |
| +} |
| + |
| +PepperTCPServerSocketMessageFilter::~PepperTCPServerSocketMessageFilter() { |
| +} |
| + |
| +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) { |
| + IPC_BEGIN_MESSAGE_MAP(PepperTCPServerSocketMessageFilter, msg) |
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL( |
| + PpapiHostMsg_TCPServerSocket_Listen, OnMsgListen) |
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL( |
| + PpapiHostMsg_TCPServerSocket_Accept, OnMsgAccept) |
| + PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( |
| + PpapiHostMsg_TCPServerSocket_StopListening, OnMsgStopListening) |
| + IPC_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(BrowserThread::CurrentlyOn(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_view_id_)) { |
| + return PP_ERROR_NOACCESS; |
| + } |
| + |
| + BrowserThread::PostTask( |
| + BrowserThread::IO, FROM_HERE, |
| + base::Bind(&PepperTCPServerSocketMessageFilter::DoListen, |
| + base::Unretained(this), |
|
yzshen1
2013/07/19 23:51:58
You need to use |this| instead of |base::Unretaine
ygorshenin1
2013/07/29 14:03:57
Done.
|
| + context->MakeReplyMessageContext(), addr, backlog)); |
| + return PP_OK_COMPLETIONPENDING; |
| +} |
| + |
| +int32_t PepperTCPServerSocketMessageFilter::OnMsgAccept( |
| + const ppapi::host::HostMessageContext* context, |
| + uint32 plugin_dispatcher_id) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + DCHECK(context); |
| + |
| + ppapi::host::ReplyMessageContext reply_context( |
|
yzshen1
2013/07/19 23:51:58
nit: You could move this downwards.
ygorshenin1
2013/07/29 14:03:57
Done.
|
| + context->MakeReplyMessageContext()); |
| + |
| + if (state_ != STATE_LISTENING) |
| + return PP_ERROR_FAILED; |
| + |
| + state_ = STATE_ACCEPT_IN_PROGRESS; |
| + int result = socket_->Accept( |
|
yzshen1
2013/07/19 23:51:58
nit: maybe it is better to use |net_result| so tha
ygorshenin1
2013/07/29 14:03:57
Done.
|
| + &socket_buffer_, |
| + base::Bind(&PepperTCPServerSocketMessageFilter::OnAcceptCompleted, |
| + base::Unretained(this), |
| + reply_context, plugin_dispatcher_id)); |
| + if (result != net::ERR_IO_PENDING) |
| + OnAcceptCompleted(reply_context, plugin_dispatcher_id, result); |
| + return PP_OK_COMPLETIONPENDING; |
| +} |
| + |
| +int32_t PepperTCPServerSocketMessageFilter::OnMsgStopListening( |
| + const ppapi::host::HostMessageContext* context) { |
| + DCHECK(BrowserThread::CurrentlyOn(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(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + |
| + net::IPAddressNumber address; |
| + int port; |
| + if (state_ != STATE_BEFORE_LISTENING || |
| + !NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &address, &port)) { |
| + SendListenError(context, PP_ERROR_FAILED); |
| + return; |
| + } |
| + |
| + state_ = STATE_LISTEN_IN_PROGRESS; |
| + |
| + socket_.reset(new net::TCPServerSocket(NULL, net::NetLog::Source())); |
| + int result = socket_->Listen(net::IPEndPoint(address, port), backlog); |
|
yzshen1
2013/07/19 23:51:58
nit: maybe it is better to use |net_result| so tha
ygorshenin1
2013/07/29 14:03:57
Done.
|
| + if (result != net::ERR_IO_PENDING) |
| + OnListenCompleted(context, result); |
| +} |
| + |
| +void PepperTCPServerSocketMessageFilter::OnListenCompleted( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int result) { |
| + if (state_ != STATE_LISTEN_IN_PROGRESS) { |
| + SendListenError(context, PP_ERROR_FAILED); |
| + return; |
| + } |
| + if (result != net::OK) { |
| + SendListenError(context, NetErrorToPepperError(result)); |
|
yzshen1
2013/07/19 23:51:58
This changes the behavior of the API, it returns m
ygorshenin1
2013/07/29 14:03:57
Hope, that it's fine as tcp server sockets are sti
|
| + 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); |
| + return; |
| + } |
| + if (!NetAddressPrivateImpl::IPEndPointToNetAddress(end_point.address(), |
| + end_point.port(), |
| + &addr)) { |
| + SendListenError(context, PP_ERROR_FAILED); |
| + return; |
| + } |
| + |
| + SendListenReply(context, PP_OK, addr); |
| + state_ = STATE_LISTENING; |
|
yzshen1
2013/07/19 23:51:58
What if we fail above? Then we will be in STATE_LI
ygorshenin1
2013/07/29 14:03:57
Done.
|
| +} |
| + |
| +void PepperTCPServerSocketMessageFilter::OnAcceptCompleted( |
| + const ppapi::host::ReplyMessageContext& context, |
| + uint32 plugin_dispatcher_id, |
| + int result) { |
| + if (state_ != STATE_ACCEPT_IN_PROGRESS) { |
| + SendAcceptError(context, PP_ERROR_FAILED); |
|
yzshen1
2013/07/19 23:51:58
we should also reset state_ in failure cases.
ygorshenin1
2013/07/29 14:03:57
Done.
|
| + return; |
| + } |
| + if (result != net::OK) { |
| + SendAcceptError(context, NetErrorToPepperError(result)); |
| + return; |
| + } |
| + |
| + DCHECK(socket_buffer_.get()); |
| + |
| + state_ = STATE_LISTENING; |
| + |
| + scoped_ptr<net::StreamSocket> socket(socket_buffer_.release()); |
| + net::IPEndPoint ip_end_point_local; |
| + net::IPEndPoint ip_end_point_remote; |
| + PP_NetAddress_Private local_addr = NetAddressPrivateImpl::kInvalidNetAddress; |
| + PP_NetAddress_Private remote_addr = NetAddressPrivateImpl::kInvalidNetAddress; |
| + |
| + int32_t pp_result = |
| + NetErrorToPepperError(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)) { |
| + SendAcceptError(context, PP_ERROR_FAILED); |
| + return; |
| + } |
| + pp_result = |
| + NetErrorToPepperError(socket->GetPeerAddress(&ip_end_point_remote)); |
| + if (pp_result != PP_OK) { |
| + SendAcceptError(context, pp_result); |
| + return; |
| + } |
| + if (!NetAddressPrivateImpl::IPEndPointToNetAddress( |
| + ip_end_point_remote.address(), |
| + ip_end_point_remote.port(), |
| + &remote_addr)) { |
| + SendAcceptError(context, PP_ERROR_FAILED); |
| + return; |
| + } |
| + if (!pepper_message_filter_.get() || plugin_dispatcher_id == 0) { |
| + SendAcceptError(context, PP_ERROR_FAILED); |
| + return; |
| + } |
| + uint32 accepted_socket_id = pepper_message_filter_->AddAcceptedTCPSocket( |
| + ppapi::API_ID_PPB_TCPSOCKET_PRIVATE, |
| + plugin_dispatcher_id, |
| + socket.release()); |
| + if (accepted_socket_id != 0) { |
| + SendAcceptReply(context, PP_OK, accepted_socket_id, local_addr, |
| + remote_addr); |
| + } else { |
| + SendAcceptError(context, PP_ERROR_NOSPACE); |
| + } |
| +} |
| + |
| +void PepperTCPServerSocketMessageFilter::SendListenReply( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int32_t result, |
| + const PP_NetAddress_Private& local_addr) { |
| + ppapi::host::ReplyMessageContext reply_context(context); |
| + reply_context.params.set_result(result); |
| + SendReply(reply_context, |
| + PpapiPluginMsg_TCPServerSocket_ListenReply(local_addr)); |
| +} |
| + |
| +void PepperTCPServerSocketMessageFilter::SendListenError( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int32_t result) { |
| + SendListenReply(context, result, |
| + NetAddressPrivateImpl::kInvalidNetAddress); |
| +} |
| + |
| +void PepperTCPServerSocketMessageFilter::SendAcceptReply( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int32_t result, |
| + uint32 accepted_socket_id, |
| + const PP_NetAddress_Private& local_addr, |
| + const PP_NetAddress_Private& remote_addr) { |
| + ppapi::host::ReplyMessageContext reply_context(context); |
| + reply_context.params.set_result(result); |
| + SendReply(reply_context, PpapiPluginMsg_TCPServerSocket_AcceptReply( |
| + accepted_socket_id, local_addr, remote_addr)); |
| +} |
| + |
| +void PepperTCPServerSocketMessageFilter::SendAcceptError( |
| + const ppapi::host::ReplyMessageContext& context, |
| + int32_t result) { |
| + SendAcceptReply(context, |
| + result, |
| + 0, |
| + NetAddressPrivateImpl::kInvalidNetAddress, |
| + NetAddressPrivateImpl::kInvalidNetAddress); |
| +} |
| + |
| +} // namespace content |