diff options
37 files changed, 1680 insertions, 16 deletions
diff --git a/chrome/test/ui/ppapi_uitest.cc b/chrome/test/ui/ppapi_uitest.cc index 5e17212..6fb6dbd 100644 --- a/chrome/test/ui/ppapi_uitest.cc +++ b/chrome/test/ui/ppapi_uitest.cc @@ -401,6 +401,8 @@ TEST_PPAPI_NACL_VIA_HTTP(UDPSocketPrivateShared) TEST_PPAPI_NACL_VIA_HTTP_DISALLOWED_SOCKETS(TCPSocketPrivateDisallowed) TEST_PPAPI_NACL_VIA_HTTP_DISALLOWED_SOCKETS(UDPSocketPrivateDisallowed) +TEST_PPAPI_IN_PROCESS_VIA_HTTP(TCPServerSocketPrivate) + // URLLoader tests. TEST_PPAPI_IN_PROCESS_VIA_HTTP(URLLoader_BasicGET) TEST_PPAPI_IN_PROCESS_VIA_HTTP(URLLoader_BasicPOST) diff --git a/content/browser/renderer_host/pepper_message_filter.cc b/content/browser/renderer_host/pepper_message_filter.cc index b1a04c6..21327c6 100644 --- a/content/browser/renderer_host/pepper_message_filter.cc +++ b/content/browser/renderer_host/pepper_message_filter.cc @@ -9,10 +9,12 @@ #include "base/compiler_specific.h" #include "base/logging.h" #include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" #include "base/process_util.h" #include "base/threading/worker_pool.h" #include "base/values.h" #include "content/browser/font_list_async.h" +#include "content/browser/renderer_host/pepper_tcp_server_socket.h" #include "content/browser/renderer_host/pepper_tcp_socket.h" #include "content/browser/renderer_host/pepper_udp_socket.h" #include "content/browser/renderer_host/render_process_host_impl.h" @@ -29,6 +31,7 @@ #include "net/base/host_resolver.h" #include "net/base/net_errors.h" #include "net/base/single_request_host_resolver.h" +#include "ppapi/c/pp_errors.h" #include "ppapi/c/private/ppb_flash_net_connector.h" #include "ppapi/proxy/ppapi_messages.h" #include "ppapi/shared_impl/private/net_address_private_impl.h" @@ -83,7 +86,8 @@ void PepperMessageFilter::OverrideThreadForMessage( BrowserThread::ID* thread) { if (message.type() == PpapiHostMsg_PPBTCPSocket_Connect::ID || message.type() == PpapiHostMsg_PPBTCPSocket_ConnectWithNetAddress::ID || - message.type() == PpapiHostMsg_PPBUDPSocket_Bind::ID) { + message.type() == PpapiHostMsg_PPBUDPSocket_Bind::ID || + message.type() == PpapiHostMsg_PPBTCPServerSocket_Listen::ID) { *thread = BrowserThread::UI; } } @@ -118,6 +122,14 @@ bool PepperMessageFilter::OnMessageReceived(const IPC::Message& msg, IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBUDPSocket_SendTo, OnUDPSendTo) IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBUDPSocket_Close, OnUDPClose) + // TCP Server messages. + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTCPServerSocket_Listen, + OnTCPServerListen) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTCPServerSocket_Accept, + OnTCPServerAccept) + IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBTCPServerSocket_Destroy, + RemoveTCPServerSocket) + IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP_EX() return handled; @@ -135,6 +147,37 @@ net::CertVerifier* PepperMessageFilter::GetCertVerifier() { return cert_verifier_.get(); } +uint32 PepperMessageFilter::AddAcceptedTCPSocket( + int32 routing_id, + uint32 plugin_dispatcher_id, + net::StreamSocket* socket) { + scoped_ptr<net::StreamSocket> s(socket); + + uint32 tcp_socket_id = GenerateSocketID(); + if (tcp_socket_id != kInvalidSocketID) { + tcp_sockets_[tcp_socket_id] = linked_ptr<PepperTCPSocket>( + new PepperTCPSocket(this, + routing_id, + plugin_dispatcher_id, + tcp_socket_id, + s.release())); + } + return tcp_socket_id; +} + +void PepperMessageFilter::RemoveTCPServerSocket(uint32 real_socket_id) { + TCPServerSocketMap::iterator iter = tcp_server_sockets_.find(real_socket_id); + if (iter == tcp_server_sockets_.end()) { + NOTREACHED(); + return; + } + + // Destroy the TCPServerSocket instance will cancel any pending completion + // callback. From this point on, there won't be any messages associated with + // this socket sent to the plugin side. + tcp_server_sockets_.erase(iter); +} + #if defined(ENABLE_FLAPPER_HACKS) namespace { @@ -546,6 +589,63 @@ void PepperMessageFilter::OnUDPClose(uint32 socket_id) { udp_sockets_.erase(iter); } +void PepperMessageFilter::OnTCPServerListen(int32 routing_id, + uint32 plugin_dispatcher_id, + uint32 temp_socket_id, + const PP_NetAddress_Private& addr, + int32_t backlog) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, + base::Bind(&PepperMessageFilter::DoTCPServerListen, + this, + CanUseSocketAPIs(routing_id), + routing_id, + plugin_dispatcher_id, + temp_socket_id, + addr, + backlog)); +} + +void PepperMessageFilter::DoTCPServerListen(bool allowed, + int32 routing_id, + uint32 plugin_dispatcher_id, + uint32 temp_socket_id, + const PP_NetAddress_Private& addr, + int32_t backlog) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + if (!allowed) { + Send(new PpapiMsg_PPBTCPServerSocket_ListenACK(routing_id, + plugin_dispatcher_id, + 0, + temp_socket_id, + PP_ERROR_FAILED)); + return; + } + uint32 real_socket_id = GenerateSocketID(); + if (real_socket_id == kInvalidSocketID) { + Send(new PpapiMsg_PPBTCPServerSocket_ListenACK(routing_id, + plugin_dispatcher_id, + real_socket_id, + temp_socket_id, + PP_ERROR_NOSPACE)); + return; + } + PepperTCPServerSocket* socket = new PepperTCPServerSocket( + this, routing_id, plugin_dispatcher_id, real_socket_id, temp_socket_id); + tcp_server_sockets_[real_socket_id] = + linked_ptr<PepperTCPServerSocket>(socket); + socket->Listen(addr, backlog); +} + +void PepperMessageFilter::OnTCPServerAccept(uint32 real_socket_id) { + TCPServerSocketMap::iterator iter = tcp_server_sockets_.find(real_socket_id); + if (iter == tcp_server_sockets_.end()) { + NOTREACHED(); + return; + } + iter->second->Accept(); +} + void PepperMessageFilter::GetFontFamiliesComplete( IPC::Message* reply_msg, scoped_refptr<content::FontListResult> result) { @@ -584,8 +684,10 @@ uint32 PepperMessageFilter::GenerateSocketID() { // PepperSocketMessageHandler object, because for each plugin or renderer // process, there is at most one PepperMessageFilter (in other words, at most // one PepperSocketMessageHandler) talking to it. - if (tcp_sockets_.size() + udp_sockets_.size() >= kMaxSocketsAllowed) + if (tcp_sockets_.size() + udp_sockets_.size() + tcp_server_sockets_.size() >= + kMaxSocketsAllowed) { return kInvalidSocketID; + } uint32 socket_id = kInvalidSocketID; do { @@ -594,7 +696,8 @@ uint32 PepperMessageFilter::GenerateSocketID() { socket_id = next_socket_id_++; } while (socket_id == kInvalidSocketID || tcp_sockets_.find(socket_id) != tcp_sockets_.end() || - udp_sockets_.find(socket_id) != udp_sockets_.end()); + udp_sockets_.find(socket_id) != udp_sockets_.end() || + tcp_server_sockets_.find(socket_id) != tcp_server_sockets_.end()); return socket_id; } diff --git a/content/browser/renderer_host/pepper_message_filter.h b/content/browser/renderer_host/pepper_message_filter.h index 203491d..a5f5dec 100644 --- a/content/browser/renderer_host/pepper_message_filter.h +++ b/content/browser/renderer_host/pepper_message_filter.h @@ -17,8 +17,10 @@ #include "content/browser/font_list_async.h" #include "content/public/browser/browser_message_filter.h" #include "net/base/ssl_config_service.h" +#include "net/socket/stream_socket.h" #include "ppapi/c/pp_stdint.h" +class PepperTCPServerSocket; class PepperTCPSocket; class PepperUDPSocket; struct PP_NetAddress_Private; @@ -68,6 +70,15 @@ class PepperMessageFilter : public content::BrowserMessageFilter { net::CertVerifier* GetCertVerifier(); + // Adds already accepted socket to the internal TCP sockets table. Takes + // ownership over |socket|. In the case of failure (full socket table) + // returns 0 and deletes |socket|. Otherwise, returns generated ID for + // |socket|. + uint32 AddAcceptedTCPSocket(int32 routing_id, + uint32 plugin_dispatcher_id, + net::StreamSocket* socket); + void RemoveTCPServerSocket(uint32 real_socket_id); + const net::SSLConfig& ssl_config() { return ssl_config_; } private: @@ -135,6 +146,13 @@ class PepperMessageFilter : public content::BrowserMessageFilter { const PP_NetAddress_Private& addr); void OnUDPClose(uint32 socket_id); + void OnTCPServerListen(int32 routing_id, + uint32 plugin_dispatcher_id, + uint32 temp_socket_id, + const PP_NetAddress_Private& addr, + int32_t backlog); + void OnTCPServerAccept(uint32 real_socket_id); + void DoTCPConnect(bool allowed, int32 routing_id, uint32 socket_id, @@ -148,6 +166,12 @@ class PepperMessageFilter : public content::BrowserMessageFilter { int32 routing_id, uint32 socket_id, const PP_NetAddress_Private& addr); + void DoTCPServerListen(bool allowed, + int32 routing_id, + uint32 plugin_dispatcher_id, + uint32 temp_socket_id, + const PP_NetAddress_Private& addr, + int32_t backlog); // Callback when the font list has been retrieved on a background thread. void GetFontFamiliesComplete(IPC::Message* reply_msg, @@ -184,6 +208,10 @@ class PepperMessageFilter : public content::BrowserMessageFilter { typedef std::map<uint32, linked_ptr<PepperUDPSocket> > UDPSocketMap; UDPSocketMap udp_sockets_; + typedef std::map<uint32, + linked_ptr<PepperTCPServerSocket> > TCPServerSocketMap; + TCPServerSocketMap tcp_server_sockets_; + DISALLOW_COPY_AND_ASSIGN(PepperMessageFilter); }; diff --git a/content/browser/renderer_host/pepper_tcp_server_socket.cc b/content/browser/renderer_host/pepper_tcp_server_socket.cc new file mode 100644 index 0000000..b108d0f --- /dev/null +++ b/content/browser/renderer_host/pepper_tcp_server_socket.cc @@ -0,0 +1,160 @@ +// Copyright (c) 2012 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_tcp_server_socket.h" + +#include <cstddef> + +#include "base/logging.h" +#include "content/browser/renderer_host/pepper_message_filter.h" +#include "content/public/browser/browser_thread.h" +#include "net/base/ip_endpoint.h" +#include "net/base/net_errors.h" +#include "net/socket/tcp_client_socket.h" +#include "net/socket/tcp_server_socket.h" +#include "ppapi/c/pp_errors.h" +#include "ppapi/proxy/ppapi_messages.h" +#include "ppapi/shared_impl/private/net_address_private_impl.h" + +using content::BrowserThread; +using ppapi::NetAddressPrivateImpl; + +PepperTCPServerSocket::PepperTCPServerSocket( + PepperMessageFilter* manager, + int32 routing_id, + uint32 plugin_dispatcher_id, + uint32 real_socket_id, + uint32 temp_socket_id) + : manager_(manager), + routing_id_(routing_id), + plugin_dispatcher_id_(plugin_dispatcher_id), + real_socket_id_(real_socket_id), + temp_socket_id_(temp_socket_id), + state_(BEFORE_LISTENING) { + DCHECK(manager); +} + +PepperTCPServerSocket::~PepperTCPServerSocket() { +} + +void PepperTCPServerSocket::Listen(const PP_NetAddress_Private& addr, + int32 backlog) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + net::IPEndPoint ip_end_point; + if (state_ != BEFORE_LISTENING || + !NetAddressPrivateImpl::NetAddressToIPEndPoint(addr, &ip_end_point)) { + CancelListenRequest(); + return; + } + + state_ = LISTEN_IN_PROGRESS; + + socket_.reset(new net::TCPServerSocket(NULL, net::NetLog::Source())); + int result = socket_->Listen(ip_end_point, backlog); + if (result != net::ERR_IO_PENDING) + OnListenCompleted(result); +} + +void PepperTCPServerSocket::Accept() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + + if (state_ != LISTENING) { + SendAcceptACKError(); + return; + } + + state_ = ACCEPT_IN_PROGRESS; + + int result = socket_->Accept( + &socket_buffer_, + base::Bind(&PepperTCPServerSocket::OnAcceptCompleted, + base::Unretained(this))); + if (result != net::ERR_IO_PENDING) + OnAcceptCompleted(result); +} + +void PepperTCPServerSocket::CancelListenRequest() { + manager_->Send(new PpapiMsg_PPBTCPServerSocket_ListenACK( + routing_id_, + plugin_dispatcher_id_, + 0, + temp_socket_id_, + PP_ERROR_FAILED)); + BrowserThread::PostTask( + BrowserThread::IO, + FROM_HERE, + base::Bind(&PepperMessageFilter::RemoveTCPServerSocket, manager_, + real_socket_id_)); +} + +void PepperTCPServerSocket::SendAcceptACKError() { + manager_->Send(new PpapiMsg_PPBTCPServerSocket_AcceptACK( + routing_id_, + plugin_dispatcher_id_, + real_socket_id_, + 0, + NetAddressPrivateImpl::kInvalidNetAddress, + NetAddressPrivateImpl::kInvalidNetAddress)); +} + +void PepperTCPServerSocket::OnListenCompleted(int result) { + DCHECK(state_ == LISTEN_IN_PROGRESS && socket_.get()); + + if (result != net::OK) { + CancelListenRequest(); + } else { + manager_->Send(new PpapiMsg_PPBTCPServerSocket_ListenACK( + routing_id_, + plugin_dispatcher_id_, + real_socket_id_, + temp_socket_id_, + PP_OK)); + state_ = LISTENING; + } +} + +void PepperTCPServerSocket::OnAcceptCompleted(int result) { + DCHECK(state_ == ACCEPT_IN_PROGRESS && socket_buffer_.get()); + + if (result != net::OK) { + SendAcceptACKError(); + } else { + scoped_ptr<net::StreamSocket> socket(socket_buffer_.release()); + + net::IPEndPoint ip_end_point; + net::AddressList address_list; + PP_NetAddress_Private local_addr = + NetAddressPrivateImpl::kInvalidNetAddress; + PP_NetAddress_Private remote_addr = + NetAddressPrivateImpl::kInvalidNetAddress; + + if (socket->GetLocalAddress(&ip_end_point) != net::OK || + !NetAddressPrivateImpl::IPEndPointToNetAddress(ip_end_point, + &local_addr) || + socket->GetPeerAddress(&address_list) != net::OK || + !NetAddressPrivateImpl::AddressListToNetAddress(address_list, + &remote_addr)) { + SendAcceptACKError(); + } else { + uint32 accepted_socket_id = + manager_->AddAcceptedTCPSocket(routing_id_, + plugin_dispatcher_id_, + socket.release()); + if (accepted_socket_id != 0) { + manager_->Send(new PpapiMsg_PPBTCPServerSocket_AcceptACK( + routing_id_, + plugin_dispatcher_id_, + real_socket_id_, + accepted_socket_id, + local_addr, + remote_addr)); + } else { + SendAcceptACKError(); + } + } + } + + state_ = LISTENING; +} diff --git a/content/browser/renderer_host/pepper_tcp_server_socket.h b/content/browser/renderer_host/pepper_tcp_server_socket.h new file mode 100644 index 0000000..77b5f43 --- /dev/null +++ b/content/browser/renderer_host/pepper_tcp_server_socket.h @@ -0,0 +1,63 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_RENDERER_HOST_PEPPER_TCP_SERVER_SOCKET_H_ +#define CONTENT_BROWSER_RENDERER_HOST_PEPPER_TCP_SERVER_SOCKET_H_ +#pragma once + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" + +class PepperMessageFilter; +struct PP_NetAddress_Private; + +namespace net { +class ServerSocket; +class StreamSocket; +} + +// PepperTCPSocket is used by PepperMessageFilter to handle requests +// from the Pepper TCP server socket API +// (PPB_TCPServerSocket_Private). +class PepperTCPServerSocket { + public: + PepperTCPServerSocket(PepperMessageFilter* manager, + int32 routing_id, + uint32 plugin_dispatcher_id, + uint32 real_socket_id, + uint32 temp_socket_id); + ~PepperTCPServerSocket(); + + void Listen(const PP_NetAddress_Private& addr, int32 backlog); + void Accept(); + + private: + enum State { + BEFORE_LISTENING, + LISTEN_IN_PROGRESS, + LISTENING, + ACCEPT_IN_PROGRESS, + }; + + void CancelListenRequest(); + void SendAcceptACKError(); + + void OnListenCompleted(int result); + void OnAcceptCompleted(int result); + + PepperMessageFilter* manager_; + int32 routing_id_; + uint32 plugin_dispatcher_id_; + uint32 real_socket_id_; + uint32 temp_socket_id_; + + State state_; + + scoped_ptr<net::ServerSocket> socket_; + scoped_ptr<net::StreamSocket> socket_buffer_; + + DISALLOW_COPY_AND_ASSIGN(PepperTCPServerSocket); +}; + +#endif // CONTENT_BROWSER_RENDERER_HOST_PEPPER_TCP_SERVER_SOCKET_H_ diff --git a/content/browser/renderer_host/pepper_tcp_socket.cc b/content/browser/renderer_host/pepper_tcp_socket.cc index 05a84cf..21b1cef 100644 --- a/content/browser/renderer_host/pepper_tcp_socket.cc +++ b/content/browser/renderer_host/pepper_tcp_socket.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -44,6 +44,22 @@ PepperTCPSocket::PepperTCPSocket( DCHECK(manager); } +PepperTCPSocket::PepperTCPSocket( + PepperMessageFilter* manager, + int32 routing_id, + uint32 plugin_dispatcher_id, + uint32 socket_id, + net::StreamSocket* socket) + : manager_(manager), + routing_id_(routing_id), + plugin_dispatcher_id_(plugin_dispatcher_id), + socket_id_(socket_id), + connection_state_(CONNECTED), + end_of_file_reached_(false), + socket_(socket) { + DCHECK(manager); +} + PepperTCPSocket::~PepperTCPSocket() { // Make sure no further callbacks from socket_. if (socket_.get()) diff --git a/content/browser/renderer_host/pepper_tcp_socket.h b/content/browser/renderer_host/pepper_tcp_socket.h index 77378d4..af1b6ed 100644 --- a/content/browser/renderer_host/pepper_tcp_socket.h +++ b/content/browser/renderer_host/pepper_tcp_socket.h @@ -32,6 +32,14 @@ class PepperTCPSocket { int32 routing_id, uint32 plugin_dispatcher_id, uint32 socket_id); + + // Used for creation already connected sockets. Takes ownership of + // |socket|. + PepperTCPSocket(PepperMessageFilter* manager, + int32 routing_id, + uint32 plugin_dispatcher_id, + uint32 socket_id, + net::StreamSocket* socket); ~PepperTCPSocket(); int routing_id() { return routing_id_; } diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 79727e9..ff70b51 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -512,6 +512,8 @@ 'browser/renderer_host/pepper_file_message_filter.h', 'browser/renderer_host/pepper_message_filter.cc', 'browser/renderer_host/pepper_message_filter.h', + 'browser/renderer_host/pepper_tcp_server_socket.cc', + 'browser/renderer_host/pepper_tcp_server_socket.h', 'browser/renderer_host/pepper_tcp_socket.cc', 'browser/renderer_host/pepper_tcp_socket.h', 'browser/renderer_host/pepper_udp_socket.cc', diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.cc b/content/renderer/pepper/pepper_plugin_delegate_impl.cc index c18475e..337b920 100644 --- a/content/renderer/pepper/pepper_plugin_delegate_impl.cc +++ b/content/renderer/pepper/pepper_plugin_delegate_impl.cc @@ -79,6 +79,7 @@ #include "webkit/plugins/ppapi/ppb_broker_impl.h" #include "webkit/plugins/ppapi/ppb_flash_impl.h" #include "webkit/plugins/ppapi/ppb_flash_net_connector_impl.h" +#include "webkit/plugins/ppapi/ppb_tcp_server_socket_private_impl.h" #include "webkit/plugins/ppapi/ppb_tcp_socket_private_impl.h" #include "webkit/plugins/ppapi/ppb_udp_socket_private_impl.h" #include "webkit/plugins/ppapi/resource_helper.h" @@ -1774,18 +1775,20 @@ void PepperPluginDelegateImpl::TCPSocketConnect( uint32 socket_id, const std::string& host, uint16_t port) { - tcp_sockets_.AddWithID(socket, socket_id); - render_view_->Send(new PpapiHostMsg_PPBTCPSocket_Connect( - render_view_->routing_id(), socket_id, host, port)); + RegisterTCPSocket(socket, socket_id); + render_view_->Send( + new PpapiHostMsg_PPBTCPSocket_Connect( + render_view_->routing_id(), socket_id, host, port)); } void PepperPluginDelegateImpl::TCPSocketConnectWithNetAddress( webkit::ppapi::PPB_TCPSocket_Private_Impl* socket, uint32 socket_id, const PP_NetAddress_Private& addr) { - tcp_sockets_.AddWithID(socket, socket_id); - render_view_->Send(new PpapiHostMsg_PPBTCPSocket_ConnectWithNetAddress( - render_view_->routing_id(), socket_id, addr)); + RegisterTCPSocket(socket, socket_id); + render_view_->Send( + new PpapiHostMsg_PPBTCPSocket_ConnectWithNetAddress( + render_view_->routing_id(), socket_id, addr)); } void PepperPluginDelegateImpl::TCPSocketSSLHandshake( @@ -1819,6 +1822,12 @@ void PepperPluginDelegateImpl::TCPSocketDisconnect(uint32 socket_id) { tcp_sockets_.Remove(socket_id); } +void PepperPluginDelegateImpl::RegisterTCPSocket( + webkit::ppapi::PPB_TCPSocket_Private_Impl* socket, + uint32 socket_id) { + tcp_sockets_.AddWithID(socket, socket_id); +} + uint32 PepperPluginDelegateImpl::UDPSocketCreate() { uint32 socket_id = 0; render_view_->Send(new PpapiHostMsg_PPBUDPSocket_Create( @@ -1859,6 +1868,38 @@ void PepperPluginDelegateImpl::UDPSocketClose(uint32 socket_id) { udp_sockets_.Remove(socket_id); } +void PepperPluginDelegateImpl::TCPServerSocketListen( + webkit::ppapi::PPB_TCPServerSocket_Private_Impl* socket, + uint32 temp_socket_id, + const PP_NetAddress_Private& addr, + int32_t backlog) { + uninitialized_tcp_server_sockets_.AddWithID(socket, temp_socket_id); + render_view_->Send( + new PpapiHostMsg_PPBTCPServerSocket_Listen( + render_view_->routing_id(), 0, temp_socket_id, addr, backlog)); +} + +void PepperPluginDelegateImpl::TCPServerSocketAccept(uint32 real_socket_id) { + DCHECK(tcp_server_sockets_.Lookup(real_socket_id)); + render_view_->Send(new PpapiHostMsg_PPBTCPServerSocket_Accept( + real_socket_id)); +} + +void PepperPluginDelegateImpl::TCPServerSocketStopListening( + uint32 real_socket_id, + uint32 temp_socket_id) { + if (real_socket_id == 0) { + if (uninitialized_tcp_server_sockets_.Lookup(temp_socket_id)) { + // Pending Listen request. + uninitialized_tcp_server_sockets_.Remove(temp_socket_id); + } + } else { + render_view_->Send( + new PpapiHostMsg_PPBTCPServerSocket_Destroy(real_socket_id)); + tcp_server_sockets_.Remove(real_socket_id); + } +} + int32_t PepperPluginDelegateImpl::ShowContextMenu( webkit::ppapi::PluginInstance* instance, webkit::ppapi::PPB_Flash_Menu_Impl* menu, @@ -2110,6 +2151,10 @@ bool PepperPluginDelegateImpl::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(PpapiMsg_PPBUDPSocket_RecvFromACK, OnUDPSocketRecvFromACK) IPC_MESSAGE_HANDLER(PpapiMsg_PPBUDPSocket_SendToACK, OnUDPSocketSendToACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPServerSocket_ListenACK, + OnTCPServerSocketListenACK) + IPC_MESSAGE_HANDLER(PpapiMsg_PPBTCPServerSocket_AcceptACK, + OnTCPServerSocketAcceptACK) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -2131,6 +2176,8 @@ void PepperPluginDelegateImpl::OnTCPSocketConnectACK( tcp_sockets_.Lookup(socket_id); if (socket) socket->OnConnectCompleted(succeeded, local_addr, remote_addr); + if (!succeeded) + tcp_sockets_.Remove(socket_id); } void PepperPluginDelegateImpl::OnTCPSocketSSLHandshakeACK( @@ -2172,6 +2219,8 @@ void PepperPluginDelegateImpl::OnUDPSocketBindACK( udp_sockets_.Lookup(socket_id); if (socket) socket->OnBindCompleted(succeeded, addr); + if (!succeeded) + udp_sockets_.Remove(socket_id); } void PepperPluginDelegateImpl::OnUDPSocketRecvFromACK( @@ -2196,6 +2245,43 @@ void PepperPluginDelegateImpl::OnUDPSocketSendToACK(uint32 plugin_dispatcher_id, socket->OnSendToCompleted(succeeded, bytes_written); } +void PepperPluginDelegateImpl::OnTCPServerSocketListenACK( + uint32 plugin_dispatcher_id, + uint32 real_socket_id, + uint32 temp_socket_id, + int32_t status) { + webkit::ppapi::PPB_TCPServerSocket_Private_Impl* socket = + uninitialized_tcp_server_sockets_.Lookup(temp_socket_id); + if (socket == NULL) { + // StopListening was called before completion of Listen. + render_view_->Send( + new PpapiHostMsg_PPBTCPServerSocket_Destroy(real_socket_id)); + } else { + uninitialized_tcp_server_sockets_.Remove(temp_socket_id); + + if (status == PP_OK) + tcp_server_sockets_.AddWithID(socket, real_socket_id); + socket->OnListenCompleted(real_socket_id, status); + } +} + +void PepperPluginDelegateImpl::OnTCPServerSocketAcceptACK( + uint32 plugin_dispatcher_id, + uint32 real_server_socket_id, + uint32 accepted_socket_id, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr) { + webkit::ppapi::PPB_TCPServerSocket_Private_Impl* socket = + tcp_server_sockets_.Lookup(real_server_socket_id); + if (socket) { + bool succeeded = accepted_socket_id != 0; + socket->OnAcceptCompleted(succeeded, + accepted_socket_id, + local_addr, + remote_addr); + } +} + int PepperPluginDelegateImpl::GetRoutingId() const { return render_view_->routing_id(); } diff --git a/content/renderer/pepper/pepper_plugin_delegate_impl.h b/content/renderer/pepper/pepper_plugin_delegate_impl.h index 0679f38..92222b1 100644 --- a/content/renderer/pepper/pepper_plugin_delegate_impl.h +++ b/content/renderer/pepper/pepper_plugin_delegate_impl.h @@ -337,6 +337,9 @@ class PepperPluginDelegateImpl virtual void TCPSocketWrite(uint32 socket_id, const std::string& buffer) OVERRIDE; virtual void TCPSocketDisconnect(uint32 socket_id) OVERRIDE; + virtual void RegisterTCPSocket( + webkit::ppapi::PPB_TCPSocket_Private_Impl* socket, + uint32 socket_id) OVERRIDE; virtual uint32 UDPSocketCreate() OVERRIDE; virtual void UDPSocketBind( @@ -349,6 +352,14 @@ class PepperPluginDelegateImpl const std::string& buffer, const PP_NetAddress_Private& addr) OVERRIDE; virtual void UDPSocketClose(uint32 socket_id) OVERRIDE; + virtual void TCPServerSocketListen( + webkit::ppapi::PPB_TCPServerSocket_Private_Impl* socket, + uint32 temp_socket_id, + const PP_NetAddress_Private& addr, + int32_t backlog) OVERRIDE; + virtual void TCPServerSocketAccept(uint32 real_socket_id) OVERRIDE; + virtual void TCPServerSocketStopListening(uint32 real_socket_id, + uint32 temp_socket_id) OVERRIDE; virtual int32_t ShowContextMenu( webkit::ppapi::PluginInstance* instance, @@ -427,6 +438,15 @@ class PepperPluginDelegateImpl bool succeeded, const std::string& data, const PP_NetAddress_Private& addr); + void OnTCPServerSocketListenACK(uint32 plugin_dispatcher_id, + uint32 real_socket_id, + uint32 temp_socket_id, + int32_t status); + void OnTCPServerSocketAcceptACK(uint32 plugin_dispatcher_id, + uint32 real_server_socket_id, + uint32 accepted_socket_id, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr); CONTENT_EXPORT int GetRoutingId() const; @@ -481,6 +501,11 @@ class PepperPluginDelegateImpl IDMap<webkit::ppapi::PPB_UDPSocket_Private_Impl> udp_sockets_; + IDMap<webkit::ppapi::PPB_TCPServerSocket_Private_Impl> tcp_server_sockets_; + + IDMap<webkit::ppapi::PPB_TCPServerSocket_Private_Impl> + uninitialized_tcp_server_sockets_; + IDMap<scoped_refptr<webkit::ppapi::PPB_Flash_Menu_Impl>, IDMapOwnPointer> pending_context_menus_; diff --git a/ppapi/api/private/ppb_tcp_server_socket_private.idl b/ppapi/api/private/ppb_tcp_server_socket_private.idl new file mode 100644 index 0000000..a1224e1 --- /dev/null +++ b/ppapi/api/private/ppb_tcp_server_socket_private.idl @@ -0,0 +1,61 @@ +/* Copyright (c) 2012 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. + */ + +/** + * This file defines the <code>PPB_TCPServerSocket_Private</code> interface. + */ + +label Chrome { + M18 = 0.1 +}; + +/** + * The <code>PPB_TCPServerSocket_Private</code> interface provides TCP + * server socket operations. + */ +interface PPB_TCPServerSocket_Private { + /** + * Allocates a TCP server socket resource. + */ + PP_Resource Create([in] PP_Instance instance); + + /** + * Determines if a given resource is TCP server socket. + */ + PP_Bool IsTCPServerSocket([in] PP_Resource resource); + + /** + * Binds |tcp_server_socket| to the address given by |addr| and + * starts listening. The |backlog| argument defines the maximum + * length to which the queue of pending connections may + * grow. |callback| is invoked when |tcp_server_socket| is ready to + * accept incoming connections or in the case of failure. Returns + * PP_ERROR_NOSPACE if socket can't be initialized, or + * PP_ERROR_FAILED in the case of Listen failure. Otherwise, returns + * PP_OK. + */ + int32_t Listen([in] PP_Resource tcp_server_socket, + [in] PP_NetAddress_Private addr, + [in] int32_t backlog, + [in] PP_CompletionCallback callback); + + /** + * Accepts single connection, creates instance of + * PPB_TCPSocket_Private and stores reference to it in + * |tcp_socket|. |callback| is invoked when connection is accepted + * or in the case of failure. This method can be called only after + * succesfull Listen call on |tcp_server_socket|. + */ + int32_t Accept([in] PP_Resource tcp_server_socket, + [out] PP_Resource tcp_socket, + [in] PP_CompletionCallback callback); + + /** + * Cancels all pending callbacks reporting PP_ERROR_ABORTED and + * closes the socket. Note: this method is implicitly called when + * server socket is destroyed. + */ + void StopListening([in] PP_Resource tcp_server_socket); +}; diff --git a/ppapi/c/private/ppb_tcp_server_socket_private.h b/ppapi/c/private/ppb_tcp_server_socket_private.h new file mode 100644 index 0000000..8355b15 --- /dev/null +++ b/ppapi/c/private/ppb_tcp_server_socket_private.h @@ -0,0 +1,87 @@ +/* Copyright (c) 2012 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. + */ + +/* From private/ppb_tcp_server_socket_private.idl, + * modified Tue Feb 14 12:24:48 2012. + */ + +#ifndef PPAPI_C_PRIVATE_PPB_TCP_SERVER_SOCKET_PRIVATE_H_ +#define PPAPI_C_PRIVATE_PPB_TCP_SERVER_SOCKET_PRIVATE_H_ + +#include "ppapi/c/pp_bool.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/c/pp_instance.h" +#include "ppapi/c/pp_macros.h" +#include "ppapi/c/pp_resource.h" +#include "ppapi/c/pp_stdint.h" +#include "ppapi/c/private/ppb_net_address_private.h" + +#define PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE_0_1 \ + "PPB_TCPServerSocket_Private;0.1" +#define PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE \ + PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE_0_1 + +/** + * @file + * This file defines the <code>PPB_TCPServerSocket_Private</code> interface. + */ + + +/** + * @addtogroup Interfaces + * @{ + */ +/** + * The <code>PPB_TCPServerSocket_Private</code> interface provides TCP + * server socket operations. + */ +struct PPB_TCPServerSocket_Private_0_1 { + /** + * Allocates a TCP server socket resource. + */ + PP_Resource (*Create)(PP_Instance instance); + /** + * Determines if a given resource is TCP server socket. + */ + PP_Bool (*IsTCPServerSocket)(PP_Resource resource); + /** + * Binds |tcp_server_socket| to the address given by |addr| and + * starts listening. The |backlog| argument defines the maximum + * length to which the queue of pending connections may + * grow. |callback| is invoked when |tcp_server_socket| is ready to + * accept incoming connections or in the case of failure. Returns + * PP_ERROR_NOSPACE if socket can't be initialized, or + * PP_ERROR_FAILED in the case of Listen failure. Otherwise, returns + * PP_OK. + */ + int32_t (*Listen)(PP_Resource tcp_server_socket, + const struct PP_NetAddress_Private* addr, + int32_t backlog, + struct PP_CompletionCallback callback); + /** + * Accepts single connection, creates instance of + * PPB_TCPSocket_Private and stores reference to it in + * |tcp_socket|. |callback| is invoked when connection is accepted + * or in the case of failure. This method can be called only after + * succesfull Listen call on |tcp_server_socket|. + */ + int32_t (*Accept)(PP_Resource tcp_server_socket, + PP_Resource* tcp_socket, + struct PP_CompletionCallback callback); + /** + * Cancels all pending callbacks reporting PP_ERROR_ABORTED and + * closes the socket. Note: this method is implicitly called when + * server socket is destroyed. + */ + void (*StopListening)(PP_Resource tcp_server_socket); +}; + +typedef struct PPB_TCPServerSocket_Private_0_1 PPB_TCPServerSocket_Private; +/** + * @} + */ + +#endif /* PPAPI_C_PRIVATE_PPB_TCP_SERVER_SOCKET_PRIVATE_H_ */ + diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi index b6c3b62..56df78c1 100644 --- a/ppapi/ppapi_shared.gypi +++ b/ppapi/ppapi_shared.gypi @@ -130,7 +130,8 @@ 'shared_impl/private/ppb_browser_font_trusted_shared.h', 'shared_impl/private/ppb_char_set_shared.cc', 'shared_impl/private/ppb_char_set_shared.h', - + 'shared_impl/private/ppb_tcp_server_socket_shared.cc', + 'shared_impl/private/ppb_tcp_server_socket_shared.h', 'shared_impl/private/tcp_socket_private_impl.cc', 'shared_impl/private/tcp_socket_private_impl.h', 'shared_impl/private/udp_socket_private_impl.cc', @@ -206,6 +207,8 @@ 'thunk/ppb_resource_array_thunk.cc', 'thunk/ppb_scrollbar_api.h', 'thunk/ppb_scrollbar_thunk.cc', + 'thunk/ppb_tcp_server_socket_private_api.h', + 'thunk/ppb_tcp_server_socket_private_thunk.cc', 'thunk/ppb_tcp_socket_private_api.h', 'thunk/ppb_tcp_socket_private_thunk.cc', 'thunk/ppb_text_input_api.h', diff --git a/ppapi/ppapi_sources.gypi b/ppapi/ppapi_sources.gypi index d0bee15..e212681 100644 --- a/ppapi/ppapi_sources.gypi +++ b/ppapi/ppapi_sources.gypi @@ -290,6 +290,8 @@ 'tests/test_case.h', 'tests/test_net_address_private_untrusted.cc', 'tests/test_net_address_private_untrusted.h', + 'tests/test_tcp_server_socket_private.cc', + 'tests/test_tcp_server_socket_private.h', 'tests/test_tcp_socket_private_shared.cc', 'tests/test_tcp_socket_private_shared.h', 'tests/test_udp_socket_private_shared.cc', diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h index dceb91d..ff19419 100644 --- a/ppapi/proxy/ppapi_messages.h +++ b/ppapi/proxy/ppapi_messages.h @@ -332,6 +332,26 @@ IPC_MESSAGE_ROUTED4(PpapiMsg_PPBUDPSocket_SendToACK, bool /* succeeded */, int32_t /* bytes_written */) +// PPB_TCPServerSocket_Private. + +// |status| == PP_ERROR_NOSPACE means that the socket table is full +// and new socket can't be initialized. +// |status| == PP_ERROR_FAILED means that socket is correctly +// initialized (if needed) but Listen call is failed. +// |status| == PP_OK means that socket is correctly initialized (if +// needed) and Listen call succeeds. +IPC_MESSAGE_ROUTED4(PpapiMsg_PPBTCPServerSocket_ListenACK, + uint32 /* plugin_dispatcher_id */, + uint32 /* real_socket_id */, + uint32 /* temp_socket_id */, + int32_t /* status */) +IPC_MESSAGE_ROUTED5(PpapiMsg_PPBTCPServerSocket_AcceptACK, + uint32 /* plugin_dispatcher_id */, + uint32 /* real_server_socket_id */, + uint32 /* accepted_socket_id */, + PP_NetAddress_Private /* local_addr */, + PP_NetAddress_Private /* remote_addr */) + // PPB_Graphics2D. IPC_MESSAGE_ROUTED2(PpapiMsg_PPBGraphics2D_FlushACK, ppapi::HostResource /* graphics_2d */, @@ -849,6 +869,22 @@ IPC_MESSAGE_CONTROL3(PpapiHostMsg_PPBUDPSocket_SendTo, IPC_MESSAGE_CONTROL1(PpapiHostMsg_PPBUDPSocket_Close, uint32 /* socket_id */) +// PPB_TCPServerSocket_Private. +IPC_MESSAGE_CONTROL5(PpapiHostMsg_PPBTCPServerSocket_Listen, + int32 /* routing_id */, + uint32 /* plugin_dispatcher_id */, + uint32 /* temp_socket_id */, + PP_NetAddress_Private /* addr */, + int32_t /* backlog */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_PPBTCPServerSocket_Accept, + uint32 /* real_socket_id */) +IPC_MESSAGE_CONTROL1(PpapiHostMsg_PPBTCPServerSocket_Destroy, + uint32 /* real_socket_id */) + +// PPB_Font. +IPC_SYNC_MESSAGE_CONTROL0_1(PpapiHostMsg_PPBFont_GetFontFamilies, + std::string /* result */) + // PPB_Graphics2D. IPC_SYNC_MESSAGE_ROUTED3_1(PpapiHostMsg_PPBGraphics2D_Create, PP_Instance /* instance */, diff --git a/ppapi/proxy/resource_creation_proxy.cc b/ppapi/proxy/resource_creation_proxy.cc index 731dd60..45dd02e 100644 --- a/ppapi/proxy/resource_creation_proxy.cc +++ b/ppapi/proxy/resource_creation_proxy.cc @@ -268,6 +268,12 @@ PP_Resource ResourceCreationProxy::CreateScrollbar(PP_Instance instance, return 0; } +PP_Resource ResourceCreationProxy::CreateTCPServerSocketPrivate( + PP_Instance instance) { + // TODO (ygorshenin): implement this + return 0; +} + PP_Resource ResourceCreationProxy::CreateTCPSocketPrivate( PP_Instance instance) { return PPB_TCPSocket_Private_Proxy::CreateProxyResource(instance); diff --git a/ppapi/proxy/resource_creation_proxy.h b/ppapi/proxy/resource_creation_proxy.h index f508e42..c7f84ab 100644 --- a/ppapi/proxy/resource_creation_proxy.h +++ b/ppapi/proxy/resource_creation_proxy.h @@ -106,6 +106,8 @@ class ResourceCreationProxy : public InterfaceProxy, uint32_t size) OVERRIDE; virtual PP_Resource CreateScrollbar(PP_Instance instance, PP_Bool vertical) OVERRIDE; + virtual PP_Resource CreateTCPServerSocketPrivate( + PP_Instance instance) OVERRIDE; virtual PP_Resource CreateTCPSocketPrivate(PP_Instance instance) OVERRIDE; virtual PP_Resource CreateTransport(PP_Instance instance, const char* name, diff --git a/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.cc b/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.cc new file mode 100644 index 0000000..284db1e --- /dev/null +++ b/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.cc @@ -0,0 +1,113 @@ +// Copyright (c) 2012 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 "ppapi/shared_impl/private/ppb_tcp_server_socket_shared.h" + +#include <cstddef> + +#include "base/logging.h" +#include "ppapi/c/pp_errors.h" + +namespace ppapi { + +PPB_TCPServerSocket_Shared::PPB_TCPServerSocket_Shared(PP_Instance instance) + : Resource(OBJECT_IS_IMPL, instance), + real_socket_id_(0), + temp_socket_id_(GenerateTempSocketID()), + state_(BEFORE_LISTENING), + tcp_socket_buffer_(NULL) { +} + +PPB_TCPServerSocket_Shared::PPB_TCPServerSocket_Shared( + const HostResource& resource) + : Resource(OBJECT_IS_PROXY, resource), + real_socket_id_(0), + temp_socket_id_(GenerateTempSocketID()), + state_(BEFORE_LISTENING), + tcp_socket_buffer_(NULL) { +} + +PPB_TCPServerSocket_Shared::~PPB_TCPServerSocket_Shared() { +} + +thunk::PPB_TCPServerSocket_Private_API* +PPB_TCPServerSocket_Shared::AsPPB_TCPServerSocket_Private_API() { + return this; +} + +int32_t PPB_TCPServerSocket_Shared::Listen(const PP_NetAddress_Private* addr, + int32_t backlog, + PP_CompletionCallback callback) { + if (!addr) + return PP_ERROR_BADARGUMENT; + if (!callback.func) + return PP_ERROR_BLOCKS_MAIN_THREAD; + if (state_ != BEFORE_LISTENING) + return PP_ERROR_FAILED; + if (TrackedCallback::IsPending(listen_callback_)) + return PP_ERROR_INPROGRESS; // Can only have one pending request. + + listen_callback_ = new TrackedCallback(this, callback); + // Send the request, the browser will call us back via ListenACK + SendListen(temp_socket_id_, *addr, backlog); + return PP_OK_COMPLETIONPENDING; +} + +int32_t PPB_TCPServerSocket_Shared::Accept(PP_Resource* tcp_socket, + PP_CompletionCallback callback) { + if (!tcp_socket) + return PP_ERROR_BADARGUMENT; + if (!callback.func) + return PP_ERROR_BLOCKS_MAIN_THREAD; + + if (state_ != LISTENING) + return PP_ERROR_FAILED; + if (TrackedCallback::IsPending(accept_callback_)) + return PP_ERROR_INPROGRESS; + + tcp_socket_buffer_ = tcp_socket; + accept_callback_ = new TrackedCallback(this, callback); + + SendAccept(); + return PP_OK_COMPLETIONPENDING; +} + +void PPB_TCPServerSocket_Shared::StopListening() { + if (state_ == CLOSED) + return; + + state_ = CLOSED; + + SendStopListening(); + real_socket_id_ = 0; + + if (listen_callback_.get()) + listen_callback_->PostAbort(); + if (accept_callback_.get()) + accept_callback_->PostAbort(); + tcp_socket_buffer_ = NULL; +} + +void PPB_TCPServerSocket_Shared::OnListenCompleted(uint32 real_socket_id, + int32_t status) { + if (state_ != BEFORE_LISTENING || + !TrackedCallback::IsPending(listen_callback_)) { + NOTREACHED(); + return; + } + + if (status == PP_OK) { + real_socket_id_ = real_socket_id; + state_ = LISTENING; + } + + TrackedCallback::ClearAndRun(&listen_callback_, status); +} + +uint32 PPB_TCPServerSocket_Shared::GenerateTempSocketID() { + static uint32 socket_id = 0; + return socket_id++; +} + +} // namespace ppapi diff --git a/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.h b/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.h new file mode 100644 index 0000000..15cbc03 --- /dev/null +++ b/ppapi/shared_impl/private/ppb_tcp_server_socket_shared.h @@ -0,0 +1,84 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_SHARED_IMPL_PRIVATE_PPB_TCP_SERVER_SOCKET_SHARED_H_ +#define PPAPI_SHARED_IMPL_PRIVATE_PPB_TCP_SERVER_SOCKET_SHARED_H_ + +#include "base/compiler_specific.h" +#include "ppapi/c/pp_completion_callback.h" +#include "ppapi/shared_impl/resource.h" +#include "ppapi/shared_impl/tracked_callback.h" +#include "ppapi/thunk/ppb_tcp_server_socket_private_api.h" + +namespace ppapi { + +// This class provides the shared implementation of a +// PPB_TCPServerSocket_Private. The functions that actually send +// messages to browser are implemented differently for the proxied and +// non-proxied derived classes. +class PPAPI_SHARED_EXPORT PPB_TCPServerSocket_Shared + : public thunk::PPB_TCPServerSocket_Private_API, + public Resource { + public: + // C-tor used in Impl case. + PPB_TCPServerSocket_Shared(PP_Instance instance); + // C-tor used in Proxy case. + PPB_TCPServerSocket_Shared(const HostResource& resource); + + virtual ~PPB_TCPServerSocket_Shared(); + + // Resource overrides. + virtual PPB_TCPServerSocket_Private_API* + AsPPB_TCPServerSocket_Private_API() OVERRIDE; + + // PPB_TCPServerSocket_Private_API implementation. + virtual int32_t Listen(const PP_NetAddress_Private* addr, + int32_t backlog, + PP_CompletionCallback callback) OVERRIDE; + virtual int32_t Accept(PP_Resource* tcp_socket, + PP_CompletionCallback callback) OVERRIDE; + virtual void StopListening() OVERRIDE; + + void OnListenCompleted(uint32 real_socket_id, int32_t status); + virtual void OnAcceptCompleted(bool succeeded, + uint32 tcp_socket_id, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr) = 0; + + // Send functions that need to be implemented differently for the + // proxied and non-proxied derived classes. + virtual void SendListen(uint32 temp_socket_id, + const PP_NetAddress_Private& addr, + int32_t backlog) = 0; + virtual void SendAccept() = 0; + virtual void SendStopListening() = 0; + + protected: + enum State { + // Before listening (including a listen request is pending or a + // previous listen request failed). + BEFORE_LISTENING, + // Socket is successfully bound and in listening mode. + LISTENING, + // The socket is closed. + CLOSED + }; + + static uint32 GenerateTempSocketID(); + + uint32 real_socket_id_; + uint32 temp_socket_id_; + State state_; + + scoped_refptr<TrackedCallback> listen_callback_; + scoped_refptr<TrackedCallback> accept_callback_; + + PP_Resource* tcp_socket_buffer_; + + DISALLOW_COPY_AND_ASSIGN(PPB_TCPServerSocket_Shared); +}; + +} // namespace ppapi + +#endif // PPAPI_SHARED_IMPL_PRIVATE_PPB_TCP_SERVER_SOCKET_SHARED_H_ diff --git a/ppapi/shared_impl/resource.h b/ppapi/shared_impl/resource.h index 8f4dc25..34df0ea 100644 --- a/ppapi/shared_impl/resource.h +++ b/ppapi/shared_impl/resource.h @@ -47,6 +47,7 @@ F(PPB_PDFFont_API) \ F(PPB_ResourceArray_API) \ F(PPB_Scrollbar_API) \ + F(PPB_TCPServerSocket_Private_API) \ F(PPB_TCPSocket_Private_API) \ F(PPB_Transport_API) \ F(PPB_UDPSocket_Private_API) \ diff --git a/ppapi/tests/test_tcp_server_socket_private.cc b/ppapi/tests/test_tcp_server_socket_private.cc new file mode 100644 index 0000000..47edda9 --- /dev/null +++ b/ppapi/tests/test_tcp_server_socket_private.cc @@ -0,0 +1,399 @@ +// Copyright (c) 2012 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 "ppapi/tests/test_tcp_server_socket_private.h" + +#include <cstddef> +#include <cstring> +#include <vector> + +#include "ppapi/cpp/module.h" +#include "ppapi/cpp/private/net_address_private.h" +#include "ppapi/cpp/private/tcp_socket_private.h" +#include "ppapi/tests/test_utils.h" +#include "ppapi/tests/testing_instance.h" + +#define ASSERT_SUCCESS(error_message) \ + if (!(error_message).empty()) \ + return (error_message); + +using pp::NetAddressPrivate; +using pp::TCPSocketPrivate; + +namespace { + +const uint16_t kPortScanFrom = 1024; +const uint16_t kPortScanTo = 4096; + +} // namespace + +REGISTER_TEST_CASE(TCPServerSocketPrivate); + +TestTCPServerSocketPrivate::TestTCPServerSocketPrivate( + TestingInstance* instance) + : TestCase(instance), + core_interface_(NULL), + tcp_server_socket_private_interface_(NULL), + tcp_socket_private_interface_(NULL), + port_(0) { +} + +bool TestTCPServerSocketPrivate::Init() { + core_interface_ = static_cast<const PPB_Core*>( + pp::Module::Get()->GetBrowserInterface(PPB_CORE_INTERFACE)); + if (!core_interface_) + instance_->AppendError("PPB_Core interface not available"); + tcp_server_socket_private_interface_ = + static_cast<const PPB_TCPServerSocket_Private*>( + pp::Module::Get()->GetBrowserInterface( + PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE)); + if (!tcp_server_socket_private_interface_) { + instance_->AppendError( + "PPB_TCPServerSocket_Private interface not available"); + } + + tcp_socket_private_interface_ = + static_cast<const PPB_TCPSocket_Private*>( + pp::Module::Get()->GetBrowserInterface( + PPB_TCPSOCKET_PRIVATE_INTERFACE)); + if (!tcp_socket_private_interface_) + instance_->AppendError("PPB_TCPSocket_Private interface not available"); + + bool tcp_socket_private_is_available = TCPSocketPrivate::IsAvailable(); + if (!tcp_socket_private_is_available) + instance_->AppendError("PPB_TCPSocket_Private interface not available"); + + bool net_address_private_is_available = NetAddressPrivate::IsAvailable(); + if (!net_address_private_is_available) + instance_->AppendError("PPB_NetAddress_Private interface not available"); + + bool init_host_port = GetLocalHostPort( + instance_->pp_instance(), &host_, &port_); + if (!init_host_port) + instance_->AppendError("Can't init host and port"); + + return core_interface_ && + tcp_server_socket_private_interface_ && + tcp_socket_private_is_available && + net_address_private_is_available && + init_host_port && + CheckTestingInterface(); +} + +void TestTCPServerSocketPrivate::RunTests(const std::string& filter) { + RUN_TEST_FORCEASYNC_AND_NOT(Create, filter); + RUN_TEST_FORCEASYNC_AND_NOT(Listen, filter); + RUN_TEST_FORCEASYNC_AND_NOT(Backlog, filter); +} + +std::string TestTCPServerSocketPrivate::GetLocalAddress( + PP_NetAddress_Private* address) { + TCPSocketPrivate socket(instance_); + + TestCompletionCallback callback(instance_->pp_instance(), force_async_); + int32_t rv = socket.Connect(host_.c_str(), port_, callback); + if (force_async_ && rv != PP_OK_COMPLETIONPENDING) + return ReportError("PPB_TCPSocket_Private::Connect force_async", rv); + if (rv == PP_OK_COMPLETIONPENDING) + rv = callback.WaitForResult(); + if (rv != PP_OK) + return ReportError("PPB_TCPSocket_Private::Connect", rv); + + if (!socket.GetLocalAddress(address)) + return ReportError("PPB_TCPSocket_Private::GetLocalAddress", 0); + socket.Disconnect(); + PASS(); +} + +std::string TestTCPServerSocketPrivate::SyncRead(PP_Resource socket, + char* buffer, + int32_t num_bytes) { + TestCompletionCallback callback(instance_->pp_instance(), force_async_); + + int32_t rv = tcp_socket_private_interface_->Read( + socket, buffer, num_bytes, + static_cast<pp::CompletionCallback>(callback).pp_completion_callback()); + + if (force_async_ && rv != PP_OK_COMPLETIONPENDING) + return ReportError("PPB_TCPSocket_Private::Read force_async", rv); + if (rv == PP_OK_COMPLETIONPENDING) + rv = callback.WaitForResult(); + + if (num_bytes != rv) + return ReportError("PPB_TCPSocket_Private::Read", rv); + + PASS(); +} + +std::string TestTCPServerSocketPrivate::SyncWrite(PP_Resource socket, + const char* buffer, + int32_t num_bytes) { + TestCompletionCallback callback(instance_->pp_instance(), force_async_); + int32_t rv = tcp_socket_private_interface_->Write( + socket, buffer, num_bytes, + static_cast<pp::CompletionCallback>(callback).pp_completion_callback()); + + if (force_async_ && rv != PP_OK_COMPLETIONPENDING) + return ReportError("PPB_TCPSocket_Private::Write force_async", rv); + if (rv == PP_OK_COMPLETIONPENDING) + rv = callback.WaitForResult(); + if (num_bytes != rv) + return ReportError("PPB_TCPSocket_Private::Write", rv); + + PASS(); +} + +std::string TestTCPServerSocketPrivate::SyncConnect(PP_Resource socket, + const char* host, + uint16_t port) { + TestCompletionCallback callback(instance_->pp_instance(), force_async_); + int32_t rv = tcp_socket_private_interface_->Connect( + socket, + host_.c_str(), + port, + static_cast<pp::CompletionCallback>(callback).pp_completion_callback()); + if (force_async_ && rv != PP_OK_COMPLETIONPENDING) + return ReportError("PPB_TCPSocket_Private::Connect force_async", rv); + if (rv == PP_OK_COMPLETIONPENDING) + rv = callback.WaitForResult(); + if (rv != PP_OK) + return ReportError("PPB_TCPSocket_Private::Connect", rv); + + PASS(); +} + +void TestTCPServerSocketPrivate::ForceConnect(PP_Resource socket, + const char* host, + uint16_t port) { + std::string error_message; + do { + error_message = SyncConnect(socket, host, port); + } while (!error_message.empty()); +} + +std::string TestTCPServerSocketPrivate::SyncListen(PP_Resource socket, + uint16_t* port, + int32_t backlog) { + PP_NetAddress_Private base_address, local_address; + std::string error_message = GetLocalAddress(&base_address); + ASSERT_SUCCESS(error_message); + + // TODO (ygorshenin): find more efficient way to select available + // ports. + bool is_free_port_found = false; + for (uint16_t p = kPortScanFrom; p < kPortScanTo; ++p) { + if (!NetAddressPrivate::ReplacePort(base_address, p, &local_address)) + return ReportError("PPB_NetAddress_Private::ReplacePort", 0); + + TestCompletionCallback callback(instance_->pp_instance(), force_async_); + int32_t rv = tcp_server_socket_private_interface_->Listen( + socket, + &local_address, + backlog, + static_cast<pp::CompletionCallback>(callback).pp_completion_callback()); + if (force_async_ && rv != PP_OK_COMPLETIONPENDING) + return ReportError("PPB_TCPServerSocket_Private::Listen force_async", rv); + if (rv == PP_OK_COMPLETIONPENDING) + rv = callback.WaitForResult(); + if (rv == PP_OK) { + *port = p; + is_free_port_found = true; + break; + } + } + + if (!is_free_port_found) + return "Can't find available port"; + PASS(); +} + +bool TestTCPServerSocketPrivate::IsSocketsConnected( + PP_Resource lhs, + PP_Resource rhs) { + PP_NetAddress_Private lhs_local_addr, lhs_remote_addr; + + if (!tcp_socket_private_interface_->GetLocalAddress(lhs, &lhs_local_addr)) + return false; + if (!tcp_socket_private_interface_->GetRemoteAddress(lhs, &lhs_remote_addr)) + return false; + + PP_NetAddress_Private rhs_local_addr, rhs_remote_addr; + if (!tcp_socket_private_interface_->GetLocalAddress(rhs, &rhs_local_addr)) + return false; + if (!tcp_socket_private_interface_->GetRemoteAddress(rhs, &rhs_remote_addr)) + return false; + + return NetAddressPrivate::AreEqual(lhs_local_addr, rhs_remote_addr) && + NetAddressPrivate::AreEqual(lhs_remote_addr, rhs_local_addr); +} + +std::string TestTCPServerSocketPrivate::SendMessage(PP_Resource dst, + PP_Resource src, + const char* message) { + const size_t message_size = strlen(message); + + std::string error_message = SyncWrite(src, message, message_size); + ASSERT_SUCCESS(error_message); + + std::vector<char> message_buffer(message_size); + error_message = SyncRead(dst, &message_buffer[0], message_size); + ASSERT_SUCCESS(error_message); + ASSERT_EQ(0, strncmp(message, &message_buffer[0], message_size)); + PASS(); +} + +std::string TestTCPServerSocketPrivate::TestConnectedSockets(PP_Resource lhs, + PP_Resource rhs) { + static const char* const kMessage = "simple message"; + std::string error_message = SendMessage(lhs, rhs, kMessage); + ASSERT_SUCCESS(error_message); + error_message = SendMessage(rhs, lhs, kMessage); + ASSERT_SUCCESS(error_message); + PASS(); +} + +std::string TestTCPServerSocketPrivate::TestCreate() { + PP_Resource server_socket; + + server_socket = tcp_server_socket_private_interface_->Create(0); + ASSERT_EQ(0, server_socket); + core_interface_->ReleaseResource(server_socket); + + server_socket = + tcp_server_socket_private_interface_->Create(instance_->pp_instance()); + ASSERT_TRUE(server_socket != 0); + ASSERT_TRUE(tcp_server_socket_private_interface_->IsTCPServerSocket( + server_socket)); + core_interface_->ReleaseResource(server_socket); + PASS(); +} + +std::string TestTCPServerSocketPrivate::TestListen() { + static const int kBacklog = 2; + + PP_Resource server_socket = + tcp_server_socket_private_interface_->Create(instance_->pp_instance()); + ASSERT_TRUE(server_socket != 0); + + uint16_t port; + std::string error_message = SyncListen(server_socket, &port, kBacklog); + ASSERT_SUCCESS(error_message); + + TestCompletionCallback accept_callback(instance_->pp_instance(), + force_async_); + PP_Resource accepted_socket; + int32_t accept_rv = tcp_server_socket_private_interface_->Accept( + server_socket, + &accepted_socket, + static_cast<pp::CompletionCallback>( + accept_callback).pp_completion_callback()); + + TCPSocketPrivate client_socket(instance_); + + ForceConnect(client_socket.pp_resource(), host_.c_str(), port); + + if (force_async_ && accept_rv != PP_OK_COMPLETIONPENDING) + return ReportError("PPB_TCPServerSocket_Private::Accept force_async", + accept_rv); + if (accept_rv == PP_OK_COMPLETIONPENDING) + accept_rv = accept_callback.WaitForResult(); + if (accept_rv != PP_OK) + return ReportError("PPB_TCPServerSocket_Private::Accept", accept_rv); + + ASSERT_TRUE(accepted_socket != 0); + ASSERT_TRUE(tcp_socket_private_interface_->IsTCPSocket(accepted_socket)); + + ASSERT_TRUE(IsSocketsConnected(client_socket.pp_resource(), accepted_socket)); + error_message = TestConnectedSockets(client_socket.pp_resource(), + accepted_socket); + ASSERT_SUCCESS(error_message); + + tcp_socket_private_interface_->Disconnect(accepted_socket); + client_socket.Disconnect(); + tcp_server_socket_private_interface_->StopListening(server_socket); + + core_interface_->ReleaseResource(accepted_socket); + core_interface_->ReleaseResource(server_socket); + PASS(); +} + +std::string TestTCPServerSocketPrivate::TestBacklog() { + static const size_t kBacklog = 5; + + PP_Resource server_socket = + tcp_server_socket_private_interface_->Create(instance_->pp_instance()); + ASSERT_TRUE(server_socket != 0); + + uint16_t port; + std::string error_message = SyncListen(server_socket, &port, 2 * kBacklog); + ASSERT_SUCCESS(error_message); + + std::vector<TCPSocketPrivate*> client_sockets(kBacklog); + std::vector<TestCompletionCallback*> connect_callbacks(kBacklog); + std::vector<int32_t> connect_rv(kBacklog); + for (size_t i = 0; i < kBacklog; ++i) { + client_sockets[i] = new TCPSocketPrivate(instance_); + connect_callbacks[i] = new TestCompletionCallback(instance_->pp_instance(), + force_async_); + connect_rv[i] = client_sockets[i]->Connect(host_.c_str(), + port, + *connect_callbacks[i]); + if (force_async_ && connect_rv[i] != PP_OK_COMPLETIONPENDING) + return ReportError("PPB_TCPSocket_Private::Connect force_async", + connect_rv[i]); + } + + std::vector<PP_Resource> accepted_sockets(kBacklog); + for (size_t i = 0; i < kBacklog; ++i) { + TestCompletionCallback callback(instance_->pp_instance(), force_async_); + int32_t rv = tcp_server_socket_private_interface_->Accept( + server_socket, + &accepted_sockets[i], + static_cast<pp::CompletionCallback>(callback).pp_completion_callback()); + if (force_async_ && rv != PP_OK_COMPLETIONPENDING) + return ReportError("PPB_TCPServerSocket_Private::Accept force_async", rv); + if (rv == PP_OK_COMPLETIONPENDING) + rv = callback.WaitForResult(); + if (rv != PP_OK) + return ReportError("PPB_TCPServerSocket_Private::Accept", rv); + + ASSERT_TRUE(accepted_sockets[i] != 0); + ASSERT_TRUE(tcp_socket_private_interface_->IsTCPSocket( + accepted_sockets[i])); + } + + for (size_t i = 0; i < kBacklog; ++i) { + if (connect_rv[i] == PP_OK_COMPLETIONPENDING) + connect_rv[i] = connect_callbacks[i]->WaitForResult(); + if (connect_rv[i] != PP_OK) + return ReportError("PPB_TCPSocket_Private::Connect", connect_rv[i]); + } + + for (size_t i = 0; i < kBacklog; ++i) { + bool found = false; + for (size_t j = 0; j < kBacklog && !found; ++j) + if (IsSocketsConnected(client_sockets[i]->pp_resource(), + accepted_sockets[j])) { + TestConnectedSockets(client_sockets[i]->pp_resource(), + accepted_sockets[j]); + found = true; + } + ASSERT_TRUE(found); + } + + for (size_t i = 0; i < kBacklog; ++i) { + tcp_socket_private_interface_->Disconnect(accepted_sockets[i]); + core_interface_->ReleaseResource(accepted_sockets[i]); + } + + for (size_t i = 0; i < kBacklog; ++i) { + client_sockets[i]->Disconnect(); + delete client_sockets[i]; + delete connect_callbacks[i]; + } + + tcp_server_socket_private_interface_->StopListening(server_socket); + core_interface_->ReleaseResource(server_socket); + PASS(); +} diff --git a/ppapi/tests/test_tcp_server_socket_private.h b/ppapi/tests/test_tcp_server_socket_private.h new file mode 100644 index 0000000..5ada1c1 --- /dev/null +++ b/ppapi/tests/test_tcp_server_socket_private.h @@ -0,0 +1,56 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_TESTS_TEST_TCP_SERVER_SOCKET_PRIVATE_H_ +#define PPAPI_TESTS_TEST_TCP_SERVER_SOCKET_PRIVATE_H_ + +#include <string> + +#include "ppapi/c/pp_stdint.h" +#include "ppapi/c/ppb_core.h" +#include "ppapi/c/private/ppb_net_address_private.h" +#include "ppapi/c/private/ppb_tcp_server_socket_private.h" +#include "ppapi/c/private/ppb_tcp_socket_private.h" +#include "ppapi/tests/test_case.h" + +class TestTCPServerSocketPrivate : public TestCase { + public: + explicit TestTCPServerSocketPrivate(TestingInstance* instance); + + // TestCase implementation. + virtual bool Init(); + virtual void RunTests(const std::string& filter); + + private: + std::string GetLocalAddress(PP_NetAddress_Private* address); + std::string SyncRead(PP_Resource socket, char* buffer, int32_t num_bytes); + std::string SyncWrite(PP_Resource socket, + const char* buffer, + int32_t num_bytes); + std::string SyncConnect(PP_Resource socket, const char* host, uint16_t port); + void ForceConnect(PP_Resource socket, const char* host, uint16_t port); + std::string SyncListen(PP_Resource socket, uint16_t* port, int32_t backlog); + + bool IsSocketsConnected(PP_Resource lhs, PP_Resource rhs); + std::string SendMessage(PP_Resource dst, + PP_Resource src, + const char* message); + std::string TestConnectedSockets(PP_Resource lhs, PP_Resource rhs); + + std::string CheckIOOfConnectedSockets(PP_Resource src, PP_Resource dst); + std::string CheckAddressesOfConnectedSockets(PP_Resource lhs, + PP_Resource rhs); + + std::string TestCreate(); + std::string TestListen(); + std::string TestBacklog(); + + const PPB_Core* core_interface_; + const PPB_TCPServerSocket_Private* tcp_server_socket_private_interface_; + const PPB_TCPSocket_Private* tcp_socket_private_interface_; + std::string host_; + uint16_t port_; +}; + +#endif // PPAPI_TESTS_TEST_TCP_SERVER_SOCKET_PRIVATE_H_ diff --git a/ppapi/thunk/ppb_tcp_server_socket_private_api.h b/ppapi/thunk/ppb_tcp_server_socket_private_api.h new file mode 100644 index 0000000..b88dfc8 --- /dev/null +++ b/ppapi/thunk/ppb_tcp_server_socket_private_api.h @@ -0,0 +1,29 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PPAPI_THUNK_PPB_TCP_SERVER_SOCKET_PRIVATE_API_H_ +#define PPAPI_THUNK_PPB_TCP_SERVER_SOCKET_PRIVATE_API_H_ + +#include "ppapi/c/private/ppb_tcp_server_socket_private.h" +#include "ppapi/thunk/ppapi_thunk_export.h" + +namespace ppapi { +namespace thunk { + +class PPAPI_THUNK_EXPORT PPB_TCPServerSocket_Private_API { +public: + virtual ~PPB_TCPServerSocket_Private_API() {} + + virtual int32_t Listen(const PP_NetAddress_Private* addr, + int32_t backlog, + PP_CompletionCallback callback) = 0; + virtual int32_t Accept(PP_Resource* tcp_socket, + PP_CompletionCallback callback) = 0; + virtual void StopListening() = 0; +}; + +} // namespace thunk +} // namespace ppapi + +#endif // PPAPI_THUNK_PPB_TCP_SERVER_SOCKET_PRIVATE_API_H_ diff --git a/ppapi/thunk/ppb_tcp_server_socket_private_thunk.cc b/ppapi/thunk/ppb_tcp_server_socket_private_thunk.cc new file mode 100644 index 0000000..c4b6bd8 --- /dev/null +++ b/ppapi/thunk/ppb_tcp_server_socket_private_thunk.cc @@ -0,0 +1,71 @@ +// Copyright (c) 2012 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 "ppapi/c/pp_errors.h" +#include "ppapi/c/private/ppb_tcp_server_socket_private.h" +#include "ppapi/thunk/enter.h" +#include "ppapi/thunk/ppb_tcp_server_socket_private_api.h" +#include "ppapi/thunk/resource_creation_api.h" +#include "ppapi/thunk/thunk.h" + +namespace ppapi { +namespace thunk { + +namespace { + +typedef EnterResource<PPB_TCPServerSocket_Private_API> EnterTCPServer; + +PP_Resource Create(PP_Instance instance) { + EnterFunction<ResourceCreationAPI> enter(instance, true); + if (enter.failed()) + return 0; + return enter.functions()->CreateTCPServerSocketPrivate(instance); +} + +PP_Bool IsTCPServerSocket(PP_Resource resource) { + EnterTCPServer enter(resource, false); + return PP_FromBool(enter.succeeded()); +} + +int32_t Listen(PP_Resource tcp_server_socket, + const PP_NetAddress_Private* addr, + int32_t backlog, + PP_CompletionCallback callback) { + EnterTCPServer enter(tcp_server_socket, callback, true); + if (enter.failed()) + return enter.retval(); + return enter.SetResult(enter.object()->Listen(addr, backlog, callback)); +} + +int32_t Accept(PP_Resource tcp_server_socket, + PP_Resource* tcp_socket, + PP_CompletionCallback callback) { + EnterTCPServer enter(tcp_server_socket, callback, true); + if (enter.failed()) + return enter.retval(); + return enter.SetResult(enter.object()->Accept(tcp_socket, callback)); +} + +void StopListening(PP_Resource tcp_server_socket) { + EnterTCPServer enter(tcp_server_socket, true); + if (enter.succeeded()) + enter.object()->StopListening(); +} + +const PPB_TCPServerSocket_Private g_ppb_tcp_server_socket_thunk = { + Create, + IsTCPServerSocket, + Listen, + Accept, + StopListening +}; + +} // namespace + +const PPB_TCPServerSocket_Private* GetPPB_TCPServerSocket_Private_0_1_Thunk() { + return &g_ppb_tcp_server_socket_thunk; +} + +} // namespace thunk +} // namespace ppapi diff --git a/ppapi/thunk/resource_creation_api.h b/ppapi/thunk/resource_creation_api.h index 05c90c2..d567a18 100644 --- a/ppapi/thunk/resource_creation_api.h +++ b/ppapi/thunk/resource_creation_api.h @@ -108,6 +108,7 @@ class ResourceCreationAPI { uint32_t size) = 0; virtual PP_Resource CreateScrollbar(PP_Instance instance, PP_Bool vertical) = 0; + virtual PP_Resource CreateTCPServerSocketPrivate(PP_Instance instance) = 0; virtual PP_Resource CreateTCPSocketPrivate(PP_Instance instace) = 0; virtual PP_Resource CreateTransport(PP_Instance instance, const char* name, diff --git a/ppapi/thunk/thunk.h b/ppapi/thunk/thunk.h index 703ab02..f7ac751 100644 --- a/ppapi/thunk/thunk.h +++ b/ppapi/thunk/thunk.h @@ -12,6 +12,7 @@ #include "ppapi/c/private/ppb_flash_net_connector.h" #include "ppapi/c/private/ppb_flash_fullscreen.h" #include "ppapi/c/private/ppb_instance_private.h" +#include "ppapi/c/private/ppb_tcp_server_socket_private.h" #include "ppapi/c/private/ppb_tcp_socket_private.h" #include "ppapi/c/private/ppb_udp_socket_private.h" #include "ppapi/c/trusted/ppb_audio_input_trusted_dev.h" @@ -71,6 +72,8 @@ PPAPI_THUNK_EXPORT const PPB_ImageDataTrusted_0_4* GetPPB_ImageDataTrusted_0_4_Thunk(); PPAPI_THUNK_EXPORT const PPB_Instance_Private_0_1* GetPPB_Instance_Private_0_1_Thunk(); +PPAPI_THUNK_EXPORT const PPB_TCPServerSocket_Private_0_1* + GetPPB_TCPServerSocket_Private_0_1_Thunk(); PPAPI_THUNK_EXPORT const PPB_TCPSocket_Private_0_3* GetPPB_TCPSocket_Private_0_3_Thunk(); PPAPI_THUNK_EXPORT const PPB_UDPSocket_Private_0_2* diff --git a/webkit/glue/webkit_glue.gypi b/webkit/glue/webkit_glue.gypi index 36cbcde..d294167 100644 --- a/webkit/glue/webkit_glue.gypi +++ b/webkit/glue/webkit_glue.gypi @@ -299,6 +299,8 @@ '../plugins/ppapi/ppb_proxy_impl.h', '../plugins/ppapi/ppb_scrollbar_impl.cc', '../plugins/ppapi/ppb_scrollbar_impl.h', + '../plugins/ppapi/ppb_tcp_server_socket_private_impl.cc', + '../plugins/ppapi/ppb_tcp_server_socket_private_impl.h', '../plugins/ppapi/ppb_tcp_socket_private_impl.cc', '../plugins/ppapi/ppb_tcp_socket_private_impl.h', '../plugins/ppapi/ppb_text_input_impl.cc', diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.cc b/webkit/plugins/ppapi/mock_plugin_delegate.cc index ea6a9f2..c62f39e 100644 --- a/webkit/plugins/ppapi/mock_plugin_delegate.cc +++ b/webkit/plugins/ppapi/mock_plugin_delegate.cc @@ -275,6 +275,10 @@ void MockPluginDelegate::TCPSocketWrite(uint32 socket_id, void MockPluginDelegate::TCPSocketDisconnect(uint32 socket_id) { } +void MockPluginDelegate::RegisterTCPSocket(PPB_TCPSocket_Private_Impl* socket, + uint32 socket_id) { +} + uint32 MockPluginDelegate::UDPSocketCreate() { return 0; } @@ -296,6 +300,20 @@ void MockPluginDelegate::UDPSocketSendTo(uint32 socket_id, void MockPluginDelegate::UDPSocketClose(uint32 socket_id) { } +void MockPluginDelegate::TCPServerSocketListen( + PPB_TCPServerSocket_Private_Impl* socket, + uint32 temp_socket_id, + const PP_NetAddress_Private& addr, + int32_t backlog) { +} + +void MockPluginDelegate::TCPServerSocketAccept(uint32 real_socket_id) { +} + +void MockPluginDelegate::TCPServerSocketStopListening(uint32 real_socket_id, + uint32 temp_socket_id) { +} + int32_t MockPluginDelegate::ShowContextMenu( PluginInstance* instance, webkit::ppapi::PPB_Flash_Menu_Impl* menu, diff --git a/webkit/plugins/ppapi/mock_plugin_delegate.h b/webkit/plugins/ppapi/mock_plugin_delegate.h index cb40de7..8b35aff 100644 --- a/webkit/plugins/ppapi/mock_plugin_delegate.h +++ b/webkit/plugins/ppapi/mock_plugin_delegate.h @@ -122,6 +122,8 @@ class MockPluginDelegate : public PluginDelegate { virtual void TCPSocketRead(uint32 socket_id, int32_t bytes_to_read); virtual void TCPSocketWrite(uint32 socket_id, const std::string& buffer); virtual void TCPSocketDisconnect(uint32 socket_id); + virtual void RegisterTCPSocket(PPB_TCPSocket_Private_Impl* socket, + uint32 socket_id); virtual uint32 UDPSocketCreate(); virtual void UDPSocketBind(PPB_UDPSocket_Private_Impl* socket, uint32 socket_id, @@ -131,6 +133,13 @@ class MockPluginDelegate : public PluginDelegate { const std::string& buffer, const PP_NetAddress_Private& addr); virtual void UDPSocketClose(uint32 socket_id); + virtual void TCPServerSocketListen(PPB_TCPServerSocket_Private_Impl* socket, + uint32 temp_socket_id, + const PP_NetAddress_Private& addr, + int32_t backlog); + virtual void TCPServerSocketAccept(uint32 real_socket_id); + virtual void TCPServerSocketStopListening(uint32 real_socket_id, + uint32 temp_socket_id); virtual int32_t ShowContextMenu( PluginInstance* instance, webkit::ppapi::PPB_Flash_Menu_Impl* menu, diff --git a/webkit/plugins/ppapi/plugin_delegate.h b/webkit/plugins/ppapi/plugin_delegate.h index fe7d45d..973c6e4 100644 --- a/webkit/plugins/ppapi/plugin_delegate.h +++ b/webkit/plugins/ppapi/plugin_delegate.h @@ -82,6 +82,7 @@ class PluginModule; class PPB_Broker_Impl; class PPB_Flash_Menu_Impl; class PPB_Flash_NetConnector_Impl; +class PPB_TCPServerSocket_Private_Impl; class PPB_TCPSocket_Private_Impl; class PPB_UDPSocket_Private_Impl; @@ -452,6 +453,8 @@ class PluginDelegate { virtual void TCPSocketRead(uint32 socket_id, int32_t bytes_to_read) = 0; virtual void TCPSocketWrite(uint32 socket_id, const std::string& buffer) = 0; virtual void TCPSocketDisconnect(uint32 socket_id) = 0; + virtual void RegisterTCPSocket(PPB_TCPSocket_Private_Impl* socket, + uint32 socket_id) = 0; // For PPB_UDPSocket_Private. virtual uint32 UDPSocketCreate() = 0; @@ -464,6 +467,15 @@ class PluginDelegate { const PP_NetAddress_Private& addr) = 0; virtual void UDPSocketClose(uint32 socket_id) = 0; + // For PPB_TCPServerSocket_Private. + virtual void TCPServerSocketListen(PPB_TCPServerSocket_Private_Impl* socket, + uint32 temp_socket_id, + const PP_NetAddress_Private& addr, + int32_t backlog) = 0; + virtual void TCPServerSocketAccept(uint32 real_socket_id) = 0; + virtual void TCPServerSocketStopListening(uint32 real_socket_id, + uint32 temp_socket_id) = 0; + // Show the given context menu at the given position (in the plugin's // coordinates). virtual int32_t ShowContextMenu( diff --git a/webkit/plugins/ppapi/plugin_module.cc b/webkit/plugins/ppapi/plugin_module.cc index 195046a..0a5d457 100644 --- a/webkit/plugins/ppapi/plugin_module.cc +++ b/webkit/plugins/ppapi/plugin_module.cc @@ -76,6 +76,7 @@ #include "ppapi/c/private/ppb_instance_private.h" #include "ppapi/c/private/ppb_pdf.h" #include "ppapi/c/private/ppb_proxy_private.h" +#include "ppapi/c/private/ppb_tcp_server_socket_private.h" #include "ppapi/c/private/ppb_tcp_socket_private.h" #include "ppapi/c/private/ppb_udp_socket_private.h" #include "ppapi/c/private/ppb_uma_private.h" @@ -343,6 +344,8 @@ const void* GetInterface(const char* name) { return ::ppapi::PPB_OpenGLES2_Shared::GetInterface(); if (strcmp(name, PPB_PROXY_PRIVATE_INTERFACE) == 0) return PPB_Proxy_Impl::GetInterface(); + if (strcmp(name, PPB_TCPSERVERSOCKET_PRIVATE_INTERFACE) == 0) + return ::ppapi::thunk::GetPPB_TCPServerSocket_Private_0_1_Thunk(); if (strcmp(name, PPB_UMA_PRIVATE_INTERFACE) == 0) return PPB_UMA_Private_Impl::GetInterface(); if (strcmp(name, PPB_URLLOADERTRUSTED_INTERFACE_0_3) == 0) diff --git a/webkit/plugins/ppapi/ppb_tcp_server_socket_private_impl.cc b/webkit/plugins/ppapi/ppb_tcp_server_socket_private_impl.cc new file mode 100644 index 0000000..213b4bf --- /dev/null +++ b/webkit/plugins/ppapi/ppb_tcp_server_socket_private_impl.cc @@ -0,0 +1,86 @@ +// Copyright (c) 2012 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 "webkit/plugins/ppapi/ppb_tcp_server_socket_private_impl.h" + +#include "base/logging.h" +#include "webkit/plugins/ppapi/host_globals.h" +#include "webkit/plugins/ppapi/plugin_delegate.h" +#include "webkit/plugins/ppapi/ppapi_plugin_instance.h" +#include "webkit/plugins/ppapi/ppb_tcp_socket_private_impl.h" +#include "webkit/plugins/ppapi/resource_helper.h" + +namespace webkit { +namespace ppapi { + +PPB_TCPServerSocket_Private_Impl::PPB_TCPServerSocket_Private_Impl( + PP_Instance instance) + : ::ppapi::PPB_TCPServerSocket_Shared(instance) { +} + +PPB_TCPServerSocket_Private_Impl::~PPB_TCPServerSocket_Private_Impl() { + StopListening(); +} + +PP_Resource PPB_TCPServerSocket_Private_Impl::CreateResource( + PP_Instance instance) { + PPB_TCPServerSocket_Private_Impl* socket = + new PPB_TCPServerSocket_Private_Impl(instance); + return socket->GetReference(); +} + +void PPB_TCPServerSocket_Private_Impl::OnAcceptCompleted( + bool succeeded, + uint32 tcp_socket_id, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr) { + if (!::ppapi::TrackedCallback::IsPending(accept_callback_) || + !tcp_socket_buffer_) { + NOTREACHED(); + return; + } + + if (succeeded) { + *tcp_socket_buffer_ = + PPB_TCPSocket_Private_Impl::CreateConnectedSocket(pp_instance(), + tcp_socket_id, + local_addr, + remote_addr); + } + tcp_socket_buffer_ = NULL; + + ::ppapi::TrackedCallback::ClearAndRun(&accept_callback_, + succeeded ? PP_OK : PP_ERROR_FAILED); +} + +void PPB_TCPServerSocket_Private_Impl::SendListen( + uint32 temp_socket_id, + const PP_NetAddress_Private& addr, + int32_t backlog) { + PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this); + if (!plugin_delegate) + return; + + plugin_delegate->TCPServerSocketListen(this, temp_socket_id, addr, backlog); +} + +void PPB_TCPServerSocket_Private_Impl::SendAccept() { + PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this); + if (!plugin_delegate) + return; + + plugin_delegate->TCPServerSocketAccept(real_socket_id_); +} + +void PPB_TCPServerSocket_Private_Impl::SendStopListening() { + PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this); + if (!plugin_delegate) + return; + + plugin_delegate->TCPServerSocketStopListening(real_socket_id_, + temp_socket_id_); +} + +} // namespace ppapi +} // namespace webkit diff --git a/webkit/plugins/ppapi/ppb_tcp_server_socket_private_impl.h b/webkit/plugins/ppapi/ppb_tcp_server_socket_private_impl.h new file mode 100644 index 0000000..6533e61 --- /dev/null +++ b/webkit/plugins/ppapi/ppb_tcp_server_socket_private_impl.h @@ -0,0 +1,41 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEBKIT_PLUGINS_PPAPI_PPB_TCP_SERVER_SOCKET_PRIVATE_IMPL_H_ +#define WEBKIT_PLUGINS_PPAPI_PPB_TCP_SERVER_SOCKET_PRIVATE_IMPL_H_ + +#include "base/compiler_specific.h" +#include "ppapi/shared_impl/private/ppb_tcp_server_socket_shared.h" + +namespace webkit { +namespace ppapi { + +class PPB_TCPServerSocket_Private_Impl + : public ::ppapi::PPB_TCPServerSocket_Shared { + public: + static PP_Resource CreateResource(PP_Instance instance); + + virtual void OnAcceptCompleted( + bool succeeded, + uint32 tcp_socket_id, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr) OVERRIDE; + + virtual void SendListen(uint32_t temp_socket_id, + const PP_NetAddress_Private& addr, + int32_t backlog) OVERRIDE; + virtual void SendAccept() OVERRIDE; + virtual void SendStopListening() OVERRIDE; + + private: + PPB_TCPServerSocket_Private_Impl(PP_Instance instance); + virtual ~PPB_TCPServerSocket_Private_Impl(); + + DISALLOW_COPY_AND_ASSIGN(PPB_TCPServerSocket_Private_Impl); +}; + +} // namespace ppapi +} // namespace webkit + +#endif // WEBKIT_PLUGINS_PPAPI_PPB_TCP_SERVER_SOCKET_PRIVATE_IMPL_H_ diff --git a/webkit/plugins/ppapi/ppb_tcp_socket_private_impl.cc b/webkit/plugins/ppapi/ppb_tcp_socket_private_impl.cc index 61fc83c..06489aa 100644 --- a/webkit/plugins/ppapi/ppb_tcp_socket_private_impl.cc +++ b/webkit/plugins/ppapi/ppb_tcp_socket_private_impl.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -22,11 +22,10 @@ PPB_TCPSocket_Private_Impl::~PPB_TCPSocket_Private_Impl() { } PP_Resource PPB_TCPSocket_Private_Impl::CreateResource(PP_Instance instance) { - PluginInstance* plugin_instance = HostGlobals::Get()->GetInstance(instance); - if (!plugin_instance) + PluginDelegate* plugin_delegate = GetPluginDelegate(instance); + if (!plugin_delegate) return 0; - PluginDelegate* plugin_delegate = plugin_instance->delegate(); uint32 socket_id = plugin_delegate->TCPSocketCreate(); if (!socket_id) return 0; @@ -34,6 +33,27 @@ PP_Resource PPB_TCPSocket_Private_Impl::CreateResource(PP_Instance instance) { return (new PPB_TCPSocket_Private_Impl(instance, socket_id))->GetReference(); } +PP_Resource PPB_TCPSocket_Private_Impl::CreateConnectedSocket( + PP_Instance instance, + uint32 socket_id, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr) { + PluginDelegate* plugin_delegate = GetPluginDelegate(instance); + if (!plugin_delegate) + return 0; + + PPB_TCPSocket_Private_Impl* socket = + new PPB_TCPSocket_Private_Impl(instance, socket_id); + + socket->connection_state_ = PPB_TCPSocket_Private_Impl::CONNECTED; + socket->local_addr_ = local_addr; + socket->remote_addr_ = remote_addr; + + plugin_delegate->RegisterTCPSocket(socket, socket_id); + + return socket->GetReference(); +} + void PPB_TCPSocket_Private_Impl::SendConnect(const std::string& host, uint16_t port) { PluginDelegate* plugin_delegate = ResourceHelper::GetPluginDelegate(this); @@ -87,5 +107,13 @@ void PPB_TCPSocket_Private_Impl::SendDisconnect() { plugin_delegate->TCPSocketDisconnect(socket_id_); } +PluginDelegate* PPB_TCPSocket_Private_Impl::GetPluginDelegate( + PP_Instance instance) { + PluginInstance* plugin_instance = HostGlobals::Get()->GetInstance(instance); + if (!plugin_instance) + return NULL; + return plugin_instance->delegate(); +} + } // namespace ppapi } // namespace webkit diff --git a/webkit/plugins/ppapi/ppb_tcp_socket_private_impl.h b/webkit/plugins/ppapi/ppb_tcp_socket_private_impl.h index ba86518..fdc298c 100644 --- a/webkit/plugins/ppapi/ppb_tcp_socket_private_impl.h +++ b/webkit/plugins/ppapi/ppb_tcp_socket_private_impl.h @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -11,9 +11,16 @@ namespace webkit { namespace ppapi { +class PluginDelegate; + class PPB_TCPSocket_Private_Impl : public ::ppapi::TCPSocketPrivateImpl { public: static PP_Resource CreateResource(PP_Instance instance); + static PP_Resource CreateConnectedSocket( + PP_Instance instance, + uint32 socket_id, + const PP_NetAddress_Private& local_addr, + const PP_NetAddress_Private& remote_addr); virtual void SendConnect(const std::string& host, uint16_t port) OVERRIDE; virtual void SendConnectWithNetAddress( @@ -28,6 +35,8 @@ class PPB_TCPSocket_Private_Impl : public ::ppapi::TCPSocketPrivateImpl { PPB_TCPSocket_Private_Impl(PP_Instance instance, uint32 socket_id); virtual ~PPB_TCPSocket_Private_Impl(); + static PluginDelegate* GetPluginDelegate(PP_Instance instance); + DISALLOW_COPY_AND_ASSIGN(PPB_TCPSocket_Private_Impl); }; diff --git a/webkit/plugins/ppapi/resource_creation_impl.cc b/webkit/plugins/ppapi/resource_creation_impl.cc index 120c587..4ef430e 100644 --- a/webkit/plugins/ppapi/resource_creation_impl.cc +++ b/webkit/plugins/ppapi/resource_creation_impl.cc @@ -27,6 +27,7 @@ #include "webkit/plugins/ppapi/ppb_graphics_3d_impl.h" #include "webkit/plugins/ppapi/ppb_image_data_impl.h" #include "webkit/plugins/ppapi/ppb_scrollbar_impl.h" +#include "webkit/plugins/ppapi/ppb_tcp_server_socket_private_impl.h" #include "webkit/plugins/ppapi/ppb_tcp_socket_private_impl.h" #include "webkit/plugins/ppapi/ppb_transport_impl.h" #include "webkit/plugins/ppapi/ppb_udp_socket_private_impl.h" @@ -257,6 +258,11 @@ PP_Resource ResourceCreationImpl::CreateResourceArray( return object->GetReference(); } +PP_Resource ResourceCreationImpl::CreateTCPServerSocketPrivate( + PP_Instance instance) { + return PPB_TCPServerSocket_Private_Impl::CreateResource(instance); +} + PP_Resource ResourceCreationImpl::CreateTCPSocketPrivate(PP_Instance instance) { return PPB_TCPSocket_Private_Impl::CreateResource(instance); } diff --git a/webkit/plugins/ppapi/resource_creation_impl.h b/webkit/plugins/ppapi/resource_creation_impl.h index d4595ae..f7c2a70 100644 --- a/webkit/plugins/ppapi/resource_creation_impl.h +++ b/webkit/plugins/ppapi/resource_creation_impl.h @@ -93,7 +93,10 @@ class ResourceCreationImpl : public ::ppapi::FunctionGroupBase, uint32_t size) OVERRIDE; virtual PP_Resource CreateScrollbar(PP_Instance instance, PP_Bool vertical) OVERRIDE; + virtual PP_Resource CreateTCPServerSocketPrivate( + PP_Instance instance) OVERRIDE; virtual PP_Resource CreateTCPSocketPrivate(PP_Instance instance) OVERRIDE; + virtual PP_Resource CreateTransport(PP_Instance instance, const char* name, PP_TransportType type) OVERRIDE; |