blob: 3f2b617670e44134d71decf165a7234c4341c5a5 [file] [log] [blame]
[email protected]00d320a2012-02-14 00:27:041// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]ae971c22011-04-17 00:13:222// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/proxy/ppb_broker_proxy.h"
6
[email protected]1f6581c2011-10-04 23:10:157#include "base/bind.h"
avie029c4132015-12-23 06:45:228#include "base/macros.h"
[email protected]ae971c22011-04-17 00:13:229#include "ppapi/c/pp_errors.h"
10#include "ppapi/c/trusted/ppb_broker_trusted.h"
[email protected]c8c07382011-06-02 17:01:0411#include "ppapi/proxy/enter_proxy.h"
[email protected]ae971c22011-04-17 00:13:2212#include "ppapi/proxy/plugin_dispatcher.h"
[email protected]ae971c22011-04-17 00:13:2213#include "ppapi/proxy/ppapi_messages.h"
[email protected]5a77eca2011-11-23 23:46:4614#include "ppapi/shared_impl/platform_file.h"
[email protected]a78956b2012-01-05 18:17:0515#include "ppapi/shared_impl/tracked_callback.h"
[email protected]9815108e2011-05-27 21:50:2816#include "ppapi/thunk/enter.h"
avie029c4132015-12-23 06:45:2217#include "ppapi/thunk/ppb_broker_api.h"
[email protected]5c966022011-09-13 18:09:3718#include "ppapi/thunk/resource_creation_api.h"
[email protected]9815108e2011-05-27 21:50:2819#include "ppapi/thunk/thunk.h"
[email protected]ae971c22011-04-17 00:13:2220
[email protected]5a77eca2011-11-23 23:46:4621using ppapi::IntToPlatformFile;
22using ppapi::PlatformFileToInt;
[email protected]79d23c72011-08-08 19:40:4023using ppapi::thunk::PPB_Broker_API;
24
[email protected]4d2efd22011-08-18 21:58:0225namespace ppapi {
[email protected]ae971c22011-04-17 00:13:2226namespace proxy {
27
[email protected]7f8b26b2011-08-18 15:41:0128class Broker : public PPB_Broker_API, public Resource {
[email protected]9815108e2011-05-27 21:50:2829 public:
30 explicit Broker(const HostResource& resource);
nicke4784432015-04-23 14:01:4831 ~Broker() override;
[email protected]9815108e2011-05-27 21:50:2832
[email protected]5a77eca2011-11-23 23:46:4633 // Resource overrides.
nicke4784432015-04-23 14:01:4834 PPB_Broker_API* AsPPB_Broker_API() override;
[email protected]9815108e2011-05-27 21:50:2835
36 // PPB_Broker_API implementation.
nicke4784432015-04-23 14:01:4837 int32_t Connect(scoped_refptr<TrackedCallback> connect_callback) override;
38 int32_t GetHandle(int32_t* handle) override;
[email protected]9815108e2011-05-27 21:50:2839
40 // Called by the proxy when the host side has completed the request.
41 void ConnectComplete(IPC::PlatformFileForTransit socket_handle,
42 int32_t result);
43
44 private:
45 bool called_connect_;
[email protected]a78956b2012-01-05 18:17:0546 scoped_refptr<TrackedCallback> current_connect_callback_;
[email protected]9815108e2011-05-27 21:50:2847
48 // The plugin module owns the handle.
49 // The host side transfers ownership of the handle to the plugin side when it
50 // sends the IPC. This member holds the handle value for the plugin module
51 // to read, but the plugin side of the proxy never takes ownership.
52 base::SyncSocket::Handle socket_handle_;
53
54 DISALLOW_COPY_AND_ASSIGN(Broker);
55};
56
[email protected]a78956b2012-01-05 18:17:0557Broker::Broker(const HostResource& resource)
[email protected]00d320a2012-02-14 00:27:0458 : Resource(OBJECT_IS_PROXY, resource),
[email protected]9815108e2011-05-27 21:50:2859 called_connect_(false),
[email protected]dd7a8a42014-06-10 12:58:2960 socket_handle_(base::SyncSocket::kInvalidHandle) {
[email protected]9815108e2011-05-27 21:50:2861}
62
63Broker::~Broker() {
[email protected]dd7a8a42014-06-10 12:58:2964 socket_handle_ = base::SyncSocket::kInvalidHandle;
[email protected]9815108e2011-05-27 21:50:2865}
66
[email protected]79d23c72011-08-08 19:40:4067PPB_Broker_API* Broker::AsPPB_Broker_API() {
[email protected]9815108e2011-05-27 21:50:2868 return this;
69}
70
[email protected]aed96532012-06-23 14:27:4271int32_t Broker::Connect(scoped_refptr<TrackedCallback> connect_callback) {
[email protected]a78956b2012-01-05 18:17:0572 if (TrackedCallback::IsPending(current_connect_callback_))
[email protected]9815108e2011-05-27 21:50:2873 return PP_ERROR_INPROGRESS;
74 else if (called_connect_)
75 return PP_ERROR_FAILED;
76
[email protected]aed96532012-06-23 14:27:4277 current_connect_callback_ = connect_callback;
[email protected]9815108e2011-05-27 21:50:2878 called_connect_ = true;
79
[email protected]7f8b26b2011-08-18 15:41:0180 bool success = PluginDispatcher::GetForResource(this)->Send(
81 new PpapiHostMsg_PPBBroker_Connect(
[email protected]ac4b54d2011-10-20 23:09:2882 API_ID_PPB_BROKER, host_resource()));
[email protected]9815108e2011-05-27 21:50:2883 return success ? PP_OK_COMPLETIONPENDING : PP_ERROR_FAILED;
84}
85
86int32_t Broker::GetHandle(int32_t* handle) {
[email protected]dd7a8a42014-06-10 12:58:2987 if (socket_handle_ == base::SyncSocket::kInvalidHandle)
[email protected]9815108e2011-05-27 21:50:2888 return PP_ERROR_FAILED;
89 *handle = PlatformFileToInt(socket_handle_);
90 return PP_OK;
91}
92
93void Broker::ConnectComplete(IPC::PlatformFileForTransit socket_handle,
94 int32_t result) {
95 if (result == PP_OK) {
[email protected]dd7a8a42014-06-10 12:58:2996 DCHECK(socket_handle_ == base::SyncSocket::kInvalidHandle);
[email protected]9815108e2011-05-27 21:50:2897 socket_handle_ = IPC::PlatformFileForTransitToPlatformFile(socket_handle);
98 } else {
99 // The caller may still have given us a handle in the failure case.
100 // The easiest way to clean it up is to just put it in an object
101 // and then close them. This failure case is not performance critical.
102 base::SyncSocket temp_socket(
103 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
104 }
105
[email protected]a78956b2012-01-05 18:17:05106 if (!TrackedCallback::IsPending(current_connect_callback_)) {
[email protected]9815108e2011-05-27 21:50:28107 // The handle might leak if the plugin never calls GetHandle().
108 return;
109 }
110
[email protected]c9eb50582012-11-05 20:08:24111 current_connect_callback_->Run(result);
[email protected]9815108e2011-05-27 21:50:28112}
113
[email protected]5c966022011-09-13 18:09:37114PPB_Broker_Proxy::PPB_Broker_Proxy(Dispatcher* dispatcher)
115 : InterfaceProxy(dispatcher),
[email protected]a2f53dc2013-04-30 01:06:35116 callback_factory_(this){
[email protected]ae971c22011-04-17 00:13:22117}
118
119PPB_Broker_Proxy::~PPB_Broker_Proxy() {
120}
121
122// static
[email protected]9815108e2011-05-27 21:50:28123PP_Resource PPB_Broker_Proxy::CreateProxyResource(PP_Instance instance) {
124 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
125 if (!dispatcher)
126 return 0;
127
128 HostResource result;
129 dispatcher->Send(new PpapiHostMsg_PPBBroker_Create(
[email protected]ac4b54d2011-10-20 23:09:28130 API_ID_PPB_BROKER, instance, &result));
[email protected]9815108e2011-05-27 21:50:28131 if (result.is_null())
132 return 0;
[email protected]7f8b26b2011-08-18 15:41:01133 return (new Broker(result))->GetReference();
[email protected]9815108e2011-05-27 21:50:28134}
135
[email protected]ae971c22011-04-17 00:13:22136bool PPB_Broker_Proxy::OnMessageReceived(const IPC::Message& msg) {
137 bool handled = true;
138 IPC_BEGIN_MESSAGE_MAP(PPB_Broker_Proxy, msg)
139 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Create, OnMsgCreate)
140 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Connect, OnMsgConnect)
141 IPC_MESSAGE_HANDLER(PpapiMsg_PPBBroker_ConnectComplete,
142 OnMsgConnectComplete)
143 IPC_MESSAGE_UNHANDLED(handled = false)
144 IPC_END_MESSAGE_MAP()
145 return handled;
146}
147
148void PPB_Broker_Proxy::OnMsgCreate(PP_Instance instance,
149 HostResource* result_resource) {
[email protected]e9c3df92012-12-10 23:38:59150 if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE))
151 return;
[email protected]5c966022011-09-13 18:09:37152 thunk::EnterResourceCreation enter(instance);
153 if (enter.succeeded()) {
154 result_resource->SetHostResource(
155 instance,
156 enter.functions()->CreateBroker(instance));
157 }
[email protected]ae971c22011-04-17 00:13:22158}
159
160void PPB_Broker_Proxy::OnMsgConnect(const HostResource& broker) {
[email protected]e9c3df92012-12-10 23:38:59161 if (!dispatcher()->permissions().HasPermission(PERMISSION_PRIVATE))
162 return;
[email protected]79d23c72011-08-08 19:40:40163 EnterHostFromHostResourceForceCallback<PPB_Broker_API> enter(
164 broker, callback_factory_,
[email protected]ae971c22011-04-17 00:13:22165 &PPB_Broker_Proxy::ConnectCompleteInHost, broker);
[email protected]79d23c72011-08-08 19:40:40166 if (enter.succeeded())
167 enter.SetResult(enter.object()->Connect(enter.callback()));
[email protected]ae971c22011-04-17 00:13:22168}
169
170// Called in the plugin to handle the connect callback.
171// The proxy owns the handle and transfers it to the Broker. At that point,
172// the plugin owns the handle and is responsible for closing it.
173// The caller guarantees that socket_handle is not valid if result is not PP_OK.
174void PPB_Broker_Proxy::OnMsgConnectComplete(
[email protected]9815108e2011-05-27 21:50:28175 const HostResource& resource,
[email protected]ae971c22011-04-17 00:13:22176 IPC::PlatformFileForTransit socket_handle,
177 int32_t result) {
178 DCHECK(result == PP_OK ||
179 socket_handle == IPC::InvalidPlatformFileForTransit());
180
[email protected]79d23c72011-08-08 19:40:40181 EnterPluginFromHostResource<PPB_Broker_API> enter(resource);
[email protected]9815108e2011-05-27 21:50:28182 if (enter.failed()) {
183 // As in Broker::ConnectComplete, we need to close the resource on error.
[email protected]ae971c22011-04-17 00:13:22184 base::SyncSocket temp_socket(
185 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
[email protected]9815108e2011-05-27 21:50:28186 } else {
187 static_cast<Broker*>(enter.object())->ConnectComplete(socket_handle,
188 result);
[email protected]ae971c22011-04-17 00:13:22189 }
[email protected]ae971c22011-04-17 00:13:22190}
191
192// Callback on the host side.
193// Transfers ownership of the handle to the plugin side. This function must
194// either successfully call the callback or close the handle.
195void PPB_Broker_Proxy::ConnectCompleteInHost(int32_t result,
196 const HostResource& broker) {
197 IPC::PlatformFileForTransit foreign_socket_handle =
198 IPC::InvalidPlatformFileForTransit();
199 if (result == PP_OK) {
[email protected]dd7a8a42014-06-10 12:58:29200 int32_t socket_handle = PlatformFileToInt(base::SyncSocket::kInvalidHandle);
[email protected]5c966022011-09-13 18:09:37201 EnterHostFromHostResource<PPB_Broker_API> enter(broker);
202 if (enter.succeeded())
203 result = enter.object()->GetHandle(&socket_handle);
[email protected]ae971c22011-04-17 00:13:22204 DCHECK(result == PP_OK ||
[email protected]dd7a8a42014-06-10 12:58:29205 socket_handle ==
206 PlatformFileToInt(base::SyncSocket::kInvalidHandle));
[email protected]ae971c22011-04-17 00:13:22207
208 if (result == PP_OK) {
209 foreign_socket_handle =
210 dispatcher()->ShareHandleWithRemote(IntToPlatformFile(socket_handle),
211 true);
212 if (foreign_socket_handle == IPC::InvalidPlatformFileForTransit()) {
213 result = PP_ERROR_FAILED;
214 // Assume the local handle was closed even if the foreign handle could
215 // not be created.
216 }
217 }
218 }
219 DCHECK(result == PP_OK ||
220 foreign_socket_handle == IPC::InvalidPlatformFileForTransit());
221
222 bool success = dispatcher()->Send(new PpapiMsg_PPBBroker_ConnectComplete(
[email protected]ac4b54d2011-10-20 23:09:28223 API_ID_PPB_BROKER, broker, foreign_socket_handle, result));
[email protected]ae971c22011-04-17 00:13:22224
[email protected]4b417e52011-04-18 22:51:08225 if (!success || result != PP_OK) {
[email protected]ae971c22011-04-17 00:13:22226 // The plugin did not receive the handle, so it must be closed.
227 // The easiest way to clean it up is to just put it in an object
228 // and then close it. This failure case is not performance critical.
229 // The handle could still leak if Send succeeded but the IPC later failed.
230 base::SyncSocket temp_socket(
231 IPC::PlatformFileForTransitToPlatformFile(foreign_socket_handle));
232 }
233}
234
235} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02236} // namespace ppapi