mirror of
https://gitlab.freedesktop.org/dbus/dbus.git
synced 2026-04-27 10:40:40 +02:00
Merge branch 'dbus-1.4'
This commit is contained in:
commit
c83287898c
16 changed files with 1763 additions and 88 deletions
21
NEWS
21
NEWS
|
|
@ -1,8 +1,29 @@
|
|||
D-Bus 1.5.4 (UNRELEASED)
|
||||
==
|
||||
|
||||
Security (local denial of service):
|
||||
|
||||
• Byte-swap foreign-endian messages correctly, preventing a long-standing
|
||||
local DoS if foreign-endian messages are relayed through the dbus-daemon
|
||||
(backporters: this is git commit c3223ba6c401ba81df1305851312a47c485e6cd7)
|
||||
(fd.o #38120, Debian #629938, no CVE number yet; Simon McVittie)
|
||||
|
||||
New things:
|
||||
|
||||
• The constant to use for an infinite timeout now has a name,
|
||||
DBUS_TIMEOUT_INFINITE. It is numerically equivalent to 0x7fffffff (INT32_MAX)
|
||||
which can be used for source compatibility with older versions of libdbus.
|
||||
|
||||
• If GLib and DBus-GLib are already installed, more tests will be built,
|
||||
providing better coverage. They can be installed via
|
||||
./configure --enable-installed-tests
|
||||
for system integration testing, if required. (fd.o #34570, Simon McVittie)
|
||||
|
||||
Changes:
|
||||
|
||||
• Consistently use atomic operations for the DBusConnection's refcount
|
||||
(fd.o #38005, Simon McVittie)
|
||||
|
||||
• Don't use -Wl,--gc-sections by default: in practice the size decrease is
|
||||
small (300KiB on x86-64) and it frequently doesn't work in unusual
|
||||
toolchains. To optimize for minimum installed size, you should benchmark
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ ENABLE_TESTING()
|
|||
option (DBUS_BUILD_TESTS "enable unit test code" ON)
|
||||
|
||||
if(DBUS_BUILD_TESTS)
|
||||
add_definitions(-DDBUS_BUILD_TESTS)
|
||||
add_definitions(-DDBUS_BUILD_TESTS -DDBUS_ENABLE_EMBEDDED_TESTS)
|
||||
endif(DBUS_BUILD_TESTS)
|
||||
|
||||
option (DBUS_USE_OUTPUT_DEBUG_STRING "enable win32 debug port for message output" OFF)
|
||||
|
|
|
|||
82
configure.ac
82
configure.ac
|
|
@ -122,7 +122,6 @@ AM_CONDITIONAL(DBUS_WINCE, test "$dbus_wince" = yes)
|
|||
AM_CONDITIONAL(DBUS_UNIX, test "$dbus_unix" = yes)
|
||||
AM_CONDITIONAL(DBUS_CYGWIN, test "$dbus_cygwin" = yes)
|
||||
|
||||
AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests],[enable unit test code in the library and binaries]),enable_tests=$enableval,enable_tests=$USE_MAINTAINER_MODE)
|
||||
AC_ARG_ENABLE(ansi, AS_HELP_STRING([--enable-ansi],[enable -ansi -pedantic gcc flags]),enable_ansi=$enableval,enable_ansi=no)
|
||||
AC_ARG_ENABLE(verbose-mode, AS_HELP_STRING([--enable-verbose-mode],[support verbose debug mode]),enable_verbose_mode=$enableval,enable_verbose_mode=$USE_MAINTAINER_MODE)
|
||||
AC_ARG_ENABLE(asserts, AS_HELP_STRING([--enable-asserts],[include assertion checks]),enable_asserts=$enableval,enable_asserts=$USE_MAINTAINER_MODE)
|
||||
|
|
@ -151,20 +150,80 @@ AC_ARG_WITH(launchd-agent-dir, AS_HELP_STRING([--with-launchd-agent-dir=[dirname
|
|||
AC_ARG_WITH(dbus_user, AS_HELP_STRING([--with-dbus-user=<user>],[User for running the DBUS daemon (messagebus)]))
|
||||
AC_ARG_WITH(dbus_daemondir, AS_HELP_STRING([--with-dbus-daemondir=[dirname]],[Directory for installing the DBUS daemon]))
|
||||
|
||||
dnl DBUS_BUILD_TESTS controls unit tests built in to .c files
|
||||
dnl and also some stuff in the test/ subdir
|
||||
AM_CONDITIONAL(DBUS_BUILD_TESTS, test x$enable_tests = xyes)
|
||||
if test x$enable_tests = xyes; then
|
||||
AC_DEFINE(DBUS_BUILD_TESTS,1,[Build test code])
|
||||
AC_ARG_ENABLE([embedded-tests],
|
||||
AS_HELP_STRING([--enable-embedded-tests],
|
||||
[enable unit test code in the library and binaries]),
|
||||
[], [enable_embedded_tests=$USE_MAINTAINER_MODE])
|
||||
AC_ARG_ENABLE([modular-tests],
|
||||
AS_HELP_STRING([--enable-modular-tests],
|
||||
[enable modular regression tests (requires GLib)]),
|
||||
[], [enable_modular_tests=auto])
|
||||
# --enable-tests overrides both --enable-embedded-tests and
|
||||
# --enable-modular-tests
|
||||
AC_ARG_ENABLE([tests],
|
||||
AS_HELP_STRING([--enable-tests],
|
||||
[enable/disable all tests, overriding embedded-tests/modular-tests]),
|
||||
[enable_embedded_tests=$enableval; enable_modular_tests=$enableval],
|
||||
[])
|
||||
|
||||
# DBUS_ENABLE_EMBEDDED_TESTS controls unit tests built in to .c files
|
||||
# and also some stuff in the test/ subdir. DBUS_BUILD_TESTS was an older
|
||||
# name for this.
|
||||
AM_CONDITIONAL([DBUS_BUILD_TESTS], [test "x$enable_embedded_tests" = xyes])
|
||||
AM_CONDITIONAL([DBUS_ENABLE_EMBEDDED_TESTS],
|
||||
[test "x$enable_embedded_tests" = xyes])
|
||||
if test "x$enable_embedded_tests" = xyes; then
|
||||
AC_DEFINE([DBUS_ENABLE_EMBEDDED_TESTS], [1],
|
||||
[Define to build test code into the library and binaries])
|
||||
AC_DEFINE([DBUS_BUILD_TESTS], [1],
|
||||
[Define to build test code into the library and binaries])
|
||||
fi
|
||||
|
||||
# DBUS_ENABLE_MODULAR_TESTS controls tests that work based on public API.
|
||||
# These use GTest, from GLib, because life's too short. They're enabled by
|
||||
# default (unless you don't have GLib), because they don't bloat the library
|
||||
# or binaries.
|
||||
if test "x$enable_modular_tests" != xno; then
|
||||
PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.22, gio-2.0 >= 2.22],
|
||||
[],
|
||||
[if test "x$enable_modular_tests" = xyes; then
|
||||
AC_MSG_ERROR([GLib is required by the modular tests])
|
||||
else # assumed to be "auto"
|
||||
enable_modular_tests=no
|
||||
fi])
|
||||
# If dbus-gmain.[ch] returned to libdbus then we wouldn't need this
|
||||
PKG_CHECK_MODULES([DBUS_GLIB], [dbus-glib-1],
|
||||
[],
|
||||
[if test "x$enable_modular_tests" = xyes; then
|
||||
AC_MSG_ERROR([dbus-glib is required by the modular tests (for now)])
|
||||
else # assumed to be "auto"
|
||||
enable_modular_tests=no
|
||||
fi])
|
||||
if test "x$enable_modular_tests" != xno; then
|
||||
# dependencies checked, switch from auto to yes
|
||||
enable_modular_tests=yes
|
||||
fi
|
||||
fi
|
||||
if test "x$enable_modular_tests" = xyes; then
|
||||
AC_DEFINE([DBUS_ENABLE_MODULAR_TESTS], [1],
|
||||
[Define to build independent test binaries (requires GLib)])
|
||||
fi
|
||||
AM_CONDITIONAL([DBUS_ENABLE_MODULAR_TESTS],
|
||||
[test "x$enable_modular_tests" = xyes])
|
||||
|
||||
AC_ARG_ENABLE([installed-tests],
|
||||
AS_HELP_STRING([--enable-installed-tests],
|
||||
[enable unit test code in the library and binaries]),
|
||||
[], [enable_installed_tests=no])
|
||||
AM_CONDITIONAL([DBUS_ENABLE_INSTALLED_TESTS],
|
||||
[test "x$enable_installed_tests" = xyes])
|
||||
|
||||
if test x$enable_verbose_mode = xyes; then
|
||||
AC_DEFINE(DBUS_ENABLE_VERBOSE_MODE,1,[Support a verbose mode])
|
||||
fi
|
||||
|
||||
if test x$enable_asserts = xno; then
|
||||
AC_DEFINE(DBUS_DISABLE_ASSERT,1,[Disable assertion checking])
|
||||
AC_DEFINE(G_DISABLE_ASSERT,1,[Disable GLib assertion macros])
|
||||
R_DYNAMIC_LDFLAG=""
|
||||
else
|
||||
# -rdynamic is needed for glibc's backtrace_symbols to work.
|
||||
|
|
@ -1569,7 +1628,8 @@ echo "
|
|||
echo "
|
||||
Maintainer mode: ${USE_MAINTAINER_MODE}
|
||||
gcc coverage profiling: ${enable_compiler_coverage}
|
||||
Building unit tests: ${enable_tests}
|
||||
Building embedded tests: ${enable_embedded_tests}
|
||||
Building modular tests: ${enable_modular_tests}
|
||||
Building verbose mode: ${enable_verbose_mode}
|
||||
Building assertions: ${enable_asserts}
|
||||
Building checks: ${enable_checks}
|
||||
|
|
@ -1601,11 +1661,11 @@ if test x$have_launchd = xyes; then
|
|||
fi
|
||||
echo
|
||||
|
||||
if test x$enable_tests = xyes; then
|
||||
if test x$enable_embedded_tests = xyes; then
|
||||
echo "NOTE: building with unit tests increases the size of the installed library and renders it insecure."
|
||||
fi
|
||||
if test x$enable_tests = xyes -a x$enable_asserts = xno; then
|
||||
echo "NOTE: building with unit tests but without assertions means tests may not properly report failures (this configuration is only useful when doing something like profiling the tests)"
|
||||
if test x$enable_embedded_tests = xyes -a x$enable_asserts = xno; then
|
||||
echo "NOTE: building with embedded tests but without assertions means tests may not properly report failures (this configuration is only useful when doing something like profiling the tests)"
|
||||
fi
|
||||
if test x$enable_compiler_coverage = xyes; then
|
||||
echo "NOTE: building with coverage profiling is definitely for developers only."
|
||||
|
|
|
|||
|
|
@ -1400,13 +1400,8 @@ _dbus_connection_ref_unlocked (DBusConnection *connection)
|
|||
_dbus_assert (connection->generation == _dbus_current_generation);
|
||||
|
||||
HAVE_LOCK_CHECK (connection);
|
||||
|
||||
#ifdef DBUS_HAVE_ATOMIC_INT
|
||||
|
||||
_dbus_atomic_inc (&connection->refcount);
|
||||
#else
|
||||
_dbus_assert (connection->refcount.value > 0);
|
||||
connection->refcount.value += 1;
|
||||
#endif
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
|
@ -1426,22 +1421,8 @@ _dbus_connection_unref_unlocked (DBusConnection *connection)
|
|||
|
||||
_dbus_assert (connection != NULL);
|
||||
|
||||
/* The connection lock is better than the global
|
||||
* lock in the atomic increment fallback
|
||||
*/
|
||||
|
||||
#ifdef DBUS_HAVE_ATOMIC_INT
|
||||
last_unref = (_dbus_atomic_dec (&connection->refcount) == 1);
|
||||
#else
|
||||
_dbus_assert (connection->refcount.value > 0);
|
||||
|
||||
connection->refcount.value -= 1;
|
||||
last_unref = (connection->refcount.value == 0);
|
||||
#if 0
|
||||
printf ("unref_unlocked() connection %p count = %d\n", connection, connection->refcount.value);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (last_unref)
|
||||
_dbus_connection_last_unref (connection);
|
||||
}
|
||||
|
|
@ -2127,11 +2108,23 @@ _dbus_connection_send_and_unlock (DBusConnection *connection,
|
|||
void
|
||||
_dbus_connection_close_if_only_one_ref (DBusConnection *connection)
|
||||
{
|
||||
CONNECTION_LOCK (connection);
|
||||
|
||||
_dbus_assert (connection->refcount.value > 0);
|
||||
dbus_int32_t tmp_refcount;
|
||||
|
||||
if (connection->refcount.value == 1)
|
||||
CONNECTION_LOCK (connection);
|
||||
|
||||
/* We increment and then decrement the refcount, because there is no
|
||||
* _dbus_atomic_get (mirroring the fact that there's no InterlockedGet
|
||||
* on Windows). */
|
||||
_dbus_atomic_inc (&connection->refcount);
|
||||
tmp_refcount = _dbus_atomic_dec (&connection->refcount);
|
||||
|
||||
/* The caller should have one ref, and this function temporarily took
|
||||
* one more, which is reflected in this count even though we already
|
||||
* released it (relying on the caller's ref) due to _dbus_atomic_dec
|
||||
* semantics */
|
||||
_dbus_assert (tmp_refcount >= 2);
|
||||
|
||||
if (tmp_refcount == 2)
|
||||
_dbus_connection_close_possibly_shared_and_unlock (connection);
|
||||
else
|
||||
CONNECTION_UNLOCK (connection);
|
||||
|
|
@ -2633,25 +2626,8 @@ dbus_connection_ref (DBusConnection *connection)
|
|||
{
|
||||
_dbus_return_val_if_fail (connection != NULL, NULL);
|
||||
_dbus_return_val_if_fail (connection->generation == _dbus_current_generation, NULL);
|
||||
|
||||
/* The connection lock is better than the global
|
||||
* lock in the atomic increment fallback
|
||||
*
|
||||
* (FIXME but for now we always use the atomic version,
|
||||
* to avoid taking the connection lock, due to
|
||||
* the mess with set_timeout_functions()/set_watch_functions()
|
||||
* calling out to the app without dropping locks)
|
||||
*/
|
||||
|
||||
#if 1
|
||||
_dbus_atomic_inc (&connection->refcount);
|
||||
#else
|
||||
CONNECTION_LOCK (connection);
|
||||
_dbus_assert (connection->refcount.value > 0);
|
||||
|
||||
connection->refcount.value += 1;
|
||||
CONNECTION_UNLOCK (connection);
|
||||
#endif
|
||||
_dbus_atomic_inc (&connection->refcount);
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
|
@ -2788,33 +2764,9 @@ dbus_connection_unref (DBusConnection *connection)
|
|||
|
||||
_dbus_return_if_fail (connection != NULL);
|
||||
_dbus_return_if_fail (connection->generation == _dbus_current_generation);
|
||||
|
||||
/* The connection lock is better than the global
|
||||
* lock in the atomic increment fallback
|
||||
*
|
||||
* (FIXME but for now we always use the atomic version,
|
||||
* to avoid taking the connection lock, due to
|
||||
* the mess with set_timeout_functions()/set_watch_functions()
|
||||
* calling out to the app without dropping locks)
|
||||
*/
|
||||
|
||||
#if 1
|
||||
|
||||
last_unref = (_dbus_atomic_dec (&connection->refcount) == 1);
|
||||
#else
|
||||
CONNECTION_LOCK (connection);
|
||||
|
||||
_dbus_assert (connection->refcount.value > 0);
|
||||
|
||||
connection->refcount.value -= 1;
|
||||
last_unref = (connection->refcount.value == 0);
|
||||
|
||||
#if 0
|
||||
printf ("unref() connection %p count = %d\n", connection, connection->refcount.value);
|
||||
#endif
|
||||
|
||||
CONNECTION_UNLOCK (connection);
|
||||
#endif
|
||||
|
||||
if (last_unref)
|
||||
{
|
||||
#ifndef DBUS_DISABLE_CHECKS
|
||||
|
|
@ -3362,8 +3314,9 @@ reply_handler_timeout (void *data)
|
|||
*
|
||||
* If -1 is passed for the timeout, a sane default timeout is used. -1
|
||||
* is typically the best value for the timeout for this reason, unless
|
||||
* you want a very short or very long timeout. If INT_MAX is passed for
|
||||
* the timeout, no timeout will be set and the call will block forever.
|
||||
* you want a very short or very long timeout. If #DBUS_TIMEOUT_INFINITE is
|
||||
* passed for the timeout, no timeout will be set and the call will block
|
||||
* forever.
|
||||
*
|
||||
* @warning if the connection is disconnected or you try to send Unix
|
||||
* file descriptors on a connection that does not support them, the
|
||||
|
|
@ -3375,7 +3328,9 @@ reply_handler_timeout (void *data)
|
|||
* object, or #NULL if connection is disconnected or when you try to
|
||||
* send Unix file descriptors on a connection that does not support
|
||||
* them.
|
||||
* @param timeout_milliseconds timeout in milliseconds, -1 for default or INT_MAX for no timeout
|
||||
* @param timeout_milliseconds timeout in milliseconds, -1 (or
|
||||
* #DBUS_TIMEOUT_USE_DEFAULT) for default or #DBUS_TIMEOUT_INFINITE for no
|
||||
* timeout
|
||||
* @returns #FALSE if no memory, #TRUE otherwise.
|
||||
*
|
||||
*/
|
||||
|
|
@ -3508,7 +3463,9 @@ dbus_connection_send_with_reply (DBusConnection *connection,
|
|||
*
|
||||
* @param connection the connection
|
||||
* @param message the message to send
|
||||
* @param timeout_milliseconds timeout in milliseconds, -1 for default or INT_MAX for no timeout.
|
||||
* @param timeout_milliseconds timeout in milliseconds, -1 (or
|
||||
* #DBUS_TIMEOUT_USE_DEFAULT) for default or #DBUS_TIMEOUT_INFINITE for no
|
||||
* timeout
|
||||
* @param error return location for error message
|
||||
* @returns the message that is the reply or #NULL with an error code if the
|
||||
* function fails.
|
||||
|
|
|
|||
|
|
@ -1468,14 +1468,20 @@ void
|
|||
_dbus_header_byteswap (DBusHeader *header,
|
||||
int new_order)
|
||||
{
|
||||
unsigned char byte_order;
|
||||
|
||||
if (header->byte_order == new_order)
|
||||
return;
|
||||
|
||||
byte_order = _dbus_string_get_byte (&header->data, BYTE_ORDER_OFFSET);
|
||||
_dbus_assert (header->byte_order == byte_order);
|
||||
|
||||
_dbus_marshal_byteswap (&_dbus_header_signature_str,
|
||||
0, header->byte_order,
|
||||
new_order,
|
||||
&header->data, 0);
|
||||
|
||||
_dbus_string_set_byte (&header->data, BYTE_ORDER_OFFSET, new_order);
|
||||
header->byte_order = new_order;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4680,7 +4680,7 @@ dbus_message_demarshal_bytes_needed(const char *buf,
|
|||
|
||||
if (validity == DBUS_VALID)
|
||||
{
|
||||
_dbus_assert(have_message);
|
||||
_dbus_assert (have_message || (header_len + body_len) > len);
|
||||
return header_len + body_len;
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -84,7 +84,9 @@ static dbus_int32_t notify_user_data_slot = -1;
|
|||
* Creates a new pending reply object.
|
||||
*
|
||||
* @param connection connection where reply will arrive
|
||||
* @param timeout_milliseconds length of timeout, -1 for default, INT_MAX for no timeout
|
||||
* @param timeout_milliseconds length of timeout, -1 (or
|
||||
* #DBUS_TIMEOUT_USE_DEFAULT) for default,
|
||||
* #DBUS_TIMEOUT_INFINITE for no timeout
|
||||
* @param timeout_handler timeout handler, takes pending call as data
|
||||
* @returns a new #DBusPendingCall or #NULL if no memory.
|
||||
*/
|
||||
|
|
@ -112,7 +114,7 @@ _dbus_pending_call_new_unlocked (DBusConnection *connection,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (timeout_milliseconds != _DBUS_INT_MAX)
|
||||
if (timeout_milliseconds != DBUS_TIMEOUT_INFINITE)
|
||||
{
|
||||
timeout = _dbus_timeout_new (timeout_milliseconds,
|
||||
timeout_handler,
|
||||
|
|
@ -515,6 +517,26 @@ _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending,
|
|||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def DBUS_TIMEOUT_INFINITE
|
||||
*
|
||||
* An integer constant representing an infinite timeout. This has the
|
||||
* numeric value 0x7fffffff (the largest 32-bit signed integer).
|
||||
*
|
||||
* For source compatibility with D-Bus versions earlier than 1.4.12, use
|
||||
* 0x7fffffff, or INT32_MAX (assuming your platform has it).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def DBUS_TIMEOUT_USE_DEFAULT
|
||||
*
|
||||
* An integer constant representing a request to use the default timeout.
|
||||
* This has numeric value -1.
|
||||
*
|
||||
* For source compatibility with D-Bus versions earlier than 1.4.12, use a
|
||||
* literal -1.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef DBusPendingCall
|
||||
*
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@ DBUS_BEGIN_DECLS
|
|||
* @{
|
||||
*/
|
||||
|
||||
#define DBUS_TIMEOUT_INFINITE ((int) 0x7fffffff)
|
||||
#define DBUS_TIMEOUT_USE_DEFAULT (-1)
|
||||
|
||||
DBUS_EXPORT
|
||||
DBusPendingCall* dbus_pending_call_ref (DBusPendingCall *pending);
|
||||
DBUS_EXPORT
|
||||
|
|
|
|||
5
test/.gitignore
vendored
5
test/.gitignore
vendored
|
|
@ -15,6 +15,7 @@ unbase64
|
|||
*.gcov
|
||||
break-loader
|
||||
spawn-test
|
||||
test-corrupt
|
||||
test-exit
|
||||
test-segfault
|
||||
test-service
|
||||
|
|
@ -23,3 +24,7 @@ decode-gcov
|
|||
shell-test
|
||||
test-shell-service
|
||||
test-names
|
||||
test-loopback
|
||||
test-relay
|
||||
test-dbus-daemon
|
||||
test-marshal
|
||||
|
|
|
|||
|
|
@ -52,7 +52,8 @@ test_segfault_SOURCES = \
|
|||
test_sleep_forever_SOURCES = \
|
||||
test-sleep-forever.c
|
||||
|
||||
# When any programs are not linked to libdbus-internal, fix this.
|
||||
# This assumes that most tests will be linked to libdbus-internal;
|
||||
# tests linked to only the public libdbus have their own CPPFLAGS.
|
||||
AM_CPPFLAGS=-DDBUS_STATIC_BUILD
|
||||
TEST_LIBS=$(top_builddir)/dbus/libdbus-internal.la $(DBUS_TEST_LIBS)
|
||||
|
||||
|
|
@ -69,7 +70,89 @@ shell_test_LDFLAGS=@R_DYNAMIC_LDFLAG@
|
|||
spawn_test_LDADD=$(TEST_LIBS)
|
||||
spawn_test_LDFLAGS=@R_DYNAMIC_LDFLAG@
|
||||
|
||||
EXTRA_DIST=
|
||||
EXTRA_DIST = dbus-test-runner
|
||||
|
||||
testexecdir = $(libdir)/dbus-1.0/test
|
||||
|
||||
testexec_PROGRAMS =
|
||||
|
||||
installable_tests = \
|
||||
test-corrupt \
|
||||
test-dbus-daemon \
|
||||
test-loopback \
|
||||
test-marshal \
|
||||
test-relay \
|
||||
$(NULL)
|
||||
|
||||
installcheck_tests =
|
||||
installcheck_environment = \
|
||||
DBUS_TEST_DAEMON=$(DESTDIR)$(DBUS_DAEMONDIR)/dbus-daemon$(EXEEXT) \
|
||||
DBUS_TEST_SYSCONFDIR=$(DESTDIR)$(sysconfdir)
|
||||
|
||||
TESTS_ENVIRONMENT = \
|
||||
DBUS_TEST_DAEMON=@abs_top_builddir@/bus/dbus-daemon$(EXEEXT) \
|
||||
DBUS_TEST_DATA=@abs_top_builddir@/test/data
|
||||
|
||||
test_corrupt_SOURCES = corrupt.c
|
||||
test_corrupt_CPPFLAGS = $(GLIB_CFLAGS) $(DBUS_GLIB_CFLAGS)
|
||||
test_corrupt_LDFLAGS = @R_DYNAMIC_LDFLAG@
|
||||
test_corrupt_LDADD = $(top_builddir)/dbus/libdbus-1.la \
|
||||
$(GLIB_LIBS) \
|
||||
$(DBUS_GLIB_LIBS)
|
||||
|
||||
test_loopback_SOURCES = loopback.c
|
||||
test_loopback_CPPFLAGS = $(GLIB_CFLAGS) $(DBUS_GLIB_CFLAGS)
|
||||
test_loopback_LDFLAGS = @R_DYNAMIC_LDFLAG@
|
||||
test_loopback_LDADD = $(top_builddir)/dbus/libdbus-1.la \
|
||||
$(GLIB_LIBS) \
|
||||
$(DBUS_GLIB_LIBS)
|
||||
|
||||
test_relay_SOURCES = relay.c
|
||||
test_relay_CPPFLAGS = $(GLIB_CFLAGS) $(DBUS_GLIB_CFLAGS)
|
||||
test_relay_LDFLAGS = @R_DYNAMIC_LDFLAG@
|
||||
test_relay_LDADD = $(top_builddir)/dbus/libdbus-1.la \
|
||||
$(GLIB_LIBS) \
|
||||
$(DBUS_GLIB_LIBS)
|
||||
|
||||
test_dbus_daemon_SOURCES = dbus-daemon.c
|
||||
test_dbus_daemon_CPPFLAGS = $(GLIB_CFLAGS) $(DBUS_GLIB_CFLAGS)
|
||||
test_dbus_daemon_LDFLAGS = @R_DYNAMIC_LDFLAG@
|
||||
test_dbus_daemon_LDADD = $(top_builddir)/dbus/libdbus-1.la \
|
||||
$(GLIB_LIBS) \
|
||||
$(DBUS_GLIB_LIBS)
|
||||
|
||||
test_marshal_SOURCES = marshal.c
|
||||
test_marshal_CPPFLAGS = $(GLIB_CFLAGS) $(DBUS_GLIB_CFLAGS)
|
||||
test_marshal_LDFLAGS = @R_DYNAMIC_LDFLAG@
|
||||
test_marshal_LDADD = $(top_builddir)/dbus/libdbus-1.la \
|
||||
$(GLIB_LIBS) \
|
||||
$(DBUS_GLIB_LIBS)
|
||||
|
||||
if DBUS_ENABLE_MODULAR_TESTS
|
||||
TESTS += $(installable_tests)
|
||||
installcheck_tests += $(installable_tests)
|
||||
|
||||
if DBUS_ENABLE_INSTALLED_TESTS
|
||||
testexec_PROGRAMS += $(installable_tests)
|
||||
else !DBUS_ENABLE_INSTALLED_TESTS
|
||||
testexec_PROGRAMS += $(installable_tests)
|
||||
endif !DBUS_ENABLE_INSTALLED_TESTS
|
||||
|
||||
endif DBUS_ENABLE_MODULAR_TESTS
|
||||
|
||||
# If we're installing the tests into a DESTDIR we can't run them
|
||||
# again using the installed copy, because we don't know how to
|
||||
# do a portable equivalent of setting LD_LIBRARY_PATH.
|
||||
installcheck-local:
|
||||
$(MAKE) check-TESTS TESTS='$$(installcheck_tests)' \
|
||||
TESTS_ENVIRONMENT='$$(installcheck_environment)'
|
||||
if DBUS_ENABLE_INSTALLED_TESTS
|
||||
test -n "$(DESTDIR)" || \
|
||||
$(installcheck_environment) \
|
||||
$(srcdir)/dbus-test-runner \
|
||||
$(testexecdir) \
|
||||
$(testexec_PROGRAMS)
|
||||
endif DBUS_ENABLE_INSTALLED_TESTS
|
||||
|
||||
## keep these in creation order, i.e. uppermost dirs first
|
||||
TESTDIRS= \
|
||||
|
|
|
|||
362
test/corrupt.c
Normal file
362
test/corrupt.c
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
/* Regression test for being disconnected by a corrupt message (fd.o #15578)
|
||||
*
|
||||
* Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
|
||||
* Copyright © 2010-2011 Nokia Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
|
||||
typedef struct {
|
||||
DBusError e;
|
||||
|
||||
DBusServer *server;
|
||||
DBusConnection *server_conn;
|
||||
/* queue of DBusMessage */
|
||||
GQueue client_messages;
|
||||
|
||||
DBusConnection *client_conn;
|
||||
} Fixture;
|
||||
|
||||
static void
|
||||
assert_no_error (const DBusError *e)
|
||||
{
|
||||
if (G_UNLIKELY (dbus_error_is_set (e)))
|
||||
g_error ("expected success but got error: %s: %s", e->name, e->message);
|
||||
}
|
||||
|
||||
static DBusHandlerResult
|
||||
client_message_cb (DBusConnection *client_conn,
|
||||
DBusMessage *message,
|
||||
void *data)
|
||||
{
|
||||
Fixture *f = data;
|
||||
|
||||
g_assert (client_conn == f->client_conn);
|
||||
g_queue_push_tail (&f->client_messages, dbus_message_ref (message));
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
static void
|
||||
new_conn_cb (DBusServer *server,
|
||||
DBusConnection *server_conn,
|
||||
void *data)
|
||||
{
|
||||
Fixture *f = data;
|
||||
|
||||
g_assert (f->server_conn == NULL);
|
||||
f->server_conn = dbus_connection_ref (server_conn);
|
||||
dbus_connection_setup_with_g_main (server_conn, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
setup (Fixture *f,
|
||||
gconstpointer addr)
|
||||
{
|
||||
dbus_error_init (&f->e);
|
||||
g_queue_init (&f->client_messages);
|
||||
|
||||
f->server = dbus_server_listen (addr, &f->e);
|
||||
assert_no_error (&f->e);
|
||||
g_assert (f->server != NULL);
|
||||
|
||||
dbus_server_set_new_connection_function (f->server,
|
||||
new_conn_cb, f, NULL);
|
||||
dbus_server_setup_with_g_main (f->server, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_connect (Fixture *f,
|
||||
gconstpointer addr G_GNUC_UNUSED)
|
||||
{
|
||||
dbus_bool_t have_mem;
|
||||
|
||||
g_assert (f->server_conn == NULL);
|
||||
|
||||
f->client_conn = dbus_connection_open_private (
|
||||
dbus_server_get_address (f->server), &f->e);
|
||||
assert_no_error (&f->e);
|
||||
g_assert (f->client_conn != NULL);
|
||||
dbus_connection_setup_with_g_main (f->client_conn, NULL);
|
||||
|
||||
while (f->server_conn == NULL)
|
||||
{
|
||||
g_print (".");
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
have_mem = dbus_connection_add_filter (f->client_conn,
|
||||
client_message_cb, f, NULL);
|
||||
g_assert (have_mem);
|
||||
}
|
||||
|
||||
static void
|
||||
test_message (Fixture *f,
|
||||
gconstpointer addr)
|
||||
{
|
||||
dbus_bool_t have_mem;
|
||||
dbus_uint32_t serial;
|
||||
DBusMessage *outgoing, *incoming;
|
||||
|
||||
test_connect (f, addr);
|
||||
|
||||
outgoing = dbus_message_new_signal ("/com/example/Hello",
|
||||
"com.example.Hello", "Greeting");
|
||||
g_assert (outgoing != NULL);
|
||||
|
||||
have_mem = dbus_connection_send (f->server_conn, outgoing, &serial);
|
||||
g_assert (have_mem);
|
||||
g_assert (serial != 0);
|
||||
|
||||
while (g_queue_is_empty (&f->client_messages))
|
||||
{
|
||||
g_print (".");
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
g_assert_cmpuint (g_queue_get_length (&f->client_messages), ==, 1);
|
||||
|
||||
incoming = g_queue_pop_head (&f->client_messages);
|
||||
|
||||
g_assert (!dbus_message_contains_unix_fds (incoming));
|
||||
g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL);
|
||||
g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL);
|
||||
g_assert_cmpstr (dbus_message_get_interface (incoming), ==,
|
||||
"com.example.Hello");
|
||||
g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting");
|
||||
g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL);
|
||||
g_assert_cmpstr (dbus_message_get_signature (incoming), ==, "");
|
||||
g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello");
|
||||
g_assert_cmpuint (dbus_message_get_serial (incoming), ==, serial);
|
||||
|
||||
dbus_message_unref (incoming);
|
||||
|
||||
dbus_message_unref (outgoing);
|
||||
}
|
||||
|
||||
/* Enough bytes for it to be obvious that this connection is broken */
|
||||
#define CORRUPT_LEN 1024
|
||||
|
||||
/* All-zero is not a valid D-Bus message header - for a start, this is
|
||||
* protocol version 1, not 0 */
|
||||
static const gchar not_a_dbus_message[CORRUPT_LEN] = { 0 };
|
||||
|
||||
static void
|
||||
test_corrupt (Fixture *f,
|
||||
gconstpointer addr)
|
||||
{
|
||||
GSocket *socket;
|
||||
GError *gerror = NULL;
|
||||
int fd;
|
||||
gssize len, total_sent;
|
||||
DBusMessage *incoming;
|
||||
|
||||
test_message (f, addr);
|
||||
|
||||
dbus_connection_flush (f->server_conn);
|
||||
|
||||
/* OK, now the connection is working, let's break it! Don't try this
|
||||
* at home; splicing arbitrary bytes into the middle of the stream is
|
||||
* specifically documented as not a valid thing to do. Who'd have thought? */
|
||||
if (!dbus_connection_get_socket (f->server_conn, &fd))
|
||||
g_error ("failed to steal fd from server connection");
|
||||
|
||||
socket = g_socket_new_from_fd (fd, &gerror);
|
||||
g_assert_no_error (gerror);
|
||||
g_assert (socket != NULL);
|
||||
|
||||
total_sent = 0;
|
||||
|
||||
while (total_sent < CORRUPT_LEN)
|
||||
{
|
||||
len = g_socket_send_with_blocking (socket,
|
||||
not_a_dbus_message + total_sent, CORRUPT_LEN - total_sent,
|
||||
TRUE, NULL, &gerror);
|
||||
g_assert_no_error (gerror);
|
||||
g_assert (len >= 0);
|
||||
total_sent += len;
|
||||
}
|
||||
|
||||
/* Now spin on the client connection: the server just sent it complete
|
||||
* rubbish, so it should disconnect */
|
||||
while (g_queue_is_empty (&f->client_messages))
|
||||
{
|
||||
g_print (".");
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
incoming = g_queue_pop_head (&f->client_messages);
|
||||
|
||||
g_assert (!dbus_message_contains_unix_fds (incoming));
|
||||
g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL);
|
||||
g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL);
|
||||
g_assert_cmpstr (dbus_message_get_interface (incoming), ==,
|
||||
"org.freedesktop.DBus.Local");
|
||||
g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Disconnected");
|
||||
g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL);
|
||||
g_assert_cmpstr (dbus_message_get_signature (incoming), ==, "");
|
||||
g_assert_cmpstr (dbus_message_get_path (incoming), ==,
|
||||
"/org/freedesktop/DBus/Local");
|
||||
|
||||
dbus_message_unref (incoming);
|
||||
}
|
||||
|
||||
static void
|
||||
test_byte_order (Fixture *f,
|
||||
gconstpointer addr)
|
||||
{
|
||||
GSocket *socket;
|
||||
GError *gerror = NULL;
|
||||
int fd;
|
||||
char *blob;
|
||||
const gchar *arg = not_a_dbus_message;
|
||||
const gchar * const *args = &arg;
|
||||
int blob_len, len, total_sent;
|
||||
DBusMessage *message;
|
||||
dbus_bool_t mem;
|
||||
|
||||
test_message (f, addr);
|
||||
|
||||
message = dbus_message_new_signal ("/", "a.b", "c");
|
||||
g_assert (message != NULL);
|
||||
/* Append 0xFF bytes, so that the length of the body when byte-swapped
|
||||
* is 0xFF000000, which is invalid */
|
||||
mem = dbus_message_append_args (message,
|
||||
DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &args, 0xFF,
|
||||
DBUS_TYPE_INVALID);
|
||||
g_assert (mem);
|
||||
mem = dbus_message_marshal (message, &blob, &blob_len);
|
||||
g_assert (mem);
|
||||
g_assert_cmpuint (blob_len, >, 0xFF);
|
||||
g_assert (blob != NULL);
|
||||
|
||||
dbus_message_unref (message);
|
||||
|
||||
/* Break the message by changing its claimed byte order, without actually
|
||||
* byteswapping anything. We happen to know that byte order is the first
|
||||
* byte. */
|
||||
if (blob[0] == 'B')
|
||||
blob[0] = 'l';
|
||||
else
|
||||
blob[0] = 'B';
|
||||
|
||||
/* OK, now the connection is working, let's break it */
|
||||
|
||||
dbus_connection_flush (f->server_conn);
|
||||
|
||||
if (!dbus_connection_get_socket (f->server_conn, &fd))
|
||||
g_error ("failed to steal fd from server connection");
|
||||
|
||||
socket = g_socket_new_from_fd (fd, &gerror);
|
||||
g_assert_no_error (gerror);
|
||||
g_assert (socket != NULL);
|
||||
|
||||
total_sent = 0;
|
||||
|
||||
while (total_sent < blob_len)
|
||||
{
|
||||
len = g_socket_send_with_blocking (socket, blob + total_sent,
|
||||
blob_len - total_sent, TRUE, NULL, &gerror);
|
||||
g_assert_no_error (gerror);
|
||||
g_assert (len >= 0);
|
||||
total_sent += len;
|
||||
}
|
||||
|
||||
dbus_free (blob);
|
||||
|
||||
/* Now spin on the client connection: the server just sent it a faulty
|
||||
* message, so it should disconnect */
|
||||
while (g_queue_is_empty (&f->client_messages))
|
||||
{
|
||||
g_print (".");
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
message = g_queue_pop_head (&f->client_messages);
|
||||
|
||||
g_assert (!dbus_message_contains_unix_fds (message));
|
||||
g_assert_cmpstr (dbus_message_get_destination (message), ==, NULL);
|
||||
g_assert_cmpstr (dbus_message_get_error_name (message), ==, NULL);
|
||||
g_assert_cmpstr (dbus_message_get_interface (message), ==,
|
||||
"org.freedesktop.DBus.Local");
|
||||
g_assert_cmpstr (dbus_message_get_member (message), ==, "Disconnected");
|
||||
g_assert_cmpstr (dbus_message_get_sender (message), ==, NULL);
|
||||
g_assert_cmpstr (dbus_message_get_signature (message), ==, "");
|
||||
g_assert_cmpstr (dbus_message_get_path (message), ==,
|
||||
"/org/freedesktop/DBus/Local");
|
||||
|
||||
dbus_message_unref (message);
|
||||
}
|
||||
|
||||
static void
|
||||
teardown (Fixture *f,
|
||||
gconstpointer addr G_GNUC_UNUSED)
|
||||
{
|
||||
if (f->client_conn != NULL)
|
||||
{
|
||||
dbus_connection_close (f->client_conn);
|
||||
dbus_connection_unref (f->client_conn);
|
||||
f->client_conn = NULL;
|
||||
}
|
||||
|
||||
if (f->server_conn != NULL)
|
||||
{
|
||||
dbus_connection_close (f->server_conn);
|
||||
dbus_connection_unref (f->server_conn);
|
||||
f->server_conn = NULL;
|
||||
}
|
||||
|
||||
if (f->server != NULL)
|
||||
{
|
||||
dbus_server_disconnect (f->server);
|
||||
dbus_server_unref (f->server);
|
||||
f->server = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
g_type_init ();
|
||||
|
||||
g_test_add ("/corrupt/tcp", Fixture, "tcp:host=127.0.0.1", setup,
|
||||
test_corrupt, teardown);
|
||||
|
||||
#ifdef DBUS_UNIX
|
||||
g_test_add ("/corrupt/unix", Fixture, "unix:tmpdir=/tmp", setup,
|
||||
test_corrupt, teardown);
|
||||
#endif
|
||||
|
||||
g_test_add ("/corrupt/byte-order/tcp", Fixture, "tcp:host=127.0.0.1", setup,
|
||||
test_byte_order, teardown);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
326
test/dbus-daemon.c
Normal file
326
test/dbus-daemon.c
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
/* Integration tests for the dbus-daemon
|
||||
*
|
||||
* Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
|
||||
* Copyright © 2010-2011 Nokia Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifdef DBUS_WIN
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <signal.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
DBusError e;
|
||||
GError *ge;
|
||||
|
||||
gint daemon_pid;
|
||||
|
||||
DBusConnection *left_conn;
|
||||
|
||||
DBusConnection *right_conn;
|
||||
gboolean right_conn_echo;
|
||||
} Fixture;
|
||||
|
||||
#define assert_no_error(e) _assert_no_error (e, __FILE__, __LINE__)
|
||||
static void
|
||||
_assert_no_error (const DBusError *e,
|
||||
const char *file,
|
||||
int line)
|
||||
{
|
||||
if (G_UNLIKELY (dbus_error_is_set (e)))
|
||||
g_error ("%s:%d: expected success but got error: %s: %s",
|
||||
file, line, e->name, e->message);
|
||||
}
|
||||
|
||||
static gchar *
|
||||
spawn_dbus_daemon (gchar *binary,
|
||||
gchar *configuration,
|
||||
gint *daemon_pid)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GString *address;
|
||||
gint address_fd;
|
||||
gchar *argv[] = {
|
||||
binary,
|
||||
configuration,
|
||||
"--nofork",
|
||||
"--print-address=1", /* stdout */
|
||||
NULL
|
||||
};
|
||||
|
||||
g_spawn_async_with_pipes (NULL, /* working directory */
|
||||
argv,
|
||||
NULL, /* envp */
|
||||
G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
|
||||
NULL, /* child_setup */
|
||||
NULL, /* user data */
|
||||
daemon_pid,
|
||||
NULL, /* child's stdin = /dev/null */
|
||||
&address_fd,
|
||||
NULL, /* child's stderr = our stderr */
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
address = g_string_new (NULL);
|
||||
|
||||
/* polling until the dbus-daemon writes out its address is a bit stupid,
|
||||
* but at least it's simple, unlike dbus-launch... in principle we could
|
||||
* use select() here, but life's too short */
|
||||
while (1)
|
||||
{
|
||||
gssize bytes;
|
||||
gchar buf[4096];
|
||||
gchar *newline;
|
||||
|
||||
bytes = read (address_fd, buf, sizeof (buf));
|
||||
|
||||
if (bytes > 0)
|
||||
g_string_append_len (address, buf, bytes);
|
||||
|
||||
newline = strchr (address->str, '\n');
|
||||
|
||||
if (newline != NULL)
|
||||
{
|
||||
g_string_truncate (address, newline - address->str);
|
||||
break;
|
||||
}
|
||||
|
||||
g_usleep (G_USEC_PER_SEC / 10);
|
||||
}
|
||||
|
||||
return g_string_free (address, FALSE);
|
||||
}
|
||||
|
||||
static DBusConnection *
|
||||
connect_to_bus (const gchar *address)
|
||||
{
|
||||
DBusConnection *conn;
|
||||
DBusError error = DBUS_ERROR_INIT;
|
||||
dbus_bool_t ok;
|
||||
|
||||
conn = dbus_connection_open_private (address, &error);
|
||||
assert_no_error (&error);
|
||||
g_assert (conn != NULL);
|
||||
|
||||
ok = dbus_bus_register (conn, &error);
|
||||
assert_no_error (&error);
|
||||
g_assert (ok);
|
||||
g_assert (dbus_bus_get_unique_name (conn) != NULL);
|
||||
|
||||
dbus_connection_setup_with_g_main (conn, NULL);
|
||||
return conn;
|
||||
}
|
||||
|
||||
static DBusHandlerResult
|
||||
echo_filter (DBusConnection *connection,
|
||||
DBusMessage *message,
|
||||
void *user_data)
|
||||
{
|
||||
DBusMessage *reply;
|
||||
DBusError error = DBUS_ERROR_INIT;
|
||||
int *sleep_ms = user_data;
|
||||
|
||||
if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
|
||||
reply = dbus_message_new_method_return (message);
|
||||
|
||||
if (reply == NULL)
|
||||
g_error ("OOM");
|
||||
|
||||
if (!dbus_connection_send (connection, reply, NULL))
|
||||
g_error ("OOM");
|
||||
|
||||
dbus_message_unref (reply);
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
static void
|
||||
setup (Fixture *f,
|
||||
gconstpointer context G_GNUC_UNUSED)
|
||||
{
|
||||
gchar *dbus_daemon;
|
||||
gchar *config;
|
||||
gchar *address;
|
||||
|
||||
f->ge = NULL;
|
||||
dbus_error_init (&f->e);
|
||||
|
||||
dbus_daemon = g_strdup (g_getenv ("DBUS_TEST_DAEMON"));
|
||||
|
||||
if (dbus_daemon == NULL)
|
||||
dbus_daemon = g_strdup ("dbus-daemon");
|
||||
|
||||
if (g_getenv ("DBUS_TEST_SYSCONFDIR") != NULL)
|
||||
{
|
||||
config = g_strdup_printf ("--config-file=%s/dbus-1/session.conf",
|
||||
g_getenv ("DBUS_TEST_SYSCONFDIR"));
|
||||
}
|
||||
else if (g_getenv ("DBUS_TEST_DATA") != NULL)
|
||||
{
|
||||
config = g_strdup_printf (
|
||||
"--config-file=%s/valid-config-files/session.conf",
|
||||
g_getenv ("DBUS_TEST_DATA"));
|
||||
}
|
||||
else
|
||||
{
|
||||
config = g_strdup ("--session");
|
||||
}
|
||||
|
||||
address = spawn_dbus_daemon (dbus_daemon, config, &f->daemon_pid);
|
||||
|
||||
g_free (dbus_daemon);
|
||||
g_free (config);
|
||||
|
||||
f->left_conn = connect_to_bus (address);
|
||||
f->right_conn = connect_to_bus (address);
|
||||
g_free (address);
|
||||
}
|
||||
|
||||
static void
|
||||
add_echo_filter (Fixture *f)
|
||||
{
|
||||
if (!dbus_connection_add_filter (f->right_conn, echo_filter, NULL, NULL))
|
||||
g_error ("OOM");
|
||||
|
||||
f->right_conn_echo = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pc_count (DBusPendingCall *pc,
|
||||
void *data)
|
||||
{
|
||||
guint *received_p = data;
|
||||
|
||||
(*received_p)++;
|
||||
}
|
||||
|
||||
static void
|
||||
test_echo (Fixture *f,
|
||||
gconstpointer context G_GNUC_UNUSED)
|
||||
{
|
||||
guint count = 2000;
|
||||
guint sent;
|
||||
guint received = 0;
|
||||
double elapsed;
|
||||
|
||||
if (g_test_perf ())
|
||||
count = 100000;
|
||||
|
||||
add_echo_filter (f);
|
||||
|
||||
g_test_timer_start ();
|
||||
|
||||
for (sent = 0; sent < count; sent++)
|
||||
{
|
||||
DBusMessage *m = dbus_message_new_method_call (
|
||||
dbus_bus_get_unique_name (f->right_conn), "/",
|
||||
"com.example", "Spam");
|
||||
DBusPendingCall *pc;
|
||||
|
||||
if (m == NULL)
|
||||
g_error ("OOM");
|
||||
|
||||
if (!dbus_connection_send_with_reply (f->left_conn, m, &pc,
|
||||
DBUS_TIMEOUT_INFINITE) ||
|
||||
pc == NULL)
|
||||
g_error ("OOM");
|
||||
|
||||
if (dbus_pending_call_get_completed (pc))
|
||||
pc_count (pc, &received);
|
||||
else if (!dbus_pending_call_set_notify (pc, pc_count, &received,
|
||||
NULL))
|
||||
g_error ("OOM");
|
||||
|
||||
dbus_pending_call_unref (pc);
|
||||
dbus_message_unref (m);
|
||||
}
|
||||
|
||||
while (received < count)
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
elapsed = g_test_timer_elapsed ();
|
||||
|
||||
g_test_maximized_result (count / elapsed, "%u messages / %f seconds",
|
||||
count, elapsed);
|
||||
}
|
||||
|
||||
static void
|
||||
teardown (Fixture *f,
|
||||
gconstpointer context G_GNUC_UNUSED)
|
||||
{
|
||||
dbus_error_free (&f->e);
|
||||
g_clear_error (&f->ge);
|
||||
|
||||
if (f->left_conn != NULL)
|
||||
{
|
||||
dbus_connection_close (f->left_conn);
|
||||
dbus_connection_unref (f->left_conn);
|
||||
f->left_conn = NULL;
|
||||
}
|
||||
|
||||
if (f->right_conn != NULL)
|
||||
{
|
||||
if (f->right_conn_echo)
|
||||
{
|
||||
dbus_connection_remove_filter (f->right_conn, echo_filter, NULL);
|
||||
f->right_conn_echo = FALSE;
|
||||
}
|
||||
|
||||
dbus_connection_close (f->right_conn);
|
||||
dbus_connection_unref (f->right_conn);
|
||||
f->right_conn = NULL;
|
||||
}
|
||||
|
||||
#ifdef DBUS_WIN
|
||||
TerminateProcess (f->daemon_pid, 1);
|
||||
#else
|
||||
kill (f->daemon_pid, SIGTERM);
|
||||
#endif
|
||||
|
||||
g_spawn_close_pid (f->daemon_pid);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
|
||||
|
||||
g_test_add ("/echo/session", Fixture, NULL, setup, test_echo, teardown);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
43
test/dbus-test-runner
Executable file
43
test/dbus-test-runner
Executable file
|
|
@ -0,0 +1,43 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
dir="$1"
|
||||
shift
|
||||
|
||||
if ! test -d "$dir"; then
|
||||
echo "Usage: dbus-test-runner directory [executable...]"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
passed=0
|
||||
failed=0
|
||||
skipped=0
|
||||
|
||||
for prog in "$@"; do
|
||||
e=0
|
||||
"$dir/$prog" || e=$?
|
||||
case $e in
|
||||
(0)
|
||||
echo "PASS: $prog"
|
||||
passed=`expr $passed + 1`
|
||||
;;
|
||||
(77)
|
||||
echo "SKIP: $prog"
|
||||
skipped=`expr $skipped + 1`
|
||||
;;
|
||||
(*)
|
||||
echo "FAIL: $prog"
|
||||
failed=`expr $failed + 1`
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if test $failed = 0; then
|
||||
# avoid saying "FAIL", to make it easy to grep results!
|
||||
echo "PASSED $passed / SKIPPED $skipped"
|
||||
exit 0
|
||||
else
|
||||
echo "PASSED $passed / FAILED $failed / SKIPPED $skipped"
|
||||
exit 1
|
||||
fi
|
||||
211
test/loopback.c
Normal file
211
test/loopback.c
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
/* Simple sanity-check for loopback through TCP and Unix sockets.
|
||||
*
|
||||
* Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
|
||||
* Copyright © 2010-2011 Nokia Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
|
||||
typedef struct {
|
||||
DBusError e;
|
||||
|
||||
DBusServer *server;
|
||||
DBusConnection *server_conn;
|
||||
/* queue of DBusMessage */
|
||||
GQueue server_messages;
|
||||
|
||||
DBusConnection *client_conn;
|
||||
} Fixture;
|
||||
|
||||
static void
|
||||
assert_no_error (const DBusError *e)
|
||||
{
|
||||
if (G_UNLIKELY (dbus_error_is_set (e)))
|
||||
g_error ("expected success but got error: %s: %s", e->name, e->message);
|
||||
}
|
||||
|
||||
static DBusHandlerResult
|
||||
server_message_cb (DBusConnection *server_conn,
|
||||
DBusMessage *message,
|
||||
void *data)
|
||||
{
|
||||
Fixture *f = data;
|
||||
|
||||
g_assert (server_conn == f->server_conn);
|
||||
g_queue_push_tail (&f->server_messages, dbus_message_ref (message));
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
static void
|
||||
new_conn_cb (DBusServer *server,
|
||||
DBusConnection *server_conn,
|
||||
void *data)
|
||||
{
|
||||
Fixture *f = data;
|
||||
dbus_bool_t have_mem;
|
||||
|
||||
g_assert (f->server_conn == NULL);
|
||||
f->server_conn = dbus_connection_ref (server_conn);
|
||||
dbus_connection_setup_with_g_main (server_conn, NULL);
|
||||
|
||||
have_mem = dbus_connection_add_filter (server_conn,
|
||||
server_message_cb, f, NULL);
|
||||
g_assert (have_mem);
|
||||
}
|
||||
|
||||
static void
|
||||
setup (Fixture *f,
|
||||
gconstpointer addr)
|
||||
{
|
||||
dbus_error_init (&f->e);
|
||||
g_queue_init (&f->server_messages);
|
||||
|
||||
f->server = dbus_server_listen (addr, &f->e);
|
||||
assert_no_error (&f->e);
|
||||
g_assert (f->server != NULL);
|
||||
|
||||
dbus_server_set_new_connection_function (f->server,
|
||||
new_conn_cb, f, NULL);
|
||||
dbus_server_setup_with_g_main (f->server, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_connect (Fixture *f,
|
||||
gconstpointer addr G_GNUC_UNUSED)
|
||||
{
|
||||
g_assert (f->server_conn == NULL);
|
||||
|
||||
f->client_conn = dbus_connection_open_private (
|
||||
dbus_server_get_address (f->server), &f->e);
|
||||
assert_no_error (&f->e);
|
||||
g_assert (f->client_conn != NULL);
|
||||
dbus_connection_setup_with_g_main (f->client_conn, NULL);
|
||||
|
||||
while (f->server_conn == NULL)
|
||||
{
|
||||
g_print (".");
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_message (Fixture *f,
|
||||
gconstpointer addr)
|
||||
{
|
||||
dbus_bool_t have_mem;
|
||||
dbus_uint32_t serial;
|
||||
DBusMessage *outgoing, *incoming;
|
||||
|
||||
test_connect (f, addr);
|
||||
|
||||
outgoing = dbus_message_new_signal ("/com/example/Hello",
|
||||
"com.example.Hello", "Greeting");
|
||||
g_assert (outgoing != NULL);
|
||||
|
||||
have_mem = dbus_connection_send (f->client_conn, outgoing, &serial);
|
||||
g_assert (have_mem);
|
||||
g_assert (serial != 0);
|
||||
|
||||
while (g_queue_is_empty (&f->server_messages))
|
||||
{
|
||||
g_print (".");
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
g_assert_cmpuint (g_queue_get_length (&f->server_messages), ==, 1);
|
||||
|
||||
incoming = g_queue_pop_head (&f->server_messages);
|
||||
|
||||
g_assert (!dbus_message_contains_unix_fds (incoming));
|
||||
g_assert_cmpstr (dbus_message_get_destination (incoming), ==, NULL);
|
||||
g_assert_cmpstr (dbus_message_get_error_name (incoming), ==, NULL);
|
||||
g_assert_cmpstr (dbus_message_get_interface (incoming), ==,
|
||||
"com.example.Hello");
|
||||
g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Greeting");
|
||||
g_assert_cmpstr (dbus_message_get_sender (incoming), ==, NULL);
|
||||
g_assert_cmpstr (dbus_message_get_signature (incoming), ==, "");
|
||||
g_assert_cmpstr (dbus_message_get_path (incoming), ==, "/com/example/Hello");
|
||||
g_assert_cmpuint (dbus_message_get_serial (incoming), ==, serial);
|
||||
|
||||
dbus_message_unref (incoming);
|
||||
|
||||
dbus_message_unref (outgoing);
|
||||
}
|
||||
|
||||
static void
|
||||
teardown (Fixture *f,
|
||||
gconstpointer addr G_GNUC_UNUSED)
|
||||
{
|
||||
if (f->client_conn != NULL)
|
||||
{
|
||||
dbus_connection_close (f->client_conn);
|
||||
dbus_connection_unref (f->client_conn);
|
||||
f->client_conn = NULL;
|
||||
}
|
||||
|
||||
if (f->server_conn != NULL)
|
||||
{
|
||||
dbus_connection_close (f->server_conn);
|
||||
dbus_connection_unref (f->server_conn);
|
||||
f->server_conn = NULL;
|
||||
}
|
||||
|
||||
if (f->server != NULL)
|
||||
{
|
||||
dbus_server_disconnect (f->server);
|
||||
dbus_server_unref (f->server);
|
||||
f->server = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add ("/connect/tcp", Fixture, "tcp:host=127.0.0.1", setup,
|
||||
test_connect, teardown);
|
||||
g_test_add ("/message/tcp", Fixture, "tcp:host=127.0.0.1", setup,
|
||||
test_message, teardown);
|
||||
|
||||
g_test_add ("/connect/nonce-tcp", Fixture, "nonce-tcp:host=127.0.0.1", setup,
|
||||
test_connect, teardown);
|
||||
g_test_add ("/message/nonce-tcp", Fixture, "nonce-tcp:host=127.0.0.1", setup,
|
||||
test_message, teardown);
|
||||
|
||||
#ifdef DBUS_UNIX
|
||||
g_test_add ("/connect/unix", Fixture, "unix:tmpdir=/tmp", setup,
|
||||
test_connect, teardown);
|
||||
g_test_add ("/message/unix", Fixture, "unix:tmpdir=/tmp", setup,
|
||||
test_message, teardown);
|
||||
#endif
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
258
test/marshal.c
Normal file
258
test/marshal.c
Normal file
|
|
@ -0,0 +1,258 @@
|
|||
/* Simple sanity-check for D-Bus message serialization.
|
||||
*
|
||||
* Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
|
||||
* Copyright © 2010-2011 Nokia Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
|
||||
typedef struct {
|
||||
DBusError e;
|
||||
} Fixture;
|
||||
|
||||
static void
|
||||
assert_no_error (const DBusError *e)
|
||||
{
|
||||
if (G_UNLIKELY (dbus_error_is_set (e)))
|
||||
g_error ("expected success but got error: %s: %s", e->name, e->message);
|
||||
}
|
||||
|
||||
static void
|
||||
setup (Fixture *f,
|
||||
gconstpointer arg G_GNUC_UNUSED)
|
||||
{
|
||||
dbus_error_init (&f->e);
|
||||
}
|
||||
|
||||
/* this is meant to be obviously correct, not efficient! */
|
||||
static guint32
|
||||
get_uint32 (const gchar *blob,
|
||||
gsize offset,
|
||||
char endian)
|
||||
{
|
||||
if (endian == 'l')
|
||||
{
|
||||
return
|
||||
blob[offset] |
|
||||
(blob[offset + 1] << 8) |
|
||||
(blob[offset + 2] << 16) |
|
||||
(blob[offset + 3] << 24);
|
||||
}
|
||||
else if (endian == 'B')
|
||||
{
|
||||
return
|
||||
(blob[offset] << 24) |
|
||||
(blob[offset + 1] << 16) |
|
||||
(blob[offset + 2] << 8) |
|
||||
blob[offset + 3];
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
}
|
||||
|
||||
#define BLOB_LENGTH (sizeof (le_blob) - 1)
|
||||
#define OFFSET_BODY_LENGTH (4)
|
||||
#define OFFSET_SERIAL (8)
|
||||
|
||||
const gchar le_blob[] =
|
||||
/* byte 0 */
|
||||
/* yyyyuu fixed headers */
|
||||
"l" /* little-endian */
|
||||
"\2" /* reply (which is the simplest message) */
|
||||
"\2" /* no auto-starting */
|
||||
"\1" /* D-Bus version = 1 */
|
||||
/* byte 4 */
|
||||
"\4\0\0\0" /* bytes in body = 4 */
|
||||
/* byte 8 */
|
||||
"\x78\x56\x34\x12" /* serial number = 0x12345678 */
|
||||
/* byte 12 */
|
||||
/* a(uv) variable headers start here */
|
||||
"\x0f\0\0\0" /* bytes in array of variable headers = 15 */
|
||||
/* pad to 8-byte boundary = nothing */
|
||||
/* byte 16 */
|
||||
"\5" /* in reply to: */
|
||||
"\1u\0" /* variant signature = u */
|
||||
/* pad to 4-byte boundary = nothing */
|
||||
"\x12\xef\xcd\xab" /* 0xabcdef12 */
|
||||
/* pad to 8-byte boundary = nothing */
|
||||
/* byte 24 */
|
||||
"\x08" /* signature: */
|
||||
"\1g\0" /* variant signature = g */
|
||||
"\1u\0" /* 1 byte, u, NUL (no alignment needed) */
|
||||
"\0" /* pad to 8-byte boundary for body */
|
||||
/* body; byte 32 */
|
||||
"\xef\xbe\xad\xde" /* 0xdeadbeef */
|
||||
;
|
||||
|
||||
const gchar be_blob[] =
|
||||
/* byte 0 */
|
||||
/* yyyyuu fixed headers */
|
||||
"B" /* big-endian */
|
||||
"\2" /* reply (which is the simplest message) */
|
||||
"\2" /* no auto-starting */
|
||||
"\1" /* D-Bus version = 1 */
|
||||
/* byte 4 */
|
||||
"\0\0\0\4" /* bytes in body = 4 */
|
||||
/* byte 8 */
|
||||
"\x12\x34\x56\x78" /* serial number = 0x12345678 */
|
||||
/* byte 12 */
|
||||
/* a(uv) variable headers start here */
|
||||
"\0\0\0\x0f" /* bytes in array of variable headers = 15 */
|
||||
/* pad to 8-byte boundary = nothing */
|
||||
/* byte 16 */
|
||||
"\5" /* in reply to: */
|
||||
"\1u\0" /* variant signature = u */
|
||||
/* pad to 4-byte boundary = nothing */
|
||||
"\xab\xcd\xef\x12" /* 0xabcdef12 */
|
||||
/* pad to 8-byte boundary = nothing */
|
||||
/* byte 24 */
|
||||
"\x08" /* signature: */
|
||||
"\1g\0" /* variant signature = g */
|
||||
"\1u\0" /* 1 byte, u, NUL (no alignment needed) */
|
||||
"\0" /* pad to 8-byte boundary for body */
|
||||
/* body; byte 32 */
|
||||
"\xde\xad\xbe\xef" /* 0xdeadbeef */
|
||||
;
|
||||
|
||||
static void
|
||||
test_endian (Fixture *f,
|
||||
gconstpointer arg)
|
||||
{
|
||||
const gchar *blob = arg;
|
||||
const gchar *native_blob;
|
||||
char *output;
|
||||
DBusMessage *m;
|
||||
int len;
|
||||
dbus_uint32_t u;
|
||||
dbus_bool_t ok;
|
||||
|
||||
g_assert_cmpuint ((guint) sizeof (le_blob), ==, (guint) sizeof (be_blob));
|
||||
|
||||
g_assert_cmpuint (get_uint32 (blob, OFFSET_BODY_LENGTH, blob[0]), ==, 4);
|
||||
g_assert_cmpuint (get_uint32 (blob, OFFSET_SERIAL, blob[0]), ==,
|
||||
0x12345678u);
|
||||
|
||||
len = dbus_message_demarshal_bytes_needed (blob, sizeof (le_blob));
|
||||
/* everything in the string except the implicit "\0" at the end is part of
|
||||
* the message */
|
||||
g_assert_cmpint (len, ==, BLOB_LENGTH);
|
||||
|
||||
m = dbus_message_demarshal (blob, sizeof (le_blob), &f->e);
|
||||
assert_no_error (&f->e);
|
||||
g_assert (m != NULL);
|
||||
|
||||
g_assert_cmpuint (dbus_message_get_serial (m), ==, 0x12345678u);
|
||||
g_assert_cmpuint (dbus_message_get_reply_serial (m), ==, 0xabcdef12u);
|
||||
g_assert_cmpstr (dbus_message_get_signature (m), ==, "u");
|
||||
|
||||
/* Implementation detail: appending to the message results in it being
|
||||
* byteswapped into compiler byte order, which exposed a bug in libdbus,
|
||||
* fd.o #38120. (If that changes, this test might not exercise that
|
||||
* particular bug but will still be valid.) */
|
||||
u = 0xdecafbadu;
|
||||
ok = dbus_message_append_args (m,
|
||||
DBUS_TYPE_UINT32, &u,
|
||||
DBUS_TYPE_INVALID);
|
||||
g_assert (ok);
|
||||
|
||||
dbus_message_marshal (m, &output, &len);
|
||||
|
||||
g_assert (output[0] == 'l' || output[0] == 'B');
|
||||
/* the single-byte fields are unaffected, even if the endianness was
|
||||
* swapped */
|
||||
g_assert_cmpint (output[1], ==, blob[1]);
|
||||
g_assert_cmpint (output[2], ==, blob[2]);
|
||||
g_assert_cmpint (output[3], ==, blob[3]);
|
||||
/* the length and serial are in the new endianness, the length has expanded
|
||||
* to 8, and the serial is correct */
|
||||
g_assert_cmpuint (get_uint32 (output, OFFSET_BODY_LENGTH, output[0]), ==, 8);
|
||||
g_assert_cmpuint (get_uint32 (output, OFFSET_SERIAL, output[0]), ==,
|
||||
0x12345678u);
|
||||
/* the second "u" in the signature replaced a padding byte, so only
|
||||
* the length of the body changed */
|
||||
g_assert_cmpint (len, ==, BLOB_LENGTH + 4);
|
||||
}
|
||||
|
||||
static void
|
||||
test_needed (Fixture *f,
|
||||
gconstpointer arg)
|
||||
{
|
||||
const gchar *blob = arg;
|
||||
|
||||
/* We need at least 16 bytes to know how long the message is - that's just
|
||||
* a fact of the D-Bus protocol. */
|
||||
g_assert_cmpint (
|
||||
dbus_message_demarshal_bytes_needed (blob, 0), ==, 0);
|
||||
g_assert_cmpint (
|
||||
dbus_message_demarshal_bytes_needed (blob, 15), ==, 0);
|
||||
/* This is enough that we should be able to tell how much we need. */
|
||||
g_assert_cmpint (
|
||||
dbus_message_demarshal_bytes_needed (blob, 16), ==, BLOB_LENGTH);
|
||||
/* The header is 32 bytes long (here), so that's another interesting
|
||||
* boundary. */
|
||||
g_assert_cmpint (
|
||||
dbus_message_demarshal_bytes_needed (blob, 31), ==, BLOB_LENGTH);
|
||||
g_assert_cmpint (
|
||||
dbus_message_demarshal_bytes_needed (blob, 32), ==, BLOB_LENGTH);
|
||||
g_assert_cmpint (
|
||||
dbus_message_demarshal_bytes_needed (blob, 33), ==, BLOB_LENGTH);
|
||||
g_assert_cmpint (
|
||||
dbus_message_demarshal_bytes_needed (blob, BLOB_LENGTH - 1), ==,
|
||||
BLOB_LENGTH);
|
||||
g_assert_cmpint (
|
||||
dbus_message_demarshal_bytes_needed (blob, BLOB_LENGTH), ==,
|
||||
BLOB_LENGTH);
|
||||
g_assert_cmpint (
|
||||
dbus_message_demarshal_bytes_needed (blob, sizeof (be_blob)), ==,
|
||||
BLOB_LENGTH);
|
||||
}
|
||||
|
||||
static void
|
||||
teardown (Fixture *f,
|
||||
gconstpointer arg G_GNUC_UNUSED)
|
||||
{
|
||||
dbus_error_free (&f->e);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add ("/demarshal/le", Fixture, le_blob, setup, test_endian, teardown);
|
||||
g_test_add ("/demarshal/be", Fixture, be_blob, setup, test_endian, teardown);
|
||||
g_test_add ("/demarshal/needed/le", Fixture, le_blob, setup, test_needed,
|
||||
teardown);
|
||||
g_test_add ("/demarshal/needed/be", Fixture, be_blob, setup, test_needed,
|
||||
teardown);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
318
test/relay.c
Normal file
318
test/relay.c
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
/* Regression test for passing unmodified messages between connections
|
||||
*
|
||||
* Author: Simon McVittie <simon.mcvittie@collabora.co.uk>
|
||||
* Copyright © 2010-2011 Nokia Corporation
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
|
||||
/* This is basically a miniature dbus-daemon. We relay messages from the client
|
||||
* on the left to the client on the right.
|
||||
*
|
||||
* left socket left dispatch right socket right
|
||||
* client ===========> server --------------> server ===========> client
|
||||
* conn conn conn conn
|
||||
*
|
||||
* In the real dbus-daemon, the client connections would be out-of-process,
|
||||
* but here we're cheating and doing everything in-process.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
DBusError e;
|
||||
|
||||
DBusServer *server;
|
||||
|
||||
DBusConnection *left_client_conn;
|
||||
DBusConnection *left_server_conn;
|
||||
|
||||
DBusConnection *right_server_conn;
|
||||
DBusConnection *right_client_conn;
|
||||
/* queue of DBusMessage received by right_client_conn */
|
||||
GQueue messages;
|
||||
} Fixture;
|
||||
|
||||
static void
|
||||
assert_no_error (const DBusError *e)
|
||||
{
|
||||
if (G_UNLIKELY (dbus_error_is_set (e)))
|
||||
g_error ("expected success but got error: %s: %s", e->name, e->message);
|
||||
}
|
||||
|
||||
static DBusHandlerResult
|
||||
server_message_cb (DBusConnection *server_conn,
|
||||
DBusMessage *message,
|
||||
void *data)
|
||||
{
|
||||
Fixture *f = data;
|
||||
|
||||
g_assert (server_conn == f->left_server_conn);
|
||||
g_assert (f->right_server_conn != NULL);
|
||||
|
||||
dbus_connection_send (f->right_server_conn, message, NULL);
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
static DBusHandlerResult
|
||||
right_client_message_cb (DBusConnection *client_conn,
|
||||
DBusMessage *message,
|
||||
void *data)
|
||||
{
|
||||
Fixture *f = data;
|
||||
|
||||
g_assert (client_conn == f->right_client_conn);
|
||||
g_queue_push_tail (&f->messages, dbus_message_ref (message));
|
||||
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
|
||||
static void
|
||||
new_conn_cb (DBusServer *server,
|
||||
DBusConnection *server_conn,
|
||||
void *data)
|
||||
{
|
||||
Fixture *f = data;
|
||||
dbus_bool_t have_mem;
|
||||
|
||||
if (f->left_server_conn == NULL)
|
||||
{
|
||||
f->left_server_conn = dbus_connection_ref (server_conn);
|
||||
|
||||
have_mem = dbus_connection_add_filter (server_conn,
|
||||
server_message_cb, f, NULL);
|
||||
g_assert (have_mem);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_assert (f->right_server_conn == NULL);
|
||||
f->right_server_conn = dbus_connection_ref (server_conn);
|
||||
}
|
||||
|
||||
dbus_connection_setup_with_g_main (server_conn, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
setup (Fixture *f,
|
||||
gconstpointer data G_GNUC_UNUSED)
|
||||
{
|
||||
dbus_error_init (&f->e);
|
||||
g_queue_init (&f->messages);
|
||||
|
||||
f->server = dbus_server_listen ("tcp:host=127.0.0.1", &f->e);
|
||||
assert_no_error (&f->e);
|
||||
g_assert (f->server != NULL);
|
||||
|
||||
dbus_server_set_new_connection_function (f->server,
|
||||
new_conn_cb, f, NULL);
|
||||
dbus_server_setup_with_g_main (f->server, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_connect (Fixture *f,
|
||||
gconstpointer data G_GNUC_UNUSED)
|
||||
{
|
||||
dbus_bool_t have_mem;
|
||||
|
||||
g_assert (f->left_server_conn == NULL);
|
||||
g_assert (f->right_server_conn == NULL);
|
||||
|
||||
f->left_client_conn = dbus_connection_open_private (
|
||||
dbus_server_get_address (f->server), &f->e);
|
||||
assert_no_error (&f->e);
|
||||
g_assert (f->left_client_conn != NULL);
|
||||
dbus_connection_setup_with_g_main (f->left_client_conn, NULL);
|
||||
|
||||
while (f->left_server_conn == NULL)
|
||||
{
|
||||
g_print (".");
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
f->right_client_conn = dbus_connection_open_private (
|
||||
dbus_server_get_address (f->server), &f->e);
|
||||
assert_no_error (&f->e);
|
||||
g_assert (f->right_client_conn != NULL);
|
||||
dbus_connection_setup_with_g_main (f->right_client_conn, NULL);
|
||||
|
||||
while (f->right_server_conn == NULL)
|
||||
{
|
||||
g_print (".");
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
have_mem = dbus_connection_add_filter (f->right_client_conn,
|
||||
right_client_message_cb, f, NULL);
|
||||
g_assert (have_mem);
|
||||
}
|
||||
|
||||
static dbus_uint32_t
|
||||
send_one (Fixture *f,
|
||||
const char *member)
|
||||
{
|
||||
dbus_bool_t have_mem;
|
||||
dbus_uint32_t serial;
|
||||
DBusMessage *outgoing;
|
||||
|
||||
outgoing = dbus_message_new_signal ("/com/example/Hello",
|
||||
"com.example.Hello", member);
|
||||
g_assert (outgoing != NULL);
|
||||
|
||||
have_mem = dbus_connection_send (f->left_client_conn, outgoing, &serial);
|
||||
g_assert (have_mem);
|
||||
g_assert (serial != 0);
|
||||
|
||||
dbus_message_unref (outgoing);
|
||||
return serial;
|
||||
}
|
||||
|
||||
static void
|
||||
test_relay (Fixture *f,
|
||||
gconstpointer data)
|
||||
{
|
||||
DBusMessage *incoming;
|
||||
|
||||
test_connect (f, data);
|
||||
|
||||
send_one (f, "First");
|
||||
send_one (f, "Second");
|
||||
|
||||
while (g_queue_get_length (&f->messages) < 2)
|
||||
{
|
||||
g_print (".");
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
g_assert_cmpuint (g_queue_get_length (&f->messages), ==, 2);
|
||||
|
||||
incoming = g_queue_pop_head (&f->messages);
|
||||
g_assert_cmpstr (dbus_message_get_member (incoming), ==, "First");
|
||||
dbus_message_unref (incoming);
|
||||
|
||||
incoming = g_queue_pop_head (&f->messages);
|
||||
g_assert_cmpstr (dbus_message_get_member (incoming), ==, "Second");
|
||||
dbus_message_unref (incoming);
|
||||
}
|
||||
|
||||
/* An arbitrary number of messages */
|
||||
#define MANY 8192
|
||||
|
||||
static void
|
||||
test_limit (Fixture *f,
|
||||
gconstpointer data)
|
||||
{
|
||||
DBusMessage *incoming;
|
||||
guint i;
|
||||
|
||||
test_connect (f, data);
|
||||
|
||||
/* This was an attempt to reproduce fd.o #34393. It didn't work. */
|
||||
g_test_bug ("34393");
|
||||
dbus_connection_set_max_received_size (f->left_server_conn, 1);
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
|
||||
for (i = 0; i < MANY; i++)
|
||||
{
|
||||
gchar *buf = g_strdup_printf ("Message%u", i);
|
||||
|
||||
send_one (f, buf);
|
||||
g_free (buf);
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
||||
while (i < MANY)
|
||||
{
|
||||
while (g_queue_is_empty (&f->messages))
|
||||
{
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
}
|
||||
|
||||
while ((incoming = g_queue_pop_head (&f->messages)) != NULL)
|
||||
{
|
||||
i++;
|
||||
dbus_message_unref (incoming);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
teardown (Fixture *f,
|
||||
gconstpointer data G_GNUC_UNUSED)
|
||||
{
|
||||
if (f->left_client_conn != NULL)
|
||||
{
|
||||
dbus_connection_close (f->left_client_conn);
|
||||
dbus_connection_unref (f->left_client_conn);
|
||||
f->left_client_conn = NULL;
|
||||
}
|
||||
|
||||
if (f->right_client_conn != NULL)
|
||||
{
|
||||
dbus_connection_close (f->right_client_conn);
|
||||
dbus_connection_unref (f->right_client_conn);
|
||||
f->right_client_conn = NULL;
|
||||
}
|
||||
|
||||
if (f->left_server_conn != NULL)
|
||||
{
|
||||
dbus_connection_close (f->left_server_conn);
|
||||
dbus_connection_unref (f->left_server_conn);
|
||||
f->left_server_conn = NULL;
|
||||
}
|
||||
|
||||
if (f->right_server_conn != NULL)
|
||||
{
|
||||
dbus_connection_close (f->right_server_conn);
|
||||
dbus_connection_unref (f->right_server_conn);
|
||||
f->right_server_conn = NULL;
|
||||
}
|
||||
|
||||
if (f->server != NULL)
|
||||
{
|
||||
dbus_server_disconnect (f->server);
|
||||
dbus_server_unref (f->server);
|
||||
f->server = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char **argv)
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id=");
|
||||
|
||||
g_test_add ("/connect", Fixture, NULL, setup,
|
||||
test_connect, teardown);
|
||||
g_test_add ("/relay", Fixture, NULL, setup,
|
||||
test_relay, teardown);
|
||||
g_test_add ("/limit", Fixture, NULL, setup,
|
||||
test_limit, teardown);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue