summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-20 15:29:13 +0000
committeryzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-20 15:29:13 +0000
commit92576792823018d937fc58e74267b0d30663e459 (patch)
treea80543169bea29b7fee7346387a1a0e1d6b34090
parent5603a6cf5fb7197f509b894e45bdc733e720b28a (diff)
downloadchromium_src-92576792823018d937fc58e74267b0d30663e459.zip
chromium_src-92576792823018d937fc58e74267b0d30663e459.tar.gz
chromium_src-92576792823018d937fc58e74267b0d30663e459.tar.bz2
PPB_TCPSocket: add support for TCP server socket operations.
BUG=262601 TEST=new tests in test_tcp_socket. Review URL: https://chromiumcodereview.appspot.com/24195004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@224383 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/test/ppapi/ppapi_browsertest.cc8
-rw-r--r--content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc55
-rw-r--r--content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h21
-rw-r--r--content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.cc51
-rw-r--r--content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h14
-rw-r--r--content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc533
-rw-r--r--content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h111
-rw-r--r--content/content_browser.gypi1
-rw-r--r--content/renderer/pepper/resource_creation_impl.cc4
-rw-r--r--content/renderer/pepper/resource_creation_impl.h1
-rw-r--r--ppapi/api/ppb_tcp_socket.idl97
-rw-r--r--ppapi/c/ppb_tcp_socket.h118
-rw-r--r--ppapi/cpp/tcp_socket.cc72
-rw-r--r--ppapi/cpp/tcp_socket.h68
-rw-r--r--ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c87
-rw-r--r--ppapi/ppapi_shared.gypi2
-rw-r--r--ppapi/proxy/ppapi_messages.h22
-rw-r--r--ppapi/proxy/resource_creation_proxy.cc10
-rw-r--r--ppapi/proxy/resource_creation_proxy.h1
-rw-r--r--ppapi/proxy/tcp_socket_private_resource.cc19
-rw-r--r--ppapi/proxy/tcp_socket_private_resource.h6
-rw-r--r--ppapi/proxy/tcp_socket_resource.cc51
-rw-r--r--ppapi/proxy/tcp_socket_resource.h28
-rw-r--r--ppapi/proxy/tcp_socket_resource_base.cc263
-rw-r--r--ppapi/proxy/tcp_socket_resource_base.h49
-rw-r--r--ppapi/shared_impl/ppb_tcp_socket_shared.cc90
-rw-r--r--ppapi/shared_impl/ppb_tcp_socket_shared.h74
-rw-r--r--ppapi/tests/test_tcp_socket.cc297
-rw-r--r--ppapi/tests/test_tcp_socket.h13
-rw-r--r--ppapi/tests/test_utils.cc47
-rw-r--r--ppapi/tests/test_utils.h5
-rw-r--r--ppapi/thunk/interfaces_ppb_public_stable.h1
-rw-r--r--ppapi/thunk/ppb_tcp_socket_api.h6
-rw-r--r--ppapi/thunk/ppb_tcp_socket_thunk.cc60
-rw-r--r--ppapi/thunk/resource_creation_api.h3
35 files changed, 1897 insertions, 391 deletions
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index 7dadd5c..debec82 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -324,6 +324,8 @@ IN_PROC_BROWSER_TEST_F(OutOfProcessPPAPITest, TCPSocket) {
LIST_TEST(TCPSocket_Connect)
LIST_TEST(TCPSocket_ReadWrite)
LIST_TEST(TCPSocket_SetOption)
+ LIST_TEST(TCPSocket_Listen)
+ LIST_TEST(TCPSocket_Backlog)
);
}
IN_PROC_BROWSER_TEST_F(PPAPINaClNewlibTest, TCPSocket) {
@@ -331,6 +333,8 @@ IN_PROC_BROWSER_TEST_F(PPAPINaClNewlibTest, TCPSocket) {
LIST_TEST(TCPSocket_Connect)
LIST_TEST(TCPSocket_ReadWrite)
LIST_TEST(TCPSocket_SetOption)
+ LIST_TEST(TCPSocket_Listen)
+ LIST_TEST(TCPSocket_Backlog)
);
}
IN_PROC_BROWSER_TEST_F(PPAPINaClGLibcTest, MAYBE_GLIBC(TCPSocket)) {
@@ -338,6 +342,8 @@ IN_PROC_BROWSER_TEST_F(PPAPINaClGLibcTest, MAYBE_GLIBC(TCPSocket)) {
LIST_TEST(TCPSocket_Connect)
LIST_TEST(TCPSocket_ReadWrite)
LIST_TEST(TCPSocket_SetOption)
+ LIST_TEST(TCPSocket_Listen)
+ LIST_TEST(TCPSocket_Backlog)
);
}
IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, TCPSocket) {
@@ -345,6 +351,8 @@ IN_PROC_BROWSER_TEST_F(PPAPINaClPNaClTest, TCPSocket) {
LIST_TEST(TCPSocket_Connect)
LIST_TEST(TCPSocket_ReadWrite)
LIST_TEST(TCPSocket_SetOption)
+ LIST_TEST(TCPSocket_Listen)
+ LIST_TEST(TCPSocket_Backlog)
);
}
diff --git a/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc b/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc
index 46e8c13..39e778d 100644
--- a/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc
+++ b/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.cc
@@ -19,7 +19,6 @@
#include "content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h"
#include "content/browser/renderer_host/pepper/pepper_truetype_font_list_host.h"
#include "content/browser/renderer_host/pepper/pepper_udp_socket_message_filter.h"
-#include "net/socket/stream_socket.h"
#include "ppapi/host/message_filter_host.h"
#include "ppapi/host/ppapi_host.h"
#include "ppapi/host/resource_host.h"
@@ -105,16 +104,13 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
host_, instance, params.pp_resource(), file_system, internal_path));
}
case PpapiHostMsg_TCPSocket_Create::ID: {
- if (CanCreateSocket()) {
- scoped_refptr<ResourceMessageFilter> tcp_socket(
- new PepperTCPSocketMessageFilter(host_,
- instance,
- false));
- return scoped_ptr<ResourceHost>(new MessageFilterHost(
- host_->GetPpapiHost(), instance, params.pp_resource(), tcp_socket));
- } else {
+ ppapi::TCPSocketVersion version;
+ if (!UnpackMessage<PpapiHostMsg_TCPSocket_Create>(message, &version) ||
+ version == ppapi::TCP_SOCKET_VERSION_PRIVATE) {
return scoped_ptr<ResourceHost>();
}
+
+ return CreateNewTCPSocket(instance, params.pp_resource(), version);
}
case PpapiHostMsg_UDPSocket_Create::ID: {
if (CanCreateSocket()) {
@@ -178,16 +174,8 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
}
}
if (message.type() == PpapiHostMsg_TCPSocket_CreatePrivate::ID) {
- if (CanCreateSocket()) {
- scoped_refptr<ResourceMessageFilter> tcp_socket(
- new PepperTCPSocketMessageFilter(host_,
- instance,
- true));
- return scoped_ptr<ResourceHost>(new MessageFilterHost(
- host_->GetPpapiHost(), instance, params.pp_resource(), tcp_socket));
- } else {
- return scoped_ptr<ResourceHost>();
- }
+ return CreateNewTCPSocket(instance, params.pp_resource(),
+ ppapi::TCP_SOCKET_VERSION_PRIVATE);
}
if (message.type() == PpapiHostMsg_UDPSocket_CreatePrivate::ID) {
if (CanCreateSocket()) {
@@ -223,21 +211,34 @@ scoped_ptr<ResourceHost> ContentBrowserPepperHostFactory::CreateResourceHost(
scoped_ptr<ppapi::host::ResourceHost>
ContentBrowserPepperHostFactory::CreateAcceptedTCPSocket(
PP_Instance instance,
- bool private_api,
- net::StreamSocket* socket) {
- scoped_ptr<net::StreamSocket> s(socket);
-
+ ppapi::TCPSocketVersion version,
+ scoped_ptr<net::TCPSocket> socket) {
if (!CanCreateSocket())
return scoped_ptr<ResourceHost>();
scoped_refptr<ResourceMessageFilter> tcp_socket(
- new PepperTCPSocketMessageFilter(host_,
- instance,
- private_api,
- s.release()));
+ new PepperTCPSocketMessageFilter(host_, instance, version,
+ socket.Pass()));
return scoped_ptr<ResourceHost>(new MessageFilterHost(
host_->GetPpapiHost(), instance, 0, tcp_socket));
}
+scoped_ptr<ppapi::host::ResourceHost>
+ContentBrowserPepperHostFactory::CreateNewTCPSocket(
+ PP_Instance instance,
+ PP_Resource resource,
+ ppapi::TCPSocketVersion version) {
+ if (!CanCreateSocket())
+ return scoped_ptr<ResourceHost>();
+
+ scoped_refptr<ResourceMessageFilter> tcp_socket(
+ new PepperTCPSocketMessageFilter(this, host_, instance, version));
+ if (!tcp_socket)
+ return scoped_ptr<ResourceHost>();
+
+ return scoped_ptr<ResourceHost>(new MessageFilterHost(
+ host_->GetPpapiHost(), instance, resource, tcp_socket));
+}
+
const ppapi::PpapiPermissions&
ContentBrowserPepperHostFactory::GetPermissions() const {
return host_->GetPpapiHost()->permissions();
diff --git a/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h b/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h
index 64c8b42..04267a3 100644
--- a/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h
+++ b/content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h
@@ -8,11 +8,10 @@
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "net/socket/tcp_socket.h"
+#include "ppapi/c/pp_resource.h"
#include "ppapi/host/host_factory.h"
-
-namespace net {
-class StreamSocket;
-}
+#include "ppapi/shared_impl/ppb_tcp_socket_shared.h"
namespace ppapi {
class PpapiPermissions;
@@ -35,15 +34,19 @@ class ContentBrowserPepperHostFactory : public ppapi::host::HostFactory {
PP_Instance instance,
const IPC::Message& message) OVERRIDE;
- // Creates ResourceHost for already accepted TCP |socket|. Takes
- // ownership of the |socket|. In the case of failure returns wrapped
- // NULL.
+ // Creates ResourceHost for already accepted TCP |socket|. In the case of
+ // failure returns wrapped NULL.
scoped_ptr<ppapi::host::ResourceHost> CreateAcceptedTCPSocket(
PP_Instance instance,
- bool private_api,
- net::StreamSocket* socket);
+ ppapi::TCPSocketVersion version,
+ scoped_ptr<net::TCPSocket> socket);
private:
+ scoped_ptr<ppapi::host::ResourceHost> CreateNewTCPSocket(
+ PP_Instance instance,
+ PP_Resource resource,
+ ppapi::TCPSocketVersion version);
+
const ppapi::PpapiPermissions& GetPermissions() const;
// Non-owning pointer.
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
index af2234d..e2912a7 100644
--- 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
@@ -15,8 +15,6 @@
#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"
@@ -25,6 +23,7 @@
#include "ppapi/host/resource_host.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/shared_impl/api_id.h"
+#include "ppapi/shared_impl/ppb_tcp_socket_shared.h"
#include "ppapi/shared_impl/private/net_address_private_impl.h"
using ppapi::NetAddressPrivateImpl;
@@ -134,7 +133,8 @@ int32_t PepperTCPServerSocketMessageFilter::OnMsgAccept(
ppapi::host::ReplyMessageContext reply_context(
context->MakeReplyMessageContext());
int net_result = socket_->Accept(
- &socket_buffer_,
+ &accepted_socket_,
+ &accepted_address_,
base::Bind(&PepperTCPServerSocketMessageFilter::OnAcceptCompleted,
base::Unretained(this), reply_context));
if (net_result != net::ERR_IO_PENDING)
@@ -169,8 +169,22 @@ void PepperTCPServerSocketMessageFilter::DoListen(
state_ = STATE_LISTEN_IN_PROGRESS;
- socket_.reset(new net::TCPServerSocket(NULL, net::NetLog::Source()));
- int net_result = socket_->Listen(net::IPEndPoint(address, port), backlog);
+ socket_.reset(new net::TCPSocket(NULL, net::NetLog::Source()));
+ int net_result = net::OK;
+ do {
+ net::IPEndPoint ip_end_point(address, port);
+ net_result = socket_->Open(ip_end_point.GetFamily());
+ if (net_result != net::OK)
+ break;
+ net_result = socket_->SetDefaultOptionsForServer();
+ if (net_result != net::OK)
+ break;
+ net_result = socket_->Bind(ip_end_point);
+ if (net_result != net::OK)
+ break;
+ net_result = socket_->Listen(backlog);
+ } while (false);
+
if (net_result != net::ERR_IO_PENDING)
OnListenCompleted(context, net_result);
}
@@ -229,16 +243,15 @@ void PepperTCPServerSocketMessageFilter::OnAcceptCompleted(
return;
}
- DCHECK(socket_buffer_.get());
+ DCHECK(accepted_socket_.get());
- 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));
+ NetErrorToPepperError(accepted_socket_->GetLocalAddress(
+ &ip_end_point_local));
if (pp_result != PP_OK) {
SendAcceptError(context, pp_result);
return;
@@ -246,19 +259,10 @@ void PepperTCPServerSocketMessageFilter::OnAcceptCompleted(
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(),
+ &local_addr) ||
+ !NetAddressPrivateImpl::IPEndPointToNetAddress(
+ accepted_address_.address(),
+ accepted_address_.port(),
&remote_addr)) {
SendAcceptError(context, PP_ERROR_FAILED);
return;
@@ -266,7 +270,8 @@ void PepperTCPServerSocketMessageFilter::OnAcceptCompleted(
scoped_ptr<ppapi::host::ResourceHost> host =
factory_->CreateAcceptedTCPSocket(
- instance_, true /* private_api */, socket.release());
+ instance_, ppapi::TCP_SOCKET_VERSION_PRIVATE,
+ accepted_socket_.Pass());
if (!host) {
SendAcceptError(context, PP_ERROR_NOSPACE);
return;
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h
index d36b787..5d17333 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h
+++ b/content/browser/renderer_host/pepper/pepper_tcp_server_socket_message_filter.h
@@ -10,16 +10,13 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "content/common/content_export.h"
+#include "net/base/ip_endpoint.h"
+#include "net/socket/tcp_socket.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/host/resource_message_filter.h"
struct PP_NetAddress_Private;
-namespace net {
-class ServerSocket;
-class StreamSocket;
-}
-
namespace ppapi {
namespace host {
class PpapiHost;
@@ -31,6 +28,8 @@ namespace content {
class BrowserPpapiHostImpl;
class ContentBrowserPepperHostFactory;
+// TODO(yzshen): Remove this class entirely and let
+// TCPServerSocketPrivateResource inherit TCPSocketResourceBase.
class CONTENT_EXPORT PepperTCPServerSocketMessageFilter
: public ppapi::host::ResourceMessageFilter {
public:
@@ -97,8 +96,9 @@ class CONTENT_EXPORT PepperTCPServerSocketMessageFilter
PP_Instance instance_;
State state_;
- scoped_ptr<net::ServerSocket> socket_;
- scoped_ptr<net::StreamSocket> socket_buffer_;
+ scoped_ptr<net::TCPSocket> socket_;
+ scoped_ptr<net::TCPSocket> accepted_socket_;
+ net::IPEndPoint accepted_address_;
// Following fields are initialized on the IO thread but used only
// on the UI thread.
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
index 2ec8c54..26c1b7c 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
+++ b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.cc
@@ -4,15 +4,20 @@
#include "content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h"
+#include <cstring>
+
#include "base/bind.h"
#include "base/logging.h"
+#include "build/build_config.h"
#include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
+#include "content/browser/renderer_host/pepper/content_browser_pepper_host_factory.h"
#include "content/browser/renderer_host/pepper/pepper_socket_utils.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/resource_context.h"
#include "content/public/common/socket_permission_request.h"
+#include "net/base/address_family.h"
#include "net/base/host_port_pair.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
@@ -21,9 +26,10 @@
#include "net/socket/client_socket_handle.h"
#include "net/socket/ssl_client_socket.h"
#include "net/socket/tcp_client_socket.h"
-#include "ppapi/c/private/ppb_net_address_private.h"
#include "ppapi/host/dispatch_host_message.h"
#include "ppapi/host/error_conversion.h"
+#include "ppapi/host/ppapi_host.h"
+#include "ppapi/host/resource_host.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/tcp_socket_resource_base.h"
#include "ppapi/shared_impl/private/net_address_private_impl.h"
@@ -31,6 +37,8 @@
using ppapi::NetAddressPrivateImpl;
using ppapi::host::NetErrorToPepperError;
using ppapi::proxy::TCPSocketResourceBase;
+using ppapi::TCPSocketState;
+using ppapi::TCPSocketVersion;
namespace {
@@ -41,16 +49,24 @@ size_t g_num_instances = 0;
namespace content {
PepperTCPSocketMessageFilter::PepperTCPSocketMessageFilter(
+ ContentBrowserPepperHostFactory* factory,
BrowserPpapiHostImpl* host,
PP_Instance instance,
- bool private_api)
- : external_plugin_(host->external_plugin()),
- private_api_(private_api),
+ TCPSocketVersion version)
+ : version_(version),
+ external_plugin_(host->external_plugin()),
render_process_id_(0),
render_view_id_(0),
- state_(STATE_BEFORE_CONNECT),
+ ppapi_host_(host->GetPpapiHost()),
+ factory_(factory),
+ instance_(instance),
+ state_(TCPSocketState::INITIAL),
end_of_file_reached_(false),
- ssl_context_helper_(host->ssl_context_helper()) {
+ bind_input_addr_(NetAddressPrivateImpl::kInvalidNetAddress),
+ socket_(new net::TCPSocket(NULL, net::NetLog::Source())),
+ ssl_context_helper_(host->ssl_context_helper()),
+ pending_accept_(false),
+ allow_address_reuse_(false) {
DCHECK(host);
++g_num_instances;
if (!host->GetRenderViewIDsForInstance(instance,
@@ -63,17 +79,25 @@ PepperTCPSocketMessageFilter::PepperTCPSocketMessageFilter(
PepperTCPSocketMessageFilter::PepperTCPSocketMessageFilter(
BrowserPpapiHostImpl* host,
PP_Instance instance,
- bool private_api,
- net::StreamSocket* socket)
- : external_plugin_(host->external_plugin()),
- private_api_(private_api),
+ TCPSocketVersion version,
+ scoped_ptr<net::TCPSocket> socket)
+ : version_(version),
+ external_plugin_(host->external_plugin()),
render_process_id_(0),
render_view_id_(0),
- state_(STATE_CONNECTED),
+ ppapi_host_(host->GetPpapiHost()),
+ factory_(NULL),
+ instance_(instance),
+ state_(TCPSocketState::CONNECTED),
end_of_file_reached_(false),
- socket_(socket),
- ssl_context_helper_(host->ssl_context_helper()) {
+ bind_input_addr_(NetAddressPrivateImpl::kInvalidNetAddress),
+ socket_(socket.Pass()),
+ ssl_context_helper_(host->ssl_context_helper()),
+ pending_accept_(false),
+ allow_address_reuse_(false) {
DCHECK(host);
+ DCHECK_NE(version, ppapi::TCP_SOCKET_VERSION_1_0);
+
++g_num_instances;
if (!host->GetRenderViewIDsForInstance(instance,
&render_process_id_,
@@ -84,7 +108,9 @@ PepperTCPSocketMessageFilter::PepperTCPSocketMessageFilter(
PepperTCPSocketMessageFilter::~PepperTCPSocketMessageFilter() {
if (socket_)
- socket_->Disconnect();
+ socket_->Close();
+ if (ssl_socket_)
+ ssl_socket_->Disconnect();
--g_num_instances;
}
@@ -97,13 +123,16 @@ scoped_refptr<base::TaskRunner>
PepperTCPSocketMessageFilter::OverrideTaskRunnerForMessage(
const IPC::Message& message) {
switch (message.type()) {
+ case PpapiHostMsg_TCPSocket_Bind::ID:
case PpapiHostMsg_TCPSocket_Connect::ID:
case PpapiHostMsg_TCPSocket_ConnectWithNetAddress::ID:
+ case PpapiHostMsg_TCPSocket_Listen::ID:
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
case PpapiHostMsg_TCPSocket_SSLHandshake::ID:
case PpapiHostMsg_TCPSocket_Read::ID:
case PpapiHostMsg_TCPSocket_Write::ID:
- case PpapiHostMsg_TCPSocket_Disconnect::ID:
+ case PpapiHostMsg_TCPSocket_Accept::ID:
+ case PpapiHostMsg_TCPSocket_Close::ID:
case PpapiHostMsg_TCPSocket_SetOption::ID:
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
}
@@ -115,6 +144,8 @@ int32_t PepperTCPSocketMessageFilter::OnResourceMessageReceived(
ppapi::host::HostMessageContext* context) {
IPC_BEGIN_MESSAGE_MAP(PepperTCPSocketMessageFilter, msg)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(
+ PpapiHostMsg_TCPSocket_Bind, OnMsgBind)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(
PpapiHostMsg_TCPSocket_Connect, OnMsgConnect)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(
PpapiHostMsg_TCPSocket_ConnectWithNetAddress,
@@ -125,14 +156,38 @@ int32_t PepperTCPSocketMessageFilter::OnResourceMessageReceived(
PpapiHostMsg_TCPSocket_Read, OnMsgRead)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(
PpapiHostMsg_TCPSocket_Write, OnMsgWrite)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL(
+ PpapiHostMsg_TCPSocket_Listen, OnMsgListen)
+ PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
+ PpapiHostMsg_TCPSocket_Accept, OnMsgAccept)
PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
- PpapiHostMsg_TCPSocket_Disconnect, OnMsgDisconnect)
+ PpapiHostMsg_TCPSocket_Close, OnMsgClose)
PPAPI_DISPATCH_HOST_RESOURCE_CALL(
PpapiHostMsg_TCPSocket_SetOption, OnMsgSetOption)
IPC_END_MESSAGE_MAP()
return PP_ERROR_FAILED;
}
+int32_t PepperTCPSocketMessageFilter::OnMsgBind(
+ const ppapi::host::HostMessageContext* context,
+ const PP_NetAddress_Private& net_addr) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // This is only supported by PPB_TCPSocket v1.1 or above.
+ if (version_ != ppapi::TCP_SOCKET_VERSION_1_1_OR_ABOVE) {
+ NOTREACHED();
+ return PP_ERROR_NOACCESS;
+ }
+
+ bind_input_addr_ = net_addr;
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PepperTCPSocketMessageFilter::DoBind, this,
+ context->MakeReplyMessageContext(), net_addr));
+ return PP_OK_COMPLETIONPENDING;
+}
+
int32_t PepperTCPSocketMessageFilter::OnMsgConnect(
const ppapi::host::HostMessageContext* context,
const std::string& host,
@@ -140,7 +195,7 @@ int32_t PepperTCPSocketMessageFilter::OnMsgConnect(
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// This is only supported by PPB_TCPSocket_Private.
- if (!private_api_) {
+ if (!IsPrivateAPI()) {
NOTREACHED();
return PP_ERROR_NOACCESS;
}
@@ -148,9 +203,9 @@ int32_t PepperTCPSocketMessageFilter::OnMsgConnect(
SocketPermissionRequest request(SocketPermissionRequest::TCP_CONNECT,
host,
port);
- if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_, private_api_,
- request, render_process_id_,
- render_view_id_)) {
+ if (!pepper_socket_utils::CanUseSocketAPIs(
+ external_plugin_, true /* private_api */, request, render_process_id_,
+ render_view_id_)) {
return PP_ERROR_NOACCESS;
}
@@ -178,7 +233,7 @@ int32_t PepperTCPSocketMessageFilter::OnMsgConnectWithNetAddress(
content::SocketPermissionRequest request =
pepper_socket_utils::CreateSocketPermissionRequest(
content::SocketPermissionRequest::TCP_CONNECT, net_addr);
- if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_, private_api_,
+ if (!pepper_socket_utils::CanUseSocketAPIs(external_plugin_, IsPrivateAPI(),
request, render_process_id_,
render_view_id_)) {
return PP_ERROR_NOACCESS;
@@ -201,18 +256,19 @@ int32_t PepperTCPSocketMessageFilter::OnMsgSSLHandshake(
// Allow to do SSL handshake only if currently the socket has been connected
// and there isn't pending read or write.
- // IsConnected() includes the state that SSL handshake has been finished and
- // therefore isn't suitable here.
- if (state_ != STATE_CONNECTED || read_buffer_.get() ||
- write_buffer_base_.get() || write_buffer_.get()) {
+ if (!state_.IsValidTransition(TCPSocketState::SSL_CONNECT) ||
+ read_buffer_.get() || write_buffer_base_.get() || write_buffer_.get()) {
return PP_ERROR_FAILED;
}
- SetState(STATE_SSL_HANDSHAKE_IN_PROGRESS);
// TODO(raymes,rsleevi): Use trusted/untrusted certificates when connecting.
+ net::IPEndPoint peer_address;
+ if (socket_->GetPeerAddress(&peer_address) != net::OK)
+ return PP_ERROR_FAILED;
scoped_ptr<net::ClientSocketHandle> handle(new net::ClientSocketHandle());
- handle->SetSocket(socket_.Pass());
+ handle->SetSocket(make_scoped_ptr<net::StreamSocket>(
+ new net::TCPClientSocket(socket_.Pass(), peer_address)));
net::ClientSocketFactory* factory =
net::ClientSocketFactory::GetDefaultFactory();
net::HostPortPair host_port_pair(server_name, server_port);
@@ -220,17 +276,20 @@ int32_t PepperTCPSocketMessageFilter::OnMsgSSLHandshake(
ssl_context.cert_verifier = ssl_context_helper_->GetCertVerifier();
ssl_context.transport_security_state =
ssl_context_helper_->GetTransportSecurityState();
- socket_ = factory->CreateSSLClientSocket(
+ ssl_socket_ = factory->CreateSSLClientSocket(
handle.Pass(), host_port_pair, ssl_context_helper_->ssl_config(),
ssl_context);
- if (!socket_) {
+ if (!ssl_socket_) {
LOG(WARNING) << "Failed to create an SSL client socket.";
+ state_.CompletePendingTransition(false);
return PP_ERROR_FAILED;
}
+ state_.SetPendingTransition(TCPSocketState::SSL_CONNECT);
+
const ppapi::host::ReplyMessageContext reply_context(
context->MakeReplyMessageContext());
- int net_result = socket_->Connect(
+ int net_result = ssl_socket_->Connect(
base::Bind(&PepperTCPSocketMessageFilter::OnSSLHandshakeCompleted,
base::Unretained(this), reply_context));
if (net_result != net::ERR_IO_PENDING)
@@ -242,7 +301,7 @@ int32_t PepperTCPSocketMessageFilter::OnMsgRead(
const ppapi::host::HostMessageContext* context,
int32_t bytes_to_read) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!IsConnected() || end_of_file_reached_)
+ if (!state_.IsConnected() || end_of_file_reached_)
return PP_ERROR_FAILED;
if (read_buffer_.get())
return PP_ERROR_INPROGRESS;
@@ -254,11 +313,23 @@ int32_t PepperTCPSocketMessageFilter::OnMsgRead(
ppapi::host::ReplyMessageContext reply_context(
context->MakeReplyMessageContext());
read_buffer_ = new net::IOBuffer(bytes_to_read);
- int net_result = socket_->Read(
- read_buffer_.get(),
- bytes_to_read,
- base::Bind(&PepperTCPSocketMessageFilter::OnReadCompleted,
- base::Unretained(this), reply_context));
+
+ int net_result = net::ERR_FAILED;
+ if (socket_) {
+ DCHECK_EQ(state_.state(), TCPSocketState::CONNECTED);
+ net_result = socket_->Read(
+ read_buffer_.get(),
+ bytes_to_read,
+ base::Bind(&PepperTCPSocketMessageFilter::OnReadCompleted,
+ base::Unretained(this), reply_context));
+ } else if (ssl_socket_) {
+ DCHECK_EQ(state_.state(), TCPSocketState::SSL_CONNECTED);
+ net_result = ssl_socket_->Read(
+ read_buffer_.get(),
+ bytes_to_read,
+ base::Bind(&PepperTCPSocketMessageFilter::OnReadCompleted,
+ base::Unretained(this), reply_context));
+ }
if (net_result != net::ERR_IO_PENDING)
OnReadCompleted(reply_context, net_result);
return PP_OK_COMPLETIONPENDING;
@@ -269,7 +340,7 @@ int32_t PepperTCPSocketMessageFilter::OnMsgWrite(
const std::string& data) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!IsConnected())
+ if (!state_.IsConnected())
return PP_ERROR_FAILED;
if (write_buffer_base_.get() || write_buffer_.get())
return PP_ERROR_INPROGRESS;
@@ -288,10 +359,68 @@ int32_t PepperTCPSocketMessageFilter::OnMsgWrite(
return PP_OK_COMPLETIONPENDING;
}
-int32_t PepperTCPSocketMessageFilter::OnMsgDisconnect(
+int32_t PepperTCPSocketMessageFilter::OnMsgListen(
+ const ppapi::host::HostMessageContext* context,
+ int32_t backlog) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ // This is only supported by PPB_TCPSocket v1.1 or above.
+ if (version_ != ppapi::TCP_SOCKET_VERSION_1_1_OR_ABOVE) {
+ NOTREACHED();
+ return PP_ERROR_NOACCESS;
+ }
+
+ content::SocketPermissionRequest request =
+ pepper_socket_utils::CreateSocketPermissionRequest(
+ content::SocketPermissionRequest::TCP_LISTEN, bind_input_addr_);
+ if (!pepper_socket_utils::CanUseSocketAPIs(
+ external_plugin_, false /* private_api */, request,
+ render_process_id_, render_view_id_)) {
+ return PP_ERROR_NOACCESS;
+ }
+
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&PepperTCPSocketMessageFilter::DoListen, this,
+ context->MakeReplyMessageContext(), backlog));
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperTCPSocketMessageFilter::OnMsgAccept(
const ppapi::host::HostMessageContext* context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- SetState(STATE_CLOSED);
+
+ if (pending_accept_)
+ return PP_ERROR_INPROGRESS;
+ if (state_.state() != TCPSocketState::LISTENING)
+ return PP_ERROR_FAILED;
+
+ pending_accept_ = true;
+ ppapi::host::ReplyMessageContext reply_context(
+ context->MakeReplyMessageContext());
+ int net_result = socket_->Accept(
+ &accepted_socket_,
+ &accepted_address_,
+ base::Bind(&PepperTCPSocketMessageFilter::OnAcceptCompleted,
+ base::Unretained(this), reply_context));
+ if (net_result != net::ERR_IO_PENDING)
+ OnAcceptCompleted(reply_context, net_result);
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t PepperTCPSocketMessageFilter::OnMsgClose(
+ const ppapi::host::HostMessageContext* context) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (state_.state() == TCPSocketState::CLOSED)
+ return PP_OK;
+
+ state_.DoTransition(TCPSocketState::CLOSE, true);
+ // Make sure we get no further callbacks from |socket_| or |ssl_socket_|.
+ if (socket_) {
+ socket_->Close();
+ } else if (ssl_socket_) {
+ ssl_socket_->Disconnect();
+ }
return PP_OK;
}
@@ -301,22 +430,21 @@ int32_t PepperTCPSocketMessageFilter::OnMsgSetOption(
const ppapi::SocketOptionData& value) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (!IsConnected() || IsSsl())
- return PP_ERROR_FAILED;
-
- net::TCPClientSocket* tcp_socket =
- static_cast<net::TCPClientSocket*>(socket_.get());
- DCHECK(tcp_socket);
-
switch (name) {
case PP_TCPSOCKET_OPTION_NO_DELAY: {
+ if (state_.state() != TCPSocketState::CONNECTED)
+ return PP_ERROR_FAILED;
+
bool boolean_value = false;
if (!value.GetBool(&boolean_value))
return PP_ERROR_BADARGUMENT;
- return tcp_socket->SetNoDelay(boolean_value) ? PP_OK : PP_ERROR_FAILED;
+ return socket_->SetNoDelay(boolean_value) ? PP_OK : PP_ERROR_FAILED;
}
case PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE:
case PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE: {
+ if (state_.state() != TCPSocketState::CONNECTED)
+ return PP_ERROR_FAILED;
+
int32_t integer_value = 0;
if (!value.GetInt32(&integer_value) || integer_value <= 0)
return PP_ERROR_BADARGUMENT;
@@ -325,20 +453,91 @@ int32_t PepperTCPSocketMessageFilter::OnMsgSetOption(
if (name == PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE) {
if (integer_value > TCPSocketResourceBase::kMaxSendBufferSize)
return PP_ERROR_BADARGUMENT;
- result = tcp_socket->SetSendBufferSize(integer_value);
+ result = socket_->SetSendBufferSize(integer_value);
} else {
if (integer_value > TCPSocketResourceBase::kMaxReceiveBufferSize)
return PP_ERROR_BADARGUMENT;
- result = tcp_socket->SetReceiveBufferSize(integer_value);
+ result = socket_->SetReceiveBufferSize(integer_value);
}
return result ? PP_OK : PP_ERROR_FAILED;
}
+ case PP_TCPSOCKET_OPTION_ADDRESS_REUSE: {
+ if (version_ != ppapi::TCP_SOCKET_VERSION_1_1_OR_ABOVE)
+ return PP_ERROR_NOTSUPPORTED;
+ if (state_.state() != TCPSocketState::INITIAL)
+ return PP_ERROR_FAILED;
+
+ bool boolean_value = false;
+ if (!value.GetBool(&boolean_value))
+ return PP_ERROR_BADARGUMENT;
+ allow_address_reuse_ = boolean_value;
+ return PP_OK;
+ }
default: {
NOTREACHED();
return PP_ERROR_BADARGUMENT;
}
}
- return PP_ERROR_FAILED;
+}
+
+void PepperTCPSocketMessageFilter::DoBind(
+ const ppapi::host::ReplyMessageContext& context,
+ const PP_NetAddress_Private& net_addr) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (state_.IsPending(TCPSocketState::BIND)) {
+ SendBindError(context, PP_ERROR_INPROGRESS);
+ return;
+ }
+ if (!state_.IsValidTransition(TCPSocketState::BIND)) {
+ SendBindError(context, PP_ERROR_FAILED);
+ return;
+ }
+
+ int pp_result = PP_OK;
+ do {
+ net::IPAddressNumber address;
+ int port;
+ if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(net_addr, &address,
+ &port)) {
+ pp_result = PP_ERROR_ADDRESS_INVALID;
+ break;
+ }
+ net::IPEndPoint bind_addr(address, port);
+
+ DCHECK(!socket_->IsValid());
+ pp_result = NetErrorToPepperError(OpenSocket(bind_addr.GetFamily()));
+ if (pp_result != PP_OK)
+ break;
+
+ pp_result = NetErrorToPepperError(socket_->Bind(bind_addr));
+ if (pp_result != PP_OK)
+ break;
+
+ net::IPEndPoint ip_end_point_local;
+ pp_result = NetErrorToPepperError(
+ socket_->GetLocalAddress(&ip_end_point_local));
+ if (pp_result != PP_OK)
+ break;
+
+ PP_NetAddress_Private local_addr =
+ NetAddressPrivateImpl::kInvalidNetAddress;
+ if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
+ ip_end_point_local.address(),
+ ip_end_point_local.port(),
+ &local_addr)) {
+ pp_result = PP_ERROR_ADDRESS_INVALID;
+ break;
+ }
+
+ SendBindReply(context, PP_OK, local_addr);
+ state_.DoTransition(TCPSocketState::BIND, true);
+ return;
+ } while (false);
+ if (socket_->IsValid())
+ socket_->Close();
+ SendBindError(context, pp_result);
+ state_.DoTransition(TCPSocketState::BIND, false);
}
void PepperTCPSocketMessageFilter::DoConnect(
@@ -348,12 +547,12 @@ void PepperTCPSocketMessageFilter::DoConnect(
ResourceContext* resource_context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (state_ != STATE_BEFORE_CONNECT) {
+ if (!state_.IsValidTransition(TCPSocketState::CONNECT)) {
SendConnectError(context, PP_ERROR_FAILED);
return;
}
- SetState(STATE_CONNECT_IN_PROGRESS);
+ state_.SetPendingTransition(TCPSocketState::CONNECT);
net::HostResolver::RequestInfo request_info(net::HostPortPair(host, port));
resolver_.reset(new net::SingleRequestHostResolver(
resource_context->GetHostResolver()));
@@ -373,15 +572,18 @@ void PepperTCPSocketMessageFilter::DoConnectWithNetAddress(
const PP_NetAddress_Private& net_addr) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (state_ != STATE_BEFORE_CONNECT) {
+ if (!state_.IsValidTransition(TCPSocketState::CONNECT)) {
SendConnectError(context, PP_ERROR_FAILED);
return;
}
+ state_.SetPendingTransition(TCPSocketState::CONNECT);
+
net::IPAddressNumber address;
int port;
if (!NetAddressPrivateImpl::NetAddressToIPEndPoint(net_addr, &address,
&port)) {
+ state_.CompletePendingTransition(false);
SendConnectError(context, PP_ERROR_ADDRESS_INVALID);
return;
}
@@ -389,7 +591,6 @@ void PepperTCPSocketMessageFilter::DoConnectWithNetAddress(
// Copy the single IPEndPoint to address_list_.
address_list_.clear();
address_list_.push_back(net::IPEndPoint(address, port));
- SetState(STATE_CONNECT_IN_PROGRESS);
StartConnect(context);
}
@@ -399,30 +600,61 @@ void PepperTCPSocketMessageFilter::DoWrite(
DCHECK(write_buffer_base_.get());
DCHECK(write_buffer_.get());
DCHECK_GT(write_buffer_->BytesRemaining(), 0);
-
- int net_result = socket_->Write(
- write_buffer_.get(),
- write_buffer_->BytesRemaining(),
- base::Bind(&PepperTCPSocketMessageFilter::OnWriteCompleted,
- base::Unretained(this), context));
+ DCHECK(state_.IsConnected());
+
+ int net_result = net::ERR_FAILED;
+ if (socket_) {
+ DCHECK_EQ(state_.state(), TCPSocketState::CONNECTED);
+ net_result = socket_->Write(
+ write_buffer_.get(),
+ write_buffer_->BytesRemaining(),
+ base::Bind(&PepperTCPSocketMessageFilter::OnWriteCompleted,
+ base::Unretained(this), context));
+ } else if (ssl_socket_) {
+ DCHECK_EQ(state_.state(), TCPSocketState::SSL_CONNECTED);
+ net_result = ssl_socket_->Write(
+ write_buffer_.get(),
+ write_buffer_->BytesRemaining(),
+ base::Bind(&PepperTCPSocketMessageFilter::OnWriteCompleted,
+ base::Unretained(this), context));
+ }
if (net_result != net::ERR_IO_PENDING)
OnWriteCompleted(context, net_result);
}
+void PepperTCPSocketMessageFilter::DoListen(
+ const ppapi::host::ReplyMessageContext& context,
+ int32_t backlog) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (state_.IsPending(TCPSocketState::LISTEN)) {
+ SendListenReply(context, PP_ERROR_INPROGRESS);
+ return;
+ }
+ if (!state_.IsValidTransition(TCPSocketState::LISTEN)) {
+ SendListenReply(context, PP_ERROR_FAILED);
+ return;
+ }
+
+ int32_t pp_result = NetErrorToPepperError(socket_->Listen(backlog));
+ SendListenReply(context, pp_result);
+ state_.DoTransition(TCPSocketState::LISTEN, pp_result == PP_OK);
+}
+
void PepperTCPSocketMessageFilter::OnResolveCompleted(
const ppapi::host::ReplyMessageContext& context,
int net_result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (state_ != STATE_CONNECT_IN_PROGRESS) {
+ if (!state_.IsPending(TCPSocketState::CONNECT)) {
+ DCHECK(state_.state() == TCPSocketState::CLOSED);
SendConnectError(context, PP_ERROR_FAILED);
- SetState(STATE_CLOSED);
return;
}
if (net_result != net::OK) {
SendConnectError(context, NetErrorToPepperError(net_result));
- SetState(STATE_BEFORE_CONNECT);
+ state_.CompletePendingTransition(false);
return;
}
@@ -432,18 +664,18 @@ void PepperTCPSocketMessageFilter::OnResolveCompleted(
void PepperTCPSocketMessageFilter::StartConnect(
const ppapi::host::ReplyMessageContext& context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(state_.IsPending(TCPSocketState::CONNECT));
- if (state_ != STATE_CONNECT_IN_PROGRESS) {
- SendConnectError(context, PP_ERROR_FAILED);
- SetState(STATE_CLOSED);
- return;
- }
+ int net_result = net::OK;
+ if (!socket_->IsValid())
+ net_result = OpenSocket(address_list_[0].GetFamily());
- socket_.reset(new net::TCPClientSocket(address_list_, NULL,
- net::NetLog::Source()));
- int net_result = socket_->Connect(
- base::Bind(&PepperTCPSocketMessageFilter::OnConnectCompleted,
- base::Unretained(this), context));
+ if (net_result == net::OK) {
+ net_result = socket_->Connect(
+ address_list_[0],
+ base::Bind(&PepperTCPSocketMessageFilter::OnConnectCompleted,
+ base::Unretained(this), context));
+ }
if (net_result != net::ERR_IO_PENDING)
OnConnectCompleted(context, net_result);
}
@@ -452,11 +684,10 @@ void PepperTCPSocketMessageFilter::OnConnectCompleted(
const ppapi::host::ReplyMessageContext& context,
int net_result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- DCHECK(socket_.get());
- if (state_ != STATE_CONNECT_IN_PROGRESS) {
+ if (!state_.IsPending(TCPSocketState::CONNECT)) {
+ DCHECK(state_.state() == TCPSocketState::CLOSED);
SendConnectError(context, PP_ERROR_FAILED);
- SetState(STATE_CLOSED);
return;
}
@@ -492,13 +723,24 @@ void PepperTCPSocketMessageFilter::OnConnectCompleted(
break;
}
+ socket_->SetDefaultOptionsForClient();
SendConnectReply(context, PP_OK, local_addr, remote_addr);
- SetState(STATE_CONNECTED);
+ state_.CompletePendingTransition(true);
return;
} while (false);
SendConnectError(context, pp_result);
- SetState(STATE_BEFORE_CONNECT);
+ if (version_ == ppapi::TCP_SOCKET_VERSION_1_1_OR_ABOVE) {
+ state_.CompletePendingTransition(false);
+ } else {
+ // In order to maintain backward compatibility, allow further attempts to
+ // connect the socket.
+ state_ = TCPSocketState(TCPSocketState::INITIAL);
+ // We have to recreate |socket_| because it doesn't allow a second connect
+ // attempt. We won't lose any state such as bound address or set options,
+ // because in the private or v1.0 API, connect must be the first operation.
+ socket_.reset(new net::TCPSocket(NULL, net::NetLog::Source()));
+ }
}
void PepperTCPSocketMessageFilter::OnSSLHandshakeCompleted(
@@ -506,15 +748,14 @@ void PepperTCPSocketMessageFilter::OnSSLHandshakeCompleted(
int net_result) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
- if (state_ != STATE_SSL_HANDSHAKE_IN_PROGRESS) {
+ if (!state_.IsPending(TCPSocketState::SSL_CONNECT)) {
+ DCHECK(state_.state() == TCPSocketState::CLOSED);
SendSSLHandshakeReply(context, PP_ERROR_FAILED);
- SetState(STATE_CLOSED);
return;
}
+
SendSSLHandshakeReply(context, NetErrorToPepperError(net_result));
- SetState(net_result == net::OK ?
- STATE_SSL_CONNECTED :
- STATE_SSL_HANDSHAKE_FAILED);
+ state_.CompletePendingTransition(net_result == net::OK);
}
void PepperTCPSocketMessageFilter::OnReadCompleted(
@@ -547,7 +788,7 @@ void PepperTCPSocketMessageFilter::OnWriteCompleted(
// likely infinite loop.
if (net_result > 0) {
write_buffer_->DidConsume(net_result);
- if (write_buffer_->BytesRemaining() > 0) {
+ if (write_buffer_->BytesRemaining() > 0 && state_.IsConnected()) {
DoWrite(context);
return;
}
@@ -562,6 +803,76 @@ void PepperTCPSocketMessageFilter::OnWriteCompleted(
write_buffer_base_ = NULL;
}
+void PepperTCPSocketMessageFilter::OnAcceptCompleted(
+ const ppapi::host::ReplyMessageContext& context,
+ int net_result) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK(pending_accept_);
+
+ pending_accept_ = false;
+
+ if (net_result != net::OK) {
+ SendAcceptError(context, NetErrorToPepperError(net_result));
+ return;
+ }
+
+ DCHECK(accepted_socket_.get());
+
+ net::IPEndPoint ip_end_point_local;
+ PP_NetAddress_Private local_addr = NetAddressPrivateImpl::kInvalidNetAddress;
+ PP_NetAddress_Private remote_addr = NetAddressPrivateImpl::kInvalidNetAddress;
+
+ int32_t pp_result =
+ NetErrorToPepperError(accepted_socket_->GetLocalAddress(
+ &ip_end_point_local));
+ if (pp_result != PP_OK) {
+ SendAcceptError(context, pp_result);
+ return;
+ }
+ if (!NetAddressPrivateImpl::IPEndPointToNetAddress(
+ ip_end_point_local.address(),
+ ip_end_point_local.port(),
+ &local_addr) ||
+ !NetAddressPrivateImpl::IPEndPointToNetAddress(
+ accepted_address_.address(),
+ accepted_address_.port(),
+ &remote_addr)) {
+ SendAcceptError(context, PP_ERROR_ADDRESS_INVALID);
+ return;
+ }
+
+ // |factory_| is guaranteed to be non-NULL here. Only those instances created
+ // in CONNECTED state have a NULL |factory_|, while getting here requires
+ // LISTENING state.
+ scoped_ptr<ppapi::host::ResourceHost> host =
+ factory_->CreateAcceptedTCPSocket(
+ instance_, version_, accepted_socket_.Pass());
+ if (!host) {
+ SendAcceptError(context, PP_ERROR_NOSPACE);
+ return;
+ }
+ int pending_host_id = ppapi_host_->AddPendingResourceHost(host.Pass());
+ if (pending_host_id)
+ SendAcceptReply(context, PP_OK, pending_host_id, local_addr, remote_addr);
+ else
+ SendAcceptError(context, PP_ERROR_NOSPACE);
+}
+
+void PepperTCPSocketMessageFilter::SendBindReply(
+ const ppapi::host::ReplyMessageContext& context,
+ int32_t pp_result,
+ const PP_NetAddress_Private& local_addr) {
+ ppapi::host::ReplyMessageContext reply_context(context);
+ reply_context.params.set_result(pp_result);
+ SendReply(reply_context, PpapiPluginMsg_TCPSocket_BindReply(local_addr));
+}
+
+void PepperTCPSocketMessageFilter::SendBindError(
+ const ppapi::host::ReplyMessageContext& context,
+ int32_t pp_error) {
+ SendBindReply(context, pp_error, NetAddressPrivateImpl::kInvalidNetAddress);
+}
+
void PepperTCPSocketMessageFilter::SendConnectReply(
const ppapi::host::ReplyMessageContext& context,
int32_t pp_result,
@@ -590,10 +901,8 @@ void PepperTCPSocketMessageFilter::SendSSLHandshakeReply(
ppapi::PPB_X509Certificate_Fields certificate_fields;
if (pp_result == PP_OK) {
// Our socket is guaranteed to be an SSL socket if we get here.
- net::SSLClientSocket* ssl_socket =
- static_cast<net::SSLClientSocket*>(socket_.get());
net::SSLInfo ssl_info;
- ssl_socket->GetSSLInfo(&ssl_info);
+ ssl_socket_->GetSSLInfo(&ssl_info);
if (ssl_info.cert.get()) {
pepper_socket_utils::GetCertificateFields(*ssl_info.cert.get(),
&certificate_fields);
@@ -626,23 +935,49 @@ void PepperTCPSocketMessageFilter::SendWriteReply(
SendReply(reply_context, PpapiPluginMsg_TCPSocket_WriteReply());
}
-bool PepperTCPSocketMessageFilter::IsConnected() const {
- return state_ == STATE_CONNECTED || state_ == STATE_SSL_CONNECTED;
+void PepperTCPSocketMessageFilter::SendListenReply(
+ const ppapi::host::ReplyMessageContext& context,
+ int32_t pp_result) {
+ ppapi::host::ReplyMessageContext reply_context(context);
+ reply_context.params.set_result(pp_result);
+ SendReply(reply_context, PpapiPluginMsg_TCPSocket_ListenReply());
+}
+
+void PepperTCPSocketMessageFilter::SendAcceptReply(
+ const ppapi::host::ReplyMessageContext& context,
+ int32_t pp_result,
+ int pending_host_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr) {
+ ppapi::host::ReplyMessageContext reply_context(context);
+ reply_context.params.set_result(pp_result);
+ SendReply(reply_context,
+ PpapiPluginMsg_TCPSocket_AcceptReply(
+ pending_host_id, local_addr, remote_addr));
}
-bool PepperTCPSocketMessageFilter::IsSsl() const {
- return state_ == STATE_SSL_HANDSHAKE_IN_PROGRESS ||
- state_ == STATE_SSL_CONNECTED ||
- state_ == STATE_SSL_HANDSHAKE_FAILED;
+void PepperTCPSocketMessageFilter::SendAcceptError(
+ const ppapi::host::ReplyMessageContext& context,
+ int32_t pp_error) {
+ SendAcceptReply(context, pp_error, 0,
+ NetAddressPrivateImpl::kInvalidNetAddress,
+ NetAddressPrivateImpl::kInvalidNetAddress);
}
-void PepperTCPSocketMessageFilter::SetState(State state) {
- state_ = state;
- if (state_ == STATE_CLOSED && socket_) {
- // Make sure no further callbacks from socket_.
- socket_->Disconnect();
- socket_.reset();
+int PepperTCPSocketMessageFilter::OpenSocket(net::AddressFamily family) {
+ int net_error = socket_->Open(family);
+ if (net_error != net::OK)
+ return net_error;
+
+ // TODO(yzshen): Handle it for Windows.
+#if defined(POSIX)
+ if (allow_address_reuse_) {
+ net_error = socket_->SetAddressReuse(true);
+ LOG_IF(WARNING, net_error != net::OK) << "SetAddressReuse() failed.";
}
+#endif
+
+ return net::OK;
}
} // namespace content
diff --git a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
index 84e8a75..01947ec 100644
--- a/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
+++ b/content/browser/renderer_host/pepper/pepper_tcp_socket_message_filter.h
@@ -15,23 +15,27 @@
#include "content/browser/renderer_host/pepper/ssl_context_helper.h"
#include "content/common/content_export.h"
#include "net/base/address_list.h"
+#include "net/base/ip_endpoint.h"
+#include "net/socket/tcp_socket.h"
#include "ppapi/c/pp_instance.h"
#include "ppapi/c/ppb_tcp_socket.h"
+#include "ppapi/c/private/ppb_net_address_private.h"
#include "ppapi/host/resource_message_filter.h"
-
-struct PP_NetAddress_Private;
+#include "ppapi/shared_impl/ppb_tcp_socket_shared.h"
namespace net {
+enum AddressFamily;
class DrainableIOBuffer;
class IOBuffer;
class SingleRequestHostResolver;
-class StreamSocket;
+class SSLClientSocket;
}
namespace ppapi {
class SocketOptionData;
namespace host {
+class PpapiHost;
struct ReplyMessageContext;
}
}
@@ -39,47 +43,29 @@ struct ReplyMessageContext;
namespace content {
class BrowserPpapiHostImpl;
+class ContentBrowserPepperHostFactory;
class ResourceContext;
class CONTENT_EXPORT PepperTCPSocketMessageFilter
: public ppapi::host::ResourceMessageFilter {
public:
PepperTCPSocketMessageFilter(
+ ContentBrowserPepperHostFactory* factory,
BrowserPpapiHostImpl* host,
PP_Instance instance,
- bool private_api);
+ ppapi::TCPSocketVersion version);
- // Used for creating already connected sockets. Takes ownership of
- // |socket|.
+ // Used for creating already connected sockets.
PepperTCPSocketMessageFilter(
BrowserPpapiHostImpl* host,
PP_Instance instance,
- bool private_api,
- net::StreamSocket* socket);
+ ppapi::TCPSocketVersion version,
+ scoped_ptr<net::TCPSocket> socket);
static size_t GetNumInstances();
- protected:
- virtual ~PepperTCPSocketMessageFilter();
-
private:
- enum State {
- // Before a connection is successfully established (including a previous
- // connect request failed).
- STATE_BEFORE_CONNECT,
- // There is a connect request that is pending.
- STATE_CONNECT_IN_PROGRESS,
- // A connection has been successfully established.
- STATE_CONNECTED,
- // There is an SSL handshake request that is pending.
- STATE_SSL_HANDSHAKE_IN_PROGRESS,
- // An SSL connection has been successfully established.
- STATE_SSL_CONNECTED,
- // An SSL handshake has failed.
- STATE_SSL_HANDSHAKE_FAILED,
- // Socket is closed.
- STATE_CLOSED
- };
+ virtual ~PepperTCPSocketMessageFilter();
// ppapi::host::ResourceMessageFilter overrides.
virtual scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
@@ -88,6 +74,8 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
const IPC::Message& msg,
ppapi::host::HostMessageContext* context) OVERRIDE;
+ int32_t OnMsgBind(const ppapi::host::HostMessageContext* context,
+ const PP_NetAddress_Private& net_addr);
int32_t OnMsgConnect(const ppapi::host::HostMessageContext* context,
const std::string& host,
uint16_t port);
@@ -104,11 +92,16 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
int32_t bytes_to_read);
int32_t OnMsgWrite(const ppapi::host::HostMessageContext* context,
const std::string& data);
- int32_t OnMsgDisconnect(const ppapi::host::HostMessageContext* context);
+ int32_t OnMsgListen(const ppapi::host::HostMessageContext* context,
+ int32_t backlog);
+ int32_t OnMsgAccept(const ppapi::host::HostMessageContext* context);
+ int32_t OnMsgClose(const ppapi::host::HostMessageContext* context);
int32_t OnMsgSetOption(const ppapi::host::HostMessageContext* context,
PP_TCPSocket_Option name,
const ppapi::SocketOptionData& value);
+ void DoBind(const ppapi::host::ReplyMessageContext& context,
+ const PP_NetAddress_Private& net_addr);
void DoConnect(const ppapi::host::ReplyMessageContext& context,
const std::string& host,
uint16_t port,
@@ -117,6 +110,8 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
const ppapi::host::ReplyMessageContext& context,
const PP_NetAddress_Private& net_addr);
void DoWrite(const ppapi::host::ReplyMessageContext& context);
+ void DoListen(const ppapi::host::ReplyMessageContext& context,
+ int32_t backlog);
void OnResolveCompleted(const ppapi::host::ReplyMessageContext& context,
int net_result);
@@ -130,7 +125,14 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
int net_result);
void OnWriteCompleted(const ppapi::host::ReplyMessageContext& context,
int net_result);
+ void OnAcceptCompleted(const ppapi::host::ReplyMessageContext& context,
+ int net_result);
+ void SendBindReply(const ppapi::host::ReplyMessageContext& context,
+ int32_t pp_result,
+ const PP_NetAddress_Private& local_addr);
+ void SendBindError(const ppapi::host::ReplyMessageContext& context,
+ int32_t pp_error);
void SendConnectReply(const ppapi::host::ReplyMessageContext& context,
int32_t pp_result,
const PP_NetAddress_Private& local_addr,
@@ -146,28 +148,57 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
int32_t pp_error);
void SendWriteReply(const ppapi::host::ReplyMessageContext& context,
int32_t pp_result);
+ void SendListenReply(const ppapi::host::ReplyMessageContext& context,
+ int32_t pp_result);
+ void SendAcceptReply(const ppapi::host::ReplyMessageContext& context,
+ int32_t pp_result,
+ int pending_host_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr);
+ void SendAcceptError(const ppapi::host::ReplyMessageContext& context,
+ int32_t pp_error);
- bool IsConnected() const;
- bool IsSsl() const;
- void SetState(State state);
+ int32_t OpenSocket(net::AddressFamily family);
- bool external_plugin_;
- bool private_api_;
+ bool IsPrivateAPI() const {
+ return version_ == ppapi::TCP_SOCKET_VERSION_PRIVATE;
+ }
+
+ // The following fields are used on both the UI and IO thread.
+ const ppapi::TCPSocketVersion version_;
+
+ // The following fields are used only on the UI thread.
+ const bool external_plugin_;
int render_process_id_;
int render_view_id_;
- State state_;
+ // The following fields are used only on the IO thread.
+ // Non-owning ptr.
+ ppapi::host::PpapiHost* ppapi_host_;
+ // Non-owning ptr.
+ ContentBrowserPepperHostFactory* factory_;
+ PP_Instance instance_;
+
+ ppapi::TCPSocketState state_;
bool end_of_file_reached_;
+ // This is the address requested to bind. Please note that this is not the
+ // bound address. For example, |bind_input_addr_| may have port set to 0.
+ // It is used to check permission for listening.
+ PP_NetAddress_Private bind_input_addr_;
+
scoped_ptr<net::SingleRequestHostResolver> resolver_;
net::AddressList address_list_;
- scoped_ptr<net::StreamSocket> socket_;
+ // Non-null unless an SSL connection is requested.
+ scoped_ptr<net::TCPSocket> socket_;
+ // Non-null if an SSL connection is requested.
+ scoped_ptr<net::SSLClientSocket> ssl_socket_;
scoped_refptr<net::IOBuffer> read_buffer_;
- // StreamSocket::Write() may not always write the full buffer, but we would
+ // TCPSocket::Write() may not always write the full buffer, but we would
// rather have our DoWrite() do so whenever possible. To do this, we may have
// to call the former multiple times for each of the latter. This entails
// using a DrainableIOBuffer, which requires an underlying base IOBuffer.
@@ -175,6 +206,12 @@ class CONTENT_EXPORT PepperTCPSocketMessageFilter
scoped_refptr<net::DrainableIOBuffer> write_buffer_;
scoped_refptr<SSLContextHelper> ssl_context_helper_;
+ bool pending_accept_;
+ scoped_ptr<net::TCPSocket> accepted_socket_;
+ net::IPEndPoint accepted_address_;
+
+ bool allow_address_reuse_;
+
DISALLOW_COPY_AND_ASSIGN(PepperTCPSocketMessageFilter);
};
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index f62174e..82b077b 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -1519,6 +1519,7 @@
['enable_plugins==1', {
'dependencies': [
'../ppapi/ppapi_internal.gyp:ppapi_ipc',
+ '../ppapi/ppapi_internal.gyp:ppapi_shared',
],
}, { # enable_plugins==0
'sources!': [
diff --git a/content/renderer/pepper/resource_creation_impl.cc b/content/renderer/pepper/resource_creation_impl.cc
index 42fd413..cef6fd3 100644
--- a/content/renderer/pepper/resource_creation_impl.cc
+++ b/content/renderer/pepper/resource_creation_impl.cc
@@ -245,6 +245,10 @@ PP_Resource ResourceCreationImpl::CreateTCPServerSocketPrivate(
return 0; // Not supported in-process.
}
+PP_Resource ResourceCreationImpl::CreateTCPSocket1_0(PP_Instance instance) {
+ return 0; // Not supported in-process.
+}
+
PP_Resource ResourceCreationImpl::CreateTCPSocket(PP_Instance instance) {
return 0; // Not supported in-process.
}
diff --git a/content/renderer/pepper/resource_creation_impl.h b/content/renderer/pepper/resource_creation_impl.h
index ace9935..adb7e5c 100644
--- a/content/renderer/pepper/resource_creation_impl.h
+++ b/content/renderer/pepper/resource_creation_impl.h
@@ -114,6 +114,7 @@ class ResourceCreationImpl : public ppapi::thunk::ResourceCreationAPI {
virtual PP_Resource CreateTalk(PP_Instance instance) OVERRIDE;
virtual PP_Resource CreateTCPServerSocketPrivate(
PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateTCPSocket1_0(PP_Instance instance) OVERRIDE;
virtual PP_Resource CreateTCPSocket(PP_Instance instance) OVERRIDE;
virtual PP_Resource CreateTCPSocketPrivate(PP_Instance instance) OVERRIDE;
virtual PP_Resource CreateUDPSocket(PP_Instance instance) OVERRIDE;
diff --git a/ppapi/api/ppb_tcp_socket.idl b/ppapi/api/ppb_tcp_socket.idl
index 833879c..6c43712 100644
--- a/ppapi/api/ppb_tcp_socket.idl
+++ b/ppapi/api/ppb_tcp_socket.idl
@@ -7,10 +7,9 @@
* This file defines the <code>PPB_TCPSocket</code> interface.
*/
-[generate_thunk]
-
label Chrome {
- M29 = 1.0
+ M29 = 1.0,
+ M31 = 1.1
};
/**
@@ -45,14 +44,23 @@ enum PP_TCPSocket_Option {
* size. Even if <code>SetOption()</code> succeeds, the browser doesn't
* guarantee it will conform to the size.
*/
- PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE = 2
+ PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE = 2,
+
+ /**
+ * Allows the socket to share the local address to which it will be bound.
+ * Value's type should be <code>PP_VARTYPE_BOOL</code>.
+ * This option can only be set before calling <code>Bind()</code>.
+ * Supported since version 1.1.
+ */
+ PP_TCPSOCKET_OPTION_ADDRESS_REUSE = 3
};
/**
* The <code>PPB_TCPSocket</code> interface provides TCP socket operations.
*
* Permissions: Apps permission <code>socket</code> with subrule
- * <code>tcp-connect</code> is required for <code>Connect()</code>.
+ * <code>tcp-connect</code> is required for <code>Connect()</code>; subrule
+ * <code>tcp-listen</code> is required for <code>Listen()</code>.
* For more details about network communication permissions, please see:
* http://developer.chrome.com/apps/app_network.html
*/
@@ -79,7 +87,27 @@ interface PPB_TCPSocket {
PP_Bool IsTCPSocket([in] PP_Resource resource);
/**
- * Connects the socket to the given address.
+ * Binds the socket to the given address. The socket must not be bound.
+ *
+ * @param[in] tcp_socket A <code>PP_Resource</code> corresponding to a TCP
+ * socket.
+ * @param[in] addr A <code>PPB_NetAddress</code> resource.
+ * @param[in] callback A <code>PP_CompletionCallback</code> to be called upon
+ * completion.
+ *
+ * @return An int32_t containing an error code from <code>pp_errors.h</code>,
+ * including (but not limited to):
+ * - <code>PP_ERROR_ADDRESS_IN_USE</code>: the address is already in use.
+ * - <code>PP_ERROR_ADDRESS_INVALID</code>: the address is invalid.
+ */
+ [version=1.1]
+ int32_t Bind([in] PP_Resource tcp_socket,
+ [in] PP_Resource addr,
+ [in] PP_CompletionCallback callback);
+
+ /**
+ * Connects the socket to the given address. The socket must not be listening.
+ * Binding the socket beforehand is optional.
*
* @param[in] tcp_socket A <code>PP_Resource</code> corresponding to a TCP
* socket.
@@ -98,13 +126,18 @@ interface PPB_TCPSocket {
* - <code>PP_ERROR_CONNECTION_FAILED</code>: the connection attempt failed.
* - <code>PP_ERROR_CONNECTION_TIMEDOUT</code>: the connection attempt timed
* out.
+ *
+ * If the socket is listening/connected or has a pending listen/connect
+ * request, <code>Connect()</code> will fail without starting a connection
+ * attempt. Otherwise, any failure during the connection attempt will cause
+ * the socket to be closed.
*/
int32_t Connect([in] PP_Resource tcp_socket,
[in] PP_Resource addr,
[in] PP_CompletionCallback callback);
/**
- * Gets the local address of the socket, if it is connected.
+ * Gets the local address of the socket, if it is bound.
*
* @param[in] tcp_socket A <code>PP_Resource</code> corresponding to a TCP
* socket.
@@ -162,13 +195,53 @@ interface PPB_TCPSocket {
[in] str_t buffer,
[in] int32_t bytes_to_write,
[in] PP_CompletionCallback callback);
+ /**
+ * Starts listening. The socket must be bound and not connected.
+ *
+ * @param[in] tcp_socket A <code>PP_Resource</code> corresponding to a TCP
+ * socket.
+ * @param[in] backlog A hint to determine the maximum length to which the
+ * queue of pending connections may grow.
+ * @param[in] callback A <code>PP_CompletionCallback</code> to be called upon
+ * completion.
+ *
+ * @return An int32_t containing an error code from <code>pp_errors.h</code>,
+ * including (but not limited to):
+ * - <code>PP_ERROR_NOACCESS</code>: the caller doesn't have required
+ * permissions.
+ * - <code>PP_ERROR_ADDRESS_IN_USE</code>: Another socket is already listening
+ * on the same port.
+ */
+ [version=1.1]
+ int32_t Listen([in] PP_Resource tcp_socket,
+ [in] int32_t backlog,
+ [in] PP_CompletionCallback callback);
+
+ /**
+ * Accepts a connection. The socket must be listening.
+ *
+ * @param[in] tcp_socket A <code>PP_Resource</code> corresponding to a TCP
+ * socket.
+ * @param[out] accepted_tcp_socket Stores the accepted TCP socket on success.
+ * @param[in] callback A <code>PP_CompletionCallback</code> to be called upon
+ * completion.
+ *
+ * @return An int32_t containing an error code from <code>pp_errors.h</code>,
+ * including (but not limited to):
+ * - <code>PP_ERROR_CONNECTION_ABORTED</code>: A connection has been aborted.
+ */
+ [version=1.1]
+ int32_t Accept([in] PP_Resource tcp_socket,
+ [out] PP_Resource accepted_tcp_socket,
+ [in] PP_CompletionCallback callback);
/**
- * Cancels all pending reads and writes and disconnects the socket. Any
- * pending callbacks will still run, reporting <code>PP_ERROR_ABORTED</code>
- * if pending IO was interrupted. After a call to this method, no output
- * buffer pointers passed into previous <code>Read()</code> calls will be
- * accessed. It is not valid to call <code>Connect()</code> again.
+ * Cancels all pending operations and closes the socket. Any pending callbacks
+ * will still run, reporting <code>PP_ERROR_ABORTED</code> if pending IO was
+ * interrupted. After a call to this method, no output buffer pointers passed
+ * into previous <code>Read()</code> or <code>Accept()</code> calls will be
+ * accessed. It is not valid to call <code>Connect()</code> or
+ * <code>Listen()</code> again.
*
* The socket is implicitly closed if it is destroyed, so you are not required
* to call this method.
diff --git a/ppapi/c/ppb_tcp_socket.h b/ppapi/c/ppb_tcp_socket.h
index 467656f..9a9b964 100644
--- a/ppapi/c/ppb_tcp_socket.h
+++ b/ppapi/c/ppb_tcp_socket.h
@@ -3,7 +3,7 @@
* found in the LICENSE file.
*/
-/* From ppb_tcp_socket.idl modified Sat Jun 22 11:17:34 2013. */
+/* From ppb_tcp_socket.idl modified Thu Sep 19 14:01:43 2013. */
#ifndef PPAPI_C_PPB_TCP_SOCKET_H_
#define PPAPI_C_PPB_TCP_SOCKET_H_
@@ -17,7 +17,8 @@
#include "ppapi/c/pp_var.h"
#define PPB_TCPSOCKET_INTERFACE_1_0 "PPB_TCPSocket;1.0"
-#define PPB_TCPSOCKET_INTERFACE PPB_TCPSOCKET_INTERFACE_1_0
+#define PPB_TCPSOCKET_INTERFACE_1_1 "PPB_TCPSocket;1.1"
+#define PPB_TCPSOCKET_INTERFACE PPB_TCPSOCKET_INTERFACE_1_1
/**
* @file
@@ -58,7 +59,14 @@ typedef enum {
* size. Even if <code>SetOption()</code> succeeds, the browser doesn't
* guarantee it will conform to the size.
*/
- PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE = 2
+ PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE = 2,
+ /**
+ * Allows the socket to share the local address to which it will be bound.
+ * Value's type should be <code>PP_VARTYPE_BOOL</code>.
+ * This option can only be set before calling <code>Bind()</code>.
+ * Supported since version 1.1.
+ */
+ PP_TCPSOCKET_OPTION_ADDRESS_REUSE = 3
} PP_TCPSocket_Option;
PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TCPSocket_Option, 4);
/**
@@ -73,11 +81,12 @@ PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_TCPSocket_Option, 4);
* The <code>PPB_TCPSocket</code> interface provides TCP socket operations.
*
* Permissions: Apps permission <code>socket</code> with subrule
- * <code>tcp-connect</code> is required for <code>Connect()</code>.
+ * <code>tcp-connect</code> is required for <code>Connect()</code>; subrule
+ * <code>tcp-listen</code> is required for <code>Listen()</code>.
* For more details about network communication permissions, please see:
* http://developer.chrome.com/apps/app_network.html
*/
-struct PPB_TCPSocket_1_0 {
+struct PPB_TCPSocket_1_1 {
/**
* Creates a TCP socket resource.
*
@@ -98,7 +107,25 @@ struct PPB_TCPSocket_1_0 {
*/
PP_Bool (*IsTCPSocket)(PP_Resource resource);
/**
- * Connects the socket to the given address.
+ * Binds the socket to the given address. The socket must not be bound.
+ *
+ * @param[in] tcp_socket A <code>PP_Resource</code> corresponding to a TCP
+ * socket.
+ * @param[in] addr A <code>PPB_NetAddress</code> resource.
+ * @param[in] callback A <code>PP_CompletionCallback</code> to be called upon
+ * completion.
+ *
+ * @return An int32_t containing an error code from <code>pp_errors.h</code>,
+ * including (but not limited to):
+ * - <code>PP_ERROR_ADDRESS_IN_USE</code>: the address is already in use.
+ * - <code>PP_ERROR_ADDRESS_INVALID</code>: the address is invalid.
+ */
+ int32_t (*Bind)(PP_Resource tcp_socket,
+ PP_Resource addr,
+ struct PP_CompletionCallback callback);
+ /**
+ * Connects the socket to the given address. The socket must not be listening.
+ * Binding the socket beforehand is optional.
*
* @param[in] tcp_socket A <code>PP_Resource</code> corresponding to a TCP
* socket.
@@ -117,12 +144,17 @@ struct PPB_TCPSocket_1_0 {
* - <code>PP_ERROR_CONNECTION_FAILED</code>: the connection attempt failed.
* - <code>PP_ERROR_CONNECTION_TIMEDOUT</code>: the connection attempt timed
* out.
+ *
+ * If the socket is listening/connected or has a pending listen/connect
+ * request, <code>Connect()</code> will fail without starting a connection
+ * attempt. Otherwise, any failure during the connection attempt will cause
+ * the socket to be closed.
*/
int32_t (*Connect)(PP_Resource tcp_socket,
PP_Resource addr,
struct PP_CompletionCallback callback);
/**
- * Gets the local address of the socket, if it is connected.
+ * Gets the local address of the socket, if it is bound.
*
* @param[in] tcp_socket A <code>PP_Resource</code> corresponding to a TCP
* socket.
@@ -178,11 +210,48 @@ struct PPB_TCPSocket_1_0 {
int32_t bytes_to_write,
struct PP_CompletionCallback callback);
/**
- * Cancels all pending reads and writes and disconnects the socket. Any
- * pending callbacks will still run, reporting <code>PP_ERROR_ABORTED</code>
- * if pending IO was interrupted. After a call to this method, no output
- * buffer pointers passed into previous <code>Read()</code> calls will be
- * accessed. It is not valid to call <code>Connect()</code> again.
+ * Starts listening. The socket must be bound and not connected.
+ *
+ * @param[in] tcp_socket A <code>PP_Resource</code> corresponding to a TCP
+ * socket.
+ * @param[in] backlog A hint to determine the maximum length to which the
+ * queue of pending connections may grow.
+ * @param[in] callback A <code>PP_CompletionCallback</code> to be called upon
+ * completion.
+ *
+ * @return An int32_t containing an error code from <code>pp_errors.h</code>,
+ * including (but not limited to):
+ * - <code>PP_ERROR_NOACCESS</code>: the caller doesn't have required
+ * permissions.
+ * - <code>PP_ERROR_ADDRESS_IN_USE</code>: Another socket is already listening
+ * on the same port.
+ */
+ int32_t (*Listen)(PP_Resource tcp_socket,
+ int32_t backlog,
+ struct PP_CompletionCallback callback);
+ /**
+ * Accepts a connection. The socket must be listening.
+ *
+ * @param[in] tcp_socket A <code>PP_Resource</code> corresponding to a TCP
+ * socket.
+ * @param[out] accepted_tcp_socket Stores the accepted TCP socket on success.
+ * @param[in] callback A <code>PP_CompletionCallback</code> to be called upon
+ * completion.
+ *
+ * @return An int32_t containing an error code from <code>pp_errors.h</code>,
+ * including (but not limited to):
+ * - <code>PP_ERROR_CONNECTION_ABORTED</code>: A connection has been aborted.
+ */
+ int32_t (*Accept)(PP_Resource tcp_socket,
+ PP_Resource* accepted_tcp_socket,
+ struct PP_CompletionCallback callback);
+ /**
+ * Cancels all pending operations and closes the socket. Any pending callbacks
+ * will still run, reporting <code>PP_ERROR_ABORTED</code> if pending IO was
+ * interrupted. After a call to this method, no output buffer pointers passed
+ * into previous <code>Read()</code> or <code>Accept()</code> calls will be
+ * accessed. It is not valid to call <code>Connect()</code> or
+ * <code>Listen()</code> again.
*
* The socket is implicitly closed if it is destroyed, so you are not required
* to call this method.
@@ -211,7 +280,30 @@ struct PPB_TCPSocket_1_0 {
struct PP_CompletionCallback callback);
};
-typedef struct PPB_TCPSocket_1_0 PPB_TCPSocket;
+typedef struct PPB_TCPSocket_1_1 PPB_TCPSocket;
+
+struct PPB_TCPSocket_1_0 {
+ PP_Resource (*Create)(PP_Instance instance);
+ PP_Bool (*IsTCPSocket)(PP_Resource resource);
+ int32_t (*Connect)(PP_Resource tcp_socket,
+ PP_Resource addr,
+ struct PP_CompletionCallback callback);
+ PP_Resource (*GetLocalAddress)(PP_Resource tcp_socket);
+ PP_Resource (*GetRemoteAddress)(PP_Resource tcp_socket);
+ int32_t (*Read)(PP_Resource tcp_socket,
+ char* buffer,
+ int32_t bytes_to_read,
+ struct PP_CompletionCallback callback);
+ int32_t (*Write)(PP_Resource tcp_socket,
+ const char* buffer,
+ int32_t bytes_to_write,
+ struct PP_CompletionCallback callback);
+ void (*Close)(PP_Resource tcp_socket);
+ int32_t (*SetOption)(PP_Resource tcp_socket,
+ PP_TCPSocket_Option name,
+ struct PP_Var value,
+ struct PP_CompletionCallback callback);
+};
/**
* @}
*/
diff --git a/ppapi/cpp/tcp_socket.cc b/ppapi/cpp/tcp_socket.cc
index f0002fa..ab08ff3 100644
--- a/ppapi/cpp/tcp_socket.cc
+++ b/ppapi/cpp/tcp_socket.cc
@@ -17,13 +17,20 @@ template <> const char* interface_name<PPB_TCPSocket_1_0>() {
return PPB_TCPSOCKET_INTERFACE_1_0;
}
+template <> const char* interface_name<PPB_TCPSocket_1_1>() {
+ return PPB_TCPSOCKET_INTERFACE_1_1;
+}
+
} // namespace
TCPSocket::TCPSocket() {
}
TCPSocket::TCPSocket(const InstanceHandle& instance) {
- if (has_interface<PPB_TCPSocket_1_0>()) {
+ if (has_interface<PPB_TCPSocket_1_1>()) {
+ PassRefFromConstructor(get_interface<PPB_TCPSocket_1_1>()->Create(
+ instance.pp_instance()));
+ } else if (has_interface<PPB_TCPSocket_1_0>()) {
PassRefFromConstructor(get_interface<PPB_TCPSocket_1_0>()->Create(
instance.pp_instance()));
}
@@ -46,11 +53,25 @@ TCPSocket& TCPSocket::operator=(const TCPSocket& other) {
// static
bool TCPSocket::IsAvailable() {
- return has_interface<PPB_TCPSocket_1_0>();
+ return has_interface<PPB_TCPSocket_1_1>() ||
+ has_interface<PPB_TCPSocket_1_0>();
+}
+
+int32_t TCPSocket::Bind(const NetAddress& addr,
+ const CompletionCallback& callback) {
+ if (has_interface<PPB_TCPSocket_1_1>()) {
+ return get_interface<PPB_TCPSocket_1_1>()->Bind(
+ pp_resource(), addr.pp_resource(), callback.pp_completion_callback());
+ }
+ return callback.MayForce(PP_ERROR_NOINTERFACE);
}
int32_t TCPSocket::Connect(const NetAddress& addr,
const CompletionCallback& callback) {
+ if (has_interface<PPB_TCPSocket_1_1>()) {
+ return get_interface<PPB_TCPSocket_1_1>()->Connect(
+ pp_resource(), addr.pp_resource(), callback.pp_completion_callback());
+ }
if (has_interface<PPB_TCPSocket_1_0>()) {
return get_interface<PPB_TCPSocket_1_0>()->Connect(
pp_resource(), addr.pp_resource(), callback.pp_completion_callback());
@@ -59,6 +80,11 @@ int32_t TCPSocket::Connect(const NetAddress& addr,
}
NetAddress TCPSocket::GetLocalAddress() const {
+ if (has_interface<PPB_TCPSocket_1_1>()) {
+ return NetAddress(
+ PASS_REF,
+ get_interface<PPB_TCPSocket_1_1>()->GetLocalAddress(pp_resource()));
+ }
if (has_interface<PPB_TCPSocket_1_0>()) {
return NetAddress(
PASS_REF,
@@ -68,6 +94,11 @@ NetAddress TCPSocket::GetLocalAddress() const {
}
NetAddress TCPSocket::GetRemoteAddress() const {
+ if (has_interface<PPB_TCPSocket_1_1>()) {
+ return NetAddress(
+ PASS_REF,
+ get_interface<PPB_TCPSocket_1_1>()->GetRemoteAddress(pp_resource()));
+ }
if (has_interface<PPB_TCPSocket_1_0>()) {
return NetAddress(
PASS_REF,
@@ -79,6 +110,11 @@ NetAddress TCPSocket::GetRemoteAddress() const {
int32_t TCPSocket::Read(char* buffer,
int32_t bytes_to_read,
const CompletionCallback& callback) {
+ if (has_interface<PPB_TCPSocket_1_1>()) {
+ return get_interface<PPB_TCPSocket_1_1>()->Read(
+ pp_resource(), buffer, bytes_to_read,
+ callback.pp_completion_callback());
+ }
if (has_interface<PPB_TCPSocket_1_0>()) {
return get_interface<PPB_TCPSocket_1_0>()->Read(
pp_resource(), buffer, bytes_to_read,
@@ -90,6 +126,11 @@ int32_t TCPSocket::Read(char* buffer,
int32_t TCPSocket::Write(const char* buffer,
int32_t bytes_to_write,
const CompletionCallback& callback) {
+ if (has_interface<PPB_TCPSocket_1_1>()) {
+ return get_interface<PPB_TCPSocket_1_1>()->Write(
+ pp_resource(), buffer, bytes_to_write,
+ callback.pp_completion_callback());
+ }
if (has_interface<PPB_TCPSocket_1_0>()) {
return get_interface<PPB_TCPSocket_1_0>()->Write(
pp_resource(), buffer, bytes_to_write,
@@ -98,14 +139,39 @@ int32_t TCPSocket::Write(const char* buffer,
return callback.MayForce(PP_ERROR_NOINTERFACE);
}
+int32_t TCPSocket::Listen(int32_t backlog,
+ const CompletionCallback& callback) {
+ if (has_interface<PPB_TCPSocket_1_1>()) {
+ return get_interface<PPB_TCPSocket_1_1>()->Listen(
+ pp_resource(), backlog, callback.pp_completion_callback());
+ }
+ return callback.MayForce(PP_ERROR_NOINTERFACE);
+}
+
+int32_t TCPSocket::Accept(
+ const CompletionCallbackWithOutput<TCPSocket>& callback) {
+ if (has_interface<PPB_TCPSocket_1_1>()) {
+ return get_interface<PPB_TCPSocket_1_1>()->Accept(
+ pp_resource(), callback.output(), callback.pp_completion_callback());
+ }
+ return callback.MayForce(PP_ERROR_NOINTERFACE);
+}
+
void TCPSocket::Close() {
- if (has_interface<PPB_TCPSocket_1_0>())
+ if (has_interface<PPB_TCPSocket_1_1>()) {
+ get_interface<PPB_TCPSocket_1_1>()->Close(pp_resource());
+ } else if (has_interface<PPB_TCPSocket_1_0>()) {
get_interface<PPB_TCPSocket_1_0>()->Close(pp_resource());
+ }
}
int32_t TCPSocket::SetOption(PP_TCPSocket_Option name,
const Var& value,
const CompletionCallback& callback) {
+ if (has_interface<PPB_TCPSocket_1_1>()) {
+ return get_interface<PPB_TCPSocket_1_1>()->SetOption(
+ pp_resource(), name, value.pp_var(), callback.pp_completion_callback());
+ }
if (has_interface<PPB_TCPSocket_1_0>()) {
return get_interface<PPB_TCPSocket_1_0>()->SetOption(
pp_resource(), name, value.pp_var(), callback.pp_completion_callback());
diff --git a/ppapi/cpp/tcp_socket.h b/ppapi/cpp/tcp_socket.h
index 5a5e0f4..bf999b8 100644
--- a/ppapi/cpp/tcp_socket.h
+++ b/ppapi/cpp/tcp_socket.h
@@ -15,10 +15,13 @@ namespace pp {
class CompletionCallback;
class InstanceHandle;
+template <typename T> class CompletionCallbackWithOutput;
+
/// The <code>TCPSocket</code> class provides TCP socket operations.
///
/// Permissions: Apps permission <code>socket</code> with subrule
-/// <code>tcp-connect</code> is required for <code>Connect()</code>.
+/// <code>tcp-connect</code> is required for <code>Connect()</code>; subrule
+/// <code>tcp-listen</code> is required for <code>Listen()</code>.
/// For more details about network communication permissions, please see:
/// http://developer.chrome.com/apps/app_network.html
class TCPSocket : public Resource {
@@ -60,7 +63,20 @@ class TCPSocket : public Resource {
/// @return true if the interface is available, false otherwise.
static bool IsAvailable();
- /// Connects the socket to the given address.
+ /// Binds the socket to the given address. The socket must not be bound.
+ ///
+ /// @param[in] addr A <code>NetAddress</code> object.
+ /// @param[in] callback A <code>CompletionCallback</code> to be called upon
+ /// completion.
+ ///
+ /// @return An int32_t containing an error code from <code>pp_errors.h</code>,
+ /// including (but not limited to):
+ /// - <code>PP_ERROR_ADDRESS_IN_USE</code>: the address is already in use.
+ /// - <code>PP_ERROR_ADDRESS_INVALID</code>: the address is invalid.
+ int32_t Bind(const NetAddress& addr, const CompletionCallback& callback);
+
+ /// Connects the socket to the given address. The socket must not be
+ /// listening. Binding the socket beforehand is optional.
///
/// @param[in] addr A <code>NetAddress</code> object.
/// @param[in] callback A <code>CompletionCallback</code> to be called upon
@@ -77,10 +93,14 @@ class TCPSocket : public Resource {
/// - <code>PP_ERROR_CONNECTION_FAILED</code>: the connection attempt failed.
/// - <code>PP_ERROR_CONNECTION_TIMEDOUT</code>: the connection attempt timed
/// out.
- int32_t Connect(const NetAddress& addr,
- const CompletionCallback& callback);
+ ///
+ /// If the socket is listening/connected or has a pending listen/connect
+ /// request, <code>Connect()</code> will fail without starting a connection
+ /// attempt. Otherwise, any failure during the connection attempt will cause
+ /// the socket to be closed.
+ int32_t Connect(const NetAddress& addr, const CompletionCallback& callback);
- /// Gets the local address of the socket, if it is connected.
+ /// Gets the local address of the socket, if it is bound.
///
/// @return A <code>NetAddress</code> object. The object will be null
/// (i.e., is_null() returns true) on failure.
@@ -135,11 +155,38 @@ class TCPSocket : public Resource {
int32_t bytes_to_write,
const CompletionCallback& callback);
- /// Cancels all pending reads and writes and disconnects the socket. Any
- /// pending callbacks will still run, reporting <code>PP_ERROR_ABORTED</code>
- /// if pending IO was interrupted. After a call to this method, no output
- /// buffer pointers passed into previous <code>Read()</code> calls will be
- /// accessed. It is not valid to call <code>Connect()</code> again.
+ /// Starts listening. The socket must be bound and not connected.
+ ///
+ /// @param[in] backlog A hint to determine the maximum length to which the
+ /// queue of pending connections may grow.
+ /// @param[in] callback A <code>CompletionCallback</code> to be called upon
+ /// completion.
+ ///
+ /// @return An int32_t containing an error code from <code>pp_errors.h</code>,
+ /// including (but not limited to):
+ /// - <code>PP_ERROR_NOACCESS</code>: the caller doesn't have required
+ /// permissions.
+ /// - <code>PP_ERROR_ADDRESS_IN_USE</code>: Another socket is already
+ /// listening on the same port.
+ int32_t Listen(int32_t backlog,
+ const CompletionCallback& callback);
+
+ /// Accepts a connection. The socket must be listening.
+ ///
+ /// @param[in] callback A <code>CompletionCallbackWithOutput</code> to be
+ /// called upon completion.
+ ///
+ /// @return An int32_t containing an error code from <code>pp_errors.h</code>,
+ /// including (but not limited to):
+ /// - <code>PP_ERROR_CONNECTION_ABORTED</code>: A connection has been aborted.
+ int32_t Accept(const CompletionCallbackWithOutput<TCPSocket>& callback);
+
+ /// Cancels all pending operations and closes the socket. Any pending
+ /// callbacks will still run, reporting <code>PP_ERROR_ABORTED</code> if
+ /// pending IO was interrupted. After a call to this method, no output buffer
+ /// pointers passed into previous <code>Read()</code> or <code>Accept()</code>
+ /// calls will be accessed. It is not valid to call <code>Connect()</code> or
+ /// <code>Listen()</code> again.
///
/// The socket is implicitly closed if it is destroyed, so you are not
/// required to call this method.
@@ -155,7 +202,6 @@ class TCPSocket : public Resource {
/// completion.
///
/// @return An int32_t containing an error code from <code>pp_errors.h</code>.
- ////
int32_t SetOption(PP_TCPSocket_Option name,
const Var& value,
const CompletionCallback& callback);
diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
index 91f9752..074bbbe 100644
--- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
+++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
@@ -158,6 +158,7 @@ static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_MouseLock_1_0;
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_NetAddress_1_0;
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_NetworkProxy_1_0;
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TCPSocket_1_0;
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TCPSocket_1_1;
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TextInputController_1_0;
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_UDPSocket_1_0;
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_URLLoader_1_0;
@@ -1073,6 +1074,70 @@ static int32_t Pnacl_M29_PPB_TCPSocket_SetOption(PP_Resource tcp_socket, PP_TCPS
/* End wrapper methods for PPB_TCPSocket_1_0 */
+/* Begin wrapper methods for PPB_TCPSocket_1_1 */
+
+static PP_Resource Pnacl_M31_PPB_TCPSocket_Create(PP_Instance instance) {
+ const struct PPB_TCPSocket_1_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_1_1.real_iface;
+ return iface->Create(instance);
+}
+
+static PP_Bool Pnacl_M31_PPB_TCPSocket_IsTCPSocket(PP_Resource resource) {
+ const struct PPB_TCPSocket_1_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_1_1.real_iface;
+ return iface->IsTCPSocket(resource);
+}
+
+static int32_t Pnacl_M31_PPB_TCPSocket_Bind(PP_Resource tcp_socket, PP_Resource addr, struct PP_CompletionCallback* callback) {
+ const struct PPB_TCPSocket_1_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_1_1.real_iface;
+ return iface->Bind(tcp_socket, addr, *callback);
+}
+
+static int32_t Pnacl_M31_PPB_TCPSocket_Connect(PP_Resource tcp_socket, PP_Resource addr, struct PP_CompletionCallback* callback) {
+ const struct PPB_TCPSocket_1_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_1_1.real_iface;
+ return iface->Connect(tcp_socket, addr, *callback);
+}
+
+static PP_Resource Pnacl_M31_PPB_TCPSocket_GetLocalAddress(PP_Resource tcp_socket) {
+ const struct PPB_TCPSocket_1_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_1_1.real_iface;
+ return iface->GetLocalAddress(tcp_socket);
+}
+
+static PP_Resource Pnacl_M31_PPB_TCPSocket_GetRemoteAddress(PP_Resource tcp_socket) {
+ const struct PPB_TCPSocket_1_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_1_1.real_iface;
+ return iface->GetRemoteAddress(tcp_socket);
+}
+
+static int32_t Pnacl_M31_PPB_TCPSocket_Read(PP_Resource tcp_socket, char* buffer, int32_t bytes_to_read, struct PP_CompletionCallback* callback) {
+ const struct PPB_TCPSocket_1_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_1_1.real_iface;
+ return iface->Read(tcp_socket, buffer, bytes_to_read, *callback);
+}
+
+static int32_t Pnacl_M31_PPB_TCPSocket_Write(PP_Resource tcp_socket, const char* buffer, int32_t bytes_to_write, struct PP_CompletionCallback* callback) {
+ const struct PPB_TCPSocket_1_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_1_1.real_iface;
+ return iface->Write(tcp_socket, buffer, bytes_to_write, *callback);
+}
+
+static int32_t Pnacl_M31_PPB_TCPSocket_Listen(PP_Resource tcp_socket, int32_t backlog, struct PP_CompletionCallback* callback) {
+ const struct PPB_TCPSocket_1_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_1_1.real_iface;
+ return iface->Listen(tcp_socket, backlog, *callback);
+}
+
+static int32_t Pnacl_M31_PPB_TCPSocket_Accept(PP_Resource tcp_socket, PP_Resource* accepted_tcp_socket, struct PP_CompletionCallback* callback) {
+ const struct PPB_TCPSocket_1_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_1_1.real_iface;
+ return iface->Accept(tcp_socket, accepted_tcp_socket, *callback);
+}
+
+static void Pnacl_M31_PPB_TCPSocket_Close(PP_Resource tcp_socket) {
+ const struct PPB_TCPSocket_1_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_1_1.real_iface;
+ iface->Close(tcp_socket);
+}
+
+static int32_t Pnacl_M31_PPB_TCPSocket_SetOption(PP_Resource tcp_socket, PP_TCPSocket_Option name, struct PP_Var* value, struct PP_CompletionCallback* callback) {
+ const struct PPB_TCPSocket_1_1 *iface = Pnacl_WrapperInfo_PPB_TCPSocket_1_1.real_iface;
+ return iface->SetOption(tcp_socket, name, *value, *callback);
+}
+
+/* End wrapper methods for PPB_TCPSocket_1_1 */
+
/* Begin wrapper methods for PPB_TextInputController_1_0 */
static void Pnacl_M30_PPB_TextInputController_SetTextInputType(PP_Instance instance, PP_TextInput_Type type) {
@@ -4265,6 +4330,21 @@ struct PPB_TCPSocket_1_0 Pnacl_Wrappers_PPB_TCPSocket_1_0 = {
.SetOption = (int32_t (*)(PP_Resource tcp_socket, PP_TCPSocket_Option name, struct PP_Var value, struct PP_CompletionCallback callback))&Pnacl_M29_PPB_TCPSocket_SetOption
};
+struct PPB_TCPSocket_1_1 Pnacl_Wrappers_PPB_TCPSocket_1_1 = {
+ .Create = (PP_Resource (*)(PP_Instance instance))&Pnacl_M31_PPB_TCPSocket_Create,
+ .IsTCPSocket = (PP_Bool (*)(PP_Resource resource))&Pnacl_M31_PPB_TCPSocket_IsTCPSocket,
+ .Bind = (int32_t (*)(PP_Resource tcp_socket, PP_Resource addr, struct PP_CompletionCallback callback))&Pnacl_M31_PPB_TCPSocket_Bind,
+ .Connect = (int32_t (*)(PP_Resource tcp_socket, PP_Resource addr, struct PP_CompletionCallback callback))&Pnacl_M31_PPB_TCPSocket_Connect,
+ .GetLocalAddress = (PP_Resource (*)(PP_Resource tcp_socket))&Pnacl_M31_PPB_TCPSocket_GetLocalAddress,
+ .GetRemoteAddress = (PP_Resource (*)(PP_Resource tcp_socket))&Pnacl_M31_PPB_TCPSocket_GetRemoteAddress,
+ .Read = (int32_t (*)(PP_Resource tcp_socket, char* buffer, int32_t bytes_to_read, struct PP_CompletionCallback callback))&Pnacl_M31_PPB_TCPSocket_Read,
+ .Write = (int32_t (*)(PP_Resource tcp_socket, const char* buffer, int32_t bytes_to_write, struct PP_CompletionCallback callback))&Pnacl_M31_PPB_TCPSocket_Write,
+ .Listen = (int32_t (*)(PP_Resource tcp_socket, int32_t backlog, struct PP_CompletionCallback callback))&Pnacl_M31_PPB_TCPSocket_Listen,
+ .Accept = (int32_t (*)(PP_Resource tcp_socket, PP_Resource* accepted_tcp_socket, struct PP_CompletionCallback callback))&Pnacl_M31_PPB_TCPSocket_Accept,
+ .Close = (void (*)(PP_Resource tcp_socket))&Pnacl_M31_PPB_TCPSocket_Close,
+ .SetOption = (int32_t (*)(PP_Resource tcp_socket, PP_TCPSocket_Option name, struct PP_Var value, struct PP_CompletionCallback callback))&Pnacl_M31_PPB_TCPSocket_SetOption
+};
+
struct PPB_TextInputController_1_0 Pnacl_Wrappers_PPB_TextInputController_1_0 = {
.SetTextInputType = (void (*)(PP_Instance instance, PP_TextInput_Type type))&Pnacl_M30_PPB_TextInputController_SetTextInputType,
.UpdateCaretPosition = (void (*)(PP_Instance instance, const struct PP_Rect* caret))&Pnacl_M30_PPB_TextInputController_UpdateCaretPosition,
@@ -5239,6 +5319,12 @@ static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TCPSocket_1_0 = {
.real_iface = NULL
};
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TCPSocket_1_1 = {
+ .iface_macro = PPB_TCPSOCKET_INTERFACE_1_1,
+ .wrapped_iface = (void *) &Pnacl_Wrappers_PPB_TCPSocket_1_1,
+ .real_iface = NULL
+};
+
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_TextInputController_1_0 = {
.iface_macro = PPB_TEXTINPUTCONTROLLER_INTERFACE_1_0,
.wrapped_iface = (void *) &Pnacl_Wrappers_PPB_TextInputController_1_0,
@@ -5719,6 +5805,7 @@ static struct __PnaclWrapperInfo *s_ppb_wrappers[] = {
&Pnacl_WrapperInfo_PPB_NetAddress_1_0,
&Pnacl_WrapperInfo_PPB_NetworkProxy_1_0,
&Pnacl_WrapperInfo_PPB_TCPSocket_1_0,
+ &Pnacl_WrapperInfo_PPB_TCPSocket_1_1,
&Pnacl_WrapperInfo_PPB_TextInputController_1_0,
&Pnacl_WrapperInfo_PPB_UDPSocket_1_0,
&Pnacl_WrapperInfo_PPB_URLLoader_1_0,
diff --git a/ppapi/ppapi_shared.gypi b/ppapi/ppapi_shared.gypi
index 2ee964e..699f603 100644
--- a/ppapi/ppapi_shared.gypi
+++ b/ppapi/ppapi_shared.gypi
@@ -71,6 +71,8 @@
'shared_impl/ppb_opengles2_shared.h',
'shared_impl/ppb_resource_array_shared.cc',
'shared_impl/ppb_resource_array_shared.h',
+ 'shared_impl/ppb_tcp_socket_shared.cc',
+ 'shared_impl/ppb_tcp_socket_shared.h',
'shared_impl/ppb_trace_event_impl.cc',
'shared_impl/ppb_trace_event_impl.h',
'shared_impl/ppb_url_util_shared.cc',
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 95bbd8b..24beb03 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -62,6 +62,7 @@
#include "ppapi/shared_impl/ppapi_preferences.h"
#include "ppapi/shared_impl/ppb_device_ref_shared.h"
#include "ppapi/shared_impl/ppb_input_event_shared.h"
+#include "ppapi/shared_impl/ppb_tcp_socket_shared.h"
#include "ppapi/shared_impl/ppb_view_shared.h"
#include "ppapi/shared_impl/ppp_flash_browser_operations_shared.h"
#include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h"
@@ -74,6 +75,8 @@
#define IPC_MESSAGE_START PpapiMsgStart
+IPC_ENUM_TRAITS_MAX_VALUE(ppapi::TCPSocketVersion,
+ ppapi::TCP_SOCKET_VERSION_1_1_OR_ABOVE)
IPC_ENUM_TRAITS(PP_AudioSampleRate)
IPC_ENUM_TRAITS(PP_DeviceType_Dev)
IPC_ENUM_TRAITS(PP_DecryptorStreamType)
@@ -99,7 +102,7 @@ IPC_ENUM_TRAITS_MAX_VALUE(PP_TalkEvent, PP_TALKEVENT_NUM_EVENTS - 1)
IPC_ENUM_TRAITS_MAX_VALUE(PP_TalkPermission,
PP_TALKPERMISSION_NUM_PERMISSIONS - 1)
IPC_ENUM_TRAITS_MAX_VALUE(PP_TCPSocket_Option,
- PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE)
+ PP_TCPSOCKET_OPTION_ADDRESS_REUSE)
IPC_ENUM_TRAITS(PP_TextInput_Type)
IPC_ENUM_TRAITS(PP_TrueTypeFontFamily_Dev)
IPC_ENUM_TRAITS(PP_TrueTypeFontStyle_Dev)
@@ -1450,11 +1453,16 @@ IPC_MESSAGE_CONTROL1(PpapiPluginMsg_Printing_GetDefaultPrintSettingsReply,
// TCP Socket ------------------------------------------------------------------
// Creates a PPB_TCPSocket resource.
-IPC_MESSAGE_CONTROL0(PpapiHostMsg_TCPSocket_Create)
+IPC_MESSAGE_CONTROL1(PpapiHostMsg_TCPSocket_Create,
+ ppapi::TCPSocketVersion /* version */)
// Creates a PPB_TCPSocket_Private resource.
IPC_MESSAGE_CONTROL0(PpapiHostMsg_TCPSocket_CreatePrivate)
+IPC_MESSAGE_CONTROL1(PpapiHostMsg_TCPSocket_Bind,
+ PP_NetAddress_Private /* net_addr */)
+IPC_MESSAGE_CONTROL1(PpapiPluginMsg_TCPSocket_BindReply,
+ PP_NetAddress_Private /* local_addr */)
IPC_MESSAGE_CONTROL2(PpapiHostMsg_TCPSocket_Connect,
std::string /* host */,
uint16_t /* port */)
@@ -1477,7 +1485,15 @@ IPC_MESSAGE_CONTROL1(PpapiPluginMsg_TCPSocket_ReadReply,
IPC_MESSAGE_CONTROL1(PpapiHostMsg_TCPSocket_Write,
std::string /* data */)
IPC_MESSAGE_CONTROL0(PpapiPluginMsg_TCPSocket_WriteReply)
-IPC_MESSAGE_CONTROL0(PpapiHostMsg_TCPSocket_Disconnect)
+IPC_MESSAGE_CONTROL1(PpapiHostMsg_TCPSocket_Listen,
+ int32_t /* backlog */)
+IPC_MESSAGE_CONTROL0(PpapiPluginMsg_TCPSocket_ListenReply)
+IPC_MESSAGE_CONTROL0(PpapiHostMsg_TCPSocket_Accept)
+IPC_MESSAGE_CONTROL3(PpapiPluginMsg_TCPSocket_AcceptReply,
+ int /* pending_host_id*/,
+ PP_NetAddress_Private /* local_addr */,
+ PP_NetAddress_Private /* remote_addr */)
+IPC_MESSAGE_CONTROL0(PpapiHostMsg_TCPSocket_Close)
IPC_MESSAGE_CONTROL2(PpapiHostMsg_TCPSocket_SetOption,
PP_TCPSocket_Option /* name */,
ppapi::SocketOptionData /* value */)
diff --git a/ppapi/proxy/resource_creation_proxy.cc b/ppapi/proxy/resource_creation_proxy.cc
index 60841022..ea01f6e 100644
--- a/ppapi/proxy/resource_creation_proxy.cc
+++ b/ppapi/proxy/resource_creation_proxy.cc
@@ -323,9 +323,17 @@ PP_Resource ResourceCreationProxy::CreateTCPServerSocketPrivate(
GetReference();
}
+PP_Resource ResourceCreationProxy::CreateTCPSocket1_0(
+ PP_Instance instance) {
+ return (new TCPSocketResource(GetConnection(), instance,
+ TCP_SOCKET_VERSION_1_0))->GetReference();
+}
+
PP_Resource ResourceCreationProxy::CreateTCPSocket(
PP_Instance instance) {
- return (new TCPSocketResource(GetConnection(), instance))->GetReference();
+ return (new TCPSocketResource(
+ GetConnection(), instance, TCP_SOCKET_VERSION_1_1_OR_ABOVE))->
+ GetReference();
}
PP_Resource ResourceCreationProxy::CreateTCPSocketPrivate(
diff --git a/ppapi/proxy/resource_creation_proxy.h b/ppapi/proxy/resource_creation_proxy.h
index 210e23c..509b155 100644
--- a/ppapi/proxy/resource_creation_proxy.h
+++ b/ppapi/proxy/resource_creation_proxy.h
@@ -138,6 +138,7 @@ class ResourceCreationProxy : public InterfaceProxy,
virtual PP_Resource CreatePrinting(PP_Instance) OVERRIDE;
virtual PP_Resource CreateTCPServerSocketPrivate(
PP_Instance instance) OVERRIDE;
+ virtual PP_Resource CreateTCPSocket1_0(PP_Instance instance) OVERRIDE;
virtual PP_Resource CreateTCPSocket(PP_Instance instance) OVERRIDE;
virtual PP_Resource CreateTCPSocketPrivate(PP_Instance instance) OVERRIDE;
virtual PP_Resource CreateUDPSocket(PP_Instance instance) OVERRIDE;
diff --git a/ppapi/proxy/tcp_socket_private_resource.cc b/ppapi/proxy/tcp_socket_private_resource.cc
index 0698e49..76ed4b9 100644
--- a/ppapi/proxy/tcp_socket_private_resource.cc
+++ b/ppapi/proxy/tcp_socket_private_resource.cc
@@ -5,13 +5,14 @@
#include "ppapi/proxy/tcp_socket_private_resource.h"
#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/ppb_tcp_socket_shared.h"
namespace ppapi {
namespace proxy {
TCPSocketPrivateResource::TCPSocketPrivateResource(Connection connection,
PP_Instance instance)
- : TCPSocketResourceBase(connection, instance, true) {
+ : TCPSocketResourceBase(connection, instance, TCP_SOCKET_VERSION_PRIVATE) {
SendCreate(BROWSER, PpapiHostMsg_TCPSocket_CreatePrivate());
}
@@ -21,14 +22,12 @@ TCPSocketPrivateResource::TCPSocketPrivateResource(
int pending_resource_id,
const PP_NetAddress_Private& local_addr,
const PP_NetAddress_Private& remote_addr)
- : TCPSocketResourceBase(connection, instance, true,
- local_addr,
- remote_addr) {
+ : TCPSocketResourceBase(connection, instance, TCP_SOCKET_VERSION_PRIVATE,
+ local_addr, remote_addr) {
AttachToPendingHost(BROWSER, pending_resource_id);
}
TCPSocketPrivateResource::~TCPSocketPrivateResource() {
- DisconnectImpl();
}
thunk::PPB_TCPSocket_Private_API*
@@ -91,7 +90,7 @@ int32_t TCPSocketPrivateResource::Write(
}
void TCPSocketPrivateResource::Disconnect() {
- DisconnectImpl();
+ CloseImpl();
}
int32_t TCPSocketPrivateResource::SetOption(
@@ -109,5 +108,13 @@ int32_t TCPSocketPrivateResource::SetOption(
}
}
+PP_Resource TCPSocketPrivateResource::CreateAcceptedSocket(
+ int /* pending_host_id */,
+ const PP_NetAddress_Private& /* local_addr */,
+ const PP_NetAddress_Private& /* remote_addr */) {
+ NOTREACHED();
+ return 0;
+}
+
} // namespace proxy
} // namespace ppapi
diff --git a/ppapi/proxy/tcp_socket_private_resource.h b/ppapi/proxy/tcp_socket_private_resource.h
index f79ab9d..9ae9bb2 100644
--- a/ppapi/proxy/tcp_socket_private_resource.h
+++ b/ppapi/proxy/tcp_socket_private_resource.h
@@ -59,6 +59,12 @@ class PPAPI_PROXY_EXPORT TCPSocketPrivateResource
const PP_Var& value,
scoped_refptr<TrackedCallback> callback) OVERRIDE;
+ // TCPSocketResourceBase implementation.
+ virtual PP_Resource CreateAcceptedSocket(
+ int pending_host_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr) OVERRIDE;
+
private:
DISALLOW_COPY_AND_ASSIGN(TCPSocketPrivateResource);
};
diff --git a/ppapi/proxy/tcp_socket_resource.cc b/ppapi/proxy/tcp_socket_resource.cc
index 085aab3..f8f8f68 100644
--- a/ppapi/proxy/tcp_socket_resource.cc
+++ b/ppapi/proxy/tcp_socket_resource.cc
@@ -4,7 +4,9 @@
#include "ppapi/proxy/tcp_socket_resource.h"
+#include "base/logging.h"
#include "ppapi/proxy/ppapi_messages.h"
+#include "ppapi/shared_impl/ppb_tcp_socket_shared.h"
#include "ppapi/thunk/enter.h"
#include "ppapi/thunk/ppb_net_address_api.h"
@@ -19,19 +21,40 @@ typedef thunk::EnterResourceNoLock<thunk::PPB_NetAddress_API>
} // namespace
TCPSocketResource::TCPSocketResource(Connection connection,
- PP_Instance instance)
- : TCPSocketResourceBase(connection, instance, false) {
- SendCreate(BROWSER, PpapiHostMsg_TCPSocket_Create());
+ PP_Instance instance,
+ TCPSocketVersion version)
+ : TCPSocketResourceBase(connection, instance, version) {
+ DCHECK_NE(version, TCP_SOCKET_VERSION_PRIVATE);
+ SendCreate(BROWSER, PpapiHostMsg_TCPSocket_Create(version));
+}
+
+TCPSocketResource::TCPSocketResource(Connection connection,
+ PP_Instance instance,
+ int pending_host_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr)
+ : TCPSocketResourceBase(connection, instance,
+ TCP_SOCKET_VERSION_1_1_OR_ABOVE, local_addr,
+ remote_addr) {
+ AttachToPendingHost(BROWSER, pending_host_id);
}
TCPSocketResource::~TCPSocketResource() {
- DisconnectImpl();
}
thunk::PPB_TCPSocket_API* TCPSocketResource::AsPPB_TCPSocket_API() {
return this;
}
+int32_t TCPSocketResource::Bind(PP_Resource addr,
+ scoped_refptr<TrackedCallback> callback) {
+ EnterNetAddressNoLock enter(addr, true);
+ if (enter.failed())
+ return PP_ERROR_BADARGUMENT;
+
+ return BindImpl(&enter.object()->GetNetAddressPrivate(), callback);
+}
+
int32_t TCPSocketResource::Connect(PP_Resource addr,
scoped_refptr<TrackedCallback> callback) {
EnterNetAddressNoLock enter(addr, true);
@@ -78,8 +101,18 @@ int32_t TCPSocketResource::Write(const char* buffer,
return WriteImpl(buffer, bytes_to_write, callback);
}
+int32_t TCPSocketResource::Listen(int32_t backlog,
+ scoped_refptr<TrackedCallback> callback) {
+ return ListenImpl(backlog, callback);
+}
+
+int32_t TCPSocketResource::Accept(PP_Resource* accepted_tcp_socket,
+ scoped_refptr<TrackedCallback> callback) {
+ return AcceptImpl(accepted_tcp_socket, callback);
+}
+
void TCPSocketResource::Close() {
- DisconnectImpl();
+ CloseImpl();
}
int32_t TCPSocketResource::SetOption(PP_TCPSocket_Option name,
@@ -88,5 +121,13 @@ int32_t TCPSocketResource::SetOption(PP_TCPSocket_Option name,
return SetOptionImpl(name, value, callback);
}
+PP_Resource TCPSocketResource::CreateAcceptedSocket(
+ int pending_host_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr) {
+ return (new TCPSocketResource(connection(), pp_instance(), pending_host_id,
+ local_addr, remote_addr))->GetReference();
+}
+
} // namespace proxy
} // namespace ppapi
diff --git a/ppapi/proxy/tcp_socket_resource.h b/ppapi/proxy/tcp_socket_resource.h
index 05b4fe3..5dbfdd5 100644
--- a/ppapi/proxy/tcp_socket_resource.h
+++ b/ppapi/proxy/tcp_socket_resource.h
@@ -11,18 +11,27 @@
#include "ppapi/thunk/ppb_tcp_socket_api.h"
namespace ppapi {
+
+enum TCPSocketVersion;
+
namespace proxy {
class PPAPI_PROXY_EXPORT TCPSocketResource : public thunk::PPB_TCPSocket_API,
public TCPSocketResourceBase {
public:
- TCPSocketResource(Connection connection, PP_Instance instance);
+ // C-tor used for new sockets created.
+ TCPSocketResource(Connection connection,
+ PP_Instance instance,
+ TCPSocketVersion version);
+
virtual ~TCPSocketResource();
// PluginResource overrides.
virtual thunk::PPB_TCPSocket_API* AsPPB_TCPSocket_API() OVERRIDE;
// thunk::PPB_TCPSocket_API implementation.
+ virtual int32_t Bind(PP_Resource addr,
+ scoped_refptr<TrackedCallback> callback) OVERRIDE;
virtual int32_t Connect(PP_Resource addr,
scoped_refptr<TrackedCallback> callback) OVERRIDE;
virtual PP_Resource GetLocalAddress() OVERRIDE;
@@ -33,12 +42,29 @@ class PPAPI_PROXY_EXPORT TCPSocketResource : public thunk::PPB_TCPSocket_API,
virtual int32_t Write(const char* buffer,
int32_t bytes_to_write,
scoped_refptr<TrackedCallback> callback) OVERRIDE;
+ virtual int32_t Listen(int32_t backlog,
+ scoped_refptr<TrackedCallback> callback) OVERRIDE;
+ virtual int32_t Accept(PP_Resource* accepted_tcp_socket,
+ scoped_refptr<TrackedCallback> callback) OVERRIDE;
virtual void Close() OVERRIDE;
virtual int32_t SetOption(PP_TCPSocket_Option name,
const PP_Var& value,
scoped_refptr<TrackedCallback> callback) OVERRIDE;
+ // TCPSocketResourceBase implementation.
+ virtual PP_Resource CreateAcceptedSocket(
+ int pending_host_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr) OVERRIDE;
+
private:
+ // C-tor used for accepted sockets.
+ TCPSocketResource(Connection connection,
+ PP_Instance instance,
+ int pending_host_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr);
+
DISALLOW_COPY_AND_ASSIGN(TCPSocketResource);
};
diff --git a/ppapi/proxy/tcp_socket_resource_base.cc b/ppapi/proxy/tcp_socket_resource_base.cc
index f02895b..2590c41 100644
--- a/ppapi/proxy/tcp_socket_resource_base.cc
+++ b/ppapi/proxy/tcp_socket_resource_base.cc
@@ -32,12 +32,13 @@ const int32_t TCPSocketResourceBase::kMaxReceiveBufferSize =
TCPSocketResourceBase::TCPSocketResourceBase(Connection connection,
PP_Instance instance,
- bool private_api)
+ TCPSocketVersion version)
: PluginResource(connection, instance),
- connection_state_(BEFORE_CONNECT),
+ state_(TCPSocketState::INITIAL),
read_buffer_(NULL),
bytes_to_read_(-1),
- private_api_(private_api) {
+ accepted_tcp_socket_(NULL),
+ version_(version) {
local_addr_.size = 0;
memset(local_addr_.data, 0,
arraysize(local_addr_.data) * sizeof(*local_addr_.data));
@@ -49,19 +50,42 @@ TCPSocketResourceBase::TCPSocketResourceBase(Connection connection,
TCPSocketResourceBase::TCPSocketResourceBase(
Connection connection,
PP_Instance instance,
- bool private_api,
+ TCPSocketVersion version,
const PP_NetAddress_Private& local_addr,
const PP_NetAddress_Private& remote_addr)
: PluginResource(connection, instance),
- connection_state_(CONNECTED),
+ state_(TCPSocketState::CONNECTED),
read_buffer_(NULL),
bytes_to_read_(-1),
local_addr_(local_addr),
remote_addr_(remote_addr),
- private_api_(private_api) {
+ accepted_tcp_socket_(NULL),
+ version_(version) {
}
TCPSocketResourceBase::~TCPSocketResourceBase() {
+ CloseImpl();
+}
+
+int32_t TCPSocketResourceBase::BindImpl(
+ const PP_NetAddress_Private* addr,
+ scoped_refptr<TrackedCallback> callback) {
+ if (!addr)
+ return PP_ERROR_BADARGUMENT;
+ if (state_.IsPending(TCPSocketState::BIND))
+ return PP_ERROR_INPROGRESS;
+ if (!state_.IsValidTransition(TCPSocketState::BIND))
+ return PP_ERROR_FAILED;
+
+ bind_callback_ = callback;
+ state_.SetPendingTransition(TCPSocketState::BIND);
+
+ Call<PpapiPluginMsg_TCPSocket_BindReply>(
+ BROWSER,
+ PpapiHostMsg_TCPSocket_Bind(*addr),
+ base::Bind(&TCPSocketResourceBase::OnPluginMsgBindReply,
+ base::Unretained(this)));
+ return PP_OK_COMPLETIONPENDING;
}
int32_t TCPSocketResourceBase::ConnectImpl(
@@ -70,12 +94,13 @@ int32_t TCPSocketResourceBase::ConnectImpl(
scoped_refptr<TrackedCallback> callback) {
if (!host)
return PP_ERROR_BADARGUMENT;
- if (connection_state_ != BEFORE_CONNECT)
+ if (state_.IsPending(TCPSocketState::CONNECT))
+ return PP_ERROR_INPROGRESS;
+ if (!state_.IsValidTransition(TCPSocketState::CONNECT))
return PP_ERROR_FAILED;
- if (TrackedCallback::IsPending(connect_callback_))
- return PP_ERROR_INPROGRESS; // Can only have one pending request.
connect_callback_ = callback;
+ state_.SetPendingTransition(TCPSocketState::CONNECT);
Call<PpapiPluginMsg_TCPSocket_ConnectReply>(
BROWSER,
@@ -90,12 +115,13 @@ int32_t TCPSocketResourceBase::ConnectWithNetAddressImpl(
scoped_refptr<TrackedCallback> callback) {
if (!addr)
return PP_ERROR_BADARGUMENT;
- if (connection_state_ != BEFORE_CONNECT)
+ if (state_.IsPending(TCPSocketState::CONNECT))
+ return PP_ERROR_INPROGRESS;
+ if (!state_.IsValidTransition(TCPSocketState::CONNECT))
return PP_ERROR_FAILED;
- if (TrackedCallback::IsPending(connect_callback_))
- return PP_ERROR_INPROGRESS; // Can only have one pending request.
connect_callback_ = callback;
+ state_.SetPendingTransition(TCPSocketState::CONNECT);
Call<PpapiPluginMsg_TCPSocket_ConnectReply>(
BROWSER,
@@ -107,7 +133,7 @@ int32_t TCPSocketResourceBase::ConnectWithNetAddressImpl(
PP_Bool TCPSocketResourceBase::GetLocalAddressImpl(
PP_NetAddress_Private* local_addr) {
- if (!IsConnected() || !local_addr)
+ if (!state_.IsBound() || !local_addr)
return PP_FALSE;
*local_addr = local_addr_;
return PP_TRUE;
@@ -115,7 +141,7 @@ PP_Bool TCPSocketResourceBase::GetLocalAddressImpl(
PP_Bool TCPSocketResourceBase::GetRemoteAddressImpl(
PP_NetAddress_Private* remote_addr) {
- if (!IsConnected() || !remote_addr)
+ if (!state_.IsConnected() || !remote_addr)
return PP_FALSE;
*remote_addr = remote_addr_;
return PP_TRUE;
@@ -128,15 +154,16 @@ int32_t TCPSocketResourceBase::SSLHandshakeImpl(
if (!server_name)
return PP_ERROR_BADARGUMENT;
- if (connection_state_ != CONNECTED)
- return PP_ERROR_FAILED;
- if (TrackedCallback::IsPending(ssl_handshake_callback_) ||
+ if (state_.IsPending(TCPSocketState::SSL_CONNECT) ||
TrackedCallback::IsPending(read_callback_) ||
TrackedCallback::IsPending(write_callback_)) {
return PP_ERROR_INPROGRESS;
}
+ if (!state_.IsValidTransition(TCPSocketState::SSL_CONNECT))
+ return PP_ERROR_FAILED;
ssl_handshake_callback_ = callback;
+ state_.SetPendingTransition(TCPSocketState::SSL_CONNECT);
Call<PpapiPluginMsg_TCPSocket_SSLHandshakeReply>(
BROWSER,
@@ -193,10 +220,10 @@ int32_t TCPSocketResourceBase::ReadImpl(
if (!buffer || bytes_to_read <= 0)
return PP_ERROR_BADARGUMENT;
- if (!IsConnected())
+ if (!state_.IsConnected())
return PP_ERROR_FAILED;
if (TrackedCallback::IsPending(read_callback_) ||
- TrackedCallback::IsPending(ssl_handshake_callback_))
+ state_.IsPending(TCPSocketState::SSL_CONNECT))
return PP_ERROR_INPROGRESS;
read_buffer_ = buffer;
bytes_to_read_ = std::min(bytes_to_read, kMaxReadSize);
@@ -217,10 +244,10 @@ int32_t TCPSocketResourceBase::WriteImpl(
if (!buffer || bytes_to_write <= 0)
return PP_ERROR_BADARGUMENT;
- if (!IsConnected())
+ if (!state_.IsConnected())
return PP_ERROR_FAILED;
if (TrackedCallback::IsPending(write_callback_) ||
- TrackedCallback::IsPending(ssl_handshake_callback_))
+ state_.IsPending(TCPSocketState::SSL_CONNECT))
return PP_ERROR_INPROGRESS;
if (bytes_to_write > kMaxWriteSize)
@@ -236,33 +263,79 @@ int32_t TCPSocketResourceBase::WriteImpl(
return PP_OK_COMPLETIONPENDING;
}
-void TCPSocketResourceBase::DisconnectImpl() {
- if (connection_state_ == DISCONNECTED)
+int32_t TCPSocketResourceBase::ListenImpl(
+ int32_t backlog,
+ scoped_refptr<TrackedCallback> callback) {
+ if (backlog <= 0)
+ return PP_ERROR_BADARGUMENT;
+ if (state_.IsPending(TCPSocketState::LISTEN))
+ return PP_ERROR_INPROGRESS;
+ if (!state_.IsValidTransition(TCPSocketState::LISTEN))
+ return PP_ERROR_FAILED;
+
+ listen_callback_ = callback;
+ state_.SetPendingTransition(TCPSocketState::LISTEN);
+
+ Call<PpapiPluginMsg_TCPSocket_ListenReply>(
+ BROWSER,
+ PpapiHostMsg_TCPSocket_Listen(backlog),
+ base::Bind(&TCPSocketResourceBase::OnPluginMsgListenReply,
+ base::Unretained(this)));
+ return PP_OK_COMPLETIONPENDING;
+}
+
+int32_t TCPSocketResourceBase::AcceptImpl(
+ PP_Resource* accepted_tcp_socket,
+ scoped_refptr<TrackedCallback> callback) {
+ if (!accepted_tcp_socket)
+ return PP_ERROR_BADARGUMENT;
+ if (TrackedCallback::IsPending(accept_callback_))
+ return PP_ERROR_INPROGRESS;
+ if (state_.state() != TCPSocketState::LISTENING)
+ return PP_ERROR_FAILED;
+
+ accept_callback_ = callback;
+ accepted_tcp_socket_ = accepted_tcp_socket;
+
+ Call<PpapiPluginMsg_TCPSocket_AcceptReply>(
+ BROWSER,
+ PpapiHostMsg_TCPSocket_Accept(),
+ base::Bind(&TCPSocketResourceBase::OnPluginMsgAcceptReply,
+ base::Unretained(this)));
+ return PP_OK_COMPLETIONPENDING;
+}
+
+void TCPSocketResourceBase::CloseImpl() {
+ if (state_.state() == TCPSocketState::CLOSED)
return;
- connection_state_ = DISCONNECTED;
+ state_.DoTransition(TCPSocketState::CLOSE, true);
- Post(BROWSER, PpapiHostMsg_TCPSocket_Disconnect());
+ Post(BROWSER, PpapiHostMsg_TCPSocket_Close());
+ PostAbortIfNecessary(&bind_callback_);
PostAbortIfNecessary(&connect_callback_);
PostAbortIfNecessary(&ssl_handshake_callback_);
PostAbortIfNecessary(&read_callback_);
PostAbortIfNecessary(&write_callback_);
+ PostAbortIfNecessary(&listen_callback_);
+ PostAbortIfNecessary(&accept_callback_);
read_buffer_ = NULL;
bytes_to_read_ = -1;
server_certificate_ = NULL;
+ accepted_tcp_socket_ = NULL;
}
int32_t TCPSocketResourceBase::SetOptionImpl(
PP_TCPSocket_Option name,
const PP_Var& value,
scoped_refptr<TrackedCallback> callback) {
- if (!IsConnected())
- return PP_ERROR_FAILED;
-
SocketOptionData option_data;
switch (name) {
case PP_TCPSOCKET_OPTION_NO_DELAY: {
+ if (!state_.IsConnected())
+ return PP_ERROR_FAILED;
+
if (value.type != PP_VARTYPE_BOOL)
return PP_ERROR_BADARGUMENT;
option_data.SetBool(PP_ToBool(value.value.as_bool));
@@ -270,11 +343,25 @@ int32_t TCPSocketResourceBase::SetOptionImpl(
}
case PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE:
case PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE: {
+ if (!state_.IsConnected())
+ return PP_ERROR_FAILED;
+
if (value.type != PP_VARTYPE_INT32)
return PP_ERROR_BADARGUMENT;
option_data.SetInt32(value.value.as_int);
break;
}
+ case PP_TCPSOCKET_OPTION_ADDRESS_REUSE: {
+ if (version_ != TCP_SOCKET_VERSION_1_1_OR_ABOVE)
+ return PP_ERROR_NOTSUPPORTED;
+ if (state_.state() != TCPSocketState::INITIAL)
+ return PP_ERROR_FAILED;
+
+ if (value.type != PP_VARTYPE_BOOL)
+ return PP_ERROR_BADARGUMENT;
+ option_data.SetBool(PP_ToBool(value.value.as_bool));
+ break;
+ }
default: {
NOTREACHED();
return PP_ERROR_BADARGUMENT;
@@ -291,34 +378,52 @@ int32_t TCPSocketResourceBase::SetOptionImpl(
return PP_OK_COMPLETIONPENDING;
}
-bool TCPSocketResourceBase::IsConnected() const {
- return connection_state_ == CONNECTED || connection_state_ == SSL_CONNECTED;
-}
-
void TCPSocketResourceBase::PostAbortIfNecessary(
scoped_refptr<TrackedCallback>* callback) {
if (TrackedCallback::IsPending(*callback))
(*callback)->PostAbort();
}
+void TCPSocketResourceBase::OnPluginMsgBindReply(
+ const ResourceMessageReplyParams& params,
+ const PP_NetAddress_Private& local_addr) {
+ // It is possible that CloseImpl() has been called. We don't want to update
+ // class members in this case.
+ if (!state_.IsPending(TCPSocketState::BIND))
+ return;
+
+ DCHECK(TrackedCallback::IsPending(bind_callback_));
+ if (params.result() == PP_OK) {
+ local_addr_ = local_addr;
+ state_.CompletePendingTransition(true);
+ } else {
+ state_.CompletePendingTransition(false);
+ }
+ RunCallback(bind_callback_, params.result());
+}
+
void TCPSocketResourceBase::OnPluginMsgConnectReply(
const ResourceMessageReplyParams& params,
const PP_NetAddress_Private& local_addr,
const PP_NetAddress_Private& remote_addr) {
- // It is possible that |connect_callback_| is pending while
- // |connection_state_| is not BEFORE_CONNECT: DisconnectImpl() has been
- // called, but a ConnectCompleted notification came earlier than the task to
- // abort |connect_callback_|. We don't want to update |connection_state_| or
- // other members in that case.
- if (connection_state_ != BEFORE_CONNECT ||
- !TrackedCallback::IsPending(connect_callback_)) {
+ // It is possible that CloseImpl() has been called. We don't want to update
+ // class members in this case.
+ if (!state_.IsPending(TCPSocketState::CONNECT))
return;
- }
+ DCHECK(TrackedCallback::IsPending(connect_callback_));
if (params.result() == PP_OK) {
local_addr_ = local_addr;
remote_addr_ = remote_addr;
- connection_state_ = CONNECTED;
+ state_.CompletePendingTransition(true);
+ } else {
+ if (version_ == TCP_SOCKET_VERSION_1_1_OR_ABOVE) {
+ state_.CompletePendingTransition(false);
+ } else {
+ // In order to maintain backward compatibility, allow to connect the
+ // socket again.
+ state_ = TCPSocketState(TCPSocketState::INITIAL);
+ }
}
RunCallback(connect_callback_, params.result());
}
@@ -326,42 +431,33 @@ void TCPSocketResourceBase::OnPluginMsgConnectReply(
void TCPSocketResourceBase::OnPluginMsgSSLHandshakeReply(
const ResourceMessageReplyParams& params,
const PPB_X509Certificate_Fields& certificate_fields) {
- // It is possible that |ssl_handshake_callback_| is pending while
- // |connection_state_| is not CONNECT: DisconnectImpl() has been
- // called, but a SSLHandshakeCompleted notification came earlier than the task
- // to abort |ssl_handshake_callback_|. We don't want to update
- // |connection_state_| or other members in that case.
- if (connection_state_ != CONNECTED ||
- !TrackedCallback::IsPending(ssl_handshake_callback_)) {
+ // It is possible that CloseImpl() has been called. We don't want to
+ // update class members in this case.
+ if (!state_.IsPending(TCPSocketState::SSL_CONNECT))
return;
- }
+ DCHECK(TrackedCallback::IsPending(ssl_handshake_callback_));
if (params.result() == PP_OK) {
- connection_state_ = SSL_CONNECTED;
+ state_.CompletePendingTransition(true);
server_certificate_ = new PPB_X509Certificate_Private_Shared(
OBJECT_IS_PROXY,
pp_instance(),
certificate_fields);
- RunCallback(ssl_handshake_callback_, params.result());
} else {
- // The resource might be released in the callback so we need to hold
- // a reference so we can Disconnect() first.
- AddRef();
- RunCallback(ssl_handshake_callback_, params.result());
- DisconnectImpl();
- Release();
+ state_.CompletePendingTransition(false);
}
+ RunCallback(ssl_handshake_callback_, params.result());
}
void TCPSocketResourceBase::OnPluginMsgReadReply(
const ResourceMessageReplyParams& params,
const std::string& data) {
- // It is possible that |read_callback_| is pending while |read_buffer_| is
- // NULL: DisconnectImpl() has been called, but a ReadCompleted notification
- // came earlier than the task to abort |read_callback_|. We shouldn't access
- // the buffer in that case. The user may have released it.
- if (!TrackedCallback::IsPending(read_callback_) || !read_buffer_)
+ // It is possible that CloseImpl() has been called. We shouldn't access the
+ // buffer in that case. The user may have released it.
+ if (!state_.IsConnected() || !TrackedCallback::IsPending(read_callback_) ||
+ !read_buffer_) {
return;
+ }
const bool succeeded = params.result() == PP_OK;
if (succeeded) {
@@ -372,19 +468,48 @@ void TCPSocketResourceBase::OnPluginMsgReadReply(
read_buffer_ = NULL;
bytes_to_read_ = -1;
- read_callback_->Run(succeeded ?
- static_cast<int32_t>(data.size()) :
- ConvertNetworkAPIErrorForCompatibility(params.result(),
- private_api_));
+ RunCallback(read_callback_,
+ succeeded ? static_cast<int32_t>(data.size()) : params.result());
}
void TCPSocketResourceBase::OnPluginMsgWriteReply(
const ResourceMessageReplyParams& params) {
- if (!TrackedCallback::IsPending(write_callback_))
+ if (!state_.IsConnected() || !TrackedCallback::IsPending(write_callback_))
return;
RunCallback(write_callback_, params.result());
}
+void TCPSocketResourceBase::OnPluginMsgListenReply(
+ const ResourceMessageReplyParams& params) {
+ if (!state_.IsPending(TCPSocketState::LISTEN))
+ return;
+
+ DCHECK(TrackedCallback::IsPending(listen_callback_));
+ state_.CompletePendingTransition(params.result() == PP_OK);
+
+ RunCallback(listen_callback_, params.result());
+}
+
+void TCPSocketResourceBase::OnPluginMsgAcceptReply(
+ const ResourceMessageReplyParams& params,
+ int pending_host_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr) {
+ // It is possible that CloseImpl() has been called. We shouldn't access the
+ // output parameter in that case. The user may have released it.
+ if (state_.state() != TCPSocketState::LISTENING ||
+ !TrackedCallback::IsPending(accept_callback_) || !accepted_tcp_socket_) {
+ return;
+ }
+
+ if (params.result() == PP_OK) {
+ *accepted_tcp_socket_ = CreateAcceptedSocket(pending_host_id, local_addr,
+ remote_addr);
+ }
+ accepted_tcp_socket_ = NULL;
+ RunCallback(accept_callback_, params.result());
+}
+
void TCPSocketResourceBase::OnPluginMsgSetOptionReply(
const ResourceMessageReplyParams& params) {
if (set_option_callbacks_.empty()) {
@@ -399,8 +524,8 @@ void TCPSocketResourceBase::OnPluginMsgSetOptionReply(
void TCPSocketResourceBase::RunCallback(scoped_refptr<TrackedCallback> callback,
int32_t pp_result) {
- callback->Run(ConvertNetworkAPIErrorForCompatibility(pp_result,
- private_api_));
+ callback->Run(ConvertNetworkAPIErrorForCompatibility(
+ pp_result, version_ == TCP_SOCKET_VERSION_PRIVATE));
}
} // namespace ppapi
diff --git a/ppapi/proxy/tcp_socket_resource_base.h b/ppapi/proxy/tcp_socket_resource_base.h
index 7e8a481..8835ab9 100644
--- a/ppapi/proxy/tcp_socket_resource_base.h
+++ b/ppapi/proxy/tcp_socket_resource_base.h
@@ -15,6 +15,7 @@
#include "ppapi/c/private/ppb_net_address_private.h"
#include "ppapi/proxy/plugin_resource.h"
#include "ppapi/proxy/ppapi_proxy_export.h"
+#include "ppapi/shared_impl/ppb_tcp_socket_shared.h"
#include "ppapi/shared_impl/tracked_callback.h"
namespace ppapi {
@@ -27,6 +28,7 @@ namespace proxy {
class PPAPI_PROXY_EXPORT TCPSocketResourceBase : public PluginResource {
public:
+ // TODO(yzshen): Move these constants to ppb_tcp_socket_shared.
// The maximum number of bytes that each PpapiHostMsg_PPBTCPSocket_Read
// message is allowed to request.
static const int32_t kMaxReadSize;
@@ -46,33 +48,28 @@ class PPAPI_PROXY_EXPORT TCPSocketResourceBase : public PluginResource {
static const int32_t kMaxReceiveBufferSize;
protected:
- enum ConnectionState {
- // Before a connection is successfully established (including a connect
- // request is pending or a previous connect request failed).
- BEFORE_CONNECT,
- // A connection has been successfully established (including a request of
- // initiating SSL is pending).
- CONNECTED,
- // An SSL connection has been successfully established.
- SSL_CONNECTED,
- // The connection has been ended.
- DISCONNECTED
- };
-
// C-tor used for new sockets.
TCPSocketResourceBase(Connection connection,
PP_Instance instance,
- bool private_api);
+ TCPSocketVersion version);
// C-tor used for already accepted sockets.
TCPSocketResourceBase(Connection connection,
PP_Instance instance,
- bool private_api,
+ TCPSocketVersion version,
const PP_NetAddress_Private& local_addr,
const PP_NetAddress_Private& remote_addr);
virtual ~TCPSocketResourceBase();
+ // Implemented by subclasses to create resources for accepted sockets.
+ virtual PP_Resource CreateAcceptedSocket(
+ int pending_host_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr) = 0;
+
+ int32_t BindImpl(const PP_NetAddress_Private* addr,
+ scoped_refptr<TrackedCallback> callback);
int32_t ConnectImpl(const char* host,
uint16_t port,
scoped_refptr<TrackedCallback> callback);
@@ -92,15 +89,19 @@ class PPAPI_PROXY_EXPORT TCPSocketResourceBase : public PluginResource {
int32_t WriteImpl(const char* buffer,
int32_t bytes_to_write,
scoped_refptr<TrackedCallback> callback);
- void DisconnectImpl();
+ int32_t ListenImpl(int32_t backlog, scoped_refptr<TrackedCallback> callback);
+ int32_t AcceptImpl(PP_Resource* accepted_tcp_socket,
+ scoped_refptr<TrackedCallback> callback);
+ void CloseImpl();
int32_t SetOptionImpl(PP_TCPSocket_Option name,
const PP_Var& value,
scoped_refptr<TrackedCallback> callback);
- bool IsConnected() const;
void PostAbortIfNecessary(scoped_refptr<TrackedCallback>* callback);
// IPC message handlers.
+ void OnPluginMsgBindReply(const ResourceMessageReplyParams& params,
+ const PP_NetAddress_Private& local_addr);
void OnPluginMsgConnectReply(const ResourceMessageReplyParams& params,
const PP_NetAddress_Private& local_addr,
const PP_NetAddress_Private& remote_addr);
@@ -110,15 +111,23 @@ class PPAPI_PROXY_EXPORT TCPSocketResourceBase : public PluginResource {
void OnPluginMsgReadReply(const ResourceMessageReplyParams& params,
const std::string& data);
void OnPluginMsgWriteReply(const ResourceMessageReplyParams& params);
+ void OnPluginMsgListenReply(const ResourceMessageReplyParams& params);
+ void OnPluginMsgAcceptReply(const ResourceMessageReplyParams& params,
+ int pending_host_id,
+ const PP_NetAddress_Private& local_addr,
+ const PP_NetAddress_Private& remote_addr);
void OnPluginMsgSetOptionReply(const ResourceMessageReplyParams& params);
+ scoped_refptr<TrackedCallback> bind_callback_;
scoped_refptr<TrackedCallback> connect_callback_;
scoped_refptr<TrackedCallback> ssl_handshake_callback_;
scoped_refptr<TrackedCallback> read_callback_;
scoped_refptr<TrackedCallback> write_callback_;
+ scoped_refptr<TrackedCallback> listen_callback_;
+ scoped_refptr<TrackedCallback> accept_callback_;
std::queue<scoped_refptr<TrackedCallback> > set_option_callbacks_;
- ConnectionState connection_state_;
+ TCPSocketState state_;
char* read_buffer_;
int32_t bytes_to_read_;
@@ -130,10 +139,12 @@ class PPAPI_PROXY_EXPORT TCPSocketResourceBase : public PluginResource {
std::vector<std::vector<char> > trusted_certificates_;
std::vector<std::vector<char> > untrusted_certificates_;
+ PP_Resource* accepted_tcp_socket_;
+
private:
void RunCallback(scoped_refptr<TrackedCallback> callback, int32_t pp_result);
- bool private_api_;
+ TCPSocketVersion version_;
DISALLOW_COPY_AND_ASSIGN(TCPSocketResourceBase);
};
diff --git a/ppapi/shared_impl/ppb_tcp_socket_shared.cc b/ppapi/shared_impl/ppb_tcp_socket_shared.cc
new file mode 100644
index 0000000..934c573
--- /dev/null
+++ b/ppapi/shared_impl/ppb_tcp_socket_shared.cc
@@ -0,0 +1,90 @@
+// 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 "ppapi/shared_impl/ppb_tcp_socket_shared.h"
+
+#include "base/logging.h"
+
+namespace ppapi {
+
+TCPSocketState::TCPSocketState(StateType state)
+ : state_(state),
+ pending_transition_(NONE) {
+ DCHECK(state_ == INITIAL || state_ == CONNECTED);
+}
+
+TCPSocketState::~TCPSocketState() {
+}
+
+void TCPSocketState::SetPendingTransition(TransitionType pending_transition) {
+ DCHECK(IsValidTransition(pending_transition));
+ pending_transition_ = pending_transition;
+}
+
+void TCPSocketState::CompletePendingTransition(bool success) {
+ switch (pending_transition_) {
+ case NONE:
+ NOTREACHED();
+ break;
+ case BIND:
+ if (success)
+ state_ = BOUND;
+ break;
+ case CONNECT:
+ state_ = success ? CONNECTED : CLOSED;
+ break;
+ case SSL_CONNECT:
+ state_ = success ? SSL_CONNECTED : CLOSED;
+ break;
+ case LISTEN:
+ if (success)
+ state_ = LISTENING;
+ break;
+ case CLOSE:
+ state_ = CLOSED;
+ break;
+ }
+ pending_transition_ = NONE;
+}
+
+void TCPSocketState::DoTransition(TransitionType transition, bool success) {
+ SetPendingTransition(transition);
+ CompletePendingTransition(success);
+}
+
+bool TCPSocketState::IsValidTransition(TransitionType transition) const {
+ if (pending_transition_ != NONE && transition != CLOSE)
+ return false;
+
+ switch (transition) {
+ case NONE:
+ return false;
+ case BIND:
+ return state_ == INITIAL;
+ case CONNECT:
+ return state_ == INITIAL || state_ == BOUND;
+ case SSL_CONNECT:
+ return state_ == CONNECTED;
+ case LISTEN:
+ return state_ == BOUND;
+ case CLOSE:
+ return true;
+ }
+ NOTREACHED();
+ return false;
+}
+
+bool TCPSocketState::IsPending(TransitionType transition) const {
+ return pending_transition_ == transition;
+}
+
+bool TCPSocketState::IsConnected() const {
+ return state_ == CONNECTED || state_ == SSL_CONNECTED;
+}
+
+bool TCPSocketState::IsBound() const {
+ return state_ != INITIAL && state_ != CLOSED;
+}
+
+} // namespace ppapi
diff --git a/ppapi/shared_impl/ppb_tcp_socket_shared.h b/ppapi/shared_impl/ppb_tcp_socket_shared.h
new file mode 100644
index 0000000..c723bdc
--- /dev/null
+++ b/ppapi/shared_impl/ppb_tcp_socket_shared.h
@@ -0,0 +1,74 @@
+// 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.
+
+#ifndef PPAPI_SHARED_IMPL_PPB_TCP_SOCKET_SHARED_H_
+#define PPAPI_SHARED_IMPL_PPB_TCP_SOCKET_SHARED_H_
+
+#include "ppapi/shared_impl/ppapi_shared_export.h"
+
+namespace ppapi {
+
+class PPAPI_SHARED_EXPORT TCPSocketState {
+ public:
+ enum StateType {
+ // The socket hasn't been bound or connected.
+ INITIAL,
+ // The socket has been bound.
+ BOUND,
+ // A connection has been established.
+ CONNECTED,
+ // An SSL connection has been established.
+ SSL_CONNECTED,
+ // The socket is listening.
+ LISTENING,
+ // The socket has been closed.
+ CLOSED
+ };
+
+ // Transitions that will change the socket state. Please note that
+ // read/write/accept are not included because they don't change the socket
+ // state.
+ enum TransitionType {
+ NONE,
+ BIND,
+ CONNECT,
+ SSL_CONNECT,
+ LISTEN,
+ CLOSE
+ };
+
+ explicit TCPSocketState(StateType state);
+ ~TCPSocketState();
+
+ StateType state() const { return state_; }
+
+ void SetPendingTransition(TransitionType pending_transition);
+ void CompletePendingTransition(bool success);
+
+ void DoTransition(TransitionType transition, bool success);
+
+ bool IsValidTransition(TransitionType transition) const;
+ bool IsPending(TransitionType transition) const;
+
+ bool IsConnected() const;
+ bool IsBound() const;
+
+ private:
+ StateType state_;
+ TransitionType pending_transition_;
+};
+
+// TCP socket API versions.
+enum PPAPI_SHARED_EXPORT TCPSocketVersion {
+ // PPB_TCPSocket_Private.
+ TCP_SOCKET_VERSION_PRIVATE,
+ // PPB_TCPSocket v1.0.
+ TCP_SOCKET_VERSION_1_0,
+ // PPB_TCPSocket v1.1 or above.
+ TCP_SOCKET_VERSION_1_1_OR_ABOVE
+};
+
+} // namespace ppapi
+
+#endif // PPAPI_SHARED_IMPL_PPB_TCP_SOCKET_SHARED_H_
diff --git a/ppapi/tests/test_tcp_socket.cc b/ppapi/tests/test_tcp_socket.cc
index a4c56eb..90f6913 100644
--- a/ppapi/tests/test_tcp_socket.cc
+++ b/ppapi/tests/test_tcp_socket.cc
@@ -4,6 +4,9 @@
#include "ppapi/tests/test_tcp_socket.h"
+#include <vector>
+
+#include "ppapi/cpp/message_loop.h"
#include "ppapi/cpp/tcp_socket.h"
#include "ppapi/tests/test_utils.h"
#include "ppapi/tests/testing_instance.h"
@@ -49,25 +52,58 @@ void TestTCPSocket::RunTests(const std::string& filter) {
RUN_CALLBACK_TEST(TestTCPSocket, Connect, filter);
RUN_CALLBACK_TEST(TestTCPSocket, ReadWrite, filter);
RUN_CALLBACK_TEST(TestTCPSocket, SetOption, filter);
+ RUN_CALLBACK_TEST(TestTCPSocket, Listen, filter);
+ RUN_CALLBACK_TEST(TestTCPSocket, Backlog, filter);
}
std::string TestTCPSocket::TestConnect() {
- pp::TCPSocket socket(instance_);
- TestCompletionCallback cb(instance_->pp_instance(), callback_type());
+ {
+ // The basic case.
+ pp::TCPSocket socket(instance_);
+ TestCompletionCallback cb(instance_->pp_instance(), callback_type());
- cb.WaitForResult(socket.Connect(addr_, cb.GetCallback()));
- CHECK_CALLBACK_BEHAVIOR(cb);
- ASSERT_EQ(PP_OK, cb.result());
+ cb.WaitForResult(socket.Connect(addr_, cb.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(cb);
+ ASSERT_EQ(PP_OK, cb.result());
+
+ pp::NetAddress local_addr, remote_addr;
+ local_addr = socket.GetLocalAddress();
+ remote_addr = socket.GetRemoteAddress();
+
+ ASSERT_NE(0, local_addr.pp_resource());
+ ASSERT_NE(0, remote_addr.pp_resource());
+ ASSERT_TRUE(EqualNetAddress(addr_, remote_addr));
- pp::NetAddress local_addr, remote_addr;
- local_addr = socket.GetLocalAddress();
- remote_addr = socket.GetRemoteAddress();
+ socket.Close();
+ }
+
+ {
+ // Connect a bound socket.
+ pp::TCPSocket socket(instance_);
+ TestCompletionCallback cb(instance_->pp_instance(), callback_type());
+
+ pp::NetAddress any_port_address;
+ ASSERT_SUBTEST_SUCCESS(GetAddressToBind(&any_port_address));
+
+ cb.WaitForResult(socket.Bind(any_port_address, cb.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(cb);
+ ASSERT_EQ(PP_OK, cb.result());
- ASSERT_NE(0, local_addr.pp_resource());
- ASSERT_NE(0, remote_addr.pp_resource());
- ASSERT_TRUE(EqualNetAddress(addr_, remote_addr));
+ cb.WaitForResult(socket.Connect(addr_, cb.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(cb);
+ ASSERT_EQ(PP_OK, cb.result());
- socket.Close();
+ pp::NetAddress local_addr, remote_addr;
+ local_addr = socket.GetLocalAddress();
+ remote_addr = socket.GetRemoteAddress();
+
+ ASSERT_NE(0, local_addr.pp_resource());
+ ASSERT_NE(0, remote_addr.pp_resource());
+ ASSERT_TRUE(EqualNetAddress(addr_, remote_addr));
+ ASSERT_NE(0u, GetPort(local_addr));
+
+ socket.Close();
+ }
PASS();
}
@@ -80,11 +116,11 @@ std::string TestTCPSocket::TestReadWrite() {
CHECK_CALLBACK_BEHAVIOR(cb);
ASSERT_EQ(PP_OK, cb.result());
- ASSERT_EQ(PP_OK, WriteStringToSocket(&socket, "GET / HTTP/1.0\r\n\r\n"));
+ ASSERT_SUBTEST_SUCCESS(WriteToSocket(&socket, "GET / HTTP/1.0\r\n\r\n"));
// Read up to the first \n and check that it looks like valid HTTP response.
std::string s;
- ASSERT_EQ(PP_OK, ReadFirstLineFromSocket(&socket, &s));
+ ASSERT_SUBTEST_SUCCESS(ReadFirstLineFromSocket(&socket, &s));
ASSERT_TRUE(ValidateHttpResponse(s));
PASS();
@@ -95,6 +131,7 @@ std::string TestTCPSocket::TestSetOption() {
TestCompletionCallback cb_1(instance_->pp_instance(), callback_type());
TestCompletionCallback cb_2(instance_->pp_instance(), callback_type());
TestCompletionCallback cb_3(instance_->pp_instance(), callback_type());
+ TestCompletionCallback cb_4(instance_->pp_instance(), callback_type());
// These options cannot be set before the socket is connected.
int32_t result_1 = socket.SetOption(PP_TCPSOCKET_OPTION_NO_DELAY,
@@ -104,6 +141,10 @@ std::string TestTCPSocket::TestSetOption() {
int32_t result_3 = socket.SetOption(PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE,
512, cb_3.GetCallback());
+ // This option can only be set before the socket is bound.
+ int32_t result_4 = socket.SetOption(PP_TCPSOCKET_OPTION_ADDRESS_REUSE,
+ true, cb_4.GetCallback());
+
cb_1.WaitForResult(result_1);
CHECK_CALLBACK_BEHAVIOR(cb_1);
ASSERT_EQ(PP_ERROR_FAILED, cb_1.result());
@@ -116,6 +157,10 @@ std::string TestTCPSocket::TestSetOption() {
CHECK_CALLBACK_BEHAVIOR(cb_3);
ASSERT_EQ(PP_ERROR_FAILED, cb_3.result());
+ cb_4.WaitForResult(result_4);
+ CHECK_CALLBACK_BEHAVIOR(cb_4);
+ ASSERT_EQ(PP_OK, cb_4.result());
+
cb_1.WaitForResult(socket.Connect(addr_, cb_1.GetCallback()));
CHECK_CALLBACK_BEHAVIOR(cb_1);
ASSERT_EQ(PP_OK, cb_1.result());
@@ -126,6 +171,8 @@ std::string TestTCPSocket::TestSetOption() {
512, cb_2.GetCallback());
result_3 = socket.SetOption(PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE,
1024, cb_3.GetCallback());
+ result_4 = socket.SetOption(PP_TCPSOCKET_OPTION_ADDRESS_REUSE,
+ false, cb_4.GetCallback());
cb_1.WaitForResult(result_1);
CHECK_CALLBACK_BEHAVIOR(cb_1);
@@ -139,53 +186,221 @@ std::string TestTCPSocket::TestSetOption() {
CHECK_CALLBACK_BEHAVIOR(cb_3);
ASSERT_EQ(PP_OK, cb_3.result());
+ cb_4.WaitForResult(result_4);
+ CHECK_CALLBACK_BEHAVIOR(cb_4);
+ ASSERT_EQ(PP_ERROR_FAILED, cb_4.result());
+
+ PASS();
+}
+
+std::string TestTCPSocket::TestListen() {
+ static const int kBacklog = 2;
+
+ pp::TCPSocket server_socket(instance_);
+ ASSERT_SUBTEST_SUCCESS(StartListen(&server_socket, kBacklog));
+
+ // We can't use a blocking callback for Accept, because it will wait forever
+ // for the client to connect, since the client connects after.
+ TestCompletionCallbackWithOutput<pp::TCPSocket>
+ accept_callback(instance_->pp_instance(), PP_REQUIRED);
+ // We need to make sure there's a message loop to run accept_callback on.
+ pp::MessageLoop current_thread_loop(pp::MessageLoop::GetCurrent());
+ if (current_thread_loop.is_null() && testing_interface_->IsOutOfProcess()) {
+ current_thread_loop = pp::MessageLoop(instance_);
+ current_thread_loop.AttachToCurrentThread();
+ }
+
+ int32_t accept_rv = server_socket.Accept(accept_callback.GetCallback());
+
+ pp::TCPSocket client_socket;
+ TestCompletionCallback callback(instance_->pp_instance(), callback_type());
+ do {
+ client_socket = pp::TCPSocket(instance_);
+
+ callback.WaitForResult(client_socket.Connect(
+ server_socket.GetLocalAddress(), callback.GetCallback()));
+ } while (callback.result() != PP_OK);
+
+ pp::NetAddress client_local_addr = client_socket.GetLocalAddress();
+ pp::NetAddress client_remote_addr = client_socket.GetRemoteAddress();
+ ASSERT_FALSE(client_local_addr.is_null());
+ ASSERT_FALSE(client_remote_addr.is_null());
+
+ accept_callback.WaitForResult(accept_rv);
+ CHECK_CALLBACK_BEHAVIOR(accept_callback);
+ ASSERT_EQ(PP_OK, accept_callback.result());
+
+ pp::TCPSocket accepted_socket(accept_callback.output());
+ pp::NetAddress accepted_local_addr = accepted_socket.GetLocalAddress();
+ pp::NetAddress accepted_remote_addr = accepted_socket.GetRemoteAddress();
+ ASSERT_FALSE(accepted_local_addr.is_null());
+ ASSERT_FALSE(accepted_remote_addr.is_null());
+
+ ASSERT_TRUE(EqualNetAddress(client_local_addr, accepted_remote_addr));
+
+ const char kSentByte = 'a';
+ ASSERT_SUBTEST_SUCCESS(WriteToSocket(&client_socket,
+ std::string(1, kSentByte)));
+
+ char received_byte;
+ ASSERT_SUBTEST_SUCCESS(ReadFromSocket(&accepted_socket,
+ &received_byte,
+ sizeof(received_byte)));
+ ASSERT_EQ(kSentByte, received_byte);
+
+ accepted_socket.Close();
+ client_socket.Close();
+ server_socket.Close();
+
PASS();
}
-int32_t TestTCPSocket::ReadFirstLineFromSocket(pp::TCPSocket* socket,
- std::string* s) {
+std::string TestTCPSocket::TestBacklog() {
+ static const size_t kBacklog = 5;
+
+ pp::TCPSocket server_socket(instance_);
+ ASSERT_SUBTEST_SUCCESS(StartListen(&server_socket, 2 * kBacklog));
+
+ std::vector<pp::TCPSocket*> client_sockets(kBacklog);
+ std::vector<TestCompletionCallback*> connect_callbacks(kBacklog);
+ std::vector<int32_t> connect_rv(kBacklog);
+ pp::NetAddress address = server_socket.GetLocalAddress();
+ for (size_t i = 0; i < kBacklog; ++i) {
+ client_sockets[i] = new pp::TCPSocket(instance_);
+ connect_callbacks[i] = new TestCompletionCallback(instance_->pp_instance(),
+ callback_type());
+ connect_rv[i] = client_sockets[i]->Connect(
+ address, connect_callbacks[i]->GetCallback());
+ }
+
+ std::vector<pp::TCPSocket*> accepted_sockets(kBacklog);
+ for (size_t i = 0; i < kBacklog; ++i) {
+ TestCompletionCallbackWithOutput<pp::TCPSocket> callback(
+ instance_->pp_instance(), callback_type());
+ callback.WaitForResult(server_socket.Accept(callback.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(callback);
+ ASSERT_EQ(PP_OK, callback.result());
+
+ accepted_sockets[i] = new pp::TCPSocket(callback.output());
+ ASSERT_FALSE(accepted_sockets[i]->is_null());
+ }
+
+ for (size_t i = 0; i < kBacklog; ++i) {
+ connect_callbacks[i]->WaitForResult(connect_rv[i]);
+ CHECK_CALLBACK_BEHAVIOR(*connect_callbacks[i]);
+ ASSERT_EQ(PP_OK, connect_callbacks[i]->result());
+ }
+
+ for (size_t i = 0; i < kBacklog; ++i) {
+ const char byte = 'a' + i;
+ ASSERT_SUBTEST_SUCCESS(WriteToSocket(client_sockets[i],
+ std::string(1, byte)));
+ }
+
+ bool byte_received[kBacklog] = {};
+ for (size_t i = 0; i < kBacklog; ++i) {
+ char byte;
+ ASSERT_SUBTEST_SUCCESS(ReadFromSocket(
+ accepted_sockets[i], &byte, sizeof(byte)));
+ const size_t index = byte - 'a';
+ ASSERT_GE(index, 0u);
+ ASSERT_LT(index, kBacklog);
+ ASSERT_FALSE(byte_received[index]);
+ byte_received[index] = true;
+ }
+
+ for (size_t i = 0; i < kBacklog; ++i) {
+ ASSERT_TRUE(byte_received[i]);
+
+ delete client_sockets[i];
+ delete connect_callbacks[i];
+ delete accepted_sockets[i];
+ }
+
+ PASS();
+}
+
+std::string TestTCPSocket::ReadFirstLineFromSocket(pp::TCPSocket* socket,
+ std::string* s) {
char buffer[1000];
s->clear();
// Make sure we don't just hang if |Read()| spews.
while (s->size() < 10000) {
TestCompletionCallback cb(instance_->pp_instance(), callback_type());
- int32_t rv = socket->Read(buffer, sizeof(buffer), cb.GetCallback());
- if (callback_type() == PP_REQUIRED && rv != PP_OK_COMPLETIONPENDING)
- return PP_ERROR_FAILED;
- cb.WaitForResult(rv);
- if (cb.result() < 0)
- return cb.result();
- if (cb.result() == 0)
- return PP_ERROR_FAILED; // Didn't get a \n-terminated line.
+ cb.WaitForResult(socket->Read(buffer, sizeof(buffer), cb.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(cb);
+ ASSERT_GT(cb.result(), 0);
s->reserve(s->size() + cb.result());
- for (int32_t i = 0; i < cb.result(); i++) {
+ for (int32_t i = 0; i < cb.result(); ++i) {
s->push_back(buffer[i]);
if (buffer[i] == '\n')
- return PP_OK;
+ PASS();
}
}
- return PP_ERROR_FAILED;
+ PASS();
+}
+
+std::string TestTCPSocket::ReadFromSocket(pp::TCPSocket* socket,
+ char* buffer,
+ size_t num_bytes) {
+ while (num_bytes > 0) {
+ TestCompletionCallback callback(instance_->pp_instance(), callback_type());
+ callback.WaitForResult(
+ socket->Read(buffer, num_bytes, callback.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(callback);
+ ASSERT_GT(callback.result(), 0);
+ buffer += callback.result();
+ num_bytes -= callback.result();
+ }
+ ASSERT_EQ(0u, num_bytes);
+ PASS();
}
-int32_t TestTCPSocket::WriteStringToSocket(pp::TCPSocket* socket,
- const std::string& s) {
+std::string TestTCPSocket::WriteToSocket(pp::TCPSocket* socket,
+ const std::string& s) {
const char* buffer = s.data();
size_t written = 0;
while (written < s.size()) {
TestCompletionCallback cb(instance_->pp_instance(), callback_type());
- int32_t rv = socket->Write(buffer + written, s.size() - written,
- cb.GetCallback());
- if (callback_type() == PP_REQUIRED && rv != PP_OK_COMPLETIONPENDING)
- return PP_ERROR_FAILED;
- cb.WaitForResult(rv);
- if (cb.result() < 0)
- return cb.result();
- if (cb.result() == 0)
- return PP_ERROR_FAILED;
+ cb.WaitForResult(
+ socket->Write(buffer + written, s.size() - written, cb.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(cb);
+ ASSERT_GT(cb.result(), 0);
written += cb.result();
}
- if (written != s.size())
- return PP_ERROR_FAILED;
- return PP_OK;
+ ASSERT_EQ(written, s.size());
+ PASS();
}
+
+std::string TestTCPSocket::GetAddressToBind(pp::NetAddress* address) {
+ pp::TCPSocket socket(instance_);
+ TestCompletionCallback callback(instance_->pp_instance(), callback_type());
+ callback.WaitForResult(socket.Connect(addr_, callback.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(callback);
+ ASSERT_EQ(PP_OK, callback.result());
+
+ ASSERT_TRUE(ReplacePort(instance_->pp_instance(), socket.GetLocalAddress(), 0,
+ address));
+ ASSERT_FALSE(address->is_null());
+ PASS();
+}
+
+std::string TestTCPSocket::StartListen(pp::TCPSocket* socket, int32_t backlog) {
+ pp::NetAddress any_port_address;
+ ASSERT_SUBTEST_SUCCESS(GetAddressToBind(&any_port_address));
+
+ TestCompletionCallback callback(instance_->pp_instance(), callback_type());
+ callback.WaitForResult(
+ socket->Bind(any_port_address, callback.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(callback);
+ ASSERT_EQ(PP_OK, callback.result());
+
+ callback.WaitForResult(
+ socket->Listen(backlog, callback.GetCallback()));
+ CHECK_CALLBACK_BEHAVIOR(callback);
+ ASSERT_EQ(PP_OK, callback.result());
+
+ PASS();
+}
+
diff --git a/ppapi/tests/test_tcp_socket.h b/ppapi/tests/test_tcp_socket.h
index 44c7321..136dc46 100644
--- a/ppapi/tests/test_tcp_socket.h
+++ b/ppapi/tests/test_tcp_socket.h
@@ -27,9 +27,16 @@ class TestTCPSocket: public TestCase {
std::string TestConnect();
std::string TestReadWrite();
std::string TestSetOption();
-
- int32_t ReadFirstLineFromSocket(pp::TCPSocket* socket, std::string* s);
- int32_t WriteStringToSocket(pp::TCPSocket* socket, const std::string& s);
+ std::string TestListen();
+ std::string TestBacklog();
+
+ std::string ReadFirstLineFromSocket(pp::TCPSocket* socket, std::string* s);
+ std::string ReadFromSocket(pp::TCPSocket* socket,
+ char* buffer,
+ size_t num_bytes);
+ std::string WriteToSocket(pp::TCPSocket* socket, const std::string& s);
+ std::string GetAddressToBind(pp::NetAddress* address);
+ std::string StartListen(pp::TCPSocket* socket, int32_t backlog);
pp::NetAddress addr_;
};
diff --git a/ppapi/tests/test_utils.cc b/ppapi/tests/test_utils.cc
index f9fd7b6..eecbe7a 100644
--- a/ppapi/tests/test_utils.cc
+++ b/ppapi/tests/test_utils.cc
@@ -179,6 +179,53 @@ bool ResolveHost(PP_Instance instance,
}
}
+bool ReplacePort(PP_Instance instance,
+ const pp::NetAddress& input_addr,
+ uint16_t port,
+ pp::NetAddress* output_addr) {
+ switch (input_addr.GetFamily()) {
+ case PP_NETADDRESS_FAMILY_IPV4: {
+ PP_NetAddress_IPv4 ipv4_addr;
+ if (!input_addr.DescribeAsIPv4Address(&ipv4_addr))
+ return false;
+ ipv4_addr.port = ConvertToNetEndian16(port);
+ *output_addr = pp::NetAddress(pp::InstanceHandle(instance), ipv4_addr);
+ return true;
+ }
+ case PP_NETADDRESS_FAMILY_IPV6: {
+ PP_NetAddress_IPv6 ipv6_addr;
+ if (!input_addr.DescribeAsIPv6Address(&ipv6_addr))
+ return false;
+ ipv6_addr.port = ConvertToNetEndian16(port);
+ *output_addr = pp::NetAddress(pp::InstanceHandle(instance), ipv6_addr);
+ return true;
+ }
+ default: {
+ return false;
+ }
+ }
+}
+
+uint16_t GetPort(const pp::NetAddress& addr) {
+ switch (addr.GetFamily()) {
+ case PP_NETADDRESS_FAMILY_IPV4: {
+ PP_NetAddress_IPv4 ipv4_addr;
+ if (!addr.DescribeAsIPv4Address(&ipv4_addr))
+ return 0;
+ return ConvertFromNetEndian16(ipv4_addr.port);
+ }
+ case PP_NETADDRESS_FAMILY_IPV6: {
+ PP_NetAddress_IPv6 ipv6_addr;
+ if (!addr.DescribeAsIPv6Address(&ipv6_addr))
+ return 0;
+ return ConvertFromNetEndian16(ipv6_addr.port);
+ }
+ default: {
+ return 0;
+ }
+ }
+}
+
void NestedEvent::Wait() {
PP_DCHECK(pp::Module::Get()->core()->IsMainThread());
// Don't allow nesting more than once; it doesn't work with the code as-is,
diff --git a/ppapi/tests/test_utils.h b/ppapi/tests/test_utils.h
index 357a1c6..4621c355 100644
--- a/ppapi/tests/test_utils.h
+++ b/ppapi/tests/test_utils.h
@@ -34,6 +34,11 @@ bool ResolveHost(PP_Instance instance,
const std::string& host,
uint16_t port,
pp::NetAddress* addr);
+bool ReplacePort(PP_Instance instance,
+ const pp::NetAddress& input_addr,
+ uint16_t port,
+ pp::NetAddress* output_addr);
+uint16_t GetPort(const pp::NetAddress& addr);
// NestedEvent allows you to run a nested MessageLoop and wait for a particular
// event to complete. For example, you can use it to wait for a callback on a
diff --git a/ppapi/thunk/interfaces_ppb_public_stable.h b/ppapi/thunk/interfaces_ppb_public_stable.h
index 7747bfc..7327cde 100644
--- a/ppapi/thunk/interfaces_ppb_public_stable.h
+++ b/ppapi/thunk/interfaces_ppb_public_stable.h
@@ -78,6 +78,7 @@ PROXIED_IFACE(PPB_Instance, PPB_MOUSELOCK_INTERFACE_1_0, PPB_MouseLock_1_0)
PROXIED_IFACE(NoAPIName, PPB_NETADDRESS_INTERFACE_1_0, PPB_NetAddress_1_0)
PROXIED_IFACE(NoAPIName, PPB_NETWORKPROXY_INTERFACE_1_0, PPB_NetworkProxy_1_0)
PROXIED_IFACE(NoAPIName, PPB_TCPSOCKET_INTERFACE_1_0, PPB_TCPSocket_1_0)
+PROXIED_IFACE(NoAPIName, PPB_TCPSOCKET_INTERFACE_1_1, PPB_TCPSocket_1_1)
PROXIED_IFACE(NoAPIName, PPB_TEXTINPUTCONTROLLER_INTERFACE_1_0,
PPB_TextInputController_1_0)
PROXIED_IFACE(NoAPIName, PPB_UDPSOCKET_INTERFACE_1_0, PPB_UDPSocket_1_0)
diff --git a/ppapi/thunk/ppb_tcp_socket_api.h b/ppapi/thunk/ppb_tcp_socket_api.h
index d33685f..beed0c6 100644
--- a/ppapi/thunk/ppb_tcp_socket_api.h
+++ b/ppapi/thunk/ppb_tcp_socket_api.h
@@ -19,6 +19,8 @@ class PPAPI_THUNK_EXPORT PPB_TCPSocket_API {
public:
virtual ~PPB_TCPSocket_API() {}
+ virtual int32_t Bind(PP_Resource addr,
+ scoped_refptr<TrackedCallback> callback) = 0;
virtual int32_t Connect(PP_Resource addr,
scoped_refptr<TrackedCallback> callback) = 0;
virtual PP_Resource GetLocalAddress() = 0;
@@ -29,6 +31,10 @@ class PPAPI_THUNK_EXPORT PPB_TCPSocket_API {
virtual int32_t Write(const char* buffer,
int32_t bytes_to_write,
scoped_refptr<TrackedCallback> callback) = 0;
+ virtual int32_t Listen(int32_t backlog,
+ scoped_refptr<TrackedCallback> callback) = 0;
+ virtual int32_t Accept(PP_Resource* accepted_tcp_socket,
+ scoped_refptr<TrackedCallback> callback) = 0;
virtual void Close() = 0;
virtual int32_t SetOption(PP_TCPSocket_Option name,
const PP_Var& value,
diff --git a/ppapi/thunk/ppb_tcp_socket_thunk.cc b/ppapi/thunk/ppb_tcp_socket_thunk.cc
index ff612fb..42ae702 100644
--- a/ppapi/thunk/ppb_tcp_socket_thunk.cc
+++ b/ppapi/thunk/ppb_tcp_socket_thunk.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-// From ppb_tcp_socket.idl modified Thu Jun 20 16:36:53 2013.
+// From ppb_tcp_socket.idl modified Sun Sep 15 16:14:21 2013.
#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/pp_errors.h"
@@ -19,6 +19,14 @@ namespace thunk {
namespace {
+PP_Resource Create_1_0(PP_Instance instance) {
+ VLOG(4) << "PPB_TCPSocket::Create_1_0()";
+ EnterResourceCreation enter(instance);
+ if (enter.failed())
+ return 0;
+ return enter.functions()->CreateTCPSocket1_0(instance);
+}
+
PP_Resource Create(PP_Instance instance) {
VLOG(4) << "PPB_TCPSocket::Create()";
EnterResourceCreation enter(instance);
@@ -33,6 +41,16 @@ PP_Bool IsTCPSocket(PP_Resource resource) {
return PP_FromBool(enter.succeeded());
}
+int32_t Bind(PP_Resource tcp_socket,
+ PP_Resource addr,
+ struct PP_CompletionCallback callback) {
+ VLOG(4) << "PPB_TCPSocket::Bind()";
+ EnterResource<PPB_TCPSocket_API> enter(tcp_socket, callback, true);
+ if (enter.failed())
+ return enter.retval();
+ return enter.SetResult(enter.object()->Bind(addr, enter.callback()));
+}
+
int32_t Connect(PP_Resource tcp_socket,
PP_Resource addr,
struct PP_CompletionCallback callback) {
@@ -85,6 +103,27 @@ int32_t Write(PP_Resource tcp_socket,
enter.callback()));
}
+int32_t Listen(PP_Resource tcp_socket,
+ int32_t backlog,
+ struct PP_CompletionCallback callback) {
+ VLOG(4) << "PPB_TCPSocket::Listen()";
+ EnterResource<PPB_TCPSocket_API> enter(tcp_socket, callback, true);
+ if (enter.failed())
+ return enter.retval();
+ return enter.SetResult(enter.object()->Listen(backlog, enter.callback()));
+}
+
+int32_t Accept(PP_Resource tcp_socket,
+ PP_Resource* accepted_tcp_socket,
+ struct PP_CompletionCallback callback) {
+ VLOG(4) << "PPB_TCPSocket::Accept()";
+ EnterResource<PPB_TCPSocket_API> enter(tcp_socket, callback, true);
+ if (enter.failed())
+ return enter.retval();
+ return enter.SetResult(enter.object()->Accept(accepted_tcp_socket,
+ enter.callback()));
+}
+
void Close(PP_Resource tcp_socket) {
VLOG(4) << "PPB_TCPSocket::Close()";
EnterResource<PPB_TCPSocket_API> enter(tcp_socket, true);
@@ -107,13 +146,28 @@ int32_t SetOption(PP_Resource tcp_socket,
}
const PPB_TCPSocket_1_0 g_ppb_tcpsocket_thunk_1_0 = {
+ &Create_1_0,
+ &IsTCPSocket,
+ &Connect,
+ &GetLocalAddress,
+ &GetRemoteAddress,
+ &Read,
+ &Write,
+ &Close,
+ &SetOption
+};
+
+const PPB_TCPSocket_1_1 g_ppb_tcpsocket_thunk_1_1 = {
&Create,
&IsTCPSocket,
+ &Bind,
&Connect,
&GetLocalAddress,
&GetRemoteAddress,
&Read,
&Write,
+ &Listen,
+ &Accept,
&Close,
&SetOption
};
@@ -124,5 +178,9 @@ const PPB_TCPSocket_1_0* GetPPB_TCPSocket_1_0_Thunk() {
return &g_ppb_tcpsocket_thunk_1_0;
}
+const PPB_TCPSocket_1_1* GetPPB_TCPSocket_1_1_Thunk() {
+ return &g_ppb_tcpsocket_thunk_1_1;
+}
+
} // namespace thunk
} // namespace ppapi
diff --git a/ppapi/thunk/resource_creation_api.h b/ppapi/thunk/resource_creation_api.h
index ae080bb..16f3d6b 100644
--- a/ppapi/thunk/resource_creation_api.h
+++ b/ppapi/thunk/resource_creation_api.h
@@ -148,7 +148,8 @@ class ResourceCreationAPI {
virtual PP_Resource CreateNetworkMonitorPrivate(PP_Instance instance) = 0;
virtual PP_Resource CreatePrinting(PP_Instance instance) = 0;
virtual PP_Resource CreateTCPServerSocketPrivate(PP_Instance instance) = 0;
- virtual PP_Resource CreateTCPSocket(PP_Instance instace) = 0;
+ virtual PP_Resource CreateTCPSocket1_0(PP_Instance instace) = 0;
+ virtual PP_Resource CreateTCPSocket(PP_Instance instance) = 0;
virtual PP_Resource CreateTCPSocketPrivate(PP_Instance instace) = 0;
virtual PP_Resource CreateUDPSocket(PP_Instance instace) = 0;
virtual PP_Resource CreateUDPSocketPrivate(PP_Instance instace) = 0;