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:
parent
60638fff52
commit
bd167dc2d3
|
@ -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;
|
||||
|
|
364
src/npruntime.c
364
src/npruntime.c
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
129
src/npw-viewer.c
129
src/npw-viewer.c
|
@ -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
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue