summaryrefslogtreecommitdiffstats
path: root/ppapi
diff options
context:
space:
mode:
authorddorwin@chromium.org <ddorwin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-17 00:13:22 +0000
committerddorwin@chromium.org <ddorwin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-04-17 00:13:22 +0000
commitae971c2c0dea23a076b4320b0eaba69d2636ff4e (patch)
treefb3d3591130f13f4e6205c0b363dc09b5fd91d32 /ppapi
parenta3eba772e8722dd01052827357bba24656fbf651 (diff)
downloadchromium_src-ae971c2c0dea23a076b4320b0eaba69d2636ff4e.zip
chromium_src-ae971c2c0dea23a076b4320b0eaba69d2636ff4e.tar.gz
chromium_src-ae971c2c0dea23a076b4320b0eaba69d2636ff4e.tar.bz2
Implemented PPB_Broker_Proxy.
BUG=none TEST=none Review URL: http://codereview.chromium.org/6833002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@81888 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ppapi')
-rw-r--r--ppapi/c/trusted/ppb_broker_trusted.h15
-rw-r--r--ppapi/ppapi_shared_proxy.gypi2
-rw-r--r--ppapi/proxy/dispatcher.cc2
-rw-r--r--ppapi/proxy/interface_id.h1
-rw-r--r--ppapi/proxy/plugin_resource.h1
-rw-r--r--ppapi/proxy/ppapi_messages.h14
-rw-r--r--ppapi/proxy/ppb_broker_proxy.cc284
-rw-r--r--ppapi/proxy/ppb_broker_proxy.h54
8 files changed, 371 insertions, 2 deletions
diff --git a/ppapi/c/trusted/ppb_broker_trusted.h b/ppapi/c/trusted/ppb_broker_trusted.h
index 68f2a97..a3c498e 100644
--- a/ppapi/c/trusted/ppb_broker_trusted.h
+++ b/ppapi/c/trusted/ppb_broker_trusted.h
@@ -28,6 +28,11 @@
* with greater privileges than the plugin. The interface only supports
* out-of-process plugins and is to be used by proxy implementations. All
* functions should be called from the main thread only.
+ *
+ * A PPB_BrokerTrusted resource represents a connection to the broker. Its
+ * lifetime controls the lifetime of the broker, regardless of whether the
+ * handle is closed. The handle should be closed before the resource is
+ * released.
*/
struct PPB_BrokerTrusted {
/**
@@ -42,7 +47,12 @@ struct PPB_BrokerTrusted {
/**
* Connects to the trusted broker. It may have already
- * been launched by another plugin instance.
+ * been launched by another instance.
+ * The plugin takes ownership of the handle once the callback has been called
+ * with a result of PP_OK. The plugin should immediately call GetHandle and
+ * begin managing it. If the result is not PP_OK, the browser still owns the
+ * handle.
+ *
* Returns PP_ERROR_WOULD_BLOCK on success, and invokes
* the |connect_callback| asynchronously to complete.
* As this function should always be invoked from the main thread,
@@ -55,7 +65,8 @@ struct PPB_BrokerTrusted {
/**
* Returns the handle to the pipe. Use once Connect has completed.
* Returns PP_OK on success.
- * Each plugin instance has its own pipe.
+ * Each instance of this interface has its own pipe.
+ * handle is only set when returning PP_OK.
*/
int32_t (*GetHandle)(PP_Resource broker, int32_t* handle);
};
diff --git a/ppapi/ppapi_shared_proxy.gypi b/ppapi/ppapi_shared_proxy.gypi
index 1ddb78e..c6b88f8 100644
--- a/ppapi/ppapi_shared_proxy.gypi
+++ b/ppapi/ppapi_shared_proxy.gypi
@@ -85,6 +85,8 @@
'proxy/ppb_audio_config_proxy.h',
'proxy/ppb_audio_proxy.cc',
'proxy/ppb_audio_proxy.h',
+ 'proxy/ppb_broker_proxy.cc',
+ 'proxy/ppb_broker_proxy.h',
'proxy/ppb_buffer_proxy.cc',
'proxy/ppb_buffer_proxy.h',
'proxy/ppb_char_set_proxy.cc',
diff --git a/ppapi/proxy/dispatcher.cc b/ppapi/proxy/dispatcher.cc
index 36f8f0a..2964835 100644
--- a/ppapi/proxy/dispatcher.cc
+++ b/ppapi/proxy/dispatcher.cc
@@ -44,6 +44,7 @@
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/ppb_audio_config_proxy.h"
#include "ppapi/proxy/ppb_audio_proxy.h"
+#include "ppapi/proxy/ppb_broker_proxy.h"
#include "ppapi/proxy/ppb_buffer_proxy.h"
#include "ppapi/proxy/ppb_char_set_proxy.h"
#include "ppapi/proxy/ppb_console_proxy.h"
@@ -106,6 +107,7 @@ InterfaceList::InterfaceList() {
// PPB (browser) interfaces.
AddPPB(PPB_AudioConfig_Proxy::GetInfo());
AddPPB(PPB_Audio_Proxy::GetInfo());
+ AddPPB(PPB_Broker_Proxy::GetInfo());
AddPPB(PPB_Buffer_Proxy::GetInfo());
AddPPB(PPB_CharSet_Proxy::GetInfo());
AddPPB(PPB_Console_Proxy::GetInfo());
diff --git a/ppapi/proxy/interface_id.h b/ppapi/proxy/interface_id.h
index a573346..10ef8c4 100644
--- a/ppapi/proxy/interface_id.h
+++ b/ppapi/proxy/interface_id.h
@@ -15,6 +15,7 @@ enum InterfaceID {
INTERFACE_ID_NONE = 0,
INTERFACE_ID_PPB_AUDIO = 1,
INTERFACE_ID_PPB_AUDIO_CONFIG,
+ INTERFACE_ID_PPB_BROKER,
INTERFACE_ID_PPB_BUFFER,
INTERFACE_ID_PPB_CHAR_SET,
INTERFACE_ID_PPB_CONSOLE,
diff --git a/ppapi/proxy/plugin_resource.h b/ppapi/proxy/plugin_resource.h
index 1a5e081..57fd4ac 100644
--- a/ppapi/proxy/plugin_resource.h
+++ b/ppapi/proxy/plugin_resource.h
@@ -15,6 +15,7 @@
#define FOR_ALL_PLUGIN_RESOURCES(F) \
F(Audio) \
F(AudioConfig) \
+ F(Broker) \
F(Buffer) \
F(Context3D) \
F(FileChooser) \
diff --git a/ppapi/proxy/ppapi_messages.h b/ppapi/proxy/ppapi_messages.h
index 270af84..3749961 100644
--- a/ppapi/proxy/ppapi_messages.h
+++ b/ppapi/proxy/ppapi_messages.h
@@ -83,6 +83,13 @@ IPC_MESSAGE_ROUTED5(PpapiMsg_PPBAudio_NotifyAudioStreamCreated,
base::SharedMemoryHandle /* handle */,
int32_t /* length */)
+// PPB_Broker.
+IPC_MESSAGE_ROUTED3(
+ PpapiMsg_PPBBroker_ConnectComplete,
+ pp::proxy::HostResource /* broker */,
+ IPC::PlatformFileForTransit /* handle */,
+ int32_t /* result */)
+
// PPB_FileChooser.
IPC_MESSAGE_ROUTED3(
PpapiMsg_PPBFileChooser_ChooseComplete,
@@ -238,6 +245,13 @@ IPC_SYNC_MESSAGE_ROUTED2_1(
uint32_t /* requested */,
uint32_t /* result */)
+// PPB_Broker.
+IPC_SYNC_MESSAGE_ROUTED1_1(PpapiHostMsg_PPBBroker_Create,
+ PP_Instance /* instance */,
+ pp::proxy::HostResource /* result_resource */)
+IPC_MESSAGE_ROUTED1(PpapiHostMsg_PPBBroker_Connect,
+ pp::proxy::HostResource /* broker */)
+
// PPB_Buffer.
IPC_SYNC_MESSAGE_ROUTED2_2(PpapiHostMsg_PPBBuffer_Create,
PP_Instance /* instance */,
diff --git a/ppapi/proxy/ppb_broker_proxy.cc b/ppapi/proxy/ppb_broker_proxy.cc
new file mode 100644
index 0000000..44747a9
--- /dev/null
+++ b/ppapi/proxy/ppb_broker_proxy.cc
@@ -0,0 +1,284 @@
+// Copyright (c) 2011 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/proxy/ppb_broker_proxy.h"
+
+#include "ppapi/c/pp_errors.h"
+#include "ppapi/c/trusted/ppb_broker_trusted.h"
+#include "ppapi/proxy/plugin_dispatcher.h"
+#include "ppapi/proxy/plugin_resource.h"
+#include "ppapi/proxy/ppapi_messages.h"
+
+namespace pp {
+namespace proxy {
+
+class Broker : public PluginResource {
+ public:
+ explicit Broker(const HostResource& resource);
+ virtual ~Broker();
+
+ // Resource overrides.
+ virtual Broker* AsBroker() { return this; }
+
+ bool called_connect_;
+ PP_CompletionCallback current_connect_callback_;
+
+ // The plugin module owns the handle.
+ // The host side transfers ownership of the handle to the plugin side when it
+ // sends the IPC. This member holds the handle value for the plugin module
+ // to read, but the plugin side of the proxy never takes ownership.
+ base::SyncSocket::Handle socket_handle_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Broker);
+};
+
+Broker::Broker(const HostResource& resource)
+ : PluginResource(resource),
+ called_connect_(false),
+ current_connect_callback_(PP_MakeCompletionCallback(NULL, NULL)),
+ socket_handle_(base::kInvalidPlatformFileValue) {
+}
+
+Broker::~Broker() {
+ // Ensure the callback is always fired.
+ if (current_connect_callback_.func) {
+ // TODO(brettw) the callbacks at this level should be refactored with a
+ // more automatic tracking system like we have in the renderer.
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction(
+ current_connect_callback_.func, current_connect_callback_.user_data,
+ static_cast<int32_t>(PP_ERROR_ABORTED)));
+ }
+
+ socket_handle_ = base::kInvalidPlatformFileValue;
+}
+
+namespace {
+
+base::PlatformFile IntToPlatformFile(int32_t handle) {
+#if defined(OS_WIN)
+ return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle));
+#elif defined(OS_POSIX)
+ return handle;
+#else
+ #error Not implemented.
+#endif
+}
+
+int32_t PlatformFileToInt(base::PlatformFile handle) {
+#if defined(OS_WIN)
+ return static_cast<int32_t>(reinterpret_cast<intptr_t>(handle));
+#elif defined(OS_POSIX)
+ return handle;
+#else
+ #error Not implemented.
+#endif
+}
+
+PP_Resource CreateTrusted(PP_Instance instance) {
+ PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
+ if (!dispatcher)
+ return 0;
+
+ HostResource result;
+ dispatcher->Send(new PpapiHostMsg_PPBBroker_Create(
+ INTERFACE_ID_PPB_BROKER, instance, &result));
+ if (result.is_null())
+ return 0;
+
+ linked_ptr<Broker> object(new Broker(result));
+ return PluginResourceTracker::GetInstance()->AddResource(object);
+}
+
+PP_Bool IsBrokerTrusted(PP_Resource resource) {
+ Broker* object = PluginResource::GetAs<Broker>(resource);
+ return BoolToPPBool(!!object);
+}
+
+int32_t Connect(PP_Resource resource,
+ PP_CompletionCallback connect_callback) {
+ Broker* object = PluginResource::GetAs<Broker>(resource);
+ if (!object)
+ return PP_ERROR_BADRESOURCE;
+
+ Dispatcher* dispatcher = PluginDispatcher::GetForInstance(object->instance());
+ if (!dispatcher)
+ return PP_ERROR_BADRESOURCE;
+
+ if (!connect_callback.func) {
+ // Synchronous calls are not supported.
+ return PP_ERROR_BADARGUMENT;
+ }
+
+ if (object->current_connect_callback_.func)
+ return PP_ERROR_INPROGRESS;
+ else if (object->called_connect_)
+ return PP_ERROR_FAILED;
+
+ object->current_connect_callback_ = connect_callback;
+ object->called_connect_ = true;
+
+ bool success = dispatcher->Send(new PpapiHostMsg_PPBBroker_Connect(
+ INTERFACE_ID_PPB_BROKER,
+ object->host_resource()));
+ return success ? PP_OK_COMPLETIONPENDING : PP_ERROR_FAILED;
+}
+
+int32_t GetHandle(PP_Resource resource, int32_t* handle) {
+ Broker* object = PluginResource::GetAs<Broker>(resource);
+ if (!object)
+ return PP_ERROR_BADRESOURCE;
+ *handle = PlatformFileToInt(object->socket_handle_);
+ return PP_OK;
+}
+
+const PPB_BrokerTrusted broker_interface = {
+ &CreateTrusted,
+ &IsBrokerTrusted,
+ &Connect,
+ &GetHandle,
+};
+
+InterfaceProxy* CreateBrokerProxy(Dispatcher* dispatcher,
+ const void* target_interface) {
+ return new PPB_Broker_Proxy(dispatcher, target_interface);
+}
+
+} // namespace
+
+PPB_Broker_Proxy::PPB_Broker_Proxy(Dispatcher* dispatcher,
+ const void* target_interface)
+ : InterfaceProxy(dispatcher, target_interface) ,
+ callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)){
+}
+
+PPB_Broker_Proxy::~PPB_Broker_Proxy() {
+}
+
+// static
+const InterfaceProxy::Info* PPB_Broker_Proxy::GetInfo() {
+ static const Info info = {
+ &broker_interface,
+ PPB_BROKER_TRUSTED_INTERFACE,
+ INTERFACE_ID_PPB_BROKER,
+ true,
+ &CreateBrokerProxy,
+ };
+ return &info;
+}
+
+bool PPB_Broker_Proxy::OnMessageReceived(const IPC::Message& msg) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(PPB_Broker_Proxy, msg)
+ IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Create, OnMsgCreate)
+ IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Connect, OnMsgConnect)
+ IPC_MESSAGE_HANDLER(PpapiMsg_PPBBroker_ConnectComplete,
+ OnMsgConnectComplete)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void PPB_Broker_Proxy::OnMsgCreate(PP_Instance instance,
+ HostResource* result_resource) {
+ result_resource->SetHostResource(
+ instance,
+ ppb_broker_target()->CreateTrusted(instance));
+}
+
+void PPB_Broker_Proxy::OnMsgConnect(const HostResource& broker) {
+ CompletionCallback callback = callback_factory_.NewCallback(
+ &PPB_Broker_Proxy::ConnectCompleteInHost, broker);
+
+ int32_t result = ppb_broker_target()->Connect(
+ broker.host_resource(),
+ callback.pp_completion_callback());
+ if (result != PP_OK_COMPLETIONPENDING)
+ callback.Run(result);
+}
+
+// Called in the plugin to handle the connect callback.
+// The proxy owns the handle and transfers it to the Broker. At that point,
+// the plugin owns the handle and is responsible for closing it.
+// The caller guarantees that socket_handle is not valid if result is not PP_OK.
+void PPB_Broker_Proxy::OnMsgConnectComplete(
+ const HostResource& broker,
+ IPC::PlatformFileForTransit socket_handle,
+ int32_t result) {
+ DCHECK(result == PP_OK ||
+ socket_handle == IPC::InvalidPlatformFileForTransit());
+
+ Broker* object = NULL;
+ if (result == PP_OK) {
+ object = PluginResource::GetAs<Broker>(
+ PluginResourceTracker::GetInstance()->PluginResourceForHostResource(
+ broker));
+ if (!object)
+ result = PP_ERROR_BADRESOURCE;
+ }
+
+ if (result == PP_OK) {
+ object->socket_handle_ =
+ IPC::PlatformFileForTransitToPlatformFile(socket_handle);
+ } else {
+ // The caller may still have given us a handle in the failure case.
+ // The easiest way to clean it up is to just put it in an object
+ // and then close them. This failure case is not performance critical.
+ base::SyncSocket temp_socket(
+ IPC::PlatformFileForTransitToPlatformFile(socket_handle));
+ }
+
+ if (!object->current_connect_callback_.func) {
+ // The handle might leak if the plugin never calls GetHandle().
+ return;
+ }
+
+ PP_CompletionCallback callback = object->current_connect_callback_;
+ object->current_connect_callback_ = PP_MakeCompletionCallback(NULL, NULL);
+ PP_RunCompletionCallback(&callback, result);
+}
+
+// Callback on the host side.
+// Transfers ownership of the handle to the plugin side. This function must
+// either successfully call the callback or close the handle.
+void PPB_Broker_Proxy::ConnectCompleteInHost(int32_t result,
+ const HostResource& broker) {
+ IPC::PlatformFileForTransit foreign_socket_handle =
+ IPC::InvalidPlatformFileForTransit();
+ if (result == PP_OK) {
+ int32_t socket_handle = PlatformFileToInt(base::kInvalidPlatformFileValue);
+ result = ppb_broker_target()->GetHandle(broker.host_resource(),
+ &socket_handle);
+ DCHECK(result == PP_OK ||
+ socket_handle == PlatformFileToInt(base::kInvalidPlatformFileValue));
+
+ if (result == PP_OK) {
+ foreign_socket_handle =
+ dispatcher()->ShareHandleWithRemote(IntToPlatformFile(socket_handle),
+ true);
+ if (foreign_socket_handle == IPC::InvalidPlatformFileForTransit()) {
+ result = PP_ERROR_FAILED;
+ // Assume the local handle was closed even if the foreign handle could
+ // not be created.
+ }
+ }
+ }
+ DCHECK(result == PP_OK ||
+ foreign_socket_handle == IPC::InvalidPlatformFileForTransit());
+
+ bool success = dispatcher()->Send(new PpapiMsg_PPBBroker_ConnectComplete(
+ INTERFACE_ID_PPB_FILE_SYSTEM, broker, foreign_socket_handle, result));
+
+ if (!success || result == PP_OK) {
+ // The plugin did not receive the handle, so it must be closed.
+ // The easiest way to clean it up is to just put it in an object
+ // and then close it. This failure case is not performance critical.
+ // The handle could still leak if Send succeeded but the IPC later failed.
+ base::SyncSocket temp_socket(
+ IPC::PlatformFileForTransitToPlatformFile(foreign_socket_handle));
+ }
+}
+
+} // namespace proxy
+} // namespace pp
diff --git a/ppapi/proxy/ppb_broker_proxy.h b/ppapi/proxy/ppb_broker_proxy.h
new file mode 100644
index 0000000..3cae023
--- /dev/null
+++ b/ppapi/proxy/ppb_broker_proxy.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2011 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_PPB_BROKER_PROXY_H_
+#define PPAPI_PPB_BROKER_PROXY_H_
+
+#include "base/sync_socket.h"
+#include "ipc/ipc_platform_file.h"
+#include "ppapi/c/pp_instance.h"
+#include "ppapi/cpp/completion_callback.h"
+#include "ppapi/proxy/interface_proxy.h"
+#include "ppapi/proxy/proxy_non_thread_safe_ref_count.h"
+
+
+struct PPB_BrokerTrusted;
+
+namespace pp {
+namespace proxy {
+
+class HostResource;
+
+class PPB_Broker_Proxy : public InterfaceProxy {
+ public:
+ PPB_Broker_Proxy(Dispatcher* dispatcher, const void* target_interface);
+ virtual ~PPB_Broker_Proxy();
+
+ static const Info* GetInfo();
+
+ const PPB_BrokerTrusted* ppb_broker_target() const {
+ return static_cast<const PPB_BrokerTrusted*>(target_interface());
+ }
+
+ // InterfaceProxy implementation.
+ virtual bool OnMessageReceived(const IPC::Message& msg);
+
+ private:
+ // Message handlers.
+ void OnMsgCreate(PP_Instance instance, HostResource* result_resource);
+ void OnMsgConnect(const HostResource& broker);
+ void OnMsgConnectComplete(const HostResource& broker,
+ IPC::PlatformFileForTransit foreign_socket_handle,
+ int32_t result);
+
+ void ConnectCompleteInHost(int32_t result, const HostResource& host_resource);
+
+ CompletionCallbackFactory<PPB_Broker_Proxy,
+ ProxyNonThreadSafeRefCount> callback_factory_;
+};
+
+} // namespace proxy
+} // namespace pp
+
+#endif // PPAPI_PPB_BROKER_PROXY_H_