From 6cb51fd4535ad20fff9b338921edc6212309f960 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 16 Apr 2011 13:20:39 -0400 Subject: [PATCH 01/91] Add strings for NPP_ClearSiteData error codes --- src/utils.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils.c b/src/utils.c index 957a66e..52b6f71 100644 --- a/src/utils.c +++ b/src/utils.c @@ -131,6 +131,8 @@ const char *string_of_NPError(int error) _(NPERR_FILE_NOT_FOUND); _(NPERR_NO_DATA); _(NPERR_STREAM_NOT_SEEKABLE); + _(NPERR_TIME_RANGE_NOT_SUPPORTED); + _(NPERR_MALFORMED_SITE); #undef _ default: str = ""; From 00534b2b7cd3992745269aca71858f55544d0008 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 19 Apr 2011 12:31:08 -0400 Subject: [PATCH 02/91] Pull in NPAPI SDK changes for DOM cursor control Also update our code to support this variable and the change in capitalization of NPPVsupportsAdvancedKeyHandling. No NPAPI version bump or additional hooks are required to support DOM cursor control. --- npapi/npapi.h | 4 +++- src/npw-rpc.c | 3 ++- src/utils.c | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/npapi/npapi.h b/npapi/npapi.h index 108460d..082feec 100644 --- a/npapi/npapi.h +++ b/npapi/npapi.h @@ -366,7 +366,9 @@ typedef enum { /* Checks to see if the plug-in would like the browser to load the "src" attribute. */ NPPVpluginCancelSrcStream = 20, - NPPVSupportsAdvancedKeyHandling = 21 + NPPVsupportsAdvancedKeyHandling = 21, + + NPPVpluginUsesDOMForCursorBool = 22 #if defined(XP_MACOSX) /* Used for negotiating drawing models */ diff --git a/src/npw-rpc.c b/src/npw-rpc.c index ecb99a4..e304b81 100644 --- a/src/npw-rpc.c +++ b/src/npw-rpc.c @@ -82,7 +82,8 @@ int rpc_type_of_NPPVariable(int variable) case NPPVpluginUrlRequestsDisplayedBool: case NPPVpluginWantsAllNetworkStreams: case NPPVpluginCancelSrcStream: - case NPPVSupportsAdvancedKeyHandling: + case NPPVsupportsAdvancedKeyHandling: + case NPPVpluginUsesDOMForCursorBool: type = RPC_TYPE_BOOLEAN; break; case NPPVpluginScriptableNPObject: diff --git a/src/utils.c b/src/utils.c index 52b6f71..80b110d 100644 --- a/src/utils.c +++ b/src/utils.c @@ -253,7 +253,8 @@ const char *string_of_NPPVariable(int variable) _(NPPVpluginWantsAllNetworkStreams); _(NPPVpluginNativeAccessibleAtkPlugId); _(NPPVpluginCancelSrcStream); - _(NPPVSupportsAdvancedKeyHandling); + _(NPPVsupportsAdvancedKeyHandling); + _(NPPVpluginUsesDOMForCursorBool); #undef _ default: switch (variable & 0xff) { From f9f3c1d0936d3f1549a2ef093a26ed35a1b12910 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 19 Apr 2011 13:54:51 -0400 Subject: [PATCH 03/91] Document the delayed call mess Now that I've finally figured out what it's for, make a comment. Also, EWWWWW! --- src/npw-viewer.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/npw-viewer.c b/src/npw-viewer.c index a0f991c..45b36fe 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -2168,6 +2168,16 @@ g_NPN_ReleaseObject(NPObject *npobj) g_NPN_ReleaseObject_Now(npobj); } else { + /* NPVariants that get tunneled over RPC get released locally. To + * counter this, they get retained when sent over RPC. However, + * the corresponding local ReleaseObject means that we are likely + * to call NPN_ReleaseObject when handle_depth != + * dispatch_depth. To that end, delay the release object. + * + * XXX: This is awful. It really should be revised, possibly by + * not using the browser-provided NPN_ReleaseVariantValue if NPAPI + * allows it. Or we make a copy of it, send that over instead and + * NPN_ReleaseVariantValue /before/ making the call. */ D(bug("NPN_ReleaseObject \n")); g_NPN_ReleaseObject_Delayed(npobj); } From 3a9056b07dde54e2b44de2f10b83a63f7ab2c7a2 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 19 Apr 2011 21:23:48 -0400 Subject: [PATCH 04/91] Release argument NPVariants before sending result Now the only releases that need be delayed are results. --- src/npruntime.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/npruntime.c b/src/npruntime.c index b48df67..07e312b 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -268,17 +268,17 @@ int npclass_handle_Invoke(rpc_connection_t *connection) g_free(result_str); } - int rpc_ret = rpc_method_send_reply(connection, - RPC_TYPE_UINT32, ret, - RPC_TYPE_NP_VARIANT, &result, - RPC_TYPE_INVALID); - if (args) { for (int i = 0; i < argCount; i++) NPN_ReleaseVariantValue(&args[i]); free(args); } + int rpc_ret = rpc_method_send_reply(connection, + RPC_TYPE_UINT32, ret, + RPC_TYPE_NP_VARIANT, &result, + RPC_TYPE_INVALID); + NPN_ReleaseVariantValue(&result); return rpc_ret; } @@ -368,17 +368,17 @@ int npclass_handle_InvokeDefault(rpc_connection_t *connection) g_free(result_str); } - int rpc_ret = rpc_method_send_reply(connection, - RPC_TYPE_UINT32, ret, - RPC_TYPE_NP_VARIANT, &result, - RPC_TYPE_INVALID); - if (args) { for (int i = 0; i < argCount; i++) NPN_ReleaseVariantValue(&args[i]); free(args); } + int rpc_ret = rpc_method_send_reply(connection, + RPC_TYPE_UINT32, ret, + RPC_TYPE_NP_VARIANT, &result, + RPC_TYPE_INVALID); + NPN_ReleaseVariantValue(&result); return rpc_ret; } @@ -867,17 +867,17 @@ int npclass_handle_Construct(rpc_connection_t *connection) g_free(result_str); } - int rpc_ret = rpc_method_send_reply(connection, - RPC_TYPE_UINT32, ret, - RPC_TYPE_NP_VARIANT, &result, - RPC_TYPE_INVALID); - if (args) { for (int i = 0; i < argCount; i++) NPN_ReleaseVariantValue(&args[i]); free(args); } + int rpc_ret = rpc_method_send_reply(connection, + RPC_TYPE_UINT32, ret, + RPC_TYPE_NP_VARIANT, &result, + RPC_TYPE_INVALID); + NPN_ReleaseVariantValue(&result); return rpc_ret; } From 2c301b1cfa39bac93e919cb80246822c273c0a28 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 19 Apr 2011 22:24:49 -0400 Subject: [PATCH 05/91] Move NPClass::* method descriptor registration into a helper function Let's cut down drastically on the interface of npruntime-impl.h. --- src/npruntime-impl.h | 12 +----------- src/npruntime.c | 18 ++++++++++++++++++ src/npw-viewer.c | 14 ++++---------- src/npw-wrapper.c | 14 ++++---------- 4 files changed, 27 insertions(+), 31 deletions(-) diff --git a/src/npruntime-impl.h b/src/npruntime-impl.h index 280535c..d8ef8cd 100644 --- a/src/npruntime-impl.h +++ b/src/npruntime-impl.h @@ -43,17 +43,7 @@ extern void npobject_bridge_destroy(void) attribute_hidden; extern NPClass npclass_bridge attribute_hidden; -extern int npclass_handle_Invalidate(rpc_connection_t *connection) attribute_hidden; -extern int npclass_handle_HasMethod(rpc_connection_t *connection) attribute_hidden; -extern int npclass_handle_Invoke(rpc_connection_t *connection) attribute_hidden; -extern int npclass_handle_InvokeDefault(rpc_connection_t *connection) attribute_hidden; -extern int npclass_handle_HasProperty(rpc_connection_t *connection) attribute_hidden; -extern int npclass_handle_GetProperty(rpc_connection_t *connection) attribute_hidden; -extern int npclass_handle_SetProperty(rpc_connection_t *connection) attribute_hidden; -extern int npclass_handle_RemoveProperty(rpc_connection_t *connection) attribute_hidden; -extern int npclass_handle_Invalidate(rpc_connection_t *connection) attribute_hidden; -extern int npclass_handle_Enumerate(rpc_connection_t *connection) attribute_hidden; -extern int npclass_handle_Construct(rpc_connection_t *connection) attribute_hidden; +extern int npclass_add_method_descriptors(rpc_connection_t *connection) attribute_hidden; struct _NPVariant; extern void npvariant_clear(struct _NPVariant *variant) attribute_hidden; diff --git a/src/npruntime.c b/src/npruntime.c index 07e312b..ffd2793 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -936,6 +936,24 @@ bool g_NPClass_Construct(NPObject *npobj, const NPVariant *args, uint32_t argCou return ret; } +int npclass_add_method_descriptors(rpc_connection_t *connection) +{ + static const rpc_method_descriptor_t vtable[] = { + { RPC_METHOD_NPCLASS_INVALIDATE, npclass_handle_Invalidate }, + { RPC_METHOD_NPCLASS_HAS_METHOD, npclass_handle_HasMethod }, + { RPC_METHOD_NPCLASS_INVOKE, npclass_handle_Invoke }, + { RPC_METHOD_NPCLASS_INVOKE_DEFAULT, npclass_handle_InvokeDefault }, + { RPC_METHOD_NPCLASS_HAS_PROPERTY, npclass_handle_HasProperty }, + { RPC_METHOD_NPCLASS_GET_PROPERTY, npclass_handle_GetProperty }, + { RPC_METHOD_NPCLASS_SET_PROPERTY, npclass_handle_SetProperty }, + { RPC_METHOD_NPCLASS_REMOVE_PROPERTY, npclass_handle_RemoveProperty }, + { RPC_METHOD_NPCLASS_ENUMERATE, npclass_handle_Enumerate }, + { RPC_METHOD_NPCLASS_CONSTRUCT, npclass_handle_Construct }, + }; + return rpc_connection_add_method_descriptors(g_rpc_connection, + vtable, sizeof(vtable)); +} + /* ====================================================================== */ /* === NPObjectInfo === */ diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 45b36fe..1e8aa70 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -4969,21 +4969,15 @@ static int do_main(int argc, char **argv, const char *connection_path) { RPC_METHOD_NPP_STREAM_AS_FILE, handle_NPP_StreamAsFile }, { RPC_METHOD_NPP_PRINT, handle_NPP_Print }, { RPC_METHOD_NPP_HANDLE_EVENT, handle_NPP_HandleEvent }, - { RPC_METHOD_NPCLASS_INVALIDATE, npclass_handle_Invalidate }, - { RPC_METHOD_NPCLASS_HAS_METHOD, npclass_handle_HasMethod }, - { RPC_METHOD_NPCLASS_INVOKE, npclass_handle_Invoke }, - { RPC_METHOD_NPCLASS_INVOKE_DEFAULT, npclass_handle_InvokeDefault }, - { RPC_METHOD_NPCLASS_HAS_PROPERTY, npclass_handle_HasProperty }, - { RPC_METHOD_NPCLASS_GET_PROPERTY, npclass_handle_GetProperty }, - { RPC_METHOD_NPCLASS_SET_PROPERTY, npclass_handle_SetProperty }, - { RPC_METHOD_NPCLASS_REMOVE_PROPERTY, npclass_handle_RemoveProperty }, - { RPC_METHOD_NPCLASS_ENUMERATE, npclass_handle_Enumerate }, - { RPC_METHOD_NPCLASS_CONSTRUCT, npclass_handle_Construct }, }; if (rpc_connection_add_method_descriptors(g_rpc_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) { npw_printf("ERROR: failed to setup NPP method callbacks\n"); return 1; } + if (npclass_add_method_descriptors(g_rpc_connection) < 0) { + npw_printf("ERROR: failed to setup NPClass method callbacks\n"); + return 1; + } id_init(); diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index 5bbcbeb..4e41cce 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -3909,21 +3909,15 @@ static void plugin_init(int is_NP_Initialize) { RPC_METHOD_NPN_IDENTIFIER_IS_STRING, handle_NPN_IdentifierIsString }, { RPC_METHOD_NPN_UTF8_FROM_IDENTIFIER, handle_NPN_UTF8FromIdentifier }, { RPC_METHOD_NPN_INT_FROM_IDENTIFIER, handle_NPN_IntFromIdentifier }, - { RPC_METHOD_NPCLASS_INVALIDATE, npclass_handle_Invalidate }, - { RPC_METHOD_NPCLASS_HAS_METHOD, npclass_handle_HasMethod }, - { RPC_METHOD_NPCLASS_INVOKE, npclass_handle_Invoke }, - { RPC_METHOD_NPCLASS_INVOKE_DEFAULT, npclass_handle_InvokeDefault }, - { RPC_METHOD_NPCLASS_HAS_PROPERTY, npclass_handle_HasProperty }, - { RPC_METHOD_NPCLASS_GET_PROPERTY, npclass_handle_GetProperty }, - { RPC_METHOD_NPCLASS_SET_PROPERTY, npclass_handle_SetProperty }, - { RPC_METHOD_NPCLASS_REMOVE_PROPERTY, npclass_handle_RemoveProperty }, - { RPC_METHOD_NPCLASS_ENUMERATE, npclass_handle_Enumerate }, - { RPC_METHOD_NPCLASS_CONSTRUCT, npclass_handle_Construct }, }; if (rpc_connection_add_method_descriptors(g_rpc_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) { npw_printf("ERROR: failed to setup NPN method callbacks\n"); return; } + if (npclass_add_method_descriptors(g_rpc_connection) < 0) { + npw_printf("ERROR: failed to setup NPClass method callbacks\n"); + return; + } // Retrieve toolkit information if (mozilla_funcs.getvalue == NULL) From f8c295a4807a1b06a8e93e35081c8d62c90f4aba Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 19 Apr 2011 22:26:52 -0400 Subject: [PATCH 06/91] Don't export npobject_info_destroy No one outside npruntime.c calls it. --- src/npruntime-impl.h | 1 - src/npruntime.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/npruntime-impl.h b/src/npruntime-impl.h index d8ef8cd..8d4a6fe 100644 --- a/src/npruntime-impl.h +++ b/src/npruntime-impl.h @@ -30,7 +30,6 @@ typedef struct { } NPObjectInfo; extern NPObjectInfo *npobject_info_new(NPObject *npobj) attribute_hidden; -extern void npobject_info_destroy(NPObjectInfo *npobj_info) 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; diff --git a/src/npruntime.c b/src/npruntime.c index ffd2793..3fe53cd 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -972,7 +972,7 @@ NPObjectInfo *npobject_info_new(NPObject *npobj) return npobj_info; } -void npobject_info_destroy(NPObjectInfo *npobj_info) +static void npobject_info_destroy(NPObjectInfo *npobj_info) { if (npobj_info == NULL) return; From 60638fff5221b5d2c7f44c8b9297de2c407cb9d5 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 01:27:08 -0400 Subject: [PATCH 07/91] Fix a typo --- src/npruntime.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/npruntime.c b/src/npruntime.c index 3fe53cd..8979d39 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -950,8 +950,8 @@ int npclass_add_method_descriptors(rpc_connection_t *connection) { RPC_METHOD_NPCLASS_ENUMERATE, npclass_handle_Enumerate }, { RPC_METHOD_NPCLASS_CONSTRUCT, npclass_handle_Construct }, }; - return rpc_connection_add_method_descriptors(g_rpc_connection, - vtable, sizeof(vtable)); + return rpc_connection_add_method_descriptors(g_rpc_connection, vtable, + sizeof(vtable) / sizeof(vtable[0])); } From bd167dc2d33e8cbaeb45ba05f7e2a4bc73f6d194 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 01:27:18 -0400 Subject: [PATCH 08/91] 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. --- src/npruntime-impl.h | 32 ++-- src/npruntime.c | 364 +++++++++++++++++++++++++------------------ src/npw-common.c | 6 + src/npw-rpc.c | 70 +++------ src/npw-rpc.h | 3 +- src/npw-viewer.c | 127 +++------------ src/npw-wrapper.c | 84 ---------- src/rpc.c | 7 +- src/rpc.h | 1 + 9 files changed, 281 insertions(+), 413 deletions(-) diff --git a/src/npruntime-impl.h b/src/npruntime-impl.h index 8d4a6fe..9d40528 100644 --- a/src/npruntime-impl.h +++ b/src/npruntime-impl.h @@ -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; diff --git a/src/npruntime.c b/src/npruntime.c index 8979d39..0c4079d 100644 --- a/src/npruntime.c +++ b/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) -{ - g_hash_table_insert(g_npobjects, npobj, npobj_info); - g_hash_table_insert(g_npobject_ids, (void *)(uintptr_t)npobj_info->npobj_id, npobj); -} - -bool npobject_hash_table_remove(NPObject *npobj) -{ - 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) +static void proxy_deactivate_func(gpointer key, gpointer value, gpointer user_data) { - return g_hash_table_lookup(g_npobject_ids, (void *)(uintptr_t)npobj_id); + NPObjectProxy *proxy = (NPObjectProxy *)value; + proxy->is_valid = false; } -static void npruntime_deactivate_func(gpointer key, gpointer value, gpointer user_data) +static void stub_destroy_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(); } diff --git a/src/npw-common.c b/src/npw-common.c index e8596df..429bfbf 100644 --- a/src/npw-common.c +++ b/src/npw-common.c @@ -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) { diff --git a/src/npw-rpc.c b/src/npw-rpc.c index e304b81..2864daf 100644 --- a/src/npw-rpc.c +++ b/src/npw-rpc.c @@ -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; } diff --git a/src/npw-rpc.h b/src/npw-rpc.h index 5a92f24..9d214e3 100644 --- a/src/npw-rpc.h +++ b/src/npw-rpc.h @@ -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 diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 1e8aa70..ff66cd3 100644 --- a/src/npw-viewer.c +++ b/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,52 +2012,22 @@ 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)); - 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; + NPObject *npobj; + if (class->allocate) + npobj = class->allocate(instance, class); + else + npobj = malloc(sizeof(*npobj)); + if (npobj) { + npobj->_class = class; + npobj->referenceCount = 1; } - - return refcount; + D(bugiD("NPN_CreateObject return: %p\n", npobj)); + return npobj; } static NPObject * @@ -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 diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index 4e41cce..61b31aa 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -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 }, diff --git a/src/rpc.c b/src/rpc.c index deb9a69..a8da2fd 100644 --- a/src/rpc.c +++ b/src/rpc.c @@ -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) { diff --git a/src/rpc.h b/src/rpc.h index 0d315a0..ae1cac5 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -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; From 94593ff6608dbafbe726d20adf4310ff686cadc9 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 02:05:18 -0400 Subject: [PATCH 09/91] Handle NPObject lifetime better All received NPObjects must be released, either directly or by releasing the NPVariant. Verified that visiting and leaving pages on YouTube and Hulu do not leak stubs and proxies. --- src/npw-rpc.c | 7 ++++--- src/npw-viewer.c | 6 +++++- src/npw-wrapper.c | 32 +++++++++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/npw-rpc.c b/src/npw-rpc.c index 2864daf..6e9ee46 100644 --- a/src/npw-rpc.c +++ b/src/npw-rpc.c @@ -1218,8 +1218,10 @@ static int do_recv_NPObject(rpc_message_t *message, void *p_value) // for it. npobj = npobject_create_proxy(npobj_id); } else { - // This is an object on our side. Just use it. + // This is an object on our side. Retain it; receiver must + // release all received NPObjects. D(bug("local\n")); + NPN_RetainObject(npobj); } D(bug("recv id 0x%x, obj %p\n", npobj_id, npobj)); assert(npobj != NULL); @@ -1451,8 +1453,7 @@ 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; - /* The NPVariant now owns a reference to this object. */ - NPN_RetainObject(result.value.objectValue); + // NPVariant owns reference from do_recv_NPObject. break; } diff --git a/src/npw-viewer.c b/src/npw-viewer.c index ff66cd3..0c98915 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -1173,6 +1173,7 @@ invoke_NPN_GetValue(PluginInstance *plugin, NPNVariable variable, void *value) } D(bug("-> value: \n", npobj)); *((NPObject **)value) = npobj; + // Caller releases NPObject reference. break; } } @@ -4080,7 +4081,10 @@ static int handle_NPP_GetValue(rpc_connection_t *connection) { NPObject *npobj = NULL; ret = g_NPP_GetValue(PLUGIN_INSTANCE_NPP(plugin), variable, (void *)&npobj); - return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_INVALID); + int err = rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_INVALID); + if (npobj) + NPN_ReleaseObject(npobj); + return err; } } diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index 61b31aa..8cfd030 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -524,7 +524,9 @@ static int handle_NPN_GetValue(rpc_connection_t *connection) NPObject *npobj = NULL; if (valid_instance) ret = g_NPN_GetValue(PLUGIN_INSTANCE_NPP(plugin), variable, (void *)&npobj); - return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_INVALID); + int err = rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_INVALID); + NPN_ReleaseObject(npobj); + return err; } } @@ -1184,6 +1186,8 @@ static int handle_NPN_Invoke(rpc_connection_t *connection) VOID_TO_NPVARIANT(result); bool ret = g_NPN_Invoke(PLUGIN_INSTANCE_NPP(plugin), npobj, methodName, args, argCount, &result); + if (npobj) + NPN_ReleaseObject(npobj); if (args) { for (int i = 0; i < argCount; i++) NPN_ReleaseVariantValue(&args[i]); @@ -1235,6 +1239,8 @@ static int handle_NPN_InvokeDefault(rpc_connection_t *connection) VOID_TO_NPVARIANT(result); bool ret = g_NPN_InvokeDefault(PLUGIN_INSTANCE_NPP(plugin), npobj, args, argCount, &result); + if (npobj) + NPN_ReleaseObject(npobj); if (args) { for (int i = 0; i < argCount; i++) NPN_ReleaseVariantValue(&args[i]); @@ -1287,6 +1293,8 @@ static int handle_NPN_Evaluate(rpc_connection_t *connection) VOID_TO_NPVARIANT(result); bool ret = g_NPN_Evaluate(PLUGIN_INSTANCE_NPP(plugin), npobj, &script, &result); + if (npobj) + NPN_ReleaseObject(npobj); if (script.UTF8Characters) NPN_MemFree((void *)script.UTF8Characters); @@ -1333,6 +1341,9 @@ static int handle_NPN_GetProperty(rpc_connection_t *connection) VOID_TO_NPVARIANT(result); bool ret = g_NPN_GetProperty(PLUGIN_INSTANCE_NPP(plugin), npobj, propertyName, &result); + if (npobj) + NPN_ReleaseObject(npobj); + int rpc_ret = rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, RPC_TYPE_NP_VARIANT, &result, @@ -1374,6 +1385,8 @@ static int handle_NPN_SetProperty(rpc_connection_t *connection) bool ret = g_NPN_SetProperty(PLUGIN_INSTANCE_NPP(plugin), npobj, propertyName, &value); + if (npobj) + NPN_ReleaseObject(npobj); NPN_ReleaseVariantValue(&value); return rpc_method_send_reply(connection, @@ -1411,6 +1424,9 @@ static int handle_NPN_RemoveProperty(rpc_connection_t *connection) bool ret = g_NPN_RemoveProperty(PLUGIN_INSTANCE_NPP(plugin), npobj, propertyName); + if (npobj) + NPN_ReleaseObject(npobj); + return rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, RPC_TYPE_INVALID); @@ -1446,6 +1462,9 @@ static int handle_NPN_HasProperty(rpc_connection_t *connection) bool ret = g_NPN_HasProperty(PLUGIN_INSTANCE_NPP(plugin), npobj, propertyName); + if (npobj) + NPN_ReleaseObject(npobj); + return rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, RPC_TYPE_INVALID); @@ -1481,6 +1500,9 @@ static int handle_NPN_HasMethod(rpc_connection_t *connection) bool ret = g_NPN_HasMethod(PLUGIN_INSTANCE_NPP(plugin), npobj, methodName); + if (npobj) + NPN_ReleaseObject(npobj); + return rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, RPC_TYPE_INVALID); @@ -1520,6 +1542,9 @@ static int handle_NPN_Enumerate(rpc_connection_t *connection) uint32_t count = 0; bool ret = g_NPN_Enumerate(PLUGIN_INSTANCE_NPP(plugin), npobj, &identifiers, &count); + if (npobj) + NPN_ReleaseObject(npobj); + error = rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, RPC_TYPE_ARRAY, RPC_TYPE_NP_IDENTIFIER, count, identifiers, @@ -1567,6 +1592,8 @@ static int handle_NPN_Construct(rpc_connection_t *connection) VOID_TO_NPVARIANT(result); bool ret = g_NPN_Construct(PLUGIN_INSTANCE_NPP(plugin), npobj, args, argCount, &result); + if (npobj) + NPN_ReleaseObject(npobj); if (args) { for (int i = 0; i < argCount; i++) NPN_ReleaseVariantValue(&args[i]); @@ -1609,6 +1636,8 @@ static int handle_NPN_SetException(rpc_connection_t *connection) g_NPN_SetException(npobj, message); + if (npobj) + NPN_ReleaseObject(npobj); // XXX memory leak (message) return rpc_method_send_reply (connection, RPC_TYPE_INVALID); @@ -2330,6 +2359,7 @@ invoke_NPP_GetValue(PluginInstance *plugin, NPPVariable variable, void *value) } D(bug("-> value: \n", npobj)); *((NPObject **)value) = npobj; + // Caller is responsible for releasing reference. break; } } From 3791e265ab8287af72e221f1efb4c1a8181b7249 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 11:13:23 -0400 Subject: [PATCH 10/91] Implement pass-ref semantics for NPObject and NPVariant This will allow us to get rid of delayed NPN_ReleaseObject. --- src/npruntime-impl.h | 2 + src/npruntime.c | 42 +++++++++++----- src/npw-rpc.c | 111 ++++++++++++++++++++++++++++++++++++++++--- src/npw-rpc.h | 2 + 4 files changed, 137 insertions(+), 20 deletions(-) diff --git a/src/npruntime-impl.h b/src/npruntime-impl.h index 9d40528..c25fdb8 100644 --- a/src/npruntime-impl.h +++ b/src/npruntime-impl.h @@ -33,6 +33,7 @@ extern int npclass_add_method_descriptors(rpc_connection_t *connection) attribut // 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 void npobject_destroy_stub(uint32_t id) attribute_hidden; extern NPObject *npobject_lookup_local(uint32_t id) attribute_hidden; // Create a proxy object. The received id must correspond to a live @@ -41,6 +42,7 @@ extern NPObject *npobject_lookup_local(uint32_t id) attribute_hidden; // its stub. extern NPObject *npobject_create_proxy(uint32_t id) attribute_hidden; extern uint32_t npobject_get_proxy_id(NPObject *npobj) attribute_hidden; +extern void npobject_destroy_proxy(NPObject *npobj, bool release_stub); struct _NPVariant; extern void npvariant_clear(struct _NPVariant *variant) attribute_hidden; diff --git a/src/npruntime.c b/src/npruntime.c index 0c4079d..dac7b8c 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -103,14 +103,21 @@ NPObject *npobject_lookup_local(uint32_t id) return stub ? stub->npobject : NULL; } -static void npobject_destroy_stub(NPObjectStub *stub) +static void npobject_destroy_stub_obj(NPObjectStub *stub) { - D(bug("npobject_stub: id=0x%x\n", stub->id)); + D(bug("npobject_destroy_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); } +void npobject_destroy_stub(uint32_t id) +{ + NPObjectStub *stub = npobject_lookup_stub(id); + assert(stub != NULL); + npobject_destroy_stub_obj(stub); +} + /* ====================================================================== */ /* === NPObject proxies === */ /* ====================================================================== */ @@ -154,6 +161,23 @@ uint32_t npobject_get_proxy_id(NPObject *npobj) return proxy->id; } +static void npclass_invoke_Deallocate(NPObjectProxy *proxy); + +void npobject_destroy_proxy(NPObject *npobj, bool release_stub) +{ + // Unregister the proxy. + D(bugiI("npobject_destroy_proxy: npobj=%p, release_stub=%d\n", + npobj, release_stub)); + NPObjectProxy *proxy = npobject_get_proxy(npobj); + assert(proxy != NULL); + if (release_stub && proxy->is_valid) { + npclass_invoke_Deallocate(proxy); + g_hash_table_remove(g_proxies, GINT_TO_POINTER(proxy->id)); + } + free(npobj); + D(bugiD("npobject_destroy_proxy done\n")); +} + static inline bool is_valid_npobject_proxy(NPObject *npobj) { if (npobj == NULL) @@ -228,7 +252,7 @@ int npclass_handle_Deallocate(rpc_connection_t *connection) D(bugiI("NPClass:Deallocate: id=0x%x\n", id)); NPObjectStub *stub = npobject_lookup_stub(id); if (stub != NULL) { - npobject_destroy_stub(stub); + npobject_destroy_stub_obj(stub); } D(bugiD("NPClass:Deallocate done\n")); @@ -260,15 +284,7 @@ static void npclass_invoke_Deallocate(NPObjectProxy *proxy) 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); + npobject_destroy_proxy(npobj, true); } // NPClass::Invalidate @@ -1155,7 +1171,7 @@ static void proxy_deactivate_func(gpointer key, gpointer value, gpointer user_da static void stub_destroy_func(gpointer key, gpointer value, gpointer user_data) { NPObjectStub *stub = (NPObjectStub *)value; - npobject_destroy_stub(stub); + npobject_destroy_stub_obj(stub); } void npruntime_deactivate(void) diff --git a/src/npw-rpc.c b/src/npw-rpc.c index 6e9ee46..b837bf0 100644 --- a/src/npw-rpc.c +++ b/src/npw-rpc.c @@ -1178,19 +1178,38 @@ static int do_recv_NPPrintData(rpc_message_t *message, void *p_value) * Process NPObject objects */ -static int do_send_NPObject(rpc_message_t *message, void *p_value) +static int do_send_NPObject_helper(rpc_message_t *message, void *p_value, + bool pass_ref) { uint32_t npobj_id = 0; NPObject *npobj = (NPObject *)p_value; + bool release_stub = false; if (npobj) { 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); + if (pass_ref) { + // Release our reference; the stub protects the object from + // deallocation. + NPN_ReleaseObject(npobj); + } } else { // This is a proxy for the object on the other side. Just pass // the id along. + if (pass_ref) { + // As above, we release out reference. If this is not the last + // reference, we may just do so. Otherwise, we destroy it, but + // do /not/ send the corresponding RPC. That gets merged into + // this one. + if (npobj->referenceCount == 1) { + npobject_destroy_proxy(npobj, false); + release_stub = true; + } else { + NPN_ReleaseObject(npobj); + } + } } D(bug("sending id 0x%x\n", npobj_id)); assert(npobj_id != 0); @@ -1198,17 +1217,28 @@ static int do_send_NPObject(rpc_message_t *message, void *p_value) int error = rpc_message_send_uint32(message, npobj_id); if (error < 0) return error; + // Tell the other side whether or not to destroy the stub. + if (pass_ref) { + if ((error = rpc_message_send_uint32(message, release_stub)) < 0) + return error; + } return RPC_ERROR_NO_ERROR; } -static int do_recv_NPObject(rpc_message_t *message, void *p_value) +static int do_recv_NPObject_helper(rpc_message_t *message, void *p_value, + bool pass_ref) { int error; uint32_t npobj_id; + uint32_t release_stub = 0; if ((error = rpc_message_recv_uint32(message, &npobj_id)) < 0) return error; + if (pass_ref) { + if ((error = rpc_message_recv_uint32(message, &release_stub)) < 0) + return error; + } NPObject *npobj = NULL; if (npobj_id) { @@ -1217,11 +1247,17 @@ static int do_recv_NPObject(rpc_message_t *message, void *p_value) // We got an id of a newly created remote stub. Create a proxy // for it. npobj = npobject_create_proxy(npobj_id); + if (release_stub) + npw_printf("ERROR: received release_stub for proxy NPObject.\n"); } else { // This is an object on our side. Retain it; receiver must // release all received NPObjects. D(bug("local\n")); NPN_RetainObject(npobj); + if (release_stub) { + // We just retained the object, so it won't be destroyed. + npobject_destroy_stub(npobj_id); + } } D(bug("recv id 0x%x, obj %p\n", npobj_id, npobj)); assert(npobj != NULL); @@ -1231,6 +1267,26 @@ static int do_recv_NPObject(rpc_message_t *message, void *p_value) return RPC_ERROR_NO_ERROR; } +static int do_send_NPObject(rpc_message_t *message, void *p_value) +{ + return do_send_NPObject_helper(message, p_value, false); +} + +static int do_recv_NPObject(rpc_message_t *message, void *p_value) +{ + return do_recv_NPObject_helper(message, p_value, false); +} + +static int do_send_NPObject_pass_ref(rpc_message_t *message, void *p_value) +{ + return do_send_NPObject_helper(message, p_value, true); +} + +static int do_recv_NPObject_pass_ref(rpc_message_t *message, void *p_value) +{ + return do_recv_NPObject_helper(message, p_value, true); +} + /* * Process NPIdentifier objects @@ -1371,7 +1427,8 @@ static int do_recv_NPString(rpc_message_t *message, void *p_value) * Process NPVariant objects */ -static int do_send_NPVariant(rpc_message_t *message, void *p_value) +static int do_send_NPVariant_helper(rpc_message_t *message, void *p_value, + bool pass_ref) { NPVariant *variant = (NPVariant *)p_value; if (variant == NULL) @@ -1403,15 +1460,23 @@ static int do_send_NPVariant(rpc_message_t *message, void *p_value) return error; break; case NPVariantType_Object: - if ((error = do_send_NPObject(message, variant->value.objectValue)) < 0) + if ((error = do_send_NPObject_helper(message, variant->value.objectValue, + pass_ref)) < 0) return error; break; } + // Clean up local data. If we had an NPObject, + // do_send_NPObject_pass_ref took care of it. + if (pass_ref && variant->type != NPVariantType_Object) { + NPN_ReleaseVariantValue(variant); + } + return RPC_ERROR_NO_ERROR; } -static int do_recv_NPVariant(rpc_message_t *message, void *p_value) +static int do_recv_NPVariant_helper(rpc_message_t *message, void *p_value, + bool pass_ref) { NPVariant *variant = (NPVariant *)p_value; if (variant) @@ -1451,9 +1516,10 @@ static int do_recv_NPVariant(rpc_message_t *message, void *p_value) return error; break; case NPVariantType_Object: - if ((error = do_recv_NPObject(message, &result.value.objectValue)) < 0) + if ((error = do_recv_NPObject_helper(message, &result.value.objectValue, + pass_ref)) < 0) return error; - // NPVariant owns reference from do_recv_NPObject. + // NPVariant owns reference from do_recv_NPObject_helper. break; } @@ -1465,6 +1531,25 @@ static int do_recv_NPVariant(rpc_message_t *message, void *p_value) return RPC_ERROR_NO_ERROR; } +static int do_send_NPVariant(rpc_message_t *message, void *p_value) +{ + return do_send_NPVariant_helper(message, p_value, false); +} + +static int do_recv_NPVariant(rpc_message_t *message, void *p_value) +{ + return do_recv_NPVariant_helper(message, p_value, false); +} + +static int do_send_NPVariant_pass_ref(rpc_message_t *message, void *p_value) +{ + return do_send_NPVariant_helper(message, p_value, true); +} + +static int do_recv_NPVariant_pass_ref(rpc_message_t *message, void *p_value) +{ + return do_recv_NPVariant_helper(message, p_value, true); +} /* * Initialize marshalers for NPAPI types @@ -1555,6 +1640,12 @@ static const rpc_message_descriptor_t message_descs[] = { do_send_NPObject, do_recv_NPObject }, + { + RPC_TYPE_NP_OBJECT_PASS_REF, + sizeof(NPObject *), + do_send_NPObject_pass_ref, + do_recv_NPObject_pass_ref + }, { RPC_TYPE_NP_IDENTIFIER, sizeof(NPIdentifier), @@ -1578,6 +1669,12 @@ static const rpc_message_descriptor_t message_descs[] = { sizeof(NPVariant), do_send_NPVariant, do_recv_NPVariant + }, + { + RPC_TYPE_NP_VARIANT_PASS_REF, + sizeof(NPVariant), + do_send_NPVariant_pass_ref, + do_recv_NPVariant_pass_ref } }; diff --git a/src/npw-rpc.h b/src/npw-rpc.h index 9d214e3..b968700 100644 --- a/src/npw-rpc.h +++ b/src/npw-rpc.h @@ -131,6 +131,8 @@ enum { RPC_TYPE_NP_STRING, /* 15 */ RPC_TYPE_NP_VARIANT, RPC_TYPE_NP_UTF8, + RPC_TYPE_NP_OBJECT_PASS_REF, + RPC_TYPE_NP_VARIANT_PASS_REF, RPC_TYPE_NPW_PLUGIN_INSTANCE }; From 3a76b975b719acaee4ccc15bada5d502a16e3cf4 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 11:22:35 -0400 Subject: [PATCH 11/91] Move an input NPN_ReleaseVariantValue before rpc_send_reply Missed one. --- src/npruntime.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/npruntime.c b/src/npruntime.c index dac7b8c..d76e871 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -805,12 +805,11 @@ int npclass_handle_SetProperty(rpc_connection_t *connection) D(bugiD("NPClass::SetProperty return: %d\n", ret)); } - int rpc_ret = rpc_method_send_reply(connection, - RPC_TYPE_UINT32, ret, - RPC_TYPE_INVALID); - NPN_ReleaseVariantValue(&value); - return rpc_ret; + + return rpc_method_send_reply(connection, + RPC_TYPE_UINT32, ret, + RPC_TYPE_INVALID); } static bool npclass_invoke_SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) From e471accc81547e7aad6ddfdf45351b4ea39a4cd4 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 11:46:15 -0400 Subject: [PATCH 12/91] Use the pass-ref variants in all return values Delayed calls should no longer be needed. --- src/npruntime.c | 52 ++++++++++++++---------------------- src/npw-viewer.c | 23 +++++++++------- src/npw-wrapper.c | 67 ++++++++++++++++++++--------------------------- 3 files changed, 61 insertions(+), 81 deletions(-) diff --git a/src/npruntime.c b/src/npruntime.c index d76e871..4e03b82 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -457,13 +457,10 @@ int npclass_handle_Invoke(rpc_connection_t *connection) free(args); } - int rpc_ret = rpc_method_send_reply(connection, - RPC_TYPE_UINT32, ret, - RPC_TYPE_NP_VARIANT, &result, - RPC_TYPE_INVALID); - - NPN_ReleaseVariantValue(&result); - return rpc_ret; + return rpc_method_send_reply(connection, + RPC_TYPE_UINT32, ret, + RPC_TYPE_NP_VARIANT_PASS_REF, &result, + RPC_TYPE_INVALID); } static bool npclass_invoke_Invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args, uint32_t argCount, @@ -486,7 +483,7 @@ static bool npclass_invoke_Invoke(NPObject *npobj, NPIdentifier name, const NPVa uint32_t ret; error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &ret, - RPC_TYPE_NP_VARIANT, result, + RPC_TYPE_NP_VARIANT_PASS_REF, result, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -557,13 +554,10 @@ int npclass_handle_InvokeDefault(rpc_connection_t *connection) free(args); } - int rpc_ret = rpc_method_send_reply(connection, - RPC_TYPE_UINT32, ret, - RPC_TYPE_NP_VARIANT, &result, - RPC_TYPE_INVALID); - - NPN_ReleaseVariantValue(&result); - return rpc_ret; + return rpc_method_send_reply(connection, + RPC_TYPE_UINT32, ret, + RPC_TYPE_NP_VARIANT_PASS_REF, &result, + RPC_TYPE_INVALID); } static bool npclass_invoke_InvokeDefault(NPObject *npobj, const NPVariant *args, uint32_t argCount, @@ -585,7 +579,7 @@ static bool npclass_invoke_InvokeDefault(NPObject *npobj, const NPVariant *args, uint32_t ret; error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &ret, - RPC_TYPE_NP_VARIANT, result, + RPC_TYPE_NP_VARIANT_PASS_REF, result, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -719,13 +713,10 @@ int npclass_handle_GetProperty(rpc_connection_t *connection) g_free(result_str); } - int rpc_ret = rpc_method_send_reply(connection, - RPC_TYPE_UINT32, ret, - RPC_TYPE_NP_VARIANT, &result, - RPC_TYPE_INVALID); - - NPN_ReleaseVariantValue(&result); - return rpc_ret; + return rpc_method_send_reply(connection, + RPC_TYPE_UINT32, ret, + RPC_TYPE_NP_VARIANT_PASS_REF, &result, + RPC_TYPE_INVALID); } static bool npclass_invoke_GetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result) @@ -746,7 +737,7 @@ static bool npclass_invoke_GetProperty(NPObject *npobj, NPIdentifier name, NPVar uint32_t ret; error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &ret, - RPC_TYPE_NP_VARIANT, result, + RPC_TYPE_NP_VARIANT_PASS_REF, result, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -1055,13 +1046,10 @@ int npclass_handle_Construct(rpc_connection_t *connection) free(args); } - int rpc_ret = rpc_method_send_reply(connection, - RPC_TYPE_UINT32, ret, - RPC_TYPE_NP_VARIANT, &result, - RPC_TYPE_INVALID); - - NPN_ReleaseVariantValue(&result); - return rpc_ret; + return rpc_method_send_reply(connection, + RPC_TYPE_UINT32, ret, + RPC_TYPE_NP_VARIANT_PASS_REF, &result, + RPC_TYPE_INVALID); } static bool npclass_invoke_Construct(NPObject *npobj, const NPVariant *args, uint32_t argCount, @@ -1083,7 +1071,7 @@ static bool npclass_invoke_Construct(NPObject *npobj, const NPVariant *args, uin uint32_t ret; error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &ret, - RPC_TYPE_NP_VARIANT, result, + RPC_TYPE_NP_VARIANT_PASS_REF, result, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 0c98915..636c47e 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -1166,7 +1166,10 @@ invoke_NPN_GetValue(PluginInstance *plugin, NPNVariable variable, void *value) case RPC_TYPE_NP_OBJECT: { NPObject *npobj = NULL; - error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_NP_OBJECT, &npobj, RPC_TYPE_INVALID); + error = rpc_method_wait_for_reply(g_rpc_connection, + RPC_TYPE_INT32, &ret, + RPC_TYPE_NP_OBJECT_PASS_REF, &npobj, + RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { npw_perror("NPN_GetValue() wait for reply", error); ret = NPERR_GENERIC_ERROR; @@ -2126,7 +2129,7 @@ invoke_NPN_Invoke(PluginInstance *plugin, NPObject *npobj, NPIdentifier methodNa uint32_t ret; error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &ret, - RPC_TYPE_NP_VARIANT, result, + RPC_TYPE_NP_VARIANT_PASS_REF, result, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -2189,7 +2192,7 @@ invoke_NPN_InvokeDefault(PluginInstance *plugin, NPObject *npobj, uint32_t ret; error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &ret, - RPC_TYPE_NP_VARIANT, result, + RPC_TYPE_NP_VARIANT_PASS_REF, result, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -2251,7 +2254,7 @@ invoke_NPN_Evaluate(PluginInstance *plugin, NPObject *npobj, NPString *script, N uint32_t ret; error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &ret, - RPC_TYPE_NP_VARIANT, result, + RPC_TYPE_NP_VARIANT_PASS_REF, result, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -2315,7 +2318,7 @@ invoke_NPN_GetProperty(PluginInstance *plugin, NPObject *npobj, NPIdentifier pro uint32_t ret; error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &ret, - RPC_TYPE_NP_VARIANT, result, + RPC_TYPE_NP_VARIANT_PASS_REF, result, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -2684,7 +2687,7 @@ invoke_NPN_Construct(PluginInstance *plugin, NPObject *npobj, uint32_t ret; error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &ret, - RPC_TYPE_NP_VARIANT, result, + RPC_TYPE_NP_VARIANT_PASS_REF, result, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -4081,10 +4084,10 @@ static int handle_NPP_GetValue(rpc_connection_t *connection) { NPObject *npobj = NULL; ret = g_NPP_GetValue(PLUGIN_INSTANCE_NPP(plugin), variable, (void *)&npobj); - int err = rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_INVALID); - if (npobj) - NPN_ReleaseObject(npobj); - return err; + return rpc_method_send_reply(connection, + RPC_TYPE_INT32, ret, + RPC_TYPE_NP_OBJECT_PASS_REF, npobj, + RPC_TYPE_INVALID); } } diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index 8cfd030..f3cc662 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -524,9 +524,10 @@ static int handle_NPN_GetValue(rpc_connection_t *connection) NPObject *npobj = NULL; if (valid_instance) ret = g_NPN_GetValue(PLUGIN_INSTANCE_NPP(plugin), variable, (void *)&npobj); - int err = rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_INVALID); - NPN_ReleaseObject(npobj); - return err; + return rpc_method_send_reply(connection, + RPC_TYPE_INT32, ret, + RPC_TYPE_NP_OBJECT_PASS_REF, npobj, + RPC_TYPE_INVALID); } } @@ -1194,13 +1195,10 @@ static int handle_NPN_Invoke(rpc_connection_t *connection) free(args); } - int rpc_ret = rpc_method_send_reply(connection, - RPC_TYPE_UINT32, ret, - RPC_TYPE_NP_VARIANT, &result, - RPC_TYPE_INVALID); - - NPN_ReleaseVariantValue(&result); - return rpc_ret; + return rpc_method_send_reply(connection, + RPC_TYPE_UINT32, ret, + RPC_TYPE_NP_VARIANT_PASS_REF, &result, + RPC_TYPE_INVALID); } // NPN_InvokeDefault @@ -1247,13 +1245,10 @@ static int handle_NPN_InvokeDefault(rpc_connection_t *connection) free(args); } - int rpc_ret = rpc_method_send_reply(connection, - RPC_TYPE_UINT32, ret, - RPC_TYPE_NP_VARIANT, &result, - RPC_TYPE_INVALID); - - NPN_ReleaseVariantValue(&result); - return rpc_ret; + return rpc_method_send_reply(connection, + RPC_TYPE_UINT32, ret, + RPC_TYPE_NP_VARIANT_PASS_REF, &result, + RPC_TYPE_INVALID); } // NPN_Evaluate @@ -1298,13 +1293,10 @@ static int handle_NPN_Evaluate(rpc_connection_t *connection) if (script.UTF8Characters) NPN_MemFree((void *)script.UTF8Characters); - int rpc_ret = rpc_method_send_reply(connection, - RPC_TYPE_UINT32, ret, - RPC_TYPE_NP_VARIANT, &result, - RPC_TYPE_INVALID); - - NPN_ReleaseVariantValue(&result); - return rpc_ret; + return rpc_method_send_reply(connection, + RPC_TYPE_UINT32, ret, + RPC_TYPE_NP_VARIANT_PASS_REF, &result, + RPC_TYPE_INVALID); } // NPN_GetProperty @@ -1344,13 +1336,10 @@ static int handle_NPN_GetProperty(rpc_connection_t *connection) if (npobj) NPN_ReleaseObject(npobj); - int rpc_ret = rpc_method_send_reply(connection, - RPC_TYPE_UINT32, ret, - RPC_TYPE_NP_VARIANT, &result, - RPC_TYPE_INVALID); - - NPN_ReleaseVariantValue(&result); - return rpc_ret; + return rpc_method_send_reply(connection, + RPC_TYPE_UINT32, ret, + RPC_TYPE_NP_VARIANT_PASS_REF, &result, + RPC_TYPE_INVALID); } // NPN_SetProperty @@ -1600,13 +1589,10 @@ static int handle_NPN_Construct(rpc_connection_t *connection) free(args); } - int rpc_ret = rpc_method_send_reply(connection, - RPC_TYPE_UINT32, ret, - RPC_TYPE_NP_VARIANT, &result, - RPC_TYPE_INVALID); - - NPN_ReleaseVariantValue(&result); - return rpc_ret; + return rpc_method_send_reply(connection, + RPC_TYPE_UINT32, ret, + RPC_TYPE_NP_VARIANT_PASS_REF, &result, + RPC_TYPE_INVALID); } // NPN_SetException @@ -2352,7 +2338,10 @@ invoke_NPP_GetValue(PluginInstance *plugin, NPPVariable variable, void *value) case RPC_TYPE_NP_OBJECT: { NPObject *npobj = NULL; - error = rpc_method_wait_for_reply(plugin->connection, RPC_TYPE_INT32, &ret, RPC_TYPE_NP_OBJECT, &npobj, RPC_TYPE_INVALID); + error = rpc_method_wait_for_reply(plugin->connection, + RPC_TYPE_INT32, &ret, + RPC_TYPE_NP_OBJECT_PASS_REF, &npobj, + RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { npw_perror("NPP_GetValue() wait for reply", error); ret = NPERR_GENERIC_ERROR; From e1c01801fb6cc81a2bbadd34b8947f7d60d9f740 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 11:46:35 -0400 Subject: [PATCH 13/91] Don't use NPN_CreateObject to make proxies Firefox crashes when you give it a NULL npp. Simulate it instead. NOTE: That may cause some problems, looking at the source. We'd best avoid it. --- src/npruntime.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/npruntime.c b/src/npruntime.c index 4e03b82..dcdb272 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -142,7 +142,19 @@ static NPObjectProxy *npobject_get_proxy(NPObject *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); + + // Firefox doesn't like it when we use a NULL npp, but we don't need + // it here (and don't know it). So simulate NPN_CreateObject. + // + // XXX: Firefox stores NPObjects in a manager on the + // PluginModuleChild. We possibly want to get our hands on the + // NPP. (Have the wrapper manage viewer-created objects after all.) + NPObject *object = npclass_bridge.allocate(NULL, &npclass_bridge); + if (object == NULL) + return NULL; + object->_class = &npclass_bridge; + object->referenceCount = 1; + NPObjectProxy *proxy = npobject_get_proxy(object); proxy->id = id; proxy->is_valid = true; From b96edf97d941f29e411d0255c3deeddafdf47324 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 11:55:44 -0400 Subject: [PATCH 14/91] Remove proxy entry from hash table always Otherwise it looked like we were leaking proxies when we really weren't. --- src/npruntime.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/npruntime.c b/src/npruntime.c index dcdb272..128565d 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -184,8 +184,8 @@ void npobject_destroy_proxy(NPObject *npobj, bool release_stub) assert(proxy != NULL); if (release_stub && proxy->is_valid) { npclass_invoke_Deallocate(proxy); - g_hash_table_remove(g_proxies, GINT_TO_POINTER(proxy->id)); } + g_hash_table_remove(g_proxies, GINT_TO_POINTER(proxy->id)); free(npobj); D(bugiD("npobject_destroy_proxy done\n")); } From b381a9e8116d50c01afc0b2189180d60ac5a1203 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 12:01:19 -0400 Subject: [PATCH 15/91] Disallow RPC calls after rpc_method_send_reply With NPObject pass-ref sending, there is no need for it. --- tests/test-rpc-nested-2.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/test-rpc-nested-2.c b/tests/test-rpc-nested-2.c index 4aa8aa6..cc89a10 100644 --- a/tests/test-rpc-nested-2.c +++ b/tests/test-rpc-nested-2.c @@ -138,8 +138,6 @@ handle_f3 (rpc_connection_t *connection) error = rpc_method_send_reply (connection, RPC_TYPE_INVALID); RPC_TEST_ENSURE_NO_ERROR (error); - f (RPC_TEST_METHOD_F5); - return error; } From 9f47596137c6b556dbcde1582c62b73de0095283 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 12:04:13 -0400 Subject: [PATCH 16/91] Remove delayed calls machinery It is no longer necessary. --- src/npw-viewer.c | 125 ++++------------------------------------------- 1 file changed, 9 insertions(+), 116 deletions(-) diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 636c47e..6b9b2b6 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -217,80 +217,6 @@ bool thread_check(void) return true; } -// Delayed calls machinery -// XXX: use a pipe, this should be faster (avoids GSource creation and -// explicit memory allocation) -enum { - RPC_DELAYED_NPN_RELEASE_OBJECT = 1 -}; - -typedef struct _DelayedCall { - gint type; - gpointer data; -} DelayedCall; - -static GList *g_delayed_calls = NULL; -static guint g_delayed_calls_id = 0; - -static void g_NPN_ReleaseObject_Now(NPObject *npobj); -static gboolean delayed_calls_process_cb(gpointer user_data); - -static void delayed_calls_add(int type, gpointer data) -{ - DelayedCall *dcall = NPW_MemNew(DelayedCall, 1); - if (dcall == NULL) - return; - dcall->type = type; - dcall->data = data; - g_delayed_calls = g_list_append(g_delayed_calls, dcall); - - if (g_delayed_calls_id == 0) - g_delayed_calls_id = g_idle_add_full(G_PRIORITY_LOW, - delayed_calls_process_cb, NULL, NULL); -} - -// Returns whether there are pending calls left in the queue -static gboolean delayed_calls_process(PluginInstance *plugin, gboolean is_in_NPP_Destroy) -{ - while (g_delayed_calls != NULL) { - - if (!is_in_NPP_Destroy) { - /* Continue later if there is incoming RPC */ - if (rpc_wait_dispatch(g_rpc_connection, 0) > 0) - return TRUE; - } - - DelayedCall *dcall = (DelayedCall *)g_delayed_calls->data; - /* XXX: Remove the link first; this function /must/ be - * re-entrant. We may be called again while processing the - * delayed call. */ - g_delayed_calls = g_list_delete_link(g_delayed_calls, g_delayed_calls); - switch (dcall->type) { - case RPC_DELAYED_NPN_RELEASE_OBJECT: - { - NPObject *npobj = (NPObject *)dcall->data; - g_NPN_ReleaseObject_Now(npobj); - break; - } - } - NPW_MemFree(dcall); - } - - if (g_delayed_calls) - return TRUE; - - if (g_delayed_calls_id) { - g_source_remove(g_delayed_calls_id); - g_delayed_calls_id = 0; - } - return FALSE; -} - -static gboolean delayed_calls_process_cb(gpointer user_data) -{ - return delayed_calls_process(NULL, FALSE); -} - // NPIdentifier cache static inline bool use_npidentifier_cache(void) { @@ -2053,8 +1979,16 @@ g_NPN_RetainObject(NPObject *npobj) } static void -g_NPN_ReleaseObject_Now(NPObject *npobj) +g_NPN_ReleaseObject(NPObject *npobj) { + if (!thread_check()) { + npw_printf("WARNING: NPN_ReleaseObject not called from the main thread\n"); + return; + } + + if (npobj == NULL) + return; + D(bugiI("NPN_ReleaseObject npobj=%p\n", npobj)); npobj->referenceCount--; uint32_t refcount = npobj->referenceCount; @@ -2069,43 +2003,6 @@ g_NPN_ReleaseObject_Now(NPObject *npobj) D(bugiD("NPN_ReleaseObject done (refcount: %d)\n", refcount)); } -static void -g_NPN_ReleaseObject_Delayed(NPObject *npobj) -{ - delayed_calls_add(RPC_DELAYED_NPN_RELEASE_OBJECT, npobj); -} - -static void -g_NPN_ReleaseObject(NPObject *npobj) -{ - if (!thread_check()) { - npw_printf("WARNING: NPN_ReleaseObject not called from the main thread\n"); - return; - } - - if (npobj == NULL) - return; - - if (rpc_method_invoke_possible(g_rpc_connection)) { - D(bug("NPN_ReleaseObject \n")); - g_NPN_ReleaseObject_Now(npobj); - } - else { - /* NPVariants that get tunneled over RPC get released locally. To - * counter this, they get retained when sent over RPC. However, - * the corresponding local ReleaseObject means that we are likely - * to call NPN_ReleaseObject when handle_depth != - * dispatch_depth. To that end, delay the release object. - * - * XXX: This is awful. It really should be revised, possibly by - * not using the browser-provided NPN_ReleaseVariantValue if NPAPI - * allows it. Or we make a copy of it, send that over instead and - * NPN_ReleaseVariantValue /before/ making the call. */ - D(bug("NPN_ReleaseObject \n")); - g_NPN_ReleaseObject_Delayed(npobj); - } -} - // Invokes a method on the given NPObject static bool invoke_NPN_Invoke(PluginInstance *plugin, NPObject *npobj, NPIdentifier methodName, @@ -3900,10 +3797,6 @@ static NPError g_NPP_Destroy(NPP instance, NPSavedData **sdata) if (sdata) *sdata = NULL; - // Process all pending calls as the data could become junk afterwards - // XXX: this also processes delayed calls from other instances - delayed_calls_process(plugin, TRUE); - D(bugiI("NPP_Destroy instance=%p\n", instance)); NPError ret = plugin_funcs.destroy(instance, sdata); D(bugiD("NPP_Destroy return: %d [%s]\n", ret, string_of_NPError(ret))); From 21480208af2a7b26dd4bccec6c4966171fb958e8 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 14:06:30 -0400 Subject: [PATCH 17/91] Don't invalidate the plugin-side object on proxy invalidate Just invalidate the proxy. We'll invalidate the viewer-side NPObjects later. --- src/npruntime.c | 52 ++++--------------------------------------------- 1 file changed, 4 insertions(+), 48 deletions(-) diff --git a/src/npruntime.c b/src/npruntime.c index 128565d..5b5a125 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -299,52 +299,6 @@ void g_NPClass_Deallocate(NPObject *npobj) npobject_destroy_proxy(npobj, true); } -// NPClass::Invalidate -int npclass_handle_Invalidate(rpc_connection_t *connection) -{ - D(bug("npclass_handle_Invalidate\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("NPClass::Invalidate() get args", error); - return error; - } - - if (npobj && is_valid_npobject_class(npobj) && npobj->_class->invalidate) { - D(bugiI("NPClass::Invalidate(npobj %p)\n", npobj)); - npobj->_class->invalidate(npobj); - D(bugiD("NPClass::Invalidate done\n")); - } - - return rpc_method_send_reply(connection, RPC_TYPE_INVALID); -} - -static void npclass_invoke_Invalidate(NPObject *npobj) -{ - npw_return_if_fail(rpc_method_invoke_possible(g_rpc_connection)); - - int error = rpc_method_invoke(g_rpc_connection, - RPC_METHOD_NPCLASS_INVALIDATE, - RPC_TYPE_NP_OBJECT, npobj, - RPC_TYPE_INVALID); - - if (error != RPC_ERROR_NO_ERROR) { - npw_perror("NPClass::Invalidate() invoke", error); - return; - } - - error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INVALID); - - if (error != RPC_ERROR_NO_ERROR) { - npw_perror("NPClass::Invalidate() wait for reply", error); - return; - } -} - void g_NPClass_Invalidate(NPObject *npobj) { if (!is_valid_npobject_proxy(npobj)) @@ -356,7 +310,10 @@ void g_NPClass_Invalidate(NPObject *npobj) } D(bugiI("NPClass::Invalidate(npobj %p)\n", npobj)); - npclass_invoke_Invalidate(npobj); + // Just invalidate the proxy itself. There may be multiple proxies + // for a plugin-side NPObject. We'll invalidate them viewer-side. + NPObjectProxy *proxy = npobject_get_proxy(npobj); + proxy->is_valid = false; D(bugiD("NPClass::Invalidate done\n")); } @@ -1121,7 +1078,6 @@ bool g_NPClass_Construct(NPObject *npobj, const NPVariant *args, uint32_t argCou int npclass_add_method_descriptors(rpc_connection_t *connection) { static const rpc_method_descriptor_t vtable[] = { - { RPC_METHOD_NPCLASS_INVALIDATE, npclass_handle_Invalidate }, { RPC_METHOD_NPCLASS_HAS_METHOD, npclass_handle_HasMethod }, { RPC_METHOD_NPCLASS_INVOKE, npclass_handle_Invoke }, { RPC_METHOD_NPCLASS_INVOKE_DEFAULT, npclass_handle_InvokeDefault }, From 5f01909fec0dd3147cc83728126f287ff221f847 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 14:14:03 -0400 Subject: [PATCH 18/91] Go back to calling NPN_CreateObject We'll later properly fix this under Firefox so that we pass the real NPP to NPN_CreateObject. --- src/npruntime-impl.h | 2 +- src/npruntime.c | 17 +++-------------- src/npw-rpc.c | 2 +- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/npruntime-impl.h b/src/npruntime-impl.h index c25fdb8..af21be1 100644 --- a/src/npruntime-impl.h +++ b/src/npruntime-impl.h @@ -40,7 +40,7 @@ extern NPObject *npobject_lookup_local(uint32_t id) attribute_hidden; // 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 NPObject *npobject_create_proxy(NPP npp, uint32_t id) attribute_hidden; extern uint32_t npobject_get_proxy_id(NPObject *npobj) attribute_hidden; extern void npobject_destroy_proxy(NPObject *npobj, bool release_stub); diff --git a/src/npruntime.c b/src/npruntime.c index 5b5a125..ff79eb9 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -139,22 +139,11 @@ static NPObjectProxy *npobject_get_proxy(NPObject *npobj) return (NPObjectProxy *)npobj; } -NPObject *npobject_create_proxy(uint32_t id) +NPObject *npobject_create_proxy(NPP instance, uint32_t id) { - D(bugiI("npobject_create_proxy: id=0x%x\n", id)); - - // Firefox doesn't like it when we use a NULL npp, but we don't need - // it here (and don't know it). So simulate NPN_CreateObject. - // - // XXX: Firefox stores NPObjects in a manager on the - // PluginModuleChild. We possibly want to get our hands on the - // NPP. (Have the wrapper manage viewer-created objects after all.) - NPObject *object = npclass_bridge.allocate(NULL, &npclass_bridge); - if (object == NULL) - return NULL; - object->_class = &npclass_bridge; - object->referenceCount = 1; + D(bugiI("npobject_create_proxy: NPP=%p, id=0x%x\n", instance, id)); + NPObject *object = NPN_CreateObject(instance, &npclass_bridge); NPObjectProxy *proxy = npobject_get_proxy(object); proxy->id = id; proxy->is_valid = true; diff --git a/src/npw-rpc.c b/src/npw-rpc.c index b837bf0..2ca9f54 100644 --- a/src/npw-rpc.c +++ b/src/npw-rpc.c @@ -1246,7 +1246,7 @@ static int do_recv_NPObject_helper(rpc_message_t *message, void *p_value, if (npobj == NULL) { // We got an id of a newly created remote stub. Create a proxy // for it. - npobj = npobject_create_proxy(npobj_id); + npobj = npobject_create_proxy(NULL, npobj_id); if (release_stub) npw_printf("ERROR: received release_stub for proxy NPObject.\n"); } else { From 8bd6c24884955271eb1754808e985dffd123baec Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 14:27:54 -0400 Subject: [PATCH 19/91] Only compile npruntime_deactivate in the browser --- src/npruntime-impl.h | 2 ++ src/npruntime.c | 2 ++ src/npw-common.h | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/npruntime-impl.h b/src/npruntime-impl.h index af21be1..0c152fe 100644 --- a/src/npruntime-impl.h +++ b/src/npruntime-impl.h @@ -49,8 +49,10 @@ extern void npvariant_clear(struct _NPVariant *variant) attribute_hidden; extern char *string_of_NPVariant(const struct _NPVariant *arg) attribute_hidden; extern void print_npvariant_args(const struct _NPVariant *args, uint32_t nargs) attribute_hidden; +#if NPW_IS_BROWSER // Deactivate all NPObject instances extern void npruntime_deactivate(void) attribute_hidden; +#endif // Check whether to use NPRuntime data caching // (on by default, disabled with NPW_NPRUNTIME_CACHE=0|no) diff --git a/src/npruntime.c b/src/npruntime.c index ff79eb9..d08b172 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -1106,6 +1106,7 @@ void npobject_bridge_destroy(void) } } +#if NPW_IS_BROWSER static void proxy_deactivate_func(gpointer key, gpointer value, gpointer user_data) { NPObjectProxy *proxy = (NPObjectProxy *)value; @@ -1127,6 +1128,7 @@ void npruntime_deactivate(void) npobject_bridge_destroy(); npobject_bridge_new(); } +#endif /* ====================================================================== */ diff --git a/src/npw-common.h b/src/npw-common.h index 9792bbe..184f745 100644 --- a/src/npw-common.h +++ b/src/npw-common.h @@ -31,7 +31,6 @@ #include #include #include -#include "npruntime-impl.h" /* Supported NPAPI interfaces */ #define NPW_NPAPI_VERSION 24 @@ -48,6 +47,8 @@ #endif #define NPW_IS_PLUGIN (!NPW_IS_BROWSER) +#include "npruntime-impl.h" + #if NPW_IS_BROWSER # define _NPW_INSTANCE_PRIVATE_DATA pdata #else From b8aa5a06fbec1c06034dac6ef0bbd3446b250e16 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 20:45:41 -0400 Subject: [PATCH 20/91] Another massive commit Maintain and send the owning NPP for every viewer-owned NPObject. Use this as the NPP when creating proxy objects. Also send an explicit NPObject type so we don't infer which side owns it from our dictionaries. This fixes the Firefox thing properly. --- src/npruntime-impl.h | 9 ++++++ src/npruntime.c | 45 ++++++++++++++++++++++++-- src/npw-rpc.c | 77 +++++++++++++++++++++++++++++++------------- src/npw-viewer.c | 45 +++++++++++++++++++++++--- 4 files changed, 148 insertions(+), 28 deletions(-) diff --git a/src/npruntime-impl.h b/src/npruntime-impl.h index 0c152fe..5f02bbd 100644 --- a/src/npruntime-impl.h +++ b/src/npruntime-impl.h @@ -44,6 +44,15 @@ extern NPObject *npobject_create_proxy(NPP npp, uint32_t id) attribute_hidden; extern uint32_t npobject_get_proxy_id(NPObject *npobj) attribute_hidden; extern void npobject_destroy_proxy(NPObject *npobj, bool release_stub); +#if NPW_IS_PLUGIN +// Firefox requires that NPN_CreateObject be called with a real NPP +// pointer, so we keep track of the ownership of NPObjects. This +// mapping also doubles as a way of tracking if they've been invalidated. +extern void npobject_register(NPObject *npobj, void *plugin) attribute_hidden; +extern void *npobject_get_owner(NPObject *npobj) attribute_hidden; +extern void npobject_unregister(NPObject *npobj) attribute_hidden; +#endif + struct _NPVariant; extern void npvariant_clear(struct _NPVariant *variant) attribute_hidden; extern char *string_of_NPVariant(const struct _NPVariant *arg) attribute_hidden; diff --git a/src/npruntime.c b/src/npruntime.c index d08b172..3ad176f 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -226,7 +226,16 @@ static NPClass npclass_bridge = { static inline bool is_valid_npobject_class(NPObject *npobj) { - return npobj != NULL && npobj->_class != NULL; + if (npobj == NULL || npobj->_class == NULL) + return false; +#if NPW_IS_PLUGIN + // Reject requests on invalidated objects. + if (npobject_get_owner(npobj) == NULL) { + npw_printf("ERROR: accessed invalidated NPObject\n"); + return false; + } +#endif + return true; } // NPClass::Allocate @@ -1082,15 +1091,41 @@ int npclass_add_method_descriptors(rpc_connection_t *connection) sizeof(vtable) / sizeof(vtable[0])); } +#if NPW_IS_PLUGIN +/* ====================================================================== */ +/* === NPObject Registration === */ +/* ====================================================================== */ + +static GHashTable *g_npobj_owners = NULL; + +void npobject_register(NPObject *npobj, void *plugin) +{ + assert(npobject_get_owner(npobj) == NULL); + g_hash_table_insert(g_npobj_owners, npobj, plugin); +} + +void *npobject_get_owner(NPObject *npobj) +{ + return g_hash_table_lookup(g_npobj_owners, npobj); +} + +void npobject_unregister(NPObject *npobj) +{ + g_hash_table_remove(g_npobj_owners, npobj); +} +#endif /* ====================================================================== */ -/* === NPObject Repository === */ +/* === NPObject Bridge System === */ /* ====================================================================== */ bool npobject_bridge_new(void) { g_stubs = g_hash_table_new(NULL, NULL); g_proxies = g_hash_table_new(NULL, NULL); +#if NPW_IS_PLUGIN + g_npobj_owners = g_hash_table_new(NULL, NULL); +#endif return true; } @@ -1104,6 +1139,12 @@ void npobject_bridge_destroy(void) g_hash_table_destroy(g_proxies); g_proxies = NULL; } +#if NPW_IS_PLUGIN + if (g_npobj_owners) { + g_hash_table_destroy(g_npobj_owners); + g_npobj_owners = NULL; + } +#endif } #if NPW_IS_BROWSER diff --git a/src/npw-rpc.c b/src/npw-rpc.c index 2ca9f54..0ece6e5 100644 --- a/src/npw-rpc.c +++ b/src/npw-rpc.c @@ -1178,26 +1178,43 @@ static int do_recv_NPPrintData(rpc_message_t *message, void *p_value) * Process NPObject objects */ +enum NPObjectType { + NPOBJECT_NULL = 0, + NPOBJECT_SENDER_OWNED, + NPOBJECT_RECEIVER_OWNED +}; + static int do_send_NPObject_helper(rpc_message_t *message, void *p_value, bool pass_ref) { - uint32_t npobj_id = 0; NPObject *npobj = (NPObject *)p_value; + + int error; + uint32_t type = NPOBJECT_NULL; + NPW_PluginInstance *plugin = NULL; + uint32_t npobj_id = 0; bool release_stub = false; + if (npobj) { 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. + type = NPOBJECT_SENDER_OWNED; npobj_id = npobject_create_stub(npobj); if (pass_ref) { // Release our reference; the stub protects the object from // deallocation. NPN_ReleaseObject(npobj); } +#if NPW_IS_PLUGIN + // Get the owning NPP so we can figure out who the owner is. + plugin = npobject_get_owner(npobj); +#endif } else { // This is a proxy for the object on the other side. Just pass // the id along. + type = NPOBJECT_RECEIVER_OWNED; if (pass_ref) { // As above, we release out reference. If this is not the last // reference, we may just do so. Otherwise, we destroy it, but @@ -1205,6 +1222,7 @@ static int do_send_NPObject_helper(rpc_message_t *message, void *p_value, // this one. if (npobj->referenceCount == 1) { npobject_destroy_proxy(npobj, false); + // Tell the other side to destroy the stub after taking a ref. release_stub = true; } else { NPN_ReleaseObject(npobj); @@ -1214,10 +1232,15 @@ static int do_send_NPObject_helper(rpc_message_t *message, void *p_value, 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) + + // This could be significantly trimmed down, but it really doesn't + // matter. Latency, not bandwidth, is what we care about. + if ((error = rpc_message_send_uint32(message, type)) < 0) + return error; + if ((error = do_send_NPW_PluginInstance(message, plugin)) < 0) + return error; + if ((error = rpc_message_send_uint32(message, npobj_id)) < 0) return error; - // Tell the other side whether or not to destroy the stub. if (pass_ref) { if ((error = rpc_message_send_uint32(message, release_stub)) < 0) return error; @@ -1230,9 +1253,15 @@ static int do_recv_NPObject_helper(rpc_message_t *message, void *p_value, bool pass_ref) { int error; - uint32_t npobj_id; + uint32_t type = NPOBJECT_NULL; + uint32_t npobj_id = 0; + NPW_PluginInstance *plugin = NULL; uint32_t release_stub = 0; + if ((error = rpc_message_recv_uint32(message, &type)) < 0) + return error; + if ((error = do_recv_NPW_PluginInstance(message, &plugin)) < 0) + return error; if ((error = rpc_message_recv_uint32(message, &npobj_id)) < 0) return error; if (pass_ref) { @@ -1241,26 +1270,30 @@ static int do_recv_NPObject_helper(rpc_message_t *message, void *p_value, } NPObject *npobj = NULL; - if (npobj_id) { + if (type == NPOBJECT_NULL) { + // Do nothing. + } else if (type == NPOBJECT_SENDER_OWNED) { + // We got a newly-created remote stub. Create a matching proxy. + npobj = npobject_create_proxy(NPW_PLUGIN_INSTANCE_NPP(plugin), npobj_id); + if (release_stub) { + npw_printf("ERROR: received release_stub for proxy NPObject.\n"); + return RPC_ERROR_GENERIC; + } + } else if (type == NPOBJECT_RECEIVER_OWNED) { npobj = npobject_lookup_local(npobj_id); - if (npobj == NULL) { - // We got an id of a newly created remote stub. Create a proxy - // for it. - npobj = npobject_create_proxy(NULL, npobj_id); - if (release_stub) - npw_printf("ERROR: received release_stub for proxy NPObject.\n"); - } else { - // This is an object on our side. Retain it; receiver must - // release all received NPObjects. - D(bug("local\n")); - NPN_RetainObject(npobj); - if (release_stub) { - // We just retained the object, so it won't be destroyed. - npobject_destroy_stub(npobj_id); - } + assert(npobj != NULL); + // This is an object on our side. Retain it; receiver must + // release all received NPObjects. + D(bug("local\n")); + NPN_RetainObject(npobj); + if (release_stub) { + // We just retained the object, so it won't be destroyed. + npobject_destroy_stub(npobj_id); } D(bug("recv id 0x%x, obj %p\n", npobj_id, npobj)); - assert(npobj != NULL); + } else { + npw_printf("ERROR: unknown NPObject type %d\n", type); + return RPC_ERROR_GENERIC; } *((NPObject **)p_value) = npobj; diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 6b9b2b6..0bc1316 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -79,6 +79,7 @@ typedef struct _PluginInstance { GdkWindow *browser_toplevel; uint32_t next_timer_id; GHashTable *timers; + GHashTable *npobjects; } PluginInstance; #define PLUGIN_INSTANCE(instance) \ @@ -159,6 +160,9 @@ static void plugin_instance_finalize(PluginInstance *plugin) if (plugin->timers) { g_hash_table_destroy(plugin->timers); } + if (plugin->npobjects) { + g_hash_table_destroy(plugin->npobjects); + } } static void plugin_instance_invalidate(PluginInstance *plugin) @@ -1945,7 +1949,9 @@ g_NPN_CreateObject(NPP instance, NPClass *class) if (class == NULL) return NULL; - D(bugiI("NPN_CreateObject\n")); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + + D(bugiI("NPN_CreateObject instance=%p, plugin=%p\n", instance, plugin)); NPObject *npobj; if (class->allocate) @@ -1955,6 +1961,12 @@ g_NPN_CreateObject(NPP instance, NPClass *class) if (npobj) { npobj->_class = class; npobj->referenceCount = 1; + + if (npobject_get_proxy_id(npobj) == 0 && plugin) { + // Register anything that isn't a proxy. + npobject_register(npobj, plugin); + g_hash_table_insert(plugin->npobjects, npobj, npobj); + } } D(bugiD("NPN_CreateObject return: %p\n", npobj)); return npobj; @@ -1993,6 +2005,14 @@ g_NPN_ReleaseObject(NPObject *npobj) npobj->referenceCount--; uint32_t refcount = npobj->referenceCount; if (npobj->referenceCount == 0) { +#if NPW_IS_PLUGIN + PluginInstance *plugin = npobject_get_owner(npobj); + if (plugin) { + // Unregister the owner, if not proxy. + g_hash_table_remove(plugin->npobjects, npobj); + npobject_unregister(npobj); + } +#endif if (npobj) { if (npobj->_class && npobj->_class->deallocate) npobj->_class->deallocate(npobj); @@ -3727,10 +3747,10 @@ static NPError g_NPP_New(NPMIMEType plugin_type, uint32_t instance_id, } plugin->next_timer_id = 1; - plugin->timers = g_hash_table_new_full(g_direct_hash, - g_direct_equal, - NULL, + plugin->timers = g_hash_table_new_full(NULL, NULL, NULL, (GDestroyNotify) timer_free); + plugin->npobjects = g_hash_table_new(NULL, NULL); + return ret; } @@ -3784,6 +3804,16 @@ static int handle_NPP_New(rpc_connection_t *connection) return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID); } +static void invalidate_npobject(gpointer key, gpointer value, gpointer user_data) +{ + NPObject *npobj = key; + D(bugiI("invalidate_npobject %p\n", npobj)); + if (npobj->_class && npobj->_class->invalidate) + npobj->_class->invalidate(npobj); + npobject_unregister(npobj); + D(bugiD("invalidate_npobject done\n")); +} + // NPP_Destroy static NPError g_NPP_Destroy(NPP instance, NPSavedData **sdata) { @@ -3801,6 +3831,13 @@ static NPError g_NPP_Destroy(NPP instance, NPSavedData **sdata) NPError ret = plugin_funcs.destroy(instance, sdata); D(bugiD("NPP_Destroy return: %d [%s]\n", ret, string_of_NPError(ret))); + // Invalidate all NPObjects remaining. We won't forcibly delete them + // like Firefox does because there may be proxies and stubs still + // holding on. The references should eventually go away and allow us + // to free it. If needbe we can track more objects, but anything + // left here is arguably a plugin or browser bug. + g_hash_table_foreach(plugin->npobjects, invalidate_npobject, NULL); + if (!plugin->use_xembed) xt_source_destroy(); From cfd90e9ce40fcbb9940f225c477d2dc8fc0920f5 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 20:50:57 -0400 Subject: [PATCH 21/91] When a NPObjectProxy is forcible invalidated, release the stub It is of no use anymore, and later code will refuse to communicate with the stub. It's easier to just free it now directly. --- src/npruntime.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/npruntime.c b/src/npruntime.c index 3ad176f..0166638 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -312,6 +312,9 @@ void g_NPClass_Invalidate(NPObject *npobj) // for a plugin-side NPObject. We'll invalidate them viewer-side. NPObjectProxy *proxy = npobject_get_proxy(npobj); proxy->is_valid = false; + // Release the underlying stub now, otherwise the is_valid check + // will refuse to do so. The stub is of no use to us now. + npclass_invoke_Deallocate(proxy); D(bugiD("NPClass::Invalidate done\n")); } @@ -1152,6 +1155,7 @@ static void proxy_deactivate_func(gpointer key, gpointer value, gpointer user_da { NPObjectProxy *proxy = (NPObjectProxy *)value; proxy->is_valid = false; + // No need to release the stub. At this point the viewer is dead. } static void stub_destroy_func(gpointer key, gpointer value, gpointer user_data) From 6947ea103ee35af96c72d5ac1286a83171016fe2 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 20:57:48 -0400 Subject: [PATCH 22/91] Remove some spurious debug statements --- src/npw-rpc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/npw-rpc.c b/src/npw-rpc.c index 0ece6e5..4b8bb5f 100644 --- a/src/npw-rpc.c +++ b/src/npw-rpc.c @@ -1229,7 +1229,6 @@ static int do_send_NPObject_helper(rpc_message_t *message, void *p_value, } } } - D(bug("sending id 0x%x\n", npobj_id)); assert(npobj_id != 0); } @@ -1284,13 +1283,11 @@ static int do_recv_NPObject_helper(rpc_message_t *message, void *p_value, assert(npobj != NULL); // This is an object on our side. Retain it; receiver must // release all received NPObjects. - D(bug("local\n")); NPN_RetainObject(npobj); if (release_stub) { // We just retained the object, so it won't be destroyed. npobject_destroy_stub(npobj_id); } - D(bug("recv id 0x%x, obj %p\n", npobj_id, npobj)); } else { npw_printf("ERROR: unknown NPObject type %d\n", type); return RPC_ERROR_GENERIC; From 82851c108beca935efeb98085cdeb34dee73d476 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 21:01:48 -0400 Subject: [PATCH 23/91] Don't reserve the topmost bit in NPObject ids We explicitly advertise the type, so client and server each get distinct id spaces. --- src/npruntime.c | 6 ++---- src/rpc.c | 7 +------ src/rpc.h | 1 - 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/npruntime.c b/src/npruntime.c index 0166638..db1dfa8 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -77,11 +77,9 @@ uint32_t npobject_create_stub(NPObject *npobj) static uint32_t next_id = 0; - // Allocate an id. Client and server get distinct id spaces. + // Allocate an id. Client and server get separate id spaces because + // of type field. 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); diff --git a/src/rpc.c b/src/rpc.c index a8da2fd..deb9a69 100644 --- a/src/rpc.c +++ b/src/rpc.c @@ -482,14 +482,9 @@ void rpc_connection_unref(rpc_connection_t *connection) } // Returns whether we are in sync mode or not (i.e. needs other end sync) -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); + return connection->type == RPC_CONNECTION_SERVER; } // Returns whether we are allowed to synchronize with the other end diff --git a/src/rpc.h b/src/rpc.h index ae1cac5..0d315a0 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -54,7 +54,6 @@ 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; From fd133c39a1ae7bab61a59267df8a59b2e6ddb097 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 22:56:39 -0400 Subject: [PATCH 24/91] Allow NPN_CreateObject to run with a NULL instance It's probably not a bad idea, and you'll crash Firefox, but let's not crash it on our end. --- src/npruntime-impl.h | 1 + src/npruntime.c | 9 +++++++-- src/npw-viewer.c | 7 ++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/npruntime-impl.h b/src/npruntime-impl.h index 5f02bbd..86f6244 100644 --- a/src/npruntime-impl.h +++ b/src/npruntime-impl.h @@ -49,6 +49,7 @@ extern void npobject_destroy_proxy(NPObject *npobj, bool release_stub); // pointer, so we keep track of the ownership of NPObjects. This // mapping also doubles as a way of tracking if they've been invalidated. extern void npobject_register(NPObject *npobj, void *plugin) attribute_hidden; +extern bool npobject_is_registered(NPObject *npobj) attribute_hidden; extern void *npobject_get_owner(NPObject *npobj) attribute_hidden; extern void npobject_unregister(NPObject *npobj) attribute_hidden; #endif diff --git a/src/npruntime.c b/src/npruntime.c index db1dfa8..d938941 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -228,7 +228,7 @@ static inline bool is_valid_npobject_class(NPObject *npobj) return false; #if NPW_IS_PLUGIN // Reject requests on invalidated objects. - if (npobject_get_owner(npobj) == NULL) { + if (!npobject_is_registered(npobj)) { npw_printf("ERROR: accessed invalidated NPObject\n"); return false; } @@ -1101,10 +1101,15 @@ static GHashTable *g_npobj_owners = NULL; void npobject_register(NPObject *npobj, void *plugin) { - assert(npobject_get_owner(npobj) == NULL); + assert(!npobject_is_registered(npobj)); g_hash_table_insert(g_npobj_owners, npobj, plugin); } +bool npobject_is_registered(NPObject *npobj) +{ + return g_hash_table_lookup_extended(g_npobj_owners, npobj, NULL, NULL); +} + void *npobject_get_owner(NPObject *npobj) { return g_hash_table_lookup(g_npobj_owners, npobj); diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 0bc1316..0a6e81b 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -1962,10 +1962,11 @@ g_NPN_CreateObject(NPP instance, NPClass *class) npobj->_class = class; npobj->referenceCount = 1; - if (npobject_get_proxy_id(npobj) == 0 && plugin) { + if (npobject_get_proxy_id(npobj) == 0) { // Register anything that isn't a proxy. npobject_register(npobj, plugin); - g_hash_table_insert(plugin->npobjects, npobj, npobj); + if (plugin) + g_hash_table_insert(plugin->npobjects, npobj, npobj); } } D(bugiD("NPN_CreateObject return: %p\n", npobj)); @@ -2010,8 +2011,8 @@ g_NPN_ReleaseObject(NPObject *npobj) if (plugin) { // Unregister the owner, if not proxy. g_hash_table_remove(plugin->npobjects, npobj); - npobject_unregister(npobj); } + npobject_unregister(npobj); #endif if (npobj) { if (npobj->_class && npobj->_class->deallocate) From 698e8d0c12fa7aef391d2ac798e6477135e476be Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 20 Apr 2011 22:59:15 -0400 Subject: [PATCH 25/91] Hide some accidentally exposed symbols Now we're back to exporting the bare minimum. --- src/npruntime-impl.h | 2 +- src/npruntime.c | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/npruntime-impl.h b/src/npruntime-impl.h index 86f6244..d3595b1 100644 --- a/src/npruntime-impl.h +++ b/src/npruntime-impl.h @@ -42,7 +42,7 @@ extern NPObject *npobject_lookup_local(uint32_t id) attribute_hidden; // its stub. extern NPObject *npobject_create_proxy(NPP npp, uint32_t id) attribute_hidden; extern uint32_t npobject_get_proxy_id(NPObject *npobj) attribute_hidden; -extern void npobject_destroy_proxy(NPObject *npobj, bool release_stub); +extern void npobject_destroy_proxy(NPObject *npobj, bool release_stub) attribute_hidden; #if NPW_IS_PLUGIN // Firefox requires that NPN_CreateObject be called with a real NPP diff --git a/src/npruntime.c b/src/npruntime.c index d938941..93b80b5 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -243,7 +243,7 @@ NPObject *g_NPClass_Allocate(NPP npp, NPClass *aclass) } // NPClass::Deallocate -int npclass_handle_Deallocate(rpc_connection_t *connection) +static int npclass_handle_Deallocate(rpc_connection_t *connection) { D(bug("npclass_handle_Deallocate\n")); @@ -317,7 +317,7 @@ void g_NPClass_Invalidate(NPObject *npobj) } // NPClass::HasMethod -int npclass_handle_HasMethod(rpc_connection_t *connection) +static int npclass_handle_HasMethod(rpc_connection_t *connection) { D(bug("npclass_handle_HasMethod\n")); @@ -388,7 +388,7 @@ bool g_NPClass_HasMethod(NPObject *npobj, NPIdentifier name) } // NPClass::Invoke -int npclass_handle_Invoke(rpc_connection_t *connection) +static int npclass_handle_Invoke(rpc_connection_t *connection) { D(bug("npclass_handle_Invoke\n")); @@ -487,7 +487,7 @@ bool g_NPClass_Invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args, } // NPClass::InvokeDefault -int npclass_handle_InvokeDefault(rpc_connection_t *connection) +static int npclass_handle_InvokeDefault(rpc_connection_t *connection) { D(bug("npclass_handle_InvokeDefault\n")); @@ -583,7 +583,7 @@ bool g_NPClass_InvokeDefault(NPObject *npobj, const NPVariant *args, uint32_t ar } // NPClass::HasProperty -int npclass_handle_HasProperty(rpc_connection_t *connection) +static int npclass_handle_HasProperty(rpc_connection_t *connection) { D(bug("npclass_handle_HasProperty\n")); @@ -654,7 +654,7 @@ bool g_NPClass_HasProperty(NPObject *npobj, NPIdentifier name) } // NPClass::GetProperty -int npclass_handle_GetProperty(rpc_connection_t *connection) +static int npclass_handle_GetProperty(rpc_connection_t *connection) { D(bug("npclass_handle_GetProperty\n")); @@ -739,7 +739,7 @@ bool g_NPClass_GetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result } // NPClass::SetProperty -int npclass_handle_SetProperty(rpc_connection_t *connection) +static int npclass_handle_SetProperty(rpc_connection_t *connection) { D(bug("npclass_handle_SetProperty\n")); @@ -822,7 +822,7 @@ bool g_NPClass_SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant * } // NPClass::RemoveProperty -int npclass_handle_RemoveProperty(rpc_connection_t *connection) +static int npclass_handle_RemoveProperty(rpc_connection_t *connection) { D(bug("npclass_handle_RemoveProperty\n")); @@ -893,7 +893,7 @@ bool g_NPClass_RemoveProperty(NPObject *npobj, NPIdentifier name) } // NPClass::Enumerate -int npclass_handle_Enumerate(rpc_connection_t *connection) +static int npclass_handle_Enumerate(rpc_connection_t *connection) { D(bug("npclass_handle_Enumerate\n")); @@ -979,7 +979,7 @@ bool g_NPClass_Enumerate(NPObject *npobj, } // NPClass::Construct -int npclass_handle_Construct(rpc_connection_t *connection) +static int npclass_handle_Construct(rpc_connection_t *connection) { D(bug("npclass_handle_Construct\n")); From 8104fc2afad1b1f33460e52711fea961e8047352 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 21 Apr 2011 09:23:11 -0400 Subject: [PATCH 26/91] Don't recompute VERSION, RELEASE, etc. in the Makefile We already have one nasty set of shell commands. Let's not make it two. --- Makefile | 18 ------------------ configure | 1 + 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/Makefile b/Makefile index f056d52..83b95af 100644 --- a/Makefile +++ b/Makefile @@ -9,24 +9,6 @@ SRC_PATH = . endif PACKAGE = nspluginwrapper -ifeq ($(VERSION),) -VERSION := $(shell sed < $(SRC_PATH)/$(PACKAGE).spec -n '/^\%define version[ ]*/s///p') -endif -ifeq ($(RELEASE),) -RELEASE := $(shell sed < $(SRC_PATH)/$(PACKAGE).spec -n '/^\%define release[ ]*/s///p') -endif -ifeq ($(SVNDATE),) -SVNDATE := $(shell sed < $(SRC_PATH)/$(PACKAGE).spec -n '/^\%define svndate[ ]*/s///p') -endif -ifeq ($(SVNDATE),) -SVNDATE := $(shell date '+%Y%m%d') -endif -ifeq ($(SNAPSHOT),) -SNAPSHOT := $(shell echo "$(RELEASE)" | grep "^0") -ifeq ($(SNAPSHOT),$(RELEASE)) -SNAPSHOT := 2 -endif -endif ifeq ($(SNAPSHOT),2) VERSION_SUFFIX = -$(SVNDATE) endif diff --git a/configure b/configure index 8223a40..d2f74ed 100755 --- a/configure +++ b/configure @@ -858,6 +858,7 @@ echo "#define LIBDIR \"$libdir\"" >> $config_h echo "ALLOW_STRIP=$strip" >> $config_mak echo "VERSION=$VERSION" >> $config_mak +echo "RELEASE=$RELEASE" >> $config_mak echo "SVNDATE=$SVNDATE" >> $config_mak echo "SNAPSHOT=$SNAPSHOT" >> $config_mak echo "#define NPW_SNAPSHOT $SNAPSHOT" >> $config_h From 6e950dc11e016286e61ca1d3966bd1411e40b795 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 21 Apr 2011 09:30:57 -0400 Subject: [PATCH 27/91] Drop changelog records from the Makefile I'm not going to maintain that, and this isn't in svn anymore. --- Makefile | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Makefile b/Makefile index 83b95af..54f108f 100644 --- a/Makefile +++ b/Makefile @@ -340,12 +340,6 @@ distrpm: $(archivedir)$(SRCARCHIVE).bz2 localrpm: $(archivedir)$(SRCARCHIVE).bz2 $(call RPMBUILD,$<) -changelog: ../common/authors.xml - svn_prefix=`svn info .|sed -n '/^URL *: .*\/svn\/\(.*\)$$/s//\1\//p'`; \ - LC_ALL=C TZ=GMT svn2cl --strip-prefix=$$svn_prefix --authors=../common/authors.xml || : -changelog.commit: changelog - svn commit -m "Generated by svn2cl." ChangeLog - $(npwrapper_LIBRARY): $(npwrapper_OBJECTS) $(CC) $(DSO_LDFLAGS) $(npwrapper_LDFLAGS) -o $@ $(npwrapper_OBJECTS) $(npwrapper_LIBS) From 115f33499ea6efbe666beb97de59255903e0696d Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 21 Apr 2011 09:32:27 -0400 Subject: [PATCH 28/91] Rename the ChangeLog file so it's visible not current --- ChangeLog => ChangeLog.pre-1-4 | 0 README | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) rename ChangeLog => ChangeLog.pre-1-4 (100%) diff --git a/ChangeLog b/ChangeLog.pre-1-4 similarity index 100% rename from ChangeLog rename to ChangeLog.pre-1-4 diff --git a/README b/README index a6ff9c5..7818d52 100644 --- a/README +++ b/README @@ -115,7 +115,7 @@ Github: https://github.com/davidben/nspluginwrapper Please consult the file "NEWS" for the release history. -A "ChangeLog" file is also available in this distribution from before +A "ChangeLog.pre-1-4" file is also available in this distribution from before git. @@ -126,4 +126,4 @@ Gwenole Beauchesne, David Benjamin, - \ No newline at end of file + From 30df6a2f17a7e85f00ff631473d312e31b56aaa2 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 21 Apr 2011 09:33:45 -0400 Subject: [PATCH 29/91] Drop archive-building Makefile targets Last I tried, they didn't work. More importantly, I don't want to maintain another list of files. That's what version control is for. --- Makefile | 43 ------------------------------------------- 1 file changed, 43 deletions(-) diff --git a/Makefile b/Makefile index 54f108f..e11809c 100644 --- a/Makefile +++ b/Makefile @@ -202,31 +202,6 @@ TARGETS += $(test_rpc_PROGRAMS) archivedir = files/ SRCARCHIVE = $(PACKAGE)-$(VERSION)$(VERSION_SUFFIX).tar -FILES = configure Makefile nspluginwrapper.spec -FILES += README NEWS TODO COPYING ChangeLog -FILES += $(wildcard utils/*.sh) -FILES += $(wildcard utils/*.c) -FILES += $(wildcard src/*.c) -FILES += $(wildcard src/*.cpp) -FILES += $(wildcard src/*.h) -FILES += $(wildcard src/*.sh) -FILES += $(wildcard src/*.map) -FILES += $(wildcard tests/*.html) -FILES += $(wildcard tests/*.c tests/*.h) -FILES += $(wildcard npapi/*.h) -FILES += $(LSB_TOP_DIR)/headers/core_filelist -FILES += $(addprefix $(LSB_TOP_DIR)/headers/,$(shell cat $(LSB_TOP_DIR)/headers/core_filelist)) -FILES += $(LSB_TOP_DIR)/headers/desktop_filelist -FILES += $(addprefix $(LSB_TOP_DIR)/headers/,$(shell cat $(LSB_TOP_DIR)/headers/desktop_filelist)) -FILES += $(LSB_SRC_DIR)/LibNameMap.txt -FILES += $(LSB_SRC_DIR)/core_filelist -FILES += $(LSB_SRC_DIR)/core_static_filelist -FILES += $(LSB_SRC_DIR)/desktop_filelist -FILES += $(patsubst %,$(LSB_SRC_DIR)/%.c,$(LSB_CORE_STUBS)) -FILES += $(patsubst %,$(LSB_SRC_DIR)/%.Version,$(LSB_CORE_STUBS)) -FILES += $(patsubst %,$(LSB_SRC_DIR)/%.c,$(LSB_CORE_STATIC_STUBS)) -FILES += $(patsubst %,$(LSB_SRC_DIR)/%.c,$(LSB_DESKTOP_STUBS)) -FILES += $(patsubst %,$(LSB_SRC_DIR)/%.Version,$(LSB_DESKTOP_STUBS)) all: $(TARGETS) @@ -309,24 +284,6 @@ install.mkruntime: $(SRC_PATH)/utils/mkruntime.sh $(archivedir):: [ -d $(archivedir) ] || mkdir $(archivedir) > /dev/null 2>&1 -tarball: - $(MAKE) -C $(SRC_PATH) do_tarball -do_tarball: $(archivedir) $(archivedir)$(SRCARCHIVE).bz2 - -$(archivedir)$(SRCARCHIVE): $(archivedir) $(FILES) - BUILDDIR=`mktemp -d /tmp/buildXXXXXXXX` ; \ - mkdir -p $$BUILDDIR/$(PACKAGE)-$(VERSION) ; \ - (cd $(SRC_PATH) && tar c $(FILES)) | tar x -C $$BUILDDIR/$(PACKAGE)-$(VERSION) ; \ - [ "$(SNAPSHOT)" = "2" ] && svndate_def="%" || svndate_def="#" ; \ - sed -e "s/^[%#]define svndate.*/$${svndate_def}define svndate $(SVNDATE)/" \ - < $(SRC_PATH)/nspluginwrapper.spec \ - > $$BUILDDIR/$(PACKAGE)-$(VERSION)/nspluginwrapper.spec ; \ - (cd $$BUILDDIR && tar cvf $(SRCARCHIVE) $(PACKAGE)-$(VERSION)) ; \ - mv -f $$BUILDDIR/$(SRCARCHIVE) $(archivedir) ; \ - rm -rf $$BUILDDIR -$(archivedir)$(SRCARCHIVE).bz2: $(archivedir)$(SRCARCHIVE) - bzip2 -9vf $(archivedir)$(SRCARCHIVE) - RPMBUILD = \ RPMDIR=`mktemp -d` ; \ mkdir -p $$RPMDIR/{SPECS,SOURCES,BUILD,RPMS,SRPMS} ; \ From 1ed587a95aa32768eac93fd76355d285a518e9bd Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 21 Apr 2011 12:35:33 -0400 Subject: [PATCH 30/91] Let's not use a deprecated function when checking for usable glib Though it really doesn't matter. --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index d2f74ed..1081626 100755 --- a/configure +++ b/configure @@ -509,7 +509,7 @@ fi cat > $TMPC << EOF #include int main(void) { - (void) g_main_pending(); + (void) g_main_context_pending(NULL); return 0; } EOF From 63f8937736d3cb1d300621bd4a6df3c21ab13252 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 21 Apr 2011 14:23:19 -0400 Subject: [PATCH 31/91] Incorporate the release number into NPW_PLUGIN_IDENT As long as distributions actually remember to increment this value, they won't keep missing updates. --- configure | 2 ++ src/sysdeps.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/configure b/configure index 1081626..5f3dd86 100755 --- a/configure +++ b/configure @@ -864,8 +864,10 @@ echo "SNAPSHOT=$SNAPSHOT" >> $config_mak echo "#define NPW_SNAPSHOT $SNAPSHOT" >> $config_h if test $SNAPSHOT -ge 2; then echo "#define NPW_VERSION \"$VERSION-Pre ($SVNDATE)\"" >> $config_h + echo "#define NPW_FULL_VERSION NPW_VERSION" >> $config_h else echo "#define NPW_VERSION \"$VERSION\"" >> $config_h + echo "#define NPW_FULL_VERSION \"$VERSION-$RELEASE\"" >> $config_h fi echo "pkglibdir=$pkglibdir" >> $config_mak diff --git a/src/sysdeps.h b/src/sysdeps.h index e404142..64e5605 100644 --- a/src/sysdeps.h +++ b/src/sysdeps.h @@ -47,7 +47,7 @@ #define NPW_WRAPPER NPW_WRAPPER_BASE ".so" #define NPW_DEFAULT_PLUGIN_PATH NPW_HOST_LIBDIR "/" NPW_WRAPPER #define NPW_PLUGIN_INFO_VERSION 2 -#define NPW_PLUGIN_IDENT "NPW:X:" NPW_VERSION +#define NPW_PLUGIN_IDENT "NPW:X:" NPW_FULL_VERSION #define NPW_PLUGIN_IDENT_SIZE 32 typedef struct __attribute__((packed)) { char ident[NPW_PLUGIN_IDENT_SIZE]; From e9aeade7cd82aba2f9ec8dd6d47e10bc5145e241 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 21 Apr 2011 16:06:27 -0400 Subject: [PATCH 32/91] Don't leak the NPN_SetException string What's this about? Both Firefox and Chrome make a copy of it. (In fact, Firefox apparently doesn't implement it for their out-of-process plugin code. But their old codepath handles it fine. --- src/npw-wrapper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index f3cc662..f037339 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -1624,7 +1624,8 @@ static int handle_NPN_SetException(rpc_connection_t *connection) if (npobj) NPN_ReleaseObject(npobj); - // XXX memory leak (message) + if (message) + free(message); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } From 31dcc57f691422f360b03f8a0543bb1c1c5ac3e7 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 21 Apr 2011 16:10:47 -0400 Subject: [PATCH 33/91] Use NPN_ReallocData to reallocate NPPVformValue and Enumerate output Saves a little bit of code. Also some of the enumerate code was bogus. Also actually reallocate NPClass::Enumerate array. Oops, must have missed that one. --- src/npruntime.c | 13 ++++++++++++- src/npw-viewer.c | 12 ++++-------- src/npw-wrapper.c | 11 ++++------- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/npruntime.c b/src/npruntime.c index 93b80b5..ad93df7 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -944,9 +944,11 @@ static bool npclass_invoke_Enumerate(NPObject *npobj, } uint32_t ret; + uint32_t myCount = 0; + NPIdentifier *myIdentifiers = NULL; error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_UINT32, &ret, - RPC_TYPE_ARRAY, RPC_TYPE_NP_IDENTIFIER, count, idents, + RPC_TYPE_ARRAY, RPC_TYPE_NP_IDENTIFIER, &myCount, &myIdentifiers, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -954,6 +956,15 @@ static bool npclass_invoke_Enumerate(NPObject *npobj, return false; } + *count = myCount; + if (ret) { + ret = NPW_ReallocData(myIdentifiers, + sizeof(**idents) * myCount, + (void**)idents) == NPERR_NO_ERROR; + } + if (myIdentifiers) + free(myIdentifiers); + return ret; } diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 0a6e81b..f955993 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -2541,15 +2541,11 @@ invoke_NPN_Enumerate(PluginInstance *plugin, NPObject *npobj, } *count = myCount; - if (ret && myIdentifiers) { - *identifiers = NPN_MemAlloc(sizeof(**identifiers) * myCount); - if (*identifiers == NULL) { - ret = NPERR_OUT_OF_MEMORY_ERROR; - } else { - memcpy(*identifiers, myIdentifiers, sizeof(**identifiers) * myCount); - } + if (ret) { + ret = NPW_ReallocData(myIdentifiers, + sizeof(**identifiers) * myCount, + (void**)identifiers) == NPERR_NO_ERROR; } - if (myIdentifiers) free(myIdentifiers); diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index f037339..e23cd2f 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -2295,14 +2295,11 @@ invoke_NPP_GetValue(PluginInstance *plugin, NPPVariable variable, void *value) switch (variable) { case NPPVformValue: // this is a '\0'-terminated UTF-8 string data allocated by NPN_MemAlloc() - if (ret == NPERR_NO_ERROR && str) { - char *utf8_str = g_NPN_MemAlloc(strlen(str) + 1); - if (utf8_str == NULL) - ret = NPERR_OUT_OF_MEMORY_ERROR; - else - strcpy(utf8_str, str); + if (ret == NPERR_NO_ERROR) { + char *npn_str = NULL; + ret = NPW_ReallocData(str, strlen(str) + 1, (void**)&npn_str); free(str); - str = utf8_str; + str = npn_str; } break; default: From cc47a002929c172c014e30d24bc0356347a3aacf Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 21 Apr 2011 19:21:47 -0400 Subject: [PATCH 34/91] Don't check gtk_plug_new and gtk_socket_new for NULL Neither can actually return NULL. --- src/npw-viewer.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/npw-viewer.c b/src/npw-viewer.c index f955993..ccfa95f 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -773,13 +773,9 @@ static int create_window(PluginInstance *plugin, NPWindow *window) if (toolkit == NULL) return -1; toolkit->container = gtk_plug_new((GdkNativeWindow)window->window); - if (toolkit->container == NULL) - return -1; gtk_widget_set_size_request(toolkit->container, window->width, window->height); gtk_widget_show(toolkit->container); toolkit->socket = gtk_socket_new(); - if (toolkit->socket == NULL) - return -1; gtk_widget_show(toolkit->socket); gtk_container_add(GTK_CONTAINER(toolkit->container), toolkit->socket); gtk_widget_show_all(toolkit->container); From 0bdca9b12679d74ac4f41419a8a64234ee351217 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 22 Apr 2011 22:55:01 -0400 Subject: [PATCH 35/91] Add more debug statements in npobject_destroy_stub In case it fails in the middle or something. --- src/npruntime.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/npruntime.c b/src/npruntime.c index ad93df7..133912a 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -103,10 +103,11 @@ NPObject *npobject_lookup_local(uint32_t id) static void npobject_destroy_stub_obj(NPObjectStub *stub) { - D(bug("npobject_destroy_stub: id=0x%x\n", stub->id)); + D(bugiI("npobject_destroy_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); + D(bugiD("npobject_destroy_stub done\n")); } void npobject_destroy_stub(uint32_t id) From 30021085d3d3b09b6568e0697fd1177bf8d01f84 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 22 Apr 2011 22:57:06 -0400 Subject: [PATCH 36/91] Release received NPObjects in npruntime handler functions Missed a few spots there. --- src/npruntime.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/npruntime.c b/src/npruntime.c index 133912a..b4776d7 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -341,6 +341,9 @@ static int npclass_handle_HasMethod(rpc_connection_t *connection) D(bugiD("NPClass::HasMethod return: %d\n", ret)); } + if (npobj) + NPN_ReleaseObject(npobj); + return rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, RPC_TYPE_INVALID); @@ -420,6 +423,8 @@ static int npclass_handle_Invoke(rpc_connection_t *connection) g_free(result_str); } + if (npobj) + NPN_ReleaseObject(npobj); if (args) { for (int i = 0; i < argCount; i++) NPN_ReleaseVariantValue(&args[i]); @@ -517,6 +522,8 @@ static int npclass_handle_InvokeDefault(rpc_connection_t *connection) g_free(result_str); } + if (npobj) + NPN_ReleaseObject(npobj); if (args) { for (int i = 0; i < argCount; i++) NPN_ReleaseVariantValue(&args[i]); @@ -607,6 +614,9 @@ static int npclass_handle_HasProperty(rpc_connection_t *connection) D(bugiD("NPClass::HasProperty return: %d\n", ret)); } + if (npobj) + NPN_ReleaseObject(npobj); + return rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, RPC_TYPE_INVALID); @@ -682,6 +692,9 @@ static int npclass_handle_GetProperty(rpc_connection_t *connection) g_free(result_str); } + if (npobj) + NPN_ReleaseObject(npobj); + return rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, RPC_TYPE_NP_VARIANT_PASS_REF, &result, @@ -765,6 +778,8 @@ static int npclass_handle_SetProperty(rpc_connection_t *connection) D(bugiD("NPClass::SetProperty return: %d\n", ret)); } + if (npobj) + NPN_ReleaseObject(npobj); NPN_ReleaseVariantValue(&value); return rpc_method_send_reply(connection, @@ -846,6 +861,9 @@ static int npclass_handle_RemoveProperty(rpc_connection_t *connection) D(bugiD("NPClass::RemoveProperty return: %d\n", ret)); } + if (npobj) + NPN_ReleaseObject(npobj); + return rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, RPC_TYPE_INVALID); @@ -920,6 +938,9 @@ static int npclass_handle_Enumerate(rpc_connection_t *connection) D(bugiD("NPClass::Enumerate return: %d (%d identifiers)\n", ret, argCount)); } + if (npobj) + NPN_ReleaseObject(npobj); + int rpc_ret = rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, RPC_TYPE_ARRAY, RPC_TYPE_NP_IDENTIFIER, argCount, idents, @@ -1020,6 +1041,8 @@ static int npclass_handle_Construct(rpc_connection_t *connection) g_free(result_str); } + if (npobj) + NPN_ReleaseObject(npobj); if (args) { for (int i = 0; i < argCount; i++) NPN_ReleaseVariantValue(&args[i]); From 189a5244a3a28cfad018815de4cbb756453441ed Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 23 Apr 2011 13:57:45 -0400 Subject: [PATCH 37/91] Add an explicit npobject_is_proxy check For obnoxious reasons, NPN_CreateObject needs to know if an object is a proxy before its proxy fields have been initialized. We can't assume proxy_id == 0 means not a proxy. Valgrind gets upset. --- src/npruntime-impl.h | 1 + src/npruntime.c | 5 +++++ src/npw-viewer.c | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/npruntime-impl.h b/src/npruntime-impl.h index d3595b1..4adca89 100644 --- a/src/npruntime-impl.h +++ b/src/npruntime-impl.h @@ -41,6 +41,7 @@ extern NPObject *npobject_lookup_local(uint32_t id) attribute_hidden; // corresponding stub. Holds a reference to the other NPObject on via // its stub. extern NPObject *npobject_create_proxy(NPP npp, uint32_t id) attribute_hidden; +extern bool npobject_is_proxy(NPObject *npobj) attribute_hidden; extern uint32_t npobject_get_proxy_id(NPObject *npobj) attribute_hidden; extern void npobject_destroy_proxy(NPObject *npobj, bool release_stub) attribute_hidden; diff --git a/src/npruntime.c b/src/npruntime.c index b4776d7..e6ddac1 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -153,6 +153,11 @@ NPObject *npobject_create_proxy(NPP instance, uint32_t id) return object; } +bool npobject_is_proxy(NPObject *npobj) +{ + return npobject_get_proxy(npobj) != NULL; +} + uint32_t npobject_get_proxy_id(NPObject *npobj) { NPObjectProxy *proxy = npobject_get_proxy(npobj); diff --git a/src/npw-viewer.c b/src/npw-viewer.c index ccfa95f..a84e8bc 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -1958,7 +1958,9 @@ g_NPN_CreateObject(NPP instance, NPClass *class) npobj->_class = class; npobj->referenceCount = 1; - if (npobject_get_proxy_id(npobj) == 0) { + // We specifically cannot call npobject_get_proxy_id here because + // the proxy has only been allocated, not constructed. (Sigh.) + if (!npobject_is_proxy(npobj)) { // Register anything that isn't a proxy. npobject_register(npobj, plugin); if (plugin) From 857234e5f180b0080fe2e386c708cd7a3246a4db Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 23 Apr 2011 14:20:17 -0400 Subject: [PATCH 38/91] Revert "Decrease the RPC message timeout from 30 seconds to 10" This reverts commit 1b259a81191aeec65f4c59c8dc321b05bf052e27. If you call a function from Flash that ends up opening an alert, the call blocks until the user closes the alert, and the call eventually times out. A 30 second timeout isn't much better, but is harder to trigger accidentally, whereas it's not difficult to trigger a 10 second timeout on accident. See bug #24. --- src/rpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc.c b/src/rpc.c index deb9a69..c285e2e 100644 --- a/src/rpc.c +++ b/src/rpc.c @@ -68,7 +68,7 @@ // Define the maximum amount of time (in seconds) to wait for a message #ifndef RPC_MESSAGE_TIMEOUT -#define RPC_MESSAGE_TIMEOUT 10 +#define RPC_MESSAGE_TIMEOUT 30 #endif // Define the maximum amount of time (in seconds) to wait for plugin connection From fd8fd73ac0de669cfee0291476e0b17fa2caed88 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 23 Apr 2011 14:39:00 -0400 Subject: [PATCH 39/91] nspluginwrapper 1.3.2 --- NEWS | 19 ++++++++++++++++++- nspluginwrapper.spec | 2 +- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 834e400..0f82857 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,22 @@ -nspluginwrapper NEWS -- history of user-visible changes. 2009-01-02 +nspluginwrapper NEWS -- history of user-visible changes. 2011-04-23 Copyright (C) 2005-2009 Gwenole Beauchesne + (C) 2011 David Benjamin + +Version 1.3.2 (BETA) - 23.Apr.2011 +* Work around lack of client-side windows in Flash +* Fix race condition when NPP_Destroy was called while viewer is busy +* Fix build on modern Linux platforms +* Support NPAPI 0.24, in particular, Flash can now query for private browsing +* Don't export any symbols but those necessary +* Support XEmbeding npplayer into another application +* Remove NPClass::HasMethod cache; it was incorrect +* Fix initializing two wrapped plugins with the same name in the same process +* Work around Qt bug that breaks npplayer when Kopete is installed +* Release implicit grabs before forwarding events to fix Flash context menu hang +* Work around Firefox quirk that broke windowless Flash in Firefox 4 +* Bind wrapper and viewer event loops together to avoid many many race conditions +* Redesign NPRuntime bridge to avoid leaking proxy objects +* Incorportate release number into ident string so update works on distro patches Version 1.3.0 (BETA) - 02.Jan.2009 * Don't poll for Xt events in Gtk (XEMBED) plug-ins diff --git a/nspluginwrapper.spec b/nspluginwrapper.spec index 50dcb75..301bb6c 100644 --- a/nspluginwrapper.spec +++ b/nspluginwrapper.spec @@ -1,5 +1,5 @@ %define name nspluginwrapper -%define version 1.3.0 +%define version 1.3.2 %define release 1 #define svndate DATE From eab4684a2ff04b8b7370a51ed30fca749a950198 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 26 Apr 2011 14:26:09 -0400 Subject: [PATCH 40/91] Fix comment typo --- src/npw-wrapper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index e23cd2f..a534e4b 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -959,7 +959,7 @@ static int handle_NPN_NewStream(rpc_connection_t *connection) RPC_TYPE_INVALID); } -// NPN_DestroySream +// NPN_DestroyStream static NPError g_NPN_DestroyStream(NPP instance, NPStream *stream, NPReason reason) { From a8017830effdc502f7c8862f78b44b1424ae776c Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 27 Apr 2011 10:06:42 -0400 Subject: [PATCH 41/91] Add header file to iteration over browser and plugin functions Saves a bit of effort, and simplifies capability passing. We lose the npruntime logic, but we may as well unconditionally initialize the bridge. It's cheap and every browser should have it by now. --- src/browser-funcs.h | 75 +++++++++++++++++++++++++++++++++++++ src/npw-viewer.c | 64 +++++--------------------------- src/npw-wrapper.c | 90 +++++++-------------------------------------- src/plugin-funcs.h | 38 +++++++++++++++++++ 4 files changed, 136 insertions(+), 131 deletions(-) create mode 100644 src/browser-funcs.h create mode 100644 src/plugin-funcs.h diff --git a/src/browser-funcs.h b/src/browser-funcs.h new file mode 100644 index 0000000..8f9ff63 --- /dev/null +++ b/src/browser-funcs.h @@ -0,0 +1,75 @@ +/* + * browser-funcs.h - Browser functions + * + * nspluginwrapper (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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +BROWSER_FUNC(NPN_GetURL, geturl) +BROWSER_FUNC(NPN_PostURL, posturl) +BROWSER_FUNC(NPN_RequestRead, requestread) +BROWSER_FUNC(NPN_NewStream, newstream) +BROWSER_FUNC(NPN_Write, write) +BROWSER_FUNC(NPN_DestroyStream, destroystream) +BROWSER_FUNC(NPN_Status, status) +BROWSER_FUNC(NPN_UserAgent, uagent) +BROWSER_FUNC(NPN_MemAlloc, memalloc) +BROWSER_FUNC(NPN_MemFree, memfree) +BROWSER_FUNC(NPN_MemFlush, memflush) +BROWSER_FUNC(NPN_ReloadPlugins, reloadplugins) +BROWSER_FUNC(NPN_GetJavaEnv, getJavaEnv) +BROWSER_FUNC(NPN_GetJavaPeer, getJavaPeer) +BROWSER_FUNC(NPN_GetURLNotify, geturlnotify) +BROWSER_FUNC(NPN_PostURLNotify, posturlnotify) +BROWSER_FUNC(NPN_GetValue, getvalue) +BROWSER_FUNC(NPN_SetValue, setvalue) +BROWSER_FUNC(NPN_InvalidateRect, invalidaterect) +BROWSER_FUNC(NPN_InvalidateRegion, invalidateregion) +BROWSER_FUNC(NPN_ForceRedraw, forceredraw) +BROWSER_FUNC(NPN_GetStringIdentifier, getstringidentifier) +BROWSER_FUNC(NPN_GetStringIdentifiers, getstringidentifiers) +BROWSER_FUNC(NPN_GetIntIdentifier, getintidentifier) +BROWSER_FUNC(NPN_IdentifierIsString, identifierisstring) +BROWSER_FUNC(NPN_UTF8FromIdentifier, utf8fromidentifier) +BROWSER_FUNC(NPN_IntFromIdentifier, intfromidentifier) +BROWSER_FUNC(NPN_CreateObject, createobject) +BROWSER_FUNC(NPN_RetainObject, retainobject) +BROWSER_FUNC(NPN_ReleaseObject, releaseobject) +BROWSER_FUNC(NPN_Invoke, invoke) +BROWSER_FUNC(NPN_InvokeDefault, invokeDefault) +BROWSER_FUNC(NPN_Evaluate, evaluate) +BROWSER_FUNC(NPN_GetProperty, getproperty) +BROWSER_FUNC(NPN_SetProperty, setproperty) +BROWSER_FUNC(NPN_RemoveProperty, removeproperty) +BROWSER_FUNC(NPN_HasProperty, hasproperty) +BROWSER_FUNC(NPN_HasMethod, hasmethod) +BROWSER_FUNC(NPN_ReleaseVariantValue, releasevariantvalue) +BROWSER_FUNC(NPN_SetException, setexception) +BROWSER_FUNC(NPN_PushPopupsEnabledState, pushpopupsenabledstate) +BROWSER_FUNC(NPN_PopPopupsEnabledState, poppopupsenabledstate) +BROWSER_FUNC(NPN_Enumerate, enumerate) +BROWSER_FUNC(NPN_PluginThreadAsyncCall, pluginthreadasynccall) +BROWSER_FUNC(NPN_Construct, construct) +BROWSER_FUNC(NPN_GetValueForURL, getvalueforurl) +BROWSER_FUNC(NPN_SetValueForURL, setvalueforurl) +BROWSER_FUNC(NPN_GetAuthenticationInfo, getauthenticationinfo) +BROWSER_FUNC(NPN_ScheduleTimer, scheduletimer) +BROWSER_FUNC(NPN_UnscheduleTimer, unscheduletimer) +// BROWSER_FUNC(NPN_PopUpContextMenu, popupcontextmenu) +// BROWSER_FUNC(NPN_ConvertPoint, convertpoint) +// BROWSER_FUNC(NPN_HandleEvent, handleevent) +// BROWSER_FUNC(NPN_UnfocusInstance, unfocusinstance) +// BROWSER_FUNC(NPN_URLRedirectResponse, urlredirectresponse) diff --git a/src/npw-viewer.c b/src/npw-viewer.c index a84e8bc..b5f93a4 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -3560,62 +3560,17 @@ g_NP_Initialize(uint32_t version, uint32_t *plugin_version) memset(&mozilla_funcs, 0, sizeof(mozilla_funcs)); mozilla_funcs.size = sizeof(mozilla_funcs); mozilla_funcs.version = version; - mozilla_funcs.geturl = g_NPN_GetURL; - mozilla_funcs.posturl = g_NPN_PostURL; - mozilla_funcs.requestread = g_NPN_RequestRead; - mozilla_funcs.newstream = g_NPN_NewStream; - mozilla_funcs.write = g_NPN_Write; - mozilla_funcs.destroystream = g_NPN_DestroyStream; - mozilla_funcs.status = g_NPN_Status; - mozilla_funcs.uagent = g_NPN_UserAgent; - mozilla_funcs.memalloc = g_NPN_MemAlloc; - mozilla_funcs.memfree = g_NPN_MemFree; - mozilla_funcs.memflush = g_NPN_MemFlush; - mozilla_funcs.reloadplugins = g_NPN_ReloadPlugins; - mozilla_funcs.getJavaEnv = g_NPN_GetJavaEnv; - mozilla_funcs.getJavaPeer = g_NPN_GetJavaPeer; - mozilla_funcs.geturlnotify = g_NPN_GetURLNotify; - mozilla_funcs.posturlnotify = g_NPN_PostURLNotify; - mozilla_funcs.getvalue = g_NPN_GetValue; - mozilla_funcs.setvalue = g_NPN_SetValue; - mozilla_funcs.invalidaterect = g_NPN_InvalidateRect; - mozilla_funcs.invalidateregion = g_NPN_InvalidateRegion; - mozilla_funcs.forceredraw = g_NPN_ForceRedraw; - mozilla_funcs.pushpopupsenabledstate = g_NPN_PushPopupsEnabledState; - mozilla_funcs.poppopupsenabledstate = g_NPN_PopPopupsEnabledState; - mozilla_funcs.pluginthreadasynccall = g_NPN_PluginThreadAsyncCall; - mozilla_funcs.getvalueforurl = g_NPN_GetValueForURL; - mozilla_funcs.setvalueforurl = g_NPN_SetValueForURL; - mozilla_funcs.getauthenticationinfo = g_NPN_GetAuthenticationInfo; - mozilla_funcs.scheduletimer = g_NPN_ScheduleTimer; - mozilla_funcs.unscheduletimer = g_NPN_UnscheduleTimer; + // TODO: query for support. +#define BROWSER_FUNC(func, member) \ + mozilla_funcs.member = g_ ## func; +#include "browser-funcs.h" +#undef BROWSER_FUNC + + if (!npobject_bridge_new()) + return NPERR_OUT_OF_MEMORY_ERROR; if (NPN_HAS_FEATURE(NPRUNTIME_SCRIPTING)) { D(bug(" browser supports scripting through npruntime\n")); - mozilla_funcs.getstringidentifier = g_NPN_GetStringIdentifier; - mozilla_funcs.getstringidentifiers = g_NPN_GetStringIdentifiers; - mozilla_funcs.getintidentifier = g_NPN_GetIntIdentifier; - mozilla_funcs.identifierisstring = g_NPN_IdentifierIsString; - mozilla_funcs.utf8fromidentifier = g_NPN_UTF8FromIdentifier; - mozilla_funcs.intfromidentifier = g_NPN_IntFromIdentifier; - mozilla_funcs.createobject = g_NPN_CreateObject; - mozilla_funcs.retainobject = g_NPN_RetainObject; - mozilla_funcs.releaseobject = g_NPN_ReleaseObject; - mozilla_funcs.invoke = g_NPN_Invoke; - mozilla_funcs.invokeDefault = g_NPN_InvokeDefault; - mozilla_funcs.evaluate = g_NPN_Evaluate; - mozilla_funcs.getproperty = g_NPN_GetProperty; - mozilla_funcs.setproperty = g_NPN_SetProperty; - mozilla_funcs.removeproperty = g_NPN_RemoveProperty; - mozilla_funcs.hasproperty = g_NPN_HasProperty; - mozilla_funcs.hasmethod = g_NPN_HasMethod; - mozilla_funcs.releasevariantvalue = g_NPN_ReleaseVariantValue; - mozilla_funcs.setexception = g_NPN_SetException; - mozilla_funcs.enumerate = g_NPN_Enumerate; - mozilla_funcs.construct = g_NPN_Construct; - - if (!npobject_bridge_new()) - return NPERR_OUT_OF_MEMORY_ERROR; } // Initialize function tables @@ -3662,8 +3617,7 @@ g_NP_Shutdown(void) NPError ret = g_plugin_NP_Shutdown(); D(bugiD("NP_Shutdown done\n")); - if (NPN_HAS_FEATURE(NPRUNTIME_SCRIPTING)) - npobject_bridge_destroy(); + npobject_bridge_destroy(); g_is_running = false; diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index a534e4b..d064bae 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -3428,69 +3428,16 @@ static NPError invoke_NP_Initialize(uint32_t npapi_version, uint32_t *plugin_version) { if (PLUGIN_DIRECT_EXEC) { - NPNetscapeFuncs mozilla_funcs; - memset(&mozilla_funcs, 0, sizeof(mozilla_funcs)); - mozilla_funcs.size = sizeof(mozilla_funcs); - mozilla_funcs.version = npapi_version; - mozilla_funcs.geturl = g_NPN_GetURL; - mozilla_funcs.posturl = g_NPN_PostURL; - mozilla_funcs.requestread = g_NPN_RequestRead; - mozilla_funcs.newstream = g_NPN_NewStream; - mozilla_funcs.write = g_NPN_Write; - mozilla_funcs.destroystream = g_NPN_DestroyStream; - mozilla_funcs.status = g_NPN_Status; - mozilla_funcs.uagent = g_NPN_UserAgent; - mozilla_funcs.memalloc = g_NPN_MemAlloc; - mozilla_funcs.memfree = g_NPN_MemFree; - mozilla_funcs.memflush = g_NPN_MemFlush; - mozilla_funcs.reloadplugins = g_NPN_ReloadPlugins; - mozilla_funcs.getJavaEnv = g_NPN_GetJavaEnv; - mozilla_funcs.getJavaPeer = g_NPN_GetJavaPeer; - mozilla_funcs.geturlnotify = g_NPN_GetURLNotify; - mozilla_funcs.posturlnotify = g_NPN_PostURLNotify; - mozilla_funcs.getvalue = g_NPN_GetValue; - mozilla_funcs.setvalue = g_NPN_SetValue; - mozilla_funcs.invalidaterect = g_NPN_InvalidateRect; - mozilla_funcs.invalidateregion = g_NPN_InvalidateRegion; - mozilla_funcs.forceredraw = g_NPN_ForceRedraw; - mozilla_funcs.pushpopupsenabledstate = g_NPN_PushPopupsEnabledState; - mozilla_funcs.poppopupsenabledstate = g_NPN_PopPopupsEnabledState; - mozilla_funcs.getvalueforurl = g_NPN_GetValueForURL; - mozilla_funcs.setvalueforurl = g_NPN_SetValueForURL; - mozilla_funcs.getauthenticationinfo = g_NPN_GetAuthenticationInfo; - if ((npapi_version & 0xff) >= NPVERS_HAS_NPRUNTIME_SCRIPTING) { - mozilla_funcs.getstringidentifier = g_NPN_GetStringIdentifier; - mozilla_funcs.getstringidentifiers = g_NPN_GetStringIdentifiers; - mozilla_funcs.getintidentifier = g_NPN_GetIntIdentifier; - mozilla_funcs.identifierisstring = g_NPN_IdentifierIsString; - mozilla_funcs.utf8fromidentifier = g_NPN_UTF8FromIdentifier; - mozilla_funcs.intfromidentifier = g_NPN_IntFromIdentifier; - mozilla_funcs.createobject = g_NPN_CreateObject; - mozilla_funcs.retainobject = g_NPN_RetainObject; - mozilla_funcs.releaseobject = g_NPN_ReleaseObject; - mozilla_funcs.invoke = g_NPN_Invoke; - mozilla_funcs.invokeDefault = g_NPN_InvokeDefault; - mozilla_funcs.evaluate = g_NPN_Evaluate; - mozilla_funcs.getproperty = g_NPN_GetProperty; - mozilla_funcs.setproperty = g_NPN_SetProperty; - mozilla_funcs.removeproperty = g_NPN_RemoveProperty; - mozilla_funcs.hasproperty = g_NPN_HasProperty; - mozilla_funcs.hasmethod = g_NPN_HasMethod; - mozilla_funcs.releasevariantvalue = g_NPN_ReleaseVariantValue; - mozilla_funcs.setexception = g_NPN_SetException; - mozilla_funcs.enumerate = g_NPN_Enumerate; - mozilla_funcs.construct = g_NPN_Construct; - } - if ((npapi_version & 0xff) >= NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL) { - // Avoid pretending we have support for this if we really don't. - mozilla_funcs.pluginthreadasynccall = g_NPN_PluginThreadAsyncCall; - } - if ((npapi_version & 0xff) >= NPVERS_MACOSX_HAS_COCOA_EVENTS) { - // Avoid pretending we have support for this if we really don't. - mozilla_funcs.scheduletimer = g_NPN_ScheduleTimer; - mozilla_funcs.unscheduletimer = g_NPN_UnscheduleTimer; - } - NPError error = g_plugin_NP_Initialize(&mozilla_funcs, &plugin_funcs); + NPNetscapeFuncs wrapped_mozilla_funcs; + memset(&wrapped_mozilla_funcs, 0, sizeof(wrapped_mozilla_funcs)); + wrapped_mozilla_funcs.size = sizeof(wrapped_mozilla_funcs); + wrapped_mozilla_funcs.version = npapi_version; +#define BROWSER_FUNC(func, member) \ + if (mozilla_funcs.member != NULL) \ + wrapped_mozilla_funcs.member = g_ ## func; +#include "browser-funcs.h" +#undef BROWSER_FUNC + NPError error = g_plugin_NP_Initialize(&wrapped_mozilla_funcs, &plugin_funcs); *plugin_version = plugin_funcs.version; return error; } @@ -3555,20 +3502,11 @@ NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs) memset(&full_plugin_funcs, 0, sizeof(full_plugin_funcs)); full_plugin_funcs.size = sizeof(NPPluginFuncs); full_plugin_funcs.version = NPW_NPAPI_VERSION; - full_plugin_funcs.newp = g_NPP_New; - full_plugin_funcs.destroy = g_NPP_Destroy; - full_plugin_funcs.setwindow = g_NPP_SetWindow; - full_plugin_funcs.newstream = g_NPP_NewStream; - full_plugin_funcs.destroystream = g_NPP_DestroyStream; - full_plugin_funcs.asfile = g_NPP_StreamAsFile; - full_plugin_funcs.writeready = g_NPP_WriteReady; - full_plugin_funcs.write = g_NPP_Write; - full_plugin_funcs.print = g_NPP_Print; - full_plugin_funcs.event = g_NPP_HandleEvent; - full_plugin_funcs.urlnotify = g_NPP_URLNotify; +#define PLUGIN_FUNC(func, member) \ + full_plugin_funcs.member = g_ ## func; +#include "plugin-funcs.h" +#undef PLUGIN_FUNC full_plugin_funcs.javaClass = NULL; - full_plugin_funcs.getvalue = g_NPP_GetValue; - full_plugin_funcs.setvalue = g_NPP_SetValue; // override function table with an additional thunking layer for // possibly broken 64-bit Konqueror versions (NPAPI 0.11) diff --git a/src/plugin-funcs.h b/src/plugin-funcs.h new file mode 100644 index 0000000..e8f3909 --- /dev/null +++ b/src/plugin-funcs.h @@ -0,0 +1,38 @@ +/* + * plugin-funcs.h - Plugin functions + * + * nspluginwrapper (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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +PLUGIN_FUNC(NPP_New, newp) +PLUGIN_FUNC(NPP_Destroy, destroy) +PLUGIN_FUNC(NPP_SetWindow, setwindow) +PLUGIN_FUNC(NPP_NewStream, newstream) +PLUGIN_FUNC(NPP_DestroyStream, destroystream) +PLUGIN_FUNC(NPP_StreamAsFile, asfile) +PLUGIN_FUNC(NPP_WriteReady, writeready) +PLUGIN_FUNC(NPP_Write, write) +PLUGIN_FUNC(NPP_Print, print) +PLUGIN_FUNC(NPP_HandleEvent, event) +PLUGIN_FUNC(NPP_URLNotify, urlnotify) +PLUGIN_FUNC(NPP_GetValue, getvalue) +PLUGIN_FUNC(NPP_SetValue, setvalue) +// PLUGIN_FUNC(NPP_GotFocus, gotfocus) +// PLUGIN_FUNC(NPP_LostFocus, lostfocus) +// PLUGIN_FUNC(NPP_URLRedirectNotify, urlredirectnotify) +// PLUGIN_FUNC(NPP_ClearSiteData, clearsitedata) +// PLUGIN_FUNC(NPP_GetSitesWithData, getsiteswithdata) From 0209a6814c81f03e0c469e243b5ae420eab35693 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 27 Apr 2011 10:58:08 -0400 Subject: [PATCH 42/91] Report browser and plugin hooks as NULL when not provided Fixes bug #7. --- src/npw-viewer.c | 58 +++++++++++++++++++++++++++++++++++++++++++---- src/npw-wrapper.c | 57 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 105 insertions(+), 10 deletions(-) diff --git a/src/npw-viewer.c b/src/npw-viewer.c index b5f93a4..80506d4 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -3549,7 +3549,9 @@ static int handle_NP_GetValue(rpc_connection_t *connection) // NP_Initialize static NPError -g_NP_Initialize(uint32_t version, uint32_t *plugin_version) +g_NP_Initialize(uint32_t version, uint32_t *plugin_version, + uint32_t *browser_capabilities, uint32_t browser_capabilities_len, + uint32_t *plugin_capabilities, uint32_t plugin_capabilities_len) { if (g_plugin_NP_Initialize == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; @@ -3560,11 +3562,22 @@ g_NP_Initialize(uint32_t version, uint32_t *plugin_version) memset(&mozilla_funcs, 0, sizeof(mozilla_funcs)); mozilla_funcs.size = sizeof(mozilla_funcs); mozilla_funcs.version = version; - // TODO: query for support. -#define BROWSER_FUNC(func, member) \ - mozilla_funcs.member = g_ ## func; + + int num = 0; +#define BROWSER_FUNC(func, member) \ + if (num >= browser_capabilities_len) { \ + npw_printf("ERROR: capabilities length mismatch at %d: got %d\n", \ + num, browser_capabilities_len); \ + goto browser_func_done; \ + } \ + if (!browser_capabilities[num]) \ + D(bug("browser does not provide " #func "\n")); \ + else \ + mozilla_funcs.member = g_ ## func; \ + num++; #include "browser-funcs.h" #undef BROWSER_FUNC + browser_func_done: if (!npobject_bridge_new()) return NPERR_OUT_OF_MEMORY_ERROR; @@ -3580,6 +3593,21 @@ g_NP_Initialize(uint32_t version, uint32_t *plugin_version) D(bugiI("NP_Initialize version=%d\n", version)); NPError ret = g_plugin_NP_Initialize(&mozilla_funcs, &plugin_funcs); *plugin_version = plugin_funcs.version; + + if (plugin_capabilities) { + int num = 0; +#define PLUGIN_FUNC(func, member) \ + if (num >= plugin_capabilities_len) { \ + D(bug("ERROR: provided array was too small.\n")); \ + goto plugin_func_done; \ + } \ + plugin_capabilities[num] = (plugin_funcs.member != NULL); \ + num++; +#include "plugin-funcs.h" +#undef PLUGIN_FUNC + } + plugin_func_done: + D(bugiD("NP_Initialize return: %d, plugin_version=%d\n", ret, *plugin_version)); return ret; } @@ -3589,8 +3617,12 @@ static int handle_NP_Initialize(rpc_connection_t *connection) D(bug("handle_NP_Initialize\n")); uint32_t version; + uint32_t *browser_capabilities; + uint32_t browser_capabilities_len; int error = rpc_method_get_args(connection, RPC_TYPE_UINT32, &version, + RPC_TYPE_ARRAY, RPC_TYPE_UINT32, + &browser_capabilities_len, &browser_capabilities, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -3599,10 +3631,26 @@ static int handle_NP_Initialize(rpc_connection_t *connection) } uint32_t plugin_version = 0; - NPError ret = g_NP_Initialize(version, &plugin_version); + uint32_t plugin_capabilities[0 +#define PLUGIN_FUNC(func, member) \ + + 1 +#include "plugin-funcs.h" +#undef PLUGIN_FUNC + ]; + NPError ret = g_NP_Initialize(version, &plugin_version, + browser_capabilities, browser_capabilities_len, + plugin_capabilities, + G_N_ELEMENTS(plugin_capabilities)); + + if (browser_capabilities) + free(browser_capabilities); + return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_UINT32, plugin_version, + RPC_TYPE_ARRAY, RPC_TYPE_UINT32, + G_N_ELEMENTS(plugin_capabilities), + plugin_capabilities, RPC_TYPE_INVALID); } diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index d064bae..918dd26 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -3425,7 +3425,10 @@ static bool is_konqueror(void) // Provides global initialization for a plug-in static NPError -invoke_NP_Initialize(uint32_t npapi_version, uint32_t *plugin_version) +invoke_NP_Initialize(uint32_t npapi_version, + uint32_t *plugin_version, + uint32_t **plugin_capabilities, + uint32_t *plugin_capabilities_len) { if (PLUGIN_DIRECT_EXEC) { NPNetscapeFuncs wrapped_mozilla_funcs; @@ -3445,9 +3448,20 @@ invoke_NP_Initialize(uint32_t npapi_version, uint32_t *plugin_version) npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), NPERR_MODULE_LOAD_FAILED_ERROR); + // Allocate browser capabilities. + uint32_t browser_capabilities[] = { +#define BROWSER_FUNC(func, member) \ + (mozilla_funcs.member != NULL) ? 1 : 0, +#include "browser-funcs.h" +#undef BROWSER_FUNC + }; + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NP_INITIALIZE, RPC_TYPE_UINT32, npapi_version, + RPC_TYPE_ARRAY, RPC_TYPE_UINT32, + G_N_ELEMENTS(browser_capabilities), + browser_capabilities, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -3459,6 +3473,9 @@ invoke_NP_Initialize(uint32_t npapi_version, uint32_t *plugin_version) error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_UINT32, plugin_version, + RPC_TYPE_ARRAY, RPC_TYPE_UINT32, + plugin_capabilities_len, + plugin_capabilities, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -3470,10 +3487,13 @@ invoke_NP_Initialize(uint32_t npapi_version, uint32_t *plugin_version) } static NPError -g_NP_Initialize(uint32_t npapi_version, uint32_t *plugin_version) +g_NP_Initialize(uint32_t npapi_version, + uint32_t *plugin_version, + uint32_t **plugin_capabilities, uint32_t *plugin_capabilities_len) { D(bugiI("NP_Initialize\n")); - NPError ret = invoke_NP_Initialize(npapi_version, plugin_version); + NPError ret = invoke_NP_Initialize(npapi_version, plugin_version, + plugin_capabilities, plugin_capabilities_len); D(bugiD("NP_Initialize return: %d [%s], plugin_version=%d\n", ret, string_of_NPError(ret), *plugin_version)); return ret; @@ -3550,7 +3570,10 @@ NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs) D(bug("Browser supports NPAPI %d, advertising version %d to plugin\n", moz_funcs->version, npapi_version)); uint32_t plugin_version = 0; - NPError error = g_NP_Initialize(npapi_version, &plugin_version); + uint32_t *plugin_capabilities = NULL; + uint32_t plugin_capabilities_len; + NPError error = g_NP_Initialize(npapi_version, &plugin_version, + &plugin_capabilities, &plugin_capabilities_len); // Likewise, advertise the common NPAPI version between the plugin and our // thunking capabilities. @@ -3558,6 +3581,23 @@ NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs) D(bug("Plugin supports NPAPI %d, advertising version %d to browser\n", plugin_version, full_plugin_funcs.version)); + // Don't advertise any functions the plugin doesn't support. + int num = 0; +#define PLUGIN_FUNC(func, member) \ + if (num >= plugin_capabilities_len) { \ + D(bug("ERROR: provided array was too small.\n")); \ + goto plugin_func_done; \ + } \ + if (!plugin_capabilities[num]) { \ + D(bug("plugin does not support " #func "\n")); \ + full_plugin_funcs.member = NULL; \ + } \ + num++; +#include "plugin-funcs.h" +#undef PLUGIN_FUNC + plugin_func_done: + free(plugin_capabilities); + // Copy only the portion of full_plugin_funcs that the browser // understands. uint16_t plugin_funcs_size = plugin_funcs->size; @@ -3964,7 +4004,14 @@ static NPError plugin_start(void) return NPERR_MODULE_LOAD_FAILED_ERROR; uint32_t plugin_version; - return g_NP_Initialize(npapi_version, &plugin_version); + uint32_t *plugin_capabilities = NULL; + uint32_t plugin_capabilities_len; + NPError ret = g_NP_Initialize(npapi_version, &plugin_version, + &plugin_capabilities, &plugin_capabilities_len); + // Assume capabilities unchanged. + if (plugin_capabilities) + free(plugin_capabilities); + return ret; } static NPError plugin_start_if_needed(void) From c9a15440ef6d37931fefa3e0269537e44bd54086 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 28 Apr 2011 19:25:38 -0400 Subject: [PATCH 43/91] Always provide the event loop functions It doesn't matter whether or not the browser handles them, we always do. --- src/npw-viewer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 80506d4..5cae158 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -3579,6 +3579,12 @@ g_NP_Initialize(uint32_t version, uint32_t *plugin_version, #undef BROWSER_FUNC browser_func_done: + // Unconditionally provide NPN_PluginThreadAsyncCall and the timer + // functions. They require no browser support. + mozilla_funcs.pluginthreadasynccall = g_NPN_PluginThreadAsyncCall; + mozilla_funcs.scheduletimer = g_NPN_ScheduleTimer; + mozilla_funcs.unscheduletimer = g_NPN_UnscheduleTimer; + if (!npobject_bridge_new()) return NPERR_OUT_OF_MEMORY_ERROR; From 272e74cbf9b53bd0f81933780952fae25fde3c05 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 13 May 2011 16:49:52 -0400 Subject: [PATCH 44/91] Kill npw_asprintf It's not used anywhere and glib provides g_strdup_printf anyway. --- src/utils.c | 19 ------------------- src/utils.h | 1 - 2 files changed, 20 deletions(-) diff --git a/src/utils.c b/src/utils.c index 80b110d..4f9e47e 100644 --- a/src/utils.c +++ b/src/utils.c @@ -372,25 +372,6 @@ const char *npw_strerror(int error) return "Unknown error"; } -char *npw_asprintf(const char *format, ...) -{ - va_list args; - va_start(args, format); - int alen = vsnprintf(NULL, 0, format, args); - va_end(args); - char *str = malloc(alen+1); - if (str == NULL) - return NULL; - va_start(args, format); - int rlen = vsnprintf(str, alen+1, format, args); - va_end(args); - if (rlen != alen) { - free(str); - return NULL; - } - return str; -} - /* Return 1 + max value the system can allocate to a new fd */ static int get_open_max(void) { diff --git a/src/utils.h b/src/utils.h index cb1b5d6..a0e2423 100644 --- a/src/utils.h +++ b/src/utils.h @@ -49,7 +49,6 @@ extern const char *string_of_NPWindowType(int type) attribute_hidden; // Misc utility functions extern void npw_perror(const char *prefix, int error) attribute_hidden; extern const char *npw_strerror(int error) attribute_hidden; -extern G_GNUC_PRINTF(1, 2) char *npw_asprintf(const char *format, ...) attribute_hidden; extern void npw_close_all_open_files(void) attribute_hidden; #ifdef __cplusplus From 25ea7083d6463387d608a04bc56e95d373633e0b Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 13 May 2011 18:30:24 -0400 Subject: [PATCH 45/91] Pass the version to NP_Initialize in NPPluginFuncs Flash 10.3 expects to find a version in there. --- src/npw-viewer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 5cae158..4768948 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -3558,6 +3558,7 @@ g_NP_Initialize(uint32_t version, uint32_t *plugin_version, memset(&plugin_funcs, 0, sizeof(plugin_funcs)); plugin_funcs.size = sizeof(plugin_funcs); + plugin_funcs.version = version; memset(&mozilla_funcs, 0, sizeof(mozilla_funcs)); mozilla_funcs.size = sizeof(mozilla_funcs); From 3050d01ac0adb247cca3092d68fb7c966490390e Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 13 May 2011 19:00:44 -0400 Subject: [PATCH 46/91] Don't check capabilities in PLUGIN_DIRECT_EXEC --- src/npw-wrapper.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index 918dd26..f72eebf 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -3581,22 +3581,24 @@ NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs) D(bug("Plugin supports NPAPI %d, advertising version %d to browser\n", plugin_version, full_plugin_funcs.version)); - // Don't advertise any functions the plugin doesn't support. - int num = 0; + if (!PLUGIN_DIRECT_EXEC) { + // Don't advertise any functions the plugin doesn't support. + int num = 0; #define PLUGIN_FUNC(func, member) \ - if (num >= plugin_capabilities_len) { \ - D(bug("ERROR: provided array was too small.\n")); \ - goto plugin_func_done; \ - } \ - if (!plugin_capabilities[num]) { \ - D(bug("plugin does not support " #func "\n")); \ - full_plugin_funcs.member = NULL; \ - } \ - num++; + if (num >= plugin_capabilities_len) { \ + D(bug("ERROR: provided array was too small.\n")); \ + goto plugin_func_done; \ + } \ + if (!plugin_capabilities[num]) { \ + D(bug("plugin does not support " #func "\n")); \ + full_plugin_funcs.member = NULL; \ + } \ + num++; #include "plugin-funcs.h" #undef PLUGIN_FUNC - plugin_func_done: - free(plugin_capabilities); + plugin_func_done: + free(plugin_capabilities); + } // Copy only the portion of full_plugin_funcs that the browser // understands. From ff68174da49e464a7b41eff13cc94329865de1a7 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 13 May 2011 19:04:03 -0400 Subject: [PATCH 47/91] Refactor some code a little bit --- src/npw-wrapper.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index f72eebf..1f41272 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -3602,10 +3602,9 @@ NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs) // Copy only the portion of full_plugin_funcs that the browser // understands. - uint16_t plugin_funcs_size = plugin_funcs->size; - memcpy(plugin_funcs, &full_plugin_funcs, - MIN(plugin_funcs_size, sizeof(full_plugin_funcs))); - plugin_funcs->size = MIN(plugin_funcs_size, sizeof(full_plugin_funcs)); + uint16_t plugin_funcs_size = MIN(plugin_funcs->size, sizeof(full_plugin_funcs)); + memcpy(plugin_funcs, &full_plugin_funcs, plugin_funcs_size); + plugin_funcs->size = plugin_funcs_size; return error; } From 5d64df2accd8bcdabf7887d03c46a7f157ec2786 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 13 May 2011 18:35:06 -0400 Subject: [PATCH 48/91] Implement NPAPI ClearSiteData hooks Now that recent stable versions of Firefox, Chrome, and Flash all implement it, we should wrap it. Tested in Flash 10.3 with Chrome's 'Clear Browsing Data', Firefox's 'Clear Recent History', and Firefox's 'Forget About This Site'. It appears Flash ignores maxAge and, when asked to clear all data ever, sometimes gives NPERR_GENERIC_ERROR. But those aren't problems on our end, and it seems to otherwise work. See bug #6. --- src/npw-common.h | 2 +- src/npw-viewer.c | 83 ++++++++++++++++++++++++++++++++++ src/npw-wrapper.c | 109 +++++++++++++++++++++++++++++++++++++++++++++ src/plugin-funcs.h | 4 +- 4 files changed, 195 insertions(+), 3 deletions(-) diff --git a/src/npw-common.h b/src/npw-common.h index 184f745..183bc06 100644 --- a/src/npw-common.h +++ b/src/npw-common.h @@ -33,7 +33,7 @@ #include /* Supported NPAPI interfaces */ -#define NPW_NPAPI_VERSION 24 +#define NPW_NPAPI_VERSION 27 #define NPW_NP_CLASS_STRUCT_VERSION 3 #define NPW_TOOLKIT NPNVGtk2 diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 4768948..48e6952 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -4496,6 +4496,87 @@ static int handle_NPP_HandleEvent(rpc_connection_t *connection) return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID); } +// Clears site-data stored by the plug-in +static NPError +g_NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge) +{ + if (plugin_funcs.clearsitedata == NULL) + return NPERR_INVALID_FUNCTABLE_ERROR; + + D(bugiI("NPP_ClearSiteData site=%s, flags=%" G_GUINT64_FORMAT + ", maxAge=%" G_GUINT64_FORMAT "\n", + site ? site : "", flags, maxAge)); + NPError ret = plugin_funcs.clearsitedata(site, flags, maxAge); + D(bugiD("NPP_ClearSiteData return: %d [%s]\n", ret, string_of_NPError(ret))); + return ret; +} + +static int handle_NPP_ClearSiteData(rpc_connection_t *connection) +{ + D(bug("handle_NPP_ClearSiteData\n")); + + char *site = NULL; + uint64_t flags; + uint64_t maxAge; + int error = rpc_method_get_args(connection, + RPC_TYPE_STRING, &site, + RPC_TYPE_UINT64, &flags, + RPC_TYPE_UINT64, &maxAge, + RPC_TYPE_INVALID); + + if (error != RPC_ERROR_NO_ERROR) { + npw_perror("NPP_ClearSiteData() get args", error); + return error; + } + + NPError ret = g_NPP_ClearSiteData(site, flags, maxAge); + + if (site) + free(site); + + return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID); +} + +// Get sites with data stored by the plug-in +static char ** +g_NPP_GetSitesWithData(void) +{ + if (plugin_funcs.getsiteswithdata == NULL) + return NULL; + + D(bugiI("NPP_GetSitesWithData\n")); + char **ret = plugin_funcs.getsiteswithdata(); + D(bugiD("NPP_GetSitesWithData return: %d sites\n", + ret ? g_strv_length(ret) : 0)); + return ret; +} + +static int handle_NPP_GetSitesWithData(rpc_connection_t *connection) +{ + D(bug("handle_NPP_GetSitesWithData\n")); + + int error = rpc_method_get_args(connection, RPC_TYPE_INVALID); + if (error != RPC_ERROR_NO_ERROR) { + npw_perror("NPP_GetSitesWithData() get args", error); + return error; + } + + char **sites = g_NPP_GetSitesWithData(); + + int ret = rpc_method_send_reply(connection, + RPC_TYPE_ARRAY, RPC_TYPE_STRING, + sites ? g_strv_length(sites) : 0, sites, + RPC_TYPE_INVALID); + if (sites) { + for (int i = 0; sites[i]; i++) { + NPN_MemFree(sites[i]); + } + NPN_MemFree(sites); + } + + return ret; +} + /* ====================================================================== */ /* === Events processing === */ @@ -4829,6 +4910,8 @@ static int do_main(int argc, char **argv, const char *connection_path) { RPC_METHOD_NPP_STREAM_AS_FILE, handle_NPP_StreamAsFile }, { RPC_METHOD_NPP_PRINT, handle_NPP_Print }, { RPC_METHOD_NPP_HANDLE_EVENT, handle_NPP_HandleEvent }, + { RPC_METHOD_NPP_CLEAR_SITE_DATA, handle_NPP_ClearSiteData }, + { RPC_METHOD_NPP_GET_SITES_WITH_DATA, handle_NPP_GetSitesWithData }, }; if (rpc_connection_add_method_descriptors(g_rpc_connection, vtable, sizeof(vtable) / sizeof(vtable[0])) < 0) { npw_printf("ERROR: failed to setup NPP method callbacks\n"); diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index 1f41272..66a95a2 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -2904,6 +2904,115 @@ static int16_t g_NPP_HandleEvent(NPP instance, void *event) return ret; } +// Clears site-data stored by the plug-in +static NPError +invoke_NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge) +{ + if (PLUGIN_DIRECT_EXEC) + return plugin_funcs.clearsitedata(site, flags, maxAge); + + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), + NPERR_GENERIC_ERROR); + + int error = rpc_method_invoke(g_rpc_connection, + RPC_METHOD_NPP_CLEAR_SITE_DATA, + RPC_TYPE_STRING, site, + RPC_TYPE_UINT64, flags, + RPC_TYPE_UINT64, maxAge, + RPC_TYPE_INVALID); + + if (error != RPC_ERROR_NO_ERROR) { + npw_perror("NPP_ClearSiteData() invoke", error); + return NPERR_GENERIC_ERROR; + } + + int32_t ret; + error = rpc_method_wait_for_reply(g_rpc_connection, + RPC_TYPE_INT32, &ret, + RPC_TYPE_INVALID); + + if (error != RPC_ERROR_NO_ERROR) { + npw_perror("NPP_ClearSiteData() wait for reply", error); + return NPERR_GENERIC_ERROR; + } + + return ret; +} + +static NPError +g_NPP_ClearSiteData(const char* site, uint64_t flags, uint64_t maxAge) +{ + D(bugiI("NPP_ClearSiteData site=%s, flags=%" G_GUINT64_FORMAT + ", maxAge=%" G_GUINT64_FORMAT "\n", + site ? site : "", flags, maxAge)); + NPError ret = invoke_NPP_ClearSiteData(site, flags, maxAge); + D(bugiD("NPP_ClearSiteData return: %d [%s]\n", ret, string_of_NPError(ret))); + return ret; +} + +// Get sites with data stored by the plug-in +static char ** +invoke_NPP_GetSitesWithData(void) +{ + if (PLUGIN_DIRECT_EXEC) + return plugin_funcs.getsiteswithdata(); + + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), NULL); + + int error = rpc_method_invoke(g_rpc_connection, + RPC_METHOD_NPP_GET_SITES_WITH_DATA, + RPC_TYPE_INVALID); + + if (error != RPC_ERROR_NO_ERROR) { + npw_perror("NPP_GetSitesWithData() invoke", error); + return NULL; + } + + char **sites = NULL; + uint32_t siteCount = 0; + error = rpc_method_wait_for_reply(g_rpc_connection, + RPC_TYPE_ARRAY, RPC_TYPE_STRING, + &siteCount, &sites, + RPC_TYPE_INVALID); + if (error != RPC_ERROR_NO_ERROR) { + npw_perror("NPP_GetSitesWithData() wait for reply", error); + return NULL; + } + + // Convert this to the format NPAPI wants... ugh. + char **sites_ret = NULL; + if (siteCount > 0) { + sites_ret = NPN_MemAlloc(sizeof(char*) * (siteCount+1)); + if (sites_ret) { + for (int i = 0; i < siteCount; i++) { + // Ignore allocation failures here. + NPW_ReallocData(sites[i], strlen(sites[i]), (void**)&sites_ret[i]); + } + sites_ret[siteCount] = NULL; + } + } + + // Delete the other copy. + if (sites) { + for (int i = 0; i < siteCount; i++) { + free(sites[i]); + } + free(sites); + } + + return sites_ret; +} + +static char ** +g_NPP_GetSitesWithData(void) +{ + D(bugiI("NPP_GetSitesWithData\n")); + char **ret = invoke_NPP_GetSitesWithData(); + D(bugiD("NPP_GetSitesWithData return: %d sites\n", + ret ? g_strv_length(ret) : 0)); + return ret; +} + // Allows the browser to query the plug-in for information static NPError g_NP_GetValue(void *future, NPPVariable variable, void *value) diff --git a/src/plugin-funcs.h b/src/plugin-funcs.h index e8f3909..39f7b57 100644 --- a/src/plugin-funcs.h +++ b/src/plugin-funcs.h @@ -34,5 +34,5 @@ PLUGIN_FUNC(NPP_SetValue, setvalue) // PLUGIN_FUNC(NPP_GotFocus, gotfocus) // PLUGIN_FUNC(NPP_LostFocus, lostfocus) // PLUGIN_FUNC(NPP_URLRedirectNotify, urlredirectnotify) -// PLUGIN_FUNC(NPP_ClearSiteData, clearsitedata) -// PLUGIN_FUNC(NPP_GetSitesWithData, getsiteswithdata) +PLUGIN_FUNC(NPP_ClearSiteData, clearsitedata) +PLUGIN_FUNC(NPP_GetSitesWithData, getsiteswithdata) From 60b4157778ee89fe1e294fdfeb98d4321f30f977 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 13 May 2011 21:38:47 -0400 Subject: [PATCH 49/91] Link npw-config against glib This file needs to be replaced with something else entirely, but it'd be good to get rid of some of disturbing buffer-manipulation logic. The plugin itself depends on it anyway. --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index e11809c..ba6685a 100644 --- a/Makefile +++ b/Makefile @@ -156,7 +156,9 @@ npconfig_RAWSRCS = npw-config.c npconfig_SOURCES = $(npconfig_RAWSRCS:%.c=$(SRC_PATH)/src/%.c) npconfig_OBJECTS = $(npconfig_RAWSRCS:%.c=npconfig-%.o) npconfig_CFLAGS = $(CFLAGS) +npconfig_CFLAGS += $(GLIB_CFLAGS) npconfig_LIBS = $(libdl_LIBS) +npconfig_LIBS += $(GLIB_LIBS) npconfig_LDFLAGS = $(LDFLAGS) ifneq (,$(findstring $(OS),netbsd dragonfly)) # We will try to dlopen() the native plugin library. If that lib is From 5e7569fd2bf567dc5570642e69fd468c8eb8d60e Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 13 May 2011 21:45:03 -0400 Subject: [PATCH 50/91] Use glib's code to get the home directory No need to reinvent the wheel. --- src/npw-config.c | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/npw-config.c b/src/npw-config.c index e8827cf..32fc0b2 100644 --- a/src/npw-config.c +++ b/src/npw-config.c @@ -39,6 +39,7 @@ #include #include +#include static bool g_auto = false; static bool g_verbose = false; @@ -166,15 +167,6 @@ static int mkdir_p(const char *path) return -1; } -static const char *get_user_home_dir(void) -{ - struct passwd *pwent = getpwuid(geteuid()); - if (pwent) - return pwent->pw_dir; - - return getenv("HOME"); -} - static const char *get_system_mozilla_plugin_dir(void) { static const char default_dir[] = LIBDIR "/mozilla/plugins"; @@ -258,7 +250,7 @@ static const char *get_user_mozilla_plugin_dir(void) const char *home; static char plugin_path[PATH_MAX]; - if ((home = get_user_home_dir()) == NULL) + if ((home = g_get_home_dir()) == NULL) return NULL; sprintf(plugin_path, "%s/.mozilla/plugins", home); @@ -647,7 +639,7 @@ static bool match_path_prefix(const char *path, const char *prefix) static bool is_user_home_path(const char *path) { const char *homedir; - if ((homedir = get_user_home_dir()) == NULL) + if ((homedir = g_get_home_dir()) == NULL) return false; return match_path_prefix(path, homedir); } From 3740fd1c389f9d6fa7008e4fe0090dce80c86c00 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 13 May 2011 21:49:05 -0400 Subject: [PATCH 51/91] Don't use a static buffer for ~/.mozilla/plugins Better avoid the potential buffer overflow. --- src/npw-config.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/npw-config.c b/src/npw-config.c index 32fc0b2..237cad7 100644 --- a/src/npw-config.c +++ b/src/npw-config.c @@ -248,13 +248,15 @@ static const char *get_system_mozilla_plugin_dir(void) static const char *get_user_mozilla_plugin_dir(void) { const char *home; - static char plugin_path[PATH_MAX]; + static char *plugin_path = NULL; + + if (plugin_path != NULL) + return plugin_path; if ((home = g_get_home_dir()) == NULL) return NULL; - sprintf(plugin_path, "%s/.mozilla/plugins", home); - return plugin_path; + return (plugin_path = g_build_filename(home, ".mozilla", "plugins", NULL)); } static const char **get_mozilla_plugin_dirs(void) From abe9cae68b91c81b1094ed529da83b7ea55cf743 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 13 May 2011 21:51:14 -0400 Subject: [PATCH 52/91] Use g_build_filename in process_plugin_dir --- src/npw-config.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/npw-config.c b/src/npw-config.c index 237cad7..fb58ba7 100644 --- a/src/npw-config.c +++ b/src/npw-config.c @@ -671,24 +671,15 @@ static int process_plugin_dir(const char *plugin_dir, is_plugin_cb test, process if (dir == NULL) return -1; - int plugin_path_length = 256; - char *plugin_path = (char *)malloc(plugin_path_length); - int plugin_dir_length = strlen(plugin_dir); - struct dirent *ent; while ((ent = readdir(dir)) != NULL) { - int len = plugin_dir_length + 1 + strlen(ent->d_name) + 1; - if (len > plugin_path_length) { - plugin_path_length = len; - plugin_path = (char *)realloc(plugin_path, plugin_path_length); - } - sprintf(plugin_path, "%s/%s", plugin_dir, ent->d_name); + char *plugin_path = g_build_filename(plugin_dir, ent->d_name, NULL); NPW_PluginInfo plugin_info; if (test(plugin_path, &plugin_info)) process(plugin_path, &plugin_info); + g_free(plugin_path); } - free(plugin_path); closedir(dir); return 0; } From 7afea9346413b4d3e5fe3f2afe4388dcbec95b84 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 13 May 2011 21:59:00 -0400 Subject: [PATCH 53/91] Replace strstart with g_str_has_prefix --- src/npw-config.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/src/npw-config.c b/src/npw-config.c index fb58ba7..1854bcb 100644 --- a/src/npw-config.c +++ b/src/npw-config.c @@ -57,22 +57,6 @@ static void error(const char *format, ...) exit(1); } -static int strstart(const char *str, const char *val, const char **ptr) -{ - const char *p, *q; - p = str; - q = val; - while (*q != '\0') { - if (*p != *q) - return 0; - p++; - q++; - } - if (ptr) - *ptr = p; - return 1; -} - static const char *strnstr(const char *str, int len, const char *substr) { const char *match = strstr(str, substr); @@ -879,7 +863,7 @@ static int update_plugin(const char *plugin_path) ret = remove_plugin(plugin_path); } else if (has_system_wide_wrapper_plugin(plugin_info.path, true) - && !strstart(plugin_path, get_system_mozilla_plugin_dir(), NULL)) { + && !g_str_has_prefix(plugin_path, get_system_mozilla_plugin_dir())) { if (g_verbose) printf(" NPAPI plugin %s is already installed system-wide, removing wrapper\n", plugin_info.path); ret = remove_plugin(plugin_path); From a3630244c16eda8709a2706a7874eaad432fc1b6 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 13 May 2011 22:15:59 -0400 Subject: [PATCH 54/91] Replace mkdir_p with g_mkdir_with_parents --- src/npw-config.c | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/src/npw-config.c b/src/npw-config.c index 1854bcb..058941d 100644 --- a/src/npw-config.c +++ b/src/npw-config.c @@ -122,35 +122,6 @@ static int strexpand(char *dst, int dstlen, const char *src, int srclen, const V return 0; } -/* Implement mkdir -p with default permissions (derived from busybox code) */ -static int mkdir_p(const char *path) -{ - char path_copy[strlen(path) + 1]; - char *s = path_copy; - path = strcpy(s, path); - for (;;) { - char c = 0; - while (*s) { - if (*s == '/') { - while (*++s == '/') - ; - c = *s; - *s = 0; - break; - } - ++s; - } - if (mkdir(path, 0755) < 0) { - struct stat st; - if ((errno != EEXIST && errno != EISDIR) || stat(path, &st) < 0 || !S_ISDIR(st.st_mode)) - break; - } - if ((*s = c) == '\0') - return 0; - } - return -1; -} - static const char *get_system_mozilla_plugin_dir(void) { static const char default_dir[] = LIBDIR "/mozilla/plugins"; @@ -787,7 +758,8 @@ static int install_plugin(const char *plugin_path, NPW_PluginInfo *plugin_info) } const char *user_plugin_dir = get_user_mozilla_plugin_dir(); - if (access(user_plugin_dir, R_OK | W_OK) < 0 && mkdir_p(user_plugin_dir) < 0) + if (access(user_plugin_dir, R_OK | W_OK) < 0 && + g_mkdir_with_parents(user_plugin_dir, 0755) < 0) return 1; ret = do_install_plugin(plugin_path, user_plugin_dir, plugin_info); From 15bbf8b8ca37eade93fcaee6bf225808be7f7c47 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 13 May 2011 23:00:26 -0400 Subject: [PATCH 55/91] Well, we work with 10.3 May as well list it. Possibly also worth garbage-collecting the other entries. --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index 7818d52..9d909f1 100644 --- a/README +++ b/README @@ -91,6 +91,7 @@ The following plugins work reasonnably well: - Flash Player 9.0.124 - Flash Player 10.0.12.36 - Flash Player 10.2.153 +- Flash Player 10.3.181 - Linux J2K 0.0.2 - Mplayerplug-in 2.80 - Mplayerplug-in 3.25 From fe3a3e541636b41f728e59643a730cffe2ed885c Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sun, 15 May 2011 13:13:33 -0400 Subject: [PATCH 56/91] List the new website in the README --- README | 1 + 1 file changed, 1 insertion(+) diff --git a/README b/README index 9d909f1..549f84e 100644 --- a/README +++ b/README @@ -5,6 +5,7 @@ Copyright (C) 2005-2009 Gwenole Beauchesne Copyright (C) 2011 David Benjamin + http://nspluginwrapper.davidben.net/ License ------- From 2cd26d49024c2b9a92659382f54e2c63bda2ebdd Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sun, 15 May 2011 15:26:43 -0400 Subject: [PATCH 57/91] Detect Konqueror and use glib event loop instead of Xt one Unfortunately, while Konqueror pretends to have an Xt event loop, it is completely non-functional. Block hooks will not run, because it is a Qt event loop polling Xt. Work procs also do not work because Xt does not report them in XtAppPending. A timeout should, in theory, work, but Konqueror doesn't even enable its Xt bridge most of the time! If the plug-in requests XEmbed (as Flash does), a PluginHostXt is never created and XtEvents::enable is never called. Instead of fighting all this, just use the glib event loop. They have a bridge and Qt uses the glib event loop these days anyway. The only reason it used to work is because, not supporting windowless plug-ins, most of communication was from browser to plug-in. Requests would just get queued up and (with luck) not time out. With the new delayed sync mechanism, we are unable to register the delayed sync and instead the plug-in hangs. --- src/npw-wrapper.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index 66a95a2..151cd3e 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -3947,7 +3947,10 @@ static void plugin_init(int is_NP_Initialize) mozilla_funcs.getvalue(NULL, NPNVToolkit, (void *)&toolkit); // Initialize RPC events listener, try to attach it to the main event loop - if (toolkit == NPNVGtk12 || toolkit == NPNVGtk2) { // GLib + if (toolkit == NPNVGtk12 || toolkit == NPNVGtk2 + || toolkit == 0xFEEDABEE) { // GLib + // We use the glib event loop in Konqueror (0xFEEDABEE) because + // its Xt event loop bridge is completely broken and non-functional. D(bug(" trying to attach RPC listener to main GLib event loop\n")); g_rpc_source = rpc_event_source_new(g_rpc_connection); g_source_set_priority(g_rpc_source, G_PRIORITY_LOW); From 141e8d5bb682c373aa12e71f650faadccb407855 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sun, 15 May 2011 15:35:06 -0400 Subject: [PATCH 58/91] nspluginwrapper 1.4.0 --- NEWS | 8 +++++++- nspluginwrapper.spec | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 0f82857..7bd559c 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,13 @@ -nspluginwrapper NEWS -- history of user-visible changes. 2011-04-23 +nspluginwrapper NEWS -- history of user-visible changes. 2011-05-15 Copyright (C) 2005-2009 Gwenole Beauchesne (C) 2011 David Benjamin +Version 1.4.0 - 15.May.2011 +* Report capabilities over RPC to fix logic based on NULL plugin/browser hooks +* Fix initialization bug that causes Flash 10.3 to report a version of 0 +* Implement ClearSiteData NPAPI extension for managing Flash LSOs +* Work around bug in Konqueror that prevents plug-ins from functioning properly + Version 1.3.2 (BETA) - 23.Apr.2011 * Work around lack of client-side windows in Flash * Fix race condition when NPP_Destroy was called while viewer is busy diff --git a/nspluginwrapper.spec b/nspluginwrapper.spec index 301bb6c..28b15cf 100644 --- a/nspluginwrapper.spec +++ b/nspluginwrapper.spec @@ -1,5 +1,5 @@ %define name nspluginwrapper -%define version 1.3.2 +%define version 1.4.0 %define release 1 #define svndate DATE From b19fd2707a1659e718c6fa3e0609426c111cff82 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sun, 15 May 2011 19:29:46 -0400 Subject: [PATCH 59/91] Send a version in npw-player Likely doesn't matter, but probably worth initializing the plug-in correctly. --- src/npw-player.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/npw-player.c b/src/npw-player.c index 644366e..57f5601 100644 --- a/src/npw-player.c +++ b/src/npw-player.c @@ -848,6 +848,7 @@ g_NP_Initialize (Plugin *plugin) memset (&plugin->plugin_funcs, 0, sizeof (plugin->plugin_funcs)); plugin->plugin_funcs.size = sizeof (plugin->plugin_funcs); + plugin->plugin_funcs.version = 19; memset (&plugin->mozilla_funcs, 0, sizeof (plugin->mozilla_funcs)); plugin->mozilla_funcs.size = sizeof (plugin->mozilla_funcs); From e87d49bdd6d3f66aba9fa22c7a05b90b3817b460 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 17 May 2011 12:23:31 -0400 Subject: [PATCH 60/91] Half-initialize the plug-in in NP_Initialize Otherwise the check for attempting to load the wrapper template plug-in fails in GTK WebKit (which tries to call NP_Initialize on every plug-in). Reported by Arch Linux users. --- src/npw-wrapper.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index 151cd3e..74f7e9a 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -3622,6 +3622,12 @@ NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs) // for now, we only need fields up to including forceRedraw if (moz_funcs->size < (offsetof(NPNetscapeFuncs, forceredraw) + sizeof(NPN_ForceRedrawProcPtr))) return NPERR_INVALID_FUNCTABLE_ERROR; + + if (g_plugin.initialized == 0) + plugin_init(0); + if (g_plugin.initialized <= 0) + return NPERR_GENERIC_ERROR; + if (g_plugin.is_wrapper) return NPERR_NO_ERROR; From 66570b9b0cb6b6b8e3d55857d6e70273c7f8bc85 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 17 May 2011 16:12:32 -0400 Subject: [PATCH 61/91] Make the plugin capabitilities check somewhat more robust --- src/npw-wrapper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index 74f7e9a..e6abb05 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -3686,7 +3686,7 @@ NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs) moz_funcs->version, npapi_version)); uint32_t plugin_version = 0; uint32_t *plugin_capabilities = NULL; - uint32_t plugin_capabilities_len; + uint32_t plugin_capabilities_len = 0; NPError error = g_NP_Initialize(npapi_version, &plugin_version, &plugin_capabilities, &plugin_capabilities_len); @@ -3696,7 +3696,7 @@ NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs) D(bug("Plugin supports NPAPI %d, advertising version %d to browser\n", plugin_version, full_plugin_funcs.version)); - if (!PLUGIN_DIRECT_EXEC) { + if (plugin_capabilities) { // Don't advertise any functions the plugin doesn't support. int num = 0; #define PLUGIN_FUNC(func, member) \ From c7c9aa3fc090146c619df247197beb97af239e26 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 17 May 2011 18:37:36 -0400 Subject: [PATCH 62/91] Refactor the GDK_NATIVE_WINDOWS patch Follow the Fedora patch and put it into npw-viewer.sh. It's a little cleaner than in the Makefile. --- Makefile | 5 ----- src/npw-viewer.sh | 6 ++++++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index ba6685a..fbbf924 100644 --- a/Makefile +++ b/Makefile @@ -265,11 +265,6 @@ install.viewer.glue:: echo "#!/bin/sh" > $$p; \ echo "TARGET_OS=$(TARGET_OS)" >> $$p; \ echo "TARGET_ARCH=$(TARGET_ARCH)" >> $$p; \ - echo 'case "$$*" in' >> $$p; \ - echo "*libflashplayer*)" >> $$p; \ - echo " export GDK_NATIVE_WINDOWS=1" >> $$p; \ - echo " ;;" >> $$p; \ - echo "esac" >> $$p; \ echo ". $(npcommondir)/$(nploader_PROGRAM)" >> $$p; \ chmod 755 $$p do.install.libnoxshm: $(libnoxshm_LIBRARY) diff --git a/src/npw-viewer.sh b/src/npw-viewer.sh index 2911072..44e6a8f 100644 --- a/src/npw-viewer.sh +++ b/src/npw-viewer.sh @@ -5,6 +5,12 @@ OS="`uname -s | tr '[A-Z]' '[a-z]'`" ARCH="`uname -m`" +case "$*" in + *libflashplayer*) + export GDK_NATIVE_WINDOWS=1 + ;; +esac + if test -z "$TARGET_OS"; then echo "*** NSPlugin Viewer *** error, TARGET_OS not initialized" exit 1 From f136c8bae3bd007c70a604df9c0827cd12e27355 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 18 May 2011 00:49:01 -0400 Subject: [PATCH 63/91] Move variable declaration down a bit Just to refactor a little. --- src/npw-wrapper.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index e6abb05..ccd3f01 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -3613,7 +3613,6 @@ NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs) { D(bug("NP_Initialize\n")); - static NPPluginFuncs full_plugin_funcs; if (moz_funcs == NULL || plugin_funcs == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; @@ -3634,6 +3633,7 @@ NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs) // copy mozilla_funcs table here as plugin_init() will need it memcpy(&mozilla_funcs, moz_funcs, MIN(moz_funcs->size, sizeof(mozilla_funcs))); + static NPPluginFuncs full_plugin_funcs; memset(&full_plugin_funcs, 0, sizeof(full_plugin_funcs)); full_plugin_funcs.size = sizeof(NPPluginFuncs); full_plugin_funcs.version = NPW_NPAPI_VERSION; From 7ad48aab42f1e05d0c00ed92de40273fb9446833 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 20 May 2011 15:55:43 -0400 Subject: [PATCH 64/91] Pull in latest npapi-sdk headers Just a boring whitespace change. --- npapi/npruntime.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/npapi/npruntime.h b/npapi/npruntime.h index 816a4f8..ad0e370 100644 --- a/npapi/npruntime.h +++ b/npapi/npruntime.h @@ -167,14 +167,14 @@ NP_END_MACRO #define STRINGZ_TO_NPVARIANT(_val, _v) \ NP_BEGIN_MACRO \ (_v).type = NPVariantType_String; \ - NPString str = { _val, (uint32_t)(strlen(_val)) }; \ + NPString str = { _val, (uint32_t)(strlen(_val)) }; \ (_v).value.stringValue = str; \ NP_END_MACRO #define STRINGN_TO_NPVARIANT(_val, _len, _v) \ NP_BEGIN_MACRO \ (_v).type = NPVariantType_String; \ - NPString str = { _val, (uint32_t)(_len) }; \ + NPString str = { _val, (uint32_t)(_len) }; \ (_v).value.stringValue = str; \ NP_END_MACRO From cea4f99888ad34227fda39fda76c3c4c40a8d5ae Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 25 May 2011 23:17:27 -0400 Subject: [PATCH 65/91] Use %.*s instead of strndup to print the script in NPN_Evaluate --- src/npw-wrapper.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index ccd3f01..1ce459a 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -1256,9 +1256,7 @@ static bool g_NPN_Evaluate(NPP instance, NPObject *npobj, NPString *script, NPVariant *result) { D(bugiI("NPN_Evaluate instance=%p, npobj=%p\n", instance, npobj)); - gchar *script_str = g_strndup(script->UTF8Characters, script->UTF8Length); - D(bug("script = '%s'\n", script_str)); - g_free(script_str); + D(bug("script = '%.*s'\n", script->UTF8Length, script->UTF8Characters)); bool ret = mozilla_funcs.evaluate(instance, npobj, script, result); gchar *result_str = string_of_NPVariant(result); D(bugiD("NPN_Evaluate return: %d (%s)\n", ret, result_str)); From c8bacf3192ae49e7229e897bb77d6c0d70c5d4af Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sun, 29 May 2011 17:07:50 -0700 Subject: [PATCH 66/91] Use the correct symbol version for _Unwind_GetIPInfo See bug #29. Reported by Matthias Dahl. --- lsb-build/stub_libs/libgcc_s.Version | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lsb-build/stub_libs/libgcc_s.Version b/lsb-build/stub_libs/libgcc_s.Version index 2b4c00d..2c5c3cc 100644 --- a/lsb-build/stub_libs/libgcc_s.Version +++ b/lsb-build/stub_libs/libgcc_s.Version @@ -6,7 +6,6 @@ GCC_3.0 { _Unwind_GetDataRelBase; _Unwind_GetGR; _Unwind_GetIP; - _Unwind_GetIPInfo; _Unwind_GetLanguageSpecificData; _Unwind_GetRegionStart; _Unwind_GetTextRelBase; @@ -21,3 +20,6 @@ GCC_3.3 { _Unwind_GetCFA; _Unwind_Resume_or_Rethrow; }; +GCC_4.2.0 { + _Unwind_GetIPInfo; +}; From ee50a9d6817de45e6ba749e9a353418b43913151 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 2 Jun 2011 09:29:03 -0700 Subject: [PATCH 67/91] Fix install with parallel make Patch by Shannon of Gentoo bugzilla. Fixes #30. http://bugs.gentoo.org/show_bug.cgi?id=368665#c10 --- Makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index fbbf924..96c834c 100644 --- a/Makefile +++ b/Makefile @@ -242,38 +242,38 @@ install.dirs: mkdir -p $(DESTDIR)$(nphostdir) || : mkdir -p $(DESTDIR)$(nptargetdir) || : ifeq ($(build_player),yes) -install.player: $(npplayer_PROGRAM) +install.player: install.dirs $(npplayer_PROGRAM) $(INSTALL) -m 755 $(STRIP_OPT) $(npplayer_PROGRAM) $(DESTDIR)$(nphostdir)/$(npplayer_PROGRAM) mkdir -p $(DESTDIR)$(bindir) $(LN_S) $(nphostdir)/$(npplayer_PROGRAM) $(DESTDIR)$(bindir)/nspluginplayer else install.player: endif -install.wrapper: $(npwrapper_LIBRARY) +install.wrapper: install.dirs $(npwrapper_LIBRARY) $(INSTALL) -m 755 $(STRIP_OPT) $(npwrapper_LIBRARY) $(DESTDIR)$(nphostdir)/$(npwrapper_LIBRARY) ifeq ($(build_viewer),yes) -install.viewer: install.viewer.bin install.viewer.glue -install.libnoxshm: do.install.libnoxshm +install.viewer: install.dirs install.viewer.bin install.viewer.glue +install.libnoxshm: install.dirs do.install.libnoxshm else install.viewer: install.libnoxshm: endif -install.viewer.bin: $(npviewer_PROGRAM) +install.viewer.bin: install.dirs $(npviewer_PROGRAM) $(INSTALL) -m 755 $(STRIP_OPT) $(npviewer_PROGRAM) $(DESTDIR)$(nptargetdir)/$(npviewer_PROGRAM) -install.viewer.glue:: +install.viewer.glue:: install.dirs p=$(DESTDIR)$(nptargetdir)/$(npviewer_PROGRAM:%.bin=%); \ echo "#!/bin/sh" > $$p; \ echo "TARGET_OS=$(TARGET_OS)" >> $$p; \ echo "TARGET_ARCH=$(TARGET_ARCH)" >> $$p; \ echo ". $(npcommondir)/$(nploader_PROGRAM)" >> $$p; \ chmod 755 $$p -do.install.libnoxshm: $(libnoxshm_LIBRARY) +do.install.libnoxshm: install.dirs $(libnoxshm_LIBRARY) $(INSTALL) -m 755 $(STRIP_OPT) $(libnoxshm_LIBRARY) $(DESTDIR)$(nptargetdir)/$(libnoxshm_LIBRARY) -install.config: $(npconfig_PROGRAM) +install.config: install.dirs $(npconfig_PROGRAM) $(INSTALL) -m 755 $(STRIP_OPT) $(npconfig_PROGRAM) $(DESTDIR)$(nphostdir)/$(npconfig_PROGRAM) mkdir -p $(DESTDIR)$(bindir) $(LN_S) $(nphostdir)/$(npconfig_PROGRAM) $(DESTDIR)$(bindir)/nspluginwrapper -install.loader: $(nploader_PROGRAM) +install.loader: install.dirs $(nploader_PROGRAM) $(INSTALL) -m 755 $(nploader_PROGRAM) $(DESTDIR)$(npcommondir)/$(nploader_PROGRAM) install.mkruntime: $(SRC_PATH)/utils/mkruntime.sh $(INSTALL) -m 755 $< $(DESTDIR)$(npcommondir)/mkruntime From 253d41890a601616ab2ef34778931a291a429f42 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 4 Jun 2011 11:41:40 -0700 Subject: [PATCH 68/91] nspluginwrapper 1.4.2 --- NEWS | 7 ++++++- nspluginwrapper.spec | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 7bd559c..11809c0 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,12 @@ -nspluginwrapper NEWS -- history of user-visible changes. 2011-05-15 +nspluginwrapper NEWS -- history of user-visible changes. 2011-06-04 Copyright (C) 2005-2009 Gwenole Beauchesne (C) 2011 David Benjamin +Version 1.4.2 - 04.Jun.2011 +* Fix crash in WebKit/GTK when npwrapper.so is incorrectly treated as a plugin +* Fix symbol versioning issues with _Unwind_GetIPInfo on some systems +* Fix install process with parallel make + Version 1.4.0 - 15.May.2011 * Report capabilities over RPC to fix logic based on NULL plugin/browser hooks * Fix initialization bug that causes Flash 10.3 to report a version of 0 diff --git a/nspluginwrapper.spec b/nspluginwrapper.spec index 28b15cf..ae31cf3 100644 --- a/nspluginwrapper.spec +++ b/nspluginwrapper.spec @@ -1,5 +1,5 @@ %define name nspluginwrapper -%define version 1.4.0 +%define version 1.4.2 %define release 1 #define svndate DATE From 173fc6a221d98dd85d6a01a6b368c442d370bb65 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 28 Jun 2011 20:30:26 -0700 Subject: [PATCH 69/91] Fix crash when the number of file descriptors grows and then shrinks This is a bit of an embarrassing bug. The allocated size of the array and the number of elements are not always the same. Reported by Fridtjof Busse. --- src/npw-viewer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 48e6952..445eb7a 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -4961,10 +4961,10 @@ static int do_main(int argc, char **argv, const char *connection_path) } /* POLL */ - (g_main_context_get_poll_func(context))(fds, nfds, timeout); + (g_main_context_get_poll_func(context))(fds, needed_fds + 1, timeout); /* CHECK */ - bool ready = g_main_context_check(context, max_priority, fds + 1, nfds - 1); + bool ready = g_main_context_check(context, max_priority, fds + 1, needed_fds); /* DISPATCH */ if (ready) { From e80bd44a50d071712e0ba59f84f6f99bfbb13bb7 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 28 Jun 2011 20:33:37 -0700 Subject: [PATCH 70/91] Use g_renew instead of freeing and reusing the memory --- src/npw-viewer.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 445eb7a..0a67ae1 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -4953,9 +4953,8 @@ static int do_main(int argc, char **argv, const char *connection_path) while ((needed_fds = g_main_context_query(context, max_priority, &timeout, fds + 1, nfds - 1)) > nfds - 1) { // Reallocate to make room - g_free(fds); nfds = needed_fds + 1; - fds = g_new0(GPollFD, nfds); + fds = g_renew(GPollFD, fds, nfds); fds[0].fd = rpc_socket(g_rpc_connection); fds[0].events = G_IO_IN; } From f6ec3f4c24a55726b485cd77967fd4165a556907 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 28 Jun 2011 20:34:57 -0700 Subject: [PATCH 71/91] Rename a variable to be less confusing --- src/npw-viewer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 0a67ae1..f4e615b 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -4936,8 +4936,8 @@ static int do_main(int argc, char **argv, const char *connection_path) // Cache an array for the FDs to poll. We always poll one extra: the // RPC fd, which is treated special. - int nfds = 2; - GPollFD *fds = g_new0(GPollFD, nfds); + int fds_size = 2; + GPollFD *fds = g_new0(GPollFD, fds_size); fds[0].fd = rpc_socket(g_rpc_connection); fds[0].events = G_IO_IN; @@ -4951,10 +4951,10 @@ static int do_main(int argc, char **argv, const char *connection_path) /* QUERY */ int timeout, needed_fds; while ((needed_fds = g_main_context_query(context, max_priority, &timeout, - fds + 1, nfds - 1)) > nfds - 1) { + fds + 1, fds_size - 1)) > fds_size - 1) { // Reallocate to make room - nfds = needed_fds + 1; - fds = g_renew(GPollFD, fds, nfds); + fds_size = needed_fds + 1; + fds = g_renew(GPollFD, fds, fds_size); fds[0].fd = rpc_socket(g_rpc_connection); fds[0].events = G_IO_IN; } From 9b1c7f0ff5909ea60e340f7a18c7e119b467c3be Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 28 Jun 2011 20:52:06 -0700 Subject: [PATCH 72/91] Use g_main_context_add_poll for the RPC source There is not much point in playing silly games with the FD list when we could just as well add a FD and check it out-of-band. --- src/npw-viewer.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/npw-viewer.c b/src/npw-viewer.c index f4e615b..6bec039 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -4934,15 +4934,22 @@ static int do_main(int argc, char **argv, const char *connection_path) // Set error handler - stop plugin if there's a connection error rpc_connection_set_error_callback(g_rpc_connection, rpc_error_callback_cb, NULL); - // Cache an array for the FDs to poll. We always poll one extra: the - // RPC fd, which is treated special. + // Cache the array of FDs to poll. int fds_size = 2; GPollFD *fds = g_new0(GPollFD, fds_size); - fds[0].fd = rpc_socket(g_rpc_connection); - fds[0].events = G_IO_IN; g_is_running = true; GMainContext *context = g_main_context_default(); + + // We track the RPC source out-of-band so that we can integrate it + // with the remote main loop. Run it at high priority so we do not + // delay the browser on an RPC request; it's effectively the highest + // priority anyway from the sync mechanism. + GPollFD rpc_fd = { 0 }; + rpc_fd.fd = rpc_socket(g_rpc_connection); + rpc_fd.events = G_IO_IN; + g_main_context_add_poll(context, &rpc_fd, G_PRIORITY_HIGH); + while (g_is_running) { /* PREPARE */ int max_priority; @@ -4951,19 +4958,17 @@ static int do_main(int argc, char **argv, const char *connection_path) /* QUERY */ int timeout, needed_fds; while ((needed_fds = g_main_context_query(context, max_priority, &timeout, - fds + 1, fds_size - 1)) > fds_size - 1) { + fds, fds_size)) > fds_size) { // Reallocate to make room - fds_size = needed_fds + 1; + fds_size = needed_fds; fds = g_renew(GPollFD, fds, fds_size); - fds[0].fd = rpc_socket(g_rpc_connection); - fds[0].events = G_IO_IN; } /* POLL */ - (g_main_context_get_poll_func(context))(fds, needed_fds + 1, timeout); + (g_main_context_get_poll_func(context))(fds, needed_fds, timeout); /* CHECK */ - bool ready = g_main_context_check(context, max_priority, fds + 1, needed_fds); + bool ready = g_main_context_check(context, max_priority, fds, needed_fds); /* DISPATCH */ if (ready) { @@ -4972,12 +4977,13 @@ static int do_main(int argc, char **argv, const char *connection_path) rpc_sync(g_rpc_connection); g_main_context_dispatch(context); rpc_end_sync(g_rpc_connection); - } else if (fds[0].revents & fds[0].events) { + } else if (rpc_fd.revents & rpc_fd.events) { // We don't have anything, but there is an incoming RPC // request. Just respond to it. No need to sync. rpc_dispatch(g_rpc_connection); } } + g_main_context_remove_poll(context, &rpc_fd); g_free(fds); D(bug("--- EXIT ---\n")); From dbce3d441879d73eab0cd21bd4cd17882fa1f789 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 30 Jun 2011 20:17:50 -0700 Subject: [PATCH 73/91] Add missing install.dirs dependency --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 96c834c..5d374a1 100644 --- a/Makefile +++ b/Makefile @@ -275,7 +275,7 @@ install.config: install.dirs $(npconfig_PROGRAM) $(LN_S) $(nphostdir)/$(npconfig_PROGRAM) $(DESTDIR)$(bindir)/nspluginwrapper install.loader: install.dirs $(nploader_PROGRAM) $(INSTALL) -m 755 $(nploader_PROGRAM) $(DESTDIR)$(npcommondir)/$(nploader_PROGRAM) -install.mkruntime: $(SRC_PATH)/utils/mkruntime.sh +install.mkruntime: install.dirs $(SRC_PATH)/utils/mkruntime.sh $(INSTALL) -m 755 $< $(DESTDIR)$(npcommondir)/mkruntime $(archivedir):: From 2f2e00a95a21f4c7824964610ad1ca313578dd6c Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 30 Jun 2011 19:43:56 -0700 Subject: [PATCH 74/91] nspluginwrapper 1.4.4 --- NEWS | 5 ++++- nspluginwrapper.spec | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 11809c0..8f41f20 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,10 @@ -nspluginwrapper NEWS -- history of user-visible changes. 2011-06-04 +nspluginwrapper NEWS -- history of user-visible changes. 2011-06-30 Copyright (C) 2005-2009 Gwenole Beauchesne (C) 2011 David Benjamin +Version 1.4.4 - 30.Jun.2011 +* Fix crash in some cases when the number of watched file descriptors decreases + Version 1.4.2 - 04.Jun.2011 * Fix crash in WebKit/GTK when npwrapper.so is incorrectly treated as a plugin * Fix symbol versioning issues with _Unwind_GetIPInfo on some systems diff --git a/nspluginwrapper.spec b/nspluginwrapper.spec index ae31cf3..4e41885 100644 --- a/nspluginwrapper.spec +++ b/nspluginwrapper.spec @@ -1,5 +1,5 @@ %define name nspluginwrapper -%define version 1.4.2 +%define version 1.4.4 %define release 1 #define svndate DATE From 304a86f7b8f54d567a26a5e9059bebc61003a824 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 1 Jul 2011 09:33:04 -0700 Subject: [PATCH 75/91] New hostname Thanks to the Fedora project for letting me use it. --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 549f84e..90362e3 100644 --- a/README +++ b/README @@ -5,7 +5,7 @@ Copyright (C) 2005-2009 Gwenole Beauchesne Copyright (C) 2011 David Benjamin - http://nspluginwrapper.davidben.net/ + http://nspluginwrapper.org/ License ------- From 8f3be9a1f82cfa0bbf264c86f7640a0567c70d61 Mon Sep 17 00:00:00 2001 From: Stanislav Brabec Date: Wed, 13 Jul 2011 21:16:04 -0700 Subject: [PATCH 76/91] Tell curl that we are a multi-threaded program - i. e. it can not use signals. Signed-off-by: Stanislav Brabec --- src/npw-player.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/npw-player.c b/src/npw-player.c index 57f5601..a99b8f7 100644 --- a/src/npw-player.c +++ b/src/npw-player.c @@ -1233,6 +1233,7 @@ np_stream_new (const gchar *url, void *notify_data) return NULL; curl_easy_setopt (handle, CURLOPT_URL, url); + curl_easy_setopt (handle, CURLOPT_NOSIGNAL, 1); curl_easy_setopt (handle, CURLOPT_WRITEFUNCTION, on_stream_read_nothing_cb); curl_easy_setopt (handle, CURLOPT_FILETIME, 1); curl_easy_setopt (handle, CURLOPT_TIMECONDITION, CURL_TIMECOND_LASTMOD); @@ -1626,6 +1627,7 @@ on_stream_open_cb (gpointer user_data) CURL * const handle = pstream->curl_handle; curl_easy_setopt (handle, CURLOPT_URL, pstream->np_stream->url); + curl_easy_setopt (handle, CURLOPT_NOSIGNAL, 1); curl_easy_setopt (handle, CURLOPT_WRITEFUNCTION, on_stream_read_cb); curl_easy_setopt (handle, CURLOPT_WRITEDATA, pstream); curl_easy_setopt (handle, CURLOPT_PRIVATE, pstream); From 66f613f65bdcf89c35121a051267b569d8e9918d Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Fri, 22 Jul 2011 20:02:49 -0700 Subject: [PATCH 77/91] Update to latest npapi-sdk headers Just some whitespace changes. Nothing interesting. --- npapi/npfunctions.h | 2 +- npapi/npruntime.h | 12 ++++++------ npapi/nptypes.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/npapi/npfunctions.h b/npapi/npfunctions.h index 51f691a..3b70a39 100644 --- a/npapi/npfunctions.h +++ b/npapi/npfunctions.h @@ -217,7 +217,7 @@ typedef struct _NPNetscapeFuncs { * These can be called to retreive MIME information from the plugin dynamically * * Note: For compatibility with Quicktime, BPSupportedMIMEtypes is another way - * to get mime info from the plugin only on OSX and may not be supported + * to get mime info from the plugin only on OSX and may not be supported * in furture version -- use NP_GetMIMEDescription instead */ enum diff --git a/npapi/npruntime.h b/npapi/npruntime.h index ad0e370..6e89165 100644 --- a/npapi/npruntime.h +++ b/npapi/npruntime.h @@ -1,12 +1,12 @@ /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* - * Copyright (c) 2004, Apple Computer, Inc. and The Mozilla Foundation. + * Copyright (c) 2004, Apple Computer, Inc. and The Mozilla Foundation. * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: - * + * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright @@ -16,7 +16,7 @@ * Foundation ("Mozilla") nor the names of their contributors may be used * to endorse or promote products derived from this software without * specific prior written permission. - * + * * THIS SOFTWARE IS PROVIDED BY APPLE, MOZILLA AND THEIR CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A @@ -44,7 +44,7 @@ extern "C" { objects. The API in this header does not assume the presence of a user agent. That is, it can be used to bind C code to scripting environments outside of the context of a user agent. - + However, the normal use of the this API is in the context of a scripting environment running in a browser or other user agent. In particular it is used to support the extended Netscape @@ -355,7 +355,7 @@ void NPN_ReleaseObject(NPObject *npobj); value, it will be supplied via the result NPVariant argument. Successful calls will return true, false will be returned in case of an error. - + Calls made from plugin code to script must be made from the thread on which the plugin was initialized. */ diff --git a/npapi/nptypes.h b/npapi/nptypes.h index 3001288..abcc96b 100644 --- a/npapi/nptypes.h +++ b/npapi/nptypes.h @@ -69,7 +69,7 @@ #endif #elif defined(bsdi) || defined(FREEBSD) || defined(OPENBSD) /* - * BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and + * BSD/OS, FreeBSD, and OpenBSD ship sys/types.h that define int32_t and * u_int32_t. */ #include From b8a6af3f13595fc6584210343235600cabc665cc Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 13 Aug 2011 11:23:27 -0700 Subject: [PATCH 78/91] Set GDK_NATIVE_WINDOWS unconditionally Browsers are supposed to set it all the time, if we take what Firefox and Chrome do as the spec (which is as reasonable as anything). May as well apply the workaround everywhere instead of assuming only Flash needs it. Reported-By: Stanislav Brabec --- src/npw-viewer.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/npw-viewer.sh b/src/npw-viewer.sh index 44e6a8f..34f83b6 100644 --- a/src/npw-viewer.sh +++ b/src/npw-viewer.sh @@ -5,11 +5,9 @@ OS="`uname -s | tr '[A-Z]' '[a-z]'`" ARCH="`uname -m`" -case "$*" in - *libflashplayer*) - export GDK_NATIVE_WINDOWS=1 - ;; -esac +# Browsers are supposed to set this (both Firefox and Chromium do), but some +# don't. Workaround this here. +export GDK_NATIVE_WINDOWS=1 if test -z "$TARGET_OS"; then echo "*** NSPlugin Viewer *** error, TARGET_OS not initialized" From c5b1faa7d384a76c39256ab1a2d179f26493b48f Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 13 Aug 2011 11:56:30 -0700 Subject: [PATCH 79/91] Fix another parallel build issue Adapted from a Gentoo patch. Reported-By: Martin von Gagern --- Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 5d374a1..6628907 100644 --- a/Makefile +++ b/Makefile @@ -333,23 +333,23 @@ $(nploader_PROGRAM): $(nploader_SOURCES) sed -e 's|%NPW_VIEWER_DIR%|$(nptargetdir_var)|' $< > $@ chmod 755 $@ -$(LSB_OBJ_DIR):: +$(LSB_OBJ_DIR): @[ -d $(LSB_OBJ_DIR) ] || mkdir $(LSB_OBJ_DIR) > /dev/null 2>&1 -$(LSB_OBJ_DIR)/%.o: $(LSB_SRC_DIR)/%.c +$(LSB_OBJ_DIR)/%.o: $(LSB_SRC_DIR)/%.c | $(LSB_OBJ_DIR) $(CC) $(CFLAGS_32) -nostdinc -fno-builtin -I. -I$(LSB_INC_DIR) -c $< -o $@ -$(LSB_OBJ_DIR)/%.a: $(LSB_OBJ_DIR)/%.o +$(LSB_OBJ_DIR)/%.a: $(LSB_OBJ_DIR)/%.o | $(LSB_OBJ_DIR) $(AR) rc $@ $< -$(LSB_OBJ_DIR)/libc.so: $(LSB_OBJ_DIR)/libc_main.so $(LSB_OBJ_DIR)/libc_nonshared.a +$(LSB_OBJ_DIR)/libc.so: $(LSB_OBJ_DIR)/libc_main.so $(LSB_OBJ_DIR)/libc_nonshared.a | $(LSB_OBJ_DIR) @echo "OUTPUT_FORMAT($(TARGET_ELF_ARCH))" > $@ @echo "GROUP ( $(LSB_OBJ_DIR)/libc_main.so $(LSB_OBJ_DIR)/libc_nonshared.a )" >> $@ -$(LSB_OBJ_DIR)/libgcc_s_32.so: $(LSB_OBJ_DIR)/libgcc_s.so +$(LSB_OBJ_DIR)/libgcc_s_32.so: $(LSB_OBJ_DIR)/libgcc_s.so | $(LSB_OBJ_DIR) $(LN_S) libgcc_s.so $@ -$(LSB_OBJ_DIR)/%.so: $(LSB_OBJ_DIR)/%.o +$(LSB_OBJ_DIR)/%.so: $(LSB_OBJ_DIR)/%.o | $(LSB_OBJ_DIR) $(CC) $(LDFLAGS_32) -nostdlib $(DSO_LDFLAGS) $< -o $@ \ -Wl,--version-script,$(patsubst $(LSB_OBJ_DIR)/%.o,$(LSB_SRC_DIR)/%.Version,$<) \ -Wl,-soname,`grep "$(patsubst $(LSB_OBJ_DIR)/%.o,%,$<) " $(LSB_SRC_DIR)/LibNameMap.txt | cut -f2 -d' '` From c857c1b01d98571ef84d8639a83c5c9adf860db5 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 13 Aug 2011 11:57:31 -0700 Subject: [PATCH 80/91] Drop some more archive-related rules The archive-making ones were removed earlier, so these don't work anymore. No one complained, so let's drop the rest too. --- Makefile | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/Makefile b/Makefile index 6628907..e36a991 100644 --- a/Makefile +++ b/Makefile @@ -278,22 +278,6 @@ install.loader: install.dirs $(nploader_PROGRAM) install.mkruntime: install.dirs $(SRC_PATH)/utils/mkruntime.sh $(INSTALL) -m 755 $< $(DESTDIR)$(npcommondir)/mkruntime -$(archivedir):: - [ -d $(archivedir) ] || mkdir $(archivedir) > /dev/null 2>&1 - -RPMBUILD = \ - RPMDIR=`mktemp -d` ; \ - mkdir -p $$RPMDIR/{SPECS,SOURCES,BUILD,RPMS,SRPMS} ; \ - rpmbuild --define "_topdir $$RPMDIR" -ta $(2) $(1) && \ - find $$RPMDIR/ -name *.rpm -exec mv -f {} $(archivedir) \; ; \ - rm -rf $$RPMDIR - -distrpm: $(archivedir)$(SRCARCHIVE).bz2 - $(call RPMBUILD,$<,--with generic) - -localrpm: $(archivedir)$(SRCARCHIVE).bz2 - $(call RPMBUILD,$<) - $(npwrapper_LIBRARY): $(npwrapper_OBJECTS) $(CC) $(DSO_LDFLAGS) $(npwrapper_LDFLAGS) -o $@ $(npwrapper_OBJECTS) $(npwrapper_LIBS) From 37b70dee718eedbf8bfc7c944e580d23723d0c97 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Mon, 15 Aug 2011 00:29:04 -0700 Subject: [PATCH 81/91] Update to latest NPAPI SDK Added a new variable. OS X only, so uninteresting. --- npapi/npapi.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/npapi/npapi.h b/npapi/npapi.h index 082feec..ccf41be 100644 --- a/npapi/npapi.h +++ b/npapi/npapi.h @@ -429,6 +429,8 @@ typedef enum { , NPNVsupportsCocoaBool = 3001 /* TRUE if the browser supports the Cocoa event model */ , NPNVsupportsUpdatedCocoaTextInputBool = 3002 /* TRUE if the browser supports the updated Cocoa text input specification. */ + , NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports + CA model compositing */ #endif #if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6) , NPNVSupportsWindowlessLocal = 2002 From f40a1f60893ed3b8097213a23dd3f0fd8ad56b1c Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 16 Aug 2011 10:14:50 -0700 Subject: [PATCH 82/91] Replace the plugin atomically instead of writing in-place To say nothing of atomicity, lots of Bad Things happen when you replace libraries in-place. gdb apparently gets upset at you, and you get random crashes in programs which have the library loaded. Evidently libdl.so can't even handle it. It's unspecified whether changes to a file mmapped as MAP_PRIVATE are visible to the process. Fixes #35. --- src/npw-config.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/npw-config.c b/src/npw-config.c index 058941d..e9e8007 100644 --- a/src/npw-config.c +++ b/src/npw-config.c @@ -721,13 +721,10 @@ static int do_install_plugin(const char *plugin_path, const char *plugin_dir, NP !is_root_only_accessible_plugin(plugin_dir)) mode = 0755; - int d_fd = open(d_plugin_path, O_CREAT | O_WRONLY, mode); - if (d_fd < 0) - return 4; - - if (write(d_fd, plugin_data, w_size) != w_size) - return 13; - close(d_fd); + // TODO: Don't swallow the error message. Also get rid of these ridiculous + // return codes. They're never acted on anyway. Use GError or something. + if (!g_file_set_contents(d_plugin_path, plugin_data, w_size, NULL)) + return 4; if (g_verbose) printf(" into %s\n", d_plugin_path); From f3c2b2d1f5ee558ad2f3c7830821d591c8a0f440 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Tue, 6 Sep 2011 19:48:36 -0400 Subject: [PATCH 83/91] Leak library handles in is_wrapper_plugin Many libraries crash on unload. Better to just keep them all loaded in the process like everything else does. --- src/npw-config.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/npw-config.c b/src/npw-config.c index e9e8007..4ad4bc1 100644 --- a/src/npw-config.c +++ b/src/npw-config.c @@ -534,7 +534,8 @@ static bool is_wrapper_plugin(const char *plugin_path, NPW_PluginInfo *out_plugi return false; bool ret = is_wrapper_plugin_handle(handle, out_plugin_info); - dlclose(handle); + /* Intentionally leak the handle; many libraries crash when unloaded. */ + /* dlclose(handle); */ return ret; } From 5e1f84fc9c99991379cc40724db5da6882f9a101 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 14 Sep 2011 08:38:56 -0400 Subject: [PATCH 84/91] Update NPAPI headers to r13 There's now a NPNVdocumentOrigin. --- npapi/npapi.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/npapi/npapi.h b/npapi/npapi.h index ccf41be..e5baad9 100644 --- a/npapi/npapi.h +++ b/npapi/npapi.h @@ -411,7 +411,9 @@ typedef enum { NPNVprivateModeBool = 18, - NPNVsupportsAdvancedKeyHandling = 21 + NPNVsupportsAdvancedKeyHandling = 21, + + NPNVdocumentOrigin = 22 #if defined(XP_MACOSX) /* Used for negotiating drawing models */ From 2090fbafdc0e426c0f209a77a48d52b3dfc01d35 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 14 Sep 2011 09:21:43 -0400 Subject: [PATCH 85/91] Add missing NULL check --- src/npw-viewer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 6bec039..2bd3d57 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -3998,7 +3998,7 @@ static int handle_NPP_GetValue(rpc_connection_t *connection) ret = g_NPP_GetValue(PLUGIN_INSTANCE_NPP(plugin), variable, (void *)&str); error = rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_STRING, str, RPC_TYPE_INVALID); // Eww. NPPVformValue needs to be freed, but not the others. - if (variable == NPPVformValue) + if (variable == NPPVformValue && str != NULL) NPN_MemFree(str); return error; } From 62a50c7197b54dfe6b68e3ddd8320483bf7cabd1 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 14 Sep 2011 10:49:54 -0400 Subject: [PATCH 86/91] Implement NPNVdocumentOrigin No one implements it yet, but it's a very simple variable, and very very important to support when it does get used. --- src/npw-rpc.c | 3 +++ src/npw-viewer.c | 20 ++++++++++++++++++++ src/npw-wrapper.c | 9 +++++++++ src/utils.c | 1 + 4 files changed, 33 insertions(+) diff --git a/src/npw-rpc.c b/src/npw-rpc.c index 4b8bb5f..3221895 100644 --- a/src/npw-rpc.c +++ b/src/npw-rpc.c @@ -49,6 +49,9 @@ int rpc_type_of_NPNVariable(int variable) case NPNVnetscapeWindow: type = RPC_TYPE_UINT32; break; + case NPNVdocumentOrigin: + type = RPC_TYPE_STRING; + break; case NPNVWindowNPObject: case NPNVPluginElementNPObject: type = RPC_TYPE_NP_OBJECT; diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 2bd3d57..ef29f32 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -1089,6 +1089,25 @@ invoke_NPN_GetValue(PluginInstance *plugin, NPNVariable variable, void *value) *((NPBool *)value) = b ? TRUE : FALSE; break; } + case RPC_TYPE_STRING: + { + char *str = NULL; + error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_INT32, &ret, RPC_TYPE_STRING, &str, RPC_TYPE_INVALID); + if (error != RPC_ERROR_NO_ERROR) { + npw_perror("NPN_GetValue() wait for reply", error); + ret = NPERR_GENERIC_ERROR; + } + D(bug("-> value: %s\n", str ? str : "(null)")); + // Reallocate with NPN_MemAlloc. Caller frees. + if (ret == NPERR_NO_ERROR) { + char *npn_str = NULL; + ret = NPW_ReallocData(str, strlen(str) + 1, (void**)&npn_str); + free(str); + str = npn_str; + } + *((char **)value) = str; + break; + } case RPC_TYPE_NP_OBJECT: { NPObject *npobj = NULL; @@ -1171,6 +1190,7 @@ g_NPN_GetValue(NPP instance, NPNVariable variable, void *value) case NPNVPluginElementNPObject: case NPNVprivateModeBool: case NPNVsupportsAdvancedKeyHandling: + case NPNVdocumentOrigin: return g_NPN_GetValue_real(instance, variable, value); default: switch (variable & 0xff) { diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index 1ce459a..fffc4b8 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -519,6 +519,15 @@ static int handle_NPN_GetValue(rpc_connection_t *connection) ret = g_NPN_GetValue(PLUGIN_INSTANCE_NPP(plugin), variable, (void *)&b); return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_BOOLEAN, b, RPC_TYPE_INVALID); } + case RPC_TYPE_STRING: + { + char *str = NULL; + ret = g_NPN_GetValue(PLUGIN_INSTANCE_NPP(plugin), variable, (void *)&str); + error = rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_STRING, str, RPC_TYPE_INVALID); + if (str) + NPN_MemFree(str); + return error; + } case RPC_TYPE_NP_OBJECT: { NPObject *npobj = NULL; diff --git a/src/utils.c b/src/utils.c index 4f9e47e..62a8ceb 100644 --- a/src/utils.c +++ b/src/utils.c @@ -293,6 +293,7 @@ const char *string_of_NPNVariable(int variable) _(NPNVSupportsWindowless); _(NPNVprivateModeBool); _(NPNVsupportsAdvancedKeyHandling); + _(NPNVdocumentOrigin); #undef _ default: switch (variable & 0xff) { From 65ef09da15b75cce7f917265f081281bfc09c0e6 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 14 Sep 2011 10:55:56 -0400 Subject: [PATCH 87/91] Hard-code NPNVsupportsAdvancedKeyHandling to FALSE In case a plugin attempts to check this (unlikely as no browser implements it yet) and avoid NULL checks on all the entry points, we shouldn't crash. Also, for correctness, even if the browser supports it, a browser + nspluginwrapper combination doesn't. --- src/npw-viewer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/npw-viewer.c b/src/npw-viewer.c index ef29f32..377b06d 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -1184,12 +1184,16 @@ g_NPN_GetValue(NPP instance, NPNVariable variable, void *value) } *((GdkNativeWindow *)value) = GDK_WINDOW_XWINDOW(plugin->browser_toplevel); break; + // TODO: when AdvancedKeyHandling hooks are supported, proxy this value over + // from the browser. + case NPNVsupportsAdvancedKeyHandling: + *(NPBool*)value = FALSE; + break; case NPNVSupportsWindowless: case NPNVSupportsXEmbedBool: case NPNVWindowNPObject: case NPNVPluginElementNPObject: case NPNVprivateModeBool: - case NPNVsupportsAdvancedKeyHandling: case NPNVdocumentOrigin: return g_NPN_GetValue_real(instance, variable, value); default: From a9e1623e4498aa1212e6f777dec31314b85e4901 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Wed, 19 Oct 2011 16:42:40 -0400 Subject: [PATCH 88/91] Update to npapi-sdk r14 Just uninteresting thing about undefined variables. --- npapi/npapi.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/npapi/npapi.h b/npapi/npapi.h index e5baad9..507b723 100644 --- a/npapi/npapi.h +++ b/npapi/npapi.h @@ -379,7 +379,7 @@ typedef enum { , NPPVpluginCoreAnimationLayer = 1003 #endif -#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6) +#if defined(MOZ_PLATFORM_MAEMO) && ((MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)) , NPPVpluginWindowlessLocalBool = 2002 #endif } NPPVariable; @@ -434,7 +434,7 @@ typedef enum { , NPNVsupportsCompositingCoreAnimationPluginsBool = 74656 /* TRUE if the browser supports CA model compositing */ #endif -#if (MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6) +#if defined(MOZ_PLATFORM_MAEMO) && ((MOZ_PLATFORM_MAEMO == 5) || (MOZ_PLATFORM_MAEMO == 6)) , NPNVSupportsWindowlessLocal = 2002 #endif } NPNVariable; From 6bd99e4da88ffce9c61962d74bd53644438de563 Mon Sep 17 00:00:00 2001 From: Pavel Roskin Date: Sat, 29 Oct 2011 15:12:46 -0400 Subject: [PATCH 89/91] Use libdl when linking npplayer Without it, following error occurs on Fedora 15 when compiling for x86_64: /usr/bin/ld: npplayer-npw-player.o: undefined reference to symbol 'dlsym@@GLIBC_2.2.5' /usr/bin/ld: note: 'dlsym@@GLIBC_2.2.5' is defined in DSO /lib64/libdl.so.2 so try adding it to the linker command line /lib64/libdl.so.2: could not read symbols: Invalid operation collect2: ld returned 1 exit status Fedora already has a patch that adds -ldl to LDFLAGS Signed-off-by: Pavel Roskin --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e36a991..2a40671 100644 --- a/Makefile +++ b/Makefile @@ -142,7 +142,7 @@ npplayer_CFLAGS += $(GTK_CFLAGS) $(GLIB_CFLAGS) $(MOZILLA_CFLAGS) $(CURL_CFLAGS npplayer_LDFLAGS = $(LDFLAGS) npplayer_LDFLAGS += $(libpthread_LDFLAGS) npplayer_LIBS = $(GTK_LIBS) $(GLIB_LIBS) $(CURL_LIBS) $(X_LIBS) -npplayer_LIBS += $(libpthread_LIBS) $(libsocket_LIBS) +npplayer_LIBS += $(libdl_LIBS) $(libpthread_LIBS) $(libsocket_LIBS) libnoxshm_LIBRARY = libnoxshm.so libnoxshm_RAWSRCS = libnoxshm.c From de08bfb186b732f32aec796d0fa6e8f901e66ca6 Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 29 Dec 2011 08:31:42 -0500 Subject: [PATCH 90/91] Don't include gthread.h directly Only glib.h (and glib/gstdio.h) are supposed to be included directly. Fixes bug #43. Reported-by: Anssi Hannula --- src/npw-player.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/npw-player.c b/src/npw-player.c index a99b8f7..217b5ba 100644 --- a/src/npw-player.c +++ b/src/npw-player.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include #include From 928c32260a2a6eccf81b169ee7e80388aa69ecdd Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Thu, 29 Dec 2011 08:40:52 -0500 Subject: [PATCH 91/91] Link to gthread-2.0 We call g_thread_init and whatnot. Fixes bug #44. Reported-by: Micah Gersten --- configure | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 5f3dd86..09c400a 100755 --- a/configure +++ b/configure @@ -499,8 +499,8 @@ fi # check for Glib 2.0 compile CFLAGS if $pkgconfig --exists glib-2.0; then - GLIB_CFLAGS=`$pkgconfig --cflags glib-2.0` - GLIB_LIBS=`$pkgconfig --libs glib-2.0` + GLIB_CFLAGS=`$pkgconfig --cflags glib-2.0 gthread-2.0` + GLIB_LIBS=`$pkgconfig --libs glib-2.0 gthread-2.0` GLIB_VERSION=`$pkgconfig --modversion glib-2.0` else echo "GLIB 2.0 environment not found"