nspluginwrapper-1.1.10

Taken from Ubuntu orig.tar.gz file.
This commit is contained in:
David Benjamin 2011-03-05 22:26:53 -05:00
parent dec6139d44
commit 1f0ad8eb29
32 changed files with 4507 additions and 2299 deletions

522
ChangeLog
View File

@ -1,3 +1,525 @@
2008-12-07 22:35 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npw-wrapper.c: Fix NPP_HandleEvent() return value on error.
2008-12-07 08:10 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/debug.h: Add npw_return_if_fail() and
npw_return_val_if_fail() helpers.
2008-12-07 07:16 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* tests/test-rpc-common.h: Add helpers.
2008-12-06 18:10 Gwenole Beauchesne <gb.public@free.fr>
* Makefile, tests/test-rpc-nested-1.c, tests/test-rpc-nested.c:
Rename.
2008-12-06 09:08 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npruntime-impl.h, src/npruntime.c: Add debug messages for
NPClass::invoke_*() functions.
2008-12-02 21:49 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npw-common.h: Remove extraneous "extern" linkage keyword,
this is default behaviour.
2008-12-01 21:46 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npw-viewer.c: Fix pid_check() for USE_PID_CHECK == 0 (thanks
Martin Stransky).
2008-12-01 20:03 Gwenole Beauchesne <gb.public@free.fr>
* nspluginwrapper.spec: Bump release for development.
2008-11-30 23:03 Gwenole Beauchesne <gb.public@free.fr>
* ChangeLog: Generated by svn2cl.
2008-11-30 23:00 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* NEWS, nspluginwrapper.spec: Updates for 1.1.8.
2008-11-30 22:39 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npw-viewer.c: Don't delay call to NPN_ReleaseObject() if we
can handle it now.
2008-11-30 21:52 Gwenole Beauchesne <gb.public@free.fr>
* src/rpc.c: Add rpc_method_*_valist() variants, internal only for
now.
2008-11-30 21:24 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npw-malloc.h: Fix typo.
2008-11-30 20:47 Gwenole Beauchesne <gb.public@free.fr>
* src/npruntime.c, src/npw-viewer.c: Delay calls to
NPN_ReleaseObject. Revert:
2008-11-22 10:43 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npruntime.c, src/npw-viewer.c, src/npw-wrapper.c: Add
missing debugging messages.
2008-11-30 17:21 Gwenole Beauchesne <gb.public@free.fr>
* src/npruntime.c: Fix pid_check() for the browser-side
implementation.
2008-11-30 17:14 Gwenole Beauchesne <gb.public@free.fr>
* src/npruntime.c, src/npw-viewer.c: Extend PID check to npruntime
bridge.
2008-11-30 15:52 Gwenole Beauchesne <gb.public@free.fr>
* lsb-build/stub_libs/libc_main.c: Add dirfd() for
npw_close_all_open_files().
2008-11-30 15:47 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npruntime.c: Rename is_npclass_valid() to
is_valid_npobject_class().
2008-11-30 14:50 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npw-wrapper.c: Likewise for npobject_bridge_destroy().
2008-11-30 14:18 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npw-viewer.c: Kill viewer if the parent browser died (Martin
Stransky).
2008-11-30 13:08 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/rpc.c: Add SOCK_CLOEXEC to socket() flags. This is a Linux
>= 2.6.27 extension.
2008-11-30 09:01 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* utils/npw-shadow.c: Nuke dead file.
2008-11-29 14:47 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/utils.c: Fix id_init() to create a new hash if it does not
exist already.
2008-11-25 22:11 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* nspluginwrapper.spec: Bump release for development.
2008-11-24 18:35 Gwenole Beauchesne <gb.public@free.fr>
* NEWS: Fix typo.
2008-11-23 21:57 Gwenole Beauchesne <gb.public@free.fr>
* ChangeLog: Generated by svn2cl.
2008-11-23 06:43 Gwenole Beauchesne <gb.public@free.fr>
* src/npw-viewer.c: Fix a warning (enumeration value not handled
in switch).
2008-11-23 06:39 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* ChangeLog: Generated by svn2cl.
2008-11-22 15:20 Gwenole Beauchesne <gb.public@free.fr>
* src/npruntime.c: Fix string_of_NPVariant() for NULL arguments.
2008-11-22 15:04 Gwenole Beauchesne <gb.public@free.fr>
* src/npruntime.c: Release args variants prior to calling
rpc_method_send_reply().
2008-11-22 13:49 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npw-wrapper.c: Fix debug message in NPN_Write().
2008-11-22 10:52 Gwenole Beauchesne <gb.public@free.fr>
* src/npw-wrapper.c: Fix memory leak in NPN_GetStringIdentifiers()
RPC handler.
2008-11-22 10:50 Gwenole Beauchesne <gb.public@free.fr>
* src/npw-malloc.h: Add NPW_MemNew() and NPW_MemNew0() helpers.
2008-11-22 10:43 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npw-rpc.c: Don't make the sync message a WARNING.
2008-11-22 07:52 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npw-viewer.c: Fix plugin window resize in XEMBED hack mode.
2008-11-17 21:55 Gwenole Beauchesne <gb.public@free.fr>
* tests/test-plugins.html: Newer demo for the SqueakVM plugin.
2008-11-17 21:40 Gwenole Beauchesne <gb.public@free.fr>
* src/npw-viewer.c, src/npw-wrapper.c: Lower priority of RPC
handlers.
2008-11-15 21:50 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* src/npw-common.h: Fix npw_get_stream_instance().
2008-11-09 17:02 Gwenole Beauchesne <gb.public@free.fr>
* src/npw-wrapper.c: Update NPP_Write() comment for negative array
lengths.
2008-11-09 16:56 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* 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 <gb.public@free.fr>
* tests/test-rpc-types.c: Add tests for arrays. Fix
rpc_test_signature() for arrays.
2008-11-09 15:24 Gwenole Beauchesne <gb.public@free.fr>
* src/rpc.c: Allow arrays of uint64 or double.
2008-11-09 14:29 Gwenole Beauchesne <gb.public@free.fr>
* 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 <gb.public@free.fr>
* configure: Enable glib memory hooks by default if not
configuring with --enable-generic.
2008-11-09 14:13 Gwenole Beauchesne <gb.public@free.fr>
* nspluginwrapper.spec: Bump version for development.
2008-11-06 22:36 Gwenole Beauchesne <gb.public@free.fr>
* ChangeLog: Generated by svn2cl.
2008-11-06 22:28 Gwenole Beauchesne <gb.public@free.fr>
* NEWS, README, nspluginwrapper.spec: Updates for 1.1.4.

View File

@ -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)

29
NEWS
View File

@ -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)

11
README
View File

@ -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

48
configure vendored
View File

@ -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

View File

@ -130,6 +130,7 @@ void dcgettext() {} ;
void dcngettext() {} ;
void dgettext() {} ;
void difftime() {} ;
void dirfd() {} ;
void dirname() {} ;
void div() {} ;
void dngettext() {} ;

View File

@ -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 <gb.public@free.fr> 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 <gb.public@free.fr> 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 <gb.public@free.fr> 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 <gb.public@free.fr> 1.1.4-1
- fix memory leaks in NPRuntime bridge
- fix XEMBED support (workaround Gtk2 and Firefox bugs)

View File

@ -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);
}

View File

@ -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

View File

@ -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 */

View File

@ -24,6 +24,7 @@
#include <glib.h> /* <glib/ghash.h> */
#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
}

View File

@ -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)
{

View File

@ -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 */

View File

@ -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 */

View File

@ -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);

View File

@ -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 *),

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

505
src/rpc.c
View File

@ -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 = "<unknown>";
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: <invoke> (body: <method-id> 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: <invoke> = MESSAGE_START <method-id> 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: <method-args> = MESSAGE_ARGS [ <arg-type> <arg-value> ]+ 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: <method-args>
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: <method-args>
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: [ <method-args> ]
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 === */

View File

@ -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 */

View File

@ -18,12 +18,17 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#define _GNU_SOURCE 1
#include "sysdeps.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <glib.h> /* <glib/ghash.h> */
#include <fcntl.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/resource.h>
#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 = "<unknown variable>";
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 = "<unknown variable>";
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 === */

View File

@ -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
}

View File

@ -26,7 +26,7 @@ Various sample data to exercise the NPAPI plugins compatibility layer
<li><p><b>Tcl Plugin Demos</b><br>
<a href="http://www.tcl.tk/software/plugin/applets.html">http://www.tcl.tk/software/plugin/applets.html</a>
<li><p><b>Squeak VM plugin tests</b><br>
<a href="http://www.squeakland.org/plugin/launch.html">http://www.squeakland.org/plugin/launch.html</a>
<a href="http://wiki.squeak.org/squeak/5858">http://wiki.squeak.org/squeak/5858</a>
<li><p><b>Citrix ICA Client demo</b><br>
<a href="http://www.rentonlinesoftware.com/store/tryademo.asp">http://www.rentonlinesoftware.com/store/tryademo.asp</a>
</ul>

View File

@ -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;
}

View File

@ -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
{

View File

@ -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;
}

View File

@ -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;
}

189
tests/test-rpc-nested-2.c Normal file
View File

@ -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 <unistd.h>
#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 "<unknown>";
}
#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;
}

View File

@ -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;
}

File diff suppressed because it is too large Load Diff