blob: 37f8ba04fc9e131c550208802ff296279c9dce08 [file] [log] [blame]
[email protected]ae971c22011-04-17 00:13:221// Copyright (c) 2011 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.
4
5#include "ppapi/proxy/ppb_broker_proxy.h"
6
7#include "ppapi/c/pp_errors.h"
8#include "ppapi/c/trusted/ppb_broker_trusted.h"
[email protected]c8c07382011-06-02 17:01:049#include "ppapi/proxy/enter_proxy.h"
[email protected]ae971c22011-04-17 00:13:2210#include "ppapi/proxy/plugin_dispatcher.h"
11#include "ppapi/proxy/plugin_resource.h"
12#include "ppapi/proxy/ppapi_messages.h"
[email protected]98151082011-05-27 21:50:2813#include "ppapi/thunk/ppb_broker_api.h"
14#include "ppapi/thunk/enter.h"
15#include "ppapi/thunk/thunk.h"
[email protected]ae971c22011-04-17 00:13:2216
17namespace pp {
18namespace proxy {
19
[email protected]ae971c22011-04-17 00:13:2220namespace {
21
22base::PlatformFile IntToPlatformFile(int32_t handle) {
23#if defined(OS_WIN)
24 return reinterpret_cast<HANDLE>(static_cast<intptr_t>(handle));
25#elif defined(OS_POSIX)
26 return handle;
27#else
28 #error Not implemented.
29#endif
30}
31
32int32_t PlatformFileToInt(base::PlatformFile handle) {
33#if defined(OS_WIN)
34 return static_cast<int32_t>(reinterpret_cast<intptr_t>(handle));
35#elif defined(OS_POSIX)
36 return handle;
37#else
38 #error Not implemented.
39#endif
40}
41
[email protected]ae971c22011-04-17 00:13:2242InterfaceProxy* CreateBrokerProxy(Dispatcher* dispatcher,
43 const void* target_interface) {
44 return new PPB_Broker_Proxy(dispatcher, target_interface);
45}
46
47} // namespace
48
[email protected]98151082011-05-27 21:50:2849class Broker : public ppapi::thunk::PPB_Broker_API,
50 public PluginResource {
51 public:
52 explicit Broker(const HostResource& resource);
53 virtual ~Broker();
54
55 // ResourceObjectBase overries.
[email protected]cd910b92011-06-01 07:19:3156 virtual ppapi::thunk::PPB_Broker_API* AsPPB_Broker_API() OVERRIDE;
[email protected]98151082011-05-27 21:50:2857
58 // PPB_Broker_API implementation.
59 virtual int32_t Connect(PP_CompletionCallback connect_callback) OVERRIDE;
60 virtual int32_t GetHandle(int32_t* handle) OVERRIDE;
61
62 // Called by the proxy when the host side has completed the request.
63 void ConnectComplete(IPC::PlatformFileForTransit socket_handle,
64 int32_t result);
65
66 private:
67 bool called_connect_;
68 PP_CompletionCallback current_connect_callback_;
69
70 // The plugin module owns the handle.
71 // The host side transfers ownership of the handle to the plugin side when it
72 // sends the IPC. This member holds the handle value for the plugin module
73 // to read, but the plugin side of the proxy never takes ownership.
74 base::SyncSocket::Handle socket_handle_;
75
76 DISALLOW_COPY_AND_ASSIGN(Broker);
77};
78
79Broker::Broker(const HostResource& resource)
80 : PluginResource(resource),
81 called_connect_(false),
82 current_connect_callback_(PP_MakeCompletionCallback(NULL, NULL)),
83 socket_handle_(base::kInvalidPlatformFileValue) {
84}
85
86Broker::~Broker() {
87 // Ensure the callback is always fired.
88 if (current_connect_callback_.func) {
89 // TODO(brettw) the callbacks at this level should be refactored with a
90 // more automatic tracking system like we have in the renderer.
91 MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction(
92 current_connect_callback_.func, current_connect_callback_.user_data,
93 static_cast<int32_t>(PP_ERROR_ABORTED)));
94 }
95
96 socket_handle_ = base::kInvalidPlatformFileValue;
97}
98
[email protected]cd910b92011-06-01 07:19:3199ppapi::thunk::PPB_Broker_API* Broker::AsPPB_Broker_API() {
[email protected]98151082011-05-27 21:50:28100 return this;
101}
102
103int32_t Broker::Connect(PP_CompletionCallback connect_callback) {
104 if (!connect_callback.func) {
105 // Synchronous calls are not supported.
106 return PP_ERROR_BADARGUMENT;
107 }
108
109 if (current_connect_callback_.func)
110 return PP_ERROR_INPROGRESS;
111 else if (called_connect_)
112 return PP_ERROR_FAILED;
113
114 current_connect_callback_ = connect_callback;
115 called_connect_ = true;
116
117 bool success = GetDispatcher()->Send(new PpapiHostMsg_PPBBroker_Connect(
118 INTERFACE_ID_PPB_BROKER, host_resource()));
119 return success ? PP_OK_COMPLETIONPENDING : PP_ERROR_FAILED;
120}
121
122int32_t Broker::GetHandle(int32_t* handle) {
123 if (socket_handle_ == base::kInvalidPlatformFileValue)
124 return PP_ERROR_FAILED;
125 *handle = PlatformFileToInt(socket_handle_);
126 return PP_OK;
127}
128
129void Broker::ConnectComplete(IPC::PlatformFileForTransit socket_handle,
130 int32_t result) {
131 if (result == PP_OK) {
132 DCHECK(socket_handle_ == base::kInvalidPlatformFileValue);
133 socket_handle_ = IPC::PlatformFileForTransitToPlatformFile(socket_handle);
134 } else {
135 // The caller may still have given us a handle in the failure case.
136 // The easiest way to clean it up is to just put it in an object
137 // and then close them. This failure case is not performance critical.
138 base::SyncSocket temp_socket(
139 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
140 }
141
142 if (!current_connect_callback_.func) {
143 // The handle might leak if the plugin never calls GetHandle().
144 return;
145 }
146
147 PP_RunAndClearCompletionCallback(&current_connect_callback_, result);
148}
149
[email protected]ae971c22011-04-17 00:13:22150PPB_Broker_Proxy::PPB_Broker_Proxy(Dispatcher* dispatcher,
151 const void* target_interface)
152 : InterfaceProxy(dispatcher, target_interface) ,
153 callback_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)){
154}
155
156PPB_Broker_Proxy::~PPB_Broker_Proxy() {
157}
158
159// static
160const InterfaceProxy::Info* PPB_Broker_Proxy::GetInfo() {
161 static const Info info = {
[email protected]98151082011-05-27 21:50:28162 ppapi::thunk::GetPPB_Broker_Thunk(),
[email protected]ae971c22011-04-17 00:13:22163 PPB_BROKER_TRUSTED_INTERFACE,
164 INTERFACE_ID_PPB_BROKER,
165 true,
166 &CreateBrokerProxy,
167 };
168 return &info;
169}
170
[email protected]98151082011-05-27 21:50:28171// static
172PP_Resource PPB_Broker_Proxy::CreateProxyResource(PP_Instance instance) {
173 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
174 if (!dispatcher)
175 return 0;
176
177 HostResource result;
178 dispatcher->Send(new PpapiHostMsg_PPBBroker_Create(
179 INTERFACE_ID_PPB_BROKER, instance, &result));
180 if (result.is_null())
181 return 0;
182
183 linked_ptr<Broker> object(new Broker(result));
184 return PluginResourceTracker::GetInstance()->AddResource(object);
185}
186
[email protected]ae971c22011-04-17 00:13:22187bool PPB_Broker_Proxy::OnMessageReceived(const IPC::Message& msg) {
188 bool handled = true;
189 IPC_BEGIN_MESSAGE_MAP(PPB_Broker_Proxy, msg)
190 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Create, OnMsgCreate)
191 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBBroker_Connect, OnMsgConnect)
192 IPC_MESSAGE_HANDLER(PpapiMsg_PPBBroker_ConnectComplete,
193 OnMsgConnectComplete)
194 IPC_MESSAGE_UNHANDLED(handled = false)
195 IPC_END_MESSAGE_MAP()
196 return handled;
197}
198
199void PPB_Broker_Proxy::OnMsgCreate(PP_Instance instance,
200 HostResource* result_resource) {
201 result_resource->SetHostResource(
202 instance,
203 ppb_broker_target()->CreateTrusted(instance));
204}
205
206void PPB_Broker_Proxy::OnMsgConnect(const HostResource& broker) {
[email protected]917e86a2011-06-30 21:42:37207 CompletionCallback callback = callback_factory_.NewOptionalCallback(
[email protected]ae971c22011-04-17 00:13:22208 &PPB_Broker_Proxy::ConnectCompleteInHost, broker);
209
210 int32_t result = ppb_broker_target()->Connect(
211 broker.host_resource(),
212 callback.pp_completion_callback());
213 if (result != PP_OK_COMPLETIONPENDING)
214 callback.Run(result);
215}
216
217// Called in the plugin to handle the connect callback.
218// The proxy owns the handle and transfers it to the Broker. At that point,
219// the plugin owns the handle and is responsible for closing it.
220// The caller guarantees that socket_handle is not valid if result is not PP_OK.
221void PPB_Broker_Proxy::OnMsgConnectComplete(
[email protected]98151082011-05-27 21:50:28222 const HostResource& resource,
[email protected]ae971c22011-04-17 00:13:22223 IPC::PlatformFileForTransit socket_handle,
224 int32_t result) {
225 DCHECK(result == PP_OK ||
226 socket_handle == IPC::InvalidPlatformFileForTransit());
227
[email protected]c8c07382011-06-02 17:01:04228 EnterPluginFromHostResource<ppapi::thunk::PPB_Broker_API> enter(resource);
[email protected]98151082011-05-27 21:50:28229 if (enter.failed()) {
230 // As in Broker::ConnectComplete, we need to close the resource on error.
[email protected]ae971c22011-04-17 00:13:22231 base::SyncSocket temp_socket(
232 IPC::PlatformFileForTransitToPlatformFile(socket_handle));
[email protected]98151082011-05-27 21:50:28233 } else {
234 static_cast<Broker*>(enter.object())->ConnectComplete(socket_handle,
235 result);
[email protected]ae971c22011-04-17 00:13:22236 }
[email protected]ae971c22011-04-17 00:13:22237}
238
239// Callback on the host side.
240// Transfers ownership of the handle to the plugin side. This function must
241// either successfully call the callback or close the handle.
242void PPB_Broker_Proxy::ConnectCompleteInHost(int32_t result,
243 const HostResource& broker) {
244 IPC::PlatformFileForTransit foreign_socket_handle =
245 IPC::InvalidPlatformFileForTransit();
246 if (result == PP_OK) {
247 int32_t socket_handle = PlatformFileToInt(base::kInvalidPlatformFileValue);
248 result = ppb_broker_target()->GetHandle(broker.host_resource(),
249 &socket_handle);
250 DCHECK(result == PP_OK ||
251 socket_handle == PlatformFileToInt(base::kInvalidPlatformFileValue));
252
253 if (result == PP_OK) {
254 foreign_socket_handle =
255 dispatcher()->ShareHandleWithRemote(IntToPlatformFile(socket_handle),
256 true);
257 if (foreign_socket_handle == IPC::InvalidPlatformFileForTransit()) {
258 result = PP_ERROR_FAILED;
259 // Assume the local handle was closed even if the foreign handle could
260 // not be created.
261 }
262 }
263 }
264 DCHECK(result == PP_OK ||
265 foreign_socket_handle == IPC::InvalidPlatformFileForTransit());
266
267 bool success = dispatcher()->Send(new PpapiMsg_PPBBroker_ConnectComplete(
[email protected]4b417e52011-04-18 22:51:08268 INTERFACE_ID_PPB_BROKER, broker, foreign_socket_handle, result));
[email protected]ae971c22011-04-17 00:13:22269
[email protected]4b417e52011-04-18 22:51:08270 if (!success || result != PP_OK) {
[email protected]ae971c22011-04-17 00:13:22271 // The plugin did not receive the handle, so it must be closed.
272 // The easiest way to clean it up is to just put it in an object
273 // and then close it. This failure case is not performance critical.
274 // The handle could still leak if Send succeeded but the IPC later failed.
275 base::SyncSocket temp_socket(
276 IPC::PlatformFileForTransitToPlatformFile(foreign_socket_handle));
277 }
278}
279
280} // namespace proxy
281} // namespace pp