summaryrefslogtreecommitdiffstats
path: root/ppapi/proxy/ppb_broker_proxy.cc
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/proxy/ppb_broker_proxy.cc
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/proxy/ppb_broker_proxy.cc')
-rw-r--r--ppapi/proxy/ppb_broker_proxy.cc284
1 files changed, 284 insertions, 0 deletions
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