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 |