|  | // 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<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_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<const PPP_Class_Deprecated*>( | 
|  | static_cast<intptr_t>(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<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_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<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_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<SerializedVar>* 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 |