From 1f0ad8eb2955d8d4faf8b304704d1dc458f2e56a Mon Sep 17 00:00:00 2001 From: David Benjamin Date: Sat, 5 Mar 2011 22:26:53 -0500 Subject: [PATCH] nspluginwrapper-1.1.10 Taken from Ubuntu orig.tar.gz file. --- ChangeLog | 522 ++++++++ Makefile | 6 +- NEWS | 29 +- README | 11 +- configure | 48 +- lsb-build/stub_libs/libc_main.c | 1 + nspluginwrapper.spec | 31 +- src/debug.c | 91 +- src/debug.h | 32 + src/npruntime-impl.h | 14 +- src/npruntime.c | 331 ++++- src/npw-common.c | 55 +- src/npw-common.h | 74 +- src/npw-malloc.h | 6 + src/npw-player.c | 18 +- src/npw-rpc.c | 81 +- src/npw-rpc.h | 3 +- src/npw-viewer.c | 1169 +++++++++++++---- src/npw-viewer.sh | 4 +- src/npw-wrapper.c | 1128 ++++++++++++---- src/rpc.c | 505 +++++-- src/rpc.h | 8 + src/utils.c | 119 +- src/utils.h | 3 + tests/test-plugins.html | 2 +- tests/test-rpc-common.c | 137 +- tests/test-rpc-common.h | 30 +- tests/test-rpc-concurrent.c | 202 ++- ...{test-rpc-nested.c => test-rpc-nested-1.c} | 35 +- tests/test-rpc-nested-2.c | 189 +++ tests/test-rpc-types.c | 853 ++++++++---- utils/npw-shadow.c | 1069 --------------- 32 files changed, 4507 insertions(+), 2299 deletions(-) rename tests/{test-rpc-nested.c => test-rpc-nested-1.c} (76%) create mode 100644 tests/test-rpc-nested-2.c delete mode 100644 utils/npw-shadow.c diff --git a/ChangeLog b/ChangeLog index 35b7ed4..0c2b69a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,525 @@ +2008-12-07 22:35 Gwenole Beauchesne + + * src/npw-viewer.c: Destroy plugin window only if PluginInstance + is finalize'd. This is because an NPPVpluginScriptableNPObject + can still hold a reference to it (and a call to + NPClass::Invalidate() would fail in that case). + +2008-12-07 22:30 Gwenole Beauchesne + + * src/npruntime-impl.h, src/npruntime.c: Use NPW memory allocator + for NPObjectInfo objects. Reference count PluginInstance bound + to an NPObject if it is known at NPClass::allocate() time. + +2008-12-07 22:02 Gwenole Beauchesne + + * src/npw-viewer.c, src/npw-wrapper.c: Re-add refcount debugging + info for NPN_{Create,Retain,Release}Object(). + +2008-12-07 21:48 Gwenole Beauchesne + + * src/npw-viewer.c: Remove delayed NPN_InvalidateRect() code as + it's no longer necessary with RPC synchronous messaging. + +2008-12-07 19:25 Gwenole Beauchesne + + * src/npw-viewer.c: Make NPN_ReleaseObject() use + rpc_method_invoke_possible() to check whether we can send it + immediately. This detects the case where a call is made after + rpc_method_send_reply() but before we return from the + rpc_dispatch() handler. + +2008-12-07 19:22 Gwenole Beauchesne + + * src/rpc.c, src/rpc.h: Implement synchronous messaging. aka turns + an async call (i.e. an rpc_method_invoke() with a connection in + server mode) into a synchronous one. That way, the browser is + notified that the plugin wants to make a call and then puts self + into condition to receive the message (normal rpc_dispatch() or + at the end of a toplevel NPP_*() function). + + This makes it RPC protocol v2.6. + +2008-12-07 15:30 Gwenole Beauchesne + + * tests/test-rpc-concurrent.c: Improve concurrent test to check we + get the right answers (in case nested handling got wrong). + Besides, make sure the client waits for all server's incoming + calls prior to rpc_test_exit()'ing. + +2008-12-07 15:24 Gwenole Beauchesne + + * tests/test-rpc-common.c: Make sure to handle RPC on both ends, + including the client's side. + +2008-12-07 08:12 Gwenole Beauchesne + + * src/npw-wrapper.c: Fix NPP_HandleEvent() return value on error. + +2008-12-07 08:10 Gwenole Beauchesne + + * src/npruntime.c, src/npw-viewer.c, src/npw-wrapper.c: Add checks + for all rpc_method_invoke() functions. + +2008-12-07 08:06 Gwenole Beauchesne + + * src/debug.h: Add npw_return_if_fail() and + npw_return_val_if_fail() helpers. + +2008-12-07 07:16 Gwenole Beauchesne + + * src/rpc.c, src/rpc.h, tests/test-rpc-nested-2.c: Add + rpc_method_invoke_possible() interface to check whether we are + ready to call rpc_method_invoke() or not. i.e. in particular, if + we are not trying to invoke functions after + rpc_method_send_reply() and before we return from an RPC method + handler. + +2008-12-06 18:21 Gwenole Beauchesne + + * tests/test-rpc-common.c, tests/test-rpc-concurrent.c, + tests/test-rpc-nested-1.c, tests/test-rpc-types.c: Use helpers. + In particular, don't use g_assert() but rather RPC_TEST_ENSURE() + or RPC_TEST_ENSURE_NO_ERROR() which always evaluate. + +2008-12-06 18:13 Gwenole Beauchesne + + * Makefile, tests/test-rpc-nested-2.c: Add another testcase for + nested rpc_method_invoke(). This time, we are also emitting a + call just after an rpc_method_send_reply(). Note: this is not + fixed yet. + +2008-12-06 18:11 Gwenole Beauchesne + + * tests/test-rpc-common.h: Add helpers. + +2008-12-06 18:10 Gwenole Beauchesne + + * Makefile, tests/test-rpc-nested-1.c, tests/test-rpc-nested.c: + Rename. + +2008-12-06 09:08 Gwenole Beauchesne + + * src/npw-viewer.c: Rework the XEMBED hack. Don't let the browser + cause Gtk to kill our window. i.e. don't process WM_DELETE_EVENT + sent by the browser GtkSocket. That way, we will kill the window + ourselves in NPP_Destroy(). + +2008-12-04 21:31 Gwenole Beauchesne + + * src/npw-viewer.c: Process delayed calls in NPP_Destroy() only if + PluginInstances match. Besides, don't care about pending + NPN_InvalidateRect() requests if we already know the instance + will pass away soon (i.e. we are in NPP_Destroy()). + +2008-12-03 22:56 Gwenole Beauchesne + + * src/npw-viewer.c: Delay all NPN_InvalidateRect() messages. An + intermediate solution may be to delay the messages only if there + is actually incoming RPC. Postpone this optimization for a + future version (and smarter strategy to "compress" the + region/requests). + +2008-12-03 20:51 Gwenole Beauchesne + + * src/npruntime-impl.h, src/npruntime.c: Add debug messages for + NPClass::invoke_*() functions. + +2008-12-02 21:49 Gwenole Beauchesne + + * src/npw-viewer.c, src/npw-wrapper.c: Fix invalid RPC beyond + NPP_Destroy(). This fixes the following scenario: + + Browser: NPP_Destroy() + -> rpc_method_invoke() + Viewer: NPN_InvalidateRect() + -> rpc_method_invoke() + -> rpc_dispatch() pending messages + -> handle_NPP_Destroy() + -> PluginInstance is killed + -> send PluginInstance but it was killed... + + Now, with the help of reference counting, we can hold the + PluginInstance. Besides, NPP_Destroy() will reset instance_id, + thus RPC won't be sending a "valid" PluginInstance to the other + side, thus reducing the other side call to a no-op. i.e. don't + try to do anything with the browser NPP instance that was killed + previously (the NPP_Destroy() call would have completed by the + time the browser-side needs to handle incoming RPC). + +2008-12-02 21:00 Gwenole Beauchesne + + * src/npw-viewer.c: Preserve PluginInstance objects during + invoke_NPN_*() function calls. This is because + rpc_method_invoke() can handle pending messages, among which an + NPP_Destroy() is possible. Since the latter unref the + PluginInstance, we could arrive in a situation where we are + dereferencing deallocated data. + +2008-12-02 20:44 Gwenole Beauchesne + + * src/npw-common.h, src/npw-viewer.c, src/npw-wrapper.c: Replace + all RPC_TYPE_NPP with RPC_TYPE_NPW_PLUGIN_INSTANCE. + +2008-12-02 20:15 Gwenole Beauchesne + + * src/npw-rpc.c, src/npw-rpc.h: Add RPC_TYPE_NPW_PLUGIN_INSTANCE + to marshal PluginInstance objects. + +2008-12-01 23:01 Gwenole Beauchesne + + * src/npw-viewer.c: Pass PluginInstance to invoke_NP*() functions. + The next step is to replace RPC_TYPE_NPP with + RPC_TYPE_NPW_PLUGIN_INSTANCE. + +2008-12-01 21:55 Gwenole Beauchesne + + * src/npw-viewer.c, src/npw-wrapper.c: Minor cleanups. Make sure + plugin->instance is NULL on exit from NPP_Destroy(). + +2008-12-01 21:47 Gwenole Beauchesne + + * src/npw-common.h: Remove extraneous "extern" linkage keyword, + this is default behaviour. + +2008-12-01 21:46 Gwenole Beauchesne + + * src/npw-common.c, src/npw-common.h, src/npw-viewer.c, + src/npw-wrapper.c: Add infrastructure to refcount PlugInstances. + +2008-12-01 20:28 Gwenole Beauchesne + + * configure, src/npruntime.c, src/npw-viewer.c: Disable PID check, + this is not really useful unless a plugin does fork() without + exec(). This could be reactivated with --enable-pid-check though. + +2008-12-01 20:06 Gwenole Beauchesne + + * src/npw-viewer.c: Fix pid_check() for USE_PID_CHECK == 0 (thanks + Martin Stransky). + +2008-12-01 20:03 Gwenole Beauchesne + + * nspluginwrapper.spec: Bump release for development. + +2008-11-30 23:03 Gwenole Beauchesne + + * ChangeLog: Generated by svn2cl. + +2008-11-30 23:00 Gwenole Beauchesne + + * src/npw-viewer.c: Drop use of "extern inline" as some (older) + compilers don't support ISO C semantics. + +2008-11-30 22:54 Gwenole Beauchesne + + * NEWS, nspluginwrapper.spec: Updates for 1.1.8. + +2008-11-30 22:39 Gwenole Beauchesne + + * src/npw-viewer.c: Process all pending calls in NPP_Destroy() as + the data could become junk afterwards. + +2008-11-30 22:34 Gwenole Beauchesne + + * src/npw-viewer.c: Don't delay call to NPN_ReleaseObject() if we + can handle it now. + +2008-11-30 21:52 Gwenole Beauchesne + + * src/rpc.c: Add rpc_method_*_valist() variants, internal only for + now. + +2008-11-30 21:24 Gwenole Beauchesne + + * src/npw-viewer.c: Slightly improved delayed call mechanism. This + is not fully satisfying yet as I believe a pipe should be better + (glib GSource creation is slow). Fortunately, there doesn't seem + to be that many calls to NPN_ReleaseObject(). + +2008-11-30 21:07 Gwenole Beauchesne + + * src/npw-malloc.h: Fix typo. + +2008-11-30 20:47 Gwenole Beauchesne + + * src/npruntime.c, src/npw-viewer.c: Delay calls to + NPN_ReleaseObject. Revert: + + 2008-11-22 10:43 Gwenole Beauchesne + + * src/npw-wrapper.c: Fix NPN_ReleaseObject() reply, i.e. don't + dereference npobj after the real call to NPN handler as it could + be deallocated. + +2008-11-30 17:38 Gwenole Beauchesne + + * src/npruntime.c, src/npw-viewer.c, src/npw-wrapper.c: Add + missing debugging messages. + +2008-11-30 17:21 Gwenole Beauchesne + + * src/npruntime.c: Fix pid_check() for the browser-side + implementation. + +2008-11-30 17:14 Gwenole Beauchesne + + * src/npruntime.c, src/npw-viewer.c: Extend PID check to npruntime + bridge. + +2008-11-30 15:52 Gwenole Beauchesne + + * lsb-build/stub_libs/libc_main.c: Add dirfd() for + npw_close_all_open_files(). + +2008-11-30 15:47 Gwenole Beauchesne + + * src/npw-viewer.c: Check that processes fork()'ed off + npviewer.bin don't issue RPC calls. Initial patch by Martin + Stransky. + +2008-11-30 14:56 Gwenole Beauchesne + + * src/npruntime.c: Rename is_npclass_valid() to + is_valid_npobject_class(). + +2008-11-30 14:50 Gwenole Beauchesne + + * src/npruntime.c, src/npw-wrapper.c: Remove wrong comment. The + errors previously noticed were due to the fact that NPObjects + were looked up in the wrong (previously deallocated) hash table. + We now preserve that hash table. + +2008-11-30 14:33 Gwenole Beauchesne + + * src/npw-wrapper.c: Likewise for npobject_bridge_destroy(). + +2008-11-30 14:18 Gwenole Beauchesne + + * src/npw-wrapper.c: Move id_init() into NP_Initialize(), likewise + for id_kill() into NP_Shutdown(). Those functions are guaranteed + to be called only once. g_NP_Initialize() and g_NP_Shutdown() + could be called several times for the restart machinery but we + don't want to clobber with IDs generated previously. + +2008-11-30 13:17 Gwenole Beauchesne + + * src/npw-viewer.c: Kill viewer if the parent browser died (Martin + Stransky). + +2008-11-30 13:08 Gwenole Beauchesne + + * src/npruntime.c, src/npw-wrapper.c: Use + rpc_connection_set_error_callback() to detect and handle an RPC + connection loss (Martin Stransky). In that case, all NPObjects + are invalidated. XXX: this is too global. + +2008-11-30 12:10 Gwenole Beauchesne + + * src/npruntime-impl.h, src/npruntime.c: Add a mechanism to stop + calls to NPClass functions if the other end died. We get + notified of this situation through npruntime_deactivate(). + Initial patch by Martin Stransky. + +2008-11-30 11:09 Gwenole Beauchesne + + * src/rpc.c, src/rpc.h: Introduce + rpc_connection_set_error_callback() to register a callback for + RPC errors (Martin Stransky). + +2008-11-30 10:41 Gwenole Beauchesne + + * src/npw-viewer.c: Warn out when we explicitly don't support + specific variables for XPCOM in NPN_GetValue() (Martin Stransky). + +2008-11-30 09:18 Gwenole Beauchesne + + * src/rpc.c: Add SOCK_CLOEXEC to socket() flags. This is a Linux + >= 2.6.27 extension. + +2008-11-30 09:01 Gwenole Beauchesne + + * src/npw-wrapper.c, src/utils.c, src/utils.h: Close all open + files on fork(). Initial patch by Dan Walsh. + +2008-11-29 14:49 Gwenole Beauchesne + + * utils/npw-shadow.c: Nuke dead file. + +2008-11-29 14:47 Gwenole Beauchesne + + * src/npw-wrapper.c: Make it possible to execute native plugins + directly (i.e. without npviewer.bin) if either "NPW_DIRECT_EXEC" + or "NPW_DIRECT_EXECUTION" environment variable is set. + +2008-11-29 14:03 Gwenole Beauchesne + + * src/utils.c: Fix id_init() to create a new hash if it does not + exist already. + +2008-11-25 22:11 Gwenole Beauchesne + + * src/npw-viewer.sh: Make `which' failures silent for + soudwrappers. It's also correct to work without a soundwrapper + if the audio device is correctly multiplexed (Stanislav Brabec). + +2008-11-25 21:20 Gwenole Beauchesne + + * nspluginwrapper.spec: Bump release for development. + +2008-11-24 18:35 Gwenole Beauchesne + + * NEWS: Fix typo. + +2008-11-23 21:57 Gwenole Beauchesne + + * ChangeLog: Generated by svn2cl. + +2008-11-23 06:43 Gwenole Beauchesne + + * src/npw-viewer.c: Fix a warning (enumeration value not handled + in switch). + +2008-11-23 06:39 Gwenole Beauchesne + + * NEWS, nspluginwrapper.spec: Updates for 1.1.6. + * README: Fix typos and mention trademark as there are commercial + interests (and be on the safe side). + +2008-11-22 15:33 Gwenole Beauchesne + + * ChangeLog: Generated by svn2cl. + +2008-11-22 15:20 Gwenole Beauchesne + + * src/npruntime.c: Fix string_of_NPVariant() for NULL arguments. + +2008-11-22 15:04 Gwenole Beauchesne + + * src/npruntime.c: Release args variants prior to calling + rpc_method_send_reply(). + +2008-11-22 13:49 Gwenole Beauchesne + + * src/npw-viewer.c, src/npw-wrapper.c, src/utils.c, src/utils.h: + Improve debug info for NP[PN]_[SG]etValue(). + +2008-11-22 13:23 Gwenole Beauchesne + + * src/npw-wrapper.c: Fix debug message in NPN_Write(). + +2008-11-22 10:52 Gwenole Beauchesne + + * src/npw-wrapper.c: Fix memory leak in NPN_GetStringIdentifiers() + RPC handler. + +2008-11-22 10:50 Gwenole Beauchesne + + * src/npw-malloc.h: Add NPW_MemNew() and NPW_MemNew0() helpers. + +2008-11-22 10:43 Gwenole Beauchesne + + * src/npw-wrapper.c: Fix NPN_ReleaseObject() reply, i.e. don't + dereference npobj after the real call to NPN handler as it could + be deallocated. + +2008-11-22 10:01 Gwenole Beauchesne + + * src/debug.c, src/debug.h, src/npruntime.c, src/npw-viewer.c, + src/npw-wrapper.c: Indent debugging messages. + +2008-11-22 08:54 Gwenole Beauchesne + + * src/npruntime.c, src/npw-viewer.c, src/npw-wrapper.c: Improve + debugging messages. Nested invocations could confuse what the + return value actually refers to. + +2008-11-22 07:54 Gwenole Beauchesne + + * src/npw-rpc.c: Don't make the sync message a WARNING. + +2008-11-22 07:52 Gwenole Beauchesne + + * src/npw-rpc.c: Always synchronize NPObject::referenceCount in + case the plugin wants to inspect that. Synchronization through + NPN_RetainObject()/NPN_ReleaseObject() should be enough though. + +2008-11-22 07:37 Gwenole Beauchesne + + * src/npw-viewer.c: Fix plugin window resize in XEMBED hack mode. + +2008-11-17 21:55 Gwenole Beauchesne + + * tests/test-plugins.html: Newer demo for the SqueakVM plugin. + +2008-11-17 21:40 Gwenole Beauchesne + + * src/npw-viewer.c, src/npw-wrapper.c: Lower priority of RPC + handlers. + +2008-11-15 21:50 Gwenole Beauchesne + + * src/npw-player.c: Fix for "javascript:" requests. Don't make + them fail because we are starting those streams manually. + +2008-11-15 21:45 Gwenole Beauchesne + + * src/npw-common.h: Fix npw_get_stream_instance(). + +2008-11-09 17:02 Gwenole Beauchesne + + * src/npw-wrapper.c: Update NPP_Write() comment for negative array + lengths. + +2008-11-09 16:56 Gwenole Beauchesne + + * src/npw-wrapper.c: Propagate NPP_Write() with negative lengths + since the plugin may want to handle that case (e.g. close a + stream?). In practise, this doesn't make much sense either. + NPAPI specs need to be updated to mean "close the stream" if + NPP_WriteReady() returns a negative value. + +2008-11-09 16:46 Gwenole Beauchesne + + * src/rpc.c, tests/test-rpc-types.c: Actually, since an array of + negative size doesn't make sense, let it be the responsibility + of the caller to check for bounds. + +2008-11-09 16:38 Gwenole Beauchesne + + * src/rpc.c, tests/test-rpc-types.c: Size of the array to + RPC_TYPE_ARRAY argument is now an int32. Allow for NULL arrays + or arrays of negative length. In that case, the returned array + pointer in the other size is NULL. + +2008-11-09 15:26 Gwenole Beauchesne + + * tests/test-rpc-types.c: Add tests for arrays. Fix + rpc_test_signature() for arrays. + +2008-11-09 15:24 Gwenole Beauchesne + + * src/rpc.c: Allow arrays of uint64 or double. + +2008-11-09 14:29 Gwenole Beauchesne + + * tests/test-rpc-common.c, tests/test-rpc-common.h, + tests/test-rpc-concurrent.c, tests/test-rpc-nested.c, + tests/test-rpc-types.c: Fix indentation (8-char tabs, not 4). + +2008-11-09 14:18 Gwenole Beauchesne + + * configure: Enable glib memory hooks by default if not + configuring with --enable-generic. + +2008-11-09 14:13 Gwenole Beauchesne + + * nspluginwrapper.spec: Bump version for development. + +2008-11-06 22:36 Gwenole Beauchesne + + * ChangeLog: Generated by svn2cl. + 2008-11-06 22:28 Gwenole Beauchesne * NEWS, README, nspluginwrapper.spec: Updates for 1.1.4. diff --git a/Makefile b/Makefile index 831a3f4..9ae51a6 100644 --- a/Makefile +++ b/Makefile @@ -193,7 +193,11 @@ test_rpc_client_CPPFLAGS = $(CPPFLAGS) -I$(SRC_PATH)/src -DBUILD_CLIENT -DNPW_CO test_rpc_server_CPPFLAGS = $(CPPFLAGS) -I$(SRC_PATH)/src -DBUILD_SERVER -DNPW_COMPONENT_NAME="\"Server\"" test_rpc_CFLAGS = -I$(SRC_PATH)/src $(GLIB_CFLAGS) test_rpc_LDFLAGS = $(GLIB_LDFLAGS) $(libpthread_LDFLAGS) $(libsocket_LDFLAGS) -test_rpc_RAWPROGS = test-rpc-types test-rpc-nested test-rpc-concurrent +test_rpc_RAWPROGS = \ + test-rpc-types \ + test-rpc-nested-1 \ + test-rpc-nested-2 \ + test-rpc-concurrent test_rpc_PROGRAMS = \ $(test_rpc_RAWPROGS:%=%-client) \ $(test_rpc_RAWPROGS:%=%-server) diff --git a/NEWS b/NEWS index 52f3283..a0f4e6c 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,33 @@ -nspluginwrapper NEWS -- history of user-visible changes. 2008-11-07 +nspluginwrapper NEWS -- history of user-visible changes. 2008-12-08 Copyright (C) 2005-2008 Gwenole Beauchesne +Version 1.1.10 (BETA) - 08.Dec.2008 +* Fix NPPVpluginScriptableNPObject::Invalidate() +* Fix condition for delayed NPN_ReleaseObject() call +* Fix XEMBED (rework for lost events/focus regressions) +* Fix RPC for calls initiated by the plugin (SYNC mode) +* Fix invalid RPC after the plugin was NPP_Destroy()'ed + +Version 1.1.8 (BETA) - 01.Dec.2008 +* Delay NPN_ReleaseObject() if there is incoming RPC +* Improve plugins restart machinery (Martin Stransky) +* Close npviewer.bin sockets on exec() +* Close all open files on fork() (initial patch by Dan Walsh) +* Make `which` failures silent for soundwrappers (Stanislav Brabec) +* Allow direct execution of native plugins if NPW_DIRECT_EXEC is set + +Version 1.1.6 (BETA) - 23.Nov.2008 +* Enable glib memory hooks by default +* Lower priority of RPC events so that timeouts are triggered first +* Fix string_of_NPVariant() that could make some plugins crash +* Fix NPClass::Invoke(|Default)() args release +* Fix memory leak in NPN_GetStringIdentifiers() +* Fix NPN_ReleaseObject() that could dereference a deallocated NPObject +* Fix (sync) NPObject referenceCount when the object is passed to the plugin +* Fix plugin window resize in XEMBED hack mode +* Fix "javascript:" streams requests in standalone player +* Fix NPP_Write() and propagate negative lengths too (DiamondX plugin) + Version 1.1.4 (BETA) - 07.Nov.2008 * Fix memory leaks in NPRuntime bridge * Fix XEMBED support (workaround Gtk2 and Firefox bugs) diff --git a/README b/README index 1ad6c58..58b8076 100644 --- a/README +++ b/README @@ -11,6 +11,8 @@ License nspluginwrapper is available under the terms of the GNU General Public License. See the file "COPYING" that is included in the distribution for details. +nspluginwrapper is a trademark of Gwenole Beauchesne. + Overview -------- @@ -21,7 +23,7 @@ like Adobe Flash Player on other platforms like Linux/x86_64, *BSD and even Linux/ppc. nspluginwrapper also provides a standalone plugins player. This -programs makes it possible to execute plugins without an actual +program makes it possible to execute plugins without an actual browser. @@ -39,10 +41,11 @@ $ make Or, if you prefer from a source package: $ rpm --rebuild nspluginwrapper.src.rpm -NOTE: if you are building the Linux viewer to use on a non-Linux +NOTE: if you are building the Linux viewer for use on a non-Linux system (e.g. NetBSD, FreeBSD), you will have to configure the Linux -build with the --enable-generic option. That way, named sockets will be -used and work under the Linux emulation on those operating systems. +build with the --enable-generic option. That way, named sockets will +be used and work under the Linux emulation layer on those operating +systems. Requirements and Installation diff --git a/configure b/configure index db51d1b..fbcfe82 100755 --- a/configure +++ b/configure @@ -36,7 +36,8 @@ host_cpu=`uname -m` target_os="linux" target_cpu="i386" rpc_init_timeout=5 -malloc_hooks="libc,glib" +malloc_hooks="glib,libc" +use_pid_check="no" case "$host_cpu" in arm*) host_cpu="arm" @@ -124,6 +125,12 @@ case "$opt" in --disable-player) build_player="no" ;; +--enable-pid-check) + use_pid_check="yes" + ;; +--disable-pid-check) + use_pid_check="no" + ;; --with-lib32=*) lib32=`echo "$opt" | cut -d '=' -f 2` ;; @@ -139,12 +146,12 @@ case "$opt" in --with-cxx=*) cxx=`echo "$opt" | cut -d '=' -f 2` ;; +--with-malloc=*) + malloc_hooks=`echo "$opt" | cut -d '=' -f 2` + ;; --rpc-init-timeout=*) rpc_init_timeout=`echo "$opt" | cut -d '=' -f 2` ;; ---with-malloc=*) - malloc_hooks=`echo "$opt" | cut -d '=' -f 2` - ;; esac done @@ -580,10 +587,12 @@ for mh in $malloc_hooks_list; do is_ok="yes" ;; glib) - if $pkgconfig --atleast-version=2.10 glib-2.0; then - is_ok="yes" - else + if test "x$linux_only" = "xno"; then + echo "WARNING: disabling glib memory hooks with --enable-generic" + elif ! $pkgconfig --atleast-version=2.10 glib-2.0; then echo "WARNING: disabling glib memory hooks that require glib >= 2.10 (system is $GLIB_VERSION)" + else + is_ok="yes" fi ;; esac @@ -596,6 +605,10 @@ for mh in $malloc_hooks_list; do fi fi done +if test -z "$malloc_hooks"; then + malloc_hook_default="libc" + malloc_hooks="$malloc_hook_default" +fi # print configure help if test x"$1" = x"-h" -o x"$1" = x"--help" ; then @@ -619,13 +632,14 @@ echo " --source-path=PATH path of source code [$source_path]" echo " --enable-strip strip resulting binaries and libraries [$strip]" echo " --enable-generic don't use system-specific additions" echo " --enable-biarch build both 32-bit and 64-bit components at once" +echo " --enable-pid-check enable PID check (DEBUG) [$use_pid_check]" echo " --with-lib32=NAME use NAME as the 32-bit library dir name [$lib32]" echo " --with-lib64=NAME use NAME as the 64-bit library dir name [$lib64]" echo " --with-x11-prefix=PREFIX use PREFIX as the X11 base dir [autodetect]" echo " --with-cc=CC use C compiler CC [$cc]" echo " --with-cxx=CXX use C++ compiler CXX [$cxx]" -echo " --rpc-init-timeout=VALUE wait VALUE seconds for the plugin to connect [$rpc_init_timeout]" echo " --with-malloc=MALLOC use MALLOC for memory allocation hooks [$malloc_hooks]" +echo " --rpc-init-timeout=VALUE wait VALUE seconds for the plugin to connect [$rpc_init_timeout]" echo "" echo "NOTE: The object files are built at the place where configure is launched" exit 1 @@ -643,13 +657,14 @@ echo "64-bit library dir name $lib64" echo "Source path $source_path" echo "C compiler $cc" echo "C++ compiler $cxx" -echo "host OS $host_os" -echo "host CPU $host_cpu" -echo "host big endian $bigendian" -echo "target OS $target_os" -echo "target CPU $target_cpu" -echo "rpc init timeout $rpc_init_timeout secs" +echo "Host OS $host_os" +echo "Host CPU $host_cpu" +echo "Host big endian $bigendian" +echo "Target OS $target_os" +echo "Target CPU $target_cpu" +echo "RPC init timeout $rpc_init_timeout secs" echo "Memory allocation hooks $malloc_hooks" +echo "Use PID check (DEBUG) $use_pid_check" config_mak="config-host.mak" echo "# Automatically generated by configure - do not modify" > $config_mak @@ -808,6 +823,11 @@ if test "$libc_provides_ssp" = "yes"; then else echo "#undef TARGET_LIBC_PROVIDES_SSP" >> $config_h fi +if test "$use_pid_check" = "yes"; then + echo "#define USE_PID_CHECK 1" >> $config_h +else + echo "#define USE_PID_CHECK 0" >> $config_h +fi config_mak="config.mak" echo "# Automatically generated by configure - do not modify" > $config_mak diff --git a/lsb-build/stub_libs/libc_main.c b/lsb-build/stub_libs/libc_main.c index 6ad9dcd..f33f52e 100644 --- a/lsb-build/stub_libs/libc_main.c +++ b/lsb-build/stub_libs/libc_main.c @@ -130,6 +130,7 @@ void dcgettext() {} ; void dcngettext() {} ; void dgettext() {} ; void difftime() {} ; +void dirfd() {} ; void dirname() {} ; void div() {} ; void dngettext() {} ; diff --git a/nspluginwrapper.spec b/nspluginwrapper.spec index e40432b..1c86ac4 100644 --- a/nspluginwrapper.spec +++ b/nspluginwrapper.spec @@ -1,7 +1,7 @@ %define name nspluginwrapper -%define version 1.1.4 +%define version 1.1.10 %define release 1 -#define svndate 20081106 +#define svndate DATE # define 32-bit arch of multiarch platforms %define arch_32 %{nil} @@ -192,6 +192,33 @@ fi %endif %changelog +* Mon Dec 08 2008 Gwenole Beauchesne 1.1.10-1 +- fix NPPVpluginScriptableNPObject::Invalidate() +- fix condition for delayed NPN_ReleaseObject() call +- fix XEMBED (rework for lost events/focus regressions) +- fix RPC for calls initiated by the plugin (SYNC mode) +- fix invalid RPC after the plugin was NPP_Destroy()'ed + +* Mon Dec 01 2008 Gwenole Beauchesne 1.1.8-1 +- delay NPN_ReleaseObject() if there is incoming RPC +- improve plugins restart machinery (Martin Stransky) +- close npviewer.bin sockets on exec() +- close all open files on fork() (initial patch by Dan Walsh) +- make `which` failures silent for soundwrappers (Stanislav Brabec) +- allow direct execution of native plugins if NPW_DIRECT_EXEC is set + +* Thu Nov 23 2008 Gwenole Beauchesne 1.1.6-1 +- enable glib memory hooks by default +- lower priority of RPC events so that timeouts are triggered first +- fix string_of_NPVariant() that could make some plugins crash +- fix args release in NPClass::Invoke(|Default)() +- fix memory leak in NPN_GetStringIdentifiers() +- fix NPN_ReleaseObject() that could dereference a deallocated NPObject +- fix (sync) NPObject referenceCount when the object is passed to the plugin +- fix plugin window resize in XEMBED hack mode +- fix "javascript:" streams requests in standalone player +- fix NPP_Write() and propage negative lengths too (DiamondX plugin) + * Thu Nov 6 2008 Gwenole Beauchesne 1.1.4-1 - fix memory leaks in NPRuntime bridge - fix XEMBED support (workaround Gtk2 and Firefox bugs) diff --git a/src/debug.c b/src/debug.c index 7285c78..4f23bc3 100644 --- a/src/debug.c +++ b/src/debug.c @@ -29,22 +29,61 @@ #include "debug.h" -static int g_debug_level = -1; +static int g_indent_level = 0; + +void npw_indent(int inc) +{ + g_indent_level += inc; +} + +static int _can_indent_messages(void) +{ + const char *indent_str = getenv("NPW_INDENT_MESSAGES"); + if (indent_str) { + // XXX: also check for "yes", "no", "true", "false" + errno = 0; + long v = strtol(indent_str, NULL, 10); + if ((v != LONG_MIN && v != LONG_MAX) || errno != ERANGE) + return v; + } + return 1; +} + +static inline int get_indent_level(void) +{ + static int can_indent_messages = -1; + if (can_indent_messages < 0) + can_indent_messages = _can_indent_messages(); + if (can_indent_messages) + return g_indent_level; + return 0; +} + + +static int _get_debug_level(void) +{ + const char *debug_str = getenv("NPW_DEBUG"); + if (debug_str) { + errno = 0; + long v = strtol(debug_str, NULL, 10); + if ((v != LONG_MIN && v != LONG_MAX) || errno != ERANGE) + return v; + } + return 0; +} + +static inline int get_debug_level(void) +{ + static int g_debug_level = -1; + if (g_debug_level < 0) + g_debug_level = _get_debug_level(); + return g_debug_level; +} + void npw_dprintf(const char *format, ...) { - if (g_debug_level < 0) { - g_debug_level = 0; - const char *debug_str = getenv("NPW_DEBUG"); - if (debug_str) { - errno = 0; - long v = strtol(debug_str, NULL, 10); - if ((v != LONG_MIN && v != LONG_MAX) || errno != ERANGE) - g_debug_level = v; - } - } - - if (g_debug_level > 0) { + if (get_debug_level() > 0) { va_list args; va_start(args, format); npw_vprintf(format, args); @@ -52,6 +91,20 @@ void npw_dprintf(const char *format, ...) } } +void npw_idprintf(int inc, const char *format, ...) +{ + if (get_debug_level() > 0) { + if (inc < 0) + npw_indent(inc); + va_list args; + va_start(args, format); + npw_vprintf(format, args); + va_end(args); + if (inc > 0) + npw_indent(inc); + } +} + static FILE *g_log_file = NULL; @@ -85,10 +138,22 @@ static void __attribute__((destructor)) log_file_sentinel(void) } +void npw_print_indent(FILE *fp) +{ + static const char blanks[] = " "; + const int blanks_length = sizeof(blanks) - 1; + int n_blanks = 2 * get_indent_level(); + for (int i = 0; i < n_blanks / blanks_length; i++) + fwrite(blanks, blanks_length, 1, fp); + if ((n_blanks = (n_blanks % blanks_length)) > 0) + fwrite(blanks, n_blanks, 1, fp); +} + void npw_vprintf(const char *format, va_list args) { FILE *log_file = npw_log_file(); fprintf(log_file, "*** NSPlugin %s *** ", NPW_COMPONENT_NAME); + npw_print_indent(log_file); vfprintf(log_file, format, args); fflush(log_file); } diff --git a/src/debug.h b/src/debug.h index 12d7681..c9dd893 100644 --- a/src/debug.h +++ b/src/debug.h @@ -29,6 +29,9 @@ extern "C" { extern void npw_dprintf(const char *format, ...) attribute_hidden; +extern void npw_indent(int inc) attribute_hidden; +extern void npw_idprintf(int inc, const char *format, ...) attribute_hidden; + extern void npw_printf(const char *format, ...) attribute_hidden; extern void npw_vprintf(const char *format, va_list args) attribute_hidden; @@ -37,14 +40,43 @@ extern void npw_vprintf(const char *format, va_list args) attribute_hidden; # if 0 && (defined(__GNUC__) && (__GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ == 96))) # define bug(format, ...) \ npw_dprintf("[%-20s:%4d] " format, __FILE__, __LINE__, ##__VA_ARGS__) +# define bugiI(format, ...) \ + npw_idprintf(+1, "[%-20s:%4d] " format, __FILE__, __LINE__, ##__VA_ARGS__) +# define bugiD(format, ...) \ + npw_idprintf(-1, "[%-20s:%4d] " format, __FILE__, __LINE__, ##__VA_ARGS__) # else # define bug npw_dprintf +# define bugiI(...) npw_idprintf(+1, __VA_ARGS__) +# define bugiD(...) npw_idprintf(-1, __VA_ARGS__) # endif # define D(x) x #else # define D(x) ; #endif +/* XXX: add an ENABLE_CHECKS config option? */ +#if DEBUG +# define npw_return_if_fail_warning(expr_str) do { \ + npw_printf("WARNING:(%s:%d):%s: assertion failed: (%s)\n", \ + __FILE__, __LINE__, __func__, expr_str); \ +} while (0) +# define npw_return_if_fail(expr) do { \ + if (!(expr)) { \ + npw_return_if_fail_warning(#expr); \ + return; \ + } \ +} while (0) +# define npw_return_val_if_fail(expr, val) do { \ + if (!(expr)) { \ + npw_return_if_fail_warning(#expr); \ + return (val); \ + } \ +} while (0) +#else +# define npw_return_if_fail(expr, val) do {} while (0) +# define npw_return_val_if_fail(expr, val) do {} while (0) +#endif + #ifdef __cplusplus } #endif diff --git a/src/npruntime-impl.h b/src/npruntime-impl.h index ac257b3..1484d9a 100644 --- a/src/npruntime-impl.h +++ b/src/npruntime-impl.h @@ -25,6 +25,8 @@ typedef struct { NPObject *npobj; uint32_t npobj_id; + bool is_valid; + void *plugin; } NPObjectInfo; extern NPObjectInfo *npobject_info_new(NPObject *npobj) attribute_hidden; @@ -41,15 +43,6 @@ extern void npobject_bridge_destroy(void) attribute_hidden; extern NPClass npclass_bridge; -extern void npclass_invoke_Invalidate(NPObject *npobj) attribute_hidden; -extern bool npclass_invoke_HasMethod(NPObject *npobj, NPIdentifier name) attribute_hidden; -extern bool npclass_invoke_Invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args, uint32_t argCount, NPVariant *result) attribute_hidden; -extern bool npclass_invoke_InvokeDefault(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) attribute_hidden; -extern bool npclass_invoke_HasProperty(NPObject *npobj, NPIdentifier name) attribute_hidden; -extern bool npclass_invoke_GetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result) attribute_hidden; -extern bool npclass_invoke_SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) attribute_hidden; -extern bool npclass_invoke_RemoveProperty(NPObject *npobj, NPIdentifier name) 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; @@ -65,4 +58,7 @@ 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; +// Deactivate all NPObject instances +extern void npruntime_deactivate(void); + #endif /* NPRUNTIME_IMPL_H */ diff --git a/src/npruntime.c b/src/npruntime.c index 7efdf37..05d962e 100644 --- a/src/npruntime.c +++ b/src/npruntime.c @@ -24,6 +24,7 @@ #include /* */ #include "utils.h" #include "npw-common.h" +#include "npw-malloc.h" #define DEBUG 1 #include "debug.h" @@ -32,28 +33,58 @@ // Defined in npw-{wrapper,viewer}.c extern rpc_connection_t *g_rpc_connection attribute_hidden; +// Defined in npw-viewer.c +#if USE_PID_CHECK && NPW_IS_PLUGIN +extern bool pid_check(void); +#else +#define pid_check() true +#endif + /* ====================================================================== */ /* === NPClass Bridge === */ /* ====================================================================== */ +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); +static bool g_NPClass_InvokeDefault(NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result); +static bool g_NPClass_HasProperty(NPObject *npobj, NPIdentifier name); +static bool g_NPClass_GetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result); +static bool g_NPClass_SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value); +static bool g_NPClass_RemoveProperty(NPObject *npobj, NPIdentifier name); + NPClass npclass_bridge = { NPW_NP_CLASS_STRUCT_VERSION, NULL, NULL, - npclass_invoke_Invalidate, - npclass_invoke_HasMethod, - npclass_invoke_Invoke, - npclass_invoke_InvokeDefault, - npclass_invoke_HasProperty, - npclass_invoke_GetProperty, - npclass_invoke_SetProperty, - npclass_invoke_RemoveProperty + g_NPClass_Invalidate, + g_NPClass_HasMethod, + g_NPClass_Invoke, + g_NPClass_InvokeDefault, + g_NPClass_HasProperty, + g_NPClass_GetProperty, + g_NPClass_SetProperty, + g_NPClass_RemoveProperty }; +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; +} + // 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, @@ -64,17 +95,19 @@ int npclass_handle_Invalidate(rpc_connection_t *connection) return error; } - if (npobj && npobj->_class && npobj->_class->invalidate) { - D(bug("NPClass::Invalidate(npobj %p)\n", npobj)); + if (npobj && is_valid_npobject_class(npobj) && npobj->_class->invalidate) { + D(bugiI("NPClass::Invalidate(npobj %p)\n", npobj)); npobj->_class->invalidate(npobj); - D(bug(" done\n")); + D(bugiD("NPClass::Invalidate done\n")); } return rpc_method_send_reply(connection, RPC_TYPE_INVALID); } -void npclass_invoke_Invalidate(NPObject *npobj) +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, @@ -93,9 +126,26 @@ void npclass_invoke_Invalidate(NPObject *npobj) } } +void g_NPClass_Invalidate(NPObject *npobj) +{ + if (!is_valid_npobject_class(npobj)) + return; + + if (!pid_check()) { + npw_printf("WARNING: NPClass::Invalidate called from the wrong process\n"); + return; + } + + D(bugiI("NPClass::Invalidate(npobj %p)\n", npobj)); + npclass_invoke_Invalidate(npobj); + D(bugiD("NPClass::Invalidate done\n")); +} + // NPClass::HasMethod int npclass_handle_HasMethod(rpc_connection_t *connection) { + D(bug("npclass_handle_HasMethod\n")); + NPObject *npobj; NPIdentifier name; int error = rpc_method_get_args(connection, @@ -109,10 +159,10 @@ int npclass_handle_HasMethod(rpc_connection_t *connection) } uint32_t ret = false; - if (npobj && npobj->_class && npobj->_class->hasMethod) { - D(bug("NPClass::HasMethod(npobj %p, name id %p)\n", npobj, name)); + if (npobj && is_valid_npobject_class(npobj) && npobj->_class->hasMethod) { + D(bugiI("NPClass::HasMethod(npobj %p, name id %p)\n", npobj, name)); ret = npobj->_class->hasMethod(npobj, name); - D(bug(" return: %d\n", ret)); + D(bugiD("NPClass::HasMethod return: %d\n", ret)); } return rpc_method_send_reply(connection, @@ -120,8 +170,10 @@ int npclass_handle_HasMethod(rpc_connection_t *connection) RPC_TYPE_INVALID); } -bool npclass_invoke_HasMethod(NPObject *npobj, NPIdentifier name) +static bool npclass_invoke_HasMethod(NPObject *npobj, NPIdentifier name) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPCLASS_HAS_METHOD, RPC_TYPE_NP_OBJECT, npobj, @@ -144,9 +196,27 @@ bool npclass_invoke_HasMethod(NPObject *npobj, NPIdentifier name) return ret; } +bool g_NPClass_HasMethod(NPObject *npobj, NPIdentifier name) +{ + if (!is_valid_npobject_class(npobj)) + return false; + + if (!pid_check()) { + npw_printf("WARNING: NPClass::HasMethod called from the wrong process\n"); + return false; + } + + D(bugiI("NPClass::HasMethod(npobj %p, name id %p)\n", npobj, name)); + bool ret = npclass_invoke_HasMethod(npobj, name); + D(bugiD("NPClass::HasMethod return: %d\n", ret)); + return ret; +} + // NPClass::Invoke int npclass_handle_Invoke(rpc_connection_t *connection) { + D(bug("npclass_handle_Invoke\n")); + NPObject *npobj; NPIdentifier name; uint32_t argCount; @@ -165,12 +235,12 @@ int npclass_handle_Invoke(rpc_connection_t *connection) uint32_t ret = false; NPVariant result; VOID_TO_NPVARIANT(result); - if (npobj && npobj->_class && npobj->_class->invoke) { - D(bug("NPClass::Invoke(npobj %p, name id %p)\n", npobj, name)); + if (npobj && is_valid_npobject_class(npobj) && npobj->_class->invoke) { + D(bugiI("NPClass::Invoke(npobj %p, name id %p)\n", npobj, name)); print_npvariant_args(args, argCount); ret = npobj->_class->invoke(npobj, name, args, argCount, &result); gchar *result_str = string_of_NPVariant(&result); - D(bug(" return: %d (%s)\n", ret, result_str)); + D(bugiD("NPClass::Invoke return: %d (%s)\n", ret, result_str)); g_free(result_str); } @@ -189,12 +259,10 @@ int npclass_handle_Invoke(rpc_connection_t *connection) return rpc_ret; } -bool npclass_invoke_Invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args, uint32_t argCount, - NPVariant *result) +static bool npclass_invoke_Invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args, uint32_t argCount, + NPVariant *result) { - if (result == NULL) - return false; - VOID_TO_NPVARIANT(*result); + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPCLASS_INVOKE, @@ -222,9 +290,35 @@ bool npclass_invoke_Invoke(NPObject *npobj, NPIdentifier name, const NPVariant * return ret; } +bool g_NPClass_Invoke(NPObject *npobj, NPIdentifier name, const NPVariant *args, uint32_t argCount, + NPVariant *result) +{ + if (result == NULL) + return false; + VOID_TO_NPVARIANT(*result); + + if (!is_valid_npobject_class(npobj)) + return false; + + if (!pid_check()) { + npw_printf("WARNING: NPClass::Invoke called from the wrong process\n"); + return false; + } + + D(bugiI("NPClass::Invoke(npobj %p, name id %p)\n", npobj, name)); + print_npvariant_args(args, argCount); + bool ret = npclass_invoke_Invoke(npobj, name, args, argCount, result); + gchar *result_str = string_of_NPVariant(result); + D(bugiD("NPClass::Invoke return: %d (%s)\n", ret, result_str)); + g_free(result_str); + return ret; +} + // NPClass::InvokeDefault int npclass_handle_InvokeDefault(rpc_connection_t *connection) { + D(bug("npclass_handle_InvokeDefault\n")); + NPObject *npobj; uint32_t argCount; NPVariant *args; @@ -241,12 +335,12 @@ int npclass_handle_InvokeDefault(rpc_connection_t *connection) uint32_t ret = false; NPVariant result; VOID_TO_NPVARIANT(result); - if (npobj && npobj->_class && npobj->_class->invokeDefault) { - D(bug("NPClass::InvokeDefault(npobj %p)\n", npobj)); + if (npobj && is_valid_npobject_class(npobj) && npobj->_class->invokeDefault) { + D(bugiI("NPClass::InvokeDefault(npobj %p)\n", npobj)); print_npvariant_args(args, argCount); ret = npobj->_class->invokeDefault(npobj, args, argCount, &result); gchar *result_str = string_of_NPVariant(&result); - D(bug(" return: %d (%s)\n", ret, result_str)); + D(bugiD("NPClass::InvokeDefault return: %d (%s)\n", ret, result_str)); g_free(result_str); } @@ -265,12 +359,10 @@ int npclass_handle_InvokeDefault(rpc_connection_t *connection) return rpc_ret; } -bool npclass_invoke_InvokeDefault(NPObject *npobj, const NPVariant *args, uint32_t argCount, - NPVariant *result) +static bool npclass_invoke_InvokeDefault(NPObject *npobj, const NPVariant *args, uint32_t argCount, + NPVariant *result) { - if (result == NULL) - return false; - VOID_TO_NPVARIANT(*result); + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPCLASS_INVOKE_DEFAULT, @@ -297,9 +389,35 @@ bool npclass_invoke_InvokeDefault(NPObject *npobj, const NPVariant *args, uint32 return ret; } +bool g_NPClass_InvokeDefault(NPObject *npobj, const NPVariant *args, uint32_t argCount, + NPVariant *result) +{ + if (result == NULL) + return false; + VOID_TO_NPVARIANT(*result); + + if (!is_valid_npobject_class(npobj)) + return false; + + if (!pid_check()) { + npw_printf("WARNING: NPClass::InvokeDefault called from the wrong process\n"); + return false; + } + + D(bugiI("NPClass::InvokeDefault(npobj %p)\n", npobj)); + print_npvariant_args(args, argCount); + bool ret = npclass_invoke_InvokeDefault(npobj, args, argCount, result); + gchar *result_str = string_of_NPVariant(result); + D(bugiD("NPClass::InvokeDefault return: %d (%s)\n", ret, result_str)); + g_free(result_str); + return ret; +} + // NPClass::HasProperty int npclass_handle_HasProperty(rpc_connection_t *connection) { + D(bug("npclass_handle_HasProperty\n")); + NPObject *npobj; NPIdentifier name; int error = rpc_method_get_args(connection, @@ -313,10 +431,10 @@ int npclass_handle_HasProperty(rpc_connection_t *connection) } uint32_t ret = false; - if (npobj && npobj->_class && npobj->_class->hasProperty) { - D(bug("NPClass::HasProperty(npobj %p, name id %p)\n", npobj, name)); + if (npobj && is_valid_npobject_class(npobj) && npobj->_class->hasProperty) { + D(bugiI("NPClass::HasProperty(npobj %p, name id %p)\n", npobj, name)); ret = npobj->_class->hasProperty(npobj, name); - D(bug(" return: %d\n", ret)); + D(bugiD("NPClass::HasProperty return: %d\n", ret)); } return rpc_method_send_reply(connection, @@ -324,8 +442,10 @@ int npclass_handle_HasProperty(rpc_connection_t *connection) RPC_TYPE_INVALID); } -bool npclass_invoke_HasProperty(NPObject *npobj, NPIdentifier name) +static bool npclass_invoke_HasProperty(NPObject *npobj, NPIdentifier name) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPCLASS_HAS_PROPERTY, RPC_TYPE_NP_OBJECT, npobj, @@ -348,9 +468,27 @@ bool npclass_invoke_HasProperty(NPObject *npobj, NPIdentifier name) return ret; } +bool g_NPClass_HasProperty(NPObject *npobj, NPIdentifier name) +{ + if (!is_valid_npobject_class(npobj)) + return false; + + if (!pid_check()) { + npw_printf("WARNING: NPClass::HasProperty called from the wrong process\n"); + return false; + } + + D(bugiI("NPClass::HasProperty(npobj %p, name id %p)\n", npobj, name)); + bool ret = npclass_invoke_HasProperty(npobj, name); + D(bugiD("NPClass::HasProperty return: %d\n", ret)); + return ret; +} + // NPClass::GetProperty int npclass_handle_GetProperty(rpc_connection_t *connection) { + D(bug("npclass_handle_GetProperty\n")); + NPObject *npobj; NPIdentifier name; int error = rpc_method_get_args(connection, @@ -366,11 +504,11 @@ int npclass_handle_GetProperty(rpc_connection_t *connection) uint32_t ret = false; NPVariant result; VOID_TO_NPVARIANT(result); - if (npobj && npobj->_class && npobj->_class->getProperty) { - D(bug("NPClass::GetProperty(npobj %p, name id %p)\n", npobj, name)); + if (npobj && is_valid_npobject_class(npobj) && npobj->_class->getProperty) { + D(bugiI("NPClass::GetProperty(npobj %p, name id %p)\n", npobj, name)); ret = npobj->_class->getProperty(npobj, name, &result); gchar *result_str = string_of_NPVariant(&result); - D(bug(" return: %d (%s)\n", ret, result_str)); + D(bugiD("NPClass::GetProperty return: %d (%s)\n", ret, result_str)); g_free(result_str); } @@ -383,11 +521,9 @@ int npclass_handle_GetProperty(rpc_connection_t *connection) return rpc_ret; } -bool npclass_invoke_GetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result) +static bool npclass_invoke_GetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result) { - if (result == NULL) - return false; - VOID_TO_NPVARIANT(*result); + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPCLASS_GET_PROPERTY, @@ -414,9 +550,33 @@ bool npclass_invoke_GetProperty(NPObject *npobj, NPIdentifier name, NPVariant *r return ret; } +bool g_NPClass_GetProperty(NPObject *npobj, NPIdentifier name, NPVariant *result) +{ + if (result == NULL) + return false; + VOID_TO_NPVARIANT(*result); + + if (!is_valid_npobject_class(npobj)) + return false; + + if (!pid_check()) { + npw_printf("WARNING: NPClass::GetProperty called from the wrong process\n"); + return false; + } + + D(bugiI("NPClass::GetProperty(npobj %p, name id %p)\n", npobj, name)); + bool ret = npclass_invoke_GetProperty(npobj, name, result); + gchar *result_str = string_of_NPVariant(result); + D(bugiD("NPClass::GetProperty return: %d (%s)\n", ret, result_str)); + g_free(result_str); + return ret; +} + // NPClass::SetProperty int npclass_handle_SetProperty(rpc_connection_t *connection) { + D(bug("npclass_handle_SetProperty\n")); + NPObject *npobj; NPIdentifier name; NPVariant value; @@ -432,10 +592,10 @@ int npclass_handle_SetProperty(rpc_connection_t *connection) } uint32_t ret = false; - if (npobj && npobj->_class && npobj->_class->setProperty) { - D(bug("NPClass::SetProperty(npobj %p, name id %p)\n", npobj, name)); + if (npobj && is_valid_npobject_class(npobj) && npobj->_class->setProperty) { + D(bugiI("NPClass::SetProperty(npobj %p, name id %p)\n", npobj, name)); ret = npobj->_class->setProperty(npobj, name, &value); - D(bug(" return: %d\n", ret)); + D(bugiD("NPClass::SetProperty return: %d\n", ret)); } int rpc_ret = rpc_method_send_reply(connection, @@ -446,10 +606,9 @@ int npclass_handle_SetProperty(rpc_connection_t *connection) return rpc_ret; } -bool npclass_invoke_SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) +static bool npclass_invoke_SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) { - if (value == NULL) - return false; + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPCLASS_SET_PROPERTY, @@ -476,9 +635,32 @@ bool npclass_invoke_SetProperty(NPObject *npobj, NPIdentifier name, const NPVari return ret; } +bool g_NPClass_SetProperty(NPObject *npobj, NPIdentifier name, const NPVariant *value) +{ + if (value == NULL) { + npw_printf("WARNING: NPClass::SetProperty() called with a NULL value\n"); + return false; + } + + if (!is_valid_npobject_class(npobj)) + return false; + + if (!pid_check()) { + npw_printf("WARNING: NPClass::SetProperty called from the wrong process\n"); + return false; + } + + D(bugiI("NPClass::SetProperty(npobj %p, name id %p)\n", npobj, name)); + bool ret = npclass_invoke_SetProperty(npobj, name, value); + D(bugiD("NPClass::SetProperty return: %d\n", ret)); + return ret; +} + // NPClass::RemoveProperty int npclass_handle_RemoveProperty(rpc_connection_t *connection) { + D(bug("npclass_handle_RemoveProperty\n")); + NPObject *npobj; NPIdentifier name; int error = rpc_method_get_args(connection, @@ -492,10 +674,10 @@ int npclass_handle_RemoveProperty(rpc_connection_t *connection) } uint32_t ret = false; - if (npobj && npobj->_class && npobj->_class->removeProperty) { - D(bug("NPClass::RemoveProperty(npobj %p, name id %p)\n", npobj, name)); + if (npobj && is_valid_npobject_class(npobj) && npobj->_class->removeProperty) { + D(bugiI("NPClass::RemoveProperty(npobj %p, name id %p)\n", npobj, name)); ret = npobj->_class->removeProperty(npobj, name); - D(bug(" return: %d\n", ret)); + D(bugiD("NPClass::RemoveProperty return: %d\n", ret)); } return rpc_method_send_reply(connection, @@ -503,8 +685,10 @@ int npclass_handle_RemoveProperty(rpc_connection_t *connection) RPC_TYPE_INVALID); } -bool npclass_invoke_RemoveProperty(NPObject *npobj, NPIdentifier name) +static bool npclass_invoke_RemoveProperty(NPObject *npobj, NPIdentifier name) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPCLASS_REMOVE_PROPERTY, RPC_TYPE_NP_OBJECT, npobj, @@ -527,6 +711,22 @@ bool npclass_invoke_RemoveProperty(NPObject *npobj, NPIdentifier name) return ret; } +bool g_NPClass_RemoveProperty(NPObject *npobj, NPIdentifier name) +{ + if (!is_valid_npobject_class(npobj)) + return false; + + if (!pid_check()) { + npw_printf("WARNING: NPClass::RemoveProperty called from the wrong process\n"); + return false; + } + + D(bugiI("NPClass::RemoveProperty(npobj %p, name id %p)\n", npobj, name)); + bool ret = npclass_invoke_RemoveProperty(npobj, name); + D(bugiD("NPClass::RemoveProperty return: %d\n", ret)); + return ret; +} + /* ====================================================================== */ /* === NPObjectInfo === */ @@ -534,19 +734,22 @@ bool npclass_invoke_RemoveProperty(NPObject *npobj, NPIdentifier name) NPObjectInfo *npobject_info_new(NPObject *npobj) { - NPObjectInfo *npobj_info = malloc(sizeof(*npobj_info)); + NPObjectInfo *npobj_info = NPW_MemNew0(NPObjectInfo, 1); if (npobj_info) { static uint32_t id; npobj_info->npobj = npobj; npobj_info->npobj_id = ++id; + npobj_info->is_valid = true; } return npobj_info; } void npobject_info_destroy(NPObjectInfo *npobj_info) { - if (npobj_info) - free(npobj_info); + if (npobj_info) { + npw_plugin_instance_unref(npobj_info->plugin); + NPW_MemFree(npobj_info); + } } @@ -593,6 +796,7 @@ NPObject *npobject_new(uint32_t npobj_id, NPP instance, NPClass *class) 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; } @@ -665,6 +869,17 @@ NPObject *npobject_lookup(uint32_t npobj_id) return g_hash_table_lookup(g_npobject_ids, (void *)(uintptr_t)npobj_id); } +static void npruntime_deactivate_func(gpointer key, gpointer value, gpointer user_data) +{ + NPObjectInfo *npobj_info = (NPObjectInfo *)value; + npobj_info->is_valid = false; +} + +void npruntime_deactivate(void) +{ + g_hash_table_foreach(g_npobjects, npruntime_deactivate_func, NULL); +} + /* ====================================================================== */ /* === NPVariant helpers === */ @@ -703,6 +918,8 @@ gchar * string_of_NPVariant(const NPVariant *arg) { #if DEBUG + if (arg == NULL) + return NULL; GString *str = g_string_new(NULL); switch (arg->type) { @@ -752,7 +969,7 @@ print_npvariant_args(const NPVariant *args, uint32_t nargs) g_string_append(str, argstr); g_free(argstr); } - D(bug(" %u args (%s)\n", nargs, str->str)); + D(bug("%u args (%s)\n", nargs, str->str)); g_string_free(str, TRUE); #endif } diff --git a/src/npw-common.c b/src/npw-common.c index 2c09e02..1ec82eb 100644 --- a/src/npw-common.c +++ b/src/npw-common.c @@ -25,6 +25,57 @@ #define DEBUG 0 #include "debug.h" + +/* ====================================================================== */ +/* === Plugin instances === */ +/* ====================================================================== */ + +void * +npw_plugin_instance_new(NPW_PluginInstanceClass *klass) +{ + NPW_PluginInstance *plugin; + if (klass && klass->allocate) + plugin = klass->allocate (); + else + plugin = NPW_MemNew0 (NPW_PluginInstance, 1); + if (plugin) + { + plugin->klass = klass; + plugin->refcount = 1; + } + return plugin; +} + +void * +npw_plugin_instance_ref(void *ptr) +{ + NPW_PluginInstance *plugin = (NPW_PluginInstance *)ptr; + if (plugin) + plugin->refcount++; + return plugin; +} + +void +npw_plugin_instance_unref(void *ptr) +{ + NPW_PluginInstance *plugin = (NPW_PluginInstance *)ptr; + if (plugin == NULL) + return; + if (--plugin->refcount > 0) + return; + NPW_PluginInstanceClass *klass = plugin->klass; + if (klass && klass->finalize) + klass->finalize (plugin); + if (klass && klass->deallocate) + klass->deallocate (plugin); + else + NPW_MemFree (plugin); +} + +/* ====================================================================== */ +/* === NPAPI interface === */ +/* ====================================================================== */ + static NPNetscapeFuncs g_mozilla_funcs; static NPPluginFuncs g_plugin_funcs; @@ -38,10 +89,6 @@ NPW_InitializeFuncs (NPNetscapeFuncs *mozilla_funcs, MIN (sizeof (g_plugin_funcs), plugin_funcs->size)); } -/* ====================================================================== */ -/* === NPAPI interface === */ -/* ====================================================================== */ - void * NPN_MemAlloc (uint32_t size) { diff --git a/src/npw-common.h b/src/npw-common.h index 9562bea..0579a2d 100644 --- a/src/npw-common.h +++ b/src/npw-common.h @@ -55,16 +55,46 @@ /* PluginInstance */ #define NPW_DECL_PLUGIN_INSTANCE \ - NPP instance; \ - uint32_t instance_id; + NPW_PluginInstanceClass *klass; \ + uint32_t refcount; \ + NPP instance; \ + uint32_t instance_id; + +typedef struct _NPW_PluginInstance NPW_PluginInstance; +typedef struct _NPW_PluginInstanceClass NPW_PluginInstanceClass; -typedef struct _NPW_PluginInstance NPW_PluginInstance; struct _NPW_PluginInstance { NPW_DECL_PLUGIN_INSTANCE; }; -#define NPW_PLUGIN_INSTANCE(instance) npw_get_plugin_instance (instance) +typedef void * +(*NPW_PluginInstanceAllocateFunctionPtr) (void); + +typedef void +(*NPW_PluginInstanceDeallocateFunctionPtr) (NPW_PluginInstance *plugin); + +typedef void +(*NPW_PluginInstanceFinalizeFunctionPtr) (NPW_PluginInstance *plugin); + +struct _NPW_PluginInstanceClass +{ + NPW_PluginInstanceAllocateFunctionPtr allocate; + NPW_PluginInstanceDeallocateFunctionPtr deallocate; + NPW_PluginInstanceFinalizeFunctionPtr finalize; +}; + +void * +npw_plugin_instance_new(NPW_PluginInstanceClass *klass) attribute_hidden; + +void * +npw_plugin_instance_ref(void *ptr) attribute_hidden; + +void +npw_plugin_instance_unref(void *ptr) attribute_hidden; + +#define NPW_PLUGIN_INSTANCE(instance) npw_get_plugin_instance (instance) +#define NPW_PLUGIN_INSTANCE_NPP(plugin) npw_get_plugin_instance_npp (plugin) static inline NPW_PluginInstance * _npw_get_plugin_instance (NPP instance) @@ -95,6 +125,12 @@ npw_get_plugin_instance (NPP instance) return NULL; } +static inline NPP +npw_get_plugin_instance_npp (NPW_PluginInstance *plugin) +{ + return plugin ? plugin->instance : NULL; +} + /* StreamInstance */ #define NPW_DECL_STREAM_INSTANCE \ NPStream *stream; \ @@ -109,13 +145,25 @@ struct _NPW_StreamInstance #define NPW_STREAM_INSTANCE(stream) npw_get_stream_instance (stream) +static inline NPW_StreamInstance * +_npw_get_stream_instance (NPStream *np_stream) +{ + return (NPW_StreamInstance *)np_stream->_NPW_INSTANCE_PRIVATE_DATA; +} + static inline NPW_StreamInstance * npw_get_stream_instance (NPStream *np_stream) { - NPW_StreamInstance *stream; - stream = (NPW_StreamInstance *)np_stream->_NPW_INSTANCE_PRIVATE_DATA; - assert (stream->stream == np_stream); - return stream; + if (np_stream) + { + NPW_StreamInstance *stream; + if ((stream = _npw_get_stream_instance (np_stream)) != NULL) + { + assert (stream->stream == np_stream); + return stream; + } + } + return NULL; } /* Unimplemented functions */ @@ -124,7 +172,7 @@ npw_get_stream_instance (NPStream *np_stream) __func__, __FILE__, __LINE__) /* Initialize NPAPI hooks */ -extern void +void NPW_InitializeFuncs (NPNetscapeFuncs *mozilla_funcs, NPPluginFuncs *plugin_funcs) attribute_hidden; @@ -146,19 +194,19 @@ struct _NPW_Identifier }; /* Create identifier from an integer */ -extern NPW_Identifier +NPW_Identifier NPW_CreateIntIdentifier (int32_t value); /* Create identifier from a string (that is copied) */ -extern NPW_Identifier +NPW_Identifier NPW_CreateStringIdentifier (const char *str); /* Create identifier from a string (that is now owned by the identifier) */ -extern NPW_Identifier +NPW_Identifier NPW_CreateStringIdentifierSink (char *str); /* Destroy identifier */ -extern void +void NPW_DestroyIdentifier (NPW_Identifier id); /* Check whether identifier is an integer */ diff --git a/src/npw-malloc.h b/src/npw-malloc.h index 0aa03ac..d5b45ba 100644 --- a/src/npw-malloc.h +++ b/src/npw-malloc.h @@ -30,4 +30,10 @@ NPW_MemAlloc0 (uint32_t size); void NPW_MemFree (void *ptr); +#define NPW_MemNew(type, n) \ + ((type *) NPW_MemAlloc ((n) * sizeof (type))) + +#define NPW_MemNew0(type, n) \ + ((type *) NPW_MemAlloc0 ((n) * sizeof (type))) + #endif /* NPW_MALLOC_H */ diff --git a/src/npw-player.c b/src/npw-player.c index 6d85a8e..b7b8925 100644 --- a/src/npw-player.c +++ b/src/npw-player.c @@ -1284,17 +1284,17 @@ stream_new (Plugin *plugin, const gchar *src, const gchar *type, void *notify_data, NPError *error) { - NPError ret = NPERR_NO_ERROR; + StreamInstance *pstream = NULL; + NPStream *np_stream = NULL; + NPError ret = NPERR_NO_ERROR; - StreamInstance *pstream = g_new0 (StreamInstance, 1); - if (pstream == NULL) + if ((pstream = g_new0 (StreamInstance, 1)) == NULL) { ret = NPERR_OUT_OF_MEMORY_ERROR; goto l_error; } - NPStream *np_stream = np_stream_new (src, notify_data); - if (np_stream == NULL) + if ((np_stream = np_stream_new (src, notify_data)) == NULL) { ret = NPERR_OUT_OF_MEMORY_ERROR; goto l_error; @@ -1643,10 +1643,6 @@ on_stream_close_cb (gpointer user_data) { if (!(pstream->status & STREAM_STATUS_ACTIVE)) { - /* XXX: consider the stream in error if it was never started */ - if (pstream->buffers == NULL) - pstream->status |= STREAM_STATUS_ERROR; - /* Special case for JavaScript that CURL could not handle */ const gchar * const url = pstream->np_stream->url; if (g_ascii_strncasecmp (url, "javascript:", 11) == 0) @@ -1697,6 +1693,10 @@ on_stream_close_cb (gpointer user_data) g_string_free (text, TRUE); } } + + /* XXX: consider the stream in error if it was never started */ + if (pstream->buffers == NULL) + pstream->status |= STREAM_STATUS_ERROR; } stream_schedule_destroy (pstream, FALSE); diff --git a/src/npw-rpc.c b/src/npw-rpc.c index 0cce610..47500ae 100644 --- a/src/npw-rpc.c +++ b/src/npw-rpc.c @@ -90,22 +90,19 @@ int rpc_type_of_NPPVariable(int variable) /* - * Process NPP objects + * Process NPW_PluginInstance objects */ -static int do_send_NPP(rpc_message_t *message, void *p_value) +static int do_send_NPW_PluginInstance(rpc_message_t *message, void *p_value) { + NPW_PluginInstance *plugin = (NPW_PluginInstance *)p_value; uint32_t instance_id = 0; - NPP instance = (NPP)p_value; - if (instance) { - NPW_PluginInstance *plugin = NPW_PLUGIN_INSTANCE(instance); - if (plugin) - instance_id = plugin->instance_id; - } + if (plugin) + instance_id = plugin->instance_id; return rpc_message_send_uint32(message, instance_id); } -static int do_recv_NPP(rpc_message_t *message, void *p_value) +static int do_recv_NPW_PluginInstance(rpc_message_t *message, void *p_value) { int error; uint32_t instance_id; @@ -115,9 +112,35 @@ static int do_recv_NPP(rpc_message_t *message, void *p_value) NPW_PluginInstance *plugin = id_lookup(instance_id); if (instance_id && plugin == NULL) - npw_printf("ERROR: passing an unknown instance\n"); - if (plugin && plugin->instance == NULL) - npw_printf("ERROR: passing a NULL instance through plugin instance id\n"); + npw_printf("ERROR: no valid NPP -> PluginInstance mapping found\n"); + else if (plugin && plugin->instance == NULL) + npw_printf("ERROR: no valid PluginInstance -> NPP mapping found\n"); + *((NPW_PluginInstance **)p_value) = plugin; + return RPC_ERROR_NO_ERROR; +} + + +/* + * Process NPP objects + */ + +static int do_send_NPP(rpc_message_t *message, void *p_value) +{ + NPP instance = (NPP)p_value; + NPW_PluginInstance *plugin = NULL; + if (instance) + plugin = NPW_PLUGIN_INSTANCE(instance); + return do_send_NPW_PluginInstance(message, plugin); +} + +static int do_recv_NPP(rpc_message_t *message, void *p_value) +{ + int error; + NPW_PluginInstance *plugin; + + if ((error = do_recv_NPW_PluginInstance(message, &plugin)) < 0) + return error; + *((NPP *)p_value) = plugin ? plugin->instance : NULL; return RPC_ERROR_NO_ERROR; } @@ -1145,7 +1168,6 @@ static int do_recv_NPPrintData(rpc_message_t *message, void *p_value) * Process NPObject objects */ -// XXX propagate reference counters? static int do_send_NPObject(rpc_message_t *message, void *p_value) { uint32_t npobj_id = 0; @@ -1165,7 +1187,19 @@ static int do_send_NPObject(rpc_message_t *message, void *p_value) #endif assert(npobj_id != 0); } - return rpc_message_send_uint32(message, npobj_id); + 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; } static int do_recv_NPObject(rpc_message_t *message, void *p_value) @@ -1187,7 +1221,20 @@ static int do_recv_NPObject(rpc_message_t *message, void *p_value) } #endif 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; return RPC_ERROR_NO_ERROR; } @@ -1451,6 +1498,12 @@ static const rpc_message_descriptor_t message_descs[] = { do_send_NPP, do_recv_NPP }, + { + RPC_TYPE_NPW_PLUGIN_INSTANCE, + sizeof(NPW_PluginInstance *), + do_send_NPW_PluginInstance, + do_recv_NPW_PluginInstance + }, { RPC_TYPE_NP_STREAM, sizeof(NPStream *), diff --git a/src/npw-rpc.h b/src/npw-rpc.h index e075375..6337807 100644 --- a/src/npw-rpc.h +++ b/src/npw-rpc.h @@ -115,7 +115,8 @@ enum { RPC_TYPE_NP_IDENTIFIER, RPC_TYPE_NP_STRING, /* 15 */ RPC_TYPE_NP_VARIANT, - RPC_TYPE_NP_UTF8 + RPC_TYPE_NP_UTF8, + RPC_TYPE_NPW_PLUGIN_INSTANCE }; // NPPrintData is used to get the plugin printed tmpfile diff --git a/src/npw-viewer.c b/src/npw-viewer.c index 3f23e66..ab0a1b8 100644 --- a/src/npw-viewer.c +++ b/src/npw-viewer.c @@ -52,21 +52,22 @@ // [UNIMPLEMENTED] Define to use XPCOM emulation #define USE_XPCOM 0 -// Define to use XEMBED hack (GTK_WINDOW_POPUP toplevel instead of GtkPlug) +// Define to use XEMBED hack (don't let browser kill our window) #define USE_XEMBED_HACK 1 // Define to allow windowless plugins #define ALLOW_WINDOWLESS_PLUGINS 1 - // RPC global connections rpc_connection_t *g_rpc_connection attribute_hidden = NULL; +// Viewer orignal pid - check against incorrect plugins +static pid_t g_viewer_pid = 0; + // Instance state information about the plugin typedef struct _PluginInstance { NPW_DECL_PLUGIN_INSTANCE; bool use_xembed; - bool use_xembed_hack; bool is_windowless; NPWindow window; uint32_t width, height; @@ -77,6 +78,9 @@ typedef struct _PluginInstance { #define PLUGIN_INSTANCE(instance) \ ((PluginInstance *)NPW_PLUGIN_INSTANCE(instance)) +#define PLUGIN_INSTANCE_NPP(plugin) \ + NPW_PLUGIN_INSTANCE_NPP((NPW_PluginInstance *)(plugin)) + // Browser side data for an NPStream instance typedef struct _StreamInstance { NPW_DECL_STREAM_INSTANCE; @@ -91,11 +95,137 @@ typedef struct _XtData { // Gtk wrapper data typedef struct _GtkData { - GdkWindow *browser_window; GtkWidget *container; GtkWidget *socket; } GtkData; +// Prototypes +static void destroy_window(PluginInstance *plugin); + + +/* ====================================================================== */ +/* === Helpers === */ +/* ====================================================================== */ + +// PluginInstance vfuncs +static void *plugin_instance_allocate(void); +static void plugin_instance_deallocate(PluginInstance *plugin); +static void plugin_instance_finalize(PluginInstance *plugin); + +static NPW_PluginInstanceClass PluginInstanceClass = { + (NPW_PluginInstanceAllocateFunctionPtr)plugin_instance_allocate, + (NPW_PluginInstanceDeallocateFunctionPtr)plugin_instance_deallocate, + (NPW_PluginInstanceFinalizeFunctionPtr)plugin_instance_finalize +}; + +static void *plugin_instance_allocate(void) +{ + return NPW_MemNew0(PluginInstance, 1); +} + +static void plugin_instance_deallocate(PluginInstance *plugin) +{ + NPW_MemFree(plugin); +} + +static void plugin_instance_finalize(PluginInstance *plugin) +{ + if (plugin->browser_toplevel) { + g_object_unref(plugin->browser_toplevel); + plugin->browser_toplevel = NULL; + } + destroy_window(plugin); +} + +// Pid support routines +static void pid_init(void) +{ + g_viewer_pid = getpid(); +} + +bool pid_check(void) +{ +#if USE_PID_CHECK + return (g_viewer_pid == getpid()); +#endif + 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, + RPC_DELAYED_NPN_INVALIDATE_RECT, +}; + +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) +{ + GList *l = g_delayed_calls; + while (l != NULL) { + GList *cl = l; + l = l->next; + + 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 *)cl->data; + switch (dcall->type) { + case RPC_DELAYED_NPN_RELEASE_OBJECT: + { + NPObject *npobj = (NPObject *)dcall->data; + g_NPN_ReleaseObject_Now(npobj); + break; + } + } + NPW_MemFree(dcall); + g_delayed_calls = g_list_delete_link(g_delayed_calls, cl); + } + + 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); +} + /* ====================================================================== */ /* === X Toolkit glue === */ @@ -420,20 +550,11 @@ static int create_window(PluginInstance *plugin, NPWindow *window) GtkData *toolkit = calloc(1, sizeof(*toolkit)); if (toolkit == NULL) return -1; - if (plugin->use_xembed_hack) - toolkit->container = gtk_window_new(GTK_WINDOW_POPUP); - else - toolkit->container = gtk_plug_new((GdkNativeWindow)window->window); + 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); - if (plugin->use_xembed_hack) { - toolkit->browser_window = gdk_window_foreign_new((GdkNativeWindow)window->window); - if (toolkit->browser_window == NULL) - return -1; - gdk_window_reparent(toolkit->container->window, toolkit->browser_window, 0, 0); - } toolkit->socket = gtk_socket_new(); if (toolkit->socket == NULL) return -1; @@ -442,6 +563,14 @@ static int create_window(PluginInstance *plugin, NPWindow *window) gtk_widget_show_all(toolkit->container); window->window = (void *)gtk_socket_get_id(GTK_SOCKET(toolkit->socket)); plugin->toolkit_data = toolkit; +#if USE_XEMBED_HACK + // don't let the browser kill our window out of NPP_Destroy() scope + g_signal_connect(toolkit->container, "delete-event", + G_CALLBACK(gtk_true), NULL); +#endif + // make sure we don't try to destroy the widget again in destroy_window() + g_signal_connect(toolkit->container, "destroy", + G_CALLBACK(gtk_widget_destroyed), &toolkit->container); // keep the socket as the plugin tries to destroy the widget itself g_signal_connect(toolkit->socket, "plug_removed", G_CALLBACK(gtk_true), NULL); @@ -521,7 +650,7 @@ static int update_window(PluginInstance *plugin, NPWindow *window) plugin->window.height = window->height; if (plugin->toolkit_data) { if (plugin->use_xembed) { - // XXX check window size changes are already caught per the XEMBED protocol + // window size changes are already caught per the XEMBED protocol } else { XtData *toolkit = (XtData *)plugin->toolkit_data; @@ -589,11 +718,14 @@ g_NPN_ForceRedraw(NPP instance) // Asks the browser to create a stream for the specified URL static NPError -invoke_NPN_GetURL(NPP instance, const char *url, const char *target) +invoke_NPN_GetURL(PluginInstance *plugin, const char *url, const char *target) { + 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_NPN_GET_URL, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_STRING, url, RPC_TYPE_STRING, target, RPC_TYPE_INVALID); @@ -617,22 +749,36 @@ invoke_NPN_GetURL(NPP instance, const char *url, const char *target) static NPError g_NPN_GetURL(NPP instance, const char *url, const char *target) { + if (!pid_check()) { + npw_printf("WARNING: NPN_GetURL called from the wrong process\n"); + return NPERR_INVALID_INSTANCE_ERROR; + } + if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; - D(bug("NPN_GetURL instance=%p\n", instance)); - NPError ret = invoke_NPN_GetURL(instance, url, target); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return NPERR_INVALID_INSTANCE_ERROR; + + D(bugiI("NPN_GetURL instance=%p\n", instance)); + npw_plugin_instance_ref(plugin); + NPError ret = invoke_NPN_GetURL(plugin, url, target); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_GetURL return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } // Requests creation of a new stream with the contents of the specified URL static NPError -invoke_NPN_GetURLNotify(NPP instance, const char *url, const char *target, void *notifyData) +invoke_NPN_GetURLNotify(PluginInstance *plugin, const char *url, const char *target, void *notifyData) { + 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_NPN_GET_URL_NOTIFY, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_STRING, url, RPC_TYPE_STRING, target, RPC_TYPE_NP_NOTIFY_DATA, notifyData, @@ -657,22 +803,36 @@ invoke_NPN_GetURLNotify(NPP instance, const char *url, const char *target, void static NPError g_NPN_GetURLNotify(NPP instance, const char *url, const char *target, void *notifyData) { + if (!pid_check()) { + npw_printf("WARNING: NPN_GetURLNotify called from the wrong process\n"); + return NPERR_INVALID_INSTANCE_ERROR; + } + if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; - D(bug("NPN_GetURLNotify instance=%p\n", instance)); - NPError ret = invoke_NPN_GetURLNotify(instance, url, target, notifyData); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return NPERR_INVALID_INSTANCE_ERROR; + + D(bugiI("NPN_GetURLNotify instance=%p\n", instance)); + npw_plugin_instance_ref(plugin); + NPError ret = invoke_NPN_GetURLNotify(plugin, url, target, notifyData); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_GetURLNotify return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } // Allows the plug-in to query the browser for information static NPError -invoke_NPN_GetValue(NPP instance, NPNVariable variable, void *value) +invoke_NPN_GetValue(PluginInstance *plugin, NPNVariable variable, void *value) { + 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_NPN_GET_VALUE, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_UINT32, variable, RPC_TYPE_INVALID); @@ -691,7 +851,7 @@ invoke_NPN_GetValue(NPP instance, NPNVariable variable, void *value) npw_perror("NPN_GetValue() wait for reply", error); ret = NPERR_GENERIC_ERROR; } - D(bug(" value: %u\n", n)); + D(bug("-> value: %u\n", n)); *((unsigned int *)value) = n; break; } @@ -703,7 +863,7 @@ invoke_NPN_GetValue(NPP instance, NPNVariable variable, void *value) npw_perror("NPN_GetValue() wait for reply", error); ret = NPERR_GENERIC_ERROR; } - D(bug(" value: %s\n", b ? "true" : "false")); + D(bug("-> value: %s\n", b ? "true" : "false")); *((PRBool *)value) = b ? PR_TRUE : PR_FALSE; break; } @@ -715,7 +875,7 @@ invoke_NPN_GetValue(NPP instance, NPNVariable variable, void *value) npw_perror("NPN_GetValue() wait for reply", error); ret = NPERR_GENERIC_ERROR; } - D(bug(" value: %p\n", npobj)); + D(bug("-> value: \n", npobj)); *((NPObject **)value) = npobj; break; } @@ -727,13 +887,29 @@ invoke_NPN_GetValue(NPP instance, NPNVariable variable, void *value) static NPError g_NPN_GetValue_real(NPP instance, NPNVariable variable, void *value) { - return invoke_NPN_GetValue(instance, variable, value); + PluginInstance *plugin = NULL; + if (instance) + plugin = PLUGIN_INSTANCE(instance); + + npw_plugin_instance_ref(plugin); + NPError ret = invoke_NPN_GetValue(plugin, variable, value); + npw_plugin_instance_unref(plugin); + return ret; } static NPError g_NPN_GetValue(NPP instance, NPNVariable variable, void *value) { - D(bug("NPN_GetValue instance=%p, variable=%d [%08x]\n", instance, variable & 0xffff, variable)); + D(bug("NPN_GetValue instance=%p, variable=%d [%s]\n", instance, variable, string_of_NPNVariable(variable))); + + if (!pid_check()) { + npw_printf("WARNING: NPN_GetValue called from the wrong process\n"); + return NPERR_INVALID_INSTANCE_ERROR; + } + + PluginInstance *plugin = NULL; + if (instance) + plugin = PLUGIN_INSTANCE(instance); switch (variable) { case NPNVxDisplay: @@ -749,14 +925,23 @@ g_NPN_GetValue(NPP instance, NPNVariable variable, void *value) case NPNVserviceManager: { nsIServiceManager *sm; int ret = NS_GetServiceManager(&sm); - if (NS_FAILED(ret)) + if (NS_FAILED(ret)) { + npw_printf("WARNING: NS_GetServiceManager failed\n"); return NPERR_GENERIC_ERROR; + } *(nsIServiceManager **)value = sm; break; } + case NPNVDOMWindow: + case NPNVDOMElement: + npw_printf("WARNING: %s is not supported by NPN_GetValue()\n", string_of_NPNVariable(variable)); + return NPERR_INVALID_PARAM; #endif - case NPNVnetscapeWindow: { - PluginInstance *plugin = PLUGIN_INSTANCE(instance); + case NPNVnetscapeWindow: + if (plugin == NULL) { + npw_printf("ERROR: NPNVnetscapeWindow requires a non NULL instance\n"); + return NPERR_INVALID_INSTANCE_ERROR; + } if (plugin->browser_toplevel == NULL) { GdkNativeWindow netscape_xid = None; NPError error = g_NPN_GetValue_real(instance, variable, &netscape_xid); @@ -770,7 +955,6 @@ g_NPN_GetValue(NPP instance, NPNVariable variable, void *value) } *((GdkNativeWindow *)value) = GDK_WINDOW_XWINDOW(plugin->browser_toplevel); break; - } #if ALLOW_WINDOWLESS_PLUGINS case NPNVSupportsWindowless: #endif @@ -779,7 +963,7 @@ g_NPN_GetValue(NPP instance, NPNVariable variable, void *value) case NPNVPluginElementNPObject: return g_NPN_GetValue_real(instance, variable, value); default: - npw_printf("WARNING: unhandled variable %d in NPN_GetValue()\n", variable); + npw_printf("WARNING: unhandled variable %d (%s) in NPN_GetValue()\n", variable, string_of_NPNVariable(variable)); return NPERR_INVALID_PARAM; } @@ -788,11 +972,13 @@ g_NPN_GetValue(NPP instance, NPNVariable variable, void *value) // Invalidates specified drawing area prior to repainting or refreshing a windowless plug-in static void -invoke_NPN_InvalidateRect(NPP instance, NPRect *invalidRect) +invoke_NPN_InvalidateRect(PluginInstance *plugin, NPRect *invalidRect) { + npw_return_if_fail(rpc_method_invoke_possible(g_rpc_connection)); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_INVALIDATE_RECT, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_RECT, invalidRect, RPC_TYPE_INVALID); @@ -812,12 +998,26 @@ invoke_NPN_InvalidateRect(NPP instance, NPRect *invalidRect) static void g_NPN_InvalidateRect(NPP instance, NPRect *invalidRect) { - if (instance == NULL || invalidRect == NULL) + if (!pid_check()) { + npw_printf("WARNING: NPN_InvalidateRect called from the wrong process\n"); + return; + } + + if (instance == NULL) return; - D(bug("NPN_InvalidateRect instance=%p\n", instance)); - invoke_NPN_InvalidateRect(instance, invalidRect); - D(bug(" done\n")); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return; + + if (invalidRect == NULL) + return; + + D(bugiI("NPN_InvalidateRect instance=%p\n", PLUGIN_INSTANCE_NPP(plugin))); + npw_plugin_instance_ref(plugin); + invoke_NPN_InvalidateRect(plugin, invalidRect); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_InvalidateRect done\n")); } // Invalidates specified region prior to repainting or refreshing a windowless plug-in @@ -833,10 +1033,10 @@ g_NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion) static void * g_NPN_MemAlloc(uint32 size) { - D(bug("NPN_MemAlloc size=%d\n", size)); + D(bugiI("NPN_MemAlloc size=%d\n", size)); void *ptr = NPW_MemAlloc(size); - D(bug(" return: %p\n", ptr)); + D(bugiD("NPN_MemAlloc return: %p\n", ptr)); return ptr; } @@ -845,7 +1045,6 @@ static uint32 g_NPN_MemFlush(uint32 size) { D(bug("NPN_MemFlush size=%d\n", size)); - return 0; } @@ -853,18 +1052,21 @@ g_NPN_MemFlush(uint32 size) static void g_NPN_MemFree(void *ptr) { - D(bug("NPN_MemFree ptr=%p\n", ptr)); - + D(bugiI("NPN_MemFree ptr=%p\n", ptr)); NPW_MemFree(ptr); + D(bugiD("NPN_MemFree done\n")); } // Posts data to a URL static NPError -invoke_NPN_PostURL(NPP instance, const char *url, const char *target, uint32 len, const char *buf, NPBool file) +invoke_NPN_PostURL(PluginInstance *plugin, const char *url, const char *target, uint32 len, const char *buf, NPBool file) { + 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_NPN_POST_URL, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_STRING, url, RPC_TYPE_STRING, target, RPC_TYPE_ARRAY, RPC_TYPE_CHAR, len, buf, @@ -890,22 +1092,36 @@ invoke_NPN_PostURL(NPP instance, const char *url, const char *target, uint32 len static NPError g_NPN_PostURL(NPP instance, const char *url, const char *target, uint32 len, const char *buf, NPBool file) { + if (!pid_check()) { + npw_printf("WARNING: NPN_PostURL called from the wrong process\n"); + return NPERR_INVALID_INSTANCE_ERROR; + } + if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; - D(bug("NPN_PostURL instance=%p\n", instance)); - NPError ret = invoke_NPN_PostURL(instance, url, target, len, buf, file); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return NPERR_INVALID_INSTANCE_ERROR; + + D(bugiI("NPN_PostURL instance=%p\n", instance)); + npw_plugin_instance_ref(plugin); + NPError ret = invoke_NPN_PostURL(plugin, url, target, len, buf, file); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_PostURL return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } // Posts data to a URL, and receives notification of the result static NPError -invoke_NPN_PostURLNotify(NPP instance, const char *url, const char *target, uint32 len, const char *buf, NPBool file, void *notifyData) +invoke_NPN_PostURLNotify(PluginInstance *plugin, const char *url, const char *target, uint32 len, const char *buf, NPBool file, void *notifyData) { + 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_NPN_POST_URL_NOTIFY, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_STRING, url, RPC_TYPE_STRING, target, RPC_TYPE_ARRAY, RPC_TYPE_CHAR, len, buf, @@ -932,12 +1148,23 @@ invoke_NPN_PostURLNotify(NPP instance, const char *url, const char *target, uint static NPError g_NPN_PostURLNotify(NPP instance, const char *url, const char *target, uint32 len, const char *buf, NPBool file, void *notifyData) { + if (!pid_check()) { + npw_printf("WARNING: NPN_PostURLNotify called from the wrong process\n"); + return NPERR_INVALID_INSTANCE_ERROR; + } + if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; - D(bug("NPN_PostURLNotify instance=%p\n", instance)); - NPError ret = invoke_NPN_PostURLNotify(instance, url, target, len, buf, file, notifyData); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return NPERR_INVALID_INSTANCE_ERROR; + + D(bugiI("NPN_PostURLNotify instance=%p\n", instance)); + npw_plugin_instance_ref(plugin); + NPError ret = invoke_NPN_PostURLNotify(plugin, url, target, len, buf, file, notifyData); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_PostURLNotify return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } @@ -972,6 +1199,9 @@ g_NPN_GetJavaPeer(NPP instance) static NPError invoke_NPN_RequestRead(NPStream *stream, NPByteRange *rangeList) { + 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_NPN_REQUEST_READ, RPC_TYPE_NP_STREAM, stream, @@ -997,12 +1227,17 @@ invoke_NPN_RequestRead(NPStream *stream, NPByteRange *rangeList) static NPError g_NPN_RequestRead(NPStream *stream, NPByteRange *rangeList) { + if (!pid_check()) { + npw_printf("WARNING: NPN_RequestRead called from the wrong process\n"); + return NPERR_INVALID_INSTANCE_ERROR; + } + if (stream == NULL || stream->ndata == NULL || rangeList == NULL) return NPERR_INVALID_PARAM; - D(bug("NPN_RequestRead stream=%p\n", stream)); + D(bugiI("NPN_RequestRead stream=%p\n", stream)); NPError ret = invoke_NPN_RequestRead(stream, rangeList); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPN_RequestRead return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } @@ -1018,9 +1253,12 @@ invoke_NPN_SetValue(PluginInstance *plugin, NPPVariable variable, void *value) return NPERR_INVALID_PARAM; } + 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_NPN_SET_VALUE, - RPC_TYPE_NPP, plugin->instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_UINT32, variable, RPC_TYPE_BOOLEAN, (uint32_t)(uintptr_t)value, RPC_TYPE_INVALID); @@ -1042,6 +1280,11 @@ invoke_NPN_SetValue(PluginInstance *plugin, NPPVariable variable, void *value) static NPError g_NPN_SetValue(NPP instance, NPPVariable variable, void *value) { + if (!pid_check()) { + npw_printf("WARNING: NPN_SetValue called from the wrong process\n"); + return NPERR_INVALID_INSTANCE_ERROR; + } + if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; @@ -1049,19 +1292,23 @@ g_NPN_SetValue(NPP instance, NPPVariable variable, void *value) if (plugin == NULL) return NPERR_INVALID_INSTANCE_ERROR; - D(bug("NPN_SetValue instance=%p, variable=%d\n", instance, variable)); + D(bugiI("NPN_SetValue instance=%p, variable=%d [%s]\n", instance, variable, string_of_NPPVariable(variable))); + npw_plugin_instance_ref(plugin); NPError ret = invoke_NPN_SetValue(plugin, variable, value); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_SetValue return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } // Displays a message on the status line of the browser window static void -invoke_NPN_Status(NPP instance, const char *message) +invoke_NPN_Status(PluginInstance *plugin, const char *message) { + npw_return_if_fail(rpc_method_invoke_possible(g_rpc_connection)); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_STATUS, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_STRING, message, RPC_TYPE_INVALID); @@ -1081,23 +1328,42 @@ invoke_NPN_Status(NPP instance, const char *message) static void g_NPN_Status(NPP instance, const char *message) { - D(bug("NPN_Status instance=%p\n", instance)); - invoke_NPN_Status(instance, message); - D(bug(" done\n")); + if (!pid_check()) { + npw_printf("WARNING: NPN_Status called from the wrong process\n"); + return; + } + + PluginInstance *plugin = NULL; + if (instance) + plugin = PLUGIN_INSTANCE(instance); + + D(bugiI("NPN_Status instance=%p, message='%s'\n", instance, message)); + npw_plugin_instance_ref(plugin); + invoke_NPN_Status(plugin, message); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_Status done\n")); } // Returns the browser's user agent field static char * invoke_NPN_UserAgent(void) { - int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_USER_AGENT, RPC_TYPE_INVALID); + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), NULL); + + int error = rpc_method_invoke(g_rpc_connection, + RPC_METHOD_NPN_USER_AGENT, + RPC_TYPE_INVALID); + if (error != RPC_ERROR_NO_ERROR) { npw_perror("NPN_UserAgent() invoke", error); return NULL; } char *user_agent; - error = rpc_method_wait_for_reply(g_rpc_connection, RPC_TYPE_STRING, &user_agent, RPC_TYPE_INVALID); + error = rpc_method_wait_for_reply(g_rpc_connection, + RPC_TYPE_STRING, &user_agent, + RPC_TYPE_INVALID); + if (error != RPC_ERROR_NO_ERROR) { npw_perror("NPN_UserAgent() wait for reply", error); return NULL; @@ -1109,20 +1375,28 @@ invoke_NPN_UserAgent(void) static const char * g_NPN_UserAgent(NPP instance) { - D(bug("NPN_UserAgent instance=%p\n", instance)); + if (!pid_check()) { + npw_printf("WARNING: NPN_UserAgent called from the wrong process\n"); + return NULL; + } + + D(bugiI("NPN_UserAgent instance=%p\n", instance)); if (g_user_agent == NULL) g_user_agent = invoke_NPN_UserAgent(); - D(bug(" user_agent='%s'\n", g_user_agent)); + D(bugiD("NPN_UserAgent return: '%s'\n", g_user_agent)); return g_user_agent; } // Requests the creation of a new data stream produced by the plug-in and consumed by the browser static NPError -invoke_NPN_NewStream(NPP instance, NPMIMEType type, const char *target, NPStream **pstream) +invoke_NPN_NewStream(PluginInstance *plugin, NPMIMEType type, const char *target, NPStream **pstream) { + 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_NPN_NEW_STREAM, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_STRING, type, RPC_TYPE_STRING, target, RPC_TYPE_INVALID); @@ -1191,26 +1465,40 @@ invoke_NPN_NewStream(NPP instance, NPMIMEType type, const char *target, NPStream static NPError g_NPN_NewStream(NPP instance, NPMIMEType type, const char *target, NPStream **stream) { + if (!pid_check()) { + npw_printf("WARNING: NPN_NewStream called from the wrong process\n"); + return NPERR_INVALID_INSTANCE_ERROR; + } + if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return NPERR_INVALID_INSTANCE_ERROR; + if (stream == NULL) return NPERR_INVALID_PARAM; *stream = NULL; - D(bug("NPN_NewStream instance=%p\n", instance)); - NPError ret = invoke_NPN_NewStream(instance, type, target, stream); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiI("NPN_NewStream instance=%p\n", instance)); + npw_plugin_instance_ref(plugin); + NPError ret = invoke_NPN_NewStream(plugin, type, target, stream); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_NewStream return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } // Closes and deletes a stream static NPError -invoke_NPN_DestroyStream(NPP instance, NPStream *stream, NPError reason) +invoke_NPN_DestroyStream(PluginInstance *plugin, NPStream *stream, NPError reason) { + 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_NPN_DESTROY_STREAM, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_STREAM, stream, RPC_TYPE_INT32, (int32_t)reason, RPC_TYPE_INVALID); @@ -1236,16 +1524,27 @@ invoke_NPN_DestroyStream(NPP instance, NPStream *stream, NPError reason) static NPError g_NPN_DestroyStream(NPP instance, NPStream *stream, NPError reason) { + if (!pid_check()) { + npw_printf("WARNING: NPN_DestroyStream called from the wrong process\n"); + return NPERR_INVALID_INSTANCE_ERROR; + } + if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return NPERR_INVALID_INSTANCE_ERROR; + if (stream == NULL) return NPERR_INVALID_PARAM; - D(bug("NPN_DestroyStream instance=%p, stream=%p, reason=%s\n", + D(bugiI("NPN_DestroyStream instance=%p, stream=%p, reason=%s\n", instance, stream, string_of_NPReason(reason))); - NPError ret = invoke_NPN_DestroyStream(instance, stream, reason); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + npw_plugin_instance_ref(plugin); + NPError ret = invoke_NPN_DestroyStream(plugin, stream, reason); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_DestroyStream return: %d [%s]\n", ret, string_of_NPError(ret))); // Mozilla calls NPP_DestroyStream() for its streams, keep stream // info in that case @@ -1263,11 +1562,13 @@ g_NPN_DestroyStream(NPP instance, NPStream *stream, NPError reason) // Pushes data into a stream produced by the plug-in and consumed by the browser static int -invoke_NPN_Write(NPP instance, NPStream *stream, int32 len, void *buf) +invoke_NPN_Write(PluginInstance *plugin, NPStream *stream, int32 len, void *buf) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), -1); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_WRITE, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_STREAM, stream, RPC_TYPE_ARRAY, RPC_TYPE_CHAR, len, buf, RPC_TYPE_INVALID); @@ -1293,25 +1594,38 @@ invoke_NPN_Write(NPP instance, NPStream *stream, int32 len, void *buf) static int32 g_NPN_Write(NPP instance, NPStream *stream, int32 len, void *buf) { + if (!pid_check()) { + npw_printf("WARNING: NPN_Write called from the wrong process\n"); + return -1; + } + if (instance == NULL) return -1; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return -1; + if (stream == NULL) return -1; - D(bug("NPN_Write instance=%p, stream=%p, len=%d, buf=%p\n", instance, stream, len, buf)); - int32 ret = invoke_NPN_Write(instance, stream, len, buf); - D(bug(" return: %d\n", ret)); + D(bugiI("NPN_Write instance=%p, stream=%p, len=%d, buf=%p\n", instance, stream, len, buf)); + npw_plugin_instance_ref(plugin); + int32 ret = invoke_NPN_Write(plugin, stream, len, buf); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_Write return: %d\n", ret)); return ret; } // Enable popups while executing code where popups should be enabled static void -invoke_NPN_PushPopupsEnabledState(NPP instance, NPBool enabled) +invoke_NPN_PushPopupsEnabledState(PluginInstance *plugin, NPBool enabled) { + npw_return_if_fail(rpc_method_invoke_possible(g_rpc_connection)); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_PUSH_POPUPS_ENABLED_STATE, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_UINT32, (uint32_t)enabled, RPC_TYPE_INVALID); @@ -1329,21 +1643,34 @@ invoke_NPN_PushPopupsEnabledState(NPP instance, NPBool enabled) static void g_NPN_PushPopupsEnabledState(NPP instance, NPBool enabled) { + if (!pid_check()) { + npw_printf("WARNING: NPN_PushPopupsEnabledState called from the wrong process\n"); + return; + } + if (instance == NULL) return; - D(bug("NPN_PushPopupsEnabledState instance=%p, enabled=%d\n", instance, enabled)); - invoke_NPN_PushPopupsEnabledState(instance, enabled); - D(bug(" done\n")); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return; + + D(bugiI("NPN_PushPopupsEnabledState instance=%p, enabled=%d\n", instance, enabled)); + npw_plugin_instance_ref(plugin); + invoke_NPN_PushPopupsEnabledState(plugin, enabled); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_PushPopupsEnabledState done\n")); } // Restore popups state static void -invoke_NPN_PopPopupsEnabledState(NPP instance) +invoke_NPN_PopPopupsEnabledState(PluginInstance *plugin) { + npw_return_if_fail(rpc_method_invoke_possible(g_rpc_connection)); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_POP_POPUPS_ENABLED_STATE, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -1360,12 +1687,23 @@ invoke_NPN_PopPopupsEnabledState(NPP instance) static void g_NPN_PopPopupsEnabledState(NPP instance) { + if (!pid_check()) { + npw_printf("WARNING: NPN_PophPopupsEnabledState called from the wrong process\n"); + return; + } + if (instance == NULL) return; - D(bug("NPN_PopPopupsEnabledState instance=%p\n", instance)); - invoke_NPN_PopPopupsEnabledState(instance); - D(bug(" done\n")); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return; + + D(bugiI("NPN_PopPopupsEnabledState instance=%p\n", instance)); + npw_plugin_instance_ref(plugin); + invoke_NPN_PopPopupsEnabledState(plugin); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_PopPopupsEnabledState done\n")); } @@ -1375,11 +1713,13 @@ g_NPN_PopPopupsEnabledState(NPP instance) // Allocates a new NPObject static uint32_t -invoke_NPN_CreateObject(NPP instance) +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_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -1403,22 +1743,38 @@ invoke_NPN_CreateObject(NPP instance) static NPObject * g_NPN_CreateObject(NPP instance, NPClass *class) { + if (!pid_check()) { + npw_printf("WARNING: NPN_CreateObject called from the wrong process\n"); + return NULL; + } + if (instance == NULL) return NULL; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return NULL; + if (class == NULL) return NULL; - D(bug("NPN_CreateObject\n")); - uint32_t npobj_id = invoke_NPN_CreateObject(instance); - D(bug(" return: %d\n", npobj_id)); - return npobject_new(npobj_id, instance, class); + 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, @@ -1443,12 +1799,17 @@ invoke_NPN_RetainObject(NPObject *npobj) static NPObject * g_NPN_RetainObject(NPObject *npobj) { + if (!pid_check()) { + npw_printf("WARNING: NPN_RetainObject called from the wrong process\n"); + return NULL; + } + if (npobj == NULL) return NULL; - D(bug("NPN_RetainObject %p\n", npobj)); + D(bugiI("NPN_RetainObject npobj=%p\n", npobj)); uint32_t refcount = invoke_NPN_RetainObject(npobj); - D(bug(" return: %d\n", refcount)); + D(bugiD("NPN_RetainObject return: %p (refcount: %d)\n", npobj, refcount)); npobj->referenceCount = refcount; return npobj; } @@ -1457,6 +1818,9 @@ g_NPN_RetainObject(NPObject *npobj) 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, @@ -1479,27 +1843,53 @@ invoke_NPN_ReleaseObject(NPObject *npobj) } static void -g_NPN_ReleaseObject(NPObject *npobj) +g_NPN_ReleaseObject_Now(NPObject *npobj) { - if (npobj == NULL) - return; - - D(bug("NPN_ReleaseObject %p\n", npobj)); + D(bugiI("NPN_ReleaseObject npobj=%p\n", npobj)); uint32_t refcount = invoke_NPN_ReleaseObject(npobj); - D(bug(" return: %d\n", refcount)); + D(bugiD("NPN_ReleaseObject done (refcount: %d)\n", refcount)); if ((npobj->referenceCount = refcount) == 0) npobject_destroy(npobj); } +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 (!pid_check()) { + npw_printf("WARNING: NPN_ReleaseObject called from the wrong process\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 { + D(bug("NPN_ReleaseObject \n")); + g_NPN_ReleaseObject_Delayed(npobj); + } +} + // Invokes a method on the given NPObject static bool -invoke_NPN_Invoke(NPP instance, NPObject *npobj, NPIdentifier methodName, +invoke_NPN_Invoke(PluginInstance *plugin, NPObject *npobj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_INVOKE, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_NP_IDENTIFIER, methodName, RPC_TYPE_ARRAY, RPC_TYPE_NP_VARIANT, argCount, args, @@ -1528,26 +1918,42 @@ static bool g_NPN_Invoke(NPP instance, NPObject *npobj, NPIdentifier methodName, const NPVariant *args, uint32_t argCount, NPVariant *result) { - if (!instance || !npobj || !npobj->_class || !npobj->_class->invoke) + if (!pid_check()) { + npw_printf("WARNING: NPN_Invoke called from the wrong process\n"); + return false; + } + + if (instance == NULL) return false; - D(bug("NPN_Invoke instance=%p, npobj=%p, methodName=%p\n", instance, npobj, methodName)); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return false; + + if (!npobj || !npobj->_class || !npobj->_class->invoke) + return false; + + D(bugiI("NPN_Invoke instance=%p, npobj=%p, methodName=%p\n", instance, npobj, methodName)); print_npvariant_args(args, argCount); - bool ret = invoke_NPN_Invoke(instance, npobj, methodName, args, argCount, result); + npw_plugin_instance_ref(plugin); + bool ret = invoke_NPN_Invoke(plugin, npobj, methodName, args, argCount, result); + npw_plugin_instance_unref(plugin); gchar *result_str = string_of_NPVariant(result); - D(bug(" return: %d (%s)\n", ret, result_str)); + D(bugiD("NPN_Invoke return: %d (%s)\n", ret, result_str)); g_free(result_str); return ret; } // Invokes the default method on the given NPObject static bool -invoke_NPN_InvokeDefault(NPP instance, NPObject *npobj, +invoke_NPN_InvokeDefault(PluginInstance *plugin, NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_INVOKE_DEFAULT, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_ARRAY, RPC_TYPE_NP_VARIANT, argCount, args, RPC_TYPE_INVALID); @@ -1575,25 +1981,41 @@ static bool g_NPN_InvokeDefault(NPP instance, NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) { - if (!instance || !npobj || !npobj->_class || !npobj->_class->invokeDefault) + if (!pid_check()) { + npw_printf("WARNING: NPN_InvokeDefault called from the wrong process\n"); + return false; + } + + if (instance == NULL) return false; - D(bug("NPN_InvokeDefault instance=%p, npobj=%p\n", instance, npobj)); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return false; + + if (!npobj || !npobj->_class || !npobj->_class->invokeDefault) + return false; + + D(bugiI("NPN_InvokeDefault instance=%p, npobj=%p\n", instance, npobj)); print_npvariant_args(args, argCount); - bool ret = invoke_NPN_InvokeDefault(instance, npobj, args, argCount, result); + npw_plugin_instance_ref(plugin); + bool ret = invoke_NPN_InvokeDefault(plugin, npobj, args, argCount, result); + npw_plugin_instance_unref(plugin); gchar *result_str = string_of_NPVariant(result); - D(bug(" return: %d (%s)\n", ret, result_str)); + D(bugiD("NPN_InvokeDefault return: %d (%s)\n", ret, result_str)); g_free(result_str); return ret; } // Evaluates a script on the scope of a given NPObject static bool -invoke_NPN_Evaluate(NPP instance, NPObject *npobj, NPString *script, NPVariant *result) +invoke_NPN_Evaluate(PluginInstance *plugin, NPObject *npobj, NPString *script, NPVariant *result) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_EVALUATE, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_NP_STRING, script, RPC_TYPE_INVALID); @@ -1620,28 +2042,44 @@ invoke_NPN_Evaluate(NPP instance, NPObject *npobj, NPString *script, NPVariant * static bool g_NPN_Evaluate(NPP instance, NPObject *npobj, NPString *script, NPVariant *result) { - if (!instance || !npobj) + if (!pid_check()) { + npw_printf("WARNING: NPN_Evaluate called from the wrong process\n"); + return false; + } + + if (instance == NULL) + return false; + + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return false; + + if (!npobj) return false; if (!script || !script->utf8length || !script->utf8characters) return true; // nothing to evaluate - D(bug("NPN_Evaluate instance=%p, npobj=%p\n", instance, npobj)); - bool ret = invoke_NPN_Evaluate(instance, npobj, script, result); + D(bugiI("NPN_Evaluate instance=%p, npobj=%p\n", instance, npobj)); + npw_plugin_instance_ref(plugin); + bool ret = invoke_NPN_Evaluate(plugin, npobj, script, result); + npw_plugin_instance_unref(plugin); gchar *result_str = string_of_NPVariant(result); - D(bug(" return: %d (%s)\n", ret, result_str)); + D(bugiD("NPN_Evaluate return: %d (%s)\n", ret, result_str)); g_free(result_str); return ret; } // Gets the value of a property on the given NPObject static bool -invoke_NPN_GetProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName, +invoke_NPN_GetProperty(PluginInstance *plugin, NPObject *npobj, NPIdentifier propertyName, NPVariant *result) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_GET_PROPERTY, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_NP_IDENTIFIER, propertyName, RPC_TYPE_INVALID); @@ -1669,25 +2107,41 @@ static bool g_NPN_GetProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName, NPVariant *result) { - if (!instance || !npobj || !npobj->_class || !npobj->_class->getProperty) + if (!pid_check()) { + npw_printf("WARNING: NPN_GetProperty called from the wrong process\n"); + return false; + } + + if (instance == NULL) return false; - D(bug("NPN_GetProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName)); - bool ret = invoke_NPN_GetProperty(instance, npobj, propertyName, result); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return false; + + if (!npobj || !npobj->_class || !npobj->_class->getProperty) + return false; + + D(bugiI("NPN_GetProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName)); + npw_plugin_instance_ref(plugin); + bool ret = invoke_NPN_GetProperty(plugin, npobj, propertyName, result); + npw_plugin_instance_unref(plugin); gchar *result_str = string_of_NPVariant(result); - D(bug(" return: %d (%s)\n", ret, result_str)); + D(bugiD("NPN_GetProperty return: %d (%s)\n", ret, result_str)); g_free(result_str); return ret; } // Sets the value of a property on the given NPObject static bool -invoke_NPN_SetProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName, +invoke_NPN_SetProperty(PluginInstance *plugin, NPObject *npobj, NPIdentifier propertyName, const NPVariant *value) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_SET_PROPERTY, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_NP_IDENTIFIER, propertyName, RPC_TYPE_NP_VARIANT, value, @@ -1715,22 +2169,38 @@ static bool g_NPN_SetProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName, const NPVariant *value) { - if (!instance || !npobj || !npobj->_class || !npobj->_class->setProperty) + if (!pid_check()) { + npw_printf("WARNING: NPN_SetProperty called from the wrong process\n"); + return false; + } + + if (instance == NULL) return false; - D(bug("NPN_SetProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName)); - bool ret = invoke_NPN_SetProperty(instance, npobj, propertyName, value); - D(bug(" return: %d\n", ret)); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return false; + + if (!npobj || !npobj->_class || !npobj->_class->setProperty) + return false; + + D(bugiI("NPN_SetProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName)); + npw_plugin_instance_ref(plugin); + bool ret = invoke_NPN_SetProperty(plugin, npobj, propertyName, value); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_SetProperty return: %d\n", ret)); return ret; } // Removes a property on the given NPObject static bool -invoke_NPN_RemoveProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName) +invoke_NPN_RemoveProperty(PluginInstance *plugin, NPObject *npobj, NPIdentifier propertyName) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_REMOVE_PROPERTY, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_NP_IDENTIFIER, propertyName, RPC_TYPE_INVALID); @@ -1756,22 +2226,38 @@ invoke_NPN_RemoveProperty(NPP instance, NPObject *npobj, NPIdentifier propertyNa static bool g_NPN_RemoveProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName) { - if (!instance || !npobj || !npobj->_class || !npobj->_class->removeProperty) + if (!pid_check()) { + npw_printf("WARNING: NPN_RemoveProperty called from the wrong process\n"); + return false; + } + + if (instance == NULL) return false; - D(bug("NPN_RemoveProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName)); - bool ret = invoke_NPN_RemoveProperty(instance, npobj, propertyName); - D(bug(" return: %d\n", ret)); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return false; + + if (!npobj || !npobj->_class || !npobj->_class->removeProperty) + return false; + + D(bugiI("NPN_RemoveProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName)); + npw_plugin_instance_ref(plugin); + bool ret = invoke_NPN_RemoveProperty(plugin, npobj, propertyName); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_RemoveProperty return: %d\n", ret)); return ret; } // Checks if a given property exists on the given NPObject static bool -invoke_NPN_HasProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName) +invoke_NPN_HasProperty(PluginInstance *plugin, NPObject *npobj, NPIdentifier propertyName) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_HAS_PROPERTY, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_NP_IDENTIFIER, propertyName, RPC_TYPE_INVALID); @@ -1797,22 +2283,38 @@ invoke_NPN_HasProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName) static bool g_NPN_HasProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName) { - if (!instance || !npobj || !npobj->_class || !npobj->_class->hasProperty) + if (!pid_check()) { + npw_printf("WARNING: NPN_HasProperty called from the wrong process\n"); + return false; + } + + if (instance == NULL) return false; - D(bug("NPN_HasProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName)); - bool ret = invoke_NPN_HasProperty(instance, npobj, propertyName); - D(bug(" return: %d\n", ret)); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return false; + + if (!npobj || !npobj->_class || !npobj->_class->hasProperty) + return false; + + D(bugiI("NPN_HasProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName)); + npw_plugin_instance_ref(plugin); + bool ret = invoke_NPN_HasProperty(plugin, npobj, propertyName); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_HasProperty return: %d\n", ret)); return ret; } // Checks if a given method exists on the given NPObject static bool -invoke_NPN_HasMethod(NPP instance, NPObject *npobj, NPIdentifier methodName) +invoke_NPN_HasMethod(PluginInstance *plugin, NPObject *npobj, NPIdentifier methodName) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_HAS_METHOD, - RPC_TYPE_NPP, instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_OBJECT, npobj, RPC_TYPE_NP_IDENTIFIER, methodName, RPC_TYPE_INVALID); @@ -1838,12 +2340,26 @@ invoke_NPN_HasMethod(NPP instance, NPObject *npobj, NPIdentifier methodName) static bool g_NPN_HasMethod(NPP instance, NPObject *npobj, NPIdentifier methodName) { - if (!instance || !npobj || !npobj->_class || !npobj->_class->hasMethod) + if (!pid_check()) { + npw_printf("WARNING: NPN_HasMethod called from the wrong process\n"); + return false; + } + + if (instance == NULL) return false; - D(bug("NPN_HasMethod instance=%p, npobj=%p, methodName=%p\n", instance, npobj, methodName)); - bool ret = invoke_NPN_HasMethod(instance, npobj, methodName); - D(bug(" return: %d\n", ret)); + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return false; + + if (!npobj || !npobj->_class || !npobj->_class->hasMethod) + return false; + + D(bugiI("NPN_HasMethod instance=%p, npobj=%p, methodName=%p\n", instance, npobj, methodName)); + npw_plugin_instance_ref(plugin); + bool ret = invoke_NPN_HasMethod(plugin, npobj, methodName); + npw_plugin_instance_unref(plugin); + D(bugiD("NPN_HasMethod return: %d\n", ret)); return ret; } @@ -1851,6 +2367,8 @@ g_NPN_HasMethod(NPP instance, NPObject *npobj, NPIdentifier methodName) static void invoke_NPN_SetException(NPObject *npobj, const NPUTF8 *message) { + npw_return_if_fail(rpc_method_invoke_possible(g_rpc_connection)); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_SET_EXCEPTION, RPC_TYPE_NP_OBJECT, npobj, @@ -1873,24 +2391,31 @@ invoke_NPN_SetException(NPObject *npobj, const NPUTF8 *message) static void g_NPN_SetException(NPObject *npobj, const NPUTF8 *message) { - D(bug("NPN_SetException npobj=%p, message='%s'\n", npobj, message)); + if (!pid_check()) { + npw_printf("WARNING: NPN_SetException called from the wrong process\n"); + return; + } + + D(bugiI("NPN_SetException npobj=%p, message='%s'\n", npobj, message)); invoke_NPN_SetException(npobj, message); - D(bug(" done\n")); + D(bugiD("NPN_SetException done\n")); } // Releases the value in the given variant static void g_NPN_ReleaseVariantValue(NPVariant *variant) { - D(bug("NPN_ReleaseVariantValue\n")); + D(bugiI("NPN_ReleaseVariantValue\n")); npvariant_clear(variant); - D(bug(" done\n")); + D(bugiD("NPN_ReleaseVariantValue done\n")); } // Returns an opaque identifier for the string that is passed in static NPIdentifier invoke_NPN_GetStringIdentifier(const NPUTF8 *name) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), NULL); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_GET_STRING_IDENTIFIER, RPC_TYPE_STRING, name, @@ -1917,12 +2442,17 @@ invoke_NPN_GetStringIdentifier(const NPUTF8 *name) static NPIdentifier g_NPN_GetStringIdentifier(const NPUTF8 *name) { + if (!pid_check()) { + npw_printf("WARNING: NPN_GetStringIdentifier called from the wrong process\n"); + return NULL; + } + if (name == NULL) return NULL; - D(bug("NPN_GetStringIdentifier name='%s'\n", name)); + D(bugiI("NPN_GetStringIdentifier name='%s'\n", name)); NPIdentifier ret = invoke_NPN_GetStringIdentifier(name); - D(bug(" return: %p\n", ret)); + D(bugiD("NPN_GetStringIdentifier return: %p\n", ret)); return ret; } @@ -1930,6 +2460,8 @@ g_NPN_GetStringIdentifier(const NPUTF8 *name) static void invoke_NPN_GetStringIdentifiers(const NPUTF8 **names, uint32_t nameCount, NPIdentifier *identifiers) { + npw_return_if_fail(rpc_method_invoke_possible(g_rpc_connection)); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_GET_STRING_IDENTIFIERS, RPC_TYPE_ARRAY, RPC_TYPE_STRING, nameCount, names, @@ -1966,21 +2498,28 @@ invoke_NPN_GetStringIdentifiers(const NPUTF8 **names, uint32_t nameCount, NPIden static void g_NPN_GetStringIdentifiers(const NPUTF8 **names, uint32_t nameCount, NPIdentifier *identifiers) { + if (!pid_check()) { + npw_printf("WARNING: NPN_GetStringIdentifiers called from the wrong process\n"); + return; + } + if (names == NULL) return; if (identifiers == NULL) return; - D(bug("NPN_GetStringIdentifiers names=%p\n", names)); + D(bugiI("NPN_GetStringIdentifiers names=%p\n", names)); invoke_NPN_GetStringIdentifiers(names, nameCount, identifiers); - D(bug(" done\n")); + D(bugiD("NPN_GetStringIdentifiers done\n")); } // Returns an opaque identifier for the integer that is passed in static NPIdentifier invoke_NPN_GetIntIdentifier(int32_t intid) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), NULL); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_GET_INT_IDENTIFIER, RPC_TYPE_INT32, intid, @@ -2007,9 +2546,14 @@ invoke_NPN_GetIntIdentifier(int32_t intid) static NPIdentifier g_NPN_GetIntIdentifier(int32_t intid) { - D(bug("NPN_GetIntIdentifier intid=%d\n", intid)); + if (!pid_check()) { + npw_printf("WARNING: NPN_GetIntIdentifier called from the wrong process\n"); + return NULL; + } + + D(bugiI("NPN_GetIntIdentifier intid=%d\n", intid)); NPIdentifier ret = invoke_NPN_GetIntIdentifier(intid); - D(bug(" return: %p\n", ret)); + D(bugiD("NPN_GetIntIdentifier return: %p\n", ret)); return ret; } @@ -2017,6 +2561,8 @@ g_NPN_GetIntIdentifier(int32_t intid) static bool invoke_NPN_IdentifierIsString(NPIdentifier identifier) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), false); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_IDENTIFIER_IS_STRING, RPC_TYPE_NP_IDENTIFIER, identifier, @@ -2043,9 +2589,14 @@ invoke_NPN_IdentifierIsString(NPIdentifier identifier) static bool g_NPN_IdentifierIsString(NPIdentifier identifier) { - D(bug("NPN_IdentifierIsString identifier=%p\n", identifier)); + if (!pid_check()) { + npw_printf("WARNING: NPN_IdentifierIsString called from the wrong process\n"); + return false; + } + + D(bugiI("NPN_IdentifierIsString identifier=%p\n", identifier)); bool ret = invoke_NPN_IdentifierIsString(identifier); - D(bug(" return: %d\n", ret)); + D(bugiD("NPN_IdentifierIsString return: %d\n", ret)); return ret; } @@ -2053,6 +2604,8 @@ g_NPN_IdentifierIsString(NPIdentifier identifier) static NPUTF8 * invoke_NPN_UTF8FromIdentifier(NPIdentifier identifier) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), NULL); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_UTF8_FROM_IDENTIFIER, RPC_TYPE_NP_IDENTIFIER, identifier, @@ -2079,9 +2632,14 @@ invoke_NPN_UTF8FromIdentifier(NPIdentifier identifier) static NPUTF8 * g_NPN_UTF8FromIdentifier(NPIdentifier identifier) { - D(bug("NPN_UTF8FromIdentifier identifier=%p\n", identifier)); + if (!pid_check()) { + npw_printf("WARNING: NPN_UTF8FromIdentifier called from the wrong process\n"); + return NULL; + } + + D(bugiI("NPN_UTF8FromIdentifier identifier=%p\n", identifier)); NPUTF8 *ret = invoke_NPN_UTF8FromIdentifier(identifier); - D(bug(" return: '%s'\n", ret)); + D(bugiD("NPN_UTF8FromIdentifier return: '%s'\n", ret)); return ret; } @@ -2090,6 +2648,8 @@ g_NPN_UTF8FromIdentifier(NPIdentifier identifier) static int32_t invoke_NPN_IntFromIdentifier(NPIdentifier identifier) { + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), -1); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_INT_FROM_IDENTIFIER, RPC_TYPE_NP_IDENTIFIER, identifier, @@ -2116,9 +2676,14 @@ invoke_NPN_IntFromIdentifier(NPIdentifier identifier) static int32_t g_NPN_IntFromIdentifier(NPIdentifier identifier) { - D(bug("NPN_IntFromIdentifier identifier=%p\n", identifier)); + if (!pid_check()) { + npw_printf("WARNING: NPN_IntFromIdentifier called from the wrong process\n"); + return 0; + } + + D(bugiI("NPN_IntFromIdentifier identifier=%p\n", identifier)); int32_t ret = invoke_NPN_IntFromIdentifier(identifier); - D(bug(" return: %d\n", ret)); + D(bugiD("NPN_IntFromIdentifier return: %d\n", ret)); return ret; } @@ -2158,9 +2723,9 @@ g_NP_GetMIMEDescription(void) if (g_plugin_NP_GetMIMEDescription == NULL) return NULL; - D(bug("NP_GetMIMEDescription\n")); + D(bugiI("NP_GetMIMEDescription\n")); char *str = g_plugin_NP_GetMIMEDescription(); - D(bug(" return: %s\n", str ? str : "")); + D(bugiD("NP_GetMIMEDescription return: %s\n", str ? str : "")); return str; } @@ -2185,9 +2750,9 @@ g_NP_GetValue(NPPVariable variable, void *value) if (g_plugin_NP_GetValue == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; - D(bug("NP_GetValue variable=%d\n", variable)); + D(bugiI("NP_GetValue variable=%d [%s]\n", variable, string_of_NPPVariable(variable))); NPError ret = g_plugin_NP_GetValue(NULL, variable, value); - D(bug(" return: %d\n", ret)); + D(bugiD("NP_GetValue return: %d\n", ret)); return ret; } @@ -2297,9 +2862,9 @@ g_NP_Initialize(uint32_t version) // XXX: remove the local copies from this file NPW_InitializeFuncs(&mozilla_funcs, &plugin_funcs); - D(bug("NP_Initialize\n")); + D(bugiI("NP_Initialize\n")); NPError ret = g_plugin_NP_Initialize(&mozilla_funcs, &plugin_funcs); - D(bug(" return: %d\n", ret)); + D(bugiD("NP_Initialize return: %d\n", ret)); return ret; } @@ -2328,9 +2893,9 @@ g_NP_Shutdown(void) if (g_plugin_NP_Shutdown == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; - D(bug("NP_Shutdown\n")); + D(bugiI("NP_Shutdown\n")); NPError ret = g_plugin_NP_Shutdown(); - D(bug(" done\n")); + D(bugiD("NP_Shutdown done\n")); if (NPN_HAS_FEATURE(NPRUNTIME_SCRIPTING)) npobject_bridge_destroy(); @@ -2359,10 +2924,9 @@ static NPError g_NPP_New(NPMIMEType plugin_type, uint32_t instance_id, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) { - PluginInstance *plugin = malloc(sizeof(*plugin)); + PluginInstance *plugin = npw_plugin_instance_new(&PluginInstanceClass); if (plugin == NULL) return NPERR_OUT_OF_MEMORY_ERROR; - memset(plugin, 0, sizeof(*plugin)); plugin->instance_id = instance_id; id_link(instance_id, plugin); @@ -2387,9 +2951,9 @@ static NPError g_NPP_New(NPMIMEType plugin_type, uint32_t instance_id, } } - D(bug("NPP_New instance=%p\n", instance)); + D(bugiI("NPP_New instance=%p\n", instance)); NPError ret = plugin_funcs.newp(plugin_type, instance, mode, argc, argn, argv, saved); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPP_New return: %d [%s]\n", ret, string_of_NPError(ret))); // check if XEMBED is to be used PRBool supports_XEmbed = PR_FALSE; @@ -2402,17 +2966,6 @@ static NPError g_NPP_New(NPMIMEType plugin_type, uint32_t instance_id, plugin->use_xembed = supports_XEmbed && needs_XEmbed; } } - -#if USE_XEMBED_HACK - // check if XEMBED hack is to be used - if (plugin->use_xembed && plugin_funcs.getvalue) { - NPNToolkitType toolkit = 0; - NPError error = g_NPN_GetValue_real(NULL, NPNVToolkit, (void *)&toolkit); - if (error == NPERR_NO_ERROR && toolkit == NPNVGtk2) - plugin->use_xembed_hack = true; - } -#endif - return ret; } @@ -2467,33 +3020,45 @@ static NPError g_NPP_Destroy(NPP instance, NPSavedData **sdata) if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); + if (plugin == NULL) + return NPERR_INVALID_INSTANCE_ERROR; + if (sdata) *sdata = NULL; - D(bug("NPP_Destroy instance=%p\n", instance)); - NPError ret = plugin_funcs.destroy(instance, sdata); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + // 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); - PluginInstance *plugin = instance->ndata; - if (plugin) { - if (plugin->browser_toplevel) { - g_object_unref(plugin->browser_toplevel); - plugin->browser_toplevel = NULL; - } - destroy_window(plugin); - id_remove(plugin->instance_id); - free(plugin); - } + 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))); + + /* NPP instance is no longer valid beyond this point. So, let's also + drop the link to the PluginInstance now */ + plugin->instance = NULL; + instance->ndata = NULL; + id_remove(plugin->instance_id); + plugin->instance_id = 0; + /* ... reset instance_id so that future RPC with this PluginInstance + will actually emit a NULL instance, which the other side will + deal as a no-op for all functions but NPN_GetValue() */ free(instance); + npw_plugin_instance_unref(plugin); return ret; } static int handle_NPP_Destroy(rpc_connection_t *connection) { + D(bug("handle_NPP_Destroy\n")); + int error; - NPP instance; - error = rpc_method_get_args(connection, RPC_TYPE_NPP, &instance, RPC_TYPE_INVALID); + PluginInstance *plugin; + error = rpc_method_get_args(connection, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, + RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { npw_perror("NPP_Destroy() get args", error); @@ -2501,9 +3066,13 @@ static int handle_NPP_Destroy(rpc_connection_t *connection) } NPSavedData *save_area; - NPError ret = g_NPP_Destroy(instance, &save_area); + NPError ret = g_NPP_Destroy(PLUGIN_INSTANCE_NPP(plugin), &save_area); + + error = rpc_method_send_reply(connection, + RPC_TYPE_INT32, ret, + RPC_TYPE_NP_SAVED_DATA, save_area, + RPC_TYPE_INVALID); - error = rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_NP_SAVED_DATA, save_area, RPC_TYPE_INVALID); rpc_connection_unref(connection); return error; } @@ -2515,13 +3084,13 @@ g_NPP_SetWindow(NPP instance, NPWindow *np_window) if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; - if (plugin_funcs.setwindow == NULL) - return NPERR_INVALID_FUNCTABLE_ERROR; - - PluginInstance *plugin = instance->ndata; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); if (plugin == NULL) return NPERR_INVALID_INSTANCE_ERROR; + if (plugin_funcs.setwindow == NULL) + return NPERR_INVALID_FUNCTABLE_ERROR; + plugin->is_windowless = np_window && np_window->type == NPWindowTypeDrawable; NPWindow *window = np_window; @@ -2537,9 +3106,9 @@ g_NPP_SetWindow(NPP instance, NPWindow *np_window) window = &plugin->window; } - D(bug("NPP_SetWindow instance=%p, window=%p\n", instance, window ? window->window : NULL)); + D(bugiI("NPP_SetWindow instance=%p, window=%p\n", instance, window ? window->window : NULL)); NPError ret = plugin_funcs.setwindow(instance, window); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPP_SetWindow return: %d [%s]\n", ret, string_of_NPError(ret))); if (np_window == NULL || (np_window->window == NULL && !plugin->is_windowless)) destroy_window(plugin); @@ -2552,11 +3121,11 @@ static int handle_NPP_SetWindow(rpc_connection_t *connection) D(bug("handle_NPP_SetWindow\n")); int error; - NPP instance; + PluginInstance *plugin; NPWindow *window; error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_WINDOW, &window, RPC_TYPE_INVALID); @@ -2565,27 +3134,13 @@ static int handle_NPP_SetWindow(rpc_connection_t *connection) return error; } - NPError ret = g_NPP_SetWindow(instance, window); + NPError ret = g_NPP_SetWindow(PLUGIN_INSTANCE_NPP(plugin), window); if (window) free(window); return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID); } // NPP_GetValue -static NPError -g_NPP_GetValue_fixes(NPP instance, NPPVariable variable, void *value) -{ - PluginInstance *plugin = PLUGIN_INSTANCE(instance); - switch (variable) { - case NPPVpluginNeedsXEmbed: - // claim we don't support XEMBED though we actually do - if (plugin->use_xembed_hack) - *((PRBool *)value) = PR_FALSE; - break; - } - return NPERR_NO_ERROR; -} - static NPError g_NPP_GetValue(NPP instance, NPPVariable variable, void *value) { @@ -2595,22 +3150,22 @@ g_NPP_GetValue(NPP instance, NPPVariable variable, void *value) if (plugin_funcs.getvalue == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; - D(bug("NPP_GetValue instance=%p, variable=%d\n", instance, variable)); + D(bugiI("NPP_GetValue instance=%p, variable=%d [%s]\n", instance, variable, string_of_NPPVariable(variable))); NPError ret = plugin_funcs.getvalue(instance, variable, value); - if (ret == NPERR_NO_ERROR) - ret = g_NPP_GetValue_fixes(instance, variable, value); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPP_GetValue return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } static int handle_NPP_GetValue(rpc_connection_t *connection) { + D(bug("handle_NPP_GetValue\n")); + int error; - NPP instance; + PluginInstance *plugin; int32_t variable; error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_INT32, &variable, RPC_TYPE_INVALID); @@ -2626,25 +3181,25 @@ static int handle_NPP_GetValue(rpc_connection_t *connection) case RPC_TYPE_STRING: { char *str = NULL; - ret = g_NPP_GetValue(instance, variable, (void *)&str); + ret = g_NPP_GetValue(PLUGIN_INSTANCE_NPP(plugin), variable, (void *)&str); return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_STRING, str, RPC_TYPE_INVALID); } case RPC_TYPE_INT32: { uint32_t n = 0; - ret = g_NPP_GetValue(instance, variable, (void *)&n); + ret = g_NPP_GetValue(PLUGIN_INSTANCE_NPP(plugin), variable, (void *)&n); return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INT32, n, RPC_TYPE_INVALID); } case RPC_TYPE_BOOLEAN: { PRBool b = PR_FALSE; - ret = g_NPP_GetValue(instance, variable, (void *)&b); + ret = g_NPP_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_NP_OBJECT: { NPObject *npobj = NULL; - ret = g_NPP_GetValue(instance, variable, (void *)&npobj); + 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); } } @@ -2662,22 +3217,24 @@ g_NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyData if (plugin_funcs.urlnotify == NULL) return; - D(bug("NPP_URLNotify instance=%p, url='%s', reason=%s, notifyData=%p\n", + D(bugiI("NPP_URLNotify instance=%p, url='%s', reason=%s, notifyData=%p\n", instance, url, string_of_NPReason(reason), notifyData)); plugin_funcs.urlnotify(instance, url, reason, notifyData); - D(bug(" done\n")); + D(bugiD("NPP_URLNotify done\n")); } static int handle_NPP_URLNotify(rpc_connection_t *connection) { + D(bug("handle_NPP_URLNotify\n")); + int error; - NPP instance; + PluginInstance *plugin; char *url; int32_t reason; void *notifyData; error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_STRING, &url, RPC_TYPE_INT32, &reason, RPC_TYPE_NP_NOTIFY_DATA, ¬ifyData, @@ -2688,7 +3245,7 @@ static int handle_NPP_URLNotify(rpc_connection_t *connection) return error; } - g_NPP_URLNotify(instance, url, reason, notifyData); + g_NPP_URLNotify(PLUGIN_INSTANCE_NPP(plugin), url, reason, notifyData); if (url) free(url); @@ -2706,17 +3263,19 @@ g_NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable if (plugin_funcs.newstream == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; - D(bug("NPP_NewStream instance=%p, stream=%p, url='%s', type='%s', seekable=%d, stype=%s, notifyData=%p\n", + D(bugiI("NPP_NewStream instance=%p, stream=%p, url='%s', type='%s', seekable=%d, stype=%s, notifyData=%p\n", instance, stream, stream->url, type, seekable, string_of_NPStreamType(*stype), stream->notifyData)); NPError ret = plugin_funcs.newstream(instance, type, stream, seekable, stype); - D(bug(" return: %d [%s], stype=%s\n", ret, string_of_NPError(ret), string_of_NPStreamType(*stype))); + D(bugiD("NPP_NewStream return: %d [%s], stype=%s\n", ret, string_of_NPError(ret), string_of_NPStreamType(*stype))); return ret; } static int handle_NPP_NewStream(rpc_connection_t *connection) { + D(bug("handle_NPP_NewStream\n")); + int error; - NPP instance; + PluginInstance *plugin; uint32_t stream_id; uint32_t seekable; NPMIMEType type; @@ -2727,7 +3286,7 @@ static int handle_NPP_NewStream(rpc_connection_t *connection) memset(stream, 0, sizeof(*stream)); error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_STRING, &type, RPC_TYPE_UINT32, &stream_id, RPC_TYPE_STRING, &stream->url, @@ -2754,7 +3313,7 @@ static int handle_NPP_NewStream(rpc_connection_t *connection) stream_ndata->is_plugin_stream = 0; uint16 stype = NP_NORMAL; - NPError ret = g_NPP_NewStream(instance, type, stream, seekable, &stype); + NPError ret = g_NPP_NewStream(PLUGIN_INSTANCE_NPP(plugin), type, stream, seekable, &stype); if (type) free(type); @@ -2779,10 +3338,10 @@ g_NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) if (stream == NULL) return NPERR_INVALID_PARAM; - D(bug("NPP_DestroyStream instance=%p, stream=%p, reason=%s\n", + D(bugiI("NPP_DestroyStream instance=%p, stream=%p, reason=%s\n", instance, stream, string_of_NPReason(reason))); NPError ret = plugin_funcs.destroystream(instance, stream, reason); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPP_DestroyStream return: %d [%s]\n", ret, string_of_NPError(ret))); StreamInstance *stream_ndata = stream->ndata; if (stream_ndata) { @@ -2800,11 +3359,11 @@ static int handle_NPP_DestroyStream(rpc_connection_t *connection) { D(bug("handle_NPP_DestroyStream\n")); - NPP instance; + PluginInstance *plugin; NPStream *stream; int32_t reason; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_STREAM, &stream, RPC_TYPE_INT32, &reason, RPC_TYPE_INVALID); @@ -2814,7 +3373,7 @@ static int handle_NPP_DestroyStream(rpc_connection_t *connection) return error; } - NPError ret = g_NPP_DestroyStream(instance, stream, reason); + NPError ret = g_NPP_DestroyStream(PLUGIN_INSTANCE_NPP(plugin), stream, reason); return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID); } @@ -2831,9 +3390,9 @@ g_NPP_WriteReady(NPP instance, NPStream *stream) if (stream == NULL) return 0; - D(bug("NPP_WriteReady instance=%p, stream=%p\n", instance, stream)); + D(bugiI("NPP_WriteReady instance=%p, stream=%p\n", instance, stream)); int32 ret = plugin_funcs.writeready(instance, stream); - D(bug(" return: %d\n", ret)); + D(bugiD("NPP_WriteReady return: %d\n", ret)); return ret; } @@ -2841,10 +3400,10 @@ static int handle_NPP_WriteReady(rpc_connection_t *connection) { D(bug("handle_NPP_WriteReady\n")); - NPP instance; + PluginInstance *plugin; NPStream *stream; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_STREAM, &stream, RPC_TYPE_INVALID); @@ -2853,7 +3412,7 @@ static int handle_NPP_WriteReady(rpc_connection_t *connection) return error; } - int32 ret = g_NPP_WriteReady(instance, stream); + int32 ret = g_NPP_WriteReady(PLUGIN_INSTANCE_NPP(plugin), stream); return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID); } @@ -2871,20 +3430,22 @@ g_NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buf) if (stream == NULL) return -1; - D(bug("NPP_Write instance=%p, stream=%p, offset=%d, len=%d, buf=%p\n", instance, stream, offset, len, buf)); + D(bugiI("NPP_Write instance=%p, stream=%p, offset=%d, len=%d, buf=%p\n", instance, stream, offset, len, buf)); int32 ret = plugin_funcs.write(instance, stream, offset, len, buf); - D(bug(" return: %d\n", ret)); + D(bugiD("NPP_Write return: %d\n", ret)); return ret; } static int handle_NPP_Write(rpc_connection_t *connection) { - NPP instance; + D(bug("handle_NPP_Write\n")); + + PluginInstance *plugin; NPStream *stream; unsigned char *buf; int32_t offset, len; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_STREAM, &stream, RPC_TYPE_INT32, &offset, RPC_TYPE_ARRAY, RPC_TYPE_CHAR, &len, &buf, @@ -2895,7 +3456,7 @@ static int handle_NPP_Write(rpc_connection_t *connection) return error; } - int32 ret = g_NPP_Write(instance, stream, offset, len, buf); + int32 ret = g_NPP_Write(PLUGIN_INSTANCE_NPP(plugin), stream, offset, len, buf); if (buf) free(buf); @@ -2916,18 +3477,20 @@ g_NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) if (stream == NULL) return; - D(bug("NPP_StreamAsFile instance=%p, stream=%p, fname='%s'\n", instance, stream, fname)); + D(bugiI("NPP_StreamAsFile instance=%p, stream=%p, fname='%s'\n", instance, stream, fname)); plugin_funcs.asfile(instance, stream, fname); - D(bug(" done\n")); + D(bugiD("NPP_StreamAsFile done\n")); } static int handle_NPP_StreamAsFile(rpc_connection_t *connection) { - NPP instance; + D(bug("handle_NPP_StreamAsFile\n")); + + PluginInstance *plugin; NPStream *stream; char *fname; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_STREAM, &stream, RPC_TYPE_STRING, &fname, RPC_TYPE_INVALID); @@ -2937,7 +3500,7 @@ static int handle_NPP_StreamAsFile(rpc_connection_t *connection) return error; } - g_NPP_StreamAsFile(instance, stream, fname); + g_NPP_StreamAsFile(PLUGIN_INSTANCE_NPP(plugin), stream, fname); if (fname) free(fname); @@ -2955,9 +3518,9 @@ g_NPP_Print(NPP instance, NPPrint *printInfo) if (printInfo == NULL) return; - D(bug("NPP_Print instance=%p, printInfo->mode=%d\n", instance, printInfo->mode)); + D(bugiI("NPP_Print instance=%p, printInfo->mode=%d\n", instance, printInfo->mode)); plugin_funcs.print(instance, printInfo); - D(bug(" done\n")); + D(bugiD("NPP_Print done\n")); } static void @@ -2966,6 +3529,8 @@ invoke_NPN_PrintData(PluginInstance *plugin, uint32_t platform_print_id, NPPrint if (printData == NULL) return; + npw_return_if_fail(rpc_method_invoke_possible(g_rpc_connection)); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NPN_PRINT_DATA, RPC_TYPE_UINT32, platform_print_id, @@ -2987,11 +3552,13 @@ invoke_NPN_PrintData(PluginInstance *plugin, uint32_t platform_print_id, NPPrint static int handle_NPP_Print(rpc_connection_t *connection) { - NPP instance; + D(bug("handle_NPP_Print\n")); + + PluginInstance *plugin; NPPrint printInfo; uint32_t platform_print_id; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_UINT32, &platform_print_id, RPC_TYPE_NP_PRINT, &printInfo, RPC_TYPE_INVALID); @@ -3017,7 +3584,7 @@ static int handle_NPP_Print(rpc_connection_t *connection) break; } - g_NPP_Print(instance, &printInfo); + g_NPP_Print(PLUGIN_INSTANCE_NPP(plugin), &printInfo); // send back the printed data if (printer.fp) { @@ -3034,12 +3601,16 @@ static int handle_NPP_Print(rpc_connection_t *connection) npw_printf("ERROR: unexpected end-of-file or error condition in NPP_Print\n"); break; } - invoke_NPN_PrintData(instance->ndata, platform_print_id, &printData); + npw_plugin_instance_ref(plugin); + invoke_NPN_PrintData(plugin, platform_print_id, &printData); + npw_plugin_instance_unref(plugin); } printData.size = file_size % printDataMaxSize; if (fread(&printData.data, printData.size, 1, printer.fp) != 1) npw_printf("ERROR: unexpected end-of-file or error condition in NPP_Print\n"); - invoke_NPN_PrintData(instance->ndata, platform_print_id, &printData); + npw_plugin_instance_ref(plugin); + invoke_NPN_PrintData(plugin, platform_print_id, &printData); + npw_plugin_instance_unref(plugin); } fclose(printer.fp); } @@ -3071,9 +3642,9 @@ g_NPP_HandleEvent(NPP instance, NPEvent *event) if (event == NULL) return false; - D(bug("NPP_HandleEvent instance=%p, event=%p [%s]\n", instance, event, string_of_NPEvent_type(event->type))); + D(bugiI("NPP_HandleEvent instance=%p, event=%p [%s]\n", instance, event, string_of_NPEvent_type(event->type))); int16 ret = plugin_funcs.event(instance, event); - D(bug(" return: %d\n", ret)); + D(bugiD("NPP_HandleEvent return: %d\n", ret)); /* XXX: let's have a chance to commit the pixmap before it's gone */ if (event->type == GraphicsExpose) @@ -3084,10 +3655,12 @@ g_NPP_HandleEvent(NPP instance, NPEvent *event) static int handle_NPP_HandleEvent(rpc_connection_t *connection) { - NPP instance; + D(bug("handle_NPP_HandleEvent\n")); + + PluginInstance *plugin; NPEvent event; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_EVENT, &event, RPC_TYPE_INVALID); @@ -3097,7 +3670,7 @@ static int handle_NPP_HandleEvent(rpc_connection_t *connection) } event.xany.display = x_display; - int16 ret = g_NPP_HandleEvent(instance, &event); + int16 ret = g_NPP_HandleEvent(PLUGIN_INSTANCE_NPP(plugin), &event); return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID); } @@ -3191,6 +3764,14 @@ static GSourceFuncs rpc_event_funcs = { (GSourceDummyMarshal)NULL }; +// RPC error callback -- kill the plugin +static void rpc_error_callback_cb(rpc_connection_t *connection, void *user_data) +{ + D(bug("RPC connection %p is in a bad state, closing the plugin\n",connection)); + rpc_connection_set_error_callback(connection, NULL, NULL); + gtk_main_quit(); +} + /* ====================================================================== */ /* === Main program === */ @@ -3208,6 +3789,9 @@ static int do_main(int argc, char **argv, const char *connection_path) } D(bug(" Plugin connection: %s\n", connection_path)); + pid_init(); + D(bug(" Plugin viewer pid: %d\n", g_viewer_pid)); + // Cleanup environment, the program may fork/exec a native shell // script and having 32-bit libraries in LD_PRELOAD is not right, // though not a fatal error @@ -3289,7 +3873,7 @@ static int do_main(int argc, char **argv, const char *connection_path) npw_printf("ERROR: failed to initialize plugin-side RPC events listener\n"); return 1; } - g_source_set_priority(rpc_source, GDK_PRIORITY_EVENTS); + g_source_set_priority(rpc_source, G_PRIORITY_LOW); g_source_attach(rpc_source, NULL); rpc_event_poll_fd.fd = rpc_listen_socket(g_rpc_connection); rpc_event_poll_fd.events = G_IO_IN; @@ -3297,6 +3881,9 @@ static int do_main(int argc, char **argv, const char *connection_path) g_source_set_callback(rpc_source, (GSourceFunc)rpc_dispatch, g_rpc_connection, NULL); g_source_add_poll(rpc_source, &rpc_event_poll_fd); + // Set error handler - stop plugin if there's a connection error + rpc_connection_set_error_callback(g_rpc_connection, rpc_error_callback_cb, NULL); + gtk_main(); D(bug("--- EXIT ---\n")); diff --git a/src/npw-viewer.sh b/src/npw-viewer.sh index 0746ad2..c08cbd1 100644 --- a/src/npw-viewer.sh +++ b/src/npw-viewer.sh @@ -110,11 +110,11 @@ case " $@ " in case "$LOADER" in *linux32) if test "$OS" = "Linux"; then - soundwrapper=`which soundwrapper` + soundwrapper=`which soundwrapper 2>/dev/null` if test -x "$soundwrapper"; then LOADER="$LOADER $soundwrapper" elif ps aux | grep artsd | grep -vq grep; then - soundwrapper=`which artsdsp` + soundwrapper=`which artsdsp 2>/dev/null` if test -x "$soundwrapper"; then LOADER="$LOADER $soundwrapper" fi diff --git a/src/npw-wrapper.c b/src/npw-wrapper.c index 74a1607..fae0abe 100644 --- a/src/npw-wrapper.c +++ b/src/npw-wrapper.c @@ -44,11 +44,17 @@ #include "utils.h" #include "npw-common.h" +#include "npw-malloc.h" #define DEBUG 1 #include "debug.h" +// Define to enable direct execution of native plugins +// (i.e. not running through npviewer.bin) +#define ALLOW_DIRECT_EXECUTION 1 + + // Globally exported plugin ident, used by the "npconfig" tool const NPW_PluginInfo NPW_Plugin = { NPW_PLUGIN_IDENT, @@ -83,11 +89,15 @@ static Plugin g_plugin = { 0, -1, 0, NULL, NULL, NULL }; typedef struct _PluginInstance { NPW_DECL_PLUGIN_INSTANCE; rpc_connection_t *connection; + NPP native_instance; } PluginInstance; #define PLUGIN_INSTANCE(instance) \ ((PluginInstance *)NPW_PLUGIN_INSTANCE(instance)) +#define PLUGIN_INSTANCE_NPP(plugin) \ + NPW_PLUGIN_INSTANCE_NPP((NPW_PluginInstance *)(plugin)) + // Plugin side data for an NPStream instance typedef struct _StreamInstance { NPW_DECL_STREAM_INSTANCE; @@ -96,7 +106,11 @@ typedef struct _StreamInstance { // Prototypes static void plugin_init(int is_NP_Initialize); static void plugin_exit(void); -static NPError plugin_restart_if_needed(void); + +static void plugin_kill_cb(rpc_connection_t *connection, void *user_data); +static NPError plugin_start(void); +static NPError plugin_start_if_needed(void); +static int plugin_killed = 0; /* * Notes concerning NSPluginWrapper recovery model. @@ -115,10 +129,8 @@ static NPError plugin_restart_if_needed(void); * connection and thus can fail early/gracefully in subsequent calls * to NPP_*() functions. * - * TODO: make NPRuntime aware of per-plugin connections? This - * shouldn't matter from the Wrapper side because npruntime requests - * come from the Viewer side (see NPN_*() handlers). XXX: even with a - * running script (NPClass handlers)? + * All active NPRuntime objects are marked as inactive and + * are no longer processed. */ // Minimal time between two plugin restarts in sec @@ -128,6 +140,11 @@ static NPError plugin_restart_if_needed(void); // XXX: move to a common place to Wrapper and Viewer #define NPERR_STREAM_BUFSIZ 65536 + +/* ====================================================================== */ +/* === Helpers === */ +/* ====================================================================== */ + // Flush the X output buffer static void toolkit_flush(void) { @@ -152,6 +169,127 @@ static void toolkit_flush(void) } } +// PluginInstance vfuncs +static void *plugin_instance_allocate(void); +static void plugin_instance_deallocate(PluginInstance *plugin); +static void plugin_instance_finalize(PluginInstance *plugin); + +static NPW_PluginInstanceClass PluginInstanceClass = { + (NPW_PluginInstanceAllocateFunctionPtr)plugin_instance_allocate, + (NPW_PluginInstanceDeallocateFunctionPtr)plugin_instance_deallocate, + (NPW_PluginInstanceFinalizeFunctionPtr)plugin_instance_finalize +}; + +static void *plugin_instance_allocate(void) +{ + return NPW_MemNew0(PluginInstance, 1); +} + +static void plugin_instance_deallocate(PluginInstance *plugin) +{ + NPW_MemFree(plugin); +} + +static void plugin_instance_finalize(PluginInstance *plugin) +{ + id_remove(plugin->instance_id); + rpc_connection_unref(plugin->connection); +} + + +/* ====================================================================== */ +/* === Plug-in side data === */ +/* ====================================================================== */ + +// Functions supplied by the plug-in +static NPPluginFuncs plugin_funcs; + +// Allows the browser to query the plug-in supported formats +typedef char * (*NP_GetMIMEDescriptionUPP)(void); +static NP_GetMIMEDescriptionUPP g_plugin_NP_GetMIMEDescription = NULL; + +// Allows the browser to query the plug-in for information +typedef NPError (*NP_GetValueUPP)(void *instance, NPPVariable variable, void *value); +static NP_GetValueUPP g_plugin_NP_GetValue = NULL; + +// Provides global initialization for a plug-in +typedef NPError (*NP_InitializeUPP)(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs); +static NP_InitializeUPP g_plugin_NP_Initialize = NULL; + +// Provides global deinitialization for a plug-in +typedef NPError (*NP_ShutdownUPP)(void); +static NP_ShutdownUPP g_plugin_NP_Shutdown = NULL; + +// Plugin native library handle +static void *plugin_handle = NULL; + +static bool plugin_load_native(void) +{ + void *handle; + const char *error; + if ((handle = dlopen(plugin_path, RTLD_LOCAL|RTLD_LAZY)) == NULL) { + npw_printf("ERROR: %s\n", dlerror()); + return false; + } + dlerror(); + g_plugin_NP_GetMIMEDescription = (NP_GetMIMEDescriptionUPP)dlsym(handle, "NP_GetMIMEDescription"); + if ((error = dlerror()) != NULL) { + npw_printf("ERROR: %s\n", error); + dlclose(handle); + return false; + } + g_plugin_NP_Initialize = (NP_InitializeUPP)dlsym(handle, "NP_Initialize"); + if ((error = dlerror()) != NULL) { + npw_printf("ERROR: %s\n", error); + dlclose(handle); + return false; + } + g_plugin_NP_Shutdown = (NP_ShutdownUPP)dlsym(handle, "NP_Shutdown"); + if ((error = dlerror()) != NULL) { + npw_printf("ERROR: %s\n", error); + dlclose(handle); + return false; + } + g_plugin_NP_GetValue = (NP_GetValueUPP)dlsym(handle, "NP_GetValue"); + plugin_handle = handle; + return true; +} + +// Check for direct execution of the plugin +static inline bool plugin_has_direct_exec_env(void) +{ + if (getenv("NPW_DIRECT_EXEC")) + return true; + if (getenv("NPW_DIRECT_EXECUTION")) + return true; + return false; +} + +static bool plugin_can_direct_exec(void) +{ + if (!plugin_has_direct_exec_env()) + return false; + if (!plugin_load_native()) + return false; + // XXX: really check for same OS/ARCH + D(bug("Run plugin natively\n")); + return true; +} + +static inline bool plugin_direct_exec(void) +{ +#if ALLOW_DIRECT_EXECUTION + static int g_plugin_direct_exec = -1; + if (G_UNLIKELY(g_plugin_direct_exec < 0)) + g_plugin_direct_exec = plugin_can_direct_exec(); + return g_plugin_direct_exec; +#else + return false; +#endif +} + +#define PLUGIN_DIRECT_EXEC plugin_direct_exec() + /* ====================================================================== */ /* === RPC communication === */ @@ -204,12 +342,43 @@ static inline uint32 g_NPN_MemFlush(uint32 size) return CallNPN_MemFlushProc(mozilla_funcs.memflush, size); } +// NPN_ReloadPlugins +static void +g_NPN_ReloadPlugins(NPBool reloadPages) +{ + D(bug("NPN_ReloadPlugins reloadPages=%d\n", reloadPages)); + + NPW_UNIMPLEMENTED(); +} + +// NPN_GetJavaEnv +static JRIEnv * +g_NPN_GetJavaEnv(void) +{ + D(bug("NPN_GetJavaEnv\n")); + + return NULL; +} + +// NPN_GetJavaPeer +static jref +g_NPN_GetJavaPeer(NPP instance) +{ + D(bug("NPN_GetJavaPeer instance=%p\n", instance)); + + return NULL; +} + // NPN_UserAgent static const char *g_NPN_UserAgent(NPP instance) { if (mozilla_funcs.uagent == NULL) return NULL; - return mozilla_funcs.uagent(instance); + + D(bugiI("NPN_UserAgent instance=%p\n", instance)); + const char *user_agent = CallNPN_UserAgentProc(mozilla_funcs.uagent, instance); + D(bugiD("NPN_UserAgent return: '%s'\n", user_agent)); + return user_agent; } static int handle_NPN_UserAgent(rpc_connection_t *connection) @@ -227,14 +396,25 @@ static int handle_NPN_UserAgent(rpc_connection_t *connection) } // NPN_Status +static void +g_NPN_Status(NPP instance, const char *message) +{ + if (mozilla_funcs.status == NULL) + return; + + D(bugiI("NPN_Status instance=%p, message='%s'\n", instance, message)); + CallNPN_StatusProc(mozilla_funcs.status, instance, message); + D(bugiD("NPN_Status done\n")); +} + static int handle_NPN_Status(rpc_connection_t *connection) { D(bug("handle_NPN_Status\n")); - NPP instance; + PluginInstance *plugin; char *message; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_STRING, &message, RPC_TYPE_INVALID); @@ -243,10 +423,8 @@ static int handle_NPN_Status(rpc_connection_t *connection) return error; } - D(bug(" instance=%p, message='%s'\n", instance, message)); + g_NPN_Status(PLUGIN_INSTANCE_NPP(plugin), message); - if (mozilla_funcs.status) - mozilla_funcs.status(instance, message); if (message) free(message); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); @@ -259,9 +437,9 @@ g_NPN_GetValue(NPP instance, NPNVariable variable, void *value) if (mozilla_funcs.getvalue == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; - D(bug("NPN_GetValue instance=%p, variable=%d\n", instance, variable)); + D(bugiI("NPN_GetValue instance=%p, variable=%d [%s]\n", instance, variable, string_of_NPNVariable(variable))); NPError ret = mozilla_funcs.getvalue(instance, variable, value); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPN_GetValue return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } @@ -269,10 +447,10 @@ static int handle_NPN_GetValue(rpc_connection_t *connection) { D(bug("handle_NPN_GetValue\n")); - NPP instance; + PluginInstance *plugin; uint32_t variable; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_UINT32, &variable, RPC_TYPE_INVALID); @@ -286,19 +464,19 @@ static int handle_NPN_GetValue(rpc_connection_t *connection) case RPC_TYPE_UINT32: { uint32_t n = 0; - ret = g_NPN_GetValue(instance, variable, (void *)&n); + ret = g_NPN_GetValue(PLUGIN_INSTANCE_NPP(plugin), variable, (void *)&n); return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_UINT32, n, RPC_TYPE_INVALID); } case RPC_TYPE_BOOLEAN: { PRBool b = PR_FALSE; - ret = g_NPN_GetValue(instance, variable, (void *)&b); + 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_NP_OBJECT: { NPObject *npobj = NULL; - ret = g_NPN_GetValue(instance, variable, (void *)&npobj); + 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); } } @@ -308,14 +486,14 @@ static int handle_NPN_GetValue(rpc_connection_t *connection) // NPN_SetValue static NPError -g_NPN_SetValue(NPP instance, NPNVariable variable, void *value) +g_NPN_SetValue(NPP instance, NPPVariable variable, void *value) { if (mozilla_funcs.setvalue == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; - D(bug("NPN_SetValue instance=%p, variable=%d\n", instance, variable)); + D(bugiI("NPN_SetValue instance=%p, variable=%d [%s]\n", instance, variable, string_of_NPPVariable(variable))); NPError ret = mozilla_funcs.setvalue(instance, variable, value); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPN_SetValue return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } @@ -323,10 +501,10 @@ static int handle_NPN_SetValue(rpc_connection_t *connection) { D(bug("handle_NPN_SetValue\n")); - NPP instance; + PluginInstance *plugin; uint32_t variable, value; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_UINT32, &variable, RPC_TYPE_BOOLEAN, &value, RPC_TYPE_INVALID); @@ -336,7 +514,7 @@ static int handle_NPN_SetValue(rpc_connection_t *connection) return error; } - NPError ret = g_NPN_SetValue(instance, variable, (void *)(uintptr_t)value); + NPError ret = g_NPN_SetValue(PLUGIN_INSTANCE_NPP(plugin), variable, (void *)(uintptr_t)value); return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID); } @@ -346,19 +524,19 @@ static void g_NPN_InvalidateRect(NPP instance, NPRect *invalidRect) if (mozilla_funcs.invalidaterect == NULL) return; - D(bug("NPN_InvalidateRect instance=%p\n", instance)); + D(bugiI("NPN_InvalidateRect instance=%p\n", instance)); CallNPN_InvalidateRectProc(mozilla_funcs.invalidaterect, instance, invalidRect); - D(bug(" done\n")); + D(bugiD("NPN_InvalidateRect done\n")); } static int handle_NPN_InvalidateRect(rpc_connection_t *connection) { D(bug("handle_NPN_InvalidateRect\n")); - NPP instance; + PluginInstance *plugin; NPRect invalidRect; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_RECT, &invalidRect, RPC_TYPE_INVALID); @@ -367,20 +545,38 @@ static int handle_NPN_InvalidateRect(rpc_connection_t *connection) return error; } - g_NPN_InvalidateRect(instance, &invalidRect); + g_NPN_InvalidateRect(PLUGIN_INSTANCE_NPP(plugin), &invalidRect); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } +// NPN_InvalidateRegion +static void +g_NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion) +{ + D(bug("NPN_InvalidateRegion instance=%p\n", instance)); + + NPW_UNIMPLEMENTED(); +} + +// NPN_ForceRedraw +static void +g_NPN_ForceRedraw(NPP instance) +{ + D(bug("NPN_ForceRedraw instance=%p\n", instance)); + + NPW_UNIMPLEMENTED(); +} + // NPN_GetURL static NPError g_NPN_GetURL(NPP instance, const char *url, const char *target) { if (mozilla_funcs.geturl == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; - D(bug("NPN_GetURL instance=%p, url='%s', target='%s'\n", instance, url, target)); + D(bugiI("NPN_GetURL instance=%p, url='%s', target='%s'\n", instance, url, target)); NPError ret = CallNPN_GetURLProc(mozilla_funcs.geturl, instance, url, target); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPN_GetURL return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } @@ -388,10 +584,10 @@ static int handle_NPN_GetURL(rpc_connection_t *connection) { D(bug("handle_NPN_GetURL\n")); - NPP instance; + PluginInstance *plugin; char *url, *target; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_STRING, &url, RPC_TYPE_STRING, &target, RPC_TYPE_INVALID); @@ -401,7 +597,7 @@ static int handle_NPN_GetURL(rpc_connection_t *connection) return error; } - NPError ret = g_NPN_GetURL(instance, url, target); + NPError ret = g_NPN_GetURL(PLUGIN_INSTANCE_NPP(plugin), url, target); if (url) free(url); @@ -417,9 +613,9 @@ static NPError g_NPN_GetURLNotify(NPP instance, const char *url, const char *tar if (mozilla_funcs.geturlnotify == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; - D(bug("NPN_GetURLNotify instance=%p, url='%s', target='%s', notifyData=%p\n", instance, url, target, notifyData)); + D(bugiI("NPN_GetURLNotify instance=%p, url='%s', target='%s', notifyData=%p\n", instance, url, target, notifyData)); NPError ret = CallNPN_GetURLNotifyProc(mozilla_funcs.geturlnotify, instance, url, target, notifyData); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPN_GetURLNotify return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } @@ -427,11 +623,11 @@ static int handle_NPN_GetURLNotify(rpc_connection_t *connection) { D(bug("handle_NPN_GetURLNotify\n")); - NPP instance; + PluginInstance *plugin; char *url, *target; void *notifyData; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_STRING, &url, RPC_TYPE_STRING, &target, RPC_TYPE_NP_NOTIFY_DATA, ¬ifyData, @@ -442,7 +638,7 @@ static int handle_NPN_GetURLNotify(rpc_connection_t *connection) return error; } - NPError ret = g_NPN_GetURLNotify(instance, url, target, notifyData); + NPError ret = g_NPN_GetURLNotify(PLUGIN_INSTANCE_NPP(plugin), url, target, notifyData); if (url) free(url); @@ -458,9 +654,9 @@ static NPError g_NPN_PostURL(NPP instance, const char *url, const char *target, if (mozilla_funcs.posturl == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; - D(bug("NPN_PostURL instance=%p, url='%s', target='%s', file='%s'\n", instance, url, target, file ? buf : "")); + D(bugiI("NPN_PostURL instance=%p, url='%s', target='%s', file='%s'\n", instance, url, target, file ? buf : "")); NPError ret = CallNPN_PostURLProc(mozilla_funcs.posturl, instance, url, target, len, buf, file); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPN_PostURL return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } @@ -468,13 +664,13 @@ static int handle_NPN_PostURL(rpc_connection_t *connection) { D(bug("handle_NPN_PostURL\n")); - NPP instance; + PluginInstance *plugin; char *url, *target; uint32_t len; char *buf; uint32_t file; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_STRING, &url, RPC_TYPE_STRING, &target, RPC_TYPE_ARRAY, RPC_TYPE_CHAR, &len, &buf, @@ -486,7 +682,7 @@ static int handle_NPN_PostURL(rpc_connection_t *connection) return error; } - NPError ret = g_NPN_PostURL(instance, url, target, len, buf, file); + NPError ret = g_NPN_PostURL(PLUGIN_INSTANCE_NPP(plugin), url, target, len, buf, file); if (url) free(url); @@ -504,9 +700,9 @@ static NPError g_NPN_PostURLNotify(NPP instance, const char *url, const char *ta if (mozilla_funcs.posturlnotify == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; - D(bug("NPN_PostURLNotify instance=%p, url='%s', target='%s', file='%s', notifyData=%p\n", instance, url, target, file ? buf : "", notifyData)); + D(bugiI("NPN_PostURLNotify instance=%p, url='%s', target='%s', file='%s', notifyData=%p\n", instance, url, target, file ? buf : "", notifyData)); NPError ret = CallNPN_PostURLNotifyProc(mozilla_funcs.posturlnotify, instance, url, target, len, buf, file, notifyData); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPN_PostURLNotify return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } @@ -514,14 +710,14 @@ static int handle_NPN_PostURLNotify(rpc_connection_t *connection) { D(bug("handle_NPN_PostURLNotify\n")); - NPP instance; + PluginInstance *plugin; char *url, *target; int32_t len; char *buf; uint32_t file; void *notifyData; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_STRING, &url, RPC_TYPE_STRING, &target, RPC_TYPE_ARRAY, RPC_TYPE_CHAR, &len, &buf, @@ -534,7 +730,7 @@ static int handle_NPN_PostURLNotify(rpc_connection_t *connection) return error; } - NPError ret = g_NPN_PostURLNotify(instance, url, target, len, buf, file, notifyData); + NPError ret = g_NPN_PostURLNotify(PLUGIN_INSTANCE_NPP(plugin), url, target, len, buf, file, notifyData); if (url) free(url); @@ -579,9 +775,9 @@ static NPError g_NPN_RequestRead(NPStream *stream, NPByteRange *rangeList) if (mozilla_funcs.requestread == NULL) return NPERR_INVALID_FUNCTABLE_ERROR; - D(bug("NPN_RequestRead stream=%p, rangeList=%p\n", stream, rangeList)); + D(bugiI("NPN_RequestRead stream=%p, rangeList=%p\n", stream, rangeList)); NPError ret = CallNPN_RequestReadProc(mozilla_funcs.requestread, stream, rangeList); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPN_RequestRead return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } @@ -621,9 +817,12 @@ static NPError g_NPN_NewStream(NPP instance, NPMIMEType type, const char *target if (stream == NULL) return NPERR_INVALID_PARAM; - D(bug("NPN_NewStream instance=%p, type='%s', target='%s'\n", instance, type, target)); + D(bugiI("NPN_NewStream instance=%p, type='%s', target='%s'\n", instance, type, target)); NPError ret = CallNPN_NewStreamProc(mozilla_funcs.newstream, instance, type, target, stream); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPN_NewStream return: %d [%s]\n", ret, string_of_NPError(ret))); + + if (PLUGIN_DIRECT_EXEC) + return ret; if (ret == NPERR_NO_ERROR) { StreamInstance *stream_pdata = malloc(sizeof(*stream_pdata)); @@ -657,11 +856,11 @@ static int handle_NPN_NewStream(rpc_connection_t *connection) { D(bug("handle_NPN_NewStream\n")); - NPP instance; + PluginInstance *plugin; char *type; char *target; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_STRING, &type, RPC_TYPE_STRING, &target, RPC_TYPE_INVALID); @@ -672,7 +871,7 @@ static int handle_NPN_NewStream(rpc_connection_t *connection) } NPStream *stream; - NPError ret = g_NPN_NewStream(instance, type, target, &stream); + NPError ret = g_NPN_NewStream(PLUGIN_INSTANCE_NPP(plugin), type, target, &stream); if (type) free(type); @@ -702,17 +901,19 @@ g_NPN_DestroyStream(NPP instance, NPStream *stream, NPReason reason) // Mozilla calls NPP_DestroyStream() for its streams, keep stream // info in that case - StreamInstance *stream_pdata = stream->pdata; - if (stream_pdata && stream_pdata->is_plugin_stream) { - id_remove(stream_pdata->stream_id); - free(stream->pdata); - stream->pdata = NULL; + if (!PLUGIN_DIRECT_EXEC) { + StreamInstance *stream_pdata = stream->pdata; + if (stream_pdata && stream_pdata->is_plugin_stream) { + id_remove(stream_pdata->stream_id); + free(stream->pdata); + stream->pdata = NULL; + } } - D(bug("NPN_DestroyStream instance=%p, stream=%p, reason=%s\n", + D(bugiI("NPN_DestroyStream instance=%p, stream=%p, reason=%s\n", instance, stream, string_of_NPReason(reason))); NPError ret = CallNPN_DestroyStreamProc(mozilla_funcs.destroystream, instance, stream, reason); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPN_DestroyStream return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } @@ -721,11 +922,11 @@ static int handle_NPN_DestroyStream(rpc_connection_t *connection) { D(bug("handle_NPN_DestroyStream\n")); - NPP instance; + PluginInstance *plugin; NPStream *stream; int32_t reason; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_STREAM, &stream, RPC_TYPE_INT32, &reason, RPC_TYPE_INVALID); @@ -735,7 +936,7 @@ static int handle_NPN_DestroyStream(rpc_connection_t *connection) return error; } - NPError ret = g_NPN_DestroyStream(instance, stream, reason); + NPError ret = g_NPN_DestroyStream(PLUGIN_INSTANCE_NPP(plugin), stream, reason); return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID); } @@ -748,9 +949,9 @@ static int32 g_NPN_Write(NPP instance, NPStream *stream, int32 len, void *buf) if (stream == NULL) return -1; - D(bug("NPP_Write instance=%p\n", instance)); + D(bugiI("NPN_Write instance=%p\n", instance)); int32 ret = CallNPN_WriteProc(mozilla_funcs.write, instance, stream, len, buf); - D(bug(" return: %d\n", ret)); + D(bugiD("NPN_Write return: %d\n", ret)); return ret; } @@ -758,12 +959,12 @@ static int handle_NPN_Write(rpc_connection_t *connection) { D(bug("handle_NPN_Write\n")); - NPP instance; + PluginInstance *plugin; NPStream *stream; unsigned char *buf; int32_t len; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_STREAM, &stream, RPC_TYPE_ARRAY, RPC_TYPE_CHAR, &len, &buf, RPC_TYPE_INVALID); @@ -773,7 +974,7 @@ static int handle_NPN_Write(rpc_connection_t *connection) return error; } - int32 ret = g_NPN_Write(instance, stream, len, buf); + int32 ret = g_NPN_Write(PLUGIN_INSTANCE_NPP(plugin), stream, len, buf); if (buf) free(buf); @@ -787,19 +988,19 @@ static void g_NPN_PushPopupsEnabledState(NPP instance, NPBool enabled) if (mozilla_funcs.pushpopupsenabledstate == NULL) return; - D(bug("NPN_PushPopupsEnabledState instance=%p, enabled=%d\n", instance, enabled)); + D(bugiI("NPN_PushPopupsEnabledState instance=%p, enabled=%d\n", instance, enabled)); CallNPN_PushPopupsEnabledStateProc(mozilla_funcs.pushpopupsenabledstate, instance, enabled); - D(bug(" done\n")); + D(bugiD("NPN_PushPopupsEnabledState done\n")); } static int handle_NPN_PushPopupsEnabledState(rpc_connection_t *connection) { D(bug("handle_NPN_PushPopupsEnabledState\n")); - NPP instance; + PluginInstance *plugin; uint32_t enabled; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_UINT32, &enabled, RPC_TYPE_INVALID); @@ -808,7 +1009,7 @@ static int handle_NPN_PushPopupsEnabledState(rpc_connection_t *connection) return error; } - g_NPN_PushPopupsEnabledState(instance, enabled); + g_NPN_PushPopupsEnabledState(PLUGIN_INSTANCE_NPP(plugin), enabled); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } @@ -819,18 +1020,18 @@ static void g_NPN_PopPopupsEnabledState(NPP instance) if (mozilla_funcs.poppopupsenabledstate == NULL) return; - D(bug("NPN_PopPopupsEnabledState instance=%p\n", instance)); + D(bugiI("NPN_PopPopupsEnabledState instance=%p\n", instance)); CallNPN_PopPopupsEnabledStateProc(mozilla_funcs.poppopupsenabledstate, instance); - D(bug(" done\n")); + D(bugiD("NPN_PopPopupsEnabledState done\n")); } static int handle_NPN_PopPopupsEnabledState(rpc_connection_t *connection) { D(bug("handle_NPN_PopPopupsEnabledState\n")); - NPP instance; + PluginInstance *plugin; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -838,7 +1039,7 @@ static int handle_NPN_PopPopupsEnabledState(rpc_connection_t *connection) return error; } - g_NPN_PopPopupsEnabledState(instance); + g_NPN_PopPopupsEnabledState(PLUGIN_INSTANCE_NPP(plugin)); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } @@ -849,11 +1050,22 @@ static int handle_NPN_PopPopupsEnabledState(rpc_connection_t *connection) /* ====================================================================== */ // NPN_CreateObject +static NPObject * +g_NPN_CreateObject(NPP instance, NPClass *klass) +{ + D(bugiI("NPN_CreateObject instance=%p, aClass=%p\n", instance, klass)); + NPObject *npobj = CallNPN_CreateObjectProc(mozilla_funcs.createobject, instance, klass); + D(bugiD("NPN_CreateObject return: %p\n", npobj)); + return npobj; +} + static int handle_NPN_CreateObject(rpc_connection_t *connection) { - NPP instance; + D(bug("handle_NPN_CreateObject\n")); + + PluginInstance *plugin; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -861,7 +1073,7 @@ static int handle_NPN_CreateObject(rpc_connection_t *connection) return error; } - NPObject *npobj = mozilla_funcs.createobject(instance, &npclass_bridge); + NPObject *npobj = g_NPN_CreateObject(PLUGIN_INSTANCE_NPP(plugin), &npclass_bridge); uint32_t npobj_id = 0; if (npobj) { @@ -876,8 +1088,19 @@ static int handle_NPN_CreateObject(rpc_connection_t *connection) } // NPN_RetainObject +static NPObject * +g_NPN_RetainObject(NPObject *npobj) +{ + D(bugiI("NPN_RetainObject npobj=%p\n", npobj)); + NPObject *new_npobj = CallNPN_RetainObjectProc(mozilla_funcs.retainobject, npobj); + D(bugiD("NPN_RetainObject return: %p (refcount: %d)\n", new_npobj, new_npobj->referenceCount)); + 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, @@ -891,14 +1114,28 @@ static int handle_NPN_RetainObject(rpc_connection_t *connection) if (npobj == NULL) // this shall not happen, let it crash npw_printf("ERROR: NPN_RetainObject got a null NPObject\n"); - mozilla_funcs.retainobject(npobj); + 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) +{ + D(bugiI("NPN_ReleaseObject npobj=%p\n", npobj)); + uint32_t refcount = npobj->referenceCount - 1; + NPN_ReleaseObject(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, @@ -912,21 +1149,41 @@ static int handle_NPN_ReleaseObject(rpc_connection_t *connection) if (npobj == NULL) // this shall not happen, let it crash npw_printf("ERROR: NPN_ReleaseObject got a null NPObject\n"); - NPN_ReleaseObject(npobj); + /* 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; - return rpc_method_send_reply(connection, RPC_TYPE_UINT32, npobj->referenceCount, RPC_TYPE_INVALID); + 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) +{ + D(bugiI("NPN_Invoke instance=%p, npobj=%p, methodName=%p\n", instance, npobj, methodName)); + print_npvariant_args(args, argCount); + bool ret = CallNPN_InvokeProc(mozilla_funcs.invoke, instance, npobj, methodName, args, argCount, result); + gchar *result_str = string_of_NPVariant(result); + D(bugiD("NPN_Invoke return: %d (%s)\n", ret, result_str)); + g_free(result_str); + return ret; +} + static int handle_NPN_Invoke(rpc_connection_t *connection) { - NPP instance; + D(bug("handle_NPN_Invoke()\n")); + + PluginInstance *plugin; NPObject *npobj; NPIdentifier methodName; NPVariant *args; uint32_t argCount; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_OBJECT, &npobj, RPC_TYPE_NP_IDENTIFIER, &methodName, RPC_TYPE_ARRAY, RPC_TYPE_NP_VARIANT, &argCount, &args, @@ -939,7 +1196,7 @@ static int handle_NPN_Invoke(rpc_connection_t *connection) NPVariant result; VOID_TO_NPVARIANT(result); - bool ret = mozilla_funcs.invoke(instance, npobj, methodName, args, argCount, &result); + bool ret = g_NPN_Invoke(PLUGIN_INSTANCE_NPP(plugin), npobj, methodName, args, argCount, &result); if (args) { for (int i = 0; i < argCount; i++) @@ -957,14 +1214,28 @@ static int handle_NPN_Invoke(rpc_connection_t *connection) } // NPN_InvokeDefault +static bool +g_NPN_InvokeDefault(NPP instance, NPObject *npobj, const NPVariant *args, uint32_t argCount, NPVariant *result) +{ + D(bugiI("NPN_InvokeDefault instance=%p, npobj=%p\n", instance, npobj)); + print_npvariant_args(args, argCount); + bool ret = CallNPN_InvokeDefaultProc(mozilla_funcs.invokeDefault, instance, npobj, args, argCount, result); + gchar *result_str = string_of_NPVariant(result); + D(bugiD("NPN_InvokeDefault return: %d (%s)\n", ret, result_str)); + g_free(result_str); + return ret; +} + static int handle_NPN_InvokeDefault(rpc_connection_t *connection) { - NPP instance; + D(bug("handle_NPN_InvokeDefault\n")); + + PluginInstance *plugin; NPObject *npobj; NPVariant *args; uint32_t argCount; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_OBJECT, &npobj, RPC_TYPE_ARRAY, RPC_TYPE_NP_VARIANT, &argCount, &args, RPC_TYPE_INVALID); @@ -976,7 +1247,7 @@ static int handle_NPN_InvokeDefault(rpc_connection_t *connection) NPVariant result; VOID_TO_NPVARIANT(result); - bool ret = mozilla_funcs.invokeDefault(instance, npobj, args, argCount, &result); + bool ret = g_NPN_InvokeDefault(PLUGIN_INSTANCE_NPP(plugin), npobj, args, argCount, &result); if (args) { for (int i = 0; i < argCount; i++) @@ -994,13 +1265,26 @@ static int handle_NPN_InvokeDefault(rpc_connection_t *connection) } // NPN_Evaluate +static bool +g_NPN_Evaluate(NPP instance, NPObject *npobj, NPString *script, NPVariant *result) +{ + D(bugiI("NPN_Evaluate instance=%p, npobj=%p\n", instance, npobj)); + bool ret = CallNPN_EvaluateProc(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)); + g_free(result_str); + return ret; +} + static int handle_NPN_Evaluate(rpc_connection_t *connection) { - NPP instance; + D(bug("handle_NPN_Evaluate\n")); + + PluginInstance *plugin; NPObject *npobj; NPString script; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_OBJECT, &npobj, RPC_TYPE_NP_STRING, &script, RPC_TYPE_INVALID); @@ -1012,7 +1296,7 @@ static int handle_NPN_Evaluate(rpc_connection_t *connection) NPVariant result; VOID_TO_NPVARIANT(result); - bool ret = mozilla_funcs.evaluate(instance, npobj, &script, &result); + bool ret = g_NPN_Evaluate(PLUGIN_INSTANCE_NPP(plugin), npobj, &script, &result); if (script.utf8characters) free((void *)script.utf8characters); @@ -1027,13 +1311,26 @@ static int handle_NPN_Evaluate(rpc_connection_t *connection) } // NPN_GetProperty +static bool +g_NPN_GetProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName, NPVariant *result) +{ + D(bugiI("NPN_GetProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName)); + bool ret = CallNPN_GetPropertyProc(mozilla_funcs.getproperty, instance, npobj, propertyName, result); + gchar *result_str = string_of_NPVariant(result); + D(bugiD("NPN_GetProperty return: %d (%s)\n", ret, result_str)); + g_free(result_str); + return ret; +} + static int handle_NPN_GetProperty(rpc_connection_t *connection) { - NPP instance; + D(bug("handle_NPN_GetProperty\n")); + + PluginInstance *plugin; NPObject *npobj; NPIdentifier propertyName; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_OBJECT, &npobj, RPC_TYPE_NP_IDENTIFIER, &propertyName, RPC_TYPE_INVALID); @@ -1045,7 +1342,7 @@ static int handle_NPN_GetProperty(rpc_connection_t *connection) NPVariant result; VOID_TO_NPVARIANT(result); - bool ret = mozilla_funcs.getproperty(instance, npobj, propertyName, &result); + bool ret = g_NPN_GetProperty(PLUGIN_INSTANCE_NPP(plugin), npobj, propertyName, &result); int rpc_ret = rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, @@ -1057,14 +1354,25 @@ static int handle_NPN_GetProperty(rpc_connection_t *connection) } // NPN_SetProperty +static bool +g_NPN_SetProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName, const NPVariant *value) +{ + D(bugiI("NPN_SetProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName)); + bool ret = CallNPN_SetPropertyProc(mozilla_funcs.setproperty, instance, npobj, propertyName, value); + D(bugiD("NPN_SetProperty return: %d\n", ret)); + return ret; +} + static int handle_NPN_SetProperty(rpc_connection_t *connection) { - NPP instance; + D(bug("handle_NPN_SetProperty\n")); + + PluginInstance *plugin; NPObject *npobj; NPIdentifier propertyName; NPVariant value; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_OBJECT, &npobj, RPC_TYPE_NP_IDENTIFIER, &propertyName, RPC_TYPE_NP_VARIANT, &value, @@ -1075,7 +1383,7 @@ static int handle_NPN_SetProperty(rpc_connection_t *connection) return error; } - bool ret = mozilla_funcs.setproperty(instance, npobj, propertyName, &value); + bool ret = g_NPN_SetProperty(PLUGIN_INSTANCE_NPP(plugin), npobj, propertyName, &value); NPN_ReleaseVariantValue(&value); @@ -1085,13 +1393,24 @@ static int handle_NPN_SetProperty(rpc_connection_t *connection) } // NPN_RemoveProperty +static bool +g_NPN_RemoveProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName) +{ + D(bugiI("NPN_RemoveProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName)); + bool ret = CallNPN_RemovePropertyProc(mozilla_funcs.removeproperty, instance, npobj, propertyName); + D(bugiD("NPN_RemoveProperty return: %d\n", ret)); + return ret; +} + static int handle_NPN_RemoveProperty(rpc_connection_t *connection) { - NPP instance; + D(bug("handle_NPN_RemoveProperty\n")); + + PluginInstance *plugin; NPObject *npobj; NPIdentifier propertyName; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_OBJECT, &npobj, RPC_TYPE_NP_IDENTIFIER, &propertyName, RPC_TYPE_INVALID); @@ -1101,7 +1420,7 @@ static int handle_NPN_RemoveProperty(rpc_connection_t *connection) return error; } - bool ret = mozilla_funcs.removeproperty(instance, npobj, propertyName); + bool ret = g_NPN_RemoveProperty(PLUGIN_INSTANCE_NPP(plugin), npobj, propertyName); return rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, @@ -1109,13 +1428,24 @@ static int handle_NPN_RemoveProperty(rpc_connection_t *connection) } // NPN_HasProperty +static bool +g_NPN_HasProperty(NPP instance, NPObject *npobj, NPIdentifier propertyName) +{ + D(bugiI("NPN_HasProperty instance=%p, npobj=%p, propertyName=%p\n", instance, npobj, propertyName)); + bool ret = CallNPN_HasPropertyProc(mozilla_funcs.hasproperty, instance, npobj, propertyName); + D(bugiD("NPN_HasProperty return: %d\n", ret)); + return ret; +} + static int handle_NPN_HasProperty(rpc_connection_t *connection) { - NPP instance; + D(bug("handle_NPN_HasProperty\n")); + + PluginInstance *plugin; NPObject *npobj; NPIdentifier propertyName; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_OBJECT, &npobj, RPC_TYPE_NP_IDENTIFIER, &propertyName, RPC_TYPE_INVALID); @@ -1125,7 +1455,7 @@ static int handle_NPN_HasProperty(rpc_connection_t *connection) return error; } - bool ret = mozilla_funcs.hasproperty(instance, npobj, propertyName); + bool ret = g_NPN_HasProperty(PLUGIN_INSTANCE_NPP(plugin), npobj, propertyName); return rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, @@ -1133,13 +1463,24 @@ static int handle_NPN_HasProperty(rpc_connection_t *connection) } // NPN_HasMethod +static bool +g_NPN_HasMethod(NPP instance, NPObject *npobj, NPIdentifier methodName) +{ + D(bugiI("NPN_HasMethod instance=%p, npobj=%p, methodName=%p\n", methodName)); + bool ret = CallNPN_HasMethodProc(mozilla_funcs.hasmethod, instance, npobj, methodName); + D(bugiD("NPN_HasMethod return: %d\n", ret)); + return ret; +} + static int handle_NPN_HasMethod(rpc_connection_t *connection) { - NPP instance; + D(bug("handle_NPN_HasMethod\n")); + + PluginInstance *plugin; NPObject *npobj; NPIdentifier methodName; int error = rpc_method_get_args(connection, - RPC_TYPE_NPP, &instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, &plugin, RPC_TYPE_NP_OBJECT, &npobj, RPC_TYPE_NP_IDENTIFIER, &methodName, RPC_TYPE_INVALID); @@ -1149,7 +1490,7 @@ static int handle_NPN_HasMethod(rpc_connection_t *connection) return error; } - bool ret = mozilla_funcs.hasmethod(instance, npobj, methodName); + bool ret = g_NPN_HasMethod(PLUGIN_INSTANCE_NPP(plugin), npobj, methodName); return rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, @@ -1157,8 +1498,18 @@ static int handle_NPN_HasMethod(rpc_connection_t *connection) } // NPN_SetException +static void +g_NPN_SetException(NPObject *npobj, const char *message) +{ + D(bugiI("NPN_SetException npobj=%p, message='%s'\n", npobj, message)); + CallNPN_SetExceptionProc(mozilla_funcs.setexception, npobj, message); + D(bugiD("NPN_SetException done\n")); +} + static int handle_NPN_SetException(rpc_connection_t *connection) { + D(bug("handle_NPN_SetException\n")); + NPObject *npobj; NPUTF8 *message; int error = rpc_method_get_args(connection, @@ -1171,7 +1522,7 @@ static int handle_NPN_SetException(rpc_connection_t *connection) return error; } - mozilla_funcs.setexception(npobj, message); + g_NPN_SetException(npobj, message); // XXX memory leak (message) @@ -1179,8 +1530,19 @@ static int handle_NPN_SetException(rpc_connection_t *connection) } // NPN_GetStringIdentifier +static NPIdentifier +g_NPN_GetStringIdentifier(const char *name) +{ + D(bugiI("NPN_GetStringIdentifier name='%s'\n", name)); + NPIdentifier ident = CallNPN_GetStringIdentifierProc(mozilla_funcs.getstringidentifier, name); + D(bugiD("NPN_GetStringIdentifier return: %p\n", ident)); + return ident; +} + static int handle_NPN_GetStringIdentifier(rpc_connection_t *connection) { + D(bug("handle_NPN_GetStringIdentifier\n")); + char *name; int error = rpc_method_get_args(connection, RPC_TYPE_STRING, &name, @@ -1191,7 +1553,7 @@ static int handle_NPN_GetStringIdentifier(rpc_connection_t *connection) return error; } - NPIdentifier ident = mozilla_funcs.getstringidentifier(name); + NPIdentifier ident = g_NPN_GetStringIdentifier(name); if (name) free(name); @@ -1202,8 +1564,18 @@ static int handle_NPN_GetStringIdentifier(rpc_connection_t *connection) } // NPN_GetStringIdentifiers +static void +g_NPN_GetStringIdentifiers(const NPUTF8 **names, uint32_t nameCount, NPIdentifier *idents) +{ + D(bugiI("NPN_GetStringIdentifiers nameCount=%d\n", nameCount)); + CallNPN_GetStringIdentifiersProc(mozilla_funcs.getstringidentifiers, names, nameCount, idents); + D(bugiD("NPN_GetStringIdentifiers done\n")); +} + static int handle_NPN_GetStringIdentifiers(rpc_connection_t *connection) { + D(bug("handle_NPN_GetStringIdentifiers\n")); + NPUTF8 **names; uint32_t nameCount; int error = rpc_method_get_args(connection, @@ -1215,9 +1587,9 @@ static int handle_NPN_GetStringIdentifiers(rpc_connection_t *connection) return error; } - NPIdentifier *idents = malloc(nameCount * sizeof(idents[0])); + NPIdentifier *idents = NPW_MemNew0(NPIdentifier, nameCount); if (idents) - mozilla_funcs.getstringidentifiers((const NPUTF8 **)names, nameCount, idents); + g_NPN_GetStringIdentifiers((const NPUTF8 **)names, nameCount, idents); if (names) { for (int i = 0; i < nameCount; i++) @@ -1225,14 +1597,28 @@ static int handle_NPN_GetStringIdentifiers(rpc_connection_t *connection) free(names); } - return rpc_method_send_reply(connection, - RPC_TYPE_ARRAY, RPC_TYPE_NP_IDENTIFIER, nameCount, idents, - RPC_TYPE_INVALID); + int rpc_ret = rpc_method_send_reply(connection, + RPC_TYPE_ARRAY, RPC_TYPE_NP_IDENTIFIER, nameCount, idents, + RPC_TYPE_INVALID); + + NPN_MemFree(idents); + return rpc_ret; } // NPN_GetIntIdentifier +static NPIdentifier +g_NPN_GetIntIdentifier(int32_t intid) +{ + D(bugiI("NPN_GetIntIdentifier intid=%d\n", intid)); + NPIdentifier ident = CallNPN_GetIntIdentifierProc(mozilla_funcs.getintidentifier, intid); + D(bugiD("NPN_GetIntIdentifier return: %p\n", ident)); + return ident; +} + static int handle_NPN_GetIntIdentifier(rpc_connection_t *connection) { + D(bug("handle_NPN_GetIntIdentifier\n")); + int32_t intid; int error = rpc_method_get_args(connection, RPC_TYPE_INT32, &intid, @@ -1243,7 +1629,7 @@ static int handle_NPN_GetIntIdentifier(rpc_connection_t *connection) return error; } - NPIdentifier ident = mozilla_funcs.getintidentifier(intid); + NPIdentifier ident = g_NPN_GetIntIdentifier(intid); return rpc_method_send_reply(connection, RPC_TYPE_NP_IDENTIFIER, ident, @@ -1251,8 +1637,19 @@ static int handle_NPN_GetIntIdentifier(rpc_connection_t *connection) } // NPN_IdentifierIsString +static bool +g_NPN_IdentifierIsString(NPIdentifier ident) +{ + D(bugiI("NPN_IdentifierIsString ident=%p\n", ident)); + bool ret = CallNPN_IdentifierIsStringProc(mozilla_funcs.identifierisstring, ident); + D(bugiD("NPN_IdentifierIsString return: %s\n", ret ? "true" : "false")); + return ret; +} + static int handle_NPN_IdentifierIsString(rpc_connection_t *connection) { + D(bug("handle_NPN_IdentifierIsString\n")); + NPIdentifier ident; int error = rpc_method_get_args(connection, RPC_TYPE_NP_IDENTIFIER, &ident, @@ -1263,7 +1660,7 @@ static int handle_NPN_IdentifierIsString(rpc_connection_t *connection) return error; } - bool ret = mozilla_funcs.identifierisstring(ident); + bool ret = g_NPN_IdentifierIsString(ident); return rpc_method_send_reply(connection, RPC_TYPE_UINT32, ret, @@ -1271,8 +1668,19 @@ static int handle_NPN_IdentifierIsString(rpc_connection_t *connection) } // NPN_UTF8FromIdentifier +static NPUTF8 * +g_NPN_UTF8FromIdentifier(NPIdentifier ident) +{ + D(bugiI("NPN_UTF8FromIdentifier ident=%p\n", ident)); + NPUTF8 *str = CallNPN_UTF8FromIdentifierProc(mozilla_funcs.utf8fromidentifier, ident); + D(bugiD("NPN_UTF8FromIdentifier return: '%s'\n", str)); + return str; +} + static int handle_NPN_UTF8FromIdentifier(rpc_connection_t *connection) { + D(bug("handle_NPN_UTF8FromIdentifier\n")); + NPIdentifier ident; int error = rpc_method_get_args(connection, RPC_TYPE_NP_IDENTIFIER, &ident, @@ -1283,7 +1691,7 @@ static int handle_NPN_UTF8FromIdentifier(rpc_connection_t *connection) return error; } - NPUTF8 *str = mozilla_funcs.utf8fromidentifier(ident); + NPUTF8 *str = g_NPN_UTF8FromIdentifier(ident); error = rpc_method_send_reply(connection, RPC_TYPE_NP_UTF8, str, @@ -1296,8 +1704,19 @@ static int handle_NPN_UTF8FromIdentifier(rpc_connection_t *connection) } // NPN_IntFromIdentifier +static int32_t +g_NPN_IntFromIdentifier(NPIdentifier ident) +{ + D(bugiI("NPN_IntFromIdentifier ident=%p\n", ident)); + int32_t ret = CallNPN_IntFromIdentifierProc(mozilla_funcs.intfromidentifier, ident); + D(bugiD("NPN_IntFromIdentifier return: %d\n", ret)); + return ret; +} + static int handle_NPN_IntFromIdentifier(rpc_connection_t *connection) { + D(bug("handle_NPN_IntFromIdentifier\n")); + NPIdentifier ident; int error = rpc_method_get_args(connection, RPC_TYPE_NP_IDENTIFIER, &ident, @@ -1308,13 +1727,22 @@ static int handle_NPN_IntFromIdentifier(rpc_connection_t *connection) return error; } - int32_t ret = mozilla_funcs.intfromidentifier(ident); + int32_t ret = g_NPN_IntFromIdentifier(ident); return rpc_method_send_reply(connection, RPC_TYPE_INT32, ret, RPC_TYPE_INVALID); } +// NPN_ReleaseVariantValue +static void +g_NPN_ReleaseVariantValue(NPVariant *variant) +{ + D(bugiI("NPN_ReleaseVariantValue\n")); + NPN_ReleaseVariantValue(variant); + D(bugiD("NPN_ReleaseVariantValue done\n")); +} + /* ====================================================================== */ /* === Plug-in side data === */ @@ -1326,6 +1754,12 @@ invoke_NPP_New(PluginInstance *plugin, NPMIMEType mime_type, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) { + if (PLUGIN_DIRECT_EXEC) + return plugin_funcs.newp(mime_type, plugin->native_instance, mode, argc, argn, argv, saved); + + npw_return_val_if_fail(rpc_method_invoke_possible(plugin->connection), + NPERR_GENERIC_ERROR); + int error = rpc_method_invoke(plugin->connection, RPC_METHOD_NPP_NEW, RPC_TYPE_UINT32, plugin->instance_id, @@ -1363,24 +1797,27 @@ g_NPP_New(NPMIMEType mime_type, NPP instance, return NPERR_INVALID_INSTANCE_ERROR; // Check if we need to restart the plug-in - NPError ret = plugin_restart_if_needed(); + NPError ret = plugin_start_if_needed(); if (ret != NPERR_NO_ERROR) return ret; - - PluginInstance *plugin = malloc(sizeof(*plugin)); + + PluginInstance *plugin = npw_plugin_instance_new(&PluginInstanceClass); if (plugin == NULL) return NPERR_OUT_OF_MEMORY_ERROR; - memset(plugin, 0, sizeof(*plugin)); plugin->instance = instance; plugin->instance_id = id_create(plugin); - plugin->connection = g_rpc_connection; + plugin->connection = rpc_connection_ref(g_rpc_connection); instance->pdata = plugin; - rpc_connection_ref(plugin->connection); + if (PLUGIN_DIRECT_EXEC) { + if ((plugin->native_instance = NPW_MemNew0(NPP_t, 1)) == NULL) + return NPERR_OUT_OF_MEMORY_ERROR; + plugin->native_instance->ndata = instance->ndata; + } - D(bug("NPP_New instance=%p\n", instance)); + D(bugiI("NPP_New instance=%p\n", instance)); ret = invoke_NPP_New(plugin, mime_type, mode, argc, argn, argv, saved); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPP_New return: %d [%s]\n", ret, string_of_NPError(ret))); if (saved) { if (saved->buf) @@ -1395,9 +1832,15 @@ g_NPP_New(NPMIMEType mime_type, NPP instance, static NPError invoke_NPP_Destroy(PluginInstance *plugin, NPSavedData **save) { + if (PLUGIN_DIRECT_EXEC) + return plugin_funcs.destroy(plugin->native_instance, save); + + npw_return_val_if_fail(rpc_method_invoke_possible(plugin->connection), + NPERR_GENERIC_ERROR); + int error = rpc_method_invoke(plugin->connection, RPC_METHOD_NPP_DESTROY, - RPC_TYPE_NPP, plugin->instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { @@ -1433,19 +1876,31 @@ g_NPP_Destroy(NPP instance, NPSavedData **save) { if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); if (plugin == NULL) return NPERR_INVALID_INSTANCE_ERROR; - D(bug("NPP_Destroy instance=%p\n", instance)); + D(bugiI("NPP_Destroy instance=%p\n", instance)); NPError ret = invoke_NPP_Destroy(plugin, save); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPP_Destroy return: %d [%s]\n", ret, string_of_NPError(ret))); - rpc_connection_unref(plugin->connection); + if (PLUGIN_DIRECT_EXEC) { + if (plugin->native_instance) { + NPW_MemFree(plugin->native_instance); + plugin->native_instance = NULL; + } + } - id_remove(plugin->instance_id); - free(plugin); + /* Browser's NPP instance is no longer valid beyond this point. So, + let's just break the link to nspluginwrapper's PluginInstance now */ + plugin->instance = NULL; instance->pdata = NULL; + /* We don't reset instance_id here because we still need the NPP -> + PluginInstance mapping for incoming RPC. However, the important + thing is plugin->instance to be NULL */ + + npw_plugin_instance_unref(plugin); return ret; } @@ -1453,9 +1908,15 @@ g_NPP_Destroy(NPP instance, NPSavedData **save) static NPError invoke_NPP_SetWindow(PluginInstance *plugin, NPWindow *window) { + if (PLUGIN_DIRECT_EXEC) + return plugin_funcs.setwindow(plugin->native_instance, window); + + npw_return_val_if_fail(rpc_method_invoke_possible(plugin->connection), + NPERR_GENERIC_ERROR); + int error = rpc_method_invoke(plugin->connection, RPC_METHOD_NPP_SET_WINDOW, - RPC_TYPE_NPP, plugin->instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_WINDOW, window, RPC_TYPE_INVALID); @@ -1482,13 +1943,14 @@ g_NPP_SetWindow(NPP instance, NPWindow *window) { if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); if (plugin == NULL) return NPERR_INVALID_INSTANCE_ERROR; - D(bug("NPP_SetWindow instance=%p\n", instance)); + D(bugiI("NPP_SetWindow instance=%p\n", instance)); NPError ret = invoke_NPP_SetWindow(plugin, window); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPP_SetWindow return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } @@ -1496,9 +1958,15 @@ g_NPP_SetWindow(NPP instance, NPWindow *window) static NPError invoke_NPP_GetValue(PluginInstance *plugin, NPPVariable variable, void *value) { + if (PLUGIN_DIRECT_EXEC) + return plugin_funcs.getvalue(plugin->native_instance, variable, value); + + npw_return_val_if_fail(rpc_method_invoke_possible(plugin->connection), + NPERR_GENERIC_ERROR); + int error = rpc_method_invoke(plugin->connection, RPC_METHOD_NPP_GET_VALUE, - RPC_TYPE_NPP, plugin->instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_INT32, variable, RPC_TYPE_INVALID); @@ -1517,7 +1985,7 @@ invoke_NPP_GetValue(PluginInstance *plugin, NPPVariable variable, void *value) npw_perror("NPP_GetValue() wait for reply", error); ret = NPERR_GENERIC_ERROR; } - D(bug(" value: %s\n", str)); + D(bug("-> value: %s\n", str)); switch (variable) { case NPPVformValue: // this is a '\0'-terminated UTF-8 string data allocated by NPN_MemAlloc() @@ -1546,7 +2014,7 @@ invoke_NPP_GetValue(PluginInstance *plugin, NPPVariable variable, void *value) npw_perror("NPP_GetValue() wait for reply", error); ret = NPERR_GENERIC_ERROR; } - D(bug(" value: %d\n", n)); + D(bug("-> value: %d\n", n)); *((int *)value) = n; break; } @@ -1558,7 +2026,7 @@ invoke_NPP_GetValue(PluginInstance *plugin, NPPVariable variable, void *value) npw_perror("NPP_GetValue() wait for reply", error); ret = NPERR_GENERIC_ERROR; } - D(bug(" value: %s\n", b ? "true" : "false")); + D(bug("-> value: %s\n", b ? "true" : "false")); *((PRBool *)value) = b ? PR_TRUE : PR_FALSE; break; } @@ -1570,7 +2038,7 @@ invoke_NPP_GetValue(PluginInstance *plugin, NPPVariable variable, void *value) npw_perror("NPP_GetValue() wait for reply", error); ret = NPERR_GENERIC_ERROR; } - D(bug(" value: %p\n", npobj)); + D(bug("-> value: \n", npobj)); *((NPObject **)value) = npobj; break; } @@ -1584,6 +2052,7 @@ g_NPP_GetValue(NPP instance, NPPVariable variable, void *value) { if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); if (plugin == NULL) return NPERR_INVALID_INSTANCE_ERROR; @@ -1599,9 +2068,9 @@ g_NPP_GetValue(NPP instance, NPPVariable variable, void *value) return NPERR_INVALID_PARAM; } - D(bug("NPP_GetValue instance=%p, variable=%d\n", instance, variable)); + D(bugiI("NPP_GetValue instance=%p, variable=%d [%s]\n", instance, variable, string_of_NPPVariable(variable))); NPError ret = invoke_NPP_GetValue(plugin, variable, value); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPP_GetValue return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } @@ -1619,13 +2088,14 @@ g_NPP_SetValue(NPP instance, NPPVariable variable, void *value) { if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); if (plugin == NULL) return NPERR_INVALID_INSTANCE_ERROR; - D(bug("NPP_SetValue instance=%p, variable=%d\n", instance, variable)); + D(bugiI("NPP_SetValue instance=%p, variable=%d [%s]\n", instance, variable, string_of_NPPVariable(variable))); NPError ret = invoke_NPP_SetValue(plugin, variable, value); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPP_SetValue return: %d [%s]\n", ret, string_of_NPError(ret))); return NPERR_GENERIC_ERROR; } @@ -1633,9 +2103,16 @@ g_NPP_SetValue(NPP instance, NPPVariable variable, void *value) static void invoke_NPP_URLNotify(PluginInstance *plugin, const char *url, NPReason reason, void *notifyData) { + if (PLUGIN_DIRECT_EXEC) { + plugin_funcs.urlnotify(plugin->native_instance, url, reason, notifyData); + return; + } + + npw_return_if_fail(rpc_method_invoke_possible(plugin->connection)); + int error = rpc_method_invoke(plugin->connection, RPC_METHOD_NPP_URL_NOTIFY, - RPC_TYPE_NPP, plugin->instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_STRING, url, RPC_TYPE_INT32, reason, RPC_TYPE_NP_NOTIFY_DATA, notifyData, @@ -1657,22 +2134,29 @@ g_NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyData { if (instance == NULL) return; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); if (plugin == NULL) return; - D(bug("NPP_URLNotify instance=%p, url='%s', reason=%d, notifyData=%p\n", instance, url, reason, notifyData)); + D(bugiI("NPP_URLNotify instance=%p, url='%s', reason=%s, notifyData=%p\n", instance, url, string_of_NPReason(reason), notifyData)); invoke_NPP_URLNotify(plugin, url, reason, notifyData); - D(bug(" done\n")); + D(bugiD("NPP_URLNotify done\n")); } // Notifies a plug-in instance of a new data stream static NPError invoke_NPP_NewStream(PluginInstance *plugin, NPMIMEType type, NPStream *stream, NPBool seekable, uint16 *stype) { + if (PLUGIN_DIRECT_EXEC) + return plugin_funcs.newstream(plugin->native_instance, type, stream, seekable, stype); + + npw_return_val_if_fail(rpc_method_invoke_possible(plugin->connection), + NPERR_GENERIC_ERROR); + int error = rpc_method_invoke(plugin->connection, RPC_METHOD_NPP_NEW_STREAM, - RPC_TYPE_NPP, plugin->instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_STRING, type, RPC_TYPE_UINT32, ((StreamInstance *)stream->pdata)->stream_id, RPC_TYPE_STRING, stream->url, @@ -1710,22 +2194,25 @@ g_NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable { if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); if (plugin == NULL) return NPERR_INVALID_INSTANCE_ERROR; - StreamInstance *stream_pdata = malloc(sizeof(*stream_pdata)); - if (stream_pdata == NULL) - return NPERR_OUT_OF_MEMORY_ERROR; - memset(stream_pdata, 0, sizeof(*stream_pdata)); - stream_pdata->stream = stream; - stream_pdata->stream_id = id_create(stream_pdata); - stream_pdata->is_plugin_stream = 0; - stream->pdata = stream_pdata; + if (!PLUGIN_DIRECT_EXEC) { + StreamInstance *stream_pdata = malloc(sizeof(*stream_pdata)); + if (stream_pdata == NULL) + return NPERR_OUT_OF_MEMORY_ERROR; + memset(stream_pdata, 0, sizeof(*stream_pdata)); + stream_pdata->stream = stream; + stream_pdata->stream_id = id_create(stream_pdata); + stream_pdata->is_plugin_stream = 0; + stream->pdata = stream_pdata; + } - D(bug("NPP_NewStream instance=%p\n", instance)); + D(bugiI("NPP_NewStream instance=%p\n", instance)); NPError ret = invoke_NPP_NewStream(plugin, type, stream, seekable, stype); - D(bug(" return: %d [%s], stype=%s\n", ret, string_of_NPError(ret), string_of_NPStreamType(*stype))); + D(bugiD("NPP_NewStream return: %d [%s], stype=%s\n", ret, string_of_NPError(ret), string_of_NPStreamType(*stype))); return ret; } @@ -1733,9 +2220,15 @@ g_NPP_NewStream(NPP instance, NPMIMEType type, NPStream *stream, NPBool seekable static NPError invoke_NPP_DestroyStream(PluginInstance *plugin, NPStream *stream, NPReason reason) { + if (PLUGIN_DIRECT_EXEC) + return plugin_funcs.destroystream(plugin->native_instance, stream, reason); + + npw_return_val_if_fail(rpc_method_invoke_possible(plugin->connection), + NPERR_GENERIC_ERROR); + int error = rpc_method_invoke(plugin->connection, RPC_METHOD_NPP_DESTROY_STREAM, - RPC_TYPE_NPP, plugin->instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_STREAM, stream, RPC_TYPE_INT32, reason, RPC_TYPE_INVALID); @@ -1763,19 +2256,22 @@ g_NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) { if (instance == NULL) return NPERR_INVALID_INSTANCE_ERROR; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); if (plugin == NULL) return NPERR_INVALID_INSTANCE_ERROR; - D(bug("NPP_DestroyStream instance=%p\n", instance)); + D(bugiI("NPP_DestroyStream instance=%p\n", instance)); NPError ret = invoke_NPP_DestroyStream(plugin, stream, reason); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); + D(bugiD("NPP_DestroyStream return: %d [%s]\n", ret, string_of_NPError(ret))); - StreamInstance *stream_pdata = stream->pdata; - if (stream_pdata) { - id_remove(stream_pdata->stream_id); - free(stream->pdata); - stream->pdata = NULL; + if (!PLUGIN_DIRECT_EXEC) { + StreamInstance *stream_pdata = stream->pdata; + if (stream_pdata) { + id_remove(stream_pdata->stream_id); + free(stream->pdata); + stream->pdata = NULL; + } } return ret; @@ -1785,9 +2281,16 @@ g_NPP_DestroyStream(NPP instance, NPStream *stream, NPReason reason) static void invoke_NPP_StreamAsFile(PluginInstance *plugin, NPStream *stream, const char *fname) { + if (PLUGIN_DIRECT_EXEC) { + plugin_funcs.asfile(plugin->native_instance, stream, fname); + return; + } + + npw_return_if_fail(rpc_method_invoke_possible(plugin->connection)); + int error = rpc_method_invoke(plugin->connection, RPC_METHOD_NPP_STREAM_AS_FILE, - RPC_TYPE_NPP, plugin->instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_STREAM, stream, RPC_TYPE_STRING, fname, RPC_TYPE_INVALID); @@ -1808,22 +2311,29 @@ g_NPP_StreamAsFile(NPP instance, NPStream *stream, const char *fname) { if (instance == NULL) return; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); if (plugin == NULL) return; - D(bug("NPP_StreamAsFile instance=%p\n", instance)); + D(bugiI("NPP_StreamAsFile instance=%p\n", instance)); invoke_NPP_StreamAsFile(plugin, stream, fname); - D(bug(" done\n")); + D(bugiD("NPP_StreamAsFile done\n")); } // Determines maximum number of bytes that the plug-in can consume static int32 invoke_NPP_WriteReady(PluginInstance *plugin, NPStream *stream) { + if (PLUGIN_DIRECT_EXEC) + return plugin_funcs.writeready(plugin->native_instance, stream); + + npw_return_val_if_fail(rpc_method_invoke_possible(plugin->connection), + NPERR_STREAM_BUFSIZ); + int error = rpc_method_invoke(plugin->connection, RPC_METHOD_NPP_WRITE_READY, - RPC_TYPE_NPP, plugin->instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_STREAM, stream, RPC_TYPE_INVALID); @@ -1850,13 +2360,14 @@ g_NPP_WriteReady(NPP instance, NPStream *stream) { if (instance == NULL) return 0; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); if (plugin == NULL) return 0; - D(bug("NPP_WriteReady instance=%p\n", instance)); + D(bugiI("NPP_WriteReady instance=%p\n", instance)); int32 ret = invoke_NPP_WriteReady(plugin, stream); - D(bug(" return: %d\n", ret)); + D(bugiD("NPP_WriteReady return: %d\n", ret)); return ret; } @@ -1865,9 +2376,14 @@ g_NPP_WriteReady(NPP instance, NPStream *stream) static int32 invoke_NPP_Write(PluginInstance *plugin, NPStream *stream, int32 offset, int32 len, void *buf) { + if (PLUGIN_DIRECT_EXEC) + return plugin_funcs.write(plugin->native_instance, stream, offset, len, buf); + + npw_return_val_if_fail(rpc_method_invoke_possible(plugin->connection), -1); + int error = rpc_method_invoke(plugin->connection, RPC_METHOD_NPP_WRITE, - RPC_TYPE_NPP, plugin->instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_STREAM, stream, RPC_TYPE_INT32, offset, RPC_TYPE_ARRAY, RPC_TYPE_CHAR, len, buf, @@ -1896,6 +2412,7 @@ g_NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buf) { if (instance == NULL) return -1; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); if (plugin == NULL) return -1; @@ -1907,17 +2424,20 @@ g_NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buf) * Google Chrome) send data through NPP_Write() anyway. Others * (Firefox, WebKit) actually suspend the stream temporarily. * - * Note that returning -1 here will destroy the stream. This is - * compatible with the expected behaviour. e.g. the DiamondX test - * plugin wants that. Is there any other "real" plugin in that case - * too? + * Note that we could also return -1 here to destroy the stream + * right away. However, some plugins may want to handle that case + * themselves. i.e. it's not our role to idealize the plugin + * intents, we are just a "passthrough". On the other hand, the only + * useful way to handle that case is to range check the arguments + * and return -1. Is there a "real" plugin that wants to do more + * than that (except an explicit NPN_DestroyStream())? */ - if (len < 0) - return -1; + if (len <= 0) + buf = NULL; - D(bug("NPP_Write instance=%p\n", instance)); + D(bugiI("NPP_Write instance=%p\n", instance)); int32 ret = invoke_NPP_Write(plugin, stream, offset, len, buf); - D(bug(" return: %d\n", ret)); + D(bugiD("NPP_Write return: %d\n", ret)); return ret; } @@ -1925,6 +2445,11 @@ g_NPP_Write(NPP instance, NPStream *stream, int32 offset, int32 len, void *buf) // Requests a platform-specific print operation for an embedded or full-screen plug-in static void invoke_NPP_Print(PluginInstance *plugin, NPPrint *PrintInfo) { + if (PLUGIN_DIRECT_EXEC) { + plugin_funcs.print(plugin->native_instance, PrintInfo); + return; + } + NPPrintCallbackStruct *platformPrint; switch (PrintInfo->mode) { case NP_FULL: @@ -1942,9 +2467,11 @@ static void invoke_NPP_Print(PluginInstance *plugin, NPPrint *PrintInfo) platform_print_id = id_create(platformPrint); D(bug(" platformPrint=%p\n", platformPrint)); + npw_return_if_fail(rpc_method_invoke_possible(plugin->connection)); + int error = rpc_method_invoke(plugin->connection, RPC_METHOD_NPP_PRINT, - RPC_TYPE_NPP, plugin->instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_UINT32, platform_print_id, RPC_TYPE_NP_PRINT, PrintInfo, RPC_TYPE_INVALID); @@ -1976,6 +2503,7 @@ static void g_NPP_Print(NPP instance, NPPrint *PrintInfo) { if (instance == NULL) return; + PluginInstance *plugin = PLUGIN_INSTANCE(instance); if (plugin == NULL) return; @@ -1983,23 +2511,28 @@ static void g_NPP_Print(NPP instance, NPPrint *PrintInfo) if (PrintInfo == NULL) return; - D(bug("NPP_Print instance=%p\n", instance)); + D(bugiI("NPP_Print instance=%p\n", instance)); invoke_NPP_Print(plugin, PrintInfo); - D(bug(" done\n")); + D(bugiD("NPP_Print done\n")); } // Delivers a platform-specific window event to the instance static int16 invoke_NPP_HandleEvent(PluginInstance *plugin, void *event) { + if (PLUGIN_DIRECT_EXEC) + return plugin_funcs.event(plugin->native_instance, event); + + npw_return_val_if_fail(rpc_method_invoke_possible(plugin->connection), false); + int error = rpc_method_invoke(plugin->connection, RPC_METHOD_NPP_HANDLE_EVENT, - RPC_TYPE_NPP, plugin->instance, + RPC_TYPE_NPW_PLUGIN_INSTANCE, plugin, RPC_TYPE_NP_EVENT, event, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { npw_perror("NPP_HandleEvent() invoke", error); - return NPERR_GENERIC_ERROR; + return false; } int32_t ret; @@ -2009,7 +2542,7 @@ static int16 invoke_NPP_HandleEvent(PluginInstance *plugin, void *event) if (error != RPC_ERROR_NO_ERROR) { npw_perror("NPP_HandleEvent() wait for reply", error); - return NPERR_GENERIC_ERROR; + return false; } return ret; @@ -2030,23 +2563,24 @@ static int16 g_NPP_HandleEvent(NPP instance, void *event) toolkit_flush(); } - D(bug("NPP_HandleEvent instance=%p\n", instance)); + D(bugiI("NPP_HandleEvent instance=%p\n", instance)); int16 ret = invoke_NPP_HandleEvent(plugin, event); - D(bug(" return: %d\n", ret)); + D(bugiD("NPP_HandleEvent return: %d\n", ret)); return ret; } // Allows the browser to query the plug-in for information -NPError -NP_GetValue(void *future, NPPVariable variable, void *value) +static NPError +g_NP_GetValue(void *future, NPPVariable variable, void *value) { - D(bug("NP_GetValue variable=%d\n", variable)); - if (g_plugin.initialized == 0) plugin_init(0); if (g_plugin.initialized <= 0) return NPERR_GENERIC_ERROR; + if (PLUGIN_DIRECT_EXEC) + return g_plugin_NP_GetValue(future, variable, value); + char *str = NULL; int ret = NPERR_GENERIC_ERROR; switch (variable) { @@ -2079,28 +2613,45 @@ NP_GetValue(void *future, NPPVariable variable, void *value) } *((char **)value) = str; - D(bug(" return: %d ['%s']\n", ret, str)); + return ret; +} + +NPError +NP_GetValue(void *future, NPPVariable variable, void *value) +{ + D(bugiI("NP_GetValue variable=%d [%s]\n", variable, string_of_NPPVariable(variable))); + NPError ret = g_NP_GetValue(future, variable, value); + D(bugiD("NP_GetValue return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } // Allows the browser to query the plug-in supported formats -char * -NP_GetMIMEDescription(void) +static char * +g_NP_GetMIMEDescription(void) { - D(bug("NP_GetMIMEDescription\n")); - if (g_plugin.initialized == 0) plugin_init(0); if (g_plugin.initialized <= 0) return NULL; + if (PLUGIN_DIRECT_EXEC) + return g_plugin_NP_GetMIMEDescription(); + if (g_plugin.is_wrapper) return "unknown/mime-type:none:Do not open"; - D(bug(" formats: '%s'\n", g_plugin.formats)); return g_plugin.formats; } +char * +NP_GetMIMEDescription(void) +{ + D(bugiI("NP_GetMIMEDescription\n")); + char *formats = g_NP_GetMIMEDescription(); + D(bugiD("NP_GetMIMEDescription return: '%s'\n", formats)); + return formats; +} + /* ====================================================================== */ /* === LONG64 NPAPI support === */ @@ -2541,6 +3092,61 @@ static bool is_konqueror(void) static NPError invoke_NP_Initialize(uint32_t npapi_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 = NewNPN_GetURLProc(g_NPN_GetURL); + mozilla_funcs.posturl = NewNPN_PostURLProc(g_NPN_PostURL); + mozilla_funcs.requestread = NewNPN_RequestReadProc(g_NPN_RequestRead); + mozilla_funcs.newstream = NewNPN_NewStreamProc(g_NPN_NewStream); + mozilla_funcs.write = NewNPN_WriteProc(g_NPN_Write); + mozilla_funcs.destroystream = NewNPN_DestroyStreamProc(g_NPN_DestroyStream); + mozilla_funcs.status = NewNPN_StatusProc(g_NPN_Status); + mozilla_funcs.uagent = NewNPN_UserAgentProc(g_NPN_UserAgent); + mozilla_funcs.memalloc = NewNPN_MemAllocProc(g_NPN_MemAlloc); + mozilla_funcs.memfree = NewNPN_MemFreeProc(g_NPN_MemFree); + mozilla_funcs.memflush = NewNPN_MemFlushProc(g_NPN_MemFlush); + mozilla_funcs.reloadplugins = NewNPN_ReloadPluginsProc(g_NPN_ReloadPlugins); + mozilla_funcs.getJavaEnv = NewNPN_GetJavaEnvProc(g_NPN_GetJavaEnv); + mozilla_funcs.getJavaPeer = NewNPN_GetJavaPeerProc(g_NPN_GetJavaPeer); + mozilla_funcs.geturlnotify = NewNPN_GetURLNotifyProc(g_NPN_GetURLNotify); + mozilla_funcs.posturlnotify = NewNPN_PostURLNotifyProc(g_NPN_PostURLNotify); + mozilla_funcs.getvalue = NewNPN_GetValueProc(g_NPN_GetValue); + mozilla_funcs.setvalue = NewNPN_SetValueProc(g_NPN_SetValue); + mozilla_funcs.invalidaterect = NewNPN_InvalidateRectProc(g_NPN_InvalidateRect); + mozilla_funcs.invalidateregion = NewNPN_InvalidateRegionProc(g_NPN_InvalidateRegion); + mozilla_funcs.forceredraw = NewNPN_ForceRedrawProc(g_NPN_ForceRedraw); + mozilla_funcs.pushpopupsenabledstate = NewNPN_PushPopupsEnabledStateProc(g_NPN_PushPopupsEnabledState); + mozilla_funcs.poppopupsenabledstate = NewNPN_PopPopupsEnabledStateProc(g_NPN_PopPopupsEnabledState); + if ((npapi_version & 0xff) >= NPVERS_HAS_NPRUNTIME_SCRIPTING) { + mozilla_funcs.getstringidentifier = NewNPN_GetStringIdentifierProc(g_NPN_GetStringIdentifier); + mozilla_funcs.getstringidentifiers = NewNPN_GetStringIdentifiersProc(g_NPN_GetStringIdentifiers); + mozilla_funcs.getintidentifier = NewNPN_GetIntIdentifierProc(g_NPN_GetIntIdentifier); + mozilla_funcs.identifierisstring = NewNPN_IdentifierIsStringProc(g_NPN_IdentifierIsString); + mozilla_funcs.utf8fromidentifier = NewNPN_UTF8FromIdentifierProc(g_NPN_UTF8FromIdentifier); + mozilla_funcs.intfromidentifier = NewNPN_IntFromIdentifierProc(g_NPN_IntFromIdentifier); + mozilla_funcs.createobject = NewNPN_CreateObjectProc(g_NPN_CreateObject); + mozilla_funcs.retainobject = NewNPN_RetainObjectProc(g_NPN_RetainObject); + mozilla_funcs.releaseobject = NewNPN_ReleaseObjectProc(g_NPN_ReleaseObject); + mozilla_funcs.invoke = NewNPN_InvokeProc(g_NPN_Invoke); + mozilla_funcs.invokeDefault = NewNPN_InvokeDefaultProc(g_NPN_InvokeDefault); + mozilla_funcs.evaluate = NewNPN_EvaluateProc(g_NPN_Evaluate); + mozilla_funcs.getproperty = NewNPN_GetPropertyProc(g_NPN_GetProperty); + mozilla_funcs.setproperty = NewNPN_SetPropertyProc(g_NPN_SetProperty); + mozilla_funcs.removeproperty = NewNPN_RemovePropertyProc(g_NPN_RemoveProperty); + mozilla_funcs.hasproperty = NewNPN_HasPropertyProc(g_NPN_HasProperty); + mozilla_funcs.hasmethod = NewNPN_HasMethodProc(g_NPN_HasMethod); + mozilla_funcs.releasevariantvalue = NewNPN_ReleaseVariantValueProc(g_NPN_ReleaseVariantValue); + mozilla_funcs.setexception = NewNPN_SetExceptionProc(g_NPN_SetException); + } + return g_plugin_NP_Initialize(&mozilla_funcs, &plugin_funcs); + } + + npw_return_val_if_fail(rpc_method_invoke_possible(g_rpc_connection), + NPERR_MODULE_LOAD_FAILED_ERROR); + int error = rpc_method_invoke(g_rpc_connection, RPC_METHOD_NP_INITIALIZE, RPC_TYPE_UINT32, npapi_version, @@ -2562,6 +3168,15 @@ invoke_NP_Initialize(uint32_t npapi_version) return ret; } +static NPError +g_NP_Initialize(uint32_t npapi_version) +{ + D(bugiI("NP_Initialize\n")); + NPError ret = invoke_NP_Initialize(npapi_version); + D(bugiD("NP_Initialize return: %d [%s]\n", ret, string_of_NPError(ret))); + return ret; +} + NPError NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs) { @@ -2625,22 +3240,31 @@ NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs) if (g_plugin.initialized <= 0) return NPERR_MODULE_LOAD_FAILED_ERROR; + if (!id_init()) + return NPERR_MODULE_LOAD_FAILED_ERROR; + if (!npobject_bridge_new()) return NPERR_MODULE_LOAD_FAILED_ERROR; // pass down common NPAPI version supported by both the underlying // browser and the thunking capabilities of nspluginwrapper npapi_version = MIN(moz_funcs->version, plugin_funcs->version); - - NPError ret = invoke_NP_Initialize(npapi_version); - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); - return ret; + return g_NP_Initialize(npapi_version); } // Provides global deinitialization for a plug-in static NPError invoke_NP_Shutdown(void) { + if (PLUGIN_DIRECT_EXEC) + return g_plugin_NP_Shutdown(); + + if (g_rpc_connection == NULL) + return NPERR_NO_ERROR; + + 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_NP_SHUTDOWN, RPC_TYPE_INVALID); if (error != RPC_ERROR_NO_ERROR) { npw_perror("NP_Shutdown() invoke", error); @@ -2654,7 +3278,18 @@ invoke_NP_Shutdown(void) return NPERR_GENERIC_ERROR; } - npobject_bridge_destroy(); + return ret; +} + +static NPError +g_NP_Shutdown(void) +{ + D(bugiI("NP_Shutdown\n")); + NPError ret = invoke_NP_Shutdown(); + D(bugiD("NP_Shutdown return: %d [%s]\n", ret, string_of_NPError(ret))); + + if (!g_plugin.is_wrapper) + plugin_exit(); return ret; } @@ -2662,17 +3297,12 @@ invoke_NP_Shutdown(void) NPError NP_Shutdown(void) { - D(bug("NP_Shutdown\n")); + NPError ret = g_NP_Shutdown(); - int32_t ret = NPERR_NO_ERROR; + npobject_bridge_destroy(); - if (g_rpc_connection) - ret = invoke_NP_Shutdown(); + id_kill(); - if (!g_plugin.is_wrapper) - plugin_exit(); - - D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } @@ -2690,6 +3320,11 @@ static void plugin_init(int is_NP_Initialize) return; } + if (PLUGIN_DIRECT_EXEC){ + g_plugin.initialized = 1; + return; + } + static const char *plugin_file_name = NULL; if (plugin_file_name == NULL) { const char *p; @@ -2771,6 +3406,8 @@ static void plugin_init(int is_NP_Initialize) argv[argc++] = connection_path; argv[argc] = NULL; + npw_close_all_open_files(); + execv(viewer_path, argv); npw_printf("ERROR: failed to execute NSPlugin viewer\n"); _Exit(255); @@ -2853,7 +3490,7 @@ static void plugin_init(int is_NP_Initialize) }; g_rpc_source = g_source_new(&rpc_event_funcs, sizeof(GSource)); if (g_rpc_source) { - g_source_set_priority(g_rpc_source, G_PRIORITY_DEFAULT); + g_source_set_priority(g_rpc_source, G_PRIORITY_LOW); g_source_set_callback(g_rpc_source, (GSourceFunc)rpc_dispatch, g_rpc_connection, NULL); g_source_attach(g_rpc_source, NULL); g_rpc_poll_fd.fd = rpc_socket(g_rpc_connection); @@ -2885,10 +3522,8 @@ static void plugin_init(int is_NP_Initialize) return; } - if (!id_init()) { - npw_printf("ERROR: failed to allocate ID hash table\n"); - return; - } + // Set error handler - stop plugin if there's a connection error + rpc_connection_set_error_callback(g_rpc_connection, plugin_kill_cb, NULL); g_plugin.initialized = 1 + is_NP_Initialize; D(bug("--- INIT ---\n")); @@ -2937,8 +3572,6 @@ static void plugin_exit(void) g_plugin.viewer_pid = -1; } - id_kill(); - g_plugin.initialized = 0; } @@ -2946,6 +3579,11 @@ static void __attribute__((destructor)) plugin_exit_sentinel(void) { plugin_exit(); + if (plugin_handle) { + dlclose(plugin_handle); + plugin_handle = NULL; + } + if (g_plugin.formats) { free(g_plugin.formats); g_plugin.formats = NULL; @@ -2962,27 +3600,59 @@ static void __attribute__((destructor)) plugin_exit_sentinel(void) } } -static NPError plugin_restart(void) +static void plugin_kill(void) { if (g_plugin.is_wrapper) - return NPERR_NO_ERROR; + return; - // Shut it down + // Kill viewer and plugin plugin_exit(); + + // Clear-up g_plugin.initialized = 0; g_plugin.viewer_pid = -1; g_plugin.is_wrapper = 0; + npruntime_deactivate(); + + // Set the kill flag + plugin_killed = 1; +} + +static void plugin_kill_cb(rpc_connection_t *connection, void *user_data) +{ + D(bug("plugin_kill, connection %p\n", connection)); + + // Don't kill the plugin again through another instance + rpc_connection_set_error_callback(connection, NULL, NULL); + + plugin_kill(); +} + +static NPError plugin_start(void) +{ + D(bug("plugin_start\n")); + + if (!plugin_killed) { + // Plugin is still active, terminate it before the restart + D(bug("plugin_start: plugin_killed == 0!\n")); + plugin_kill(); + } + plugin_killed = 0; + // And start it again plugin_init(1); if (g_plugin.initialized <= 0) return NPERR_MODULE_LOAD_FAILED_ERROR; - return invoke_NP_Initialize(npapi_version); + return g_NP_Initialize(npapi_version); } -static NPError plugin_restart_if_needed(void) +static NPError plugin_start_if_needed(void) { + if (PLUGIN_DIRECT_EXEC) + return NPERR_NO_ERROR; + if (rpc_status(g_rpc_connection) != RPC_STATUS_ACTIVE) { static time_t last_restart = 0; time_t now = time(NULL); @@ -2991,7 +3661,7 @@ static NPError plugin_restart_if_needed(void) last_restart = now; D(bug("Restart plugins viewer\n")); - NPError ret = plugin_restart(); + NPError ret = plugin_start(); D(bug(" return: %d [%s]\n", ret, string_of_NPError(ret))); return ret; } diff --git a/src/rpc.c b/src/rpc.c index e769a34..6f28a4c 100644 --- a/src/rpc.c +++ b/src/rpc.c @@ -74,6 +74,11 @@ #define RPC_INIT_TIMEOUT 5 #endif +// Set close-on-exec flag on the newly created socket (Linux >= 2.6.27) +#ifndef SOCK_CLOEXEC +#define SOCK_CLOEXEC 0 +#endif + /* ====================================================================== */ /* === Utility functions === */ @@ -255,6 +260,9 @@ const char *rpc_strerror(int error) case RPC_ERROR_MESSAGE_ARGUMENT_INVALID: str = "Message argument invalid"; break; + case RPC_ERROR_MESSAGE_SYNC_NOT_ALLOWED: + str = "SYNC message forbidden"; + break; default: str = ""; break; @@ -456,6 +464,13 @@ struct rpc_connection { pthread_t server_thread; rpc_map_t *types; rpc_map_t *methods; + rpc_error_callback_t error_callback; + void *error_callback_data; + int dispatch_depth; + int invoke_depth; + int handle_depth; + int sync_depth; + int pending_sync_depth; }; // Increment connection reference count @@ -475,6 +490,55 @@ 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) +{ + return connection->type == RPC_CONNECTION_SERVER; +} + +// Returns whether we are "synchronized" with the other end +static inline bool _rpc_connection_is_sync(rpc_connection_t *connection) +{ + if (connection->dispatch_depth < 1) + return false; + return connection->dispatch_depth == connection->handle_depth; +} + +// Returns whether we are allowed to synchronize with the other end +static inline bool _rpc_connection_is_sync_allowed(rpc_connection_t *connection) +{ + if (_rpc_connection_is_sync_mode(connection)) { + npw_printf("ERROR: RPC is not allowed to receive MESSAGE_SYNC\n"); + return false; + } + return connection->pending_sync_depth == 0; +} + +// Set error callback for a connection +void rpc_connection_set_error_callback(rpc_connection_t *connection, + rpc_error_callback_t callback, + void *callback_data) +{ + if (connection == NULL) + return; + if (connection->error_callback != NULL) + return; + connection->error_callback = callback; + connection->error_callback_data = callback_data; +} + +// Call error callback if the connection is closed +static inline void _rpc_connection_invoke_error_callback(rpc_connection_t *connection) +{ + connection->error_callback(connection, connection->error_callback_data); +} + +static inline void rpc_connection_invoke_error_callback(rpc_connection_t *connection) +{ + if (connection && connection->error_callback) + _rpc_connection_invoke_error_callback(connection); +} + // Returns connection status static inline int _rpc_status(rpc_connection_t *connection) { @@ -506,13 +570,27 @@ static void _rpc_set_status(rpc_connection_t *connection, int error) } } -static inline int rpc_error(rpc_connection_t *connection, int error) +// Set error status. The caller must return after a call to this function +// e.g. the usual practise is to "return rpc_error();" +// This is necessary because the error callback can decide to kill the +// RPC connection in that case, so anything beyond rpc_error() should +// be considered garbage. +static int rpc_error(rpc_connection_t *connection, int error) { // XXX: this function must be called only in case of error - // (otherwise, it's an internal error) + // (otherwise, it's an internal error, hence the assert()s) assert(error < 0); assert(connection != NULL); _rpc_set_status(connection, error); + + switch (_rpc_status(connection)) { + case RPC_STATUS_CLOSED: + case RPC_STATUS_BROKEN: + rpc_connection_invoke_error_callback(connection); + break; + default: + break; + } return error; } @@ -605,6 +683,13 @@ rpc_connection_t *rpc_init_server(const char *ident) connection->status = RPC_STATUS_CLOSED; connection->socket = -1; connection->server_thread_active = 0; + connection->error_callback = NULL; + connection->error_callback_data = NULL; + connection->dispatch_depth = 0; + connection->invoke_depth = 0; + connection->handle_depth = 0; + connection->sync_depth = 0; + connection->pending_sync_depth = 0; if ((connection->types = rpc_map_new_full((free))) == NULL) { rpc_exit(connection); return NULL; @@ -614,7 +699,7 @@ rpc_connection_t *rpc_init_server(const char *ident) return NULL; } - if ((connection->server_socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + if ((connection->server_socket = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0)) < 0) { perror("server socket"); rpc_exit(connection); return NULL; @@ -665,6 +750,13 @@ rpc_connection_t *rpc_init_client(const char *ident) connection->refcnt = 1; connection->status = RPC_STATUS_CLOSED; connection->server_socket = -1; + connection->error_callback = NULL; + connection->error_callback_data = NULL; + connection->dispatch_depth = 0; + connection->invoke_depth = 0; + connection->handle_depth = 0; + connection->sync_depth = 0; + connection->pending_sync_depth = 0; if ((connection->types = rpc_map_new_full((free))) == NULL) { rpc_exit(connection); return NULL; @@ -674,7 +766,7 @@ rpc_connection_t *rpc_init_client(const char *ident) return NULL; } - if ((connection->socket = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + if ((connection->socket = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0)) < 0) { perror("client socket"); rpc_exit(connection); return NULL; @@ -862,6 +954,9 @@ enum { RPC_MESSAGE_ACK = -3003, RPC_MESSAGE_REPLY = -3004, RPC_MESSAGE_FAILURE = -3005, + RPC_MESSAGE_SYNC = -3006, + RPC_MESSAGE_SYNC_END = -3007, + RPC_MESSAGE_SYNC_ACK = -3008, }; // Message type @@ -1088,20 +1183,26 @@ static int rpc_message_send_args(rpc_message_t *message, va_list args) case RPC_TYPE_ARRAY: { int i; int array_type = va_arg(args, int32_t); - int array_size = va_arg(args, uint32_t); + unsigned int array_size = va_arg(args, uint32_t); + void *array_arg = va_arg(args, void *); + bool is_valid_array = array_size > 0 && array_arg != NULL; if ((error = rpc_message_send_int32(message, array_type)) < 0) return error; if ((error = rpc_message_send_uint32(message, array_size)) < 0) return error; + if ((error = rpc_message_send_char(message, is_valid_array)) < 0) + return error; + if (!is_valid_array) + break; switch (array_type) { case RPC_TYPE_CHAR: { - unsigned char *array = va_arg(args, unsigned char *); + unsigned char *array = (unsigned char *)array_arg; error = rpc_message_send_bytes(message, array, array_size); break; } case RPC_TYPE_BOOLEAN: case RPC_TYPE_INT32: { - int32_t *array = va_arg(args, int32_t *); + int32_t *array = (int32_t *)array_arg; for (i = 0; i < array_size; i++) { if ((error = rpc_message_send_int32(message, array[i])) < 0) break; @@ -1109,15 +1210,31 @@ static int rpc_message_send_args(rpc_message_t *message, va_list args) break; } case RPC_TYPE_UINT32: { - uint32_t *array = va_arg(args, uint32_t *); + uint32_t *array = (uint32_t *)array_arg; for (i = 0; i < array_size; i++) { if ((error = rpc_message_send_uint32(message, array[i])) < 0) break; } break; } + case RPC_TYPE_UINT64: { + uint64_t *array = (uint64_t *)array_arg; + for (i = 0; i < array_size; i++) { + if ((error = rpc_message_send_uint64(message, array[i])) < 0) + break; + } + break; + } + case RPC_TYPE_DOUBLE: { + double *array = (double *)array_arg; + for (i = 0; i < array_size; i++) { + if ((error = rpc_message_send_double(message, array[i])) < 0) + break; + } + break; + } case RPC_TYPE_STRING: { - char **array = va_arg(args, char **); + char **array = (char **)array_arg; for (i = 0; i < array_size; i++) { if ((error = rpc_message_send_string(message, array[i])) < 0) break; @@ -1127,7 +1244,7 @@ static int rpc_message_send_args(rpc_message_t *message, va_list args) default: if ((desc = rpc_message_descriptor_lookup(message, array_type)) != NULL) { // arguments are passed by value (XXX: needs a way to differenciate reference/value) - uint8_t *array = va_arg(args, uint8_t *); + uint8_t *array = (uint8_t *)array_arg; for (i = 0; i < array_size; i++) { if ((error = desc->send_callback(message, &array[i * desc->size])) < 0) break; @@ -1342,13 +1459,21 @@ static int rpc_message_recv_args(rpc_message_t *message, va_list args) int i; int32_t array_type; uint32_t array_size; + char is_valid_array; if ((error = rpc_message_recv_int32(message, &array_type)) < 0) return error; if ((error = rpc_message_recv_uint32(message, &array_size)) < 0) return error; + if ((error = rpc_message_recv_char(message, &is_valid_array)) < 0) + return error; p_value = va_arg(args, void *); - *((uint32_t *)p_value) = array_size; + *((int32_t *)p_value) = array_size; p_value = va_arg(args, void *); + if (!is_valid_array) { + *((void **)p_value) = NULL; + break; + } + assert(array_size > 0); // otherwise, it's an internal error, see send() switch (array_type) { case RPC_TYPE_CHAR: { unsigned char *array; @@ -1375,8 +1500,8 @@ static int rpc_message_recv_args(rpc_message_t *message, va_list args) break; } case RPC_TYPE_UINT32: { - unsigned int *array; - if ((array = (unsigned int *)malloc(array_size * sizeof(*array))) == NULL) + uint32_t *array; + if ((array = (uint32_t *)malloc(array_size * sizeof(*array))) == NULL) return RPC_ERROR_NO_MEMORY; for (i = 0; i < array_size; i++) { uint32_t value; @@ -1387,6 +1512,32 @@ static int rpc_message_recv_args(rpc_message_t *message, va_list args) *((void **)p_value) = (void *)array; break; } + case RPC_TYPE_UINT64: { + uint64_t *array; + if ((array = (uint64_t *)malloc(array_size * sizeof(*array))) == NULL) + return RPC_ERROR_NO_MEMORY; + for (i = 0; i < array_size; i++) { + uint64_t value; + if ((error = rpc_message_recv_uint64(message, &value)) < 0) + return error; + array[i] = value; + } + *((void **)p_value) = (void *)array; + break; + } + case RPC_TYPE_DOUBLE: { + double *array; + if ((array = (double *)malloc(array_size * sizeof(*array))) == NULL) + return RPC_ERROR_NO_MEMORY; + for (i = 0; i < array_size; i++) { + double value; + if ((error = rpc_message_recv_double(message, &value)) < 0) + return error; + array[i] = value; + } + *((void **)p_value) = (void *)array; + break; + } case RPC_TYPE_STRING: { char **array; if ((array = (char **)malloc(array_size * sizeof(*array))) == NULL) @@ -1484,7 +1635,7 @@ static inline rpc_method_callback_t rpc_lookup_callback(rpc_connection_t *connec } // Dispatch message received in the server loop -static int _rpc_dispatch(rpc_connection_t *connection, rpc_message_t *message) +static int _rpc_dispatch_1(rpc_connection_t *connection, rpc_message_t *message) { // recv: (body: MESSAGE_END D(bug("receiving message\n")); @@ -1531,6 +1682,62 @@ static int _rpc_dispatch(rpc_connection_t *connection, rpc_message_t *message) return method; } +static int _rpc_dispatch(rpc_connection_t *connection, rpc_message_t *message) +{ + ++connection->dispatch_depth; + int ret = _rpc_dispatch_1(connection, message); + --connection->dispatch_depth; + return ret; +} + +// Dispatch pending remote calls until we get MSG_TAG +static int _rpc_dispatch_until(rpc_connection_t *connection, rpc_message_t *message, int32_t expected_msg_tag) +{ + assert(expected_msg_tag != 0); + for (;;) { + int32_t msg_tag; + int error = rpc_message_recv_int32(message, &msg_tag); + if (error != RPC_ERROR_NO_ERROR) + return error; + if (msg_tag == expected_msg_tag) + break; + switch (msg_tag) { + case RPC_MESSAGE_SYNC: + if (!_rpc_connection_is_sync_allowed(connection)) + return RPC_ERROR_MESSAGE_SYNC_NOT_ALLOWED; + connection->pending_sync_depth = connection->invoke_depth; + break; + case RPC_MESSAGE_START: + if ((error = _rpc_dispatch(connection, message)) < 0) + return error; + break; + default: + return RPC_ERROR_MESSAGE_TYPE_INVALID; + } + } + return RPC_ERROR_NO_ERROR; +} + +// Dispatch pending remote calls in SYNC mode (i.e. until MESSAGE_SYNC_END) +static int _rpc_dispatch_sync(rpc_connection_t *connection) +{ + rpc_message_t message; + rpc_message_init(&message, connection); + + // send: MESSAGE_SYNC_ACK + int error = rpc_message_send_int32(&message, RPC_MESSAGE_SYNC_ACK); + if (error != RPC_ERROR_NO_ERROR) + return error; + error = rpc_message_flush(&message); + if (error != RPC_ERROR_NO_ERROR) + return error; + + // call: rpc_dispatch() (pending remote calls) + // recv: MESSAGE_SYNC_END + return _rpc_dispatch_until(connection, &message, RPC_MESSAGE_SYNC_END); +} + +// Dispatch message received in the server loop (public entry point) int rpc_dispatch(rpc_connection_t *connection) { int32_t msg_tag; @@ -1541,6 +1748,8 @@ int rpc_dispatch(rpc_connection_t *connection) int error = rpc_message_recv_int32(&message, &msg_tag); if (error != RPC_ERROR_NO_ERROR) return rpc_error(connection, error); + if (msg_tag == RPC_MESSAGE_SYNC) // optional + return _rpc_dispatch_sync(connection); if (msg_tag != RPC_MESSAGE_START) return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID); @@ -1550,35 +1759,6 @@ int rpc_dispatch(rpc_connection_t *connection) return method; } -// Dispatch pending remote calls until we get MSG_TAG -static int _rpc_dispatch_until(rpc_connection_t *connection, rpc_message_t *message, int32_t expected_msg_tag) -{ - if (expected_msg_tag) { - for (;;) { - int32_t msg_tag; - int error = rpc_message_recv_int32(message, &msg_tag); - if (error != RPC_ERROR_NO_ERROR) - return error; - if (msg_tag == expected_msg_tag) - break; - if (msg_tag != RPC_MESSAGE_START) - return RPC_ERROR_MESSAGE_TYPE_INVALID; - if ((error = _rpc_dispatch(connection, message)) < 0) - return error; - } - } - else { - for (;;) { - int ret = _rpc_wait_dispatch(connection, 0); - if (ret == 0) - break; - if (ret < 0 || (ret = rpc_dispatch(connection)) < 0) - return ret; - } - } - return RPC_ERROR_NO_ERROR; -} - /* ====================================================================== */ /* === Method Callbacks Handling === */ @@ -1653,26 +1833,66 @@ int rpc_connection_remove_method_descriptors(rpc_connection_t *connection, const /* === Remote Procedure Call (method invocation) === */ /* ====================================================================== */ -// Invoke remote procedure (client side) -int rpc_method_invoke(rpc_connection_t *connection, int method, ...) +// Returns whether it is possible to rpc_method_invoke() now or not +bool rpc_method_invoke_possible(rpc_connection_t *connection) { - D(bug("rpc_method_invoke method=%d\n", method)); - - if (connection == NULL) - return RPC_ERROR_CONNECTION_NULL; - if (_rpc_status(connection) == RPC_STATUS_CLOSED) - return RPC_ERROR_CONNECTION_CLOSED; + if (rpc_status(connection) != RPC_STATUS_ACTIVE) + return false; + /* XXX: at this time, we can can call rpc_method_invoke() only if we + are not processing incoming calls already or if we are + "synchronized" with the other side. i.e. we are between an + rpc_method_get_args() and rpc_method_send_reply() in an RPC handler + function. */ + return connection->dispatch_depth == connection->handle_depth; +} +// Invoke remote procedure (client side) +static int _rpc_method_invoke_valist(rpc_connection_t *connection, int method, va_list args) +{ rpc_message_t message; rpc_message_init(&message, connection); - // call: rpc_dispatch() (pending remote calls) - int error = _rpc_dispatch_until(connection, &message, 0); - if (error != RPC_ERROR_NO_ERROR) - return rpc_error(connection, error); + /* Strategy to synchronize the connections. + + The purpose of connection synchronization is to ensure that the + other end is ready to receive our rpc_method_invoke() calls, + i.e. make sure it is not already processing RPC, or has not + started an rpc_method_invoke() call itself. + + There are two locations where it is safe to process incoming RPC: + - rpc_dispatch(), i.e. from the public entry-point + - rpc_method_wait_for_reply(), while waiting for MESSAGE_REPLY + + Otherwise, we need to synchronize both ends: + - Send MSG_SYNC, and block until we get MSG_SYNC_ACK + - Process any pending calls while we are blocked + - Honour MSG_SYNC in either rpc_dispatch() or at the end of + rpc_method_wait_for_reply(), i.e. while there is nothing else + to process, and until MSG_SYNC_END actually + */ + bool is_sync_mode = _rpc_connection_is_sync_mode(connection); + if (is_sync_mode && !_rpc_connection_is_sync(connection)) { + assert(connection->sync_depth == 0); + assert(connection->invoke_depth == 1); + + // send: MESSAGE_SYNC + int error = rpc_message_send_int32(&message, RPC_MESSAGE_SYNC); + if (error != RPC_ERROR_NO_ERROR) + return rpc_error(connection, error); + error = rpc_message_flush(&message); + if (error != RPC_ERROR_NO_ERROR) + return rpc_error(connection, error); + + // call: rpc_dispatch() (pending remote calls) + error = _rpc_dispatch_until(connection, &message, RPC_MESSAGE_SYNC_ACK); + if (error != RPC_ERROR_NO_ERROR) + return rpc_error(connection, error); + + connection->sync_depth = connection->invoke_depth; + } // send: = MESSAGE_START MESSAGE_END - error = rpc_message_send_int32(&message, RPC_MESSAGE_START); + int error = rpc_message_send_int32(&message, RPC_MESSAGE_START); if (error != RPC_ERROR_NO_ERROR) return rpc_error(connection, error); error = rpc_message_send_int32(&message, method); @@ -1686,16 +1906,14 @@ int rpc_method_invoke(rpc_connection_t *connection, int method, ...) return rpc_error(connection, error); // send optional arguments - va_list args; - va_start(args, method); + va_list args_copy; + va_copy(args_copy, args); int arg_type = va_arg(args, int); - va_end(args); if (arg_type != RPC_TYPE_INVALID) { // send: = MESSAGE_ARGS [ ]+ MESSAGE_END - va_start(args, method); - error = rpc_message_send_args(&message, args); - va_end(args); + error = rpc_message_send_args(&message, args_copy); + va_end(args_copy); if (error != RPC_ERROR_NO_ERROR) return rpc_error(connection, error); error = rpc_message_flush(&message); @@ -1703,17 +1921,46 @@ int rpc_method_invoke(rpc_connection_t *connection, int method, ...) return rpc_error(connection, error); } - // wait: MESSAGE_ACK - error = _rpc_dispatch_until(connection, &message, RPC_MESSAGE_ACK); - if (error == RPC_ERROR_ERRNO_SET) - perror("rpc_method_invoke"); + return RPC_ERROR_NO_ERROR; +} + +int rpc_method_invoke(rpc_connection_t *connection, int method, ...) +{ + D(bug("rpc_method_invoke method=%d\n", method)); + + if (connection == NULL) + return RPC_ERROR_CONNECTION_NULL; + if (_rpc_status(connection) == RPC_STATUS_CLOSED) + return RPC_ERROR_CONNECTION_CLOSED; + + ++connection->invoke_depth; + + va_list args; + va_start(args, method); + int ret = _rpc_method_invoke_valist(connection, method, args); + va_end(args); + + return ret; +} + +// Retrieve procedure arguments (server side) +static int _rpc_method_get_args_valist(rpc_connection_t *connection, va_list args) +{ + rpc_message_t message; + rpc_message_init(&message, connection); + + // we can't have pending calls here because the method invocation + // message and its arguments are atomic (i.e. they are sent right + // away, no wait for ACK) + + // recv: + int error = rpc_message_recv_args(&message, args); if (error != RPC_ERROR_NO_ERROR) return rpc_error(connection, error); return RPC_ERROR_NO_ERROR; } -// Retrieve procedure arguments (server side) int rpc_method_get_args(rpc_connection_t *connection, ...) { D(bug("rpc_method_get_args\n")); @@ -1723,42 +1970,19 @@ int rpc_method_get_args(rpc_connection_t *connection, ...) if (_rpc_status(connection) == RPC_STATUS_CLOSED) return RPC_ERROR_CONNECTION_CLOSED; - rpc_message_t message; - rpc_message_init(&message, connection); + ++connection->handle_depth; - // we can't have pending calls here because the method invocation - // message and its arguments are atomic (i.e. they are sent right - // away, no wait for ACK) - - // recv: va_list args; va_start(args, connection); - int error = rpc_message_recv_args(&message, args); + int ret = _rpc_method_get_args_valist(connection, args); va_end(args); - if (error != RPC_ERROR_NO_ERROR) - return rpc_error(connection, error); - // send: MESSAGE_ACK - error = rpc_message_send_int32(&message, RPC_MESSAGE_ACK); - if (error != RPC_ERROR_NO_ERROR) - return rpc_error(connection, error); - error = rpc_message_flush(&message); - if (error != RPC_ERROR_NO_ERROR) - return rpc_error(connection, error); - - return RPC_ERROR_NO_ERROR; + return ret; } // Wait for a reply from the remote procedure (client side) -int rpc_method_wait_for_reply(rpc_connection_t *connection, ...) +static int _rpc_method_wait_for_reply_valist(rpc_connection_t *connection, va_list args) { - D(bug("rpc_method_wait_for_reply\n")); - - if (connection == NULL) - return RPC_ERROR_CONNECTION_NULL; - if (_rpc_status(connection) == RPC_STATUS_CLOSED) - return RPC_ERROR_CONNECTION_CLOSED; - int error; int32_t msg_tag; rpc_message_t message; @@ -1771,16 +1995,14 @@ int rpc_method_wait_for_reply(rpc_connection_t *connection, ...) return rpc_error(connection, error); // receive optional arguments - va_list args; - va_start(args, connection); + va_list args_copy; + va_copy(args_copy, args); int type = va_arg(args, int); - va_end(args); if (type != RPC_TYPE_INVALID) { // recv: [ ] - va_start(args, connection); - error = rpc_message_recv_args(&message, args); - va_end(args); + error = rpc_message_recv_args(&message, args_copy); + va_end(args_copy); if (error != RPC_ERROR_NO_ERROR) return rpc_error(connection, error); } @@ -1792,26 +2014,59 @@ int rpc_method_wait_for_reply(rpc_connection_t *connection, ...) if (msg_tag != RPC_MESSAGE_END) return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID); - // wait: MESSAGE_ACK - error = rpc_message_recv_int32(&message, &msg_tag); - if (error != RPC_ERROR_NO_ERROR) - return rpc_error(connection, error); - if (msg_tag != RPC_MESSAGE_ACK) - return rpc_error(connection, RPC_ERROR_MESSAGE_TYPE_INVALID); - + // send: MESSAGE_SYNC_END (done pending message) + if (connection->sync_depth) { + if (connection->sync_depth == connection->invoke_depth) { + assert(connection->invoke_depth == 1); + + // send: MESSAGE_SYNC_END + int error = rpc_message_send_int32(&message, RPC_MESSAGE_SYNC_END); + if (error != RPC_ERROR_NO_ERROR) + return rpc_error(connection, error); + error = rpc_message_flush(&message); + if (error != RPC_ERROR_NO_ERROR) + return rpc_error(connection, error); + + connection->sync_depth = 0; + } + } + + // send: MESSAGE_SYNC_ACK (pending message) + if (connection->pending_sync_depth) { + if (connection->pending_sync_depth == connection->invoke_depth) { + assert(connection->invoke_depth == 1); + assert(_rpc_wait_dispatch(connection, 0) == 0); + + connection->pending_sync_depth = 0; + return _rpc_dispatch_sync(connection); + } + } + return RPC_ERROR_NO_ERROR; } -// Send a reply to the client (server side) -int rpc_method_send_reply(rpc_connection_t *connection, ...) +int rpc_method_wait_for_reply(rpc_connection_t *connection, ...) { - D(bug("rpc_method_send_reply\n")); + D(bug("rpc_method_wait_for_reply\n")); if (connection == NULL) return RPC_ERROR_CONNECTION_NULL; if (_rpc_status(connection) == RPC_STATUS_CLOSED) return RPC_ERROR_CONNECTION_CLOSED; + va_list args; + va_start(args, connection); + int ret = _rpc_method_wait_for_reply_valist(connection, args); + va_end(args); + + --connection->invoke_depth; + + return ret; +} + +// Send a reply to the client (server side) +static int _rpc_method_send_reply_valist(rpc_connection_t *connection, va_list args) +{ rpc_message_t message; rpc_message_init(&message, connection); @@ -1819,10 +2074,7 @@ int rpc_method_send_reply(rpc_connection_t *connection, ...) int error = rpc_message_send_int32(&message, RPC_MESSAGE_REPLY); if (error != RPC_ERROR_NO_ERROR) return rpc_error(connection, error); - va_list args; - va_start(args, connection); error = rpc_message_send_args(&message, args); - va_end(args); if (error != RPC_ERROR_NO_ERROR) return rpc_error(connection, error); error = rpc_message_send_int32(&message, RPC_MESSAGE_END); @@ -1832,17 +2084,28 @@ int rpc_method_send_reply(rpc_connection_t *connection, ...) if (error != RPC_ERROR_NO_ERROR) return rpc_error(connection, error); - // send: MESSAGE_ACK - error = rpc_message_send_int32(&message, RPC_MESSAGE_ACK); - if (error != RPC_ERROR_NO_ERROR) - return rpc_error(connection, error); - error = rpc_message_flush(&message); - if (error != RPC_ERROR_NO_ERROR) - return rpc_error(connection, error); - return RPC_ERROR_NO_ERROR; } +int rpc_method_send_reply(rpc_connection_t *connection, ...) +{ + D(bug("rpc_method_send_reply\n")); + + if (connection == NULL) + return RPC_ERROR_CONNECTION_NULL; + if (_rpc_status(connection) == RPC_STATUS_CLOSED) + return RPC_ERROR_CONNECTION_CLOSED; + + va_list args; + va_start(args, connection); + int ret = _rpc_method_send_reply_valist(connection, args); + va_end(args); + + --connection->handle_depth; + + return ret; +} + /* ====================================================================== */ /* === Test Program === */ diff --git a/src/rpc.h b/src/rpc.h index 13e7601..7c0a64e 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -41,6 +41,7 @@ enum { RPC_ERROR_MESSAGE_ARGUMENT_MISMATCH = -1010, RPC_ERROR_MESSAGE_ARGUMENT_UNKNOWN = -1011, RPC_ERROR_MESSAGE_ARGUMENT_INVALID = -1012, + RPC_ERROR_MESSAGE_SYNC_NOT_ALLOWED = -1013, }; extern const char *rpc_strerror(int error) attribute_hidden; @@ -113,6 +114,7 @@ extern int rpc_connection_add_method_descriptor(rpc_connection_t *connection, co extern int rpc_connection_add_method_descriptors(rpc_connection_t *connection, const rpc_method_descriptor_t *descs, int n_descs) attribute_hidden; // Remote Procedure Call (method invocation) +extern bool rpc_method_invoke_possible(rpc_connection_t *connection) attribute_hidden; extern int rpc_method_invoke(rpc_connection_t *connection, int method, ...) attribute_hidden; extern int rpc_method_wait_for_reply(rpc_connection_t *connection, ...) attribute_hidden; extern int rpc_method_get_args(rpc_connection_t *connection, ...) attribute_hidden; @@ -122,4 +124,10 @@ extern int rpc_method_send_reply(rpc_connection_t *connection, ...) attribute_hi } #endif +// This callback is called when the connection is closed or broken +typedef void (*rpc_error_callback_t)(rpc_connection_t *connection, void *user_data); + +// Set error callback for a connection +void rpc_connection_set_error_callback(rpc_connection_t *connection, rpc_error_callback_t callback, void *callback_data); + #endif /* RPC_H */ diff --git a/src/utils.c b/src/utils.c index 2f5ac4b..3047c21 100644 --- a/src/utils.c +++ b/src/utils.c @@ -18,12 +18,17 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#define _GNU_SOURCE 1 #include "sysdeps.h" #include #include #include #include /* */ +#include +#include +#include +#include #include "utils.h" #include "rpc.h" @@ -51,7 +56,9 @@ static inline void *id_key(uint32_t id) bool id_init(void) { - return (g_ids = g_hash_table_new(NULL, NULL)) != NULL; + if (g_ids == NULL) + g_ids = g_hash_table_new(NULL, NULL); + return g_ids != NULL; } void id_kill(void) @@ -219,6 +226,64 @@ const char *string_of_NPEvent_type(int type) return str; } + +const char *string_of_NPPVariable(int variable) +{ + const char *str; + + switch (variable) { +#define _(VAL) case VAL: str = #VAL; break; + _(NPPVpluginNameString); + _(NPPVpluginDescriptionString); + _(NPPVpluginWindowBool); + _(NPPVpluginTransparentBool); + _(NPPVjavaClass); + _(NPPVpluginWindowSize); + _(NPPVpluginTimerInterval); + _(NPPVpluginScriptableInstance); + _(NPPVpluginScriptableIID); + _(NPPVjavascriptPushCallerBool); + _(NPPVpluginKeepLibraryInMemory); + _(NPPVpluginNeedsXEmbed); + _(NPPVpluginScriptableNPObject); + _(NPPVformValue); +#undef _ + default: + str = ""; + break; + } + + return str; +} + +const char *string_of_NPNVariable(int variable) +{ + const char *str; + + switch (variable) { +#define _(VAL) case VAL: str = #VAL; break; + _(NPNVxDisplay); + _(NPNVxtAppContext); + _(NPNVnetscapeWindow); + _(NPNVjavascriptEnabledBool); + _(NPNVasdEnabledBool); + _(NPNVisOfflineBool); + _(NPNVserviceManager); + _(NPNVDOMElement); + _(NPNVDOMWindow); + _(NPNVToolkit); + _(NPNVSupportsXEmbedBool); + _(NPNVWindowNPObject); + _(NPNVPluginElementNPObject); + _(NPNVSupportsWindowless); +#undef _ + default: + str = ""; + break; + } + + return str; +} #endif @@ -265,6 +330,58 @@ char *npw_asprintf(const char *format, ...) return str; } +/* Return 1 + max value the system can allocate to a new fd */ +static int get_open_max(void) +{ + int open_max = -1; + /* SCO OpenServer has an fcntl() to retrieve the highest *currently + open* file descriptor. */ +#ifdef F_GETHFDO + if ((open_max = fcntl(-1, F_GETHFDO, 0)) >= 0) + return open_max + 1; +#endif + /* IEEE Std 1003.1-2001/Cor 1-2002 clarified the fact that return + value of sysconf(_SC_OPEN_MAX) may change if setrlimit() was + called to set RLIMIT_NOFILE. So, we should be on the safe side to + call getrlimit() first to get the soft limit. + + Note: dgettablesize() was a possibility but (i) it's equivalent + to getrlimit(), and (ii) it is not recommended for new code. */ + struct rlimit ru; + if (getrlimit(RLIMIT_NOFILE, &ru) == 0) + return ru.rlim_cur; + if ((open_max = sysconf(_SC_OPEN_MAX)) >= 0) + return open_max; + /* XXX: simply guess something reasonable. */ + return 256; +} + +void npw_close_all_open_files(void) +{ + const int min_fd = 3; + + DIR *dir = opendir("/proc/self/fd"); + if (dir) { + const int dfd = dirfd(dir); + struct dirent *d; + while ((d = readdir(dir)) != NULL) { + char *end; + long n = strtol(d->d_name, &end, 10); + if (*end == '\0') { + int fd = n; + if (fd >= min_fd && fd != dfd) + close(fd); + } + } + closedir(dir); + } + else { + const int open_max = get_open_max(); + for (int fd = min_fd; fd < open_max; fd++) + close(fd); + } +} + /* ====================================================================== */ /* === Test Program === */ diff --git a/src/utils.h b/src/utils.h index 562e33d..107c287 100644 --- a/src/utils.h +++ b/src/utils.h @@ -39,11 +39,14 @@ extern const char *string_of_NPError(int error) attribute_hidden; extern const char *string_of_NPReason(int reason) attribute_hidden; extern const char *string_of_NPStreamType(int stype) attribute_hidden; extern const char *string_of_NPEvent_type(int type) attribute_hidden; +extern const char *string_of_NPPVariable(int variable) attribute_hidden; +extern const char *string_of_NPNVariable(int variable) 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 char *npw_asprintf(const char *format, ...) attribute_hidden; +extern void npw_close_all_open_files(void) attribute_hidden; #ifdef __cplusplus } diff --git a/tests/test-plugins.html b/tests/test-plugins.html index b14ea2e..a6660ba 100644 --- a/tests/test-plugins.html +++ b/tests/test-plugins.html @@ -26,7 +26,7 @@ Various sample data to exercise the NPAPI plugins compatibility layer
  • Tcl Plugin Demos
    http://www.tcl.tk/software/plugin/applets.html

  • Squeak VM plugin tests
    -http://www.squeakland.org/plugin/launch.html +http://wiki.squeak.org/squeak/5858

  • Citrix ICA Client demo
    http://www.rentonlinesoftware.com/store/tryademo.asp diff --git a/tests/test-rpc-common.c b/tests/test-rpc-common.c index e7b9de1..b6c8ec5 100644 --- a/tests/test-rpc-common.c +++ b/tests/test-rpc-common.c @@ -46,7 +46,6 @@ static const gchar *g_connection_path; static GMainLoop *g_main_loop; static GPid g_child_pid; static guint g_child_watch_id; -static guint g_source_id; static gint g_exit_status; void @@ -54,9 +53,9 @@ rpc_test_set_funcs (const RPCTestFuncs *funcs, gpointer user_data) { g_test.user_data = user_data; if (funcs && funcs->pre_dispatch_hook) - g_test.funcs.pre_dispatch_hook = funcs->pre_dispatch_hook; + g_test.funcs.pre_dispatch_hook = funcs->pre_dispatch_hook; if (funcs && funcs->post_dispatch_hook) - g_test.funcs.post_dispatch_hook = funcs->post_dispatch_hook; + g_test.funcs.post_dispatch_hook = funcs->post_dispatch_hook; } rpc_connection_t * @@ -71,10 +70,10 @@ child_exited_cb (GPid pid, gint status, gpointer user_data) { g_print ("child_exited_cb(), pid %d, status %d\n", pid, status); if (status) - g_exit_status = status; + g_exit_status = status; g_main_loop_quit (g_main_loop); if (g_child_watch_id) - g_source_remove (g_child_watch_id); + g_source_remove (g_child_watch_id); g_spawn_close_pid (pid); } @@ -82,12 +81,12 @@ static void kill_child_now (void) { if (g_child_watch_id) - g_source_remove (g_child_watch_id); + g_source_remove (g_child_watch_id); if (g_child_pid) - { - g_spawn_close_pid (g_child_pid); - kill (g_child_pid, SIGTERM); - } + { + g_spawn_close_pid (g_child_pid); + kill (g_child_pid, SIGTERM); + } } static void @@ -97,7 +96,6 @@ urgent_exit_sig (int sig) } #endif -#ifdef BUILD_SERVER static gboolean rpc_event_prepare (GSource *source, gint *timeout) { @@ -117,15 +115,15 @@ rpc_event_dispatch (GSource *source, GSourceFunc callback, gpointer user_data) gint rc; if (g_test.funcs.pre_dispatch_hook) - { - if (!g_test.funcs.pre_dispatch_hook (g_test.user_data)) - return TRUE; - } + { + if (!g_test.funcs.pre_dispatch_hook (g_test.user_data)) + return TRUE; + } rc = rpc_dispatch (g_connection); if (g_test.funcs.post_dispatch_hook) - g_test.funcs.post_dispatch_hook (g_test.user_data); + g_test.funcs.post_dispatch_hook (g_test.user_data); return rc != RPC_ERROR_CONNECTION_CLOSED; } @@ -137,14 +135,13 @@ typedef void (*GSourceFinalizeFunc) (GSource *); static GSourceFuncs rpc_event_funcs = { - rpc_event_prepare, - rpc_event_check, - rpc_event_dispatch, - (GSourceFinalizeFunc)g_free, - (GSourceFunc)NULL, - (GSourceDummyMarshal)NULL + rpc_event_prepare, + rpc_event_check, + rpc_event_dispatch, + (GSourceFinalizeFunc)g_free, + (GSourceFunc)NULL, + (GSourceDummyMarshal)NULL }; -#endif static gboolean rpc_test_execute_cb (gpointer user_data) @@ -152,12 +149,12 @@ rpc_test_execute_cb (gpointer user_data) int rc = RPC_TEST_EXECUTE_SUCCESS; if (rpc_test_execute) - rc = rpc_test_execute (g_test.user_data); - g_assert ((rc & ~RPC_TEST_EXECUTE_DONT_QUIT) == RPC_TEST_EXECUTE_SUCCESS); + rc = rpc_test_execute (g_test.user_data); + RPC_TEST_ENSURE ((rc & ~RPC_TEST_EXECUTE_DONT_QUIT) == RPC_TEST_EXECUTE_SUCCESS); #ifdef BUILD_CLIENT if ((rc & RPC_TEST_EXECUTE_DONT_QUIT) == 0) - rpc_test_exit_full (0); + rpc_test_exit_full (0); #endif return FALSE; } @@ -169,15 +166,15 @@ clone_args (gchar **args) gint i, n, rc = 0; if ((new_args = g_strdupv (args)) == NULL) - g_error ("could not duplicate the program arguments"); + g_error ("could not duplicate the program arguments"); n = g_strv_length (new_args); #ifdef BUILD_CLIENT /* first arg was path to server program, skip it */ - g_assert (n >= 2); + RPC_TEST_ENSURE (n >= 2); g_free (new_args[1]); for (i = 1; i < n - 1; i++) - new_args[i] = new_args[i + 1]; + new_args[i] = new_args[i + 1]; new_args[i] = NULL; #endif @@ -191,13 +188,13 @@ rpc_test_init_invoke (gchar **program_args) gint n, rc = 0; if ((args = clone_args (program_args)) == NULL) - g_error ("could not clone program arguments"); + g_error ("could not clone program arguments"); n = g_strv_length (args); if (rpc_test_init) - rc = rpc_test_init (n, args); + rc = rpc_test_init (n, args); g_strfreev (args); - g_assert (rc == 0); + RPC_TEST_ENSURE (rc == 0); g_timeout_add (0, rpc_test_execute_cb, NULL); } @@ -206,11 +203,7 @@ void rpc_test_exit (int status) { if (status) - g_exit_status = status; - if (g_source_id) - g_source_remove (g_source_id); - if (g_connection) - rpc_exit (g_connection); + g_exit_status = status; g_main_loop_quit (g_main_loop); } @@ -220,9 +213,9 @@ rpc_test_exit_full (int status) #ifdef BUILD_CLIENT /* Tell server to quit, don't expect any reply from him */ rpc_method_invoke (g_connection, - RPC_TEST_METHOD_EXIT, - RPC_TYPE_INT32, status, - RPC_TYPE_INVALID); + RPC_TEST_METHOD_EXIT, + RPC_TYPE_INT32, status, + RPC_TYPE_INVALID); #endif rpc_test_exit (status); @@ -235,11 +228,11 @@ handle_rpc_test_exit (rpc_connection_t *connection) gint32 status; error = rpc_method_get_args (connection, - RPC_TYPE_INT32, &status, - RPC_TYPE_INVALID); + RPC_TYPE_INT32, &status, + RPC_TYPE_INVALID); if (error == RPC_ERROR_NO_ERROR) - rpc_test_exit (status); + rpc_test_exit (status); return error; } @@ -248,15 +241,15 @@ int main (int argc, char *argv[]) { if (rpc_test_get_connection_path) - g_connection_path = rpc_test_get_connection_path (); + g_connection_path = rpc_test_get_connection_path (); else - g_connection_path = NPW_CONNECTION_PATH "/Test.RPC"; + g_connection_path = NPW_CONNECTION_PATH "/Test.RPC"; #ifdef BUILD_CLIENT gchar **child_args; if (argc < 2) - g_error ("no server program provided on command line"); + g_error ("no server program provided on command line"); signal (SIGSEGV, urgent_exit_sig); signal (SIGBUS, urgent_exit_sig); @@ -264,49 +257,59 @@ main (int argc, char *argv[]) signal (SIGABRT, urgent_exit_sig); if ((child_args = clone_args (argv)) == NULL) - g_error ("could not create server program arguments\n"); + g_error ("could not create server program arguments\n"); g_free (child_args[0]); child_args[0] = g_strdup (argv[1]); if (!g_spawn_async (NULL, - child_args, - NULL, - G_SPAWN_DO_NOT_REAP_CHILD, - NULL, - NULL, - &g_child_pid, - NULL)) - g_error ("could not start server program '%s'", child_args[0]); + child_args, + NULL, + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, + NULL, + &g_child_pid, + NULL)) + g_error ("could not start server program '%s'", child_args[0]); g_strfreev (child_args); if ((g_connection = rpc_init_client (g_connection_path)) == NULL) - g_error ("failed to initialize RPC client connection"); + g_error ("failed to initialize RPC client connection"); #endif #ifdef BUILD_SERVER if ((g_connection = rpc_init_server (g_connection_path)) == NULL) - g_error ("failed to initialize RPC server connection"); + g_error ("failed to initialize RPC server connection"); +#endif - GSource *rpc_source; + int fd = -1; + GSource *rpc_source = NULL; + guint rpc_source_id = 0; GPollFD rpc_event_poll_fd; - if ((rpc_source = g_source_new (&rpc_event_funcs, sizeof (GSource))) == NULL) - g_error ("failed to initialize RPC source"); +#ifdef BUILD_CLIENT + fd = rpc_socket (g_connection); +#endif +#ifdef BUILD_SERVER + fd = rpc_listen_socket (g_connection); +#endif + RPC_TEST_ENSURE (fd >= 0); - g_source_id = g_source_attach (rpc_source, NULL); + if ((rpc_source = g_source_new (&rpc_event_funcs, sizeof (GSource))) == NULL) + g_error ("failed to initialize RPC source"); + + rpc_source_id = g_source_attach (rpc_source, NULL); memset (&rpc_event_poll_fd, 0, sizeof (rpc_event_poll_fd)); - rpc_event_poll_fd.fd = rpc_listen_socket (g_connection); + rpc_event_poll_fd.fd = fd; rpc_event_poll_fd.events = G_IO_IN; rpc_event_poll_fd.revents = 0; g_source_add_poll (rpc_source, &rpc_event_poll_fd); -#endif static const rpc_method_descriptor_t vtable[] = { - { RPC_TEST_METHOD_EXIT, handle_rpc_test_exit } + { RPC_TEST_METHOD_EXIT, handle_rpc_test_exit } }; if (rpc_connection_add_method_descriptor (g_connection, &vtable[0]) < 0) - g_error ("could not add method descriptor for TEST_RPC_METHOD_EXIT"); + g_error ("could not add method descriptor for TEST_RPC_METHOD_EXIT"); g_main_loop = g_main_loop_new (NULL, TRUE); #ifdef BUILD_CLIENT @@ -314,5 +317,9 @@ main (int argc, char *argv[]) #endif rpc_test_init_invoke (argv); g_main_loop_run (g_main_loop); + if (rpc_source_id) + g_source_remove (rpc_source_id); + if (g_connection) + rpc_exit (g_connection); return g_exit_status; } diff --git a/tests/test-rpc-common.h b/tests/test-rpc-common.h index d448874..f5c7107 100644 --- a/tests/test-rpc-common.h +++ b/tests/test-rpc-common.h @@ -26,17 +26,37 @@ enum { - /* void rpc_test_exit (int status); */ - RPC_TEST_METHOD_EXIT = 0, + /* void rpc_test_exit (int status); */ + RPC_TEST_METHOD_EXIT = 0, }; enum { - RPC_TEST_EXECUTE_SUCCESS = 0, - RPC_TEST_EXECUTE_FAILURE = 1, - RPC_TEST_EXECUTE_DONT_QUIT = 0x8000, + RPC_TEST_EXECUTE_SUCCESS = 0, + RPC_TEST_EXECUTE_FAILURE = 1, + RPC_TEST_EXECUTE_DONT_QUIT = 0x8000, }; +#define RPC_TEST_ENSURE(expr) do { \ + if (!(expr)) { \ + npw_printf ("ERROR:(%s:%d):%s: assertion failed: (%s)\n", \ + __FILE__, __LINE__, __func__, #expr); \ + abort (); \ + } \ +} while (0) + +#define RPC_TEST_ENSURE_ERROR(error, error_code) do { \ + if ((error) != (error_code)) { \ + npw_printf ("ERROR:(%s:%d):%s: %s\n", \ + __FILE__, __LINE__, __func__, \ + rpc_strerror (error)); \ + abort (); \ + } \ +} while (0) + +#define RPC_TEST_ENSURE_NO_ERROR(error) \ + RPC_TEST_ENSURE_ERROR(error, RPC_ERROR_NO_ERROR) + typedef struct _RPCTestFuncs RPCTestFuncs; struct _RPCTestFuncs { diff --git a/tests/test-rpc-concurrent.c b/tests/test-rpc-concurrent.c index 3cab886..c966338 100644 --- a/tests/test-rpc-concurrent.c +++ b/tests/test-rpc-concurrent.c @@ -29,74 +29,134 @@ enum { - RPC_TEST_METHOD_PRINT = 1 + RPC_TEST_METHOD_STEP = 1, + RPC_TEST_METHOD_DONE }; -static gboolean g_is_silent = TRUE; -static gint g_print_count = 5000; +static gboolean g_is_silent = TRUE; +static gint g_n_steps = 5000; +static gboolean g_got_done = FALSE; static void -invoke_print (const gchar *str) +invoke_step (int n) +{ + rpc_connection_t *connection; + int error; + int32_t ret; + + connection = rpc_test_get_connection (); + RPC_TEST_ENSURE (connection != NULL); + + error = rpc_method_invoke (connection, + RPC_TEST_METHOD_STEP, + RPC_TYPE_INT32, n, + RPC_TYPE_INVALID); + /* Error out early for invalid messages types. + + The problem we are looking at is rpc_method_invoke() waiting for + the other side MSG_ACK prior to sending the arguments. Sometimes, + the other side sends a new message first (MSG_START). So, we get + a mismatch. */ + RPC_TEST_ENSURE (error != RPC_ERROR_MESSAGE_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + error = rpc_method_wait_for_reply (connection, + RPC_TYPE_INT32, &ret, + RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + RPC_TEST_ENSURE (ret == n); +} + +static int +handle_step (rpc_connection_t *connection) +{ + int32_t n; + int error; + + error = rpc_method_get_args (connection, + RPC_TYPE_INT32, &n, + RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + if (!g_is_silent) + npw_printf ("Got message %d from the other end\n", n); + + error = rpc_method_send_reply (connection, + RPC_TYPE_INT32, n, + RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + return error; +} + +static void +invoke_done (void) { rpc_connection_t *connection; int error; connection = rpc_test_get_connection (); - g_assert (connection != NULL); + RPC_TEST_ENSURE (connection != NULL); error = rpc_method_invoke (connection, - RPC_TEST_METHOD_PRINT, - RPC_TYPE_STRING, str, - RPC_TYPE_INVALID); - /* Error out early for invalid messages types. - - The problem we are looking at is rpc_method_invoke() waiting for - the other side MSG_ACK prior to sending the arguments. Sometimes, - the other side sends a new message first (MSG_START). So, we get - a mismatch. */ - g_assert (error != RPC_ERROR_MESSAGE_TYPE_INVALID); - g_assert (error == RPC_ERROR_NO_ERROR); + RPC_TEST_METHOD_DONE, + RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); error = rpc_method_wait_for_reply (connection, RPC_TYPE_INVALID); - g_assert (error == RPC_ERROR_NO_ERROR); + RPC_TEST_ENSURE_NO_ERROR (error); } static int -handle_print (rpc_connection_t *connection) +handle_done (rpc_connection_t *connection) { - char *str; - int error; + int error; - error = rpc_method_get_args (connection, - RPC_TYPE_STRING, &str, - RPC_TYPE_INVALID); - g_assert (error == RPC_ERROR_NO_ERROR); - g_assert (str != NULL); + error = rpc_method_get_args (connection, RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); - if (!g_is_silent) - npw_printf ("Got message from the other end: '%s'\n", str); - free (str); + g_got_done = TRUE; - return rpc_method_send_reply (connection, RPC_TYPE_INVALID); +#ifdef BUILD_CLIENT + if (g_n_steps == 0) + rpc_test_exit_full (0); +#endif + + error = rpc_method_send_reply (connection, RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + return error; } static inline void -print_msg (void) +do_step (int n) { - invoke_print ("Hello from " NPW_COMPONENT_NAME); + invoke_step (n); +} + +static inline void +do_done (void) +{ + invoke_done (); } static gboolean -invoke_print_cb (gpointer user_data) +invoke_step_cb (gpointer user_data) { - print_msg (); + do_step (g_n_steps); - --g_print_count; + if (--g_n_steps == 0) + { #ifdef BUILD_CLIENT - if (g_print_count == 0) + if (g_got_done) rpc_test_exit_full (0); #endif - return g_print_count > 0; +#ifdef BUILD_SERVER + do_done (); +#endif + } + + return g_n_steps > 0; } int @@ -105,50 +165,52 @@ rpc_test_init (int argc, char *argv[]) rpc_connection_t *connection; for (int i = 1; i < argc; i++) + { + const gchar *arg = argv[i]; + if (strcmp (arg, "--silent") == 0 || strcmp (arg, "-q") == 0) + g_is_silent = TRUE; + else if (strcmp (arg, "--verbose") == 0 || strcmp (arg, "-v") == 0) + g_is_silent = FALSE; + else if (strcmp (arg, "--count") == 0) { - const gchar *arg = argv[i]; - if (strcmp (arg, "--silent") == 0 || strcmp (arg, "-q") == 0) - g_is_silent = TRUE; - else if (strcmp (arg, "--verbose") == 0 || strcmp (arg, "-v") == 0) - g_is_silent = FALSE; - else if (strcmp (arg, "--count") == 0) - { - if (++i < argc) - { - unsigned long v = strtoul (argv[i], NULL, 10); - if (v > 0) - g_print_count = v; - } - } - else if (strcmp (arg, "--help") == 0) - { - g_print ("Usage: %s [--silent|--verbose] [--count COUNT]\n", argv[0]); - rpc_test_exit (0); - } + if (++i < argc) + { + unsigned long v = strtoul (argv[i], NULL, 10); + if (v > 0) + g_n_steps = v; + } } + else if (strcmp (arg, "--help") == 0) + { + g_print ("Usage: %s [--silent|--verbose] [--count COUNT]\n", argv[0]); + rpc_test_exit (0); + } + } connection = rpc_test_get_connection (); - g_assert (connection != NULL); + RPC_TEST_ENSURE (connection != NULL); static const rpc_method_descriptor_t vtable[] = { - { RPC_TEST_METHOD_PRINT, handle_print }, + { RPC_TEST_METHOD_STEP, handle_step }, + { RPC_TEST_METHOD_DONE, handle_done } }; - if (rpc_connection_add_method_descriptor (connection, &vtable[0]) < 0) - g_error ("could not add method descriptors"); + if (rpc_connection_add_method_descriptors (connection, &vtable[0], + G_N_ELEMENTS (vtable)) < 0) + g_error ("could not add method descriptors"); if (RPC_TEST_USE_IDLE) - { - /* XXX: we hope to trigger concurrent rpc_method_invoke() */ - /* XXX: add a barrier to synchronize both processes? */ - //g_idle_add (invoke_print_cb, NULL); - g_timeout_add (0, invoke_print_cb, NULL); - } + { + /* XXX: we hope to trigger concurrent rpc_method_invoke() */ + /* XXX: add a barrier to synchronize both processes? */ + //g_idle_add (invoke_step_cb, NULL); + g_timeout_add (0, invoke_step_cb, NULL); + } else - { - while (--g_print_count >= 0) - print_msg (); - } + { + while (--g_n_steps >= 0) + do_step (g_n_steps); + } return 0; } @@ -157,7 +219,7 @@ rpc_test_execute (gpointer user_data) { #ifdef BUILD_CLIENT if (RPC_TEST_USE_IDLE) - return RPC_TEST_EXECUTE_SUCCESS|RPC_TEST_EXECUTE_DONT_QUIT; + return RPC_TEST_EXECUTE_SUCCESS|RPC_TEST_EXECUTE_DONT_QUIT; #endif return RPC_TEST_EXECUTE_SUCCESS; } diff --git a/tests/test-rpc-nested.c b/tests/test-rpc-nested-1.c similarity index 76% rename from tests/test-rpc-nested.c rename to tests/test-rpc-nested-1.c index 6b40b35..2f825c9 100644 --- a/tests/test-rpc-nested.c +++ b/tests/test-rpc-nested-1.c @@ -27,7 +27,7 @@ enum { - RPC_TEST_METHOD_GET_PID = 1 + RPC_TEST_METHOD_GET_PID = 1 }; static gint @@ -38,17 +38,17 @@ get_remote_pid (void) gint32 pid; connection = rpc_test_get_connection (); - g_assert (connection != NULL); + RPC_TEST_ENSURE (connection != NULL); error = rpc_method_invoke (connection, - RPC_TEST_METHOD_GET_PID, - RPC_TYPE_INVALID); - g_assert (error == RPC_ERROR_NO_ERROR); + RPC_TEST_METHOD_GET_PID, + RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); error = rpc_method_wait_for_reply (connection, - RPC_TYPE_INT32, &pid, - RPC_TYPE_INVALID); - g_assert (error == RPC_ERROR_NO_ERROR); + RPC_TYPE_INT32, &pid, + RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); return pid; } @@ -78,13 +78,16 @@ handle_get_pid (rpc_connection_t *connection) int error; error = rpc_method_get_args (connection, RPC_TYPE_INVALID); - g_assert (error == RPC_ERROR_NO_ERROR); + RPC_TEST_ENSURE_NO_ERROR (error); pid = get_client_pid (); - return rpc_method_send_reply (connection, - RPC_TYPE_INT32, pid, - RPC_TYPE_INVALID); + error = rpc_method_send_reply (connection, + RPC_TYPE_INT32, pid, + RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + return error; } int @@ -93,14 +96,14 @@ rpc_test_init (int argc, char *argv[]) rpc_connection_t *connection; connection = rpc_test_get_connection (); - g_assert (connection != NULL); + RPC_TEST_ENSURE (connection != NULL); static const rpc_method_descriptor_t vtable[] = { - { RPC_TEST_METHOD_GET_PID, handle_get_pid }, + { RPC_TEST_METHOD_GET_PID, handle_get_pid }, }; if (rpc_connection_add_method_descriptor (connection, &vtable[0]) < 0) - g_error ("could not add method descriptors"); + g_error ("could not add method descriptors"); return 0; } @@ -110,7 +113,7 @@ rpc_test_execute (gpointer user_data) { #ifdef BUILD_CLIENT gint pid = get_remote_pid (); - g_assert (pid == get_local_pid ()); + RPC_TEST_ENSURE (pid == get_local_pid ()); #endif return RPC_TEST_EXECUTE_SUCCESS; } diff --git a/tests/test-rpc-nested-2.c b/tests/test-rpc-nested-2.c new file mode 100644 index 0000000..0c6f62a --- /dev/null +++ b/tests/test-rpc-nested-2.c @@ -0,0 +1,189 @@ +/* + * test-rpc-nested-2.c - Test nested RPC invoke + * + * nspluginwrapper (C) 2005-2008 Gwenole Beauchesne + * + * 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. + */ + +#include "sysdeps.h" +#include "test-rpc-common.h" +#include + +#define DEBUG 1 +#include "debug.h" + +enum + { + RPC_TEST_METHOD_F1 = 1, + RPC_TEST_METHOD_F2, + RPC_TEST_METHOD_F3, + RPC_TEST_METHOD_F4, + RPC_TEST_METHOD_F5 + }; + +static const char * +f_name (int method) +{ + switch (method) + { + case RPC_TEST_METHOD_F1: return "f1"; + case RPC_TEST_METHOD_F2: return "f2"; + case RPC_TEST_METHOD_F3: return "f3"; + case RPC_TEST_METHOD_F4: return "f4"; + case RPC_TEST_METHOD_F5: return "f5"; + } + return ""; +} + +#define print_func(pfx, method) npw_printf ("%s: %s()\n", pfx, f_name (method)) +#define print_func_SEND(method) print_func ("SEND", method) +#define print_func_RECV(method) print_func ("RECV", method) + +static void +f (int method) +{ + rpc_connection_t *connection; + int error; + + print_func_SEND (method); + + connection = rpc_test_get_connection (); + RPC_TEST_ENSURE (connection != NULL); + + RPC_TEST_ENSURE (rpc_method_invoke_possible (connection)); + error = rpc_method_invoke (connection, method, RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + error = rpc_method_wait_for_reply (connection, RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); +} + +static int +handle_f1 (rpc_connection_t *connection) +{ + int error; + + print_func_RECV (RPC_TEST_METHOD_F1); + + error = rpc_method_get_args (connection, RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + f (RPC_TEST_METHOD_F2); + + error = rpc_method_send_reply (connection, RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + return error; +} + +static int +handle_fN (rpc_connection_t *connection, int method) +{ + int error; + + print_func_RECV (method); + + error = rpc_method_get_args (connection, RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + error = rpc_method_send_reply (connection, RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + return error; +} + +static int +handle_f2 (rpc_connection_t *connection) +{ + int error; + + print_func_RECV (RPC_TEST_METHOD_F2); + + error = rpc_method_get_args (connection, RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + f (RPC_TEST_METHOD_F3); + + error = rpc_method_send_reply (connection, RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + return error; +} + +static int +handle_f3 (rpc_connection_t *connection) +{ + int error; + + print_func_RECV (RPC_TEST_METHOD_F3); + + error = rpc_method_get_args (connection, RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + f (RPC_TEST_METHOD_F4); + + error = rpc_method_send_reply (connection, RPC_TYPE_INVALID); + RPC_TEST_ENSURE_NO_ERROR (error); + + f (RPC_TEST_METHOD_F5); + + return error; +} + +static int +handle_f4 (rpc_connection_t *connection) +{ + handle_fN (connection, RPC_TEST_METHOD_F4); +} + +static int +handle_f5 (rpc_connection_t *connection) +{ + handle_fN (connection, RPC_TEST_METHOD_F5); +} + +int +rpc_test_init (int argc, char *argv[]) +{ + rpc_connection_t *connection; + + connection = rpc_test_get_connection (); + RPC_TEST_ENSURE (connection != NULL); + + static const rpc_method_descriptor_t vtable[] = { + { RPC_TEST_METHOD_F1, handle_f1 }, + { RPC_TEST_METHOD_F2, handle_f2 }, + { RPC_TEST_METHOD_F3, handle_f3 }, + { RPC_TEST_METHOD_F4, handle_f4 }, + { RPC_TEST_METHOD_F5, handle_f5 } + }; + + if (rpc_connection_add_method_descriptors (connection, &vtable[0], + G_N_ELEMENTS (vtable)) < 0) + g_error ("could not add method descriptors"); + + return 0; +} + +int +rpc_test_execute (gpointer user_data) +{ +#ifdef BUILD_CLIENT + f (RPC_TEST_METHOD_F1); +#endif + npw_printf ("done\n"); + return RPC_TEST_EXECUTE_SUCCESS; +} diff --git a/tests/test-rpc-types.c b/tests/test-rpc-types.c index 0f8241f..25b5721 100644 --- a/tests/test-rpc-types.c +++ b/tests/test-rpc-types.c @@ -30,16 +30,24 @@ enum { - RPC_TEST_METHOD_VOID__VOID = 1, - RPC_TEST_METHOD_VOID__CHAR, - RPC_TEST_METHOD_VOID__CHARx10, - RPC_TEST_METHOD_VOID__BOOL, - RPC_TEST_METHOD_VOID__BOOLx10, - RPC_TEST_METHOD_VOID__INT32x10, - RPC_TEST_METHOD_VOID__UINT32x10, - RPC_TEST_METHOD_VOID__UINT64x10, - RPC_TEST_METHOD_VOID__DOUBLEx5, - RPC_TEST_METHOD_VOID__STRINGx3, + RPC_TEST_METHOD_VOID__VOID = 1, + RPC_TEST_METHOD_VOID__CHAR, + RPC_TEST_METHOD_VOID__CHARx10, + RPC_TEST_METHOD_VOID__BOOL, + RPC_TEST_METHOD_VOID__BOOLx10, + RPC_TEST_METHOD_VOID__INT32x10, + RPC_TEST_METHOD_VOID__UINT32x10, + RPC_TEST_METHOD_VOID__UINT64x10, + RPC_TEST_METHOD_VOID__DOUBLEx5, + RPC_TEST_METHOD_VOID__STRINGx3, + RPC_TEST_METHOD_VOID__CHAR_ARRAY, + RPC_TEST_METHOD_VOID__INT32_ARRAY, + RPC_TEST_METHOD_VOID__UINT64_ARRAY, + RPC_TEST_METHOD_VOID__DOUBLE_ARRAY, + RPC_TEST_METHOD_VOID__STRING_ARRAY, + RPC_TEST_METHOD_VOID__NULL_ARRAY, + RPC_TEST_METHOD_VOID__0LEN_ARRAY, + RPC_TEST_METHOD_VOID__MIXED_ARRAY }; const gchar * @@ -57,85 +65,116 @@ rpc_test_signature (gboolean is_invoke, ...) GString *str; if ((str = g_string_new (NULL)) == NULL) - return; + return; n_args = 0; was_array = FALSE; va_start (args, is_invoke); while ((type = va_arg (args, gint)) != RPC_TYPE_INVALID) + { + if (++n_args > 1 && !was_array) + g_string_append (str, ", "); + if (was_array) { - if (++n_args > 1 && !was_array) - g_string_append (str, ", "); - was_array = FALSE; - switch (type) - { - case RPC_TYPE_CHAR: - g_string_append (str, "char"); - if (is_invoke) - va_arg (args, int); - break; - case RPC_TYPE_BOOLEAN: - g_string_append (str, "bool"); - if (is_invoke) - va_arg (args, int); - break; - case RPC_TYPE_INT32: - g_string_append (str, "int32"); - if (is_invoke) - va_arg (args, gint32); - break; - case RPC_TYPE_UINT32: - g_string_append (str, "uint32"); - if (is_invoke) - va_arg (args, guint32); - break; - case RPC_TYPE_UINT64: - g_string_append (str, "uint64"); - if (is_invoke) - va_arg (args, guint64); - break; - case RPC_TYPE_DOUBLE: - g_string_append (str, "double"); - if (is_invoke) - va_arg (args, gdouble); - break; - case RPC_TYPE_STRING: - g_string_append (str, "string"); - if (is_invoke) - va_arg (args, gchar *); - break; - case RPC_TYPE_ARRAY: - g_string_append (str, "array of"); - was_array = TRUE; - break; - } - if (!is_invoke && type != RPC_TYPE_ARRAY) - va_arg (args, gpointer); + va_arg (args, guint32); + if (is_invoke) + va_arg (args, gpointer); } + switch (type) + { + case RPC_TYPE_CHAR: + g_string_append (str, "char"); + if (is_invoke && !was_array) + va_arg (args, int); + was_array = FALSE; + break; + case RPC_TYPE_BOOLEAN: + g_string_append (str, "bool"); + if (is_invoke && !was_array) + va_arg (args, int); + was_array = FALSE; + break; + case RPC_TYPE_INT32: + g_string_append (str, "int32"); + if (is_invoke && !was_array) + va_arg (args, gint32); + was_array = FALSE; + break; + case RPC_TYPE_UINT32: + g_string_append (str, "uint32"); + if (is_invoke && !was_array) + va_arg (args, guint32); + was_array = FALSE; + break; + case RPC_TYPE_UINT64: + g_string_append (str, "uint64"); + if (is_invoke && !was_array) + va_arg (args, guint64); + was_array = FALSE; + break; + case RPC_TYPE_DOUBLE: + g_string_append (str, "double"); + if (is_invoke && !was_array) + va_arg (args, gdouble); + was_array = FALSE; + break; + case RPC_TYPE_STRING: + g_string_append (str, "string"); + if (is_invoke && !was_array) + va_arg (args, gchar *); + was_array = FALSE; + break; + case RPC_TYPE_ARRAY: + /* XXX: don't allow array of arrays */ + if (!was_array) + { + g_string_append (str, "array of "); + was_array = TRUE; + break; + } + /* fall-through */ + default: + npw_printf ("ERROR: unknown type %d\n", type); + abort (); + } + if (!is_invoke && type != RPC_TYPE_ARRAY) + va_arg (args, gpointer); + } va_end (args); if (n_args == 0) - g_string_append (str, "void"); + g_string_append (str, "void"); g_print ("void f (%s)\n", str->str); g_string_free (str, TRUE); } -#define rpc_test_invoke(method, ...) do { \ - int error; \ - rpc_connection_t *connection; \ - connection = rpc_test_get_connection (); \ - rpc_test_signature (TRUE, __VA_ARGS__); \ +#define rpc_test_invoke(method, ...) do { \ + int error; \ + rpc_connection_t *connection; \ + connection = rpc_test_get_connection (); \ + rpc_test_signature (TRUE, __VA_ARGS__); \ error = rpc_method_invoke (connection, method, __VA_ARGS__); \ - g_assert (error == RPC_ERROR_NO_ERROR); \ - error = rpc_method_wait_for_reply (connection, RPC_TYPE_INVALID); \ - g_assert (error == RPC_ERROR_NO_ERROR); \ + RPC_TEST_ENSURE_NO_ERROR (error); \ + error = rpc_method_wait_for_reply (connection, RPC_TYPE_INVALID); \ + RPC_TEST_ENSURE_NO_ERROR (error); \ } while (0) -#define rpc_test_get_args(connection, ...) do { \ - int error; \ - rpc_test_signature (FALSE, __VA_ARGS__); \ - error = rpc_method_get_args (connection, __VA_ARGS__); \ - g_assert (error == RPC_ERROR_NO_ERROR); \ +#define rpc_test_get_args(connection, ...) do { \ + int error; \ + rpc_test_signature (FALSE, __VA_ARGS__); \ + error = rpc_method_get_args (connection, __VA_ARGS__); \ + RPC_TEST_ENSURE_NO_ERROR (error); \ } while (0) +static gchar g_char_array[] = + { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' }; +static gint32 g_int32_array[] = + { G_MININT32, G_MININT32+1, -2, -1, 0, 1, 2, G_MAXINT32-1, G_MAXINT32 }; +static guint64 g_uint64_array[] = + { 0, 1, G_MAXUINT32-1, G_MAXUINT32, G_MAXUINT32+1, G_MAXUINT64-1, G_MAXUINT64 }; +static gdouble g_double_array[] = + { -2.0, -1.0, 0.0, 1.0, 2.0 }; +static const gchar *g_string_array[] = + { "string", "", NULL, "another one" }; + #ifdef BUILD_SERVER typedef union _RPCTestArg RPCTestArg; @@ -148,15 +187,33 @@ union _RPCTestArg guint64 j; gdouble d; gchar *s; + struct { + gint l; + void *p; + } a; }; +#define RPC_TEST_ARG_CHAR c +#define RPC_TEST_ARG_BOOLEAN b +#define RPC_TEST_ARG_INT32 i +#define RPC_TEST_ARG_UINT32 u +#define RPC_TEST_ARG_UINT64 j +#define RPC_TEST_ARG_DOUBLE d +#define RPC_TEST_ARG_STRING s + static RPCTestArg g_args[RPC_TEST_MAX_ARGS]; +#define RPC_GET_ARG(N, TYPE) \ + RPC_TYPE_##TYPE, &g_args[N].RPC_TEST_ARG_##TYPE + +#define RPC_GET_ARRAY_ARG(N, TYPE) \ + RPC_TYPE_ARRAY, RPC_TYPE_##TYPE, &g_args[N].a.l, &g_args[N].a.p + static int handle_VOID__VOID (rpc_connection_t *connection) { rpc_test_get_args (connection, - RPC_TYPE_INVALID); + RPC_TYPE_INVALID); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } @@ -165,10 +222,10 @@ static int handle_VOID__CHAR (rpc_connection_t *connection) { rpc_test_get_args (connection, - RPC_TYPE_CHAR, &g_args[0].c, - RPC_TYPE_INVALID); + RPC_TYPE_CHAR, &g_args[0].c, + RPC_TYPE_INVALID); - g_assert (g_args[0].c == 'a'); + RPC_TEST_ENSURE (g_args[0].c == 'a'); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } @@ -177,28 +234,28 @@ static int handle_VOID__CHARx10 (rpc_connection_t *connection) { rpc_test_get_args (connection, - RPC_TYPE_CHAR, &g_args[0].c, - RPC_TYPE_CHAR, &g_args[1].c, - RPC_TYPE_CHAR, &g_args[2].c, - RPC_TYPE_CHAR, &g_args[3].c, - RPC_TYPE_CHAR, &g_args[4].c, - RPC_TYPE_CHAR, &g_args[5].c, - RPC_TYPE_CHAR, &g_args[6].c, - RPC_TYPE_CHAR, &g_args[7].c, - RPC_TYPE_CHAR, &g_args[8].c, - RPC_TYPE_CHAR, &g_args[9].c, - RPC_TYPE_INVALID); + RPC_TYPE_CHAR, &g_args[0].c, + RPC_TYPE_CHAR, &g_args[1].c, + RPC_TYPE_CHAR, &g_args[2].c, + RPC_TYPE_CHAR, &g_args[3].c, + RPC_TYPE_CHAR, &g_args[4].c, + RPC_TYPE_CHAR, &g_args[5].c, + RPC_TYPE_CHAR, &g_args[6].c, + RPC_TYPE_CHAR, &g_args[7].c, + RPC_TYPE_CHAR, &g_args[8].c, + RPC_TYPE_CHAR, &g_args[9].c, + RPC_TYPE_INVALID); - g_assert (g_args[0].c == 'a'); - g_assert (g_args[1].c == 'b'); - g_assert (g_args[2].c == 'c'); - g_assert (g_args[3].c == 'd'); - g_assert (g_args[4].c == 'e'); - g_assert (g_args[5].c == '1'); - g_assert (g_args[6].c == '2'); - g_assert (g_args[7].c == '3'); - g_assert (g_args[8].c == '4'); - g_assert (g_args[9].c == '5'); + RPC_TEST_ENSURE (g_args[0].c == 'a'); + RPC_TEST_ENSURE (g_args[1].c == 'b'); + RPC_TEST_ENSURE (g_args[2].c == 'c'); + RPC_TEST_ENSURE (g_args[3].c == 'd'); + RPC_TEST_ENSURE (g_args[4].c == 'e'); + RPC_TEST_ENSURE (g_args[5].c == '1'); + RPC_TEST_ENSURE (g_args[6].c == '2'); + RPC_TEST_ENSURE (g_args[7].c == '3'); + RPC_TEST_ENSURE (g_args[8].c == '4'); + RPC_TEST_ENSURE (g_args[9].c == '5'); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } @@ -207,10 +264,10 @@ static int handle_VOID__BOOL (rpc_connection_t *connection) { rpc_test_get_args (connection, - RPC_TYPE_BOOLEAN, &g_args[0].b, - RPC_TYPE_INVALID); + RPC_TYPE_BOOLEAN, &g_args[0].b, + RPC_TYPE_INVALID); - g_assert (g_args[0].b == TRUE); + RPC_TEST_ENSURE (g_args[0].b == TRUE); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } @@ -219,28 +276,28 @@ static int handle_VOID__BOOLx10 (rpc_connection_t *connection) { rpc_test_get_args (connection, - RPC_TYPE_BOOLEAN, &g_args[0].b, - RPC_TYPE_BOOLEAN, &g_args[1].b, - RPC_TYPE_BOOLEAN, &g_args[2].b, - RPC_TYPE_BOOLEAN, &g_args[3].b, - RPC_TYPE_BOOLEAN, &g_args[4].b, - RPC_TYPE_BOOLEAN, &g_args[5].b, - RPC_TYPE_BOOLEAN, &g_args[6].b, - RPC_TYPE_BOOLEAN, &g_args[7].b, - RPC_TYPE_BOOLEAN, &g_args[8].b, - RPC_TYPE_BOOLEAN, &g_args[9].b, - RPC_TYPE_INVALID); + RPC_TYPE_BOOLEAN, &g_args[0].b, + RPC_TYPE_BOOLEAN, &g_args[1].b, + RPC_TYPE_BOOLEAN, &g_args[2].b, + RPC_TYPE_BOOLEAN, &g_args[3].b, + RPC_TYPE_BOOLEAN, &g_args[4].b, + RPC_TYPE_BOOLEAN, &g_args[5].b, + RPC_TYPE_BOOLEAN, &g_args[6].b, + RPC_TYPE_BOOLEAN, &g_args[7].b, + RPC_TYPE_BOOLEAN, &g_args[8].b, + RPC_TYPE_BOOLEAN, &g_args[9].b, + RPC_TYPE_INVALID); - g_assert (g_args[0].b == TRUE); - g_assert (g_args[1].b == FALSE); - g_assert (g_args[2].b == TRUE); - g_assert (g_args[3].b == FALSE); - g_assert (g_args[4].b == TRUE); - g_assert (g_args[5].b == FALSE); - g_assert (g_args[6].b == TRUE); - g_assert (g_args[7].b == FALSE); - g_assert (g_args[8].b == TRUE); - g_assert (g_args[9].b == FALSE); + RPC_TEST_ENSURE (g_args[0].b == TRUE); + RPC_TEST_ENSURE (g_args[1].b == FALSE); + RPC_TEST_ENSURE (g_args[2].b == TRUE); + RPC_TEST_ENSURE (g_args[3].b == FALSE); + RPC_TEST_ENSURE (g_args[4].b == TRUE); + RPC_TEST_ENSURE (g_args[5].b == FALSE); + RPC_TEST_ENSURE (g_args[6].b == TRUE); + RPC_TEST_ENSURE (g_args[7].b == FALSE); + RPC_TEST_ENSURE (g_args[8].b == TRUE); + RPC_TEST_ENSURE (g_args[9].b == FALSE); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } @@ -249,28 +306,28 @@ static int handle_VOID__INT32x10 (rpc_connection_t *connection) { rpc_test_get_args (connection, - RPC_TYPE_INT32, &g_args[0].i, - RPC_TYPE_INT32, &g_args[1].i, - RPC_TYPE_INT32, &g_args[2].i, - RPC_TYPE_INT32, &g_args[3].i, - RPC_TYPE_INT32, &g_args[4].i, - RPC_TYPE_INT32, &g_args[5].i, - RPC_TYPE_INT32, &g_args[6].i, - RPC_TYPE_INT32, &g_args[7].i, - RPC_TYPE_INT32, &g_args[8].i, - RPC_TYPE_INT32, &g_args[9].i, - RPC_TYPE_INVALID); - - g_assert (g_args[0].i == 0); - g_assert (g_args[1].i == 1); - g_assert (g_args[2].i == -1); - g_assert (g_args[3].i == 2); - g_assert (g_args[4].i == -2); - g_assert (g_args[5].i == G_MAXINT32); - g_assert (g_args[6].i == G_MININT32); - g_assert (g_args[7].i == G_MAXINT32 - 1); - g_assert (g_args[8].i == G_MININT32 + 1); - g_assert (g_args[9].i == 0); + RPC_TYPE_INT32, &g_args[0].i, + RPC_TYPE_INT32, &g_args[1].i, + RPC_TYPE_INT32, &g_args[2].i, + RPC_TYPE_INT32, &g_args[3].i, + RPC_TYPE_INT32, &g_args[4].i, + RPC_TYPE_INT32, &g_args[5].i, + RPC_TYPE_INT32, &g_args[6].i, + RPC_TYPE_INT32, &g_args[7].i, + RPC_TYPE_INT32, &g_args[8].i, + RPC_TYPE_INT32, &g_args[9].i, + RPC_TYPE_INVALID); + + RPC_TEST_ENSURE (g_args[0].i == 0); + RPC_TEST_ENSURE (g_args[1].i == 1); + RPC_TEST_ENSURE (g_args[2].i == -1); + RPC_TEST_ENSURE (g_args[3].i == 2); + RPC_TEST_ENSURE (g_args[4].i == -2); + RPC_TEST_ENSURE (g_args[5].i == G_MAXINT32); + RPC_TEST_ENSURE (g_args[6].i == G_MININT32); + RPC_TEST_ENSURE (g_args[7].i == G_MAXINT32 - 1); + RPC_TEST_ENSURE (g_args[8].i == G_MININT32 + 1); + RPC_TEST_ENSURE (g_args[9].i == 0); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } @@ -279,28 +336,28 @@ static int handle_VOID__UINT32x10 (rpc_connection_t *connection) { rpc_test_get_args (connection, - RPC_TYPE_UINT32, &g_args[0].u, - RPC_TYPE_UINT32, &g_args[1].u, - RPC_TYPE_UINT32, &g_args[2].u, - RPC_TYPE_UINT32, &g_args[3].u, - RPC_TYPE_UINT32, &g_args[4].u, - RPC_TYPE_UINT32, &g_args[5].u, - RPC_TYPE_UINT32, &g_args[6].u, - RPC_TYPE_UINT32, &g_args[7].u, - RPC_TYPE_UINT32, &g_args[8].u, - RPC_TYPE_UINT32, &g_args[9].u, - RPC_TYPE_INVALID); + RPC_TYPE_UINT32, &g_args[0].u, + RPC_TYPE_UINT32, &g_args[1].u, + RPC_TYPE_UINT32, &g_args[2].u, + RPC_TYPE_UINT32, &g_args[3].u, + RPC_TYPE_UINT32, &g_args[4].u, + RPC_TYPE_UINT32, &g_args[5].u, + RPC_TYPE_UINT32, &g_args[6].u, + RPC_TYPE_UINT32, &g_args[7].u, + RPC_TYPE_UINT32, &g_args[8].u, + RPC_TYPE_UINT32, &g_args[9].u, + RPC_TYPE_INVALID); - g_assert (g_args[0].u == 0); - g_assert (g_args[1].u == 1); - g_assert (g_args[2].u == 0xffffffff); - g_assert (g_args[3].u == 2); - g_assert (g_args[4].u == 0xfffffffe); - g_assert (g_args[5].u == G_MAXUINT32); - g_assert (g_args[6].u == G_MAXUINT32 - 1); - g_assert (g_args[7].u == 0x80000000); - g_assert (g_args[8].u == 0x80000001); - g_assert (g_args[9].u == 0); + RPC_TEST_ENSURE (g_args[0].u == 0); + RPC_TEST_ENSURE (g_args[1].u == 1); + RPC_TEST_ENSURE (g_args[2].u == 0xffffffff); + RPC_TEST_ENSURE (g_args[3].u == 2); + RPC_TEST_ENSURE (g_args[4].u == 0xfffffffe); + RPC_TEST_ENSURE (g_args[5].u == G_MAXUINT32); + RPC_TEST_ENSURE (g_args[6].u == G_MAXUINT32 - 1); + RPC_TEST_ENSURE (g_args[7].u == 0x80000000); + RPC_TEST_ENSURE (g_args[8].u == 0x80000001); + RPC_TEST_ENSURE (g_args[9].u == 0); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } @@ -309,28 +366,28 @@ static int handle_VOID__UINT64x10 (rpc_connection_t *connection) { rpc_test_get_args (connection, - RPC_TYPE_UINT64, &g_args[0].j, - RPC_TYPE_UINT64, &g_args[1].j, - RPC_TYPE_UINT64, &g_args[2].j, - RPC_TYPE_UINT64, &g_args[3].j, - RPC_TYPE_UINT64, &g_args[4].j, - RPC_TYPE_UINT64, &g_args[5].j, - RPC_TYPE_UINT64, &g_args[6].j, - RPC_TYPE_UINT64, &g_args[7].j, - RPC_TYPE_UINT64, &g_args[8].j, - RPC_TYPE_UINT64, &g_args[9].j, - RPC_TYPE_INVALID); + RPC_TYPE_UINT64, &g_args[0].j, + RPC_TYPE_UINT64, &g_args[1].j, + RPC_TYPE_UINT64, &g_args[2].j, + RPC_TYPE_UINT64, &g_args[3].j, + RPC_TYPE_UINT64, &g_args[4].j, + RPC_TYPE_UINT64, &g_args[5].j, + RPC_TYPE_UINT64, &g_args[6].j, + RPC_TYPE_UINT64, &g_args[7].j, + RPC_TYPE_UINT64, &g_args[8].j, + RPC_TYPE_UINT64, &g_args[9].j, + RPC_TYPE_INVALID); - g_assert (g_args[0].j == 0); - g_assert (g_args[1].j == G_GINT64_CONSTANT (0x00000000000000ffU)); - g_assert (g_args[2].j == G_GINT64_CONSTANT (0x000000000000ff00U)); - g_assert (g_args[3].j == G_GINT64_CONSTANT (0x0000000000ff0000U)); - g_assert (g_args[4].j == G_GINT64_CONSTANT (0x00000000ff000000U)); - g_assert (g_args[5].j == G_GINT64_CONSTANT (0x000000ff00000000U)); - g_assert (g_args[6].j == G_GINT64_CONSTANT (0x0000ff0000000000U)); - g_assert (g_args[7].j == G_GINT64_CONSTANT (0x00ff000000000000U)); - g_assert (g_args[8].j == G_GINT64_CONSTANT (0xff00000000000000U)); - g_assert (g_args[9].j == G_GINT64_CONSTANT (0x0123456789abcdefU)); + RPC_TEST_ENSURE (g_args[0].j == 0); + RPC_TEST_ENSURE (g_args[1].j == G_GINT64_CONSTANT (0x00000000000000ffU)); + RPC_TEST_ENSURE (g_args[2].j == G_GINT64_CONSTANT (0x000000000000ff00U)); + RPC_TEST_ENSURE (g_args[3].j == G_GINT64_CONSTANT (0x0000000000ff0000U)); + RPC_TEST_ENSURE (g_args[4].j == G_GINT64_CONSTANT (0x00000000ff000000U)); + RPC_TEST_ENSURE (g_args[5].j == G_GINT64_CONSTANT (0x000000ff00000000U)); + RPC_TEST_ENSURE (g_args[6].j == G_GINT64_CONSTANT (0x0000ff0000000000U)); + RPC_TEST_ENSURE (g_args[7].j == G_GINT64_CONSTANT (0x00ff000000000000U)); + RPC_TEST_ENSURE (g_args[8].j == G_GINT64_CONSTANT (0xff00000000000000U)); + RPC_TEST_ENSURE (g_args[9].j == G_GINT64_CONSTANT (0x0123456789abcdefU)); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } @@ -339,18 +396,18 @@ static int handle_VOID__DOUBLEx5 (rpc_connection_t *connection) { rpc_test_get_args (connection, - RPC_TYPE_DOUBLE, &g_args[0].d, - RPC_TYPE_DOUBLE, &g_args[1].d, - RPC_TYPE_DOUBLE, &g_args[2].d, - RPC_TYPE_DOUBLE, &g_args[3].d, - RPC_TYPE_DOUBLE, &g_args[4].d, - RPC_TYPE_INVALID); + RPC_TYPE_DOUBLE, &g_args[0].d, + RPC_TYPE_DOUBLE, &g_args[1].d, + RPC_TYPE_DOUBLE, &g_args[2].d, + RPC_TYPE_DOUBLE, &g_args[3].d, + RPC_TYPE_DOUBLE, &g_args[4].d, + RPC_TYPE_INVALID); - g_assert (g_args[0].d == 0.0); - g_assert (g_args[1].d == 1.0); - g_assert (g_args[2].d == -1.0); - g_assert (g_args[3].d == 2.0); - g_assert (g_args[4].d == -2.0); + RPC_TEST_ENSURE (g_args[0].d == 0.0); + RPC_TEST_ENSURE (g_args[1].d == 1.0); + RPC_TEST_ENSURE (g_args[2].d == -1.0); + RPC_TEST_ENSURE (g_args[3].d == 2.0); + RPC_TEST_ENSURE (g_args[4].d == -2.0); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } @@ -359,16 +416,185 @@ static int handle_VOID__STRINGx3 (rpc_connection_t *connection) { rpc_test_get_args (connection, - RPC_TYPE_STRING, &g_args[0].s, - RPC_TYPE_STRING, &g_args[1].s, - RPC_TYPE_STRING, &g_args[2].s, - RPC_TYPE_INVALID); + RPC_TYPE_STRING, &g_args[0].s, + RPC_TYPE_STRING, &g_args[1].s, + RPC_TYPE_STRING, &g_args[2].s, + RPC_TYPE_INVALID); - g_assert (g_args[0].s && strcmp (g_args[0].s, "") == 0); + RPC_TEST_ENSURE (g_args[0].s && strcmp (g_args[0].s, "") == 0); free (g_args[0].s); - g_assert (g_args[1].s && strcmp (g_args[1].s, "one") == 0); + RPC_TEST_ENSURE (g_args[1].s && strcmp (g_args[1].s, "one") == 0); free (g_args[1].s); - g_assert (g_args[2].s == NULL); + RPC_TEST_ENSURE (g_args[2].s == NULL); + + return rpc_method_send_reply (connection, RPC_TYPE_INVALID); +} + +static int +handle_VOID__CHAR_ARRAY (rpc_connection_t *connection) +{ + guint32 len; + gchar *array; + + rpc_test_get_args (connection, + RPC_TYPE_ARRAY, RPC_TYPE_CHAR, &len, &array, + RPC_TYPE_INVALID); + + RPC_TEST_ENSURE (len == G_N_ELEMENTS (g_char_array)); + RPC_TEST_ENSURE (array != NULL); + for (int i = 0; i < len; i++) + RPC_TEST_ENSURE (array[i] == g_char_array[i]); + + free (array); + + return rpc_method_send_reply (connection, RPC_TYPE_INVALID); +} + +static int +handle_VOID__INT32_ARRAY (rpc_connection_t *connection) +{ + guint32 len; + gint32 *array; + + rpc_test_get_args (connection, + RPC_TYPE_ARRAY, RPC_TYPE_INT32, &len, &array, + RPC_TYPE_INVALID); + + RPC_TEST_ENSURE (len == G_N_ELEMENTS (g_int32_array)); + RPC_TEST_ENSURE (array != NULL); + for (int i = 0; i < len; i++) + RPC_TEST_ENSURE (array[i] == g_int32_array[i]); + + free (array); + + return rpc_method_send_reply (connection, RPC_TYPE_INVALID); +} + +static int +handle_VOID__UINT64_ARRAY (rpc_connection_t *connection) +{ + guint32 len; + guint64 *array; + + rpc_test_get_args (connection, + RPC_TYPE_ARRAY, RPC_TYPE_UINT64, &len, &array, + RPC_TYPE_INVALID); + + RPC_TEST_ENSURE (len == G_N_ELEMENTS (g_uint64_array)); + RPC_TEST_ENSURE (array != NULL); + for (int i = 0; i < len; i++) + RPC_TEST_ENSURE (array[i] == g_uint64_array[i]); + + free (array); + + return rpc_method_send_reply (connection, RPC_TYPE_INVALID); +} + +static int +handle_VOID__DOUBLE_ARRAY (rpc_connection_t *connection) +{ + guint32 len; + gdouble *array; + + rpc_test_get_args (connection, + RPC_TYPE_ARRAY, RPC_TYPE_DOUBLE, &len, &array, + RPC_TYPE_INVALID); + + RPC_TEST_ENSURE (len == G_N_ELEMENTS (g_double_array)); + RPC_TEST_ENSURE (array != NULL); + for (int i = 0; i < len; i++) + RPC_TEST_ENSURE (array[i] == g_double_array[i]); + + free (array); + + return rpc_method_send_reply (connection, RPC_TYPE_INVALID); +} + +static int +handle_VOID__STRING_ARRAY (rpc_connection_t *connection) +{ + guint32 len; + gchar **array; + + rpc_test_get_args (connection, + RPC_TYPE_ARRAY, RPC_TYPE_STRING, &len, &array, + RPC_TYPE_INVALID); + + RPC_TEST_ENSURE (len == G_N_ELEMENTS (g_string_array)); + RPC_TEST_ENSURE (array != NULL); + for (int i = 0; i < len; i++) + { + if (g_string_array[i]) + { + RPC_TEST_ENSURE (array[i] != NULL); + RPC_TEST_ENSURE (strcmp (array[i], g_string_array[i]) == 0); + + free (array[i]); + } + else + RPC_TEST_ENSURE (array[i] == NULL); + } + + free (array); + + return rpc_method_send_reply (connection, RPC_TYPE_INVALID); +} + +static int +handle_VOID__NULL_ARRAY_with_length (rpc_connection_t *connection, + gint32 expected_length) +{ + gint32 len; + gchar *array = GUINT_TO_POINTER (0xdeadbeef); + + rpc_test_get_args (connection, + RPC_TYPE_ARRAY, RPC_TYPE_CHAR, &len, &array, + RPC_TYPE_INVALID); + + RPC_TEST_ENSURE (len == expected_length); + RPC_TEST_ENSURE (array == NULL); + + return rpc_method_send_reply (connection, RPC_TYPE_INVALID); +} + +static int +handle_VOID__NULL_ARRAY (rpc_connection_t *connection) +{ + return handle_VOID__NULL_ARRAY_with_length (connection, 1); +} + +static int +handle_VOID__0LEN_ARRAY (rpc_connection_t *connection) +{ + return handle_VOID__NULL_ARRAY_with_length (connection, 0); +} + +static int +handle_VOID__MIXED_ARRAY (rpc_connection_t *connection) +{ + rpc_test_get_args (connection, + RPC_GET_ARRAY_ARG (0, CHAR), + RPC_GET_ARRAY_ARG (1, CHAR), + RPC_GET_ARRAY_ARG (2, CHAR), + RPC_GET_ARRAY_ARG (3, CHAR), + RPC_GET_ARRAY_ARG (4, CHAR), + RPC_TYPE_INVALID); + + RPC_TEST_ENSURE (g_args[0].a.l == G_N_ELEMENTS (g_char_array)); + RPC_TEST_ENSURE (g_args[0].a.p != NULL); + RPC_TEST_ENSURE (memcmp (g_args[0].a.p, g_char_array, g_args[0].a.l) == 0); + RPC_TEST_ENSURE (g_args[1].a.l == G_N_ELEMENTS (g_char_array)); + RPC_TEST_ENSURE (g_args[1].a.p != NULL); + RPC_TEST_ENSURE (memcmp (g_args[1].a.p, g_char_array, g_args[1].a.l) == 0); + RPC_TEST_ENSURE (g_args[2].a.l == 0); + RPC_TEST_ENSURE (g_args[2].a.p == NULL); + RPC_TEST_ENSURE (g_args[3].a.l == 0); + RPC_TEST_ENSURE (g_args[3].a.p == NULL); + RPC_TEST_ENSURE (g_args[4].a.l == 1); + RPC_TEST_ENSURE (g_args[4].a.p == NULL); + + free (g_args[0].a.p); + free (g_args[1].a.p); return rpc_method_send_reply (connection, RPC_TYPE_INVALID); } @@ -382,25 +608,33 @@ rpc_test_init (int argc, char *argv[]) static const rpc_method_descriptor_t vtable[] = { - { RPC_TEST_METHOD_VOID__VOID, handle_VOID__VOID }, - { RPC_TEST_METHOD_VOID__CHAR, handle_VOID__CHAR }, - { RPC_TEST_METHOD_VOID__CHARx10, handle_VOID__CHARx10 }, - { RPC_TEST_METHOD_VOID__BOOL, handle_VOID__BOOL }, - { RPC_TEST_METHOD_VOID__BOOLx10, handle_VOID__BOOLx10 }, - { RPC_TEST_METHOD_VOID__INT32x10, handle_VOID__INT32x10 }, - { RPC_TEST_METHOD_VOID__UINT32x10, handle_VOID__UINT32x10 }, - { RPC_TEST_METHOD_VOID__UINT64x10, handle_VOID__UINT64x10 }, - { RPC_TEST_METHOD_VOID__DOUBLEx5, handle_VOID__DOUBLEx5 }, - { RPC_TEST_METHOD_VOID__STRINGx3, handle_VOID__STRINGx3 }, + { RPC_TEST_METHOD_VOID__VOID, handle_VOID__VOID }, + { RPC_TEST_METHOD_VOID__CHAR, handle_VOID__CHAR }, + { RPC_TEST_METHOD_VOID__CHARx10, handle_VOID__CHARx10 }, + { RPC_TEST_METHOD_VOID__BOOL, handle_VOID__BOOL }, + { RPC_TEST_METHOD_VOID__BOOLx10, handle_VOID__BOOLx10 }, + { RPC_TEST_METHOD_VOID__INT32x10, handle_VOID__INT32x10 }, + { RPC_TEST_METHOD_VOID__UINT32x10, handle_VOID__UINT32x10 }, + { RPC_TEST_METHOD_VOID__UINT64x10, handle_VOID__UINT64x10 }, + { RPC_TEST_METHOD_VOID__DOUBLEx5, handle_VOID__DOUBLEx5 }, + { RPC_TEST_METHOD_VOID__STRINGx3, handle_VOID__STRINGx3 }, + { RPC_TEST_METHOD_VOID__CHAR_ARRAY, handle_VOID__CHAR_ARRAY }, + { RPC_TEST_METHOD_VOID__INT32_ARRAY, handle_VOID__INT32_ARRAY }, + { RPC_TEST_METHOD_VOID__UINT64_ARRAY, handle_VOID__UINT64_ARRAY }, + { RPC_TEST_METHOD_VOID__DOUBLE_ARRAY, handle_VOID__DOUBLE_ARRAY }, + { RPC_TEST_METHOD_VOID__STRING_ARRAY, handle_VOID__STRING_ARRAY }, + { RPC_TEST_METHOD_VOID__NULL_ARRAY, handle_VOID__NULL_ARRAY }, + { RPC_TEST_METHOD_VOID__0LEN_ARRAY, handle_VOID__0LEN_ARRAY }, + { RPC_TEST_METHOD_VOID__MIXED_ARRAY, handle_VOID__MIXED_ARRAY } }; connection = rpc_test_get_connection (); - g_assert (connection != NULL); + RPC_TEST_ENSURE (connection != NULL); if (rpc_connection_add_method_descriptors(connection, - vtable, - G_N_ELEMENTS (vtable)) < 0) - g_error ("could not add method descriptors"); + vtable, + G_N_ELEMENTS (vtable)) < 0) + g_error ("could not add method descriptors"); #endif return 0; @@ -410,95 +644,140 @@ int rpc_test_execute (gpointer user_data) { #ifdef BUILD_CLIENT + /* Basic types */ rpc_test_invoke (RPC_TEST_METHOD_VOID__VOID, - RPC_TYPE_INVALID); + RPC_TYPE_INVALID); rpc_test_invoke (RPC_TEST_METHOD_VOID__CHAR, - RPC_TYPE_CHAR, 'a', - RPC_TYPE_INVALID); + RPC_TYPE_CHAR, 'a', + RPC_TYPE_INVALID); rpc_test_invoke (RPC_TEST_METHOD_VOID__CHARx10, - RPC_TYPE_CHAR, 'a', - RPC_TYPE_CHAR, 'b', - RPC_TYPE_CHAR, 'c', - RPC_TYPE_CHAR, 'd', - RPC_TYPE_CHAR, 'e', - RPC_TYPE_CHAR, '1', - RPC_TYPE_CHAR, '2', - RPC_TYPE_CHAR, '3', - RPC_TYPE_CHAR, '4', - RPC_TYPE_CHAR, '5', - RPC_TYPE_INVALID); + RPC_TYPE_CHAR, 'a', + RPC_TYPE_CHAR, 'b', + RPC_TYPE_CHAR, 'c', + RPC_TYPE_CHAR, 'd', + RPC_TYPE_CHAR, 'e', + RPC_TYPE_CHAR, '1', + RPC_TYPE_CHAR, '2', + RPC_TYPE_CHAR, '3', + RPC_TYPE_CHAR, '4', + RPC_TYPE_CHAR, '5', + RPC_TYPE_INVALID); rpc_test_invoke (RPC_TEST_METHOD_VOID__BOOL, - RPC_TYPE_BOOLEAN, TRUE, - RPC_TYPE_INVALID); + RPC_TYPE_BOOLEAN, TRUE, + RPC_TYPE_INVALID); rpc_test_invoke (RPC_TEST_METHOD_VOID__BOOLx10, - RPC_TYPE_BOOLEAN, TRUE, - RPC_TYPE_BOOLEAN, FALSE, - RPC_TYPE_BOOLEAN, TRUE, - RPC_TYPE_BOOLEAN, FALSE, - RPC_TYPE_BOOLEAN, TRUE, - RPC_TYPE_BOOLEAN, FALSE, - RPC_TYPE_BOOLEAN, TRUE, - RPC_TYPE_BOOLEAN, FALSE, - RPC_TYPE_BOOLEAN, TRUE, - RPC_TYPE_BOOLEAN, FALSE, - RPC_TYPE_INVALID); + RPC_TYPE_BOOLEAN, TRUE, + RPC_TYPE_BOOLEAN, FALSE, + RPC_TYPE_BOOLEAN, TRUE, + RPC_TYPE_BOOLEAN, FALSE, + RPC_TYPE_BOOLEAN, TRUE, + RPC_TYPE_BOOLEAN, FALSE, + RPC_TYPE_BOOLEAN, TRUE, + RPC_TYPE_BOOLEAN, FALSE, + RPC_TYPE_BOOLEAN, TRUE, + RPC_TYPE_BOOLEAN, FALSE, + RPC_TYPE_INVALID); rpc_test_invoke (RPC_TEST_METHOD_VOID__INT32x10, - RPC_TYPE_INT32, 0, - RPC_TYPE_INT32, 1, - RPC_TYPE_INT32, -1, - RPC_TYPE_INT32, 2, - RPC_TYPE_INT32, -2, - RPC_TYPE_INT32, G_MAXINT32, - RPC_TYPE_INT32, G_MININT32, - RPC_TYPE_INT32, G_MAXINT32 - 1, - RPC_TYPE_INT32, G_MININT32 + 1, - RPC_TYPE_INT32, 0, - RPC_TYPE_INVALID); + RPC_TYPE_INT32, 0, + RPC_TYPE_INT32, 1, + RPC_TYPE_INT32, -1, + RPC_TYPE_INT32, 2, + RPC_TYPE_INT32, -2, + RPC_TYPE_INT32, G_MAXINT32, + RPC_TYPE_INT32, G_MININT32, + RPC_TYPE_INT32, G_MAXINT32 - 1, + RPC_TYPE_INT32, G_MININT32 + 1, + RPC_TYPE_INT32, 0, + RPC_TYPE_INVALID); rpc_test_invoke (RPC_TEST_METHOD_VOID__UINT32x10, - RPC_TYPE_UINT32, 0, - RPC_TYPE_UINT32, 1, - RPC_TYPE_UINT32, 0xffffffff, - RPC_TYPE_UINT32, 2, - RPC_TYPE_UINT32, 0xfffffffe, - RPC_TYPE_UINT32, G_MAXUINT32, - RPC_TYPE_UINT32, G_MAXUINT32 - 1, - RPC_TYPE_UINT32, 0x80000000, - RPC_TYPE_UINT32, 0x80000001, - RPC_TYPE_UINT32, 0, - RPC_TYPE_INVALID); + RPC_TYPE_UINT32, 0, + RPC_TYPE_UINT32, 1, + RPC_TYPE_UINT32, 0xffffffff, + RPC_TYPE_UINT32, 2, + RPC_TYPE_UINT32, 0xfffffffe, + RPC_TYPE_UINT32, G_MAXUINT32, + RPC_TYPE_UINT32, G_MAXUINT32 - 1, + RPC_TYPE_UINT32, 0x80000000, + RPC_TYPE_UINT32, 0x80000001, + RPC_TYPE_UINT32, 0, + RPC_TYPE_INVALID); rpc_test_invoke (RPC_TEST_METHOD_VOID__UINT64x10, - RPC_TYPE_UINT64, 0, - RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x00000000000000ffU), - RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x000000000000ff00U), - RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x0000000000ff0000U), - RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x00000000ff000000U), - RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x000000ff00000000U), - RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x0000ff0000000000U), - RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x00ff000000000000U), - RPC_TYPE_UINT64, G_GINT64_CONSTANT (0xff00000000000000U), - RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x0123456789abcdefU), - RPC_TYPE_INVALID); + RPC_TYPE_UINT64, 0, + RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x00000000000000ffU), + RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x000000000000ff00U), + RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x0000000000ff0000U), + RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x00000000ff000000U), + RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x000000ff00000000U), + RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x0000ff0000000000U), + RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x00ff000000000000U), + RPC_TYPE_UINT64, G_GINT64_CONSTANT (0xff00000000000000U), + RPC_TYPE_UINT64, G_GINT64_CONSTANT (0x0123456789abcdefU), + RPC_TYPE_INVALID); rpc_test_invoke (RPC_TEST_METHOD_VOID__DOUBLEx5, - RPC_TYPE_DOUBLE, 0.0, - RPC_TYPE_DOUBLE, 1.0, - RPC_TYPE_DOUBLE, -1.0, - RPC_TYPE_DOUBLE, 2.0, - RPC_TYPE_DOUBLE, -2.0, - RPC_TYPE_INVALID); + RPC_TYPE_DOUBLE, 0.0, + RPC_TYPE_DOUBLE, 1.0, + RPC_TYPE_DOUBLE, -1.0, + RPC_TYPE_DOUBLE, 2.0, + RPC_TYPE_DOUBLE, -2.0, + RPC_TYPE_INVALID); rpc_test_invoke (RPC_TEST_METHOD_VOID__STRINGx3, - RPC_TYPE_STRING, "", - RPC_TYPE_STRING, "one", - RPC_TYPE_STRING, NULL, - RPC_TYPE_INVALID); + RPC_TYPE_STRING, "", + RPC_TYPE_STRING, "one", + RPC_TYPE_STRING, NULL, + RPC_TYPE_INVALID); + + /* Arrays */ + rpc_test_invoke (RPC_TEST_METHOD_VOID__CHAR_ARRAY, + RPC_TYPE_ARRAY, RPC_TYPE_CHAR, + (gint32)G_N_ELEMENTS (g_char_array), g_char_array, + RPC_TYPE_INVALID); + + rpc_test_invoke (RPC_TEST_METHOD_VOID__INT32_ARRAY, + RPC_TYPE_ARRAY, RPC_TYPE_INT32, + (gint32)G_N_ELEMENTS (g_int32_array), g_int32_array, + RPC_TYPE_INVALID); + + rpc_test_invoke (RPC_TEST_METHOD_VOID__UINT64_ARRAY, + RPC_TYPE_ARRAY, RPC_TYPE_UINT64, + (gint32)G_N_ELEMENTS (g_uint64_array), g_uint64_array, + RPC_TYPE_INVALID); + + rpc_test_invoke (RPC_TEST_METHOD_VOID__DOUBLE_ARRAY, + RPC_TYPE_ARRAY, RPC_TYPE_DOUBLE, + (gint32)G_N_ELEMENTS (g_double_array), g_double_array, + RPC_TYPE_INVALID); + + rpc_test_invoke (RPC_TEST_METHOD_VOID__STRING_ARRAY, + RPC_TYPE_ARRAY, RPC_TYPE_STRING, + (gint32)G_N_ELEMENTS (g_string_array), g_string_array, + RPC_TYPE_INVALID); + + rpc_test_invoke (RPC_TEST_METHOD_VOID__NULL_ARRAY, + RPC_TYPE_ARRAY, RPC_TYPE_CHAR, 1, NULL, + RPC_TYPE_INVALID); + + rpc_test_invoke (RPC_TEST_METHOD_VOID__0LEN_ARRAY, + RPC_TYPE_ARRAY, RPC_TYPE_CHAR, 0, g_char_array, + RPC_TYPE_INVALID); + + rpc_test_invoke (RPC_TEST_METHOD_VOID__MIXED_ARRAY, + RPC_TYPE_ARRAY, RPC_TYPE_CHAR, + (gint32)G_N_ELEMENTS (g_char_array), g_char_array, + RPC_TYPE_ARRAY, RPC_TYPE_CHAR, + (gint32)G_N_ELEMENTS (g_char_array), g_char_array, + RPC_TYPE_ARRAY, RPC_TYPE_CHAR, 0, NULL, + RPC_TYPE_ARRAY, RPC_TYPE_CHAR, 0, g_char_array, + RPC_TYPE_ARRAY, RPC_TYPE_CHAR, 1, NULL, + RPC_TYPE_INVALID); #endif return RPC_TEST_EXECUTE_SUCCESS; } diff --git a/utils/npw-shadow.c b/utils/npw-shadow.c deleted file mode 100644 index de2cfaf..0000000 --- a/utils/npw-shadow.c +++ /dev/null @@ -1,1069 +0,0 @@ -#define _GNU_SOURCE 1 -#include "sysdeps.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define XP_UNIX 1 -#define MOZ_X11 1 -#include -#include - -#define DEBUG 1 -#include "debug.h" - - -// XXX unimplemented functions -#define UNIMPLEMENTED() npw_printf("WARNING: Unimplemented function %s at line %d\n", __func__, __LINE__) - -// Path to plugin to use -static const char *g_plugin_path = "/home/gb/npshadow-impl.so"; - -// Netscape exported functions -static NPNetscapeFuncs g_mozilla_funcs; - -// Functions supplied by the plug-in -static NPPluginFuncs g_plugin_funcs; - -// Plugin instance -typedef struct { - NPP instance; - NPP npn_instance; - Window old_window; - Window window; - Widget top_widget; - Widget form; - int width, height; -} PluginInstance; - -// Plugin implementation -static int g_plugin_initialized = 0; -static void *g_plugin_handle = NULL; - -// Allows the browser to query the plug-in supported formats -typedef char * (*NP_GetMIMEDescriptionUPP)(void); -static NP_GetMIMEDescriptionUPP g_NP_GetMIMEDescription = NULL; - -// Allows the browser to query the plug-in for information -typedef NPError (*NP_GetValueUPP)(void *instance, NPPVariable variable, void *value); -static NP_GetValueUPP g_NP_GetValue = NULL; - -// Provides global initialization for a plug-in -typedef NPError (*NP_InitializeUPP)(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs); -static NP_InitializeUPP g_NP_Initialize = NULL; - -// Provides global deinitialization for a plug-in -typedef NPError (*NP_ShutdownUPP)(void); -static NP_ShutdownUPP g_NP_Shutdown = NULL; - - -/* ====================================================================== */ -/* === X Toolkit glue === */ -/* ====================================================================== */ - -static Display *x_display; -static XtAppContext x_app_context; - -typedef struct _XtTMRec { - XtTranslations translations; /* private to Translation Manager */ - XtBoundActions proc_table; /* procedure bindings for actions */ - struct _XtStateRec *current_state; /* Translation Manager state ptr */ - unsigned long lastEventTime; -} XtTMRec, *XtTM; - -typedef struct _CorePart { - Widget self; /* pointer to widget itself */ - WidgetClass widget_class; /* pointer to Widget's ClassRec */ - Widget parent; /* parent widget */ - XrmName xrm_name; /* widget resource name quarkified */ - Boolean being_destroyed; /* marked for destroy */ - XtCallbackList destroy_callbacks; /* who to call when widget destroyed */ - XtPointer constraints; /* constraint record */ - Position x, y; /* window position */ - Dimension width, height; /* window dimensions */ - Dimension border_width; /* window border width */ - Boolean managed; /* is widget geometry managed? */ - Boolean sensitive; /* is widget sensitive to user events*/ - Boolean ancestor_sensitive; /* are all ancestors sensitive? */ - XtEventTable event_table; /* private to event dispatcher */ - XtTMRec tm; /* translation management */ - XtTranslations accelerators; /* accelerator translations */ - Pixel border_pixel; /* window border pixel */ - Pixmap border_pixmap; /* window border pixmap or NULL */ - WidgetList popup_list; /* list of popups */ - Cardinal num_popups; /* how many popups */ - String name; /* widget resource name */ - Screen *screen; /* window's screen */ - Colormap colormap; /* colormap */ - Window window; /* window ID */ - Cardinal depth; /* number of planes in window */ - Pixel background_pixel; /* window background pixel */ - Pixmap background_pixmap; /* window background pixmap or NULL */ - Boolean visible; /* is window mapped and not occluded?*/ - Boolean mapped_when_managed;/* map window if it's managed? */ -} CorePart; - -typedef struct _WidgetRec { - CorePart core; -} WidgetRec, CoreRec; - - -/* ====================================================================== */ -/* === Plugin glue === */ -/* ====================================================================== */ - -// Initialize plugin wrapper -static void __attribute__((constructor)) -plugin_init(void) -{ - if (g_plugin_initialized) - return; - - D(bug("plugin_init\n")); - - XtToolkitInitialize(); - x_app_context = XtCreateApplicationContext(); - int argc = 0; - x_display = XtOpenDisplay(x_app_context, NULL, "npw-viewer", "npw-viewer", NULL, 0, &argc, NULL); - - if ((g_plugin_handle = dlopen(g_plugin_path, RTLD_LAZY)) == NULL) { - npw_printf("ERROR: %s\n", dlerror()); - g_plugin_initialized = -1; - return; - } - { - const char *error; - dlerror(); - g_NP_GetMIMEDescription = (NP_GetMIMEDescriptionUPP)dlsym(g_plugin_handle, "NP_GetMIMEDescription"); - if ((error = dlerror()) != NULL) { - npw_printf("ERROR: %s\n", error); - g_plugin_initialized = -1; - return; - } - g_NP_Initialize = (NP_InitializeUPP)dlsym(g_plugin_handle, "NP_Initialize"); - if ((error = dlerror()) != NULL) { - npw_printf("ERROR: %s\n", error); - g_plugin_initialized = -1; - return; - } - g_NP_Shutdown = (NP_ShutdownUPP)dlsym(g_plugin_handle, "NP_Shutdown"); - if ((error = dlerror()) != NULL) { - npw_printf("ERROR: %s\n", error); - g_plugin_initialized = -1; - return; - } - g_NP_GetValue = (NP_GetValueUPP)dlsym(g_plugin_handle, "NP_GetValue"); - } - - g_plugin_initialized = 1; -} - -// Kill plugin wrapper -static void __attribute__((destructor)) -plugin_exit(void) -{ - D(bug("plugin_exit\n")); - - if (g_plugin_handle) - dlclose(g_plugin_handle); -} - - -/* ====================================================================== */ -/* === Browser side plug-in API === */ -/* ====================================================================== */ - -// Closes and deletes a stream -NPError -g_NPN_DestroyStream(NPP instance, NPStream *stream, NPError reason) -{ - D(bug("NPN_DestroyStream instance=%p\n", instance)); - UNIMPLEMENTED(); - - return NPERR_GENERIC_ERROR; -} - -// Forces a repaint message for a windowless plug-in -void -g_NPN_ForceRedraw(NPP instance) -{ - D(bug("NPN_ForceRedraw instance=%p\n", instance)); - UNIMPLEMENTED(); -} - -// Asks the browser to create a stream for the specified URL -NPError -g_NPN_GetURL(NPP instance, const char *url, const char *target) -{ - D(bug("NPN_GetURL instance=%p\n", instance)); - - if (instance == NULL) - return NPERR_INVALID_INSTANCE_ERROR; - - PluginInstance *plugin = instance->ndata; - - if (!g_mozilla_funcs.geturl) - return NPERR_GENERIC_ERROR; - - D(bug(" instance=%p, url='%s', target='%s'\n", plugin->npn_instance, url, target)); - NPError ret = g_mozilla_funcs.geturl(plugin->npn_instance, url, target); - - D(bug(" return: %d\n", ret)); - return ret; -} - -// Requests creation of a new stream with the contents of the specified URL -NPError -g_NPN_GetURLNotify(NPP instance, const char *url, const char *target, void *notifyData) -{ - D(bug("NPN_GetURLNotify instance=%p\n", instance)); - - if (instance == NULL) - return NPERR_INVALID_INSTANCE_ERROR; - - PluginInstance *plugin = instance->ndata; - - NPP the_instance; - if (plugin->instance->pdata == plugin) - the_instance = plugin->npn_instance; - else - the_instance = instance; - - if (!g_mozilla_funcs.geturlnotify) - return NPERR_GENERIC_ERROR; - - D(bug(" instance=%p, url='%s', target='%s', notifyData=%p\n", the_instance, url, target, notifyData)); - NPError ret = g_mozilla_funcs.geturlnotify(plugin->npn_instance, url, target, notifyData); - - D(bug(" return: %d\n", ret)); - return ret; -} - -// Allows the plug-in to query the browser for information -NPError -g_NPN_GetValue(NPP instance, NPNVariable variable, void *value) -{ - D(bug("NPN_GetValue instance=%p, variable=%d\n", instance, variable)); - -#if 0 - if (instance == NULL) - return NPERR_INVALID_INSTANCE_ERROR; - - PluginInstance *plugin = instance->ndata; - - if (!g_mozilla_funcs.getvalue) - return NPERR_GENERIC_ERROR; - - NPError ret = g_mozilla_funcs.getvalue(plugin->npn_instance, variable, value); -#else - NPError ret; - switch (variable) { - case NPNVxDisplay: - *(void **)value = x_display; - ret = NPERR_NO_ERROR; - break; - case NPNVxtAppContext: - *(void **)value = XtDisplayToApplicationContext(x_display); - ret = NPERR_NO_ERROR; - break; - default: - npw_printf("WARNING: unhandled variable %d for NPN_GetValue\n", variable); - ret = NPERR_INVALID_PARAM; - } -#endif - - D(bug(" return: %d\n", ret)); - return ret; -} - -// Invalidates specified drawing area prior to repainting or refreshing a windowless plug-in -void -g_NPN_InvalidateRect(NPP instance, NPRect *invalidRect) -{ - D(bug("NPN_InvalidateRect instance=%p\n", instance)); - UNIMPLEMENTED(); -} - -// Invalidates specified region prior to repainting or refreshing a windowless plug-in -void -g_NPN_InvalidateRegion(NPP instance, NPRegion invalidRegion) -{ - D(bug("NPN_InvalidateRegion instance=%p\n", instance)); - UNIMPLEMENTED(); -} - -// Allocates memory from the browser's memory space -void * -g_NPN_MemAlloc(uint32 size) -{ - D(bug("NPN_MemAlloc size=%d\n", size)); - - return malloc(size); -} - -// Requests that the browser free a specified amount of memory -uint32 -g_NPN_MemFlush(uint32 size) -{ - D(bug("NPN_MemFlush size=%d\n", size)); - UNIMPLEMENTED(); - - return 0; -} - -// Deallocates a block of allocated memory -void -g_NPN_MemFree(void *ptr) -{ - D(bug("NPN_MemFree ptr=%p\n", ptr)); - - free(ptr); -} - -// Requests the creation of a new data stream produced by the plug-in and consumed by the browser -NPError -g_NPN_NewStream(NPP instance, NPMIMEType type, const char *target, NPStream **stream) -{ - D(bug("NPN_NewStream instance=%p\n", instance)); - UNIMPLEMENTED(); - - return NPERR_GENERIC_ERROR; -} - -// Posts data to a URL -NPError -g_NPN_PostURL(NPP instance, const char *url, const char *target, uint32 len, const char *buf, NPBool file) -{ - D(bug("NPN_PostURL instance=%p\n", instance)); - UNIMPLEMENTED(); - - return NPERR_GENERIC_ERROR; -} - -// Posts data to a URL, and receives notification of the result -NPError -g_NPN_PostURLNotify(NPP instance, const char *url, const char *target, uint32 len, const char *buf, NPBool file, void *notifyData) -{ - D(bug("NPN_PostURLNotify instance=%p\n", instance)); - UNIMPLEMENTED(); - - return NPERR_GENERIC_ERROR; -} - -// Posts data to a URL, and receives notification of the result -void -g_NPN_ReloadPlugins(NPBool reloadPages) -{ - D(bug("NPN_ReloadPlugins reloadPages=%d\n", reloadPages)); - UNIMPLEMENTED(); -} - -// Returns the Java execution environment -JRIEnv * -g_NPN_GetJavaEnv(void) -{ - D(bug("NPN_GetJavaEnv\n")); - UNIMPLEMENTED(); - - return NULL; -} - -// Returns the Java object associated with the plug-in instance -jref -g_NPN_GetJavaPeer(NPP instance) -{ - D(bug("NPN_GetJavaPeer instance=%p\n", instance)); - UNIMPLEMENTED(); - - return NULL; -} - -// Requests a range of bytes for a seekable stream -NPError -g_NPN_RequestRead(NPStream *stream, NPByteRange *rangeList) -{ - D(bug("NPN_RequestRead stream=%p\n", stream)); - UNIMPLEMENTED(); - - return NPERR_GENERIC_ERROR; -} - -// Sets various modes of plug-in operation -NPError -g_NPN_SetValue(NPP instance, NPPVariable variable, void *value) -{ - D(bug("NPN_SetValue instance=%p\n", instance)); - UNIMPLEMENTED(); - - return NPERR_GENERIC_ERROR; -} - -// Displays a message on the status line of the browser window -void -g_NPN_Status(NPP instance, const char *message) -{ - D(bug("NPN_Status instance=%p\n", instance)); - - if (instance == NULL) - return; - - PluginInstance *plugin = instance->ndata; - - if (!g_mozilla_funcs.status) - return; - - g_mozilla_funcs.status(plugin->npn_instance, message); -} - -// Returns the browser's user agent field -const char * -g_NPN_UserAgent(NPP instance) -{ - D(bug("NPN_UserAgent instance=%p\n", instance)); - - NPP my_instance = NULL; - if (instance) - my_instance = ((PluginInstance *)instance->ndata)->npn_instance; - - if (!g_mozilla_funcs.uagent) - return NULL; - - // const char *user_agent = g_mozilla_funcs.uagent(my_instance); - const char *user_agent = NULL; - - D(bug(" user_agent='%s'\n", user_agent)); - return user_agent; -} - -// Returns version information for the Plug-in API -void -g_NPN_Version(int *plugin_major, int *plugin_minor, int *netscape_major, int *netscape_minor) -{ - D(bug("NPN_Version\n")); - UNIMPLEMENTED(); -} - -// Pushes data into a stream produced by the plug-in and consumed by the browser -int32 -g_NPN_Write(NPP instance, NPStream *stream, int32 len, void *buf) -{ - D(bug("NPN_Write instance=%d\n", instance)); - UNIMPLEMENTED(); - - return -1; -} - - -/* ====================================================================== */ -/* === Plug-in side data === */ -/* ====================================================================== */ - -// Creates a new instance of a plug-in -static NPError -g_NPP_New(NPMIMEType mime_type, NPP instance, - uint16_t mode, int16_t argc, char *argn[], char *argv[], - NPSavedData *saved) -{ - D(bug("NPP_New instance=%p\n", instance)); - - if (instance == NULL) - return NPERR_INVALID_INSTANCE_ERROR; - - if (!g_plugin_funcs.newp) - return NPERR_GENERIC_ERROR; - - if ((uintptr_t)instance > 0xffffffffUL) { - npw_printf("ERROR: FIXME: 64-bit instance doesn't fit!\n"); - return NPERR_GENERIC_ERROR; - } - - if (saved) - npw_printf("WARNING: NPP_New with non-null saved arguments\n"); - - PluginInstance *plugin = malloc(sizeof(*plugin)); - if (plugin == NULL) - return NPERR_OUT_OF_MEMORY_ERROR; - memset(plugin, 0, sizeof(*plugin)); - plugin->instance = malloc(sizeof(*plugin->instance)); - if (plugin->instance == NULL) - return NPERR_OUT_OF_MEMORY_ERROR; - plugin->instance->ndata = plugin; - - instance->pdata = (void *)plugin; - plugin->npn_instance = instance; - NPError ret = g_plugin_funcs.newp(mime_type, plugin->instance, mode, argc, argn, argv, saved); - if (plugin->npn_instance != instance) - npw_printf("############# OOOFDOFDF \n"); - D(bug(" plugin instance: %p\n", plugin->instance)); - instance->pdata = (void *)plugin; - plugin->npn_instance = instance; - - D(bug(" return: %d\n", ret)); - return ret; -} - -// Deletes a specific instance of a plug-in -static NPError -g_NPP_Destroy(NPP instance, NPSavedData **save) -{ - D(bug("NPP_Destroy instance=%p\n", instance)); - - if (instance == NULL) - return NPERR_INVALID_INSTANCE_ERROR; - - PluginInstance *plugin = instance->pdata; - - if (!g_plugin_funcs.destroy) - return NPERR_GENERIC_ERROR; - - NPError ret = g_plugin_funcs.destroy(plugin->instance, save); - free(plugin->instance); - - D(bug(" return: %d\n", ret)); - return ret; -} - -// Tells the plug-in when a window is created, moved, sized, or destroyed -static NPError -g_NPP_SetWindow(NPP instance, NPWindow *io_window) -{ - D(bug("NPP_SetWindow instance=%p\n", instance)); - - if (instance == NULL) - return NPERR_INVALID_INSTANCE_ERROR; - - PluginInstance *plugin = instance->pdata; - - if (!g_plugin_funcs.setwindow) - return NPERR_GENERIC_ERROR; - - if (io_window == NULL) - npw_printf("NULL window\n"); - - if (io_window == NULL) - return NPERR_NO_ERROR; - -#if 0 - NPWindow the_window, *window = &the_window; - window->window = io_window->window; - window->x = io_window->x; - window->y = io_window->y; - window->width = io_window->width; - window->height = io_window->height; - window->type = io_window->type; - window->clipRect.top = io_window->clipRect.top; - window->clipRect.left = io_window->clipRect.left; - window->clipRect.bottom = io_window->clipRect.bottom; - window->clipRect.right = io_window->clipRect.right; - - NPSetWindowCallbackStruct *io_ws_info = io_window->ws_info; - - NPSetWindowCallbackStruct the_ws_info, *ws_info = &the_ws_info; - window->ws_info = ws_info; - ws_info->type = io_ws_info->type; - ws_info->depth = io_ws_info->depth; - ws_info->display = x_display; - XVisualInfo visualInfo; - int screen = DefaultScreen(ws_info->display); - if (!XMatchVisualInfo(ws_info->display, screen, ws_info->depth, io_ws_info->visual->class, &visualInfo)) { - npw_printf("ERROR: could not reconstruct visual info for NPP_SetWindow\n"); - return NPERR_GENERIC_ERROR; - } - ws_info->colormap = DefaultColormap(ws_info->display, screen); - ws_info->visual = visualInfo.visual; - -#if 0 - ws_info->display = io_ws_info->display; - ws_info->visual = io_ws_info->visual; - ws_info->colormap = io_ws_info->colormap; -#endif - - D(bug(" window size = %d x %d\n", window->width, window->height)); - -#if 1 - if (plugin->window) { - if (plugin->width != window->width || plugin->height != window->height) { - D(bug(" resize window\n")); - plugin->width = window->width; - plugin->height = window->height; - XResizeWindow(x_display, plugin->window, plugin->width, plugin->height); - } - } - else { - Arg args[7]; - XSetWindowAttributes attr; - unsigned long mask; - int n; - Widget top_widget, form; - - mask = CWEventMask; - attr.event_mask = - ButtonMotionMask | - ButtonPressMask | - ButtonReleaseMask | - KeyPressMask | - KeyReleaseMask | - EnterWindowMask | - LeaveWindowMask | - PointerMotionMask | - StructureNotifyMask | - VisibilityChangeMask | - FocusChangeMask | - ExposureMask; - - plugin->width = window->width; - plugin->height = window->height; - plugin->window = XCreateWindow(x_display, (Window)window->window, - 0, 0, window->width, window->height, - 0, ws_info->depth, InputOutput, ws_info->visual, mask, &attr); - XMapWindow(x_display, plugin->window); - XFlush(x_display); - - String app_name, app_class; - XtGetApplicationNameAndClass(x_display, &app_name, &app_class); - - top_widget = XtAppCreateShell("drawingArea", app_class, applicationShellWidgetClass, x_display, NULL, 0); - plugin->top_widget = top_widget; - - n = 0; - XtSetArg(args[n], XtNwidth, window->width); n++; - XtSetArg(args[n], XtNheight, window->height); n++; - XtSetArg(args[n], XtNvisual, ws_info->visual); n++; - XtSetArg(args[n], XtNdepth, ws_info->depth); n++; - XtSetArg(args[n], XtNcolormap, ws_info->colormap ); n++; - XtSetArg(args[n], XtNborderWidth, 0); n++; - XtSetValues(top_widget, args, n); - - form = XtVaCreateWidget("form", compositeWidgetClass, top_widget, NULL); - plugin->form = form; - - n = 0; - XtSetArg(args[n], XtNwidth, window->width); n++; - XtSetArg(args[n], XtNheight, window->height); n++; - XtSetArg(args[n], XtNvisual, ws_info->visual); n++; - XtSetArg(args[n], XtNdepth, ws_info->depth); n++; - XtSetArg(args[n], XtNcolormap, ws_info->colormap ); n++; - XtSetArg(args[n], XtNborderWidth, 0); n++; - XtSetValues(form, args, n); - -#if 1 - plugin->old_window = top_widget->core.window; - top_widget->core.window = plugin->window; -#endif - - XtRegisterDrawable(x_display, plugin->window, top_widget); - XtRealizeWidget(form); - XtManageChild(form); - - plugin->window = XtWindow(plugin->form); - - XSelectInput(x_display, XtWindow(top_widget), 0x0fffff); - XSelectInput(x_display, XtWindow(form), 0x0fffff); - - XSync(x_display, False); - } - D(bug(" old window id %p\n", window->window)); - window->window = (void *)XtWindow(plugin->form); -#endif - -#if 0 - D(bug(" window=%d:%p at (%d,%d), size=%dx%d\n", (Window)window->window, window->window, window->x, window->y, window->width, window->height)); - D(bug(" clipRect={ {%d,%d}, {%d,%d} }\n", window->clipRect.top, window->clipRect.left, window->clipRect.bottom, window->clipRect.right)); - D(bug(" type=%s, %d:%d\n", window->type == NPWindowTypeWindow ? "Window" : (window->type == NPWindowTypeDrawable ? "Drawable" : "Unknown"), window->type, ws_info->type)); - D(bug(" display=%p[%s], visual=%p, colormap=%d, depth=%d\n", ws_info->display, DisplayString(ws_info->display), ws_info->visual, ws_info->colormap, ws_info->depth)); - Visual *vis = ws_info->visual; - D(bug(" Visual from visualInfo=%p { %d, %d, %x, %x, %x, %d, %d }\n", vis, - vis->visualid, vis->class, vis->red_mask, vis->green_mask, vis->blue_mask, vis->bits_per_rgb, vis->map_entries)); -#endif -#else - NPWindow *window = io_window; -#endif - - D(bug(" window id %p\n", window->window)); - NPError ret = g_plugin_funcs.setwindow(plugin->instance, window); - - D(bug(" return: %d\n", ret)); - return ret; -} - -// Allows the browser to query the plug-in for information -static NPError -g_NPP_GetValue(NPP instance, NPPVariable variable, void *value) -{ - D(bug("NPP_GetValue instance=%p, variable=%d\n", instance, variable)); - - if (instance == NULL) - return NPERR_INVALID_INSTANCE_ERROR; - - PluginInstance *plugin = instance->pdata; - - if (!g_plugin_funcs.getvalue) - return NPERR_GENERIC_ERROR; - - NPError ret = NPERR_GENERIC_ERROR; - - switch (variable) { - case NPPVpluginNameString: - case NPPVpluginDescriptionString: - { - char *s; - ret = g_plugin_funcs.getvalue(plugin->instance, variable, &s); - if (ret == NPERR_NO_ERROR) { - D(bug(" value='%s'\n", s)); - *((char **)value) = s; - } - break; - } - case NPPVpluginWindowBool: - case NPPVpluginTransparentBool: - case NPPVpluginWindowSize: - case NPPVpluginTimerInterval: - { - uint32_t n; - ret = g_plugin_funcs.getvalue(plugin->instance, variable, &n); - if (ret == NPERR_NO_ERROR) { - D(bug(" value=%d\n", n)); - *((int *)value) = n; - } - break; - } - case NPPVpluginNeedsXEmbed: - { - PRBool b; - ret = g_plugin_funcs.getvalue(plugin->instance, variable, &b); - if (ret == NPERR_NO_ERROR) { -#if 1 - // XXX Flash plugin hack - npw_printf(" XEmbed not supported yet\n"); - b = FALSE; -#else - D(bug(" value=%s\n", b ? "true" : "false")); -#endif - *((PRBool *)value) = b; - } - break; - } - } - - D(bug(" return: %d\n", ret)); - return ret; -} - -// Sets information about the plug-in -static NPError -g_NPP_SetValue(NPP instance, NPPVariable variable, void *value) -{ - D(bug("NPP_SetValue instance=%p, variable=%d\n", instance, variable)); - UNIMPLEMENTED(); - - return NPERR_GENERIC_ERROR; -} - -// Notifies the instance of the completion of a URL request -static void -g_NPP_URLNotify(NPP instance, const char *url, NPReason reason, void *notifyData) -{ - D(bug("NPP_URLNotify instance=%p, url='%s', reason=%d, notifyData=%p\n", instance, url, reason, notifyData)); - - if (instance == NULL) - return; - - PluginInstance *plugin = instance->pdata; - - if (!g_plugin_funcs.urlnotify) - return; - - g_plugin_funcs.urlnotify(plugin->instance, url, reason, notifyData); -} - -// Notifies a plug-in instance of a new data stream -static NPError -g_NPP_NewStream(NPP instance, NPMIMEType type, NPStream *io_stream, NPBool seekable, uint16 *stype) -{ - D(bug("NPP_NewStream instance=%p\n", instance)); - - if (instance == NULL) - return NPERR_INVALID_INSTANCE_ERROR; - - PluginInstance *plugin = instance->pdata; - - if (!g_plugin_funcs.newstream) - return NPERR_GENERIC_ERROR; - - uint16 v_stype = NP_NORMAL; - if (stype) - v_stype = *stype; - - NPStream *stream = malloc(sizeof(*stream)); - if (stream == NULL) - return NPERR_OUT_OF_MEMORY_ERROR; - stream->url = io_stream->url; - stream->end = io_stream->end; - stream->lastmodified = io_stream->lastmodified; - - NPError ret = g_plugin_funcs.newstream(plugin->instance, type, stream, seekable, &v_stype); - io_stream->pdata = stream; - io_stream->notifyData = stream->notifyData; - D(bug(" io_stream=%p, stream=%p, notifyData=%p\n", io_stream, stream, stream->notifyData)); - - if (stype) - *stype = v_stype; - - D(bug(" return: %d [stype=%d]\n", ret, *stype)); - return ret; -} - -// Tells the plug-in that a stream is about to be closed or destroyed -static NPError -g_NPP_DestroyStream(NPP instance, NPStream *io_stream, NPReason reason) -{ - D(bug("NPP_DestroyStream instance=%p\n", instance)); - - if (instance == NULL) - return NPERR_INVALID_INSTANCE_ERROR; - - PluginInstance *plugin = instance->pdata; - - if (!g_plugin_funcs.destroystream) - return NPERR_GENERIC_ERROR; - - NPStream *stream = io_stream->pdata; - - NPError ret = g_plugin_funcs.destroystream(plugin->instance, stream, reason); - - free(stream); - - D(bug(" return: %d\n", ret)); - return ret; -} - -// Provides a local file name for the data from a stream -static void -g_NPP_StreamAsFile(NPP instance, NPStream *io_stream, const char *fname) -{ - D(bug("NPP_StreamAsFile instance=%p\n", instance)); - - if (instance == NULL) - return; - - PluginInstance *plugin = instance->pdata; - - if (!g_plugin_funcs.asfile) - return; - - NPStream *stream = io_stream->pdata; - - D(bug(" fname='%s'\n", fname ? fname : "")); - g_plugin_funcs.asfile(plugin->instance, stream, fname); -} - -// Determines maximum number of bytes that the plug-in can consume -static int32 -g_NPP_WriteReady(NPP instance, NPStream *io_stream) -{ - D(bug("NPP_WriteReady instance=%p\n", instance)); - - if (instance == NULL) - return NPERR_INVALID_INSTANCE_ERROR; - - PluginInstance *plugin = instance->pdata; - - if (!g_plugin_funcs.writeready) - return NPERR_GENERIC_ERROR; - - NPStream *stream = io_stream->pdata; - - int32 ret = g_plugin_funcs.writeready(plugin->instance, stream); - - D(bug(" return: %d\n", ret)); - return ret; -} - -// Delivers data to a plug-in instance -static int32 -g_NPP_Write(NPP instance, NPStream *io_stream, int32 offset, int32 len, void *buf) -{ - D(bug("NPP_Write instance=%p\n", instance)); - - if (instance == NULL) - return NPERR_INVALID_INSTANCE_ERROR; - - PluginInstance *plugin = instance->pdata; - - if (!g_plugin_funcs.write) - return NPERR_GENERIC_ERROR; - - NPStream *stream = io_stream->pdata; - - int32 ret = g_plugin_funcs.write(plugin->instance, stream, offset, len, buf); - - D(bug(" return: %d\n", ret)); - return ret; -} - -// Requests a platform-specific print operation for an embedded or full-screen plug-in -static void -g_NPP_Print(NPP instance, NPPrint *PrintInfo) -{ - D(bug("NPP_Write instance=%p\n", instance)); - UNIMPLEMENTED(); -} - -// Delivers a platform-specific window event to the instance -static int16 -g_NPP_HandleEvent(NPP instance, void *event) -{ - D(bug("NPP_HandleEvent instance=%p\n", instance)); - UNIMPLEMENTED(); - - return NPERR_GENERIC_ERROR; -} - -// Allows the browser to query the plug-in for information -NPError -NP_GetValue(void *future, NPPVariable variable, void *value) -{ - D(bug("NP_GetValue\n")); - - if (g_plugin_initialized <= 0) { - npw_printf("ERROR: could not initialize underlying plugin\n"); - return NPERR_GENERIC_ERROR; - } - - // Handle NPPVpluginNameString and NPPVpluginDescriptionString only - switch (variable) { - case NPPVpluginNameString: - break; - case NPPVpluginDescriptionString: - break; - default: - return NPERR_INVALID_PARAM; - } - - char *str = NULL; - NPError ret = g_NP_GetValue ? g_NP_GetValue(NULL, variable, (void *)&str) : NPERR_GENERIC_ERROR; - - if (ret == NPERR_NO_ERROR) - *((char **) value) = str; - - D(bug(" return: %d\n", ret)); - return ret; -} - -// Allows the browser to query the plug-in supported formats -char * -NP_GetMIMEDescription(void) -{ - D(bug("NP_GetMIMEDescription\n")); - - if (g_plugin_initialized <= 0) { - npw_printf("ERROR: could not initialize underlying plugin\n"); - return NULL; - } - - char *formats = g_NP_GetMIMEDescription(); - D(bug(" formats='%s'\n", formats)); - return formats; -} - -// Provides global initialization for a plug-in -NPError -NP_Initialize(NPNetscapeFuncs *moz_funcs, NPPluginFuncs *plugin_funcs) -{ - D(bug("NP_Initialize\n")); - - if (g_plugin_initialized <= 0) { - npw_printf("ERROR: could not initialize underlying plugin\n"); - return NPERR_GENERIC_ERROR; - } - - if (moz_funcs == NULL || plugin_funcs == NULL) - return NPERR_INVALID_FUNCTABLE_ERROR; - if ((moz_funcs->version >> 8) > NP_VERSION_MAJOR) - return NPERR_INCOMPATIBLE_VERSION_ERROR; - if (moz_funcs->size < sizeof(NPNetscapeFuncs)) - return NPERR_INVALID_FUNCTABLE_ERROR; - if (plugin_funcs->size < sizeof(NPPluginFuncs)) - return NPERR_INVALID_FUNCTABLE_ERROR; - - memcpy(&g_mozilla_funcs, moz_funcs, sizeof(g_mozilla_funcs)); - - memset(&g_plugin_funcs, 0, sizeof(g_plugin_funcs)); - g_plugin_funcs.size = sizeof(g_plugin_funcs); - - memset(moz_funcs, 0, sizeof(*moz_funcs)); - moz_funcs->size = sizeof(*moz_funcs); - moz_funcs->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR; - moz_funcs->geturl = g_NPN_GetURL; - moz_funcs->posturl = g_NPN_PostURL; - moz_funcs->requestread = g_NPN_RequestRead; - moz_funcs->newstream = g_NPN_NewStream; - moz_funcs->write = g_NPN_Write; - moz_funcs->destroystream = g_NPN_DestroyStream; - moz_funcs->status = g_NPN_Status; - moz_funcs->uagent = g_NPN_UserAgent; - moz_funcs->memalloc = g_NPN_MemAlloc; - moz_funcs->memfree = g_NPN_MemFree; - moz_funcs->memflush = g_NPN_MemFlush; - moz_funcs->reloadplugins = g_NPN_ReloadPlugins; - moz_funcs->getJavaEnv = g_NPN_GetJavaEnv; - moz_funcs->getJavaPeer = g_NPN_GetJavaPeer; - moz_funcs->geturlnotify = g_NPN_GetURLNotify; - moz_funcs->posturlnotify = g_NPN_PostURLNotify; - moz_funcs->getvalue = g_NPN_GetValue; - moz_funcs->setvalue = g_NPN_SetValue; - moz_funcs->invalidaterect = g_NPN_InvalidateRect; - moz_funcs->invalidateregion = g_NPN_InvalidateRegion; - moz_funcs->forceredraw = g_NPN_ForceRedraw; - - memset(plugin_funcs, 0, sizeof(*plugin_funcs)); - plugin_funcs->size = sizeof(NPPluginFuncs); - plugin_funcs->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR; - plugin_funcs->newp = NewNPP_NewProc(g_NPP_New); - plugin_funcs->destroy = NewNPP_DestroyProc(g_NPP_Destroy); - plugin_funcs->setwindow = NewNPP_SetWindowProc(g_NPP_SetWindow); - plugin_funcs->newstream = NewNPP_NewStreamProc(g_NPP_NewStream); - plugin_funcs->destroystream = NewNPP_DestroyStreamProc(g_NPP_DestroyStream); - plugin_funcs->asfile = NewNPP_StreamAsFileProc(g_NPP_StreamAsFile); - plugin_funcs->writeready = NewNPP_WriteReadyProc(g_NPP_WriteReady); - plugin_funcs->write = NewNPP_WriteProc(g_NPP_Write); - plugin_funcs->print = NewNPP_PrintProc(g_NPP_Print); - plugin_funcs->event = NewNPP_HandleEventProc(g_NPP_HandleEvent); - plugin_funcs->urlnotify = NewNPP_URLNotifyProc(g_NPP_URLNotify); - plugin_funcs->javaClass = NULL; - plugin_funcs->getvalue = NewNPP_GetValueProc(g_NPP_GetValue); - plugin_funcs->setvalue = NewNPP_SetValueProc(g_NPP_SetValue); - - NPError ret = g_NP_Initialize(moz_funcs, &g_plugin_funcs); - D(bug(" return: %d\n", ret)); - return ret; -} - -// Provides global deinitialization for a plug-in -NPError -NP_Shutdown(void) -{ - D(bug("NP_Shutdown\n")); - - if (g_plugin_initialized <= 0) { - npw_printf("ERROR: could not initialize underlying plugin\n"); - return NPERR_GENERIC_ERROR; - } - - NPError ret = g_NP_Shutdown(); - D(bug(" return: %d\n", ret)); - return ret; -}