diff options
author | ddorwin@chromium.org <ddorwin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-17 00:13:22 +0000 |
---|---|---|
committer | ddorwin@chromium.org <ddorwin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-04-17 00:13:22 +0000 |
commit | ae971c2c0dea23a076b4320b0eaba69d2636ff4e (patch) | |
tree | fb3d3591130f13f4e6205c0b363dc09b5fd91d32 /ppapi | |
parent | a3eba772e8722dd01052827357bba24656fbf651 (diff) | |
download | chromium_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.h | 15 | ||||
-rw-r--r-- | ppapi/ppapi_shared_proxy.gypi | 2 | ||||
-rw-r--r-- | ppapi/proxy/dispatcher.cc | 2 | ||||
-rw-r--r-- | ppapi/proxy/interface_id.h | 1 | ||||
-rw-r--r-- | ppapi/proxy/plugin_resource.h | 1 | ||||
-rw-r--r-- | ppapi/proxy/ppapi_messages.h | 14 | ||||
-rw-r--r-- | ppapi/proxy/ppb_broker_proxy.cc | 284 | ||||
-rw-r--r-- | ppapi/proxy/ppb_broker_proxy.h | 54 |
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_ |