Roll src/third_party/WebKit ef7cfd7:80927b2 (svn 194570:194575)
[chromium-blink-merge.git] / ppapi / proxy / ppb_broker_proxy.cc
blobe1d38ead67117338eb126714c3c618bc72cbde5f
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ppapi/proxy/ppb_broker_proxy.h"
7 #include "base/bind.h"
8 #include "ppapi/c/pp_errors.h"
9 #include "ppapi/c/trusted/ppb_broker_trusted.h"
10 #include "ppapi/proxy/enter_proxy.h"
11 #include "ppapi/proxy/plugin_dispatcher.h"
12 #include "ppapi/proxy/ppapi_messages.h"
13 #include "ppapi/shared_impl/platform_file.h"
14 #include "ppapi/shared_impl/tracked_callback.h"
15 #include "ppapi/thunk/ppb_broker_api.h"
16 #include "ppapi/thunk/enter.h"
17 #include "ppapi/thunk/resource_creation_api.h"
18 #include "ppapi/thunk/thunk.h"
20 using ppapi::IntToPlatformFile;
21 using ppapi::PlatformFileToInt;
22 using ppapi::thunk::PPB_Broker_API;
24 namespace ppapi {
25 namespace proxy {
27 class Broker : public PPB_Broker_API, public Resource {
28 public:
29 explicit Broker(const HostResource& resource);
30 ~Broker() override;
32 // Resource overrides.
33 PPB_Broker_API* AsPPB_Broker_API() override;
35 // PPB_Broker_API implementation.
36 int32_t Connect(scoped_refptr<TrackedCallback> connect_callback) override;
37 int32_t GetHandle(int32_t* handle) override;
39 // Called by the proxy when the host side has completed the request.
40 void ConnectComplete(IPC::PlatformFileForTransit socket_handle,
41 int32_t result);
43 private:
44 bool called_connect_;
45 scoped_refptr<TrackedCallback> current_connect_callback_;
47 // The plugin module owns the handle.
48 // The host side transfers ownership of the handle to the plugin side when it
49 // sends the IPC. This member holds the handle value for the plugin module
50 // to read, but the plugin side of the proxy never takes ownership.
51 base::SyncSocket::Handle socket_handle_;
53 DISALLOW_COPY_AND_ASSIGN(Broker);
56 Broker::Broker(const HostResource& resource)
57 : Resource(OBJECT_IS_PROXY, resource),
58 called_connect_(false),
59 socket_handle_(base::SyncSocket::kInvalidHandle) {
62 Broker::~Broker() {
63 socket_handle_ = base::SyncSocket::kInvalidHandle;
66 PPB_Broker_API* Broker::AsPPB_Broker_API() {
67 return this;
70 int32_t Broker::Connect(scoped_refptr<TrackedCallback> connect_callback) {
71 if (TrackedCallback::IsPending(current_connect_callback_))
72 return PP_ERROR_INPROGRESS;
73 else if (called_connect_)
74 return PP_ERROR_FAILED;
76 current_connect_callback_ = connect_callback;
77 called_connect_ = true;
79 bool success = PluginDispatcher::GetForResource(this)->Send(
80 new PpapiHostMsg_PPBBroker_Connect(
81 API_ID_PPB_BROKER, host_resource()));
82 return success ? PP_OK_COMPLETIONPENDING : PP_ERROR_FAILED;
85 int32_t Broker::GetHandle(int32_t* handle) {
86 if (socket_handle_ == base::SyncSocket::kInvalidHandle)
87 return PP_ERROR_FAILED;
88 *handle = PlatformFileToInt(socket_handle_);
89 return PP_OK;
92 void Broker::ConnectComplete(IPC::PlatformFileForTransit socket_handle,
93 int32_t result) {
94 if (result == PP_OK) {
95 DCHECK(socket_handle_ == base::SyncSocket::kInvalidHandle);
96 socket_handle_ = IPC::PlatformFileForTransitToPlatformFile(socket_handle);
97 } else {
98 // The caller may still have given us a handle in the failure case.
99 // The easiest way to clean it up is to just put it in an object
100 // and then close them. This failure case is not performance critical.
101 base::SyncSocket temp_socket(
102 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
105 if (!TrackedCallback::IsPending(current_connect_callback_)) {
106 // The handle might leak if the plugin never calls GetHandle().
107 return;
110 current_connect_callback_->Run(result);
113 PPB_Broker_Proxy::PPB_Broker_Proxy(Dispatcher* dispatcher)
114 : InterfaceProxy(dispatcher),
115 callback_factory_(this){
118 PPB_Broker_Proxy::~PPB_Broker_Proxy() {
121 // static
122 PP_Resource PPB_Broker_Proxy::CreateProxyResource(PP_Instance instance) {
123 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
124 if (!dispatcher)
125 return 0;
127 HostResource result;
128 dispatcher->Send(new PpapiHostMsg_PPBBroker_Create(
129 API_ID_PPB_BROKER, instance, &result));
130 if (result.is_null())
131 return 0;
132 return (new Broker(result))->GetReference();
135 bool PPB_Broker_Proxy::OnMessageReceived(const IPC::Message& msg) {
136 bool handled = true;
137 IPC_BEGIN_MESSAGE_MAP(PPB_Broker_Proxy, msg)
138 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Create, OnMsgCreate)
139 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Connect, OnMsgConnect)
140 IPC_MESSAGE_HANDLER(PpapiMsg_PPBBroker_ConnectComplete,
141 OnMsgConnectComplete)
142 IPC_MESSAGE_UNHANDLED(handled = false)
143 IPC_END_MESSAGE_MAP()
144 return handled;
147 void PPB_Broker_Proxy::OnMsgCreate(PP_Instance instance,
148 HostResource* result_resource) {
149 if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE))
150 return;
151 thunk::EnterResourceCreation enter(instance);
152 if (enter.succeeded()) {
153 result_resource->SetHostResource(
154 instance,
155 enter.functions()->CreateBroker(instance));
159 void PPB_Broker_Proxy::OnMsgConnect(const HostResource& broker) {
160 if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE))
161 return;
162 EnterHostFromHostResourceForceCallback<PPB_Broker_API> enter(
163 broker, callback_factory_,
164 &PPB_Broker_Proxy::ConnectCompleteInHost, broker);
165 if (enter.succeeded())
166 enter.SetResult(enter.object()->Connect(enter.callback()));
169 // Called in the plugin to handle the connect callback.
170 // The proxy owns the handle and transfers it to the Broker. At that point,
171 // the plugin owns the handle and is responsible for closing it.
172 // The caller guarantees that socket_handle is not valid if result is not PP_OK.
173 void PPB_Broker_Proxy::OnMsgConnectComplete(
174 const HostResource& resource,
175 IPC::PlatformFileForTransit socket_handle,
176 int32_t result) {
177 DCHECK(result == PP_OK ||
178 socket_handle == IPC::InvalidPlatformFileForTransit());
180 EnterPluginFromHostResource<PPB_Broker_API> enter(resource);
181 if (enter.failed()) {
182 // As in Broker::ConnectComplete, we need to close the resource on error.
183 base::SyncSocket temp_socket(
184 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
185 } else {
186 static_cast<Broker*>(enter.object())->ConnectComplete(socket_handle,
187 result);
191 // Callback on the host side.
192 // Transfers ownership of the handle to the plugin side. This function must
193 // either successfully call the callback or close the handle.
194 void PPB_Broker_Proxy::ConnectCompleteInHost(int32_t result,
195 const HostResource& broker) {
196 IPC::PlatformFileForTransit foreign_socket_handle =
197 IPC::InvalidPlatformFileForTransit();
198 if (result == PP_OK) {
199 int32_t socket_handle = PlatformFileToInt(base::SyncSocket::kInvalidHandle);
200 EnterHostFromHostResource<PPB_Broker_API> enter(broker);
201 if (enter.succeeded())
202 result = enter.object()->GetHandle(&socket_handle);
203 DCHECK(result == PP_OK ||
204 socket_handle ==
205 PlatformFileToInt(base::SyncSocket::kInvalidHandle));
207 if (result == PP_OK) {
208 foreign_socket_handle =
209 dispatcher()->ShareHandleWithRemote(IntToPlatformFile(socket_handle),
210 true);
211 if (foreign_socket_handle == IPC::InvalidPlatformFileForTransit()) {
212 result = PP_ERROR_FAILED;
213 // Assume the local handle was closed even if the foreign handle could
214 // not be created.
218 DCHECK(result == PP_OK ||
219 foreign_socket_handle == IPC::InvalidPlatformFileForTransit());
221 bool success = dispatcher()->Send(new PpapiMsg_PPBBroker_ConnectComplete(
222 API_ID_PPB_BROKER, broker, foreign_socket_handle, result));
224 if (!success || result != PP_OK) {
225 // The plugin did not receive the handle, so it must be closed.
226 // The easiest way to clean it up is to just put it in an object
227 // and then close it. This failure case is not performance critical.
228 // The handle could still leak if Send succeeded but the IPC later failed.
229 base::SyncSocket temp_socket(
230 IPC::PlatformFileForTransitToPlatformFile(foreign_socket_handle));
234 } // namespace proxy
235 } // namespace ppapi