First iteration of completely rewritten NPObject marshalling code

Most of the credit goes to Chromium as this is the exact same design.
The main advantage is that we should no longer be leaking NPObject stubs
left and right.
This commit is contained in:
David Benjamin 2011-04-20 01:27:18 -04:00
parent 60638fff52
commit bd167dc2d3
9 changed files with 282 additions and 414 deletions

View File

@ -2,6 +2,7 @@
* npruntime.c - Scripting plugins support
*
* nspluginwrapper (C) 2005-2009 Gwenole Beauchesne
* (C) 2011 David Benjamin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -21,29 +22,26 @@
#ifndef NPRUNTIME_IMPL_H
#define NPRUNTIME_IMPL_H
// NPObjectInfo is used to hold additional information for an NPObject instance
typedef struct {
NPObject *npobj;
uint32_t npobj_id;
bool is_valid;
void *plugin;
} NPObjectInfo;
extern NPObjectInfo *npobject_info_new(NPObject *npobj) attribute_hidden;
extern NPObjectInfo *npobject_info_lookup(NPObject *npobj) attribute_hidden;
extern NPObject *npobject_new(uint32_t npobj_id, NPP instance, NPClass *class) attribute_hidden;
extern void npobject_destroy(NPObject *npobj) attribute_hidden;
extern NPObject *npobject_lookup(uint32_t npobj_id) attribute_hidden;
extern void npobject_associate(NPObject *npobj, NPObjectInfo *npobj_info) attribute_hidden;
// npruntime bridge system inspired by Chromium's proxy/stub setup.
// Init and shutdown of the NPObject bridge system.
extern bool npobject_bridge_new(void) attribute_hidden;
extern void npobject_bridge_destroy(void) attribute_hidden;
extern NPClass npclass_bridge attribute_hidden;
extern int npclass_add_method_descriptors(rpc_connection_t *connection) attribute_hidden;
// Management of stubs, objects which live on the side that owns the
// NPObject and holds a reference to it on behalf of a proxy.
extern uint32_t npobject_create_stub(NPObject *npobj) attribute_hidden;
extern NPObject *npobject_lookup_local(uint32_t id) attribute_hidden;
// Create a proxy object. The received id must correspond to a live
// stub in the other process. Deallocating this object releases its
// corresponding stub. Holds a reference to the other NPObject on via
// its stub.
extern NPObject *npobject_create_proxy(uint32_t id) attribute_hidden;
extern uint32_t npobject_get_proxy_id(NPObject *npobj) attribute_hidden;
struct _NPVariant;
extern void npvariant_clear(struct _NPVariant *variant) attribute_hidden;
extern char *string_of_NPVariant(const struct _NPVariant *arg) attribute_hidden;

View File

@ -60,11 +60,118 @@ bool npruntime_use_cache(void)
return use_cache;
}
/* ====================================================================== */
/* === NPObject stubs === */
/* ====================================================================== */
static GHashTable *g_stubs = NULL; // uint32_t -> (NPObjectStub *)
typedef struct _NPObjectStub {
NPObject *npobject;
uint32_t id;
} NPObjectStub;
uint32_t npobject_create_stub(NPObject *npobj)
{
npw_return_val_if_fail(npobj != NULL, 0);
static uint32_t next_id = 0;
// Allocate an id. Client and server get distinct id spaces.
uint32_t id = ++next_id;
assert(id < (1<<31));
if (rpc_is_server(g_rpc_connection))
id |= (1<<31);
D(bug("npobject_create_stub: npobj=%p, id=0x%x\n", npobj, id));
NPObjectStub *stub = g_new0(NPObjectStub, 1);
stub->npobject = NPN_RetainObject(npobj);
stub->id = id;
g_hash_table_insert(g_stubs, GINT_TO_POINTER(stub->id), stub);
return stub->id;
}
static NPObjectStub *npobject_lookup_stub(uint32_t id)
{
return g_hash_table_lookup(g_stubs, GINT_TO_POINTER(id));
}
NPObject *npobject_lookup_local(uint32_t id)
{
NPObjectStub *stub = npobject_lookup_stub(id);
return stub ? stub->npobject : NULL;
}
static void npobject_destroy_stub(NPObjectStub *stub)
{
D(bug("npobject_stub: id=0x%x\n", stub->id));
g_hash_table_remove(g_stubs, GINT_TO_POINTER(stub->id));
NPN_ReleaseObject(stub->npobject);
g_free(stub);
}
/* ====================================================================== */
/* === NPObject proxies === */
/* ====================================================================== */
static GHashTable *g_proxies = NULL; // uint32_t -> (NPObjectProxy *)
static NPClass npclass_bridge;
typedef struct _NPObjectProxy {
NPObject parent;
uint32_t id;
bool is_valid;
} NPObjectProxy;
static NPObjectProxy *npobject_get_proxy(NPObject *npobj)
{
if (npobj->_class != &npclass_bridge)
return NULL;
return (NPObjectProxy *)npobj;
}
NPObject *npobject_create_proxy(uint32_t id)
{
D(bugiI("npobject_create_proxy: id=0x%x\n", id));
NPObject *object = NPN_CreateObject(NULL, &npclass_bridge);
NPObjectProxy *proxy = npobject_get_proxy(object);
proxy->id = id;
proxy->is_valid = true;
// There isn't a huge need to track them by id. Any, really. But it
// does let us invalidate them all.
g_hash_table_insert(g_proxies, GINT_TO_POINTER(id), proxy);
D(bugiD("npobject_create_proxy done: obj=%p\n", object));
return object;
}
uint32_t npobject_get_proxy_id(NPObject *npobj)
{
NPObjectProxy *proxy = npobject_get_proxy(npobj);
if (proxy == NULL)
return 0;
return proxy->id;
}
static inline bool is_valid_npobject_proxy(NPObject *npobj)
{
if (npobj == NULL)
return false;
NPObjectProxy *proxy = npobject_get_proxy(npobj);
if (proxy == NULL)
return false;
if (!proxy->is_valid)
npw_printf("ERROR: NPObject proxy %p is no longer valid!\n", npobj);
return proxy->is_valid;
}
/* ====================================================================== */
/* === NPClass Bridge === */
/* ====================================================================== */
static NPObject *g_NPClass_Allocate(NPP npp, NPClass *aclass);
static void g_NPClass_Deallocate(NPObject *npobj);
static void g_NPClass_Invalidate(NPObject *npobj);
static bool g_NPClass_HasMethod(NPObject *npobj, NPIdentifier name);
static bool g_NPClass_Invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result);
@ -76,10 +183,10 @@ static bool g_NPClass_RemoveProperty(NPObject *npobj, NPIdentifier name);
static bool g_NPClass_Enumerate(NPObject *npobj, NPIdentifier **value, uint32_t *count);
static bool g_NPClass_Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result);
NPClass npclass_bridge = {
static NPClass npclass_bridge = {
NPW_NP_CLASS_STRUCT_VERSION,
NULL,
NULL,
g_NPClass_Allocate,
g_NPClass_Deallocate,
g_NPClass_Invalidate,
g_NPClass_HasMethod,
g_NPClass_Invoke,
@ -94,14 +201,74 @@ NPClass npclass_bridge = {
static inline bool is_valid_npobject_class(NPObject *npobj)
{
if (npobj == NULL || npobj->_class == NULL)
return false;
NPObjectInfo *npobj_info = npobject_info_lookup(npobj);
if (npobj_info == NULL)
return false;
if (!npobj_info->is_valid)
npw_printf("ERROR: NPObject %p is no longer valid!\n", npobj);
return npobj_info->is_valid;
return npobj != NULL && npobj->_class != NULL;
}
// NPClass::Allocate
NPObject *g_NPClass_Allocate(NPP npp, NPClass *aclass)
{
return malloc(sizeof(NPObjectProxy));
}
// NPClass::Deallocate
int npclass_handle_Deallocate(rpc_connection_t *connection)
{
D(bug("npclass_handle_Deallocate\n"));
uint32_t id;
int error = rpc_method_get_args(connection,
RPC_TYPE_UINT32, &id,
RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NPClass::Deallocate() get args", error);
return error;
}
D(bugiI("NPClass:Deallocate: id=0x%x\n", id));
NPObjectStub *stub = npobject_lookup_stub(id);
if (stub != NULL) {
npobject_destroy_stub(stub);
}
D(bugiD("NPClass:Deallocate done\n"));
return rpc_method_send_reply(connection, RPC_TYPE_INVALID);
}
static void npclass_invoke_Deallocate(NPObjectProxy *proxy)
{
npw_return_if_fail(rpc_method_invoke_possible(g_rpc_connection));
int error = rpc_method_invoke(g_rpc_connection,
RPC_METHOD_NPCLASS_DEALLOCATE,
RPC_TYPE_UINT32, proxy->id,
RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NPClass::Deallocate() invoke", error);
return;
}
// FIXME: This really could be asynchronous...
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NPClass::Deallocate() wait for reply", error);
return;
}
}
void g_NPClass_Deallocate(NPObject *npobj)
{
// Unregister the proxy.
D(bugiI("NPClass::Deallocate: npobj=%p\n", npobj));
NPObjectProxy *proxy = npobject_get_proxy(npobj);
if (proxy && proxy->is_valid) {
npclass_invoke_Deallocate(proxy);
g_hash_table_remove(g_proxies, GINT_TO_POINTER(proxy->id));
}
D(bugiD("NPClass::Deallocate done\n"));
free(npobj);
}
// NPClass::Invalidate
@ -152,7 +319,7 @@ static void npclass_invoke_Invalidate(NPObject *npobj)
void g_NPClass_Invalidate(NPObject *npobj)
{
if (!is_valid_npobject_class(npobj))
if (!is_valid_npobject_proxy(npobj))
return;
if (!thread_check()) {
@ -222,7 +389,7 @@ static bool npclass_invoke_HasMethod(NPObject *npobj, NPIdentifier name)
bool g_NPClass_HasMethod(NPObject *npobj, NPIdentifier name)
{
if (!is_valid_npobject_class(npobj))
if (!is_valid_npobject_proxy(npobj))
return false;
if (!thread_check()) {
@ -321,7 +488,7 @@ bool g_NPClass_Invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args,
return false;
VOID_TO_NPVARIANT(*result);
if (!is_valid_npobject_class(npobj))
if (!is_valid_npobject_proxy(npobj))
return false;
if (!thread_check()) {
@ -420,7 +587,7 @@ bool g_NPClass_InvokeDefault(NPObject *npobj, const NPVariant *args, uint32_t ar
return false;
VOID_TO_NPVARIANT(*result);
if (!is_valid_npobject_class(npobj))
if (!is_valid_npobject_proxy(npobj))
return false;
if (!thread_check()) {
@ -494,7 +661,7 @@ static bool npclass_invoke_HasProperty(NPObject *npobj, NPIdentifier name)
bool g_NPClass_HasProperty(NPObject *npobj, NPIdentifier name)
{
if (!is_valid_npobject_class(npobj))
if (!is_valid_npobject_proxy(npobj))
return false;
if (!thread_check()) {
@ -580,7 +747,7 @@ bool g_NPClass_GetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result
return false;
VOID_TO_NPVARIANT(*result);
if (!is_valid_npobject_class(npobj))
if (!is_valid_npobject_proxy(npobj))
return false;
if (!thread_check()) {
@ -666,7 +833,7 @@ bool g_NPClass_SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *
return false;
}
if (!is_valid_npobject_class(npobj))
if (!is_valid_npobject_proxy(npobj))
return false;
if (!thread_check()) {
@ -737,7 +904,7 @@ static bool npclass_invoke_RemoveProperty(NPObject *npobj, NPIdentifier name)
bool g_NPClass_RemoveProperty(NPObject *npobj, NPIdentifier name)
{
if (!is_valid_npobject_class(npobj))
if (!is_valid_npobject_proxy(npobj))
return false;
if (!thread_check()) {
@ -822,7 +989,7 @@ bool g_NPClass_Enumerate(NPObject *npobj,
if (count == NULL || idents == NULL)
return false;
if (!is_valid_npobject_class(npobj))
if (!is_valid_npobject_proxy(npobj))
return false;
if (!thread_check()) {
@ -919,7 +1086,7 @@ bool g_NPClass_Construct(NPObject *npobj, const NPVariant *args, uint32_t argCou
return false;
VOID_TO_NPVARIANT(*result);
if (!is_valid_npobject_class(npobj))
if (!is_valid_npobject_proxy(npobj))
return false;
if (!thread_check()) {
@ -949,169 +1116,56 @@ int npclass_add_method_descriptors(rpc_connection_t *connection)
{ RPC_METHOD_NPCLASS_REMOVE_PROPERTY, npclass_handle_RemoveProperty },
{ RPC_METHOD_NPCLASS_ENUMERATE, npclass_handle_Enumerate },
{ RPC_METHOD_NPCLASS_CONSTRUCT, npclass_handle_Construct },
{ RPC_METHOD_NPCLASS_DEALLOCATE, npclass_handle_Deallocate },
};
return rpc_connection_add_method_descriptors(g_rpc_connection, vtable,
sizeof(vtable) / sizeof(vtable[0]));
}
/* ====================================================================== */
/* === NPObjectInfo === */
/* ====================================================================== */
NPObjectInfo *npobject_info_new(NPObject *npobj)
{
NPObjectInfo *npobj_info = NPW_MemNew(NPObjectInfo, 1);
if (npobj_info) {
static uint32_t id;
npobj_info->npobj = npobj;
npobj_info->npobj_id = ++id;
npobj_info->is_valid = true;
npobj_info->plugin = NULL;
}
return npobj_info;
}
static void npobject_info_destroy(NPObjectInfo *npobj_info)
{
if (npobj_info == NULL)
return;
npw_plugin_instance_unref(npobj_info->plugin);
NPW_MemFree(npobj_info);
}
/* ====================================================================== */
/* === NPObject === */
/* ====================================================================== */
static void npobject_hash_table_insert(NPObject *npobj, NPObjectInfo *npobj_info);
static bool npobject_hash_table_remove(NPObject *npobj);
static NPObject *_npobject_new(NPP instance, NPClass *class)
{
NPObject *npobj;
if (class && class->allocate)
npobj = class->allocate(instance, class);
else
npobj = malloc(sizeof(*npobj));
if (npobj) {
npobj->_class = class ? class : &npclass_bridge;
npobj->referenceCount = 1;
}
return npobj;
}
static void _npobject_destroy(NPObject *npobj)
{
if (npobj) {
if (npobj->_class && npobj->_class->deallocate)
npobj->_class->deallocate(npobj);
else
free(npobj);
}
}
NPObject *npobject_new(uint32_t npobj_id, NPP instance, NPClass *class)
{
NPObject *npobj = _npobject_new(instance, class);
if (npobj == NULL)
return NULL;
NPObjectInfo *npobj_info = npobject_info_new(npobj);
if (npobj_info == NULL) {
_npobject_destroy(npobj);
return NULL;
}
npobj_info->npobj_id = npobj_id;
npobj_info->plugin = npw_plugin_instance_ref(NPW_PLUGIN_INSTANCE(instance));
npobject_associate(npobj, npobj_info);
return npobj;
}
void npobject_destroy(NPObject *npobj)
{
if (npobj)
npobject_hash_table_remove(npobj);
_npobject_destroy(npobj);
}
void npobject_associate(NPObject *npobj, NPObjectInfo *npobj_info)
{
assert(npobj && npobj_info && npobj_info->npobj_id > 0);
npobject_hash_table_insert(npobj, npobj_info);
}
/* ====================================================================== */
/* === NPObject Repository === */
/* ====================================================================== */
// NOTE: those hashes must be maintained in a whole, not separately
static GHashTable *g_npobjects = NULL; // (NPObject *) -> (NPObjectInfo *)
static GHashTable *g_npobject_ids = NULL; // (NPObject ID) -> (NPObject *)
bool npobject_bridge_new(void)
{
if ((g_npobjects = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify)npobject_info_destroy)) == NULL)
return false;
if ((g_npobject_ids = g_hash_table_new(NULL, NULL)) == NULL)
return false;
g_stubs = g_hash_table_new(NULL, NULL);
g_proxies = g_hash_table_new(NULL, NULL);
return true;
}
void npobject_bridge_destroy(void)
{
if (g_npobject_ids) {
g_hash_table_destroy(g_npobject_ids);
g_npobject_ids = NULL;
if (g_stubs) {
g_hash_table_destroy(g_stubs);
g_stubs = NULL;
}
if (g_npobjects) {
g_hash_table_destroy(g_npobjects);
g_npobjects = NULL;
if (g_proxies) {
g_hash_table_destroy(g_proxies);
g_proxies = NULL;
}
}
void npobject_hash_table_insert(NPObject *npobj, NPObjectInfo *npobj_info)
static void proxy_deactivate_func(gpointer key, gpointer value, gpointer user_data)
{
g_hash_table_insert(g_npobjects, npobj, npobj_info);
g_hash_table_insert(g_npobject_ids, (void *)(uintptr_t)npobj_info->npobj_id, npobj);
NPObjectProxy *proxy = (NPObjectProxy *)value;
proxy->is_valid = false;
}
bool npobject_hash_table_remove(NPObject *npobj)
static void stub_destroy_func(gpointer key, gpointer value, gpointer user_data)
{
NPObjectInfo *npobj_info = npobject_info_lookup(npobj);
assert(npobj_info != NULL);
bool removed_all = true;
if (!g_hash_table_remove(g_npobject_ids, (void *)(uintptr_t)npobj_info->npobj_id))
removed_all = false;
if (!g_hash_table_remove(g_npobjects, npobj))
removed_all = false;
return removed_all;
}
NPObjectInfo *npobject_info_lookup(NPObject *npobj)
{
return g_hash_table_lookup(g_npobjects, npobj);
}
NPObject *npobject_lookup(uint32_t npobj_id)
{
return g_hash_table_lookup(g_npobject_ids, (void *)(uintptr_t)npobj_id);
}
static void npruntime_deactivate_func(gpointer key, gpointer value, gpointer user_data)
{
NPObjectInfo *npobj_info = (NPObjectInfo *)value;
npobj_info->is_valid = false;
NPObjectStub *stub = (NPObjectStub *)value;
npobject_destroy_stub(stub);
}
void npruntime_deactivate(void)
{
g_hash_table_foreach(g_npobjects, npruntime_deactivate_func, NULL);
// Invalidate any proxies the wrapper may still be holding on to.
g_hash_table_foreach(g_proxies, proxy_deactivate_func, NULL);
g_hash_table_foreach(g_stubs, stub_destroy_func, NULL);
// Reset both tables.
npobject_bridge_destroy();
npobject_bridge_new();
}

View File

@ -128,6 +128,12 @@ NPN_MemFlush (uint32_t size)
return g_mozilla_funcs.memflush(size);
}
attribute_hidden NPObject *
NPN_CreateObject (NPP instance, NPClass *aclass)
{
return g_mozilla_funcs.createobject(instance, aclass);
}
attribute_hidden NPObject *
NPN_RetainObject (NPObject *npobj)
{

View File

@ -1183,32 +1183,22 @@ static int do_send_NPObject(rpc_message_t *message, void *p_value)
uint32_t npobj_id = 0;
NPObject *npobj = (NPObject *)p_value;
if (npobj) {
NPObjectInfo *npobj_info = npobject_info_lookup(npobj);
if (npobj_info)
npobj_id = npobj_info->npobj_id;
#ifdef BUILD_WRAPPER
else {
// create a new mapping (browser-side)
if ((npobj_info = npobject_info_new(npobj)) == NULL)
return RPC_ERROR_NO_MEMORY;
npobj_id = npobj_info->npobj_id;
npobject_associate(npobj, npobj_info);
npobj_id = npobject_get_proxy_id(npobj);
if (npobj_id == 0) {
// Sending an object on our side. Allocate a stub so the other
// side can make a proxy.
npobj_id = npobject_create_stub(npobj);
} else {
// This is a proxy for the object on the other side. Just pass
// the id along.
}
#endif
D(bug("sending id 0x%x\n", npobj_id));
assert(npobj_id != 0);
}
int error = rpc_message_send_uint32(message, npobj_id);
if (error < 0)
return error;
#ifdef BUILD_WRAPPER
// synchronize referenceCount
if (npobj) {
if ((error = rpc_message_send_uint32(message, npobj->referenceCount)) < 0)
return error;
}
#endif
return RPC_ERROR_NO_ERROR;
}
@ -1222,27 +1212,17 @@ static int do_recv_NPObject(rpc_message_t *message, void *p_value)
NPObject *npobj = NULL;
if (npobj_id) {
npobj = npobject_lookup(npobj_id);
#ifdef BUILD_VIEWER
// create a new mapping (plugin-side)
npobj = npobject_lookup_local(npobj_id);
if (npobj == NULL) {
if ((npobj = npobject_new(npobj_id, NULL, NULL)) == NULL)
return RPC_ERROR_NO_MEMORY;
// We got an id of a newly created remote stub. Create a proxy
// for it.
npobj = npobject_create_proxy(npobj_id);
} else {
// This is an object on our side. Just use it.
D(bug("local\n"));
}
#endif
D(bug("recv id 0x%x, obj %p\n", npobj_id, npobj));
assert(npobj != NULL);
#ifdef BUILD_VIEWER
// synchronize referenceCount
uint32_t referenceCount;
if ((error = rpc_message_recv_uint32(message, &referenceCount)) < 0)
return error;
if (npobj->referenceCount != referenceCount) {
D(bug("synchronize NPObject::referenceCount (%d -> %d)\n",
npobj->referenceCount, referenceCount));
npobj->referenceCount = referenceCount;
}
#endif
}
*((NPObject **)p_value) = npobj;
@ -1421,13 +1401,6 @@ static int do_send_NPVariant(rpc_message_t *message, void *p_value)
return error;
break;
case NPVariantType_Object:
if (NPW_IS_BROWSER) {
/* Note: when we pass an NPObject to the plugin, it's supposed
to be released once it's done with processing the RPC args.
i.e. NPN_ReleaseVariantValue() is called for any NPVariant we
received through rpc_method_get_args(). */
NPN_RetainObject(variant->value.objectValue);
}
if ((error = do_send_NPObject(message, variant->value.objectValue)) < 0)
return error;
break;
@ -1478,13 +1451,8 @@ static int do_recv_NPVariant(rpc_message_t *message, void *p_value)
case NPVariantType_Object:
if ((error = do_recv_NPObject(message, &result.value.objectValue)) < 0)
return error;
if (NPW_IS_BROWSER) {
/* Note: it's not necessary to propagate the refcount back to
the plugin-side since the object will be unref'ed through
NPN_ReleaseVariantValue() once we are done with processing
the RPC args. */
NPN_RetainObject(result.value.objectValue);
}
/* The NPVariant now owns a reference to this object. */
NPN_RetainObject(result.value.objectValue);
break;
}

View File

@ -108,7 +108,8 @@ enum {
RPC_METHOD_NPCLASS_SET_PROPERTY, /* 75 */
RPC_METHOD_NPCLASS_REMOVE_PROPERTY,
RPC_METHOD_NPCLASS_ENUMERATE,
RPC_METHOD_NPCLASS_CONSTRUCT
RPC_METHOD_NPCLASS_CONSTRUCT,
RPC_METHOD_NPCLASS_DEALLOCATE
};
// NPAPI data types

View File

@ -2004,35 +2004,6 @@ g_NPN_PopPopupsEnabledState(NPP instance)
/* === NPRuntime glue === */
/* ====================================================================== */
// Allocates a new NPObject
static uint32_t
invoke_NPN_CreateObject(PluginInstance *plugin)
{
npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), 0);
int error = rpc_method_invoke(g_rpc_connection,
RPC_METHOD_NPN_CREATE_OBJECT,
RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin,
RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NPN_CreateObject() invoke", error);
return 0;
}
uint32_t npobj_id = 0;
error = rpc_method_wait_for_reply(g_rpc_connection,
RPC_TYPE_UINT32, &npobj_id,
RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NPN_CreateObject() wait for reply", error);
return 0;
}
return npobj_id;
}
static NPObject *
g_NPN_CreateObject(NPP instance, NPClass *class)
{
@ -2041,54 +2012,24 @@ g_NPN_CreateObject(NPP instance, NPClass *class)
return NULL;
}
if (instance == NULL)
return NULL;
PluginInstance *plugin = PLUGIN_INSTANCE(instance);
if (plugin == NULL)
return NULL;
if (class == NULL)
return NULL;
D(bugiI("NPN_CreateObject\n"));
npw_plugin_instance_ref(plugin);
uint32_t npobj_id = invoke_NPN_CreateObject(plugin);
npw_plugin_instance_unref(plugin);
assert(npobj_id != 0);
NPObject *npobj = npobject_new(npobj_id, instance, class);
D(bugiD("NPN_CreateObject return: %p (refcount: %d)\n", npobj, npobj->referenceCount));
NPObject *npobj;
if (class->allocate)
npobj = class->allocate(instance, class);
else
npobj = malloc(sizeof(*npobj));
if (npobj) {
npobj->_class = class;
npobj->referenceCount = 1;
}
D(bugiD("NPN_CreateObject return: %p\n", npobj));
return npobj;
}
// Increments the reference count of the given NPObject
static uint32_t
invoke_NPN_RetainObject(NPObject *npobj)
{
npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection),
npobj->referenceCount);
int error = rpc_method_invoke(g_rpc_connection,
RPC_METHOD_NPN_RETAIN_OBJECT,
RPC_TYPE_NP_OBJECT, npobj,
RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NPN_RetainObject() invoke", error);
return npobj->referenceCount;
}
uint32_t refcount;
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &refcount, RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NPN_RetainObject() wait for reply", error);
return npobj->referenceCount;
}
return refcount;
}
static NPObject *
g_NPN_RetainObject(NPObject *npobj)
{
@ -2101,49 +2042,27 @@ g_NPN_RetainObject(NPObject *npobj)
return NULL;
D(bugiI("NPN_RetainObject npobj=%p\n", npobj));
uint32_t refcount = invoke_NPN_RetainObject(npobj);
D(bugiD("NPN_RetainObject return: %p (refcount: %d)\n", npobj, refcount));
npobj->referenceCount = refcount;
npobj->referenceCount++;
D(bugiD("NPN_RetainObject return: %p (refcount: %d)\n", npobj,
npobj->referenceCount));
return npobj;
}
// Decrements the reference count of the give NPObject
static uint32_t
invoke_NPN_ReleaseObject(NPObject *npobj)
{
npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection),
npobj->referenceCount);
int error = rpc_method_invoke(g_rpc_connection,
RPC_METHOD_NPN_RELEASE_OBJECT,
RPC_TYPE_NP_OBJECT, npobj,
RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NPN_ReleaseObject() invoke", error);
return npobj->referenceCount;
}
uint32_t refcount;
error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &refcount, RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NPN_ReleaseObject() wait for reply", error);
return npobj->referenceCount;
}
return refcount;
}
static void
g_NPN_ReleaseObject_Now(NPObject *npobj)
{
D(bugiI("NPN_ReleaseObject npobj=%p\n", npobj));
uint32_t refcount = invoke_NPN_ReleaseObject(npobj);
npobj->referenceCount--;
uint32_t refcount = npobj->referenceCount;
if (npobj->referenceCount == 0) {
if (npobj) {
if (npobj->_class && npobj->_class->deallocate)
npobj->_class->deallocate(npobj);
else
free(npobj);
}
}
D(bugiD("NPN_ReleaseObject done (refcount: %d)\n", refcount));
if ((npobj->referenceCount = refcount) == 0)
npobject_destroy(npobj);
}
static void

View File

@ -1126,34 +1126,6 @@ g_NPN_CreateObject(NPP instance, NPClass *klass)
return npobj;
}
static int handle_NPN_CreateObject(rpc_connection_t *connection)
{
D(bug("handle_NPN_CreateObject\n"));
PluginInstance *plugin;
int error = rpc_method_get_args(connection,
RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin,
RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NPN_CreateObject() get args", error);
return error;
}
NPObject *npobj = g_NPN_CreateObject(PLUGIN_INSTANCE_NPP(plugin), &npclass_bridge);
uint32_t npobj_id = 0;
if (npobj) {
NPObjectInfo *npobj_info = npobject_info_new(npobj);
if (npobj_info) {
npobj_id = npobj_info->npobj_id;
npobject_associate(npobj, npobj_info);
}
}
return rpc_method_send_reply(connection, RPC_TYPE_UINT32, npobj_id, RPC_TYPE_INVALID);
}
// NPN_RetainObject
static NPObject *
g_NPN_RetainObject(NPObject *npobj)
@ -1164,31 +1136,6 @@ g_NPN_RetainObject(NPObject *npobj)
return new_npobj;
}
static int handle_NPN_RetainObject(rpc_connection_t *connection)
{
D(bug("handle_NPN_RetainObject\n"));
NPObject *npobj;
int error = rpc_method_get_args(connection,
RPC_TYPE_NP_OBJECT, &npobj,
RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NPN_RetainObject() get args", error);
return error;
}
if (npobj == NULL) // this shall not happen, let it crash
npw_printf("ERROR: NPN_RetainObject got a null NPObject\n");
NPObject *new_npobj = g_NPN_RetainObject(npobj);
if (new_npobj != npobj)
npw_printf("WARNING: NPN_RetainObject() did not return the same object\n");
return rpc_method_send_reply(connection, RPC_TYPE_UINT32, npobj->referenceCount, RPC_TYPE_INVALID);
}
// NPN_ReleaseObject
static void
g_NPN_ReleaseObject(NPObject *npobj)
@ -1199,34 +1146,6 @@ g_NPN_ReleaseObject(NPObject *npobj)
D(bugiD("NPN_ReleaseObject done (refcount: %d)\n", refcount));
}
static int handle_NPN_ReleaseObject(rpc_connection_t *connection)
{
D(bug("handle_NPN_ReleaseObject\n"));
NPObject *npobj;
int error = rpc_method_get_args(connection,
RPC_TYPE_NP_OBJECT, &npobj,
RPC_TYPE_INVALID);
if (error != RPC_ERROR_NO_ERROR) {
npw_perror("NPN_ReleaseObject() get args", error);
return error;
}
if (npobj == NULL) // this shall not happen, let it crash
npw_printf("ERROR: NPN_ReleaseObject got a null NPObject\n");
/* Decrement reference count here so that we don't depend on a
* (possibly) deallocated NPObject afterwards, when we send the
* value in the RPC reply
*/
uint32_t refcount = npobj->referenceCount - 1;
g_NPN_ReleaseObject(npobj);
return rpc_method_send_reply(connection, RPC_TYPE_UINT32, refcount, RPC_TYPE_INVALID);
}
// NPN_Invoke
static bool
g_NPN_Invoke(NPP instance, NPObject *npobj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result)
@ -3889,9 +3808,6 @@ static void plugin_init(int is_NP_Initialize)
{ RPC_METHOD_NPN_GET_VALUE_FOR_URL, handle_NPN_GetValueForURL },
{ RPC_METHOD_NPN_SET_VALUE_FOR_URL, handle_NPN_SetValueForURL },
{ RPC_METHOD_NPN_GET_AUTHENTICATION_INFO, handle_NPN_GetAuthenticationInfo },
{ RPC_METHOD_NPN_CREATE_OBJECT, handle_NPN_CreateObject },
{ RPC_METHOD_NPN_RETAIN_OBJECT, handle_NPN_RetainObject },
{ RPC_METHOD_NPN_RELEASE_OBJECT, handle_NPN_ReleaseObject },
{ RPC_METHOD_NPN_INVOKE, handle_NPN_Invoke },
{ RPC_METHOD_NPN_INVOKE_DEFAULT, handle_NPN_InvokeDefault },
{ RPC_METHOD_NPN_EVALUATE, handle_NPN_Evaluate },

View File

@ -482,11 +482,16 @@ void rpc_connection_unref(rpc_connection_t *connection)
}
// Returns whether we are in sync mode or not (i.e. needs other end sync)
static inline bool _rpc_connection_is_sync_mode(rpc_connection_t *connection)
inline bool rpc_is_server(rpc_connection_t *connection)
{
return connection->type == RPC_CONNECTION_SERVER;
}
static inline bool _rpc_connection_is_sync_mode(rpc_connection_t *connection)
{
return rpc_is_server(connection);
}
// Returns whether we are allowed to synchronize with the other end
static inline bool _rpc_connection_is_sync_allowed(rpc_connection_t *connection)
{

View File

@ -54,6 +54,7 @@ extern void rpc_connection_unref(rpc_connection_t *connection) attribute_hidden;
extern rpc_connection_t *rpc_init_server(const char *ident) attribute_hidden;
extern rpc_connection_t *rpc_init_client(const char *ident) attribute_hidden;
extern bool rpc_is_server(rpc_connection_t *connection) attribute_hidden;
extern int rpc_exit(rpc_connection_t *connection) attribute_hidden;
extern int rpc_listen_socket(rpc_connection_t *connection) attribute_hidden;
extern int rpc_listen(rpc_connection_t *connection) attribute_hidden;