root/ppapi/proxy/ppp_class_proxy.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ToObjectProxy
  2. HasProperty
  3. HasMethod
  4. GetProperty
  5. GetAllPropertyNames
  6. SetProperty
  7. RemoveProperty
  8. Call
  9. Construct
  10. Deallocate
  11. ToPPPClass
  12. ToUserData
  13. Create
  14. CreateProxiedObject
  15. IsInstanceOf
  16. OnMessageReceived
  17. OnMsgHasProperty
  18. OnMsgHasMethod
  19. OnMsgGetProperty
  20. OnMsgEnumerateProperties
  21. OnMsgSetProperty
  22. OnMsgRemoveProperty
  23. OnMsgCall
  24. OnMsgConstruct
  25. OnMsgDeallocate
  26. ValidateUserData

// Copyright (c) 2012 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/ppp_class_proxy.h"

#include "ppapi/c/dev/ppb_var_deprecated.h"
#include "ppapi/c/dev/ppp_class_deprecated.h"
#include "ppapi/c/pp_var.h"
#include "ppapi/proxy/dispatcher.h"
#include "ppapi/proxy/plugin_globals.h"
#include "ppapi/proxy/ppapi_messages.h"
#include "ppapi/proxy/serialized_var.h"
#include "ppapi/shared_impl/proxy_lock.h"
#include "ppapi/shared_impl/api_id.h"

namespace ppapi {
namespace proxy {

namespace {

// PPP_Class in the browser implementation -------------------------------------

// Represents a plugin-implemented class in the browser process. This just
// stores the data necessary to call back the plugin.
struct ObjectProxy {
  ObjectProxy(Dispatcher* d, int64 p, int64 ud)
      : dispatcher(d),
        ppp_class(p),
        user_data(ud) {
  }

  Dispatcher* dispatcher;
  int64 ppp_class;
  int64 user_data;
};

ObjectProxy* ToObjectProxy(void* data) {
  ObjectProxy* obj = reinterpret_cast<ObjectProxy*>(data);
  if (!obj || !obj->dispatcher)
    return NULL;
  if (!obj->dispatcher->permissions().HasPermission(PERMISSION_DEV))
    return NULL;
  return obj;
}

bool HasProperty(void* object, PP_Var name, PP_Var* exception) {
  ObjectProxy* obj = ToObjectProxy(object);
  if (!obj)
    return false;

  bool result = false;
  ReceiveSerializedException se(obj->dispatcher, exception);
  obj->dispatcher->Send(new PpapiMsg_PPPClass_HasProperty(
      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data,
      SerializedVarSendInput(obj->dispatcher, name), &se, &result));
  return result;
}

bool HasMethod(void* object, PP_Var name, PP_Var* exception) {
  ObjectProxy* obj = ToObjectProxy(object);
  if (!obj)
    return false;

  bool result = false;
  ReceiveSerializedException se(obj->dispatcher, exception);
  obj->dispatcher->Send(new PpapiMsg_PPPClass_HasMethod(
      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data,
      SerializedVarSendInput(obj->dispatcher, name), &se, &result));
  return result;
}

PP_Var GetProperty(void* object,
                   PP_Var name,
                   PP_Var* exception) {
  ObjectProxy* obj = ToObjectProxy(object);
  if (!obj)
    return PP_MakeUndefined();

  ReceiveSerializedException se(obj->dispatcher, exception);
  ReceiveSerializedVarReturnValue result;
  obj->dispatcher->Send(new PpapiMsg_PPPClass_GetProperty(
      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data,
      SerializedVarSendInput(obj->dispatcher, name), &se, &result));
  return result.Return(obj->dispatcher);
}

void GetAllPropertyNames(void* object,
                         uint32_t* property_count,
                         PP_Var** properties,
                         PP_Var* exception) {
  NOTIMPLEMENTED();
  // TODO(brettw) implement this.
}

void SetProperty(void* object,
                 PP_Var name,
                 PP_Var value,
                 PP_Var* exception) {
  ObjectProxy* obj = ToObjectProxy(object);
  if (!obj)
    return;

  ReceiveSerializedException se(obj->dispatcher, exception);
  obj->dispatcher->Send(new PpapiMsg_PPPClass_SetProperty(
      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data,
      SerializedVarSendInput(obj->dispatcher, name),
      SerializedVarSendInput(obj->dispatcher, value), &se));
}

void RemoveProperty(void* object,
                    PP_Var name,
                    PP_Var* exception) {
  ObjectProxy* obj = ToObjectProxy(object);
  if (!obj)
    return;

  ReceiveSerializedException se(obj->dispatcher, exception);
  obj->dispatcher->Send(new PpapiMsg_PPPClass_RemoveProperty(
      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data,
      SerializedVarSendInput(obj->dispatcher, name), &se));
}

PP_Var Call(void* object,
            PP_Var method_name,
            uint32_t argc,
            PP_Var* argv,
            PP_Var* exception) {
  ObjectProxy* obj = ToObjectProxy(object);
  if (!obj)
    return PP_MakeUndefined();

  ReceiveSerializedVarReturnValue result;
  ReceiveSerializedException se(obj->dispatcher, exception);
  std::vector<SerializedVar> argv_vect;
  SerializedVarSendInput::ConvertVector(obj->dispatcher, argv, argc,
                                        &argv_vect);

  obj->dispatcher->Send(new PpapiMsg_PPPClass_Call(
      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data,
      SerializedVarSendInput(obj->dispatcher, method_name), argv_vect,
      &se, &result));
  return result.Return(obj->dispatcher);
}

PP_Var Construct(void* object,
                 uint32_t argc,
                 PP_Var* argv,
                 PP_Var* exception) {
  ObjectProxy* obj = ToObjectProxy(object);
  if (!obj)
    return PP_MakeUndefined();

  ReceiveSerializedVarReturnValue result;
  ReceiveSerializedException se(obj->dispatcher, exception);
  std::vector<SerializedVar> argv_vect;
  SerializedVarSendInput::ConvertVector(obj->dispatcher, argv, argc,
                                        &argv_vect);

  obj->dispatcher->Send(new PpapiMsg_PPPClass_Construct(
      API_ID_PPP_CLASS,
      obj->ppp_class, obj->user_data, argv_vect, &se, &result));
  return result.Return(obj->dispatcher);
}

void Deallocate(void* object) {
  ObjectProxy* obj = ToObjectProxy(object);
  if (!obj)
    return;

  obj->dispatcher->Send(new PpapiMsg_PPPClass_Deallocate(
      API_ID_PPP_CLASS, obj->ppp_class, obj->user_data));
  delete obj;
}

const PPP_Class_Deprecated class_interface = {
  &HasProperty,
  &HasMethod,
  &GetProperty,
  &GetAllPropertyNames,
  &SetProperty,
  &RemoveProperty,
  &Call,
  &Construct,
  &Deallocate
};

// Plugin helper functions -----------------------------------------------------

// Converts an int64 object from IPC to a PPP_Class* for calling into the
// plugin's implementation.
const PPP_Class_Deprecated* ToPPPClass(int64 value) {
  return reinterpret_cast<const PPP_Class_Deprecated*>(
      static_cast<intptr_t>(value));
}

// Converts an int64 object from IPC to a void* for calling into the plugin's
// implementation as the user data.
void* ToUserData(int64 value) {
  return reinterpret_cast<void*>(static_cast<intptr_t>(value));
}

}  // namespace

// PPP_Class_Proxy -------------------------------------------------------------

PPP_Class_Proxy::PPP_Class_Proxy(Dispatcher* dispatcher)
    : InterfaceProxy(dispatcher) {
}

PPP_Class_Proxy::~PPP_Class_Proxy() {
}

// static
InterfaceProxy* PPP_Class_Proxy::Create(Dispatcher* dispatcher) {
  return new PPP_Class_Proxy(dispatcher);
}

// static
PP_Var PPP_Class_Proxy::CreateProxiedObject(const PPB_Var_Deprecated* var,
                                            Dispatcher* dispatcher,
                                            PP_Instance instance_id,
                                            int64 ppp_class,
                                            int64 class_data) {
  ObjectProxy* object_proxy = new ObjectProxy(dispatcher,
                                              ppp_class, class_data);
  return var->CreateObject(instance_id, &class_interface, object_proxy);
}

// static
PP_Bool PPP_Class_Proxy::IsInstanceOf(const PPB_Var_Deprecated* ppb_var_impl,
                                      const PP_Var& var,
                                      int64 ppp_class,
                                      int64* ppp_class_data) {
  void* proxied_object = NULL;
  if (ppb_var_impl->IsInstanceOf(var,
                                 &class_interface,
                                 &proxied_object)) {
    if (static_cast<ObjectProxy*>(proxied_object)->ppp_class == ppp_class) {
      DCHECK(ppp_class_data);
      *ppp_class_data = static_cast<ObjectProxy*>(proxied_object)->user_data;
      return PP_TRUE;
    }
  }
  return PP_FALSE;
}

bool PPP_Class_Proxy::OnMessageReceived(const IPC::Message& msg) {
  if (!dispatcher()->IsPlugin())
    return false;  // These messages are only valid from host->plugin.

  bool handled = true;
  IPC_BEGIN_MESSAGE_MAP(PPP_Class_Proxy, msg)
    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_HasProperty,
                        OnMsgHasProperty)
    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_HasMethod,
                        OnMsgHasMethod)
    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_GetProperty,
                        OnMsgGetProperty)
    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_EnumerateProperties,
                        OnMsgEnumerateProperties)
    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_SetProperty,
                        OnMsgSetProperty)
    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Call,
                        OnMsgCall)
    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Construct,
                        OnMsgConstruct)
    IPC_MESSAGE_HANDLER(PpapiMsg_PPPClass_Deallocate,
                        OnMsgDeallocate)
    IPC_MESSAGE_UNHANDLED(handled = false)
  IPC_END_MESSAGE_MAP()
  return handled;
}

void PPP_Class_Proxy::OnMsgHasProperty(int64 ppp_class, int64 object,
                                       SerializedVarReceiveInput property,
                                       SerializedVarOutParam exception,
                                       bool* result) {
  if (!ValidateUserData(ppp_class, object, &exception))
    return;
  *result = CallWhileUnlocked(ToPPPClass(ppp_class)->HasProperty,
                              ToUserData(object),
                              property.Get(dispatcher()),
                              exception.OutParam(dispatcher()));
}

void PPP_Class_Proxy::OnMsgHasMethod(int64 ppp_class, int64 object,
                                     SerializedVarReceiveInput property,
                                     SerializedVarOutParam exception,
                                     bool* result) {
  if (!ValidateUserData(ppp_class, object, &exception))
    return;
  *result = CallWhileUnlocked(ToPPPClass(ppp_class)->HasMethod,
                              ToUserData(object),
                              property.Get(dispatcher()),
                              exception.OutParam(dispatcher()));
}

void PPP_Class_Proxy::OnMsgGetProperty(int64 ppp_class, int64 object,
                                       SerializedVarReceiveInput property,
                                       SerializedVarOutParam exception,
                                       SerializedVarReturnValue result) {
  if (!ValidateUserData(ppp_class, object, &exception))
    return;
  result.Return(dispatcher(), CallWhileUnlocked(
      ToPPPClass(ppp_class)->GetProperty,
      ToUserData(object), property.Get(dispatcher()),
      exception.OutParam(dispatcher())));
}

void PPP_Class_Proxy::OnMsgEnumerateProperties(
    int64 ppp_class, int64 object,
    std::vector<SerializedVar>* props,
    SerializedVarOutParam exception) {
  if (!ValidateUserData(ppp_class, object, &exception))
    return;
  NOTIMPLEMENTED();
  // TODO(brettw) implement this.
}

void PPP_Class_Proxy::OnMsgSetProperty(int64 ppp_class, int64 object,
                                       SerializedVarReceiveInput property,
                                       SerializedVarReceiveInput value,
                                       SerializedVarOutParam exception) {
  if (!ValidateUserData(ppp_class, object, &exception))
    return;
  CallWhileUnlocked(ToPPPClass(ppp_class)->SetProperty,
      ToUserData(object), property.Get(dispatcher()), value.Get(dispatcher()),
      exception.OutParam(dispatcher()));
}

void PPP_Class_Proxy::OnMsgRemoveProperty(int64 ppp_class, int64 object,
                                          SerializedVarReceiveInput property,
                                          SerializedVarOutParam exception) {
  if (!ValidateUserData(ppp_class, object, &exception))
    return;
  CallWhileUnlocked(ToPPPClass(ppp_class)->RemoveProperty,
      ToUserData(object), property.Get(dispatcher()),
      exception.OutParam(dispatcher()));
}

void PPP_Class_Proxy::OnMsgCall(
    int64 ppp_class, int64 object,
    SerializedVarReceiveInput method_name,
    SerializedVarVectorReceiveInput arg_vector,
    SerializedVarOutParam exception,
    SerializedVarReturnValue result) {
  if (!ValidateUserData(ppp_class, object, &exception))
    return;
  uint32_t arg_count = 0;
  PP_Var* args = arg_vector.Get(dispatcher(), &arg_count);
  result.Return(dispatcher(), CallWhileUnlocked(ToPPPClass(ppp_class)->Call,
      ToUserData(object), method_name.Get(dispatcher()),
      arg_count, args, exception.OutParam(dispatcher())));
}

void PPP_Class_Proxy::OnMsgConstruct(
    int64 ppp_class, int64 object,
    SerializedVarVectorReceiveInput arg_vector,
    SerializedVarOutParam exception,
    SerializedVarReturnValue result) {
  if (!ValidateUserData(ppp_class, object, &exception))
    return;
  uint32_t arg_count = 0;
  PP_Var* args = arg_vector.Get(dispatcher(), &arg_count);
  result.Return(dispatcher(), CallWhileUnlocked(
      ToPPPClass(ppp_class)->Construct,
      ToUserData(object), arg_count, args, exception.OutParam(dispatcher())));
}

void PPP_Class_Proxy::OnMsgDeallocate(int64 ppp_class, int64 object) {
  if (!ValidateUserData(ppp_class, object, NULL))
    return;
  PluginGlobals::Get()->plugin_var_tracker()->PluginImplementedObjectDestroyed(
      ToUserData(object));
  CallWhileUnlocked(ToPPPClass(ppp_class)->Deallocate, ToUserData(object));
}

bool PPP_Class_Proxy::ValidateUserData(int64 ppp_class, int64 class_data,
                                       SerializedVarOutParam* exception) {
  if (!PluginGlobals::Get()->plugin_var_tracker()->ValidatePluginObjectCall(
          ToPPPClass(ppp_class), ToUserData(class_data))) {
    // Set the exception. This is so the caller will know about the error and
    // also that we won't assert that somebody forgot to call OutParam on the
    // output parameter. Although this exception of "1" won't be very useful
    // this shouldn't happen in normal usage, only when the renderer is being
    // malicious.
    if (exception)
      *exception->OutParam(dispatcher()) = PP_MakeInt32(1);
    return false;
  }
  return true;
}

}  // namespace proxy
}  // namespace ppapi

/* [<][>][^][v][top][bottom][index][help] */