// 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/api_id.h" #include "ppapi/shared_impl/proxy_lock.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_t p, int64_t ud) : dispatcher(d), ppp_class(p), user_data(ud) {} Dispatcher* dispatcher; int64_t ppp_class; int64_t user_data; }; ObjectProxy* ToObjectProxy(void* data) { ObjectProxy* obj = reinterpret_cast(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 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 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_t object from IPC to a PPP_Class* for calling into the // plugin's implementation. const PPP_Class_Deprecated* ToPPPClass(int64_t value) { return reinterpret_cast( static_cast(value)); } // Converts an int64_t object from IPC to a void* for calling into the plugin's // implementation as the user data. void* ToUserData(int64_t value) { return reinterpret_cast(static_cast(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_t ppp_class, int64_t 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_t ppp_class, int64_t* ppp_class_data) { void* proxied_object = NULL; if (ppb_var_impl->IsInstanceOf(var, &class_interface, &proxied_object)) { if (static_cast(proxied_object)->ppp_class == ppp_class) { DCHECK(ppp_class_data); *ppp_class_data = static_cast(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_t ppp_class, int64_t 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_t ppp_class, int64_t 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_t ppp_class, int64_t 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_t ppp_class, int64_t object, std::vector* props, SerializedVarOutParam exception) { if (!ValidateUserData(ppp_class, object, &exception)) return; NOTIMPLEMENTED(); // TODO(brettw) implement this. } void PPP_Class_Proxy::OnMsgSetProperty(int64_t ppp_class, int64_t 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_t ppp_class, int64_t 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_t ppp_class, int64_t 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_t ppp_class, int64_t 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_t ppp_class, int64_t 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_t ppp_class, int64_t 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