summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon McVittie <smcv@debian.org>2014-11-06 21:09:28 +0000
committerSimon McVittie <smcv@debian.org>2014-11-06 21:09:28 +0000
commit910f72ed10f027bfda4371997678e141b9b1ba0f (patch)
tree294f20034c9f437c2fb27032d7c6bae05aef0f12
parentacd824dea246a39328c5519a325d92b691c5c9c6 (diff)
parent3d6d7094d5f391a287db6eb9556def65755a3463 (diff)
downloaddbus-910f72ed10f027bfda4371997678e141b9b1ba0f.tar.gz
Merge tag 'upstream/1.9.2' into experimental
Upstream version 1.9.2 Conflicts: NEWS configure.ac
-rw-r--r--Makefile.in9
-rw-r--r--NEWS74
-rw-r--r--aclocal.m47
-rw-r--r--bus/Makefile.in1
-rw-r--r--bus/activation.c28
-rw-r--r--bus/bus.c50
-rw-r--r--bus/bus.h1
-rw-r--r--bus/connection.c7
-rw-r--r--bus/dir-watch-kqueue.c1
-rw-r--r--bus/dispatch.c5
-rw-r--r--bus/test-main.c9
-rw-r--r--cmake/CMakeLists.txt3
-rw-r--r--cmake/ConfigureChecks.cmake6
-rw-r--r--cmake/config.h.cmake8
-rw-r--r--cmake/test/CMakeLists.txt9
-rw-r--r--config.h.in3
-rwxr-xr-xconfigure105
-rw-r--r--configure.ac15
-rw-r--r--dbus-1-uninstalled.pc.in13
-rw-r--r--dbus-1.pc.in13
-rw-r--r--dbus/Makefile.in1
-rw-r--r--dbus/dbus-auth.c2
-rw-r--r--dbus/dbus-memory.c7
-rw-r--r--dbus/dbus-message.c48
-rw-r--r--dbus/dbus-message.h8
-rw-r--r--dbus/dbus-nonce.c8
-rw-r--r--dbus/dbus-protocol.h9
-rw-r--r--dbus/dbus-server-socket.c7
-rw-r--r--dbus/dbus-spawn.c20
-rw-r--r--dbus/dbus-sysdeps-unix.c74
-rw-r--r--dbus/dbus-sysdeps-util-unix.c145
-rw-r--r--dbus/dbus-sysdeps-util-win.c35
-rw-r--r--dbus/dbus-sysdeps-win.c18
-rw-r--r--dbus/dbus-sysdeps.c30
-rw-r--r--dbus/dbus-sysdeps.h24
-rw-r--r--dbus/dbus-test-main.c9
-rw-r--r--dbus/dbus-transport-socket.c47
-rw-r--r--doc/Makefile.in1
-rw-r--r--doc/dbus-daemon.1.xml.in8
-rw-r--r--doc/dbus-specification.xml122
-rw-r--r--doc/dbus-tutorial.xml952
-rw-r--r--ltmain.sh4
-rw-r--r--test/Makefile.am1
-rw-r--r--test/Makefile.in2
-rw-r--r--test/data/valid-config-files/finite-timeout.conf.in19
-rw-r--r--test/dbus-daemon.c192
-rw-r--r--test/name-test/Makefile.in1
-rw-r--r--test/name-test/test-threads-init.c10
-rwxr-xr-xtools/GetAllMatchRules.py112
-rw-r--r--tools/Makefile.am16
-rw-r--r--tools/Makefile.in130
-rw-r--r--tools/dbus-echo.c243
-rw-r--r--tools/dbus-spam.c521
-rw-r--r--tools/test-tool.c88
-rw-r--r--tools/test-tool.h31
-rw-r--r--tools/tool-common.c60
-rw-r--r--tools/tool-common.h38
57 files changed, 2283 insertions, 1127 deletions
diff --git a/Makefile.in b/Makefile.in
index 8cb80061..c38b798f 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -107,6 +107,7 @@ DIST_COMMON = $(srcdir)/tools/lcov.am INSTALL NEWS README AUTHORS \
$(srcdir)/dbus-1.pc.in $(srcdir)/dbus-1-uninstalled.pc.in \
$(top_srcdir)/test/data/valid-config-files/debug-allow-all.conf.in \
$(top_srcdir)/test/data/valid-config-files/debug-allow-all-sha1.conf.in \
+ $(top_srcdir)/test/data/valid-config-files/finite-timeout.conf.in \
$(top_srcdir)/test/data/valid-config-files/incoming-limit.conf.in \
$(top_srcdir)/test/data/valid-config-files-system/debug-allow-all-pass.conf.in \
$(top_srcdir)/test/data/valid-config-files-system/debug-allow-all-fail.conf.in \
@@ -123,8 +124,8 @@ DIST_COMMON = $(srcdir)/tools/lcov.am INSTALL NEWS README AUTHORS \
$(top_srcdir)/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service.in \
$(top_srcdir)/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service.in \
$(top_srcdir)/test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in \
- COPYING compile config.guess config.sub install-sh missing \
- ltmain.sh
+ COPYING compile config.guess config.sub depcomp install-sh \
+ missing ltmain.sh
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \
@@ -143,6 +144,7 @@ CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES = Doxyfile dbus-1.pc dbus-1-uninstalled.pc \
test/data/valid-config-files/debug-allow-all.conf \
test/data/valid-config-files/debug-allow-all-sha1.conf \
+ test/data/valid-config-files/finite-timeout.conf \
test/data/valid-config-files/incoming-limit.conf \
test/data/valid-config-files-system/debug-allow-all-pass.conf \
test/data/valid-config-files-system/debug-allow-all-fail.conf \
@@ -456,6 +458,7 @@ build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
+dbus_daemondir = @dbus_daemondir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
@@ -583,6 +586,8 @@ test/data/valid-config-files/debug-allow-all.conf: $(top_builddir)/config.status
cd $(top_builddir) && $(SHELL) ./config.status $@
test/data/valid-config-files/debug-allow-all-sha1.conf: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-config-files/debug-allow-all-sha1.conf.in
cd $(top_builddir) && $(SHELL) ./config.status $@
+test/data/valid-config-files/finite-timeout.conf: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-config-files/finite-timeout.conf.in
+ cd $(top_builddir) && $(SHELL) ./config.status $@
test/data/valid-config-files/incoming-limit.conf: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-config-files/incoming-limit.conf.in
cd $(top_builddir) && $(SHELL) ./config.status $@
test/data/valid-config-files-system/debug-allow-all-pass.conf: $(top_builddir)/config.status $(top_srcdir)/test/data/valid-config-files-system/debug-allow-all-pass.conf.in
diff --git a/NEWS b/NEWS
index 271a3b7c..ef956da0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,77 @@
+D-Bus 1.9.2 (2014-11-10)
+==
+
+The “structurally unsound flapjack” release.
+
+Security fixes:
+
+• Increase dbus-daemon's RLIMIT_NOFILE rlimit to 65536
+ so that CVE-2014-3636 part A cannot exhaust the system bus'
+ file descriptors, completing the incomplete fix in 1.8.8.
+ (CVE-2014-7824, fd.o #85105; Simon McVittie, Alban Crequy)
+
+Enhancements:
+
+• D-Bus Specification version 0.25
+ · new value 'const' for EmitsChangedSignal annotation
+ (fd.o #72958, Lennart Poettering)
+ · new ALLOW_INTERACTIVE_AUTHORIZATION flag, for PolicyKit and similar
+ (fd.o #83449; Lennart Poettering, Simon McVittie)
+ · annotate table of types with reserved/basic/container, and for
+ basic types, fixed/string-like
+ · clarify arbitrary limits by quoting them in mebibytes
+
+• New API: add accessors for the ALLOW_INTERACTIVE_AUTHORIZATION flag
+ (fd.o #83449, Simon McVittie)
+
+• Add dbus-test-tool, a D-Bus swiss army knife with multiple subcommands,
+ useful for debugging and performance testing:
+ · dbus-test-tool spam: send repeated messages
+ · dbus-test-tool echo: send an empty reply for all method calls
+ · dbus-test-tool black-hole: do not reply to method calls
+ (fd.o #34140; Alban Crequy, Simon McVittie, Will Thompson)
+
+• Add support for process ID in credentials-passing on NetBSD
+ (fd.o #69702, Patrick Welche)
+
+• Add an example script to find potentially undesired match rules
+ (fd.o #84598, Alban Crequy)
+
+• Document the central assumption that makes our use of credentials-passing
+ secure (fd.o #83499, Simon McVittie)
+
+• Replace the dbus-glib section of the tutorial with a GDBus recommendation,
+ and add some links to GDBus and QtDBus documentation (fd.o #25140,
+ Simon McVittie)
+
+Fixes:
+
+• Use a less confusing NoReply message when disconnected with a reply pending
+ (fd.o #76112, Simon McVittie)
+
+• Make the .pc file relocatable by letting pkg-config do all variable
+ expansion itself (fd.o #75858, Руслан Ижбулатов)
+
+• Fix a build failure on platforms with kqueue, which regressed in 1.9.0
+ (fd.o #85563, Patrick Welche)
+
+• Consistently save errno after socket calls (fd.o #83625, Simon McVittie)
+
+• In dbus-spawn, when the grandchild process exits due to a failed exec(),
+ do not lose the exec() errno (fd.o #24821, Simon McVittie)
+
+• Do not fail the tests if a parent process has leaked non-close-on-exec
+ file descriptors to us (fd.o #73689, fd.o #83899; Simon McVittie)
+
+• Do not fail the tests on Unix platforms with incomplete
+ credentials-passing support, but do fail if we can't pass credentials
+ on a platform where it is known to work: Linux, FreeBSD, OpenBSD, NetBSD
+ (fd.o #69702, Simon McVittie)
+
+• Detect accept4, dirfd, inotify_init1, pipe2, and Unix fd passing
+ when building with cmake, and expand test coverage there
+ (fd.o #73689; Ralf Habacker, Simon McVittie)
+
D-Bus 1.9.0 (2014-10-01)
==
diff --git a/aclocal.m4 b/aclocal.m4
index e02ecf9e..c2c4011e 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -103,10 +103,9 @@ _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
# configured tree to be moved without reconfiguration.
AC_DEFUN([AM_AUX_DIR_EXPAND],
-[dnl Rely on autoconf to set up CDPATH properly.
-AC_PREREQ([2.50])dnl
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
])
# AM_CONDITIONAL -*- Autoconf -*-
diff --git a/bus/Makefile.in b/bus/Makefile.in
index 0f409cd4..897b22c8 100644
--- a/bus/Makefile.in
+++ b/bus/Makefile.in
@@ -492,6 +492,7 @@ build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
+dbus_daemondir = @dbus_daemondir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
diff --git a/bus/activation.c b/bus/activation.c
index bdf9cf3d..ffedf4c5 100644
--- a/bus/activation.c
+++ b/bus/activation.c
@@ -1688,6 +1688,31 @@ out:
return retval;
}
+static void
+child_setup (void *user_data)
+{
+#ifdef DBUS_UNIX
+ BusActivation *activation = user_data;
+ DBusRLimit *initial_fd_limit;
+ DBusError error;
+
+ dbus_error_init (&error);
+ initial_fd_limit = bus_context_get_initial_fd_limit (activation->context);
+
+ if (initial_fd_limit != NULL &&
+ !_dbus_rlimit_restore_fd_limit (initial_fd_limit, &error))
+ {
+ /* unfortunately we don't actually know the service name here */
+ bus_context_log (activation->context,
+ DBUS_SYSTEM_LOG_INFO,
+ "Failed to reset fd limit before activating "
+ "service: %s: %s",
+ error.name, error.message);
+ }
+#endif
+}
+
+
dbus_bool_t
bus_activation_activate_service (BusActivation *activation,
DBusConnection *connection,
@@ -2121,7 +2146,8 @@ bus_activation_activate_service (BusActivation *activation,
service_name,
argv,
envp,
- NULL, activation,
+ child_setup,
+ activation,
&tmp_error))
{
_dbus_verbose ("Failed to spawn child\n");
diff --git a/bus/bus.c b/bus/bus.c
index 35d40754..47cc3452 100644
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -64,6 +64,7 @@ struct BusContext
BusPolicy *policy;
BusMatchmaker *matchmaker;
BusLimits limits;
+ DBusRLimit *initial_fd_limit;
unsigned int fork : 1;
unsigned int syslog : 1;
unsigned int keep_umask : 1;
@@ -659,19 +660,38 @@ oom:
static void
raise_file_descriptor_limit (BusContext *context)
{
+#ifdef DBUS_UNIX
+ DBusError error = DBUS_ERROR_INIT;
- /* I just picked this out of thin air; we need some extra
- * descriptors for things like any internal pipes we create,
- * inotify, connections to SELinux, etc.
- */
- unsigned int arbitrary_extra_fds = 32;
- unsigned int limit;
+ /* we only do this once */
+ if (context->initial_fd_limit != NULL)
+ return;
- limit = context->limits.max_completed_connections +
- context->limits.max_incomplete_connections
- + arbitrary_extra_fds;
+ context->initial_fd_limit = _dbus_rlimit_save_fd_limit (&error);
+
+ if (context->initial_fd_limit == NULL)
+ {
+ bus_context_log (context, DBUS_SYSTEM_LOG_INFO,
+ "%s: %s", error.name, error.message);
+ dbus_error_free (&error);
+ return;
+ }
- _dbus_request_file_descriptor_limit (limit);
+ /* We used to compute a suitable rlimit based on the configured number
+ * of connections, but that breaks down as soon as we allow fd-passing,
+ * because each connection is allowed to pass 64 fds to us, and if
+ * they all did, we'd hit kernel limits. We now hard-code 64k as a
+ * good limit, like systemd does: that's enough to avoid DoS from
+ * anything short of multiple uids conspiring against us.
+ */
+ if (!_dbus_rlimit_raise_fd_limit_if_privileged (65536, &error))
+ {
+ bus_context_log (context, DBUS_SYSTEM_LOG_INFO,
+ "%s: %s", error.name, error.message);
+ dbus_error_free (&error);
+ return;
+ }
+#endif
}
static dbus_bool_t
@@ -1130,6 +1150,10 @@ bus_context_unref (BusContext *context)
dbus_free (context->pidfile);
}
+
+ if (context->initial_fd_limit)
+ _dbus_rlimit_free (context->initial_fd_limit);
+
dbus_free (context);
dbus_server_free_data_slot (&server_data_slot);
@@ -1294,6 +1318,12 @@ bus_context_get_reply_timeout (BusContext *context)
return context->limits.reply_timeout;
}
+DBusRLimit *
+bus_context_get_initial_fd_limit (BusContext *context)
+{
+ return context->initial_fd_limit;
+}
+
void
bus_context_log (BusContext *context, DBusSystemLogSeverity severity, const char *msg, ...) _DBUS_GNUC_PRINTF (3, 4);
diff --git a/bus/bus.h b/bus/bus.h
index 7d0b3697..dac6ea5e 100644
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -116,6 +116,7 @@ int bus_context_get_max_services_per_connection (BusContext
int bus_context_get_max_match_rules_per_connection (BusContext *context);
int bus_context_get_max_replies_per_connection (BusContext *context);
int bus_context_get_reply_timeout (BusContext *context);
+DBusRLimit * bus_context_get_initial_fd_limit (BusContext *context);
void bus_context_log (BusContext *context,
DBusSystemLogSeverity severity,
const char *msg,
diff --git a/bus/connection.c b/bus/connection.c
index 519122c5..0df8a3a8 100644
--- a/bus/connection.c
+++ b/bus/connection.c
@@ -1619,7 +1619,12 @@ bus_pending_reply_send_no_reply (BusConnections *connections,
DBUS_ERROR_NO_REPLY))
goto out;
- errmsg = "Message did not receive a reply (timeout by message bus)";
+ /* If you change these messages, adjust test/dbus-daemon.c to match */
+ if (pending->will_send_reply == NULL)
+ errmsg = "Message recipient disconnected from message bus without replying";
+ else
+ errmsg = "Message did not receive a reply (timeout by message bus)";
+
dbus_message_iter_init_append (message, &iter);
if (!dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING, &errmsg))
goto out;
diff --git a/bus/dir-watch-kqueue.c b/bus/dir-watch-kqueue.c
index c05a5997..c1e83245 100644
--- a/bus/dir-watch-kqueue.c
+++ b/bus/dir-watch-kqueue.c
@@ -38,6 +38,7 @@
#include <dbus/dbus-internals.h>
#include <dbus/dbus-list.h>
+#include <dbus/dbus-sysdeps-unix.h>
#include "dir-watch.h"
#define MAX_DIRS_TO_WATCH 128
diff --git a/bus/dispatch.c b/bus/dispatch.c
index fa2cc968..8f322f8c 100644
--- a/bus/dispatch.c
+++ b/bus/dispatch.c
@@ -1312,6 +1312,11 @@ check_get_connection_unix_process_id (BusContext *context,
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
defined(__linux__) || \
defined(__OpenBSD__)
+ /* In principle NetBSD should also be in that list, but
+ * its implementation of PID-passing doesn't work
+ * over a socketpair() as used in the debug-pipe transport.
+ * We test this functionality in a more realistic situation
+ * in test/dbus-daemon.c. */
warn_unexpected (connection, message, "not this error");
goto out;
diff --git a/bus/test-main.c b/bus/test-main.c
index 01d22870..788574fe 100644
--- a/bus/test-main.c
+++ b/bus/test-main.c
@@ -31,6 +31,10 @@
#include <dbus/dbus-message-internal.h>
#include "selinux.h"
+#ifdef DBUS_UNIX
+# include <dbus/dbus-sysdeps-unix.h>
+#endif
+
#ifdef DBUS_ENABLE_EMBEDDED_TESTS
static void
die (const char *failure)
@@ -109,6 +113,11 @@ main (int argc, char **argv)
_dbus_string_init_const (&test_data_dir, dir);
+#ifdef DBUS_UNIX
+ /* close any inherited fds so dbus-spawn's check for close-on-exec works */
+ _dbus_close_all ();
+#endif
+
if (!_dbus_threads_init_debug ())
die ("initializing debug threads");
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
index 628a681a..32250f59 100644
--- a/cmake/CMakeLists.txt
+++ b/cmake/CMakeLists.txt
@@ -496,6 +496,9 @@ add_subdirectory( dbus )
add_subdirectory( bus )
if (DBUS_BUILD_TESTS)
add_subdirectory( test )
+ add_custom_target(check
+ COMMAND ctest -R ^test-.*
+ )
endif (DBUS_BUILD_TESTS)
add_subdirectory( tools )
add_subdirectory( doc )
diff --git a/cmake/ConfigureChecks.cmake b/cmake/ConfigureChecks.cmake
index d290b0f2..6e8ebaee 100644
--- a/cmake/ConfigureChecks.cmake
+++ b/cmake/ConfigureChecks.cmake
@@ -36,6 +36,12 @@ check_symbol_exists(setlocale "locale.h" HAVE_SETLOCALE) #
check_symbol_exists(localeconv "locale.h" HAVE_LOCALECONV) # dbus-sysdeps.c
check_symbol_exists(strtoll "stdlib.h" HAVE_STRTOLL) # dbus-send.c
check_symbol_exists(strtoull "stdlib.h" HAVE_STRTOULL) # dbus-send.c
+set(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
+check_symbol_exists(pipe2 "fcntl.h;unistd.h" HAVE_PIPE2)
+check_symbol_exists(accept4 "sys/socket.h" HAVE_ACCEPT4)
+check_symbol_exists(dirfd "dirent.h" HAVE_DIRFD)
+check_symbol_exists(inotify_init1 "sys/inotify.h" HAVE_INOTIFY_INIT1)
+check_symbol_exists(SCM_RIGHTS "sys/types.h;sys/socket.h;sys/un.h" HAVE_UNIX_FD_PASSING)
check_struct_member(cmsgcred cmcred_pid "sys/types.h sys/socket.h" HAVE_CMSGCRED) # dbus-sysdeps.c
diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake
index eaec1e98..8789cf91 100644
--- a/cmake/config.h.cmake
+++ b/cmake/config.h.cmake
@@ -190,6 +190,14 @@
/* Define to 1 if you have strtoull */
#cmakedefine HAVE_STRTOULL 1
+/* Define to 1 if you have pip2 */
+#cmakedefine HAVE_PIPE2
+
+#cmakedefine HAVE_ACCEPT4 1
+#cmakedefine HAVE_DIRFD 1
+#cmakedefine HAVE_INOTIFY_INIT1 1
+#cmakedefine HAVE_UNIX_FD_PASSING 1
+
// structs
/* Define to 1 if you have struct cmsgred */
#cmakedefine HAVE_CMSGCRED 1
diff --git a/cmake/test/CMakeLists.txt b/cmake/test/CMakeLists.txt
index 13f639b1..5e81e7f9 100644
--- a/cmake/test/CMakeLists.txt
+++ b/cmake/test/CMakeLists.txt
@@ -158,7 +158,10 @@ ENDFOREACH(FILE_TYPE)
MESSAGE(STATUS "Copying generated bus config files to test directory")
set (OUTDIR ${CMAKE_BINARY_DIR}/test/data/valid-config-files)
-FILE(GLOB FILES "${CMAKE_SOURCE_DIR}/../bus/*.conf.in" )
+SET(FILES
+ "${CMAKE_SOURCE_DIR}/../bus/session.conf.in"
+ "${CMAKE_SOURCE_DIR}/../bus/system.conf.in"
+)
FILE(MAKE_DIRECTORY ${OUTDIR})
FOREACH(FILE ${FILES})
GET_FILENAME_COMPONENT(FILENAME ${FILE} NAME)
@@ -169,7 +172,3 @@ FOREACH(FILE ${FILES})
MESSAGE("FROM: ${FILE}\nTO: ${TARGET}\n")
ENDIF (CONFIG_VERBOSE)
ENDFOREACH(FILE)
-
-add_custom_target(check
- COMMAND ctest -R ^test-.*
-)
diff --git a/config.h.in b/config.h.in
index e7ff3e4c..7dca911b 100644
--- a/config.h.in
+++ b/config.h.in
@@ -347,6 +347,9 @@
/* Supports sending UNIX file descriptors */
#undef HAVE_UNIX_FD_PASSING
+/* Have unpcbid structure */
+#undef HAVE_UNPCBID
+
/* Define to 1 if you have the `unsetenv' function. */
#undef HAVE_UNSETENV
diff --git a/configure b/configure
index 203fbc2d..5d1b429b 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for dbus 1.9.0.
+# Generated by GNU Autoconf 2.69 for dbus 1.9.2.
#
# Report bugs to <https://bugs.freedesktop.org/enter_bug.cgi?product=dbus>.
#
@@ -591,8 +591,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='dbus'
PACKAGE_TARNAME='dbus'
-PACKAGE_VERSION='1.9.0'
-PACKAGE_STRING='dbus 1.9.0'
+PACKAGE_VERSION='1.9.2'
+PACKAGE_STRING='dbus 1.9.2'
PACKAGE_BUGREPORT='https://bugs.freedesktop.org/enter_bug.cgi?product=dbus'
PACKAGE_URL=''
@@ -648,6 +648,7 @@ DBUS_TEST_EXEC
DBUS_TEST_DATA
DBUS_LIBEXECDIR
DBUS_BINDIR
+dbus_daemondir
DBUS_DAEMONDIR
DBUS_DATADIR
DBUS_PREFIX
@@ -1513,7 +1514,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures dbus 1.9.0 to adapt to many kinds of systems.
+\`configure' configures dbus 1.9.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1587,7 +1588,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of dbus 1.9.0:";;
+ short | recursive ) echo "Configuration of dbus 1.9.2:";;
esac
cat <<\_ACEOF
@@ -1784,7 +1785,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-dbus configure 1.9.0
+dbus configure 1.9.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2499,11 +2500,68 @@ $as_echo "$ac_res" >&6; }
eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
} # ac_fn_c_check_decl
+
+# ac_fn_c_check_member LINENO AGGR MEMBER VAR INCLUDES
+# ----------------------------------------------------
+# Tries to find if the field MEMBER exists in type AGGR, after including
+# INCLUDES, setting cache variable VAR accordingly.
+ac_fn_c_check_member ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5
+$as_echo_n "checking for $2.$3... " >&6; }
+if eval \${$4+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$5
+int
+main ()
+{
+static $2 ac_aggr;
+if (ac_aggr.$3)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$4=yes"
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$5
+int
+main ()
+{
+static $2 ac_aggr;
+if (sizeof ac_aggr.$3)
+return 0;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$4=yes"
+else
+ eval "$4=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$4
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_member
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by dbus $as_me 1.9.0, which was
+It was created by dbus $as_me 1.9.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -3132,8 +3190,8 @@ test "$program_suffix" != NONE &&
ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
-# expand $ac_aux_dir to an absolute path
-am_aux_dir=`cd $ac_aux_dir && pwd`
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
if test x"${MISSING+set}" != xset; then
case $am_aux_dir in
@@ -3446,7 +3504,7 @@ fi
# Define the identity of the package.
PACKAGE='dbus'
- VERSION='1.9.0'
+ VERSION='1.9.2'
cat >>confdefs.h <<_ACEOF
@@ -3742,7 +3800,7 @@ _ACEOF
#
## increment if the interface has additions, changes, removals.
-LT_CURRENT=12
+LT_CURRENT=13
## increment any time the source changes; set to
## 0 if you increment CURRENT
@@ -3751,7 +3809,7 @@ LT_REVISION=0
## increment if any interfaces have been added; set to 0
## if any interfaces have been changed or removed. removal has
## precedence over adding, so set to 0 if both happened.
-LT_AGE=9
+LT_AGE=10
@@ -3759,8 +3817,8 @@ LT_AGE=9
DBUS_MAJOR_VERSION=1
DBUS_MINOR_VERSION=9
-DBUS_MICRO_VERSION=0
-DBUS_VERSION=1.9.0
+DBUS_MICRO_VERSION=2
+DBUS_VERSION=1.9.2
@@ -19353,6 +19411,15 @@ $as_echo "#define HAVE_CMSGCRED 1" >>confdefs.h
fi
+ac_fn_c_check_member "$LINENO" "struct unpcbid" "unp_pid" "ac_cv_member_struct_unpcbid_unp_pid" "#include <sys/un.h>
+"
+if test "x$ac_cv_member_struct_unpcbid_unp_pid" = xyes; then :
+
+$as_echo "#define HAVE_UNPCBID 1" >>confdefs.h
+
+fi
+
+
for ac_func in getpeerucred getpeereid
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
@@ -22616,11 +22683,14 @@ _ACEOF
#### Directory to install dbus-daemon
if test -z "$with_dbus_daemondir" ; then
DBUS_DAEMONDIR=$EXPANDED_BINDIR
+ dbus_daemondir='$bindir'
else
DBUS_DAEMONDIR=$with_dbus_daemondir
+ dbus_daemondir=$with_dbus_daemondir
fi
+
cat >>confdefs.h <<_ACEOF
#define DBUS_DAEMONDIR "$DBUS_DAEMONDIR"
_ACEOF
@@ -22838,7 +22908,7 @@ $as_echo "#define DBUS_ENABLE_STATS 1" >>confdefs.h
fi
-ac_config_files="$ac_config_files Doxyfile dbus/versioninfo.rc dbus/dbus-arch-deps.h bus/system.conf bus/session.conf bus/example-system-enable-stats.conf bus/example-session-disable-stats.conf bus/messagebus bus/messagebus-config bus/org.freedesktop.dbus-session.plist bus/rc.messagebus bus/dbus.service bus/dbus.socket Makefile dbus/Makefile bus/Makefile tools/Makefile test/Makefile test/name-test/Makefile doc/Makefile doc/dbus-cleanup-sockets.1.xml doc/dbus-daemon.1.xml doc/dbus-launch.1.xml doc/dbus-monitor.1.xml doc/dbus-run-session.1.xml doc/dbus-send.1.xml doc/dbus-uuidgen.1.xml dbus-1.pc dbus-1-uninstalled.pc test/data/valid-config-files/debug-allow-all.conf test/data/valid-config-files/debug-allow-all-sha1.conf test/data/valid-config-files/incoming-limit.conf test/data/valid-config-files-system/debug-allow-all-pass.conf test/data/valid-config-files-system/debug-allow-all-fail.conf test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service"
+ac_config_files="$ac_config_files Doxyfile dbus/versioninfo.rc dbus/dbus-arch-deps.h bus/system.conf bus/session.conf bus/example-system-enable-stats.conf bus/example-session-disable-stats.conf bus/messagebus bus/messagebus-config bus/org.freedesktop.dbus-session.plist bus/rc.messagebus bus/dbus.service bus/dbus.socket Makefile dbus/Makefile bus/Makefile tools/Makefile test/Makefile test/name-test/Makefile doc/Makefile doc/dbus-cleanup-sockets.1.xml doc/dbus-daemon.1.xml doc/dbus-launch.1.xml doc/dbus-monitor.1.xml doc/dbus-run-session.1.xml doc/dbus-send.1.xml doc/dbus-uuidgen.1.xml dbus-1.pc dbus-1-uninstalled.pc test/data/valid-config-files/debug-allow-all.conf test/data/valid-config-files/debug-allow-all-sha1.conf test/data/valid-config-files/finite-timeout.conf test/data/valid-config-files/incoming-limit.conf test/data/valid-config-files-system/debug-allow-all-pass.conf test/data/valid-config-files-system/debug-allow-all-fail.conf test/data/valid-service-files/org.freedesktop.DBus.TestSuite.PrivServer.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteEchoService.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteForkingEchoService.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteSegfaultService.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service test/data/valid-service-files/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteEchoService.service test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteSegfaultService.service test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceSuccess.service test/data/valid-service-files-system/org.freedesktop.DBus.TestSuiteShellEchoServiceFail.service test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoUser.service test/data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service"
cat >confcache <<\_ACEOF
# This file is a shell script that caches the results of configure
@@ -23475,7 +23545,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by dbus $as_me 1.9.0, which was
+This file was extended by dbus $as_me 1.9.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -23541,7 +23611,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-dbus config.status 1.9.0
+dbus config.status 1.9.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
@@ -24165,6 +24235,7 @@ do
"dbus-1-uninstalled.pc") CONFIG_FILES="$CONFIG_FILES dbus-1-uninstalled.pc" ;;
"test/data/valid-config-files/debug-allow-all.conf") CONFIG_FILES="$CONFIG_FILES test/data/valid-config-files/debug-allow-all.conf" ;;
"test/data/valid-config-files/debug-allow-all-sha1.conf") CONFIG_FILES="$CONFIG_FILES test/data/valid-config-files/debug-allow-all-sha1.conf" ;;
+ "test/data/valid-config-files/finite-timeout.conf") CONFIG_FILES="$CONFIG_FILES test/data/valid-config-files/finite-timeout.conf" ;;
"test/data/valid-config-files/incoming-limit.conf") CONFIG_FILES="$CONFIG_FILES test/data/valid-config-files/incoming-limit.conf" ;;
"test/data/valid-config-files-system/debug-allow-all-pass.conf") CONFIG_FILES="$CONFIG_FILES test/data/valid-config-files-system/debug-allow-all-pass.conf" ;;
"test/data/valid-config-files-system/debug-allow-all-fail.conf") CONFIG_FILES="$CONFIG_FILES test/data/valid-config-files-system/debug-allow-all-fail.conf" ;;
diff --git a/configure.ac b/configure.ac
index 2f62269e..d903be12 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@ AC_PREREQ([2.63])
m4_define([dbus_major_version], [1])
m4_define([dbus_minor_version], [9])
-m4_define([dbus_micro_version], [0])
+m4_define([dbus_micro_version], [2])
m4_define([dbus_version],
[dbus_major_version.dbus_minor_version.dbus_micro_version])
AC_INIT([dbus],[dbus_version],[https://bugs.freedesktop.org/enter_bug.cgi?product=dbus],[dbus])
@@ -33,7 +33,7 @@ AC_DEFINE_UNQUOTED(DBUS_DAEMON_NAME,"dbus-daemon",[Name of executable])
#
## increment if the interface has additions, changes, removals.
-LT_CURRENT=12
+LT_CURRENT=13
## increment any time the source changes; set to
## 0 if you increment CURRENT
@@ -42,7 +42,7 @@ LT_REVISION=0
## increment if any interfaces have been added; set to 0
## if any interfaces have been changed or removed. removal has
## precedence over adding, so set to 0 if both happened.
-LT_AGE=9
+LT_AGE=10
AC_SUBST(LT_CURRENT)
AC_SUBST(LT_REVISION)
@@ -818,6 +818,11 @@ if test x$dbus_have_struct_cmsgcred = xyes; then
AC_DEFINE(HAVE_CMSGCRED,1,[Have cmsgcred structure])
fi
+AC_CHECK_MEMBER([struct unpcbid.unp_pid],
+ [AC_DEFINE([HAVE_UNPCBID], 1, [Have unpcbid structure])],
+ [],
+ [[#include <sys/un.h>]])
+
AC_CHECK_FUNCS(getpeerucred getpeereid)
AC_CHECK_FUNCS(pipe2 accept4)
@@ -1583,10 +1588,13 @@ AC_DEFINE_UNQUOTED(DBUS_DATADIR,"$DBUS_DATADIR", [Directory for installing DBUS
#### Directory to install dbus-daemon
if test -z "$with_dbus_daemondir" ; then
DBUS_DAEMONDIR=$EXPANDED_BINDIR
+ dbus_daemondir='$bindir'
else
DBUS_DAEMONDIR=$with_dbus_daemondir
+ dbus_daemondir=$with_dbus_daemondir
fi
AC_SUBST(DBUS_DAEMONDIR)
+AC_SUBST(dbus_daemondir)
AC_DEFINE_UNQUOTED(DBUS_DAEMONDIR,"$DBUS_DAEMONDIR", [Directory for installing the DBUS daemon])
#### Directory to install the other binaries
@@ -1776,6 +1784,7 @@ dbus-1.pc
dbus-1-uninstalled.pc
test/data/valid-config-files/debug-allow-all.conf
test/data/valid-config-files/debug-allow-all-sha1.conf
+test/data/valid-config-files/finite-timeout.conf
test/data/valid-config-files/incoming-limit.conf
test/data/valid-config-files-system/debug-allow-all-pass.conf
test/data/valid-config-files-system/debug-allow-all-fail.conf
diff --git a/dbus-1-uninstalled.pc.in b/dbus-1-uninstalled.pc.in
index 038c83e2..b66ad2f6 100644
--- a/dbus-1-uninstalled.pc.in
+++ b/dbus-1-uninstalled.pc.in
@@ -2,12 +2,15 @@ abs_top_builddir=@abs_top_builddir@
abs_top_srcdir=@abs_top_srcdir@
prefix=
exec_prefix=
+bindir=@bindir@
system_bus_default_address=@DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@
-sysconfdir=@EXPANDED_SYSCONFDIR@
-session_bus_services_dir=@EXPANDED_DATADIR@/dbus-1/services
-system_bus_services_dir=@EXPANDED_DATADIR@/dbus-1/system-services
-interfaces_dir=@EXPANDED_DATADIR@/dbus-1/interfaces
-daemondir=@DBUS_DAEMONDIR@
+datarootdir=@datarootdir@
+datadir=@datadir@
+sysconfdir=@sysconfdir@
+session_bus_services_dir=${datadir}/dbus-1/services
+system_bus_services_dir=${datadir}/dbus-1/system-services
+interfaces_dir=${datadir}/dbus-1/interfaces
+daemondir=@dbus_daemondir@
Name: dbus
Description: Free desktop message bus (uninstalled copy)
diff --git a/dbus-1.pc.in b/dbus-1.pc.in
index 25f8bcee..f93d1563 100644
--- a/dbus-1.pc.in
+++ b/dbus-1.pc.in
@@ -1,13 +1,16 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
+bindir=@bindir@
libdir=@libdir@
includedir=@includedir@
system_bus_default_address=@DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@
-sysconfdir=@EXPANDED_SYSCONFDIR@
-session_bus_services_dir=@EXPANDED_DATADIR@/dbus-1/services
-system_bus_services_dir=@EXPANDED_DATADIR@/dbus-1/system-services
-interfaces_dir=@EXPANDED_DATADIR@/dbus-1/interfaces
-daemondir=@DBUS_DAEMONDIR@
+datarootdir=@datarootdir@
+datadir=@datadir@
+sysconfdir=@sysconfdir@
+session_bus_services_dir=${datadir}/dbus-1/services
+system_bus_services_dir=${datadir}/dbus-1/system-services
+interfaces_dir=${datadir}/dbus-1/interfaces
+daemondir=@dbus_daemondir@
Name: dbus
Description: Free desktop message bus
diff --git a/dbus/Makefile.in b/dbus/Makefile.in
index 3205e165..226c2e23 100644
--- a/dbus/Makefile.in
+++ b/dbus/Makefile.in
@@ -626,6 +626,7 @@ build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
+dbus_daemondir = @dbus_daemondir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c
index 6a07665f..64ad2b06 100644
--- a/dbus/dbus-auth.c
+++ b/dbus/dbus-auth.c
@@ -37,7 +37,7 @@
* @brief DBusAuth object
*
* DBusAuth manages the authentication negotiation when a connection
- * is first established, and also manage any encryption used over a
+ * is first established, and also manages any encryption used over a
* connection.
*
* @todo some SASL profiles require sending the empty string as a
diff --git a/dbus/dbus-memory.c b/dbus/dbus-memory.c
index 22e80727..67d5cb05 100644
--- a/dbus/dbus-memory.c
+++ b/dbus/dbus-memory.c
@@ -862,6 +862,13 @@ _dbus_register_shutdown_func_unlocked (DBusShutdownFunction func,
* You MUST free all memory and release all reference counts
* returned to you by libdbus prior to calling dbus_shutdown().
*
+ * If a shared connection is open, calling dbus_shutdown() will
+ * drain its queue of messages and disconnect it. In particular,
+ * this will result in processing of the special Disconnected
+ * signal, which may result in a call to _exit(), unless you
+ * have used dbus_connection_set_exit_on_disconnect() to disable
+ * that behaviour.
+ *
* You can't continue to use any D-Bus objects, such as connections,
* that were allocated prior to dbus_shutdown(). You can, however,
* start over; call dbus_threads_init() again, create new connections,
diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c
index 974e8fa6..01c2367c 100644
--- a/dbus/dbus-message.c
+++ b/dbus/dbus-message.c
@@ -4876,6 +4876,54 @@ dbus_message_demarshal_bytes_needed(const char *buf,
}
}
+/**
+ * Sets a flag indicating that the caller of the method is prepared
+ * to wait for interactive authorization to take place (for instance
+ * via Polkit) before the actual method is processed.
+ *
+ * The flag is #FALSE by default; that is, by default the other end is
+ * expected to make any authorization decisions non-interactively
+ * and promptly. It may use the error
+ * #DBUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED to signal that
+ * authorization failed, but could have succeeded if this flag had
+ * been used.
+ *
+ * For messages whose type is not #DBUS_MESSAGE_TYPE_METHOD_CALL,
+ * this flag is meaningless and should not be set.
+ *
+ * On the protocol level this toggles
+ * #DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION.
+ *
+ * @param message the message
+ * @param allow #TRUE if interactive authorization is acceptable
+ */
+void
+dbus_message_set_allow_interactive_authorization (DBusMessage *message,
+ dbus_bool_t allow)
+{
+ _dbus_return_if_fail (message != NULL);
+ _dbus_return_if_fail (!message->locked);
+
+ _dbus_header_toggle_flag (&message->header,
+ DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION,
+ allow);
+}
+
+/**
+ * Returns whether the flag controlled by
+ * dbus_message_set_allow_interactive_authorization() has been set.
+ *
+ * @param message the message
+ */
+dbus_bool_t
+dbus_message_get_allow_interactive_authorization (DBusMessage *message)
+{
+ _dbus_return_val_if_fail (message != NULL, FALSE);
+
+ return _dbus_header_get_flag (&message->header,
+ DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION);
+}
+
/** @} */
/* tests in dbus-message-util.c */
diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h
index 4fd44dab..baa7d7b5 100644
--- a/dbus/dbus-message.h
+++ b/dbus/dbus-message.h
@@ -302,6 +302,14 @@ DBUS_EXPORT
int dbus_message_demarshal_bytes_needed (const char *str,
int len);
+DBUS_EXPORT
+void dbus_message_set_allow_interactive_authorization (DBusMessage *message,
+ dbus_bool_t allow);
+
+DBUS_EXPORT
+dbus_bool_t dbus_message_get_allow_interactive_authorization (
+ DBusMessage *message);
+
/** @} */
DBUS_END_DECLS
diff --git a/dbus/dbus-nonce.c b/dbus/dbus-nonce.c
index 37f30f00..44c46b2f 100644
--- a/dbus/dbus-nonce.c
+++ b/dbus/dbus-nonce.c
@@ -53,10 +53,14 @@ do_check_nonce (int fd, const DBusString *nonce, DBusError *error)
while (nleft)
{
+ int saved_errno;
+
n = _dbus_read_socket (fd, &p, nleft);
- if (n == -1 && _dbus_get_is_errno_eintr())
+ saved_errno = _dbus_save_socket_errno ();
+
+ if (n == -1 && _dbus_get_is_errno_eintr (saved_errno))
;
- else if (n == -1 && _dbus_get_is_errno_eagain_or_ewouldblock())
+ else if (n == -1 && _dbus_get_is_errno_eagain_or_ewouldblock (saved_errno))
_dbus_sleep_milliseconds (100);
else if (n==-1)
{
diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h
index 60605ab2..933c3658 100644
--- a/dbus/dbus-protocol.h
+++ b/dbus/dbus-protocol.h
@@ -254,6 +254,11 @@ extern "C" {
* message.
*/
#define DBUS_HEADER_FLAG_NO_AUTO_START 0x2
+/**
+ * If set on a method call, this flag means that the caller is prepared to
+ * wait for interactive authorization.
+ */
+#define DBUS_HEADER_FLAG_ALLOW_INTERACTIVE_AUTHORIZATION 0x4
/* Header fields */
@@ -446,6 +451,10 @@ extern "C" {
/** The message meta data does not match the payload. e.g. expected
number of file descriptors were not sent over the socket this message was received on. */
#define DBUS_ERROR_INCONSISTENT_MESSAGE "org.freedesktop.DBus.Error.InconsistentMessage"
+/** The message is not allowed without performing interactive authorization,
+ * but could have succeeded if an interactive authorization step was
+ * allowed. */
+#define DBUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED "org.freedesktop.DBus.Error.InteractiveAuthorizationRequired"
/* XML introspection format */
diff --git a/dbus/dbus-server-socket.c b/dbus/dbus-server-socket.c
index 060a919e..70367c79 100644
--- a/dbus/dbus-server-socket.c
+++ b/dbus/dbus-server-socket.c
@@ -184,6 +184,7 @@ socket_handle_watch (DBusWatch *watch,
{
int client_fd;
int listen_fd;
+ int saved_errno;
listen_fd = dbus_watch_get_socket (watch);
@@ -192,15 +193,17 @@ socket_handle_watch (DBusWatch *watch,
else
client_fd = _dbus_accept (listen_fd);
+ saved_errno = _dbus_save_socket_errno ();
+
if (client_fd < 0)
{
/* EINTR handled for us */
- if (_dbus_get_is_errno_eagain_or_ewouldblock ())
+ if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno))
_dbus_verbose ("No client available to accept after all\n");
else
_dbus_verbose ("Failed to accept a client connection: %s\n",
- _dbus_strerror_from_errno ());
+ _dbus_strerror (saved_errno));
SERVER_UNLOCK (server);
}
diff --git a/dbus/dbus-spawn.c b/dbus/dbus-spawn.c
index b95cad6e..959c1844 100644
--- a/dbus/dbus-spawn.c
+++ b/dbus/dbus-spawn.c
@@ -454,9 +454,25 @@ read_data (DBusBabysitter *sitter,
{
if (what == CHILD_EXITED)
{
+ /* Do not reset sitter->errnum to 0 here. We get here if
+ * the babysitter reports that the grandchild process has
+ * exited, and there are two ways that can happen:
+ *
+ * 1. grandchild successfully exec()s the desired process,
+ * but then the desired process exits or is terminated
+ * by a signal. The babysitter observes this and reports
+ * CHILD_EXITED.
+ *
+ * 2. grandchild fails to exec() the desired process,
+ * attempts to report the exec() failure (which
+ * we will receive as CHILD_EXEC_FAILED), and then
+ * exits itself (which will prompt the babysitter to
+ * send CHILD_EXITED). We want the CHILD_EXEC_FAILED
+ * to take precedence (and have its errno logged),
+ * which _dbus_babysitter_set_child_exit_error() does.
+ */
sitter->have_child_status = TRUE;
sitter->status = arg;
- sitter->errnum = 0;
_dbus_verbose ("recorded child status exited = %d signaled = %d exitstatus = %d termsig = %d\n",
WIFEXITED (sitter->status), WIFSIGNALED (sitter->status),
WEXITSTATUS (sitter->status), WTERMSIG (sitter->status));
@@ -1017,7 +1033,7 @@ do_exec (int child_err_report_fd,
retval = fcntl (i, F_GETFD);
if (retval != -1 && !(retval & FD_CLOEXEC))
- _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
+ _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
}
#endif
diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
index 544429a7..f4a42d89 100644
--- a/dbus/dbus-sysdeps-unix.c
+++ b/dbus/dbus-sysdeps-unix.c
@@ -1663,6 +1663,25 @@ write_credentials_byte (int server_fd,
* object, then adds pid/uid if available, so any previous credentials
* stored in the object are lost.
*
+ * DBusServer makes the security assumption that the credentials
+ * returned by this method are the credentials that were active
+ * at the time the socket was opened. Do not add APIs to this
+ * method that would break that assumption.
+ *
+ * In particular, it is incorrect to use any API of the form
+ * "get the process ID at the other end of the connection, then
+ * determine its uid, gid, or other credentials from the pid"
+ * (e.g. looking in /proc on Linux). If we did that, we would
+ * be vulnerable to several attacks. A malicious process could
+ * queue up the rest of the authentication handshake and a malicious
+ * message that it should not be allowed to send, then race with
+ * the DBusServer to exec() a more privileged (e.g. setuid) binary that
+ * would have been allowed to send that message; or it could exit,
+ * and arrange for enough setuid processes to be started that its
+ * pid would be recycled for one of those processes with high
+ * probability; or it could fd-pass the connection to a more
+ * privileged process.
+ *
* Return value indicates whether a byte was read, not whether
* we got valid credentials. On some systems, such as Linux,
* reading/writing the byte isn't actually required, but we do it
@@ -1778,16 +1797,41 @@ _dbus_read_credentials_socket (int client_fd,
#endif
int cr_len = sizeof (cr);
- if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
- cr_len == sizeof (cr))
+ if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) != 0)
+ {
+ _dbus_verbose ("Failed to getsockopt(SO_PEERCRED): %s\n",
+ _dbus_strerror (errno));
+ }
+ else if (cr_len != sizeof (cr))
{
- pid_read = cr.pid;
- uid_read = cr.uid;
+ _dbus_verbose ("Failed to getsockopt(SO_PEERCRED), returned %d bytes, expected %d\n",
+ cr_len, (int) sizeof (cr));
}
else
{
- _dbus_verbose ("Failed to getsockopt() credentials, returned len %d/%d: %s\n",
- cr_len, (int) sizeof (cr), _dbus_strerror (errno));
+ pid_read = cr.pid;
+ uid_read = cr.uid;
+ }
+#elif defined(HAVE_UNPCBID) && defined(LOCAL_PEEREID)
+ /* Another variant of the above - used on NetBSD
+ */
+ struct unpcbid cr;
+ socklen_t cr_len = sizeof (cr);
+
+ if (getsockopt (client_fd, 0, LOCAL_PEEREID, &cr, &cr_len) != 0)
+ {
+ _dbus_verbose ("Failed to getsockopt(LOCAL_PEEREID): %s\n",
+ _dbus_strerror (errno));
+ }
+ else if (cr_len != sizeof (cr))
+ {
+ _dbus_verbose ("Failed to getsockopt(LOCAL_PEEREID), returned %d bytes, expected %d\n",
+ cr_len, (int) sizeof (cr));
+ }
+ else
+ {
+ pid_read = cr.unp_pid;
+ uid_read = cr.unp_euid;
}
#elif defined(HAVE_CMSGCRED)
/* We only check for HAVE_CMSGCRED, but we're really assuming that the
@@ -3937,12 +3981,12 @@ _dbus_daemon_unpublish_session_bus_address (void)
* See if errno is EAGAIN or EWOULDBLOCK (this has to be done differently
* for Winsock so is abstracted)
*
- * @returns #TRUE if errno == EAGAIN or errno == EWOULDBLOCK
+ * @returns #TRUE if e == EAGAIN or e == EWOULDBLOCK
*/
dbus_bool_t
-_dbus_get_is_errno_eagain_or_ewouldblock (void)
+_dbus_get_is_errno_eagain_or_ewouldblock (int e)
{
- return errno == EAGAIN || errno == EWOULDBLOCK;
+ return e == EAGAIN || e == EWOULDBLOCK;
}
/**
@@ -4199,4 +4243,16 @@ _dbus_append_address_from_socket (int fd,
return FALSE;
}
+int
+_dbus_save_socket_errno (void)
+{
+ return errno;
+}
+
+void
+_dbus_restore_socket_errno (int saved_errno)
+{
+ errno = saved_errno;
+}
+
/* tests in dbus-sysdeps-util.c */
diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c
index d104e41c..15465d32 100644
--- a/dbus/dbus-sysdeps-util-unix.c
+++ b/dbus/dbus-sysdeps-util-unix.c
@@ -380,53 +380,140 @@ _dbus_change_to_daemon_user (const char *user,
}
#endif /* !HAVE_LIBAUDIT */
+#ifdef HAVE_SETRLIMIT
-/**
- * Attempt to ensure that the current process can open
- * at least @p limit file descriptors.
- *
- * If @p limit is lower than the current, it will not be
- * lowered. No error is returned if the request can
- * not be satisfied.
- *
- * @param limit number of file descriptors
+/* We assume that if we have setrlimit, we also have getrlimit and
+ * struct rlimit.
*/
-void
-_dbus_request_file_descriptor_limit (unsigned int limit)
+
+struct DBusRLimit {
+ struct rlimit lim;
+};
+
+DBusRLimit *
+_dbus_rlimit_save_fd_limit (DBusError *error)
+{
+ DBusRLimit *self;
+
+ self = dbus_new0 (DBusRLimit, 1);
+
+ if (self == NULL)
+ {
+ _DBUS_SET_OOM (error);
+ return NULL;
+ }
+
+ if (getrlimit (RLIMIT_NOFILE, &self->lim) < 0)
+ {
+ dbus_set_error (error, _dbus_error_from_errno (errno),
+ "Failed to get fd limit: %s", _dbus_strerror (errno));
+ dbus_free (self);
+ return NULL;
+ }
+
+ return self;
+}
+
+dbus_bool_t
+_dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired,
+ DBusError *error)
{
-#ifdef HAVE_SETRLIMIT
struct rlimit lim;
- struct rlimit target_lim;
/* No point to doing this practically speaking
* if we're not uid 0. We expect the system
* bus to use this before we change UID, and
- * the session bus takes the Linux default
- * of 1024 for both cur and max.
+ * the session bus takes the Linux default,
+ * currently 1024 for cur and 4096 for max.
*/
if (getuid () != 0)
- return;
+ {
+ /* not an error, we're probably the session bus */
+ return TRUE;
+ }
if (getrlimit (RLIMIT_NOFILE, &lim) < 0)
- return;
+ {
+ dbus_set_error (error, _dbus_error_from_errno (errno),
+ "Failed to get fd limit: %s", _dbus_strerror (errno));
+ return FALSE;
+ }
- if (lim.rlim_cur >= limit)
- return;
+ if (lim.rlim_cur == RLIM_INFINITY || lim.rlim_cur >= desired)
+ {
+ /* not an error, everything is fine */
+ return TRUE;
+ }
/* Ignore "maximum limit", assume we have the "superuser"
* privileges. On Linux this is CAP_SYS_RESOURCE.
*/
- target_lim.rlim_cur = target_lim.rlim_max = limit;
- /* Also ignore errors; if we fail, we will at least work
- * up to whatever limit we had, which seems better than
- * just outright aborting.
- *
- * However, in the future we should probably log this so OS builders
- * have a chance to notice any misconfiguration like dbus-daemon
- * being started without CAP_SYS_RESOURCE.
- */
- setrlimit (RLIMIT_NOFILE, &target_lim);
+ lim.rlim_cur = lim.rlim_max = desired;
+
+ if (setrlimit (RLIMIT_NOFILE, &lim) < 0)
+ {
+ dbus_set_error (error, _dbus_error_from_errno (errno),
+ "Failed to set fd limit to %u: %s",
+ desired, _dbus_strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+dbus_bool_t
+_dbus_rlimit_restore_fd_limit (DBusRLimit *saved,
+ DBusError *error)
+{
+ if (setrlimit (RLIMIT_NOFILE, &saved->lim) < 0)
+ {
+ dbus_set_error (error, _dbus_error_from_errno (errno),
+ "Failed to restore old fd limit: %s",
+ _dbus_strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#else /* !HAVE_SETRLIMIT */
+
+static void
+fd_limit_not_supported (DBusError *error)
+{
+ dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
+ "cannot change fd limit on this platform");
+}
+
+DBusRLimit *
+_dbus_rlimit_save_fd_limit (DBusError *error)
+{
+ fd_limit_not_supported (error);
+ return NULL;
+}
+
+dbus_bool_t
+_dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired,
+ DBusError *error)
+{
+ fd_limit_not_supported (error);
+ return FALSE;
+}
+
+dbus_bool_t
+_dbus_rlimit_restore_fd_limit (DBusRLimit *saved,
+ DBusError *error)
+{
+ fd_limit_not_supported (error);
+ return FALSE;
+}
+
#endif
+
+void
+_dbus_rlimit_free (DBusRLimit *lim)
+{
+ dbus_free (lim);
}
void
diff --git a/dbus/dbus-sysdeps-util-win.c b/dbus/dbus-sysdeps-util-win.c
index dd53417f..2125f608 100644
--- a/dbus/dbus-sysdeps-util-win.c
+++ b/dbus/dbus-sysdeps-util-win.c
@@ -258,9 +258,42 @@ _dbus_change_to_daemon_user (const char *user,
return TRUE;
}
+static void
+fd_limit_not_supported (DBusError *error)
+{
+ dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
+ "cannot change fd limit on this platform");
+}
+
+DBusRLimit *
+_dbus_rlimit_save_fd_limit (DBusError *error)
+{
+ fd_limit_not_supported (error);
+ return NULL;
+}
+
+dbus_bool_t
+_dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired,
+ DBusError *error)
+{
+ fd_limit_not_supported (error);
+ return FALSE;
+}
+
+dbus_bool_t
+_dbus_rlimit_restore_fd_limit (DBusRLimit *saved,
+ DBusError *error)
+{
+ fd_limit_not_supported (error);
+ return FALSE;
+}
+
void
-_dbus_request_file_descriptor_limit (unsigned int limit)
+_dbus_rlimit_free (DBusRLimit *lim)
{
+ /* _dbus_rlimit_save_fd_limit() cannot return non-NULL on Windows
+ * so there cannot be anything to free */
+ _dbus_assert (lim == NULL);
}
void
diff --git a/dbus/dbus-sysdeps-win.c b/dbus/dbus-sysdeps-win.c
index 341db8ab..2c18f40e 100644
--- a/dbus/dbus-sysdeps-win.c
+++ b/dbus/dbus-sysdeps-win.c
@@ -3253,12 +3253,12 @@ _dbus_flush_caches (void)
* See if errno is EAGAIN or EWOULDBLOCK (this has to be done differently
* for Winsock so is abstracted)
*
- * @returns #TRUE if errno == EAGAIN or errno == EWOULDBLOCK
+ * @returns #TRUE if e == EAGAIN or e == EWOULDBLOCK
*/
dbus_bool_t
-_dbus_get_is_errno_eagain_or_ewouldblock (void)
+_dbus_get_is_errno_eagain_or_ewouldblock (int e)
{
- return errno == WSAEWOULDBLOCK;
+ return e == WSAEWOULDBLOCK;
}
/**
@@ -3725,6 +3725,18 @@ _dbus_check_setuid (void)
return FALSE;
}
+int
+_dbus_save_socket_errno (void)
+{
+ return errno;
+}
+
+void
+_dbus_restore_socket_errno (int saved_errno)
+{
+ _dbus_win_set_errno (saved_errno);
+}
+
/** @} end of sysdeps-win */
/* tests in dbus-sysdeps-util.c */
diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c
index f4ba0fac..99792100 100644
--- a/dbus/dbus-sysdeps.c
+++ b/dbus/dbus-sysdeps.c
@@ -722,33 +722,23 @@ _dbus_set_errno_to_zero (void)
}
/**
- * See if errno is set
- * @returns #TRUE if errno is not 0
- */
-dbus_bool_t
-_dbus_get_is_errno_nonzero (void)
-{
- return errno != 0;
-}
-
-/**
* See if errno is ENOMEM
- * @returns #TRUE if errno == ENOMEM
+ * @returns #TRUE if e == ENOMEM
*/
dbus_bool_t
-_dbus_get_is_errno_enomem (void)
+_dbus_get_is_errno_enomem (int e)
{
- return errno == ENOMEM;
+ return e == ENOMEM;
}
/**
* See if errno is EINTR
- * @returns #TRUE if errno == EINTR
+ * @returns #TRUE if e == EINTR
*/
dbus_bool_t
-_dbus_get_is_errno_eintr (void)
+_dbus_get_is_errno_eintr (int e)
{
- return errno == EINTR;
+ return e == EINTR;
}
/**
@@ -756,9 +746,9 @@ _dbus_get_is_errno_eintr (void)
* @returns #TRUE if errno == EPIPE
*/
dbus_bool_t
-_dbus_get_is_errno_epipe (void)
+_dbus_get_is_errno_epipe (int e)
{
- return errno == EPIPE;
+ return e == EPIPE;
}
/**
@@ -766,10 +756,10 @@ _dbus_get_is_errno_epipe (void)
* @returns #TRUE if errno == ETOOMANYREFS
*/
dbus_bool_t
-_dbus_get_is_errno_etoomanyrefs (void)
+_dbus_get_is_errno_etoomanyrefs (int e)
{
#ifdef ETOOMANYREFS
- return errno == ETOOMANYREFS;
+ return e == ETOOMANYREFS;
#else
return FALSE;
#endif
diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
index 955ba9aa..09b98e11 100644
--- a/dbus/dbus-sysdeps.h
+++ b/dbus/dbus-sysdeps.h
@@ -376,13 +376,14 @@ dbus_bool_t _dbus_generate_random_ascii (DBusString *str,
const char* _dbus_error_from_errno (int error_number);
const char* _dbus_error_from_system_errno (void);
+int _dbus_save_socket_errno (void);
+void _dbus_restore_socket_errno (int saved_errno);
void _dbus_set_errno_to_zero (void);
-dbus_bool_t _dbus_get_is_errno_nonzero (void);
-dbus_bool_t _dbus_get_is_errno_eagain_or_ewouldblock (void);
-dbus_bool_t _dbus_get_is_errno_enomem (void);
-dbus_bool_t _dbus_get_is_errno_eintr (void);
-dbus_bool_t _dbus_get_is_errno_epipe (void);
-dbus_bool_t _dbus_get_is_errno_etoomanyrefs (void);
+dbus_bool_t _dbus_get_is_errno_eagain_or_ewouldblock (int e);
+dbus_bool_t _dbus_get_is_errno_enomem (int e);
+dbus_bool_t _dbus_get_is_errno_eintr (int e);
+dbus_bool_t _dbus_get_is_errno_epipe (int e);
+dbus_bool_t _dbus_get_is_errno_etoomanyrefs (int e);
const char* _dbus_strerror_from_errno (void);
void _dbus_disable_sigpipe (void);
@@ -544,8 +545,6 @@ dbus_bool_t _dbus_change_to_daemon_user (const char *user,
void _dbus_flush_caches (void);
-void _dbus_request_file_descriptor_limit (unsigned int limit);
-
/*
* replaces the term DBUS_PREFIX in configure_time_path by the
* current dbus installation directory. On unix this function is a noop
@@ -564,6 +563,15 @@ _dbus_replace_install_prefix (const char *configure_time_path);
*/
#define DBUS_DEFAULT_MESSAGE_UNIX_FDS 16
+typedef struct DBusRLimit DBusRLimit;
+
+DBusRLimit *_dbus_rlimit_save_fd_limit (DBusError *error);
+dbus_bool_t _dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired,
+ DBusError *error);
+dbus_bool_t _dbus_rlimit_restore_fd_limit (DBusRLimit *saved,
+ DBusError *error);
+void _dbus_rlimit_free (DBusRLimit *lim);
+
/** @} */
DBUS_END_DECLS
diff --git a/dbus/dbus-test-main.c b/dbus/dbus-test-main.c
index f6ef7821..9a80f853 100644
--- a/dbus/dbus-test-main.c
+++ b/dbus/dbus-test-main.c
@@ -31,6 +31,10 @@
#include <locale.h>
#endif
+#ifdef DBUS_UNIX
+# include <dbus/dbus-sysdeps-unix.h>
+#endif
+
int
main (int argc,
char **argv)
@@ -38,6 +42,11 @@ main (int argc,
const char *test_data_dir;
const char *specific_test;
+#ifdef DBUS_UNIX
+ /* close any inherited fds so dbus-spawn's check for close-on-exec works */
+ _dbus_close_all ();
+#endif
+
#if HAVE_SETLOCALE
setlocale(LC_ALL, "");
#endif
diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c
index 199d3b54..c1e47018 100644
--- a/dbus/dbus-transport-socket.c
+++ b/dbus/dbus-transport-socket.c
@@ -247,13 +247,15 @@ read_data_into_auth (DBusTransport *transport,
DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
DBusString *buffer;
int bytes_read;
-
+ int saved_errno;
+
*oom = FALSE;
_dbus_auth_get_buffer (transport->auth, &buffer);
bytes_read = _dbus_read_socket (socket_transport->fd,
buffer, socket_transport->max_bytes_read_per_iteration);
+ saved_errno = _dbus_save_socket_errno ();
_dbus_auth_return_buffer (transport->auth, buffer);
@@ -267,16 +269,16 @@ read_data_into_auth (DBusTransport *transport,
{
/* EINTR already handled for us */
- if (_dbus_get_is_errno_enomem ())
+ if (_dbus_get_is_errno_enomem (saved_errno))
{
*oom = TRUE;
}
- else if (_dbus_get_is_errno_eagain_or_ewouldblock ())
+ else if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno))
; /* do nothing, just return FALSE below */
else
{
_dbus_verbose ("Error reading from remote app: %s\n",
- _dbus_strerror_from_errno ());
+ _dbus_strerror (saved_errno));
do_io_error (transport);
}
@@ -299,6 +301,7 @@ write_data_from_auth (DBusTransport *transport)
{
DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
int bytes_written;
+ int saved_errno;
const DBusString *buffer;
if (!_dbus_auth_get_bytes_to_send (transport->auth,
@@ -308,6 +311,7 @@ write_data_from_auth (DBusTransport *transport)
bytes_written = _dbus_write_socket (socket_transport->fd,
buffer,
0, _dbus_string_get_length (buffer));
+ saved_errno = _dbus_save_socket_errno ();
if (bytes_written > 0)
{
@@ -318,12 +322,12 @@ write_data_from_auth (DBusTransport *transport)
{
/* EINTR already handled for us */
- if (_dbus_get_is_errno_eagain_or_ewouldblock ())
+ if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno))
;
else
{
_dbus_verbose ("Error writing to remote app: %s\n",
- _dbus_strerror_from_errno ());
+ _dbus_strerror (saved_errno));
do_io_error (transport);
}
}
@@ -527,6 +531,7 @@ do_writing (DBusTransport *transport)
const DBusString *body;
int header_len, body_len;
int total_bytes_to_write;
+ int saved_errno;
if (total > socket_transport->max_bytes_written_per_iteration)
{
@@ -584,6 +589,7 @@ do_writing (DBusTransport *transport)
&socket_transport->encoded_outgoing,
socket_transport->message_bytes_written,
total_bytes_to_write - socket_transport->message_bytes_written);
+ saved_errno = _dbus_save_socket_errno ();
}
else
{
@@ -612,6 +618,7 @@ do_writing (DBusTransport *transport)
0, body_len,
unix_fds,
n);
+ saved_errno = _dbus_save_socket_errno ();
if (bytes_written > 0 && n > 0)
_dbus_verbose("Wrote %i unix fds\n", n);
@@ -638,6 +645,8 @@ do_writing (DBusTransport *transport)
body_len -
(socket_transport->message_bytes_written - header_len));
}
+
+ saved_errno = _dbus_save_socket_errno ();
}
}
@@ -651,7 +660,7 @@ do_writing (DBusTransport *transport)
* http://lists.freedesktop.org/archives/dbus/2008-March/009526.html
*/
- if (_dbus_get_is_errno_eagain_or_ewouldblock () || _dbus_get_is_errno_epipe ())
+ if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno) || _dbus_get_is_errno_epipe (saved_errno))
goto out;
/* Since Linux commit 25888e (from 2.6.37-rc4, Nov 2010), sendmsg()
@@ -663,7 +672,7 @@ do_writing (DBusTransport *transport)
* https://bugs.freedesktop.org/show_bug.cgi?id=80163
*/
- else if (_dbus_get_is_errno_etoomanyrefs ())
+ else if (_dbus_get_is_errno_etoomanyrefs (saved_errno))
{
/* We only send fds in the first byte of the message.
* ETOOMANYREFS cannot happen after.
@@ -686,7 +695,7 @@ do_writing (DBusTransport *transport)
else
{
_dbus_verbose ("Error writing to remote app: %s\n",
- _dbus_strerror_from_errno ());
+ _dbus_strerror (saved_errno));
do_io_error (transport);
goto out;
}
@@ -730,6 +739,7 @@ do_reading (DBusTransport *transport)
int bytes_read;
int total;
dbus_bool_t oom;
+ int saved_errno;
_dbus_verbose ("fd = %d\n",socket_transport->fd);
@@ -774,6 +784,8 @@ do_reading (DBusTransport *transport)
&socket_transport->encoded_incoming,
socket_transport->max_bytes_read_per_iteration);
+ saved_errno = _dbus_save_socket_errno ();
+
_dbus_assert (_dbus_string_get_length (&socket_transport->encoded_incoming) ==
bytes_read);
@@ -823,6 +835,7 @@ do_reading (DBusTransport *transport)
buffer,
socket_transport->max_bytes_read_per_iteration,
fds, &n_fds);
+ saved_errno = _dbus_save_socket_errno ();
if (bytes_read >= 0 && n_fds > 0)
_dbus_verbose("Read %i unix fds\n", n_fds);
@@ -834,28 +847,29 @@ do_reading (DBusTransport *transport)
{
bytes_read = _dbus_read_socket (socket_transport->fd,
buffer, socket_transport->max_bytes_read_per_iteration);
+ saved_errno = _dbus_save_socket_errno ();
}
_dbus_message_loader_return_buffer (transport->loader,
buffer);
}
-
+
if (bytes_read < 0)
{
/* EINTR already handled for us */
- if (_dbus_get_is_errno_enomem ())
+ if (_dbus_get_is_errno_enomem (saved_errno))
{
_dbus_verbose ("Out of memory in read()/do_reading()\n");
oom = TRUE;
goto out;
}
- else if (_dbus_get_is_errno_eagain_or_ewouldblock ())
+ else if (_dbus_get_is_errno_eagain_or_ewouldblock (saved_errno))
goto out;
else
{
_dbus_verbose ("Error reading from remote app: %s\n",
- _dbus_strerror_from_errno ());
+ _dbus_strerror (saved_errno));
do_io_error (transport);
goto out;
}
@@ -1129,6 +1143,8 @@ socket_do_iteration (DBusTransport *transport,
if (poll_fd.events)
{
+ int saved_errno;
+
if (flags & DBUS_ITERATION_BLOCK)
poll_timeout = timeout_milliseconds;
else
@@ -1147,8 +1163,9 @@ socket_do_iteration (DBusTransport *transport,
again:
poll_res = _dbus_poll (&poll_fd, 1, poll_timeout);
+ saved_errno = _dbus_save_socket_errno ();
- if (poll_res < 0 && _dbus_get_is_errno_eintr ())
+ if (poll_res < 0 && _dbus_get_is_errno_eintr (saved_errno))
goto again;
if (flags & DBUS_ITERATION_BLOCK)
@@ -1191,7 +1208,7 @@ socket_do_iteration (DBusTransport *transport,
else
{
_dbus_verbose ("Error from _dbus_poll(): %s\n",
- _dbus_strerror_from_errno ());
+ _dbus_strerror (saved_errno));
}
}
diff --git a/doc/Makefile.in b/doc/Makefile.in
index a48c7e5a..959666de 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -326,6 +326,7 @@ build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
+dbus_daemondir = @dbus_daemondir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
diff --git a/doc/dbus-daemon.1.xml.in b/doc/dbus-daemon.1.xml.in
index cd7942c3..78f0fd08 100644
--- a/doc/dbus-daemon.1.xml.in
+++ b/doc/dbus-daemon.1.xml.in
@@ -396,12 +396,14 @@ DBUS_SESSION_BUS_ADDRESS is set.</para>
used in a listenable address to configure the interface on which
the server will listen: either the hostname is the IP address of
one of the local machine's interfaces (most commonly 127.0.0.1),
-or a DNS name that resolves to one of those IP addresses, or '*'
-to listen on all interfaces simultaneously. If not specified,
+a DNS name that resolves to one of those IP addresses, '0.0.0.0'
+to listen on all IPv4 interfaces simultaneously, or '::'
+to listen on all IPv4 and IPv6 interfaces simultaneously (if supported
+by the OS). If not specified,
the default is the same value as "host".</para>
-<para>Example: &lt;listen&gt;tcp:host=localhost,bind=*,port=0&lt;/listen&gt;</para>
+<para>Example: &lt;listen&gt;tcp:host=localhost,bind=0.0.0.0,port=0&lt;/listen&gt;</para>
<itemizedlist remap='TP'>
diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml
index eea5eada..6316bd83 100644
--- a/doc/dbus-specification.xml
+++ b/doc/dbus-specification.xml
@@ -6,8 +6,8 @@
<article id="index">
<articleinfo>
<title>D-Bus Specification</title>
- <releaseinfo>Version 0.24</releaseinfo>
- <date>2014-10-01</date>
+ <releaseinfo>Version 0.25</releaseinfo>
+ <date>2014-11-10</date>
<authorgroup>
<author>
<firstname>Havoc</firstname>
@@ -71,6 +71,14 @@
</authorgroup>
<revhistory>
<revision>
+ <revnumber>0.25</revnumber>
+ <date>2014-11-10</date>
+ <authorinitials>smcv, lennart</authorinitials>
+ <revremark>
+ ALLOW_INTERACTIVE_AUTHORIZATION flag, EmitsChangedSignal=const
+ </revremark>
+ </revision>
+ <revision>
<revnumber>0.24</revnumber>
<date>2014-10-01</date>
<authorinitials>SMcV</authorinitials>
@@ -764,6 +772,7 @@
<tgroup cols="3">
<thead>
<row>
+ <entry>Category</entry>
<entry>Conventional Name</entry>
<entry>Code</entry>
<entry>Description</entry>
@@ -771,62 +780,77 @@
</thead>
<tbody>
<row>
+ <entry>reserved</entry>
<entry><literal>INVALID</literal></entry>
<entry>0 (ASCII NUL)</entry>
<entry>Not a valid type code, used to terminate signatures</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>BYTE</literal></entry>
<entry>121 (ASCII 'y')</entry>
<entry>8-bit unsigned integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>BOOLEAN</literal></entry>
<entry>98 (ASCII 'b')</entry>
<entry>Boolean value, 0 is <literal>FALSE</literal> and 1 is <literal>TRUE</literal>. Everything else is invalid.</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>INT16</literal></entry>
<entry>110 (ASCII 'n')</entry>
<entry>16-bit signed integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>UINT16</literal></entry>
<entry>113 (ASCII 'q')</entry>
<entry>16-bit unsigned integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>INT32</literal></entry>
<entry>105 (ASCII 'i')</entry>
<entry>32-bit signed integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>UINT32</literal></entry>
<entry>117 (ASCII 'u')</entry>
<entry>32-bit unsigned integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>INT64</literal></entry>
<entry>120 (ASCII 'x')</entry>
<entry>64-bit signed integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>UINT64</literal></entry>
<entry>116 (ASCII 't')</entry>
<entry>64-bit unsigned integer</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>DOUBLE</literal></entry>
<entry>100 (ASCII 'd')</entry>
<entry>IEEE 754 double</entry>
</row><row>
+ <entry>string-like, basic</entry>
<entry><literal>STRING</literal></entry>
<entry>115 (ASCII 's')</entry>
<entry>UTF-8 string (<emphasis>must</emphasis> be valid UTF-8). Must be nul terminated and contain no other nul bytes.</entry>
</row><row>
+ <entry>string-like, basic</entry>
<entry><literal>OBJECT_PATH</literal></entry>
<entry>111 (ASCII 'o')</entry>
<entry>Name of an object instance</entry>
</row><row>
+ <entry>string-like, basic</entry>
<entry><literal>SIGNATURE</literal></entry>
<entry>103 (ASCII 'g')</entry>
<entry>A type signature</entry>
</row><row>
+ <entry>container</entry>
<entry><literal>ARRAY</literal></entry>
<entry>97 (ASCII 'a')</entry>
<entry>Array</entry>
</row><row>
+ <entry>container</entry>
<entry><literal>STRUCT</literal></entry>
<entry>114 (ASCII 'r'), 40 (ASCII '('), 41 (ASCII ')')</entry>
<entry>Struct; type code 114 'r' is reserved for use in
@@ -834,10 +858,12 @@
concept of a struct, and must not appear in signatures
used on D-Bus.</entry>
</row><row>
+ <entry>container</entry>
<entry><literal>VARIANT</literal></entry>
<entry>118 (ASCII 'v') </entry>
<entry>Variant type (the type of the value is part of the value itself)</entry>
</row><row>
+ <entry>container</entry>
<entry><literal>DICT_ENTRY</literal></entry>
<entry>101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}') </entry>
<entry>Entry in a dict or map (array of key-value pairs).
@@ -846,11 +872,13 @@
dict or dict-entry, and must not appear in signatures
used on D-Bus.</entry>
</row><row>
+ <entry>fixed, basic</entry>
<entry><literal>UNIX_FD</literal></entry>
<entry>104 (ASCII 'h')</entry>
<entry>Unix file descriptor</entry>
</row>
<row>
+ <entry>reserved</entry>
<entry>(reserved)</entry>
<entry>109 (ASCII 'm')</entry>
<entry>Reserved for <ulink
@@ -860,6 +888,7 @@
specified here</entry>
</row>
<row>
+ <entry>reserved</entry>
<entry>(reserved)</entry>
<entry>42 (ASCII '*')</entry>
<entry>Reserved for use in bindings/implementations to
@@ -867,6 +896,7 @@
and must not appear in signatures used on D-Bus.</entry>
</row>
<row>
+ <entry>reserved</entry>
<entry>(reserved)</entry>
<entry>63 (ASCII '?')</entry>
<entry>Reserved for use in bindings/implementations to
@@ -874,6 +904,7 @@
not appear in signatures used on D-Bus.</entry>
</row>
<row>
+ <entry>reserved</entry>
<entry>(reserved)</entry>
<entry>64 (ASCII '@'), 38 (ASCII '&amp;'),
94 (ASCII '^')</entry>
@@ -995,8 +1026,8 @@
<para>
Arrays have a maximum length defined to be 2 to the 26th power or
- 67108864. Implementations must not send or accept arrays exceeding this
- length.
+ 67108864 (64 MiB). Implementations must not send or accept arrays
+ exceeding this length.
</para>
<para>
@@ -1201,8 +1232,8 @@
<para>
The maximum length of a message, including header, header alignment padding,
- and body is 2 to the 27th power or 134217728. Implementations must not
- send or accept messages exceeding this size.
+ and body is 2 to the 27th power or 134217728 (128 MiB).
+ Implementations must not send or accept messages exceeding this size.
</para>
<para>
@@ -1368,6 +1399,66 @@
for the destination name in response to this message.
</entry>
</row>
+ <row>
+ <entry><literal>ALLOW_INTERACTIVE_AUTHORIZATION</literal></entry>
+ <entry>0x4</entry>
+ <entry>
+ <para>
+ This flag may be set on a method call message to
+ inform the receiving side that the caller is prepared
+ to wait for interactive authorization, which might
+ take a considerable time to complete. For instance,
+ if this flag is set, it would be appropriate to
+ query the user for passwords or confirmation via
+ Polkit or a similar framework.
+ </para>
+ <para>
+ This flag is only useful when
+ unprivileged code calls a more privileged method call,
+ and an authorization framework is deployed that allows
+ possibly interactive authorization. If no such framework
+ is deployed it has no effect. This flag should not
+ be set by default by client implementations. If it is
+ set, the caller should also set a suitably long timeout
+ on the method call to make sure the user interaction
+ may complete. This flag is only valid for method call
+ messages, and shall be ignored otherwise.
+ </para>
+ <para>
+ Interaction that takes place as a part of the
+ effect of the method being called is outside the scope
+ of this flag, even if it could also be characterized
+ as authentication or authorization. For instance, in
+ a method call that directs a network management service
+ to attempt to connect to a virtual private network,
+ this flag should control how the network management
+ service makes the decision "is this user allowed to
+ change system network configuration?", but it should
+ not affect how or whether the network management
+ service interacts with the user to obtain the credentials
+ that are required for access to the VPN.
+ </para>
+ <para>
+ If a this flag is not set on a method call, and a
+ service determines that the requested operation is
+ not allowed without interactive authorization, but
+ could be allowed after successful interactive
+ authorization, it may return the
+ <literal>org.freedesktop.DBus.Error.InteractiveAuthorizationRequired</literal>
+ error.
+ </para>
+ <para>
+ The absence of this flag does not guarantee that
+ interactive authorization will not be applied, since
+ existing services that pre-date this flag might
+ already use interactive authorization. However,
+ existing D-Bus APIs that will use interactive
+ authorization should document that the call may take
+ longer than usual, and new D-Bus APIs should avoid
+ interactive authorization in the absence of this flag.
+ </para>
+ </entry>
+ </row>
</tbody>
</tgroup>
</informaltable>
@@ -3919,7 +4010,7 @@
</row>
<row>
<entry>org.freedesktop.DBus.Property.EmitsChangedSignal</entry>
- <entry>true,invalidates,false</entry>
+ <entry>true,invalidates,const,false</entry>
<entry>
<para>
If set to <literal>false</literal>, the
@@ -3929,6 +4020,12 @@
guaranteed to be emitted if the property changes.
</para>
<para>
+ If set to <literal>const</literal> the property never
+ changes value during the lifetime of the object it
+ belongs to, and hence the signal is never emitted for
+ it.
+ </para>
+ <para>
If set to <literal>invalidates</literal> the signal
is emitted but the value is not included in the
signal.
@@ -3944,6 +4041,17 @@
defaults to the value specified in the enclosing
interface element.
</para>
+ <para>
+ This annotation is intended to be used by code
+ generators to implement client-side caching of
+ property values. For all properties for which the
+ annotation is set to <literal>const</literal>,
+ <literal>invalidates</literal> or
+ <literal>true</literal> the client may
+ unconditionally cache the values as the properties
+ don't change or notifications are generated for them
+ if they do.
+ </para>
</entry>
</row>
</tbody>
diff --git a/doc/dbus-tutorial.xml b/doc/dbus-tutorial.xml
index 3d14e5f7..c4d9504e 100644
--- a/doc/dbus-tutorial.xml
+++ b/doc/dbus-tutorial.xml
@@ -704,939 +704,19 @@
</sect1>
<sect1 id="glib-client">
- <title>GLib API: Using Remote Objects</title>
-
- <para>
- The GLib binding is defined in the header file
- <literal>&lt;dbus/dbus-glib.h&gt;</literal>.
- </para>
-
- <sect2 id="glib-typemappings">
- <title>D-Bus - GLib type mappings</title>
- <para>
- The heart of the GLib bindings for D-Bus is the mapping it
- provides between D-Bus "type signatures" and GLib types
- (<literal>GType</literal>). The D-Bus type system is composed of
- a number of "basic" types, along with several "container" types.
- </para>
- <sect3 id="glib-basic-typemappings">
- <title>Basic type mappings</title>
- <para>
- Below is a list of the basic types, along with their associated
- mapping to a <literal>GType</literal>.
- <informaltable>
- <tgroup cols="4">
- <thead>
- <row>
- <entry>D-Bus basic type</entry>
- <entry>GType</entry>
- <entry>Free function</entry>
- <entry>Notes</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><literal>BYTE</literal></entry>
- <entry><literal>G_TYPE_UCHAR</literal></entry>
- <entry></entry>
- <entry></entry>
- </row><row>
- <entry><literal>BOOLEAN</literal></entry>
- <entry><literal>G_TYPE_BOOLEAN</literal></entry>
- <entry></entry>
- <entry></entry>
- </row><row>
- <entry><literal>INT16</literal></entry>
- <entry><literal>G_TYPE_INT</literal></entry>
- <entry></entry>
- <entry>Will be changed to a <literal>G_TYPE_INT16</literal> once GLib has it</entry>
- </row><row>
- <entry><literal>UINT16</literal></entry>
- <entry><literal>G_TYPE_UINT</literal></entry>
- <entry></entry>
- <entry>Will be changed to a <literal>G_TYPE_UINT16</literal> once GLib has it</entry>
- </row><row>
- <entry><literal>INT32</literal></entry>
- <entry><literal>G_TYPE_INT</literal></entry>
- <entry></entry>
- <entry>Will be changed to a <literal>G_TYPE_INT32</literal> once GLib has it</entry>
- </row><row>
- <entry><literal>UINT32</literal></entry>
- <entry><literal>G_TYPE_UINT</literal></entry>
- <entry></entry>
- <entry>Will be changed to a <literal>G_TYPE_UINT32</literal> once GLib has it</entry>
- </row><row>
- <entry><literal>INT64</literal></entry>
- <entry><literal>G_TYPE_GINT64</literal></entry>
- <entry></entry>
- <entry></entry>
- </row><row>
- <entry><literal>UINT64</literal></entry>
- <entry><literal>G_TYPE_GUINT64</literal></entry>
- <entry></entry>
- <entry></entry>
- </row><row>
- <entry><literal>DOUBLE</literal></entry>
- <entry><literal>G_TYPE_DOUBLE</literal></entry>
- <entry></entry>
- <entry></entry>
- </row><row>
- <entry><literal>STRING</literal></entry>
- <entry><literal>G_TYPE_STRING</literal></entry>
- <entry><literal>g_free</literal></entry>
- <entry></entry>
- </row><row>
- <entry><literal>OBJECT_PATH</literal></entry>
- <entry><literal>DBUS_TYPE_G_PROXY</literal></entry>
- <entry><literal>g_object_unref</literal></entry>
- <entry>The returned proxy does not have an interface set; use <literal>dbus_g_proxy_set_interface</literal> to invoke methods</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- As you can see, the basic mapping is fairly straightforward.
- </para>
- </sect3>
- <sect3 id="glib-container-typemappings">
- <title>Container type mappings</title>
- <para>
- The D-Bus type system also has a number of "container"
- types, such as <literal>DBUS_TYPE_ARRAY</literal> and
- <literal>DBUS_TYPE_STRUCT</literal>. The D-Bus type system
- is fully recursive, so one can for example have an array of
- array of strings (i.e. type signature
- <literal>aas</literal>).
- </para>
- <para>
- However, not all of these types are in common use; for
- example, at the time of this writing the author knows of no
- one using <literal>DBUS_TYPE_STRUCT</literal>, or a
- <literal>DBUS_TYPE_ARRAY</literal> containing any non-basic
- type. The approach the GLib bindings take is pragmatic; try
- to map the most common types in the most obvious way, and
- let using less common and more complex types be less
- "natural".
- </para>
- <para>
- First, D-Bus type signatures which have an "obvious"
- corresponding built-in GLib type are mapped using that type:
- <informaltable>
- <tgroup cols="6">
- <thead>
- <row>
- <entry>D-Bus type signature</entry>
- <entry>Description</entry>
- <entry>GType</entry>
- <entry>C typedef</entry>
- <entry>Free function</entry>
- <entry>Notes</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><literal>as</literal></entry>
- <entry>Array of strings</entry>
- <entry><literal>G_TYPE_STRV</literal></entry>
- <entry><literal>char **</literal></entry>
- <entry><literal>g_strfreev</literal></entry>
- <entry></entry>
- </row><row>
- <entry><literal>v</literal></entry>
- <entry>Generic value container</entry>
- <entry><literal>G_TYPE_VALUE</literal></entry>
- <entry><literal>GValue *</literal></entry>
- <entry><literal>g_value_unset</literal></entry>
- <entry>The calling conventions for values expect that method callers have allocated return values; see below.</entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </para>
- <para>
- The next most common recursive type signatures are arrays of
- basic values. The most obvious mapping for arrays of basic
- types is a <literal>GArray</literal>. Now, GLib does not
- provide a builtin <literal>GType</literal> for
- <literal>GArray</literal>. However, we actually need more than
- that - we need a "parameterized" type which includes the
- contained type. Why we need this we will see below.
- </para>
- <para>
- The approach taken is to create these types in the D-Bus GLib
- bindings; however, there is nothing D-Bus specific about them.
- In the future, we hope to include such "fundamental" types in GLib
- itself.
- <informaltable>
- <tgroup cols="6">
- <thead>
- <row>
- <entry>D-Bus type signature</entry>
- <entry>Description</entry>
- <entry>GType</entry>
- <entry>C typedef</entry>
- <entry>Free function</entry>
- <entry>Notes</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><literal>ay</literal></entry>
- <entry>Array of bytes</entry>
- <entry><literal>DBUS_TYPE_G_UCHAR_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- <row>
- <entry><literal>au</literal></entry>
- <entry>Array of uint</entry>
- <entry><literal>DBUS_TYPE_G_UINT_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- <row>
- <entry><literal>ai</literal></entry>
- <entry>Array of int</entry>
- <entry><literal>DBUS_TYPE_G_INT_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- <row>
- <entry><literal>ax</literal></entry>
- <entry>Array of int64</entry>
- <entry><literal>DBUS_TYPE_G_INT64_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- <row>
- <entry><literal>at</literal></entry>
- <entry>Array of uint64</entry>
- <entry><literal>DBUS_TYPE_G_UINT64_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- <row>
- <entry><literal>ad</literal></entry>
- <entry>Array of double</entry>
- <entry><literal>DBUS_TYPE_G_DOUBLE_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- <row>
- <entry><literal>ab</literal></entry>
- <entry>Array of boolean</entry>
- <entry><literal>DBUS_TYPE_G_BOOLEAN_ARRAY</literal></entry>
- <entry><literal>GArray *</literal></entry>
- <entry>g_array_free</entry>
- <entry></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </para>
- <para>
- D-Bus also includes a special type DBUS_TYPE_DICT_ENTRY which
- is only valid in arrays. It's intended to be mapped to a "dictionary"
- type by bindings. The obvious GLib mapping here is GHashTable. Again,
- however, there is no builtin <literal>GType</literal> for a GHashTable.
- Moreover, just like for arrays, we need a parameterized type so that
- the bindings can communiate which types are contained in the hash table.
- </para>
- <para>
- At present, only strings are supported. Work is in progress to
- include more types.
- <informaltable>
- <tgroup cols="6">
- <thead>
- <row>
- <entry>D-Bus type signature</entry>
- <entry>Description</entry>
- <entry>GType</entry>
- <entry>C typedef</entry>
- <entry>Free function</entry>
- <entry>Notes</entry>
- </row>
- </thead>
- <tbody>
- <row>
- <entry><literal>a{ss}</literal></entry>
- <entry>Dictionary mapping strings to strings</entry>
- <entry><literal>DBUS_TYPE_G_STRING_STRING_HASHTABLE</literal></entry>
- <entry><literal>GHashTable *</literal></entry>
- <entry>g_hash_table_destroy</entry>
- <entry></entry>
- </row>
- </tbody>
- </tgroup>
- </informaltable>
- </para>
- </sect3>
- <sect3 id="glib-generic-typemappings">
- <title>Arbitrarily recursive type mappings</title>
- <para>
- Finally, it is possible users will want to write or invoke D-Bus
- methods which have arbitrarily complex type signatures not
- directly supported by these bindings. For this case, we have a
- <literal>DBusGValue</literal> which acts as a kind of special
- variant value which may be iterated over manually. The
- <literal>GType</literal> associated is
- <literal>DBUS_TYPE_G_VALUE</literal>.
- </para>
- <para>
- TODO insert usage of <literal>DBUS_TYPE_G_VALUE</literal> here.
- </para>
- </sect3>
- </sect2>
- <sect2 id="sample-program-1">
- <title>A sample program</title>
- <para>Here is a D-Bus program using the GLib bindings.
-<programlisting>
-int
-main (int argc, char **argv)
-{
- DBusGConnection *connection;
- GError *error;
- DBusGProxy *proxy;
- char **name_list;
- char **name_list_ptr;
-
- g_type_init ();
-
- error = NULL;
- connection = dbus_g_bus_get (DBUS_BUS_SESSION,
- &amp;error);
- if (connection == NULL)
- {
- g_printerr ("Failed to open connection to bus: %s\n",
- error-&gt;message);
- g_error_free (error);
- exit (1);
- }
-
- /* Create a proxy object for the "bus driver" (name "org.freedesktop.DBus") */
-
- proxy = dbus_g_proxy_new_for_name (connection,
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS);
-
- /* Call ListNames method, wait for reply */
- error = NULL;
- if (!dbus_g_proxy_call (proxy, "ListNames", &amp;error, G_TYPE_INVALID,
- G_TYPE_STRV, &amp;name_list, G_TYPE_INVALID))
- {
- /* Just do demonstrate remote exceptions versus regular GError */
- if (error->domain == DBUS_GERROR &amp;&amp; error->code == DBUS_GERROR_REMOTE_EXCEPTION)
- g_printerr ("Caught remote method exception %s: %s",
- dbus_g_error_get_name (error),
- error-&gt;message);
- else
- g_printerr ("Error: %s\n", error-&gt;message);
- g_error_free (error);
- exit (1);
- }
-
- /* Print the results */
-
- g_print ("Names on the message bus:\n");
-
- for (name_list_ptr = name_list; *name_list_ptr; name_list_ptr++)
- {
- g_print (" %s\n", *name_list_ptr);
- }
- g_strfreev (name_list);
-
- g_object_unref (proxy);
-
- return 0;
-}
-</programlisting>
- </para>
- </sect2>
- <sect2 id="glib-program-setup">
- <title>Program initalization</title>
- <para>
- A connection to the bus is acquired using
- <literal>dbus_g_bus_get</literal>. Next, a proxy
- is created for the object "/org/freedesktop/DBus" with
- interface <literal>org.freedesktop.DBus</literal>
- on the service <literal>org.freedesktop.DBus</literal>.
- This is a proxy for the message bus itself.
- </para>
- </sect2>
- <sect2 id="glib-method-invocation">
- <title>Understanding method invocation</title>
- <para>
- You have a number of choices for method invocation. First, as
- used above, <literal>dbus_g_proxy_call</literal> sends a
- method call to the remote object, and blocks until a reply is
- recieved. The outgoing arguments are specified in the varargs
- array, terminated with <literal>G_TYPE_INVALID</literal>.
- Next, pointers to return values are specified, followed again
- by <literal>G_TYPE_INVALID</literal>.
- </para>
- <para>
- To invoke a method asynchronously, use
- <literal>dbus_g_proxy_begin_call</literal>. This returns a
- <literal>DBusGPendingCall</literal> object; you may then set a
- notification function using
- <literal>dbus_g_pending_call_set_notify</literal>.
- </para>
- </sect2>
- <sect2 id="glib-signal-connection">
- <title>Connecting to object signals</title>
- <para>
- You may connect to signals using
- <literal>dbus_g_proxy_add_signal</literal> and
- <literal>dbus_g_proxy_connect_signal</literal>. You must
- invoke <literal>dbus_g_proxy_add_signal</literal> to specify
- the signature of your signal handlers; you may then invoke
- <literal>dbus_g_proxy_connect_signal</literal> multiple times.
- </para>
- <para>
- Note that it will often be the case that there is no builtin
- marshaller for the type signature of a remote signal. In that
- case, you must generate a marshaller yourself by using
- <application>glib-genmarshal</application>, and then register
- it using <literal>dbus_g_object_register_marshaller</literal>.
- </para>
- </sect2>
- <sect2 id="glib-error-handling">
- <title>Error handling and remote exceptions</title>
- <para>
- All of the GLib binding methods such as
- <literal>dbus_g_proxy_end_call</literal> return a
- <literal>GError</literal>. This <literal>GError</literal> can
- represent two different things:
- <itemizedlist>
- <listitem>
- <para>
- An internal D-Bus error, such as an out-of-memory
- condition, an I/O error, or a network timeout. Errors
- generated by the D-Bus library itself have the domain
- <literal>DBUS_GERROR</literal>, and a corresponding code
- such as <literal>DBUS_GERROR_NO_MEMORY</literal>. It will
- not be typical for applications to handle these errors
- specifically.
- </para>
- </listitem>
- <listitem>
- <para>
- A remote D-Bus exception, thrown by the peer, bus, or
- service. D-Bus remote exceptions have both a textual
- "name" and a "message". The GLib bindings store this
- information in the <literal>GError</literal>, but some
- special rules apply.
- </para>
- <para>
- The set error will have the domain
- <literal>DBUS_GERROR</literal> as above, and will also
- have the code
- <literal>DBUS_GERROR_REMOTE_EXCEPTION</literal>. In order
- to access the remote exception name, you must use a
- special accessor, such as
- <literal>dbus_g_error_has_name</literal> or
- <literal>dbus_g_error_get_name</literal>. The remote
- exception detailed message is accessible via the regular
- GError <literal>message</literal> member.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </sect2>
- <sect2 id="glib-more-examples">
- <title>More examples of method invocation</title>
- <sect3 id="glib-sending-stuff">
- <title>Sending an integer and string, receiving an array of bytes</title>
- <para>
-<programlisting>
- GArray *arr;
-
- error = NULL;
- if (!dbus_g_proxy_call (proxy, "Foobar", &amp;error,
- G_TYPE_INT, 42, G_TYPE_STRING, "hello",
- G_TYPE_INVALID,
- DBUS_TYPE_G_UCHAR_ARRAY, &amp;arr, G_TYPE_INVALID))
- {
- /* Handle error */
- }
- g_assert (arr != NULL);
- printf ("got back %u values", arr->len);
-</programlisting>
- </para>
- </sect3>
- <sect3 id="glib-sending-hash">
- <title>Sending a GHashTable</title>
- <para>
-<programlisting>
- GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal);
- guint32 ret;
-
- g_hash_table_insert (hash, "foo", "bar");
- g_hash_table_insert (hash, "baz", "whee");
-
- error = NULL;
- if (!dbus_g_proxy_call (proxy, "HashSize", &amp;error,
- DBUS_TYPE_G_STRING_STRING_HASH, hash, G_TYPE_INVALID,
- G_TYPE_UINT, &amp;ret, G_TYPE_INVALID))
- {
- /* Handle error */
- }
- g_assert (ret == 2);
- g_hash_table_destroy (hash);
-</programlisting>
- </para>
- </sect3>
- <sect3 id="glib-receiving-bool-int">
- <title>Receiving a boolean and a string</title>
- <para>
-<programlisting>
- gboolean boolret;
- char *strret;
-
- error = NULL;
- if (!dbus_g_proxy_call (proxy, "GetStuff", &amp;error,
- G_TYPE_INVALID,
- G_TYPE_BOOLEAN, &amp;boolret,
- G_TYPE_STRING, &amp;strret,
- G_TYPE_INVALID))
- {
- /* Handle error */
- }
- printf ("%s %s", boolret ? "TRUE" : "FALSE", strret);
- g_free (strret);
-</programlisting>
- </para>
- </sect3>
- <sect3 id="glib-sending-str-arrays">
- <title>Sending two arrays of strings</title>
- <para>
-<programlisting>
- /* NULL terminate */
- char *strs_static[] = {"foo", "bar", "baz", NULL};
- /* Take pointer to array; cannot pass array directly */
- char **strs_static_p = strs_static;
- char **strs_dynamic;
-
- strs_dynamic = g_new (char *, 4);
- strs_dynamic[0] = g_strdup ("hello");
- strs_dynamic[1] = g_strdup ("world");
- strs_dynamic[2] = g_strdup ("!");
- /* NULL terminate */
- strs_dynamic[3] = NULL;
-
- error = NULL;
- if (!dbus_g_proxy_call (proxy, "TwoStrArrays", &amp;error,
- G_TYPE_STRV, strs_static_p,
- G_TYPE_STRV, strs_dynamic,
- G_TYPE_INVALID,
- G_TYPE_INVALID))
- {
- /* Handle error */
- }
- g_strfreev (strs_dynamic);
-</programlisting>
- </para>
- </sect3>
- <sect3 id="glib-getting-str-array">
- <title>Sending a boolean, receiving an array of strings</title>
- <para>
-<programlisting>
- char **strs;
- char **strs_p;
- gboolean blah;
-
- error = NULL;
- blah = TRUE;
- if (!dbus_g_proxy_call (proxy, "GetStrs", &amp;error,
- G_TYPE_BOOLEAN, blah,
- G_TYPE_INVALID,
- G_TYPE_STRV, &amp;strs,
- G_TYPE_INVALID))
- {
- /* Handle error */
- }
- for (strs_p = strs; *strs_p; strs_p++)
- printf ("got string: \"%s\"", *strs_p);
- g_strfreev (strs);
-</programlisting>
- </para>
- </sect3>
- <sect3 id="glib-sending-variant">
- <title>Sending a variant</title>
- <para>
-<programlisting>
- GValue val = {0, };
-
- g_value_init (&amp;val, G_TYPE_STRING);
- g_value_set_string (&amp;val, "hello world");
-
- error = NULL;
- if (!dbus_g_proxy_call (proxy, "SendVariant", &amp;error,
- G_TYPE_VALUE, &amp;val, G_TYPE_INVALID,
- G_TYPE_INVALID))
- {
- /* Handle error */
- }
- g_assert (ret == 2);
- g_value_unset (&amp;val);
-</programlisting>
- </para>
- </sect3>
- <sect3 id="glib-receiving-variant">
- <title>Receiving a variant</title>
- <para>
-<programlisting>
- GValue val = {0, };
-
- error = NULL;
- if (!dbus_g_proxy_call (proxy, "GetVariant", &amp;error, G_TYPE_INVALID,
- G_TYPE_VALUE, &amp;val, G_TYPE_INVALID))
- {
- /* Handle error */
- }
- if (G_VALUE_TYPE (&amp;val) == G_TYPE_STRING)
- printf ("%s\n", g_value_get_string (&amp;val));
- else if (G_VALUE_TYPE (&amp;val) == G_TYPE_INT)
- printf ("%d\n", g_value_get_int (&amp;val));
- else
- ...
- g_value_unset (&amp;val);
-</programlisting>
- </para>
- </sect3>
- </sect2>
-
- <sect2 id="glib-generated-bindings">
- <title>Generated Bindings</title>
- <para>
- By using the Introspection XML files, convenient client-side bindings
- can be automatically created to ease the use of a remote DBus object.
- </para>
- <para>
- Here is a sample XML file which describes an object that exposes
- one method, named <literal>ManyArgs</literal>.
- <programlisting>
-&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
-&lt;node name="/com/example/MyObject"&gt;
- &lt;interface name="com.example.MyObject"&gt;
- &lt;method name="ManyArgs"&gt;
- &lt;arg type="u" name="x" direction="in" /&gt;
- &lt;arg type="s" name="str" direction="in" /&gt;
- &lt;arg type="d" name="trouble" direction="in" /&gt;
- &lt;arg type="d" name="d_ret" direction="out" /&gt;
- &lt;arg type="s" name="str_ret" direction="out" /&gt;
- &lt;/method&gt;
- &lt;/interface&gt;
-&lt;/node&gt;
-</programlisting>
- </para>
- <para>
- Run <literal>dbus-binding-tool --mode=glib-client
- <replaceable>FILENAME</replaceable> &gt;
- <replaceable>HEADER_NAME</replaceable></literal> to generate the header
- file. For example: <command>dbus-binding-tool --mode=glib-client
- my-object.xml &gt; my-object-bindings.h</command>. This will generate
- inline functions with the following prototypes:
- <programlisting>
-/* This is a blocking call */
-gboolean
-com_example_MyObject_many_args (DBusGProxy *proxy, const guint IN_x,
- const char * IN_str, const gdouble IN_trouble,
- gdouble* OUT_d_ret, char ** OUT_str_ret,
- GError **error);
-
-/* This is a non-blocking call */
-DBusGProxyCall*
-com_example_MyObject_many_args_async (DBusGProxy *proxy, const guint IN_x,
- const char * IN_str, const gdouble IN_trouble,
- com_example_MyObject_many_args_reply callback,
- gpointer userdata);
-
-/* This is the typedef for the non-blocking callback */
-typedef void
-(*com_example_MyObject_many_args_reply)
-(DBusGProxy *proxy, gdouble OUT_d_ret, char * OUT_str_ret,
- GError *error, gpointer userdata);
-</programlisting>
- The first argument in all functions is a <literal>DBusGProxy
- *</literal>, which you should create with the usual
- <literal>dbus_g_proxy_new_*</literal> functions. Following that are the
- "in" arguments, and then either the "out" arguments and a
- <literal>GError *</literal> for the synchronous (blocking) function, or
- callback and user data arguments for the asynchronous (non-blocking)
- function. The callback in the asynchronous function passes the
- <literal>DBusGProxy *</literal>, the returned "out" arguments, an
- <literal>GError *</literal> which is set if there was an error otherwise
- <literal>NULL</literal>, and the user data.
- </para>
- <para>
- As with the server-side bindings support (see <xref
- linkend="glib-server"/>), the exact behaviour of the client-side
- bindings can be manipulated using "annotations". Currently the only
- annotation used by the client bindings is
- <literal>org.freedesktop.DBus.GLib.NoReply</literal>, which sets the
- flag indicating that the client isn't expecting a reply to the method
- call, so a reply shouldn't be sent. This is often used to speed up
- rapid method calls where there are no "out" arguments, and not knowing
- if the method succeeded is an acceptable compromise to half the traffic
- on the bus.
- </para>
- </sect2>
- </sect1>
-
- <sect1 id="glib-server">
- <title>GLib API: Implementing Objects</title>
+ <title>GLib APIs</title>
<para>
- At the moment, to expose a GObject via D-Bus, you must
- write XML by hand which describes the methods exported
- by the object. In the future, this manual step will
- be obviated by the upcoming GLib introspection support.
+ The recommended GLib API for D-Bus is GDBus, which has been
+ distributed with GLib since version 2.26. It is not documented here.
+ See <ulink url="https://developer.gnome.org/gio/stable/gdbus-convenience.html">the
+ GLib documentation</ulink> for details of how to use GDBus.
</para>
- <para>
- Here is a sample XML file which describes an object that exposes
- one method, named <literal>ManyArgs</literal>.
-<programlisting>
-&lt;?xml version="1.0" encoding="UTF-8" ?&gt;
-
-&lt;node name="/com/example/MyObject"&gt;
- &lt;interface name="com.example.MyObject"&gt;
- &lt;annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object"/&gt;
- &lt;method name="ManyArgs"&gt;
- &lt;!-- This is optional, and in this case is redunundant --&gt;
- &lt;annotation name="org.freedesktop.DBus.GLib.CSymbol" value="my_object_many_args"/&gt;
- &lt;arg type="u" name="x" direction="in" /&gt;
- &lt;arg type="s" name="str" direction="in" /&gt;
- &lt;arg type="d" name="trouble" direction="in" /&gt;
- &lt;arg type="d" name="d_ret" direction="out" /&gt;
- &lt;arg type="s" name="str_ret" direction="out" /&gt;
- &lt;/method&gt;
- &lt;/interface&gt;
-&lt;/node&gt;
-</programlisting>
- </para>
<para>
- This XML is in the same format as the D-Bus introspection XML
- format. Except we must include an "annotation" which give the C
- symbols corresponding to the object implementation prefix
- (<literal>my_object</literal>). In addition, if particular
- methods symbol names deviate from C convention
- (i.e. <literal>ManyArgs</literal> -&gt;
- <literal>many_args</literal>), you may specify an annotation
- giving the C symbol.
+ An older API, dbus-glib, also exists. It is deprecated and should
+ not be used in new code. Whenever possible, porting existing code
+ from dbus-glib to GDBus is also recommended.
</para>
- <para>
- Once you have written this XML, run <literal>dbus-binding-tool --mode=glib-server <replaceable>FILENAME</replaceable> &gt; <replaceable>HEADER_NAME</replaceable>.</literal> to
- generate a header file. For example: <command>dbus-binding-tool --mode=glib-server my-object.xml &gt; my-object-glue.h</command>.
- </para>
- <para>
- Next, include the generated header in your program, and invoke
- <literal>dbus_g_object_class_install_info</literal> in the class
- initializer, passing the object class and "object info" included in the
- header. For example:
- <programlisting>
- dbus_g_object_type_install_info (COM_FOO_TYPE_MY_OBJECT, &amp;com_foo_my_object_info);
- </programlisting>
- This should be done exactly once per object class.
- </para>
- <para>
- To actually implement the method, just define a C function named e.g.
- <literal>my_object_many_args</literal> in the same file as the info
- header is included. At the moment, it is required that this function
- conform to the following rules:
- <itemizedlist>
- <listitem>
- <para>
- The function must return a value of type <literal>gboolean</literal>;
- <literal>TRUE</literal> on success, and <literal>FALSE</literal>
- otherwise.
- </para>
- </listitem>
- <listitem>
- <para>
- The first parameter is a pointer to an instance of the object.
- </para>
- </listitem>
- <listitem>
- <para>
- Following the object instance pointer are the method
- input values.
- </para>
- </listitem>
- <listitem>
- <para>
- Following the input values are pointers to return values.
- </para>
- </listitem>
- <listitem>
- <para>
- The final parameter must be a <literal>GError **</literal>.
- If the function returns <literal>FALSE</literal> for an
- error, the error parameter must be initalized with
- <literal>g_set_error</literal>.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- <para>
- Finally, you can export an object using <literal>dbus_g_connection_register_g_object</literal>. For example:
- <programlisting>
- dbus_g_connection_register_g_object (connection,
- "/com/foo/MyObject",
- obj);
- </programlisting>
- </para>
-
- <sect2 id="glib-annotations">
- <title>Server-side Annotations</title>
- <para>
- There are several annotations that are used when generating the
- server-side bindings. The most common annotation is
- <literal>org.freedesktop.DBus.GLib.CSymbol</literal> but there are other
- annotations which are often useful.
- <variablelist>
- <varlistentry>
- <term><literal>org.freedesktop.DBus.GLib.CSymbol</literal></term>
- <listitem>
- <para>
- This annotation is used to specify the C symbol names for
- the various types (interface, method, etc), if it differs from the
- name DBus generates.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>org.freedesktop.DBus.GLib.Async</literal></term>
- <listitem>
- <para>
- This annotation marks the method implementation as an
- asynchronous function, which doesn't return a response straight
- away but will send the response at some later point to complete
- the call. This is used to implement non-blocking services where
- method calls can take time.
- </para>
- <para>
- When a method is asynchronous, the function prototype is
- different. It is required that the function conform to the
- following rules:
- <itemizedlist>
- <listitem>
- <para>
- The function must return a value of type <literal>gboolean</literal>;
- <literal>TRUE</literal> on success, and <literal>FALSE</literal>
- otherwise. TODO: the return value is currently ignored.
- </para>
- </listitem>
- <listitem>
- <para>
- The first parameter is a pointer to an instance of the object.
- </para>
- </listitem>
- <listitem>
- <para>
- Following the object instance pointer are the method
- input values.
- </para>
- </listitem>
- <listitem>
- <para>
- The final parameter must be a
- <literal>DBusGMethodInvocation *</literal>. This is used
- when sending the response message back to the client, by
- calling <literal>dbus_g_method_return</literal> or
- <literal>dbus_g_method_return_error</literal>.
- </para>
- </listitem>
- </itemizedlist>
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>org.freedesktop.DBus.GLib.Const</literal></term>
- <listitem>
- <para>This attribute can only be applied to "out"
- <literal>&lt;arg&gt;</literal> nodes, and specifies that the
- parameter isn't being copied when returned. For example, this
- turns a 's' argument from a <literal>char **</literal> to a
- <literal>const char **</literal>, and results in the argument not
- being freed by DBus after the message is sent.
- </para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term><literal>org.freedesktop.DBus.GLib.ReturnVal</literal></term>
- <listitem>
- <para>
- This attribute can only be applied to "out"
- <literal>&lt;arg&gt;</literal> nodes, and alters the expected
- function signature. It currently can be set to two values:
- <literal>""</literal> or <literal>"error"</literal>. The
- argument marked with this attribute is not returned via a
- pointer argument, but by the function's return value. If the
- attribute's value is the empty string, the <literal>GError
- *</literal> argument is also omitted so there is no standard way
- to return an error value. This is very useful for interfacing
- with existing code, as it is possible to match existing APIs.
- If the attribute's value is <literal>"error"</literal>, then the
- final argument is a <literal>GError *</literal> as usual.
- </para>
- <para>
- Some examples to demonstrate the usage. This introspection XML:
- <programlisting>
-&lt;method name="Increment"&gt;
- &lt;arg type="u" name="x" /&gt;
- &lt;arg type="u" direction="out" /&gt;
-&lt;/method&gt;
- </programlisting>
- Expects the following function declaration:
- <programlisting>
-gboolean
-my_object_increment (MyObject *obj, gint32 x, gint32 *ret, GError **error);
- </programlisting>
- </para>
- <para>
- This introspection XML:
- <programlisting>
-&lt;method name="IncrementRetval"&gt;
- &lt;arg type="u" name="x" /&gt;
- &lt;arg type="u" direction="out" &gt;
- &lt;annotation name="org.freedesktop.DBus.GLib.ReturnVal" value=""/&gt;
- &lt;/arg&gt;
-&lt;/method&gt;
- </programlisting>
- Expects the following function declaration:
- <programlisting>
-gint32
-my_object_increment_retval (MyObject *obj, gint32 x)
- </programlisting>
- </para>
- <para>
- This introspection XML:
- <programlisting>
-&lt;method name="IncrementRetvalError"&gt;
- &lt;arg type="u" name="x" /&gt;
- &lt;arg type="u" direction="out" &gt;
- &lt;annotation name="org.freedesktop.DBus.GLib.ReturnVal" value="error"/&gt;
- &lt;/arg&gt;
-&lt;/method&gt;
- </programlisting>
- Expects the following function declaration:
- <programlisting>
-gint32
-my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error)
- </programlisting>
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </para>
- </sect2>
</sect1>
<sect1 id="python-client">
@@ -1650,18 +730,12 @@ my_object_increment_retval_error (MyObject *obj, gint32 x, GError **error)
</sect1>
<sect1 id="qt-client">
- <title>Qt API: Using Remote Objects</title>
- <para>
-
- The Qt bindings are not yet documented.
-
- </para>
- </sect1>
-
- <sect1 id="qt-server">
- <title>Qt API: Implementing Objects</title>
+ <title>Qt API</title>
<para>
- The Qt bindings are not yet documented.
+ The Qt binding for libdbus, QtDBus, has been distributed with Qt
+ since version 4.2. It is not documented here. See
+ <ulink url="http://qt-project.org/doc/qt-5/qtdbus-index.html">the Qt
+ documentation</ulink> for details of how to use QtDBus.
</para>
</sect1>
</article>
diff --git a/ltmain.sh b/ltmain.sh
index 3fd54dfa..bffda541 100644
--- a/ltmain.sh
+++ b/ltmain.sh
@@ -70,7 +70,7 @@
# compiler: $LTCC
# compiler flags: $LTCFLAGS
# linker: $LD (gnu? $with_gnu_ld)
-# $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.10
+# $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.11
# automake: $automake_version
# autoconf: $autoconf_version
#
@@ -80,7 +80,7 @@
PROGRAM=libtool
PACKAGE=libtool
-VERSION="2.4.2 Debian-2.4.2-1.10"
+VERSION="2.4.2 Debian-2.4.2-1.11"
TIMESTAMP=""
package_revision=1.3337
diff --git a/test/Makefile.am b/test/Makefile.am
index 1ceb5b68..173df74b 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -254,6 +254,7 @@ in_data = \
data/valid-config-files-system/debug-allow-all-pass.conf.in \
data/valid-config-files/debug-allow-all-sha1.conf.in \
data/valid-config-files/debug-allow-all.conf.in \
+ data/valid-config-files/finite-timeout.conf.in \
data/valid-config-files/incoming-limit.conf.in \
data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service.in \
data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in \
diff --git a/test/Makefile.in b/test/Makefile.in
index 46b8c095..4a5a343c 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -746,6 +746,7 @@ build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
+dbus_daemondir = @dbus_daemondir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
@@ -947,6 +948,7 @@ in_data = \
data/valid-config-files-system/debug-allow-all-pass.conf.in \
data/valid-config-files/debug-allow-all-sha1.conf.in \
data/valid-config-files/debug-allow-all.conf.in \
+ data/valid-config-files/finite-timeout.conf.in \
data/valid-config-files/incoming-limit.conf.in \
data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service.in \
data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in \
diff --git a/test/data/valid-config-files/finite-timeout.conf.in b/test/data/valid-config-files/finite-timeout.conf.in
new file mode 100644
index 00000000..7d26d715
--- /dev/null
+++ b/test/data/valid-config-files/finite-timeout.conf.in
@@ -0,0 +1,19 @@
+<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <!-- Our well-known bus type, don't change this -->
+ <type>session</type>
+ <listen>@TEST_LISTEN@</listen>
+
+ <policy context="default">
+ <!-- Allow everything to be sent -->
+ <allow send_destination="*" eavesdrop="true"/>
+ <!-- Allow everything to be received -->
+ <allow eavesdrop="true"/>
+ <!-- Allow anyone to own anything -->
+ <allow own="*"/>
+ </policy>
+
+ <!-- Forcibly time out method calls after 100ms -->
+ <limit name="reply_timeout">100</limit>
+</busconfig>
diff --git a/test/dbus-daemon.c b/test/dbus-daemon.c
index 4b3b61e5..bb1d1374 100644
--- a/test/dbus-daemon.c
+++ b/test/dbus-daemon.c
@@ -43,6 +43,31 @@
#include "test-utils.h"
+/* Platforms where we know that credentials-passing passes both the
+ * uid and the pid. Please keep these in alphabetical order.
+ *
+ * These platforms should #error in _dbus_read_credentials_socket()
+ * if we didn't detect their flavour of credentials-passing, since that
+ * would be a regression.
+ */
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || \
+ defined(__linux__) || \
+ defined(__NetBSD__) || \
+ defined(__OpenBSD__)
+# define UNIX_USER_SHOULD_WORK
+# define PID_SHOULD_WORK
+#endif
+
+/* Platforms where we know that credentials-passing passes the
+ * uid, but not necessarily the pid. Again, alphabetical order please.
+ *
+ * These platforms should also #error in _dbus_read_credentials_socket()
+ * if we didn't detect their flavour of credentials-passing.
+ */
+#if 0 /* defined(__your_platform_here__) */
+# define UNIX_USER_SHOULD_WORK
+#endif
+
typedef struct {
gboolean skip;
@@ -57,6 +82,7 @@ typedef struct {
DBusConnection *right_conn;
gboolean right_conn_echo;
+ gboolean wait_forever_called;
} Fixture;
#define assert_no_error(e) _assert_no_error (e, __FILE__, __LINE__)
@@ -157,11 +183,19 @@ echo_filter (DBusConnection *connection,
DBusMessage *message,
void *user_data)
{
+ Fixture *f = user_data;
DBusMessage *reply;
if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ /* WaitForever() never replies, emulating a service that has got stuck */
+ if (dbus_message_is_method_call (message, "com.example", "WaitForever"))
+ {
+ f->wait_forever_called = TRUE;
+ return DBUS_HANDLER_RESULT_HANDLED;
+ }
+
reply = dbus_message_new_method_return (message);
if (reply == NULL)
@@ -257,7 +291,7 @@ setup (Fixture *f,
static void
add_echo_filter (Fixture *f)
{
- if (!dbus_connection_add_filter (f->right_conn, echo_filter, NULL, NULL))
+ if (!dbus_connection_add_filter (f->right_conn, echo_filter, f, NULL))
g_error ("OOM");
f->right_conn_echo = TRUE;
@@ -343,6 +377,80 @@ pending_call_store_reply (DBusPendingCall *pc,
}
static void
+test_no_reply (Fixture *f,
+ gconstpointer context)
+{
+ const Config *config = context;
+ DBusMessage *m;
+ DBusPendingCall *pc;
+ DBusMessage *reply = NULL;
+ enum { TIMEOUT, DISCONNECT } mode;
+ gboolean ok;
+
+ if (f->skip)
+ return;
+
+ g_test_bug ("76112");
+
+ if (config != NULL && config->config_file != NULL)
+ mode = TIMEOUT;
+ else
+ mode = DISCONNECT;
+
+ m = dbus_message_new_method_call (
+ dbus_bus_get_unique_name (f->right_conn), "/",
+ "com.example", "WaitForever");
+
+ add_echo_filter (f);
+
+ 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))
+ pending_call_store_reply (pc, &reply);
+ else if (!dbus_pending_call_set_notify (pc, pending_call_store_reply, &reply,
+ NULL))
+ g_error ("OOM");
+
+ dbus_pending_call_unref (pc);
+ dbus_message_unref (m);
+
+ if (mode == DISCONNECT)
+ {
+ while (!f->wait_forever_called)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ dbus_connection_remove_filter (f->right_conn, echo_filter, f);
+ dbus_connection_close (f->right_conn);
+ dbus_connection_unref (f->right_conn);
+ f->right_conn = NULL;
+ }
+
+ while (reply == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ /* using inefficient string comparison for better assertion message */
+ g_assert_cmpstr (
+ dbus_message_type_to_string (dbus_message_get_type (reply)), ==,
+ dbus_message_type_to_string (DBUS_MESSAGE_TYPE_ERROR));
+ ok = dbus_set_error_from_message (&f->e, reply);
+ g_assert (ok);
+ g_assert_cmpstr (f->e.name, ==, DBUS_ERROR_NO_REPLY);
+
+ if (mode == DISCONNECT)
+ g_assert_cmpstr (f->e.message, ==,
+ "Message recipient disconnected from message bus without replying");
+ else
+ g_assert_cmpstr (f->e.message, ==,
+ "Message did not receive a reply (timeout by message bus)");
+}
+
+static void
test_creds (Fixture *f,
gconstpointer context)
{
@@ -445,8 +553,11 @@ test_creds (Fixture *f,
dbus_message_iter_next (&arr_iter);
}
-#ifdef G_OS_UNIX
+#ifdef UNIX_USER_SHOULD_WORK
g_assert (seen & SEEN_UNIX_USER);
+#endif
+
+#ifdef PID_SHOULD_WORK
g_assert (seen & SEEN_PID);
#endif
@@ -458,6 +569,72 @@ test_creds (Fixture *f,
}
static void
+test_processid (Fixture *f,
+ gconstpointer context)
+{
+ const char *unique = dbus_bus_get_unique_name (f->left_conn);
+ DBusMessage *m = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetConnectionUnixProcessID");
+ DBusPendingCall *pc;
+ DBusError error = DBUS_ERROR_INIT;
+ guint32 pid;
+
+ if (m == NULL)
+ g_error ("OOM");
+
+ if (!dbus_message_append_args (m,
+ DBUS_TYPE_STRING, &unique,
+ DBUS_TYPE_INVALID))
+ g_error ("OOM");
+
+ if (!dbus_connection_send_with_reply (f->left_conn, m, &pc,
+ DBUS_TIMEOUT_USE_DEFAULT) ||
+ pc == NULL)
+ g_error ("OOM");
+
+ dbus_message_unref (m);
+ m = NULL;
+
+ if (dbus_pending_call_get_completed (pc))
+ pending_call_store_reply (pc, &m);
+ else if (!dbus_pending_call_set_notify (pc, pending_call_store_reply,
+ &m, NULL))
+ g_error ("OOM");
+
+ while (m == NULL)
+ test_main_context_iterate (f->ctx, TRUE);
+
+ if (dbus_message_get_args (m, &error,
+ DBUS_TYPE_UINT32, &pid,
+ DBUS_TYPE_INVALID))
+ {
+ g_assert_cmpstr (dbus_message_get_signature (m), ==, "u");
+ assert_no_error (&error);
+
+ g_message ("GetConnectionUnixProcessID returned %u", pid);
+
+#ifdef G_OS_UNIX
+ g_assert_cmpuint (pid, ==, getpid ());
+#elif defined(G_OS_WIN32)
+ g_assert_cmpuint (pid, ==, GetCurrentProcessId ());
+#else
+ g_assert_not_reached ();
+#endif
+ }
+ else
+ {
+ g_assert_cmpstr (error.name, ==, DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN);
+
+#ifdef PID_SHOULD_WORK
+ g_error ("Expected pid to be passed, but got %s: %s",
+ error.name, error.message);
+#endif
+
+ dbus_error_free (&error);
+ }
+}
+
+static void
teardown (Fixture *f,
gconstpointer context G_GNUC_UNUSED)
{
@@ -475,7 +652,7 @@ teardown (Fixture *f,
{
if (f->right_conn_echo)
{
- dbus_connection_remove_filter (f->right_conn, echo_filter, NULL);
+ dbus_connection_remove_filter (f->right_conn, echo_filter, f);
f->right_conn_echo = FALSE;
}
@@ -503,6 +680,10 @@ static Config limited_config = {
"34393", 10000, "valid-config-files/incoming-limit.conf"
};
+static Config finite_timeout_config = {
+ NULL, 1, "valid-config-files/finite-timeout.conf"
+};
+
int
main (int argc,
char **argv)
@@ -513,7 +694,12 @@ main (int argc,
g_test_add ("/echo/session", Fixture, NULL, setup, test_echo, teardown);
g_test_add ("/echo/limited", Fixture, &limited_config,
setup, test_echo, teardown);
+ g_test_add ("/no-reply/disconnect", Fixture, NULL,
+ setup, test_no_reply, teardown);
+ g_test_add ("/no-reply/timeout", Fixture, &finite_timeout_config,
+ setup, test_no_reply, teardown);
g_test_add ("/creds", Fixture, NULL, setup, test_creds, teardown);
+ g_test_add ("/processid", Fixture, NULL, setup, test_processid, teardown);
return g_test_run ();
}
diff --git a/test/name-test/Makefile.in b/test/name-test/Makefile.in
index 466bd54d..392cf8ba 100644
--- a/test/name-test/Makefile.in
+++ b/test/name-test/Makefile.in
@@ -574,6 +574,7 @@ build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
+dbus_daemondir = @dbus_daemondir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
diff --git a/test/name-test/test-threads-init.c b/test/name-test/test-threads-init.c
index 580ffe14..a517e2a2 100644
--- a/test/name-test/test-threads-init.c
+++ b/test/name-test/test-threads-init.c
@@ -149,16 +149,6 @@ main (int argc, char *argv[])
&dispatch_cond1,
&io_path_cond1);
- /* Since 1.7 it is no longer the case that mutex1 != mutex2, because
- * initializing global locks automatically initializes locks
- * in general. However, it is true that the mutex is not the dummy
- * implementation, which is what we really wanted to check here. */
- _dbus_assert (mutex1 != (DBusMutex *) 0xABCDEF);
- _dbus_assert (dispatch_mutex1 != (DBusMutex *) 0xABCDEF);
- _dbus_assert (dispatch_cond1 != (DBusCondVar *) 0xABCDEF2);
- _dbus_assert (io_path_mutex1 != (DBusMutex *) 0xABCDEF);
- _dbus_assert (io_path_cond1 != (DBusCondVar *) 0xABCDEF2);
-
_run_iteration (conn);
_dbus_connection_test_get_locks (conn, &mutex2,
&dispatch_mutex2,
diff --git a/tools/GetAllMatchRules.py b/tools/GetAllMatchRules.py
new file mode 100755
index 00000000..6a7e4cd9
--- /dev/null
+++ b/tools/GetAllMatchRules.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python
+
+import sys
+import argparse
+import dbus
+import time
+
+def get_cmdline(pid):
+ cmdline = ''
+ if pid > 0:
+ try:
+ procpath = '/proc/' + str(pid) + '/cmdline'
+ with open(procpath, 'r') as f:
+ cmdline = " ".join(f.readline().split('\0'))
+ except:
+ pass
+ return cmdline
+
+# Parsing parameters
+
+parser = argparse.ArgumentParser(description='Testing D-Bus match rules')
+parser.add_argument('--session', help='session bus', action="store_true")
+parser.add_argument('--system', help='system bus', action="store_true")
+parser.add_argument('--all', help='print all match rules', action="store_true")
+args = parser.parse_args()
+
+if args.system and args.session:
+ parser.print_help()
+ sys.exit(1)
+
+# Fetch data from the bus driver
+
+if args.system:
+ bus = dbus.SystemBus()
+else:
+ bus = dbus.SessionBus()
+
+remote_object = bus.get_object("org.freedesktop.DBus",
+ "/org/freedesktop/DBus")
+bus_iface = dbus.Interface(remote_object, "org.freedesktop.DBus")
+stats_iface = dbus.Interface(remote_object, "org.freedesktop.DBus.Debug.Stats")
+
+try:
+ match_rules = stats_iface.GetAllMatchRules()
+except:
+ print("GetConnectionMatchRules failed: did you enable the Stats interface?")
+ sys.exit(1)
+
+names = bus_iface.ListNames()
+unique_names = [ a for a in names if a.startswith(":") ]
+pids = dict((name, bus_iface.GetConnectionUnixProcessID(name)) for name in unique_names)
+cmds = dict((name, get_cmdline(pids[name])) for name in unique_names)
+well_known_names = [ a for a in names if a not in unique_names ]
+owners = dict((wkn, bus_iface.GetNameOwner(wkn)) for wkn in well_known_names)
+
+rules = dict((k_rules,
+ dict({
+ 'wkn': [k for k, v in owners.items() if v == k_rules],
+ 'pid': pids[k_rules],
+ 'cmd': cmds[k_rules] or "",
+ 'rules': v_rules,
+ 'warnings': dict({
+ 'not_signal': [a for a in v_rules if "type='signal'" not in a],
+ 'no_sender': [a for a in v_rules if "sender=" not in a],
+ 'local': [a for a in v_rules if "org.freedesktop.DBus.Local" in a],
+ 'NameOwnerChanged_arg0': [a for a in v_rules if "member='NameOwnerChanged'" in a and "arg0" not in a]
+ })
+ })
+ ) for k_rules, v_rules in match_rules.items())
+
+warnings = dict({
+ 'not_signal': 'Match rule without selecting signals',
+ 'no_sender': 'Match rule without a sender criteria',
+ 'local': 'Match rule on the org.freedesktop.DBus.Local interface',
+ 'NameOwnerChanged_arg0': 'Match rule on NameOwnerChanged without a arg0* criteria'
+ })
+
+# Print the match rules
+
+# print all match rules without analysing them
+if args.all:
+ for name in rules:
+ print("Connection %s with pid %d '%s' (%s): %d match rules, %d warnings"
+ % (name, rules[name]['pid'], rules[name]['cmd'],
+ ' '.join(rules[name]['wkn']), len(rules[name]['rules']),
+ len(sum(rules[name]['warnings'].values(), []))))
+ for rule in rules[name]['rules']:
+ print("\t%s" % (rule))
+ print("")
+ sys.exit(0)
+
+# analyse match rules and print only the suspicious ones
+for conn,data in rules.items():
+ warnings_count = len(sum(data['warnings'].values(), []))
+ if warnings_count == 0:
+ continue
+
+ print("Connection %s with pid %d '%s' (%s): %d match rules, %d warnings"
+ % (conn, data['pid'], data['cmd'], ' '.join(data['wkn']),
+ len(data['rules']), warnings_count))
+
+ for warn_code,rule_list in [(warn_code,rule_list) \
+ for warn_code, rule_list \
+ in data['warnings'].items() \
+ if len(rule_list) > 0]:
+ print(" - %s:" % (warnings[warn_code]))
+ for rule in rule_list:
+ print(" - %s" % (rule))
+
+ print("")
+
+sys.exit(0)
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 73d95fcf..05d1dcb5 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -15,6 +15,7 @@ bin_PROGRAMS = \
dbus-launch \
dbus-monitor \
dbus-send \
+ dbus-test-tool \
$(NULL)
if DBUS_UNIX
@@ -76,6 +77,21 @@ dbus_launch_LDADD = \
$(DBUS_X_LIBS) \
$(NULL)
+examplesdir = ${docdir}/examples
+dist_examples_SCRIPTS = \
+ GetAllMatchRules.py \
+ $(NULL)
+
+dbus_test_tool_SOURCES = \
+ dbus-echo.c \
+ dbus-spam.c \
+ tool-common.c \
+ tool-common.h \
+ test-tool.c \
+ test-tool.h \
+ $(NULL)
+dbus_test_tool_LDADD = $(top_builddir)/dbus/libdbus-1.la
+
EXTRA_DIST = run-with-tmp-session-bus.sh strtoll.c strtoull.c
CLEANFILES = \
run-with-tmp-session-bus.conf
diff --git a/tools/Makefile.in b/tools/Makefile.in
index dd562f10..9105bd4d 100644
--- a/tools/Makefile.in
+++ b/tools/Makefile.in
@@ -14,6 +14,7 @@
@SET_MAKE@
+
VPATH = @srcdir@
am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
am__make_running_with_option = \
@@ -79,7 +80,7 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
bin_PROGRAMS = dbus-launch$(EXEEXT) dbus-monitor$(EXEEXT) \
- dbus-send$(EXEEXT) $(am__EXEEXT_1)
+ dbus-send$(EXEEXT) dbus-test-tool$(EXEEXT) $(am__EXEEXT_1)
@DBUS_UNIX_TRUE@am__append_1 = \
@DBUS_UNIX_TRUE@ dbus-cleanup-sockets \
@DBUS_UNIX_TRUE@ dbus-run-session \
@@ -88,7 +89,7 @@ bin_PROGRAMS = dbus-launch$(EXEEXT) dbus-monitor$(EXEEXT) \
subdir = tools
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
- $(top_srcdir)/depcomp
+ $(dist_examples_SCRIPTS) $(top_srcdir)/depcomp
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \
$(top_srcdir)/m4/compiler.m4 $(top_srcdir)/m4/libtool.m4 \
@@ -106,7 +107,7 @@ CONFIG_CLEAN_VPATH_FILES =
@DBUS_UNIX_TRUE@am__EXEEXT_1 = dbus-cleanup-sockets$(EXEEXT) \
@DBUS_UNIX_TRUE@ dbus-run-session$(EXEEXT) \
@DBUS_UNIX_TRUE@ dbus-uuidgen$(EXEEXT)
-am__installdirs = "$(DESTDIR)$(bindir)"
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(examplesdir)"
PROGRAMS = $(bin_PROGRAMS)
am_dbus_cleanup_sockets_OBJECTS = dbus-cleanup-sockets.$(OBJEXT)
dbus_cleanup_sockets_OBJECTS = $(am_dbus_cleanup_sockets_OBJECTS)
@@ -138,9 +139,41 @@ am_dbus_send_OBJECTS = dbus-print-message.$(OBJEXT) \
dbus-send.$(OBJEXT)
dbus_send_OBJECTS = $(am_dbus_send_OBJECTS)
dbus_send_DEPENDENCIES = $(top_builddir)/dbus/libdbus-1.la
+am_dbus_test_tool_OBJECTS = dbus-echo.$(OBJEXT) dbus-spam.$(OBJEXT) \
+ tool-common.$(OBJEXT) test-tool.$(OBJEXT)
+dbus_test_tool_OBJECTS = $(am_dbus_test_tool_OBJECTS)
+dbus_test_tool_DEPENDENCIES = $(top_builddir)/dbus/libdbus-1.la
am_dbus_uuidgen_OBJECTS = dbus-uuidgen.$(OBJEXT)
dbus_uuidgen_OBJECTS = $(am_dbus_uuidgen_OBJECTS)
dbus_uuidgen_DEPENDENCIES = $(top_builddir)/dbus/libdbus-1.la
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+SCRIPTS = $(dist_examples_SCRIPTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
@@ -177,11 +210,12 @@ am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(dbus_cleanup_sockets_SOURCES) $(dbus_launch_SOURCES) \
$(dbus_monitor_SOURCES) $(dbus_run_session_SOURCES) \
- $(dbus_send_SOURCES) $(dbus_uuidgen_SOURCES)
+ $(dbus_send_SOURCES) $(dbus_test_tool_SOURCES) \
+ $(dbus_uuidgen_SOURCES)
DIST_SOURCES = $(dbus_cleanup_sockets_SOURCES) \
$(am__dbus_launch_SOURCES_DIST) $(dbus_monitor_SOURCES) \
$(am__dbus_run_session_SOURCES_DIST) $(dbus_send_SOURCES) \
- $(dbus_uuidgen_SOURCES)
+ $(dbus_test_tool_SOURCES) $(dbus_uuidgen_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
@@ -375,6 +409,7 @@ build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
+dbus_daemondir = @dbus_daemondir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
@@ -472,6 +507,21 @@ dbus_launch_LDADD = \
$(DBUS_X_LIBS) \
$(NULL)
+examplesdir = ${docdir}/examples
+dist_examples_SCRIPTS = \
+ GetAllMatchRules.py \
+ $(NULL)
+
+dbus_test_tool_SOURCES = \
+ dbus-echo.c \
+ dbus-spam.c \
+ tool-common.c \
+ tool-common.h \
+ test-tool.c \
+ test-tool.h \
+ $(NULL)
+
+dbus_test_tool_LDADD = $(top_builddir)/dbus/libdbus-1.la
EXTRA_DIST = run-with-tmp-session-bus.sh strtoll.c strtoull.c
CLEANFILES = \
run-with-tmp-session-bus.conf
@@ -580,9 +630,48 @@ dbus-send$(EXEEXT): $(dbus_send_OBJECTS) $(dbus_send_DEPENDENCIES) $(EXTRA_dbus_
@rm -f dbus-send$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(dbus_send_OBJECTS) $(dbus_send_LDADD) $(LIBS)
+dbus-test-tool$(EXEEXT): $(dbus_test_tool_OBJECTS) $(dbus_test_tool_DEPENDENCIES) $(EXTRA_dbus_test_tool_DEPENDENCIES)
+ @rm -f dbus-test-tool$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(dbus_test_tool_OBJECTS) $(dbus_test_tool_LDADD) $(LIBS)
+
dbus-uuidgen$(EXEEXT): $(dbus_uuidgen_OBJECTS) $(dbus_uuidgen_DEPENDENCIES) $(EXTRA_dbus_uuidgen_DEPENDENCIES)
@rm -f dbus-uuidgen$(EXEEXT)
$(AM_V_CCLD)$(LINK) $(dbus_uuidgen_OBJECTS) $(dbus_uuidgen_LDADD) $(LIBS)
+install-dist_examplesSCRIPTS: $(dist_examples_SCRIPTS)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_examples_SCRIPTS)'; test -n "$(examplesdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(examplesdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(examplesdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n' \
+ -e 'h;s|.*|.|' \
+ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+ if (++n[d] == $(am__install_max)) { \
+ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+ else { print "f", d "/" $$4, $$1 } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(examplesdir)$$dir'"; \
+ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(examplesdir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-dist_examplesSCRIPTS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_examples_SCRIPTS)'; test -n "$(examplesdir)" || exit 0; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 's,.*/,,;$(transform)'`; \
+ dir='$(DESTDIR)$(examplesdir)'; $(am__uninstall_files_from_dir)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -591,6 +680,7 @@ distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-cleanup-sockets.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-echo.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-launch-win.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-launch-x11.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-launch.Po@am__quote@
@@ -598,7 +688,10 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-print-message.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-run-session.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-send.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-spam.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbus-uuidgen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-tool.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tool-common.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@@ -711,9 +804,9 @@ distdir: $(DISTFILES)
done
check-am: all-am
check: check-am
-all-am: Makefile $(PROGRAMS)
+all-am: Makefile $(PROGRAMS) $(SCRIPTS)
installdirs:
- for dir in "$(DESTDIR)$(bindir)"; do \
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(examplesdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
@@ -769,7 +862,7 @@ info: info-am
info-am:
-install-data-am: install-data-local
+install-data-am: install-data-local install-dist_examplesSCRIPTS
install-dvi: install-dvi-am
@@ -815,7 +908,7 @@ ps: ps-am
ps-am:
-uninstall-am: uninstall-binPROGRAMS
+uninstall-am: uninstall-binPROGRAMS uninstall-dist_examplesSCRIPTS
.MAKE: install-am install-strip
@@ -824,15 +917,16 @@ uninstall-am: uninstall-binPROGRAMS
ctags ctags-am distclean distclean-compile distclean-generic \
distclean-libtool distclean-tags distdir dvi dvi-am html \
html-am info info-am install install-am install-binPROGRAMS \
- install-data install-data-am install-data-local install-dvi \
- install-dvi-am install-exec install-exec-am install-html \
- install-html-am install-info install-info-am install-man \
- install-pdf install-pdf-am install-ps install-ps-am \
- install-strip installcheck installcheck-am installcheck-local \
- installdirs maintainer-clean maintainer-clean-generic \
- mostlyclean mostlyclean-compile mostlyclean-generic \
- mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
- uninstall-am uninstall-binPROGRAMS
+ install-data install-data-am install-data-local \
+ install-dist_examplesSCRIPTS install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installcheck-local installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-binPROGRAMS uninstall-dist_examplesSCRIPTS
# create the /var/lib/dbus directory for dbus-uuidgen
diff --git a/tools/dbus-echo.c b/tools/dbus-echo.c
new file mode 100644
index 00000000..72973cdb
--- /dev/null
+++ b/tools/dbus-echo.c
@@ -0,0 +1,243 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-echo.c - a plain libdbus echo server
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <dbus/dbus.h>
+
+#include "test-tool.h"
+#include "tool-common.h"
+
+static int sleep_ms = -1;
+static dbus_bool_t noreply = FALSE;
+static dbus_bool_t noread = FALSE;
+
+static void
+usage_echo (int exit_with)
+{
+ fprintf (stderr,
+ "Usage: dbus-test-tool echo [OPTIONS]\n"
+ "\n"
+ "Respond to all method calls with an empty reply.\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " --name=NAME claim this well-known name first\n"
+ "\n"
+ " --sleep=N sleep N milliseconds before sending each reply\n"
+ "\n"
+ " --session use the session bus (default)\n"
+ " --system use the system bus\n"
+ );
+ exit (exit_with);
+}
+
+static void
+usage_black_hole (int exit_with)
+{
+ fprintf (stderr,
+ "Usage: dbus-test-tool black-hole [OPTIONS]\n"
+ "\n"
+ "Receive method calls but do not reply.\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " --name=NAME claim this well-known name first\n"
+ "\n"
+ " --no-read don't read anything on the D-Bus socket\n"
+ "\n"
+ " --session use the session bus (default)\n"
+ " --system use the system bus\n"
+ );
+ exit (exit_with);
+}
+
+static DBusHandlerResult
+filter (DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ DBusMessage *reply;
+
+ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (sleep_ms > 0)
+ {
+ tool_millisleep (sleep_ms);
+ }
+
+ if (!noreply)
+ {
+ reply = dbus_message_new_method_return (message);
+
+ if (reply == NULL)
+ tool_oom ("allocating reply");
+
+ if (!dbus_connection_send (connection, reply, NULL))
+ tool_oom ("sending reply");
+
+ dbus_message_unref (reply);
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusConnection *
+init_connection (DBusBusType type, const char *name)
+{
+ DBusConnection *connection;
+ DBusError error = DBUS_ERROR_INIT;
+
+ connection = dbus_bus_get (type, &error);
+
+ if (connection == NULL)
+ {
+ fprintf (stderr, "Failed to connect to bus: %s: %s\n",
+ error.name, error.message);
+ dbus_error_free (&error);
+ exit (1);
+ }
+
+ if (name != NULL)
+ {
+ if (dbus_bus_request_name (connection, name, DBUS_NAME_FLAG_DO_NOT_QUEUE,
+ NULL) != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+ {
+ fprintf (stderr, "failed to take bus name %s\n", name);
+ exit (1);
+ }
+ }
+ else
+ {
+ printf ("%s\n", dbus_bus_get_unique_name (connection));
+ }
+
+ if (!dbus_connection_add_filter (connection, filter, NULL, NULL))
+ tool_oom ("adding message filter");
+
+ return connection;
+}
+
+int
+dbus_test_tool_echo (int argc, char **argv)
+{
+ DBusConnection *connection;
+ DBusBusType type = DBUS_BUS_SESSION;
+ int i;
+ const char *name = NULL;
+
+ /* argv[1] is the tool name, so start from 2 */
+
+ for (i = 2; i < argc; i++)
+ {
+ const char *arg = argv[i];
+
+ if (strcmp (arg, "--system") == 0)
+ {
+ type = DBUS_BUS_SYSTEM;
+ }
+ else if (strcmp (arg, "--session") == 0)
+ {
+ type = DBUS_BUS_SESSION;
+ }
+ else if (strstr (arg, "--name=") == arg)
+ {
+ name = arg + strlen ("--name=");
+ }
+ else if (strstr (arg, "--sleep-ms=") == arg)
+ {
+ sleep_ms = atoi (arg + strlen ("--sleep-ms="));
+ }
+ else
+ {
+ usage_echo (2);
+ }
+ }
+
+ connection = init_connection (type, name);
+
+ while (dbus_connection_read_write_dispatch (connection, -1))
+ {}
+
+ dbus_connection_unref (connection);
+ return 0;
+}
+
+int
+dbus_test_tool_black_hole (int argc, char **argv)
+{
+ DBusConnection *connection;
+ DBusBusType type = DBUS_BUS_SESSION;
+ int i;
+ const char *name = NULL;
+
+ /* argv[1] is the tool name, so start from 2 */
+
+ for (i = 2; i < argc; i++)
+ {
+ const char *arg = argv[i];
+
+ if (strcmp (arg, "--system") == 0)
+ {
+ type = DBUS_BUS_SYSTEM;
+ }
+ else if (strcmp (arg, "--session") == 0)
+ {
+ type = DBUS_BUS_SESSION;
+ }
+ else if (strstr (arg, "--name=") == arg)
+ {
+ name = arg + strlen ("--name=");
+ }
+ else if (strcmp (arg, "--no-read") == 0)
+ {
+ noread = TRUE;
+ }
+ else
+ {
+ usage_black_hole (2);
+ }
+ }
+
+ connection = init_connection (type, name);
+
+ if (noread)
+ {
+ while (1)
+ sleep (3600);
+ }
+
+ noreply = TRUE;
+
+ while (dbus_connection_read_write_dispatch (connection, -1))
+ {}
+
+ dbus_connection_unref (connection);
+ return 0;
+}
diff --git a/tools/dbus-spam.c b/tools/dbus-spam.c
new file mode 100644
index 00000000..ce918754
--- /dev/null
+++ b/tools/dbus-spam.c
@@ -0,0 +1,521 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-spam.c - a plain libdbus message-sender, loosely based on dbus-send
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * 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 <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <dbus/dbus.h>
+
+#include "test-tool.h"
+#include "tool-common.h"
+
+static dbus_bool_t ignore_errors = FALSE;
+
+static void
+usage (int ecode)
+{
+ fprintf (stderr,
+ "Usage: dbus-test-tool spam [OPTIONS]\n"
+ "\n"
+ "Repeatedly call com.example.Spam() on the given D-Bus service.\n"
+ "\n"
+ "Options:\n"
+ "\n"
+ " --session use the session bus (default)\n"
+ " --system use the system bus\n"
+ "\n"
+ " --ignore-errors ignore errors\n"
+ " --dest=NAME call methods on NAME (default " DBUS_SERVICE_DBUS ")\n"
+ "\n"
+ " --count=N send N messages (default 1)\n"
+ " --queue=N queue up N messages at a time (default 1)\n"
+ " --flood send all messages immediately\n"
+ " --no-reply set the NO_REPLY flag (implies --flood)\n"
+ " --messages-per-conn=N after sending messages-per-conn, wait\n"
+ " for the pending replies if any, then reconnect\n"
+ " (default: don't reconnect)\n"
+ "\n"
+ " --string send payload as a string (default)\n"
+ " --bytes send payload as a byte-array\n"
+ " --empty send an empty payload\n"
+ "\n"
+ " --payload=S use S as payload (default \"hello, world!\")\n"
+ " --stdin read payload from stdin, until EOF\n"
+ " --message-stdin read a complete D-Bus message from stdin\n"
+ " --random-size read whitespace-separated ASCII decimal\n"
+ " payload sizes from stdin and pick one randomly\n"
+ " for each message\n"
+ "\n"
+ " --seed=SEED seed for srand (default is time())\n"
+ "\n"
+ );
+ exit (ecode);
+}
+
+static void
+pc_notify (DBusPendingCall *pc,
+ void *data)
+{
+ DBusMessage *message;
+ int *received_p = data;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ message = dbus_pending_call_steal_reply (pc);
+
+ if (!ignore_errors && dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_ERROR)
+ {
+ dbus_set_error_from_message (&error, message);
+ fprintf (stderr, "Failed to receive reply #%d: %s: %s\n", *received_p,
+ error.name, error.message);
+ }
+ else
+ {
+ VERBOSE (stderr, "received message #%d\n", *received_p);
+ }
+
+ (*received_p)++;
+}
+
+static void
+consume_stdin (char **payload_p,
+ size_t *len_p)
+{
+ const size_t BLOCK_SIZE = 4096;
+ size_t len = BLOCK_SIZE;
+ size_t pos = 0;
+ size_t n;
+ char *buf;
+
+ buf = dbus_malloc (len);
+
+ if (buf == NULL)
+ tool_oom ("reading payload from stdin");
+
+ while (1)
+ {
+ if (len - pos < BLOCK_SIZE)
+ {
+ char *tmp = dbus_realloc (buf, len + BLOCK_SIZE);
+
+ if (tmp == NULL)
+ tool_oom ("reading payload from stdin");
+
+ buf = tmp;
+ len += BLOCK_SIZE;
+ }
+
+ n = fread (buf + pos, 1, len - pos, stdin);
+
+ if (n <= 0)
+ {
+ /* EOF or error - treat as EOF */
+ break;
+ }
+
+ pos += n;
+ }
+
+ *len_p = pos;
+ *payload_p = buf;
+}
+
+int
+dbus_test_tool_spam (int argc, char **argv)
+{
+ DBusConnection *connection = NULL;
+ DBusError error = DBUS_ERROR_INIT;
+ DBusBusType type = DBUS_BUS_SESSION;
+ const char *destination = DBUS_SERVICE_DBUS;
+ int i;
+ int count = 1;
+ int sent = 0;
+ int sent_in_this_conn = 0;
+ int received = 0;
+ int received_before_this_conn = 0;
+ int queue_len = 1;
+ const char *payload = NULL;
+ char *payload_buf = NULL;
+ size_t payload_len;
+ int payload_type = DBUS_TYPE_STRING;
+ DBusMessage *template = NULL;
+ dbus_bool_t flood = FALSE;
+ dbus_bool_t no_reply = FALSE;
+ unsigned int messages_per_conn = 0;
+ unsigned int seed = time (NULL);
+ int n_random_sizes = 0;
+ unsigned int *random_sizes = NULL;
+
+ /* argv[1] is the tool name, so start from 2 */
+
+ for (i = 2; i < argc; i++)
+ {
+ const char *arg = argv[i];
+
+ if (strcmp (arg, "--system") == 0)
+ {
+ type = DBUS_BUS_SYSTEM;
+ }
+ else if (strcmp (arg, "--session") == 0)
+ {
+ type = DBUS_BUS_SESSION;
+ }
+ else if (strstr (arg, "--count=") == arg)
+ {
+ count = atoi (arg + strlen ("--count="));
+
+ if (count < 1)
+ usage (2);
+ }
+ else if (strcmp (arg, "--ignore-errors") == 0)
+ {
+ ignore_errors = TRUE;
+ }
+ else if (strstr (arg, "--dest=") == arg)
+ {
+ destination = arg + strlen ("--dest=");
+ }
+ else if (strstr (arg, "--payload=") == arg)
+ {
+ payload = arg + strlen ("--payload=");
+ }
+ else if (strcmp (arg, "--stdin") == 0)
+ {
+ consume_stdin (&payload_buf, &payload_len);
+ payload = payload_buf;
+ }
+ else if (strcmp (arg, "--message-stdin") == 0)
+ {
+ consume_stdin (&payload_buf, &payload_len);
+ payload = payload_buf;
+ template = dbus_message_demarshal (payload, payload_len, &error);
+
+ if (template == NULL)
+ {
+ fprintf (stderr, "Unable to demarshal template message: %s: %s",
+ error.name, error.message);
+ exit (1);
+ }
+
+ if (dbus_message_get_type (template) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+ {
+ fprintf (stderr, "Template message must be a method call\n");
+ exit (1);
+ }
+ }
+ else if (strcmp (arg, "--random-size") == 0)
+ {
+ unsigned int len, max = 0;
+ int j, consumed = 0;
+ const char *p;
+
+ consume_stdin (&payload_buf, &payload_len);
+
+ for (p = payload_buf; p < payload_buf + payload_len; p += consumed)
+ {
+ /* the space character matches any (or no) whitespace */
+ if (sscanf (p, " %u %n", &len, &consumed) == 0)
+ break;
+
+ n_random_sizes++;
+ }
+
+ random_sizes = dbus_new0 (int, n_random_sizes);
+
+ if (random_sizes == NULL)
+ tool_oom ("allocating array of message lengths");
+
+ for (p = payload_buf, j = 0;
+ p < payload_buf + payload_len && j < n_random_sizes;
+ p += consumed, j++)
+ {
+ sscanf (p, " %u %n", &len, &consumed);
+ random_sizes[j] = len;
+
+ if (len > max)
+ max = len;
+ }
+
+ dbus_free (payload_buf);
+ payload_len = max + 1;
+ payload_buf = dbus_new (char, payload_len);
+ payload = payload_buf;
+
+ if (payload_buf == NULL)
+ tool_oom ("allocating maximum-sized payload");
+
+ memset (payload_buf, 'X', payload_len);
+ payload_buf[payload_len - 1] = '\0';
+ }
+ else if (strcmp (arg, "--empty") == 0)
+ {
+ payload_type = DBUS_TYPE_INVALID;
+ }
+ else if (strcmp (arg, "--string") == 0)
+ {
+ payload_type = DBUS_TYPE_STRING;
+ }
+ else if (strcmp (arg, "--bytes") == 0)
+ {
+ payload_type = DBUS_TYPE_ARRAY;
+ }
+ else if (strcmp (arg, "--flood") == 0)
+ {
+ if (queue_len > 1)
+ usage (2);
+
+ if (messages_per_conn > 0)
+ usage (2);
+
+ flood = TRUE;
+ queue_len = -1;
+ }
+ else if (strcmp (arg, "--no-reply") == 0)
+ {
+ if (queue_len > 1)
+ usage (2);
+
+ queue_len = -1;
+ no_reply = TRUE;
+ }
+ else if (strstr (arg, "--queue=") == arg)
+ {
+ if (flood || no_reply)
+ usage (2);
+
+ queue_len = atoi (arg + strlen ("--queue="));
+
+ if (queue_len < 1)
+ usage (2);
+ }
+ else if (strstr (arg, "--seed=") == arg)
+ {
+ seed = strtoul (arg + strlen ("--seed="), NULL, 10);
+ }
+ else if (strstr (arg, "--messages-per-conn=") == arg)
+ {
+ messages_per_conn = atoi (arg + strlen ("--messages-per-conn="));
+
+ if (messages_per_conn > 0 && flood)
+ usage (2);
+ }
+ else
+ {
+ usage (2);
+ }
+ }
+
+ srand (seed);
+
+ if (payload == NULL)
+ {
+ payload = "hello, world!";
+ payload_len = strlen (payload);
+ }
+
+ VERBOSE (stderr, "Will send up to %d messages, with up to %d queued, max %d per connection\n",
+ count, queue_len, messages_per_conn);
+
+ while (no_reply ? sent < count : received < count)
+ {
+ /* Connect?
+ * - In the first iteration
+ * or
+ * - When messages_per_conn messages have been sent and no replies are being waited for
+ */
+ if (connection == NULL ||
+ (messages_per_conn > 0 && sent_in_this_conn == messages_per_conn &&
+ (no_reply || received - received_before_this_conn == messages_per_conn)))
+ {
+ if (connection != NULL)
+ {
+ dbus_connection_flush (connection);
+ dbus_connection_close (connection);
+ dbus_connection_unref (connection);
+ }
+
+ VERBOSE (stderr, "New connection.\n");
+ connection = dbus_bus_get_private (type, &error);
+
+ if (connection == NULL)
+ {
+ fprintf (stderr, "Failed to connect to bus: %s: %s\n",
+ error.name, error.message);
+ dbus_error_free (&error);
+ return 1;
+ }
+
+ sent_in_this_conn = 0;
+ received_before_this_conn = received;
+ }
+
+ /* Send another message? Only if we don't exceed the 3 limits:
+ * - total amount of messages
+ * - messages sent on this connection
+ * - queue
+ */
+ while (sent < count &&
+ (messages_per_conn == 0 || sent_in_this_conn < messages_per_conn) &&
+ (queue_len == -1 || sent_in_this_conn < queue_len + received - received_before_this_conn))
+ {
+ DBusMessage *message;
+
+ if (template != NULL)
+ {
+ message = dbus_message_copy (template);
+
+ if (message == NULL)
+ tool_oom ("copying message");
+
+ dbus_message_set_no_reply (message, no_reply);
+ }
+ else
+ {
+ dbus_bool_t mem;
+ unsigned int len = 0;
+
+ message = dbus_message_new_method_call (destination,
+ "/",
+ "com.example",
+ "Spam");
+
+ if (message == NULL)
+ tool_oom ("allocating message");
+
+ dbus_message_set_no_reply (message, no_reply);
+
+ switch (payload_type)
+ {
+ case DBUS_TYPE_STRING:
+ if (random_sizes != NULL)
+ {
+ /* this isn't fair, strictly speaking - the first few
+ * are a bit more likely to be chosen, unless
+ * RAND_MAX is divisible by n_random_sizes - but it's
+ * good enough for traffic-generation */
+ len = random_sizes[rand () % n_random_sizes];
+ payload_buf[len] = '\0';
+ }
+
+ mem = dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &payload,
+ DBUS_TYPE_INVALID);
+
+ if (random_sizes != NULL)
+ {
+ /* undo the truncation above */
+ payload_buf[len] = 'X';
+ }
+
+ break;
+
+ case DBUS_TYPE_ARRAY:
+ len = payload_len;
+
+ /* as above, not strictly fair, but close enough */
+ if (random_sizes != NULL)
+ len = random_sizes[rand () % n_random_sizes];
+
+ mem = dbus_message_append_args (message,
+ DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE,
+ &payload,
+ (dbus_uint32_t) len,
+ DBUS_TYPE_INVALID);
+ break;
+
+ default:
+ mem = TRUE;
+ }
+
+ if (!mem)
+ tool_oom ("building message");
+ }
+
+ if (no_reply)
+ {
+ if (!dbus_connection_send (connection, message, NULL))
+ tool_oom ("sending message");
+
+ VERBOSE (stderr, "sent message #%d\n", sent);
+ sent++;
+ sent_in_this_conn++;
+ }
+ else
+ {
+ DBusPendingCall *pc;
+
+ if (!dbus_connection_send_with_reply (connection,
+ message,
+ &pc,
+ DBUS_TIMEOUT_INFINITE))
+ tool_oom ("sending message");
+
+ VERBOSE (stderr, "sent message #%d\n", sent);
+ sent++;
+ sent_in_this_conn++;
+
+ if (pc == NULL)
+ tool_oom ("sending message");
+
+ if (dbus_pending_call_get_completed (pc))
+ pc_notify (pc, &received);
+ else if (!dbus_pending_call_set_notify (pc, pc_notify, &received,
+ NULL))
+ tool_oom ("setting pending call notifier");
+
+ dbus_pending_call_unref (pc);
+ }
+
+ dbus_message_unref (message);
+ }
+
+ if (!dbus_connection_read_write_dispatch (connection, -1))
+ {
+ fprintf (stderr, "Disconnected from bus\n");
+ exit (1);
+ }
+ }
+
+ if (connection != NULL)
+ {
+ dbus_connection_flush (connection);
+ dbus_connection_close (connection);
+ dbus_connection_unref (connection);
+ }
+
+ VERBOSE (stderr, "Done\n");
+
+ dbus_free (payload_buf);
+
+ if (template != NULL)
+ dbus_message_unref (template);
+
+ dbus_shutdown ();
+ return 0;
+}
diff --git a/tools/test-tool.c b/tools/test-tool.c
new file mode 100644
index 00000000..149c10ab
--- /dev/null
+++ b/tools/test-tool.c
@@ -0,0 +1,88 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-test-tool - D-Bus swiss army knife
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * 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 <config.h>
+#include "test-tool.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <dbus/dbus.h>
+
+static struct {
+ const char *name;
+ int (*callback) (int, char **);
+} subcommands[] = {
+ { "black-hole", dbus_test_tool_black_hole },
+ { "echo", dbus_test_tool_echo },
+ { "spam", dbus_test_tool_spam },
+ { NULL, NULL }
+};
+
+static void usage (int exit_with) _DBUS_GNUC_NORETURN;
+
+static void
+usage (int exit_with)
+{
+ int i;
+
+ fprintf (stderr,
+ "Usage: dbus-test-tool SUBCOMMAND [OPTIONS]\n"
+ "\n"
+ "Known SUBCOMMANDs are:\n"
+ "\n"
+ );
+
+ for (i = 0; subcommands[i].name != NULL; i++)
+ {
+ fprintf (stderr, "- %s\n", subcommands[i].name);
+ }
+
+ fprintf (stderr,
+ "\n"
+ "For more information: dbus-test-tool SUBCOMMAND --help\n"
+ );
+
+ exit (exit_with);
+}
+
+int
+main (int argc, char **argv)
+{
+ int i;
+
+ if (argc < 2)
+ {
+ usage (2);
+ }
+
+ for (i = 0; subcommands[i].name != NULL; i++)
+ {
+ if (!strcmp (argv[1], subcommands[i].name))
+ return subcommands[i].callback (argc, argv);
+ }
+
+ usage (2);
+ return 2;
+}
diff --git a/tools/test-tool.h b/tools/test-tool.h
new file mode 100644
index 00000000..8143cd50
--- /dev/null
+++ b/tools/test-tool.h
@@ -0,0 +1,31 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* dbus-test-tool - D-Bus swiss army knife
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * 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
+ *
+ */
+
+#ifndef DBUS_TEST_TOOL_H
+#define DBUS_TEST_TOOL_H
+
+int dbus_test_tool_black_hole (int argc, char **argv);
+int dbus_test_tool_echo (int argc, char **argv);
+int dbus_test_tool_spam (int argc, char **argv);
+
+#endif
diff --git a/tools/tool-common.c b/tools/tool-common.c
new file mode 100644
index 00000000..b6af629f
--- /dev/null
+++ b/tools/tool-common.c
@@ -0,0 +1,60 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* tool-common - common functionality for dbus-test-tool modules
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * 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 <config.h>
+#include "tool-common.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef DBUS_WIN
+#include <windows.h>
+#endif
+
+/* a hack to avoid having to depend on the static -util version of libdbus;
+ * it's useful for ancillary programs to be able to use the shared library */
+void
+tool_millisleep (int ms)
+{
+#ifdef DBUS_WIN
+ Sleep (ms);
+#else
+ fd_set nothing;
+ struct timeval tv;
+
+ tv.tv_sec = ms / 1000;
+ tv.tv_usec = (ms % 1000) * 1000;
+
+ FD_ZERO (&nothing);
+ select (1, &nothing, &nothing, &nothing, &tv);
+#endif
+}
+
+void
+tool_oom (const char *doing)
+{
+ fprintf (stderr, "OOM while %s\n", doing);
+ exit (1);
+}
diff --git a/tools/tool-common.h b/tools/tool-common.h
new file mode 100644
index 00000000..f31076fe
--- /dev/null
+++ b/tools/tool-common.h
@@ -0,0 +1,38 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/* tool-common - common functionality for dbus-test-tool modules
+ *
+ * Copyright © 2003 Philip Blundell <philb@gnu.org>
+ * Copyright © 2011 Nokia Corporation
+ * Copyright © 2014 Collabora Ltd.
+ *
+ * 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
+ *
+ */
+
+#ifndef DBUS_TOOL_COMMON_H
+#define DBUS_TOOL_COMMON_H
+
+#include <dbus/dbus.h>
+
+#if 0
+#define VERBOSE fprintf
+#else
+#define VERBOSE(...) do {} while (0)
+#endif
+
+void tool_millisleep (int ms);
+void tool_oom (const char *doing);
+
+#endif