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.
4
5#include "ppapi/proxy/ppp_class_proxy.h"
6
7#include "ppapi/c/dev/ppb_var_deprecated.h"
8#include "ppapi/c/dev/ppp_class_deprecated.h"
9#include "ppapi/c/pp_var.h"
10#include "ppapi/proxy/dispatcher.h"
11#include "ppapi/proxy/plugin_globals.h"
12#include "ppapi/proxy/ppapi_messages.h"
13#include "ppapi/proxy/serialized_var.h"
14#include "ppapi/shared_impl/proxy_lock.h"
15#include "ppapi/shared_impl/api_id.h"
16
17namespace ppapi {
18namespace proxy {
19
20namespace {
21
22// PPP_Class in the browser implementation -------------------------------------
23
24// Represents a plugin-implemented class in the browser process. This just
25// stores the data necessary to call back the plugin.
26struct ObjectProxy {
27  ObjectProxy(Dispatcher* d, int64 p, int64 ud)
28      : dispatcher(d),
29        ppp_class(p),
30        user_data(ud) {
31  }
32
33  Dispatcher* dispatcher;
34  int64 ppp_class;
35  int64 user_data;
36};
37
38ObjectProxy* ToObjectProxy(void* data) {
39  ObjectProxy* obj = reinterpret_cast<ObjectProxy*>(data);
40  if (!obj || !obj->dispatcher)
41    return NULL;
42  if (!obj->dispatcher->permissions().HasPermission(PERMISSION_DEV))
43    return NULL;
44  return obj;
45}
46
47bool HasProperty(void* object, PP_Var name, PP_Var* exception) {
48  ObjectProxy* obj = ToObjectProxy(object);
49  if (!obj)
50    return false;
51
52  bool result = false;
53  ReceiveSerializedException se(obj->dispatcher, exception);
54  obj->dispatcher->Send(new PpapiMsg_PPPClass_HasProperty(
55      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data,
56      SerializedVarSendInput(obj->dispatcher, name), &se, &result));
57  return result;
58}
59
60bool HasMethod(void* object, PP_Var name, PP_Var* exception) {
61  ObjectProxy* obj = ToObjectProxy(object);
62  if (!obj)
63    return false;
64
65  bool result = false;
66  ReceiveSerializedException se(obj->dispatcher, exception);
67  obj->dispatcher->Send(new PpapiMsg_PPPClass_HasMethod(
68      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data,
69      SerializedVarSendInput(obj->dispatcher, name), &se, &result));
70  return result;
71}
72
73PP_Var GetProperty(void* object,
74                   PP_Var name,
75                   PP_Var* exception) {
76  ObjectProxy* obj = ToObjectProxy(object);
77  if (!obj)
78    return PP_MakeUndefined();
79
80  ReceiveSerializedException se(obj->dispatcher, exception);
81  ReceiveSerializedVarReturnValue result;
82  obj->dispatcher->Send(new PpapiMsg_PPPClass_GetProperty(
83      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data,
84      SerializedVarSendInput(obj->dispatcher, name), &se, &result));
85  return result.Return(obj->dispatcher);
86}
87
88void GetAllPropertyNames(void* object,
89                         uint32_t* property_count,
90                         PP_Var** properties,
91                         PP_Var* exception) {
92  NOTIMPLEMENTED();
93  // TODO(brettw) implement this.
94}
95
96void SetProperty(void* object,
97                 PP_Var name,
98                 PP_Var value,
99                 PP_Var* exception) {
100  ObjectProxy* obj = ToObjectProxy(object);
101  if (!obj)
102    return;
103
104  ReceiveSerializedException se(obj->dispatcher, exception);
105  obj->dispatcher->Send(new PpapiMsg_PPPClass_SetProperty(
106      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data,
107      SerializedVarSendInput(obj->dispatcher, name),
108      SerializedVarSendInput(obj->dispatcher, value), &se));
109}
110
111void RemoveProperty(void* object,
112                    PP_Var name,
113                    PP_Var* exception) {
114  ObjectProxy* obj = ToObjectProxy(object);
115  if (!obj)
116    return;
117
118  ReceiveSerializedException se(obj->dispatcher, exception);
119  obj->dispatcher->Send(new PpapiMsg_PPPClass_RemoveProperty(
120      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data,
121      SerializedVarSendInput(obj->dispatcher, name), &se));
122}
123
124PP_Var Call(void* object,
125            PP_Var method_name,
126            uint32_t argc,
127            PP_Var* argv,
128            PP_Var* exception) {
129  ObjectProxy* obj = ToObjectProxy(object);
130  if (!obj)
131    return PP_MakeUndefined();
132
133  ReceiveSerializedVarReturnValue result;
134  ReceiveSerializedException se(obj->dispatcher, exception);
135  std::vector<SerializedVar> argv_vect;
136  SerializedVarSendInput::ConvertVector(obj->dispatcher, argv, argc,
137                                        &argv_vect);
138
139  obj->dispatcher->Send(new PpapiMsg_PPPClass_Call(
140      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data,
141      SerializedVarSendInput(obj->dispatcher, method_name), argv_vect,
142      &se, &result));
143  return result.Return(obj->dispatcher);
144}
145
146PP_Var Construct(void* object,
147                 uint32_t argc,
148                 PP_Var* argv,
149                 PP_Var* exception) {
150  ObjectProxy* obj = ToObjectProxy(object);
151  if (!obj)
152    return PP_MakeUndefined();
153
154  ReceiveSerializedVarReturnValue result;
155  ReceiveSerializedException se(obj->dispatcher, exception);
156  std::vector<SerializedVar> argv_vect;
157  SerializedVarSendInput::ConvertVector(obj->dispatcher, argv, argc,
158                                        &argv_vect);
159
160  obj->dispatcher->Send(new PpapiMsg_PPPClass_Construct(
161      API_ID_PPP_CLASS,
162      obj->ppp_class, obj->user_data, argv_vect, &se, &result));
163  return result.Return(obj->dispatcher);
164}
165
166void Deallocate(void* object) {
167  ObjectProxy* obj = ToObjectProxy(object);
168  if (!obj)
169    return;
170
171  obj->dispatcher->Send(new PpapiMsg_PPPClass_Deallocate(
172      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data));
173  delete obj;
174}
175
176const PPP_Class_Deprecated class_interface = {
177  &HasProperty,
178  &HasMethod,
179  &GetProperty,
180  &GetAllPropertyNames,
181  &SetProperty,
182  &RemoveProperty,
183  &Call,
184  &Construct,
185  &Deallocate
186};
187
188// Plugin helper functions -----------------------------------------------------
189
190// Converts an int64 object from IPC to a PPP_Class* for calling into the
191// plugin's implementation.
192const PPP_Class_Deprecated* ToPPPClass(int64 value) {
193  return reinterpret_cast<const PPP_Class_Deprecated*>(
194      static_cast<intptr_t>(value));
195}
196
197// Converts an int64 object from IPC to a void* for calling into the plugin's
198// implementation as the user data.
199void* ToUserData(int64 value) {
200  return reinterpret_cast<void*>(static_cast<intptr_t>(value));
201}
202
203}  // namespace
204
205// PPP_Class_Proxy -------------------------------------------------------------
206
207PPP_Class_Proxy::PPP_Class_Proxy(Dispatcher* dispatcher)
208    : InterfaceProxy(dispatcher) {
209}
210
211PPP_Class_Proxy::~PPP_Class_Proxy() {
212}
213
214// static
215InterfaceProxy* PPP_Class_Proxy::Create(Dispatcher* dispatcher) {
216  return new PPP_Class_Proxy(dispatcher);
217}
218
219// static
220PP_Var PPP_Class_Proxy::CreateProxiedObject(const PPB_Var_Deprecated* var,
221                                            Dispatcher* dispatcher,
222                                            PP_Instance instance_id,
223                                            int64 ppp_class,
224                                            int64 class_data) {
225  ObjectProxy* object_proxy = new ObjectProxy(dispatcher,
226                                              ppp_class, class_data);
227  return var->CreateObject(instance_id, &class_interface, object_proxy);
228}
229
230// static
231PP_Bool PPP_Class_Proxy::IsInstanceOf(const PPB_Var_Deprecated* ppb_var_impl,
232                                      const PP_Var& var,
233                                      int64 ppp_class,
234                                      int64* ppp_class_data) {
235  void* proxied_object = NULL;
236  if (ppb_var_impl->IsInstanceOf(var,
237                                 &class_interface,
238                                 &proxied_object)) {
239    if (static_cast<ObjectProxy*>(proxied_object)->ppp_class == ppp_class) {
240      DCHECK(ppp_class_data);
241      *ppp_class_data = static_cast<ObjectProxy*>(proxied_object)->user_data;
242      return PP_TRUE;
243    }
244  }
245  return PP_FALSE;
246}
247
248bool PPP_Class_Proxy::OnMessageReceived(const IPC::Message& msg) {
249  if (!dispatcher()->IsPlugin())
250    return false;  // These messages are only valid from host->plugin.
251
252  bool handled = true;
253  IPC_BEGIN_MESSAGE_MAP(PPP_Class_Proxy, msg)
254    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_HasProperty,
255                        OnMsgHasProperty)
256    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_HasMethod,
257                        OnMsgHasMethod)
258    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_GetProperty,
259                        OnMsgGetProperty)
260    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_EnumerateProperties,
261                        OnMsgEnumerateProperties)
262    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_SetProperty,
263                        OnMsgSetProperty)
264    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Call,
265                        OnMsgCall)
266    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Construct,
267                        OnMsgConstruct)
268    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Deallocate,
269                        OnMsgDeallocate)
270    IPC_MESSAGE_UNHANDLED(handled = false)
271  IPC_END_MESSAGE_MAP()
272  return handled;
273}
274
275void PPP_Class_Proxy::OnMsgHasProperty(int64 ppp_class, int64 object,
276                                       SerializedVarReceiveInput property,
277                                       SerializedVarOutParam exception,
278                                       bool* result) {
279  if (!ValidateUserData(ppp_class, object, &exception))
280    return;
281  *result = CallWhileUnlocked(ToPPPClass(ppp_class)->HasProperty,
282                              ToUserData(object),
283                              property.Get(dispatcher()),
284                              exception.OutParam(dispatcher()));
285}
286
287void PPP_Class_Proxy::OnMsgHasMethod(int64 ppp_class, int64 object,
288                                     SerializedVarReceiveInput property,
289                                     SerializedVarOutParam exception,
290                                     bool* result) {
291  if (!ValidateUserData(ppp_class, object, &exception))
292    return;
293  *result = CallWhileUnlocked(ToPPPClass(ppp_class)->HasMethod,
294                              ToUserData(object),
295                              property.Get(dispatcher()),
296                              exception.OutParam(dispatcher()));
297}
298
299void PPP_Class_Proxy::OnMsgGetProperty(int64 ppp_class, int64 object,
300                                       SerializedVarReceiveInput property,
301                                       SerializedVarOutParam exception,
302                                       SerializedVarReturnValue result) {
303  if (!ValidateUserData(ppp_class, object, &exception))
304    return;
305  result.Return(dispatcher(), CallWhileUnlocked(
306      ToPPPClass(ppp_class)->GetProperty,
307      ToUserData(object), property.Get(dispatcher()),
308      exception.OutParam(dispatcher())));
309}
310
311void PPP_Class_Proxy::OnMsgEnumerateProperties(
312    int64 ppp_class, int64 object,
313    std::vector<SerializedVar>* props,
314    SerializedVarOutParam exception) {
315  if (!ValidateUserData(ppp_class, object, &exception))
316    return;
317  NOTIMPLEMENTED();
318  // TODO(brettw) implement this.
319}
320
321void PPP_Class_Proxy::OnMsgSetProperty(int64 ppp_class, int64 object,
322                                       SerializedVarReceiveInput property,
323                                       SerializedVarReceiveInput value,
324                                       SerializedVarOutParam exception) {
325  if (!ValidateUserData(ppp_class, object, &exception))
326    return;
327  CallWhileUnlocked(ToPPPClass(ppp_class)->SetProperty,
328      ToUserData(object), property.Get(dispatcher()), value.Get(dispatcher()),
329      exception.OutParam(dispatcher()));
330}
331
332void PPP_Class_Proxy::OnMsgRemoveProperty(int64 ppp_class, int64 object,
333                                          SerializedVarReceiveInput property,
334                                          SerializedVarOutParam exception) {
335  if (!ValidateUserData(ppp_class, object, &exception))
336    return;
337  CallWhileUnlocked(ToPPPClass(ppp_class)->RemoveProperty,
338      ToUserData(object), property.Get(dispatcher()),
339      exception.OutParam(dispatcher()));
340}
341
342void PPP_Class_Proxy::OnMsgCall(
343    int64 ppp_class, int64 object,
344    SerializedVarReceiveInput method_name,
345    SerializedVarVectorReceiveInput arg_vector,
346    SerializedVarOutParam exception,
347    SerializedVarReturnValue result) {
348  if (!ValidateUserData(ppp_class, object, &exception))
349    return;
350  uint32_t arg_count = 0;
351  PP_Var* args = arg_vector.Get(dispatcher(), &arg_count);
352  result.Return(dispatcher(), CallWhileUnlocked(ToPPPClass(ppp_class)->Call,
353      ToUserData(object), method_name.Get(dispatcher()),
354      arg_count, args, exception.OutParam(dispatcher())));
355}
356
357void PPP_Class_Proxy::OnMsgConstruct(
358    int64 ppp_class, int64 object,
359    SerializedVarVectorReceiveInput arg_vector,
360    SerializedVarOutParam exception,
361    SerializedVarReturnValue result) {
362  if (!ValidateUserData(ppp_class, object, &exception))
363    return;
364  uint32_t arg_count = 0;
365  PP_Var* args = arg_vector.Get(dispatcher(), &arg_count);
366  result.Return(dispatcher(), CallWhileUnlocked(
367      ToPPPClass(ppp_class)->Construct,
368      ToUserData(object), arg_count, args, exception.OutParam(dispatcher())));
369}
370
371void PPP_Class_Proxy::OnMsgDeallocate(int64 ppp_class, int64 object) {
372  if (!ValidateUserData(ppp_class, object, NULL))
373    return;
374  PluginGlobals::Get()->plugin_var_tracker()->PluginImplementedObjectDestroyed(
375      ToUserData(object));
376  CallWhileUnlocked(ToPPPClass(ppp_class)->Deallocate, ToUserData(object));
377}
378
379bool PPP_Class_Proxy::ValidateUserData(int64 ppp_class, int64 class_data,
380                                       SerializedVarOutParam* exception) {
381  if (!PluginGlobals::Get()->plugin_var_tracker()->ValidatePluginObjectCall(
382          ToPPPClass(ppp_class), ToUserData(class_data))) {
383    // Set the exception. This is so the caller will know about the error and
384    // also that we won't assert that somebody forgot to call OutParam on the
385    // output parameter. Although this exception of "1" won't be very useful
386    // this shouldn't happen in normal usage, only when the renderer is being
387    // malicious.
388    if (exception)
389      *exception->OutParam(dispatcher()) = PP_MakeInt32(1);
390    return false;
391  }
392  return true;
393}
394
395}  // namespace proxy
396}  // namespace ppapi
397