Merge tag 'upstream/2.52.2' into tizen 88/131288/4
authorAdrian Szyndela <adrian.s@samsung.com>
Thu, 25 May 2017 09:50:11 +0000 (11:50 +0200)
committerAdrian Szyndela <adrian.s@samsung.com>
Wed, 31 May 2017 09:07:28 +0000 (11:07 +0200)
upstream/2.52.2

Change-Id: I60b56ce4eaa45877acc7e53ac4551d0a31234f7e

36 files changed:
1  2 
NEWS
configure.ac
docs/reference/glib/glib-sections.txt
gio/Makefile.am
gio/gdbus-2.0/codegen/codegen.py
gio/gdbusaddress.c
gio/gdbusconnection.c
gio/gdbusconnection.h
gio/gdbusmessage.c
gio/gdbusmethodinvocation.c
gio/gdbusnamewatching.c
gio/gdbusobjectmanagerclient.c
gio/gdbusprivate.c
gio/gdbusprivate.h
gio/gdbusproxy.c
gio/gioenums.h
gio/gkdbus.c
gio/gkdbus.h
gio/gkdbusfakedaemon.c
glib/Makefile.am
glib/gbytes.c
glib/glib-private.c
glib/glib-private.h
glib/gmessages.h
glib/gtestutils.c
glib/gtestutils.h
glib/gvariant-core.c
glib/gvariant-parser.c
glib/gvariant-serialiser.c
glib/gvariant.c
glib/gvariant.h
glib/gvarianttype.c
glib/gvarianttype.h
glib/gvarianttypeinfo.c
glib/tests/bytes.c
glib/tests/gvariant.c

diff --cc NEWS
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
+ Overview of changes in GLib 2.52.2
+ ==================================
+ * Bug fixes:
+  734946 Implement GContentType on OSX
+  761102 Increase performance for main loop
+  780300 gio/gosxappinfo.c uses deprecated LSFindApplicationForInfo
+  780309 gio/tests/appinfo build fails: gdesktopappinfo.c skipped on OS X
+  781298 gfileutils.c:330:3: error: ISO C90 forbids mixed declarations and code
+ * Translation updates:
+  Indonesian
+ Overview of changes in GLib 2.52.1
+ ==================================
+ * Bug fixes:
+  674885 type initialisation deadlock in GObject
+  698064 Add g_ptr_array_contains()
+  725894 build: Include gettext libraries for static compilation on Mac OS X
+  734946 Implement GContentType on OSX
+  755046 gfileutils: Add precondition checks to g_file_test()
+  775879 g_log_default_handler should not check G_MESSAGES_DEBUG
+  777961 Documentation for g_app_info_equals() could be clearer
+  778049 race in gsource detected by TSan
+  778207 gio-querymodules: fix memory leak
+  778287 G_MODULE_EXPORT and -fvisibility=hidden
+  779409 Fix false positive g_warning() in remove_filter()
+  780066 g_base64_encode_close() in glib/gbase64.c produces invalid base64 encoding
+  780095 g_utf8_get_char_validated() stopping at nul byte even for length specified buffers
+  780306 Unused function in gunicollate.c for CARBON
+  780310 g_tls_database_verify_chain doesn't set the GError for failures other than cancellation
+  780384 gio/tests/contenttype fails on OS X: "public.directory" != "public.folder"
+  780441 Make the portal implementation of g_app_info_launch() synchronous
+  780471 appinfo: Only use portal as fallback
+  780924 Memory leak in gdbusmethodinvocation.c
+ * Translation updates:
+  Friulian
+  Hebrew
+  Indonesian
+  Polish
+  Russian
+ Overview of changes in GLib 2.52.0
+ ==================================
+ * Bug fixes:
+  779799 gdatetime test fails with tzdata 2017a
+  780032 Add missing attributes to two functions
+  780144 gio/fam: Remove leftover debug print
+ * Translation updates:
+  French
+  Friulian
+  Latvian
+ Overview of changes in GLib 2.51.5
+ ==================================
+ * OS X implementations of GContentType and GAppInfo
+   have been added
+ * Bugs fixed:
+  673047 gunicollate is broken on OS X (patch included!)
+  734946 Implement GContentType on OSX
+  747146 Implement GNotification on OSX
+  769983 glib-mkenums generates non-reproducible Makefile snippets
+  777203 gnulib license information is not correct in glib2.0
+  778515 Crash in the gio kqueue backend
+  779456 Make g_utf8_make_valid optionally take a length
+ * Translation updates:
+  Danish
+  Friulian
+  German
+  Hungarian
+  Korean
+  Lithuanian
+ Overview of changes in GLib 2.51.4
+ ==================================
+ * Memory leak fixes
+ * Fix the released tarball
+ Overview of changes in GLib 2.51.3
+ ==================================
+ * Bugs fixed:
+  771997 gchecksum: Add SHA-384 support
+  778422 gsubprocesslauncher: Clarify the behavior of set_environ()
+  778581 gdbus-codegen: Fix -Wconversion warning
+  778801 gdbus-codegen: Add --outdir flag
+  778991 Plug a mem leak in gdbusauth
+  779183 g_io_extension_point_get_extensions should check for NULL pointer
+ * Translation updates:
+  Basque
+  Chinese (Taiwan)
+  Danish
+  Indonesian
+  Italian
+  Serbian
+ Overview of changes in GLib 2.51.2
+ ==================================
+ * Minimal support for UUIDs has been added
+ * A new file attribute, G_FILE_ATTRIBUTE_RECENT_MODIFIED has been added
+   to improve sorting of recent files
+ * Bugs fixed:
+  639078 UUID support feature request
+  777135 gkeyfile: Be more specific about error codes in documentation
+  777307 race condition between gdbus signal callback and g_bus_unwatch_name...
+  777481 goutputstream: docs: fix typos
+  777493 g_mkdtemp() not introspectable
+  777507 Recent view sorting incorrectly
+  777592 Add minor examples to GDBus and GVariant documentation
+  778002 race in gdbusprivate.c detected by the ThreadSanitizer
+  778096 race in gdbusconnection reported by TSan
+ * Translation updates:
+  Norwegian bokmÃ¥l
+  Polish
+  Simplified Chinese
+  Slovak
+  Spanish
+  Swedish
+ Overview of changes in GLib 2.51.1
+ ==================================
+ * glib-compile-resources grew a --generate-phony-targets flag
+ * GLib now installs a valgrind suppressions file for GLib and GIO
+ * Bugs fixed:
+  666114 should have infrastructure to run its tests under valgrind
+  729730 GDBusMessage: Fix segfault if DEBUG_SERIALIZER is enabled
+  730932 statically assert that reasonable assumptions about enums are true
+  735731 gobject: Document behaviour of GType checking macros on NULL
+  736810 gdbus: Fix leak in g_dbus_message_print()
+  762283 GSocket â€“ Fix race conditions on Win32 if multiple threads are waiting on cond...
+  767609 Test suite problems
+  767952 g_dbus_method_invocation_return_*, g_dbus_method_invocation_take_error: They d...
+  769672 Assert threads for testcase 642026 are sucessfully created
+  769745 gtask: Add guards for public functions
+  770175 Add command line argument to mkenums and genmarshal to write output to a file
+  770646 glib: Namespace global tapset variables by soname
+  772160 Add g_unix_mount_for() support
+  772989 Totem allows invalid urls that might cause segfault that's irrecoverable
+  773823 gio: Bump copy buffer size to 256k by default
+  774086 fix g_main_context_check declaration
+  774368 Dependency file output of resource scanner breaks Ninja
+  774421 Two minor patches
+  774520 GSocket allocates and processes control messages even if not requested
+  775309 Crash in gdbusauth
+  775468 Improve log write supports color method on windows
+  775510 testing with -fsanitize=undefined reports various undefined behaviour
+  775517 Password input is echoed in the terminal
+  775621 gmessages: Fix compilation on Android
+  775765 FDO notification withdrawal backend sends wrong ID to the server
+  775913 subprocesslauncher: potential infinite loop in verify_disposition()
+  776198 Stray semicolon after g_variant_print() function in gvariant.c
+  776586 License headers cleanup
+  777077 Use of memory after it is freed
+ * Translation updates:
+  Brazilian Portuguese
+  Czech
+  Galician
+  German
+  Hebrew
+  Kazakh
+  Lithuanian
+  Spanish
+  Swedish
+ Overview of changes in GLib 2.51.0
+ ==================================
+ * glib-genmarshal and glib-mkenums have gained --output options
+   for better build system integration
+ * New API: g_utf8_make_valid
+ * Bugs fixed:
+  591603 Make _g_utf8_make_valid public
+  610969 Nice to have g_utf8_make_valid as public
+  767882 Bit shift overflow (-Wshift-overflow) warning in gparam.h
+  769135 External control for g_test_add/g_test_run
+  769630 gfile: G_FILE_MONITOR_WATCH_MOVES was actually introduced in 2.46
+  772160 Add g_unix_mount_for() support
+  772221 Take advantage of Unicode
+  773303 GApplication leaks option_strings 
+ * Translation updates:
+  French
+  Galician
+  German
+  Hungarian
+  Lithuanian
+  Norwegian bokmÃ¥l
+  Occitan
+  Polish
+  Slovak
+  Turkish
+ Overview of changes in GLib 2.50.1
+ ==================================
+ * Update Unicode support to Unicode 9.0.0
+ * Bugs fixed:
+  662946 gunixmounts monitoring doesn't work correctly with libmount
+  771591 Update to Unicode 9.0.0
+  772054 glib/gspawn-win32-helper.c: unexpected behavior re CommandLineToArgvW()
+  772255 gresolver: Mark GResolver as an abstract class
+  772269 Add --version options to glib-compile-resources and glib-compile-schemas
+  772297 completion: Complete gsettings describe
+  772511 g_log_default_handler crashes windows apps with "Unspecified fatal err...
+ * Translation updates:
+  Brazilian Portuguese
+  Catalan
+  Croatian
+  Czech
+  Danish
+  Hungarian
+  Italian
+  Latvian
+  Polish
+  Swedish
+ Overview of changes in GLib 2.50.0
+ ==================================
+ * Bugs fixed:
+  771438 Turn on libmount by default on linux
+         Fix the annotation for g_log_variant
+ * Translation updates:
+  British English
+  French
+ Overview of changes in GLib 2.49.7
+ ==================================
+ * Add g_log_variant, binding-friendly api for structured logging
+ Bugs fixed:
+  646926 arg_data invalid after g_option_context_parse() fails
+ * Translation updates:
+  Danish
+  Finnish
+  Galician
+  German
+  Hebrew
+  Kazakh
+  Korean
+  Latvian
+  Lithuanian
+  Polish
+  Portuguese
+  Serbian
+  Slovak
+  Spanish
+  Swedish
+  Thai
+ Overview of changes in GLib 2.49.6
+ ==================================
+ * The gsettings commandline tool now has a describe command
+ Bugs fixed:
+  745754 Add gcc-style dependency output to glib-compile-resources
+  769076 Fix warning: attempt to override closure->va_marshal with new marshal
+  770372 gdbus-codegen: Strip @since parameters before comparison
+ Translation updates:
+  Brazilian Portuguese
+  Czech
+  German
+  Hungarian
+  Polish
+  Portuguese
+  Spanish
+ Overview of changes in GLib 2.49.5
+ ==================================
+ * Structured logging:
+  - drop libsystemd dependency
+  - document that g_test_expect_message does not work with structured logs
+ * Use libmount for unix mount support
+ * Add an async variant of g_app_info_launch_default_for_uri
+ Bugs fixed:
+  522053 GUnixMountMonitor needs to use /proc/self/mountinfo on recent Linux
+  682794 Add usage guidance to logging documentation
+  744456 Structured logging API
+  766370 Add a macro for initializing g_auto(GVariantBuilder)
+  767240 Regex failures with pcre 8.38
+  768198 Can't build glib with systemtap enabled
+  768453 Gdbus test: compilation fails due to -Werror=format-y2k errors
+  768752 Add async variant of g_app_info_launch_default_for_uri
+  769027 Docs misleadingly imply G_CHECKSUM_SHA512 is available since 2.16
+  769029 gmessage: compiler complains about -Wformat-nonliteral
+  769042 'O_CLOEXEC' undeclared (first use in this function)
+  769087 gmessages: support NULL log domain
+  769089 Fix gsettings uint64 testcase
+  769104 Build failure when using _GLIB_CHECKED_ADD_U32 with the Intel compiler
+  769139 g_log_writer_journald uses non-standard 'htole64' function
+  769238 memory increases every time I umount and mount my secondary hard disk.
+  769245 is_valid_heap_iter define misses NULL pointer check
+  769507 gmessages: Don’t require is_journald() call before writer_journald()
+  769785 gmessages: Expand documentation further for structured logging
+  769995 gdbus-codegen: Allow '@since: UNRELEASED' in documentation comments
+ Translation updates:
+  Catalan
+  Hebrew
+  Lithuanian
+  Slovak
+  Spanish
+ Overview of changes in GLib 2.49.4
+ ==================================
+ * Change the just-introduced structured logging API. The arguments
+   of g_log_structured() had to be reordered to enable an implementation
+   within the limits of what the standards guarantee about var args.
+ Bugs fixed:
+  744456 Structured logging API
+  768936 gio doc build fails because of missing gio.xml in the tarballs
+  768963 improper va_list use in g_log_structured()
+  768968 gio/tests/socket-listener hangs since e4ee307
+ Translation updates:
+  Spanish
+ Overview of changes in GLib 2.49.3
+ ==================================
+ * GLib has a structured logging API, g_log_structured, with support
+   for writing to the systemd journal. It also supports colored output
+   in terminals
+ * Some new GBytes API has been added:
+  - g_key_file_load_from_bytes
+  - g_compute_hmac_for_bytes
+ * Stack-allocated GVariantBuilder and GVariantDict objects can now be
+   initialized with G_VARIANT_BUILDER_INIT and G_VARIANT_DICT_INIT
+ * gio:
+  - Add a way to register handlers for custom uri schemes
+  - Add a G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE attribute to
+    have these heuristics in a single place
+  - Include a gio tool that makes the functionality of the
+    various gvfs commandline tools available in a single place
+  - Add portal support to g_app_info_launch_default_for_uri
+  - Add portal support to GNetworkMonitor
+  - Add portal support to GProxyResolver
+  - Add portal support to g_application_send_notification
+ Bugs fixed:
+  547200 g_utf8_find_next_char() issues
+  662802 systemtap multiarch issue
+  723506 fork/exec from non-main thread when autolaunching could be avoided...
+  725902 build: simplify dtrace configuration
+  728207 gsocketservice: Documentation does not mention that is already act...
+  729914 instead of DEBUG_CODE and IF_DEBUG, provide a common macro to supp...
+  744456 Structured logging API
+  744678 Unable to delete relocatable schemas
+  746685 clarify that g_variant_get_data() can be used instead of g_variant...
+  747134 glib-compile-resources --generate should detect common C++ file ex...
+  750257 GSettings changed signal should clearly state the order required
+  753231 Memory is potentially used after free
+  754012 missing filename in "Error loading css: Failed to import: Error op...
+  760115 gtestutils: add missing dash in seed argument's --help documentation
+  760423 gio-querymodules prints error messages as question marks on some l...
+  761102 Increase performance for main loop
+  765338 GLib.compute_hmac_for_data throws every time
+  766370 Add a macro for initializing g_auto(GVariantBuilder)
+  766899 Superflous HTML/XML comments in GDBusProxyTypeFunc documentation s...
+  766933 GSocketAddress leaks in gnetworkmonitornetlink.c:read_netlink_mess...
+  767765 Add names and tags to various GSources and GTasks constructed in GLib
+  767880 gkeyfile: add g_key_file_load_from_bytes() API
+  767887 vfs: add g_vfs_register_uri_scheme()
+  767949 [patch] Typos in glib docs
+  768029 infinite loop in parse_name_internal()
+  768119 Fix fallout from get_supported_schemes() changes
+  768357 Build the gio tool on Windows/MSVC
+  768498 portal support for glib
+  768504 keyfile: g_key_file_get_double behavior doesn't follow documentation
+  768549 Test failure: test_ip_sync_dgram
+  768551 Test failure: test_socket_address_to_string
+  768560 gio/tests/gsettings: fix GSettings reference leaks in some tests
+  768780 O_PATH is a non-standard flag which may be unavailable on non-Lin...
+  768806 gdbus tool must swallow -- argument
+ Translation updates:
+  Chinese (Taiwan)
+  French
+  Hebrew
+  Indonesian
+  Lithuanian
+  Portuguese
+  Spanish
+ Overview of changes in GLib 2.49.2
+ ==================================
+  * GMainContext and GTask have gained more systemtap probes
+ Bugs fixed:
+  673101 resource compiler dependency generation not working for gen...
+  700756 GFile.new_for_path arguments misses (type filename) annotation
+  730187 glocalfileoutputstream: Fix an FD leak in an error path
+  755439 Memory leak in gdbusproxy.c
+  759813 Add more SystemTap/DTrace probes for main context and GTask
+  761810 gio: Support using GDBusObjectManagerServer at path â€˜/’
+  767172 docs: Move GIO_USE_VFS to "okay for production" section
+  767218 Remove a UTF-8 ellipsis from gsignal.h
+  767245 Add filename type annotations
+  767824 Some UTC timezones incorrectly recognized on Windows 7
+ Translation updates:
+  Occitan
+ Overview of changes in GLib 2.49.1
+ ==================================
+  * GDesktopAppInfo now allows bus activation with dashes. This is
+    not technically allowed per the Desktop Entry specification, but
+    it happens in the wild. Rather than forcing people to go through
+    another traumatic desktop file rename, accept it and translate - to _.
+  * The support for giving names to threads has been improved. Thread names
+    are now supported on Solaris as well, and the Linux support no longer
+    uses prctl() but the pthread api.
+  * GIO resources can now be overridden at runtime, using the G_RESOURCE_OVERLAYS
+    environment variable.
+  * gdbus-codegen can now generate autocleanup definitions for the types
+    it generates. Use the --c-generate-autocleanup option to control this
+ Bugs fixed:
+  665446 Use g_abort() instead of abort()
+  731988 glocalfile: Avoid a potential NULL pointer dereference
+  742898 g_value_type_transformable() description differs from the code
+  747107 GVariant varargs documentation: g_variant_get() example
+  747478 g_system_thread_set_name() is not implemented for gthread-win32
+  748474 g_get_language_names() is not thread-safe
+  748530 gthread: W32 implementation of g_get_num_processors() has lame fallback
+  748806 GVariant: Better introduction to the concepts and its uses
+  749583 GSequence performance improvements
+  749606 tests: always remove app.desktop
+  755898 [PATCH] settings: add get/set uint64
+  758174 Fix documentation typos
+  758738 Usage of GType properties causes crashes due to gulong/gpointer mismatch
+  760186 namespace clash with gdb pretty-printing code
+  762994 Race condition in GIO/AppFileChooser crashes Firefox/Gtk3
+  763379 codegen: Add support for g_autoptr to gdbus-codegen–generated objects
+  763821 build: Also dist Systemtap files always for gobject/
+  764092 gstrfuncs: Document the behaviour of g_strjoinv()
+  764163 g_task_had_error doesn't remember the error after g_task_propagate_*
+  764415 Very High CPU usage in g_poll() Windows implementation
+  764574 build: Fix all statfs() tests failing
+  764575 tests: Fix compilation errors due to Y2K format problems
+  764685 GApplication documentation about handling command-line options is confusing
+  764754 '-' in application id: unbreak bus activation and notifications
+  765173 documentation of g_main_context_push_thread_default() regarding GIO...
+  765668 GResources: add support for resource overlays
+  765710 gdbus-tool: only print note about expected argument types if that...
+  765712 tests: Fix compilation
+  765861 task: avoid context lock when setting source name
+  765900 Add g_drive_is_removable() support
+  765924 Improve external drives detection
+  765959 socket: set fd field to -1 after closing socket
+  765990 Visual Studio: Define inline only when necessary
+  765991 Compilation of gresource.c is broken due to S_ISDIR
+  766092 Incorrect locale handling in g_date_time_format_locale()
+  766211 Fix the upper bound in g_unichar_iswide_bsearch
+  766407 Some build-related defects in glib testsuite
+  766570 build: Fix a misnamed variable in glib-tap.mk
+ Translation updates:
+  Basque
+  Catalan
+  Chinese
+  Occitan
+  Portuguese
+  Turkish
+  Vietnamese
+ Overview of changes in GLib 2.48.0
+ ==================================
+  * a minor build fix in the name of determinism
+  * a few coverity fixes
+ Bugs fixed:
+  763617 giotypefuncs.c: Sort _get_type functions in the 'C' locale
+ Translations updated:
+  Danish
+  Italian
+ Overview of changes in GLib 2.47.92
+ ===================================
+  * gdbus-codegen now supports g_autoptr()
+  * g_get_user_runtime_dir() now reliably returns an existing directory
+  * g_array_remove_range() can now remove 0 items from the end of an array
+  * Many fixes for Windows
+    * build fixes
+    * file monitoring
+    * gsettings backend
+    * streams
+    * random numbers
+    * wide character support
+  * documentation improvements
+  * other small bugfixes
+ Bugs fixed:
+  724847 Segmentation fault on "gsettings list-recursively"
+  743933 gapplication: add --app-id command line option
+  756706 [PATCH] gio/gtestdbus.c: don't use non-standard %m printf modifier
+  757506 gsettings: schema_list should use the passed schema's source
+  760694 W32: Apps linked with -mwindows make cursor busy sometimes
+  762202 g_win32_error_message improvements
+  762637 build: Unconditionally dist tapset files
+  762748 Undefined behavior
+  762937 Mention that g_clear_error can be used with an "empty" GError
+  763339 array: Support clearing an empty array with g_array_remove_range()
+  763344 g_get_user_runtime_dir(): ensure directory exists
+  763379 codegen: Add support for g_autoptr to gdbus-codegen–generated objects
+ Translations updated:
+  Brazilian Portuguese
+  Czech
+  Finnish
+  French
+  Galician s
+  German
+  Greek
+  Hebrew
+  Hungarian
+  Italian
+  Kazakh
+  Korean
+  Latvian
+  Lithuanian
+  Occitan
+  Polish
+  Russian
+  Serbian
+  Slovak
+  Slovenian
+  Spanish
+  Swedish
+ Overview of changes in GLib 2.47.6
+ ==================================
+ * Windows usupport:
+  - Fixes and improvements to the GSettings registry backend
+  - Handle readability and writability of registry keys
+  - Use Unicode registry APIs
+ * Bugs fixed:
+ 760852 744772 761126 747927 761337 744570 761504 761550 761843
+  744570 GString is missing (transfer none) annotations on many of its methods
+  744772 systemtap and gdb scripts install in wrong place
+  747927 Documentation: various small improvements
+  760852 gdbusobjectmanagerserver: Clarify recommended ObjectManager paths
+  761126 winiconv: update to upstream version
+  761337 Fix some annotations
+  761504 W32 registry GSettings backend does not use Unicode
+  761550 Cannot build with default flags under Fedora rawhide (-Werror=format-...
+  761843 gmacros.h is testing attributes with __has_feature (when compiling wi...
+ * Translation updates:
+  Brazilian Portuguese
+  Bulagarian
+  Chinese (Taiwan)
+  Hungarian
+  Polish
+  Slovak
+  Slovenian
+  Spanish
+  Swedish
+ Overview of changes in GLib 2.47.5
+ ==================================
+ * the system copy of PCRE is now used by default to implement GRegex.
+   Configure with --with-pcre=internal if a system PCRE version
+   is unavailable or undesired.
+ * interfaces for DTLS support have been added.  A new version of
+   glib-networking will also be required.
+ * GDBusMethodInvocation now drops replies if the sender set the
+   NO_REPLY_EXPECTED flag
+ * several GApplication fixes, including fixes for commandline arguments
+   in interpreted languages on Windows
+ Bugs fixed:
+  624186 Deprecate glib-gettext macros
+  734095 gtk-demo.py of PyGObject fails to run on Windows (and likely other binding scripts using g_application_run())
+  735754 Implement close on TLS GOutputStream
+  748064 gnulib vfprintf returns desired (not actual) number of bytes, ignores errors
+  752240 Add DTLS support to GIO
+  755421 GDBus ignores NO_REPLY_EXPECTED flag in messages, leading to warnings on system bus
+  756875 Include ntdef.h for NTSTATUS
+  759554 g_application_run() calls g_main_context_default() repeatidly
+  760199 gsettings: Install gettext ITS rules
+  760215 G_LIKELY/_UNLIKELY macros need more parentheses
+  760683 regex test: Check the expected PCRE exceptions at runtime
+ Translations updated:
+  Brazilian Portuguese
+  Czech
+  German
+  Lithuanian
+  Swedish
+ Overview of changes in GLib 2.47.4
+ ==================================
+ * The GApplication documentation has been improved in several areas.
+ * Bugs fixed:
+  749092 gdb pretty-printers fail on Python 3 with a TypeError...
+  757374 macros: clean up "inline" mess
+  758641 Memory leak in g_dbus_proxy_new_for_bus_sync()
+  759134 Add missing checks for gnulib vasnprintf()
+  759408 Do not use uninitialized var 
+  756475 Stop supporting non-POSIX getpwuid_r, getgrgid_r
+  757372 GApplication: destroy the impl on shutdown
+  728099 macros: add G_GNUC_CHECK_VERSION() for compiler checks
+  757299 glib-compile-resources: do not leak c_name
+  758553 Fix gettext use
+  758823 file monitors: reorder some code to avoid segfault
+  756214 gsettings: Don't translate ""
+  710243 Add GParamSpec object ref management annotations
+  735696 xdgmime: Finer handling for cases where mmap() is not available
+  752983 gapplication: Acquire the main context before running
+ * Translation updates:
+  Swedish
+ Overview of changes in GLib 2.47.3
+ ==================================
+ The inline cleanup in the last release accidentally removed three
+ symbols from libglib-2.0.so.  It is unlikely that this will have caused
+ any problems because these symbols were only backup symbols for
+ definitions exported as inlines in the header files, but ABI is ABI.
+ This release corrects only this problem.
+ Overview of changes in GLib 2.47.2
+ ==================================
+ * We have formalised the assumption that all compilers that are
+   interested in support 'static inline' and simplified the macros around
+   this considerably.  Please watch for and report unintentional fallout.
+ * New API: hardware-assisted helpers for overflow-checked integer math.
+ * other fixes
+ Bugs fixed:
+  696324 gtester-report doesn't work with Python 3.x
+  719966 glib: Add missing (nullable) and (optional) annotations
+  752837 gobject and glib-compile-resources rely on .CRT$XCU section, no longer works with Win 10 UCRT (VS 2015)
+  755364 make gtkdoc-check happy again
+  756134 Segmentation fault on calling g_simple_action_group_add_action with bad action constructor call
+  756179 gwin32.c: Replace VerifyVersionInfoW() with RtlGetVersion() due to API deprecation
+  756988 GSequence should document each function's complexity
+  757294 Move G_POLLFD_FORMAT to glibconfig.h
+  757374 macros: clean up "inline" mess
+  757451 doc: fix g_task_attach_source() example
+  757628 gio tests fail to build when cross compiling 2.46.1
+  757693 Invalid free in g_local_file_trash()
+  757742 Fix up annotations in ghash.c
+  758181 GTask: fix wrong example code
+ Translations updated:
+  Greek
+  Hebrew
+  Hungarian
+  Norwegian bokmÃ¥l
+  Portuguese
+  Scottish Gaelic
+  Simplified Chinese
+  Spanish
+ Overview of changes in GLib 2.47.1
+ ==================================
+ * The Unicode support has been updated to version 8.0 of the Unicode standard
+ * GDesktopAppInfo no longer sets the DISPLAY environment variable when
+   launching apps. This is now done in the GAppLaunchContext implementations
+   when appropriate
+ * Bug fixes:
+  664740 Key-value file parser, space after integer
+  687223 cleverer GThreadPool management
+  692085 stderr and stdout are not always file descriptors 1 and 2
+  697907 Add interface for socket-like things (GSocket, DTLS, etc)
+  735754 Implement close on TLS GOutputStream
+  737116 Add functions to print GSocketConnectables and addresses as strings
+  743011 Minor additions to GError documentation
+  749161 undefined reference to `__imp__stat32i64'
+  749314 Cannot restore a just-trashed file
+  751924 Add recvmmsg()-like API on GSocket
+  752240 Add DTLS support to GIO
+  752837 gobject and glib-compile-resources rely on .CRT$XCU section, no longer...
+  753310 Remove `#pragma GCC system_header` from gmessages.h
+  753935 Update example namespace and class names in GObject tutorial
+  754855 Object instantiation documentation refers to example that no longer ex...
+  754983 Wayland: g_desktop_app_info_launch_uris_with_spawn() forces DISPLAY va...
+  754994 g_date_time_get_second () sometimes returns an off-by-one result
+  755083 Clarify in G_ADD_PRIVATE that it is safe to call _get_instance_private...
+  755351 Example still contains g_autoptr(gchar)
+  755355 Move GStrv to glib.h so it can be used with g_auto()
+  755374 g_variant_get_child(): flatten-first logic on '&'
+  755496 glib 2.46 fails GStreamer test suite
+  755609 glib 2.46.0 breaks Sun Java JVM 1.8.0.60
+  755766 gvalue: The g_auto cleanup function assert if value is G_VALUE_INIT
+  755795 2.46 considers empty files as octet-stream rather than text (leads to...
+  755961 Fix up annotations in gbytes.c
+  756053 MSVC doesn't understand the symbol 'msghdr'
+  756054 MSVC linker error due to 'g_socket_send_message_with_timeout()'
+  756077 testutils: remove internal ABI comment
+  756099 g_main_context_query(): Annotate @n_fds as (in) parameter
+  756139 musl: ctors called in the wrong order
+  756179 gwin32.c: Replace VerifyVersionInfoW() with RtlGetVersion() due to AP...
+  756251 The documentation of G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START is confusing
+  756255 GOutputStream swallowing errors in splice with G_OUTPUT_STREAM_SPLICE...
+  756316 GSequence should provide fast api to check if empty
+  756382 snprintf used on Windows with VS2015 doesn't support %n
+  756477 gio/gthreadedresolver.c has outdated copy of bionic headers (for android)
+  756550 gtypes.h: Make G_MININTn literals negative
+  756875 Include ntdef.h for NTSTATUS
+  756952 giomodule: return a copy of module name
+ * Translation updates:
+  Basque
+  Czech
+  Serbian
+  Serbian Latin
+  Vietnamese
+ Overview of changes in GLib 2.46.0
+ ==================================
+ * Disable runtime-deprecation warnings
+ * Fix marshalling of flags on bigendian 64bit architectures
+ * Translation updates
+  Brazilian Portuguese
+  Danish
+  German
+  Latvian
+  Russian
+  Turkish
+ Overview of changes in GLib 2.45.8
+ ==================================
+ * utf8 validation and utf8-to-ucs4 conversion are faster
+ * Small speedups to property change notification
+ * Various other small optimizations for GQuark, GData
+ * Bugs fixed:
+  696426 GParamSpecTypeInfo do not need to be static
+  735429 Cleanup MSVC Project Files Generation
+  738504 Optimize UTF-8 decoding by unrolling branches and expressions
+  742903 Add missing (transfer) annotation to GString
+  748633 g_set_object order of operations
+  754431 Fix build of glib/gstrfuncs.c on Windows
+  754560 gioerror: Add more mappings for WinSock error codes
+  754582 Glib cannot compile
+  754601 Make g_strerror work with non-glibc POSIX systems
+  754636 tests/unicode-encoding test fails for glib 2.45.7 on x86-64
+  754788 more g_strerror stuff
+  754831 autocleanups: Add GString type
+  754924 Improve test coverage of g_utf8_validate() by added known-...
+  754986 Avoid unnecessary signal emission during draw
+ * Translation updates:
+  Italian
+  Kazakh
+  Korean
+  Lithuanian
+  Slovenian
+  Swedish
+ Overview of changes in GLib 2.45.7
+ ==================================
+ * Add G_FILE_ATTRIBUTE_STANDARD_IS_VOLATILE for use by non-POSIX-like
+   backends (e.g. cloud storage).
+ * GFileMonitor: Make the inotify backend work with atomic renames again
+ * GSettings: change notification is again working unconditionally
+ * GListStore has a sort function now
+ * Test infrastructure:
+  - Tests are now required to have unique names
+  - TAP support has been improved
+  - A macro for asserting that two memory regions have identical content
+    has been added
+ * Bugs fixed:
+  708525 A "g_file_query_info" on the file path "/sys/kernel/debug/hid"...
+  742849 inotify: send paired events to both sides
+  744060 Update GObject tutorial documentation to use G_DECLARE_FINAL_T...
+  747364 Fix GError leak in g_file_query_writable_namespaces()
+  749492 Support file creation time on FreeBSD and NetBSD
+  752769 (g_socket_receive_message | g_socket_send_message) performance
+  753745 glib-genmarshal still needed for cross-compilation
+  754152 Add g_list_store_sort
+  754211 Memory leak in g_file_enumerator_iterate ()
+  754264 GLib 2.44 certificate chain construction fails if the PEM incl...
+  754283 gtestutils: add g_assert_cmpmem()
+  754284 gtestutils: print the TAP test plan first, not last
+  754286 misc gtestutils fixes
+  754307 size of array '_GStaticAssertCompileTimeAssertion_3387' is neg...
+ * Translation updates:
+  Chinese (Taiwan)
+  French
+  Galician
+  Greek
+  Hebrew
+  Hungarian
+  Indonesian
+  Polish
+  Portuguese
+ Overview of changes in GLib 2.45.6
+ ==================================
+ * Fix a test failure and a build failure
+ Overview of changes in GLib 2.45.5
+ ==================================
+ * GNetworkMonitor now provides information about metered networks
+ * g_mem_set_vtable has been deprecated; it has not been working for
+   quite a while. The recommendation is to use valgrind, or replace
+   malloc itself.
+ * Bugs fixed:
+  656325 Make GDBusInterfaceVTable binding friendly
+  741779 Documentation tweaks addressing real-world API misuses
+  741822 Fails to build with VS 2015
+  742386 gdbusconnection: Don't g_printerr() when exiting
+  743018 gobject: Add more cross-links between documentation pages
+  750282 Add g_network_monitor_get_network_metered() to get if the connection...
+  751358 GFileMonitor doesn't react to "mv some-file watched-file"
+  751592 Stop using GMemVtable
+  751598 Stop 'handle-local-options' propagation when callback reports an err...
+  751610 g_str_hash produces collisions with strings of length 2
+  751751 Wrong docs of g_async_queue_remove
+  752210 gdbus command crashes with SIGSEGV
+  752656 gdbusconnection: Fix signal subscription documentation
+  752767 Fix typo in g_hash_table_replace() documentation
+  753278 gdbus: Don't use g_assert_no_error() GDBusObjectManagerServer
+  753285 g_menu_item_set_icon fails if called with NULL icon
+ * Translation updates:
+  Catalan
+  Czech
+  French
+  Indonesian
+  Lithuanian
+  Norwegian bokmÃ¥l
+  Slovak
+  Spanish
+  Thai
+  Turkish
+ Overview of changes in GLib 2.45.4
+ ==================================
+ * Bugs fixed:
+  727829 win32: glibconfig.h.win32 updates
+  741901 Clang cannot know that g_error don't return
+  746339 GSocket kills process when fd is not a socket
+  747676 gio/tests/socket fails: test_fd_roundtrip
+  748610 Some tests fail with non-English locales
+  749911 g_inet_address_to_string broken on XP/2003
+  749912 g_inet_address_new_from_string broken on XP/2003
+  750625 Should dismiss Software Updates Available notification after...
+  750807 G_BREAKPOINT doesn't work as intended on Darwin
+  751160 gtask does unnecessary work
+  751672 -Wduplicate-decl-specifier in glib/tests/keyfile.c
+  751731 GFile/DirectoryMonitor emit move events with other_file=NULL
+  751737 gio/tests/appmonitor test fails in 2.45.3
+  751798 Wrong enum type used in some test-cases
+  752089 make gsocketservice::active a property
+  752293 small cleanup: use list_free_full
+ * Translation updates:
+  Greek
+  Hebrew
+  Portuguese
+ Overview of changes in GLib 2.45.3
+ ==================================
+ * Improve performance of g_signal_handler_disconnect for signals
+   with many handlers
+ * GDBus has gained a new call flag to allow interactive authorization
+ * GSettings:
+  - New API: g_settings_schema_list_keys
+  - Deprecated: g_settings_list_keys
+ * OS X:
+  - Implement GNotification
+  - Bump the OS X requirement to 10.9
+ * Windows:
+  - Add registry reading API
+  - Reimplement GAppInfo using registry information
+ * Bugs fixed:
+  666831 Support URI opening on W32
+  728489 property action with inverted boolean state
+  730168 Incorrect annotation on g_action_group_get_action_state_type return...
+  733325 Several regex tests fail with pcre3 8.35
+  734888 GLib has no helper functions to work with W32 Registry
+  737009 signal handler lookup doesn't scale
+  738185 Misleading language about "file name encoding" in the docs on g_env...
+  738504 Optimize UTF-8 decoding by unrolling branches and expressions
+  739122 glib not handling -1 return ("no limit") from sysconf (_SC_THREAD_S...
+  739424 gnome-shell crashes when files are added, deleted, or modified in $...
+  739616 DBus; Add new call flag to allow interactive authorization
+  740308 Add g_settings_schema_list_keys() method
+  740516 RFE: please provide an introspectible version of g_log_set_handler
+  741788 Document GSettings build system integration
+  745013 GBinding not thread safe
+  747146 Implement GNotification on OSX
+  747941 try XDG_RUNTIME_DIR/bus before falling back to X11 autolaunch (dbus...
+  748727 Filechooser dialog shows no icons for directories on W32
+  749693 GActionGroupExporter: flush queue on requests
+  750203 GNetworkMonitorNetlink hangs in user namespace
+  750322 gapplication: Make sure --help output is translated
+  750344 GTlsInteractionClass is missing from doc
+  750369 Various GBinding cleanups
+  750386 Race condition in g_io_condition_get_type
+  750399 Typo "equilalent" in glib documentation's glib-Error-Reporting.html...
+  750573 GTlsDatabaseClass is not documented
+  750918 genmarshal: silence register storage class warnings
+  751122 gsocket: avoid unnecessary g_socket_cond_wait() in _send_messages()
+  479730 The "g_key_file_set_comment" interface prepends '#' character to...
+ * Translation updates:
+  Hungarian
+  Spanish
+ Overview of changes in GLib 2.45.2
+ ==================================
+ * Improve error reporting in glib-compile-schemas.
+ * Add introspection annotations to GListStore.
+ * Bugs fixed:
+  696749 win32 : failed to compile because of careless mistake in the code
+  723394 const parameter to GtkPopover gtk_popover_set_pointing_to
+  724113 gdbus-connection-loss test can fail on slow machines
+  725981 tap-driver.sh: internal error getting exit status
+  733325 Several regex tests fail with pcre3 8.35
+  744895 Unknown or unsupported transport 'this-should-not-be-used-and-will...
+  747882 gtype: Bump allowed number of children
+  748534 gtest: if a subprocess assertion fails, print its stdout and stderr
+  748612 de_DE locale used in option-context test is not supported by FreeBSD
+  748614 Double unref in g_socket_listener_add_inet_port
+  748834 glocalfilemonitor: Emit notification on rate limit change
+  749079 gdbus-peer test: TCP tests can fail with ECONNRESET due to a race...
+  749080 gdatetime test: fails if close to rollover between seconds
+  749180 gnetworkaddress: add return type annotation to parse methods
+  749352 g_binding_unbind() fails when source is also the target
+  749353 GBinding does not connect to the detailed notify signal
+ * Translation updates:
+  Catalan
+  French
+  Slovak
+  Thai
+ Overview of changes in GLib 2.45.1
+ ==================================
+ * The GSettings schema compiler, glib-compile-schemas has been changed
+   to reject schema xml that has duplicate <summary> or <description>
+   elements. Such elements typically occur when translations are merged
+   into the schema, with xml:lang attributes. This is not the correct
+   way to translate schemas. Instead keep the translations in the .mo
+   file and set the gettext-domain attribute on the <schemalist> element.
+ * The file monitoring infrastructure has been rewritten, and all backends
+   have seen major improvements.
+   The inotify backend is reporting events with less delay (no event will
+   be delayed more than 10ms) and wakeups due to file monitoring have been
+   significantly reduced. A CHANGES_DONE event will also be sent when new
+   files appear.
+   The poll implementation is now using the thread default main context.
+   The fam implmentation is now running in the worker thread.
+   The fen implementation has been removed, since it was unmaintained.
+ * The GSettings schema compiler, glib-compile-schemas, is more strict
+   about rejecting schemas with xml:lang style merged translations.
+   Schema translations should be done by specifying the gettext domain
+   in the xml, and keeping the translations in gettext. To avoid breaking
+   already-installed schemas, this change is only taking effect when
+   you use the --strict option.
+ * The hardcoded 10-thread limit of GTask's thread pool has been removed,
+   since it was prone to causing deadlocks. The thread pool is now allowed
+   to grow dynamically and will shrink back over time.
+ * GSimpleAsyncResult has been deprecated in favor of GTask.
+ * The algorithm used by GAppInfo to find default handlers for mime types
+   has been tweaked to prefer apps that handle the specific subtype over
+   default handlers for a generic supertype.
+ * Bug fixes:
+  627285 inotify file monitor hardwired delay
+  631597 Segmentation fault in append_escaped_text
+  661767 merge/improve various bits of run-in-thread functionality
+  687223 cleverer GThreadPool management
+  711547 win32: silence some build warnings
+  719966 glib: Add missing (nullable) and (optional) annotations
+  726447 Possibly an error in text string
+  728663 W32: wrong stat struct is used when built with MinGW-w64
+  728669 W32: GLocalFile can't measure size of files larger than 2^32...
+  730188 gsocket: Document FD ownership with g_socket_new_from_fd()
+  733325 Several regex tests fail with pcre3 8.35
+  738207 Add a way to set SO_SENDBUF and SO_RECVBUF on listener (and...
+  739850 GClosure: add valgrind hints
+  741791 gmain: Save errno when handling unix signals
+  744282 gvfs-open for application/x-virt-viewer changed behaviour bet...
+  745255 Add support for copying sessions between GTlsClientConnections
+  745745 gdbus: fix out-of-bound array access
+  745821 Don't use __alloc_size__ attribute with clang
+  746749 GLib-GIO:ERROR:inotify-kernel.c:327:ik_source_dispatch: ass...
+  746753 Glib-compile-resources --generate-header not using ".h" as ...
+  747209 glib-compile-schemas ought to reject repeated <summary> and...
+  747349 Conversion of gdbus to use GTask causes deadlocks
+  747363 gatomic: Add missing new line in API doc comment
+  747472 Don't ignore already-installed schemas with multiple <summa...
+  747541 gdbus segfaults with invalid --dest
+  747772 Having hardcoded utf8 strings in the source code does not p...
+  748019 gsocketconnection: Fix copy-pasto in documentation
+  748177 not all test schemas are distributed, "make distcheck" fails
+ * Translation updates:
+  Basque
+  Czech
+  Danish
+  Finnish
+  German
+  Hebrew
+  Icelandic
+  Norwegian bokmÃ¥l
+  Russian
+  Turkish
 +Overview of changes in GLib 2.44.1
 +==================================
 +
 +* Don't redefine typedefs to avoid build problems on OpenBSD
 +
 +* Improve the default application algorithm
 +
 +* Bump the number of children a GType can have
 +
 +* Various testsuite improvements
 +
 +* Translation updates:
 + Czech
 + Icelandic
 + Russian
 +
 +
 +Overview of changes in GLib 2.44.0
 +===================================
 +
 +With the exception of translation and documentation, there have been no
 +changes since the prerelease.
 +
 +Bugs fixed:
 + 730188 gsocket: Document FD ownership with g_socket_new_from_fd()
 +
 +Translations updated:
 + Basque language
 + Brazilian Portuguese
 + Chinese (Taiwan)
 + Danish
 + Galician s
 + Hebrew
 + Indonesian
 + Norwegian bokmÃ¥l
 + Turkish
 +
  Overview of changes in GLib 2.43.92
  ===================================
  
diff --cc configure.ac
@@@ -785,7 -708,8 +722,8 @@@ AC_CHECK_HEADERS([sys/param.h sys/resou
  AC_CHECK_HEADERS([sys/select.h stdint.h inttypes.h sched.h malloc.h])
  AC_CHECK_HEADERS([sys/vfs.h sys/vmount.h sys/statfs.h sys/statvfs.h sys/filio.h])
  AC_CHECK_HEADERS([mntent.h sys/mnttab.h sys/vfstab.h sys/mntctl.h fstab.h])
 -AC_CHECK_HEADERS([linux/magic.h])
 +AC_CHECK_HEADERS([linux/magic.h linux/memfd.h sys/prctl.h])
+ AC_CHECK_HEADERS([termios.h])
  
  # Some versions of MSC lack these
  AC_CHECK_HEADERS([dirent.h sys/time.h])
Simple merge
diff --cc gio/Makefile.am
@@@ -216,11 -223,9 +223,13 @@@ local_sources = 
  platform_libadd =
  platform_deps =
  appinfo_sources =
+ appinfo_headers =
+ contenttype_sources =
  
 +if LIBDBUSPOLICY
 +platform_libadd += $(LIBDBUSPOLICY1_LIBS)
 +endif
 +
  if HAVE_INOTIFY
  SUBDIRS += inotify
  platform_libadd += inotify/libinotify.la
@@@ -253,15 -251,16 +255,20 @@@ SUBDIRS += fa
  endif
  
  if OS_UNIX
- appinfo_sources += gdesktopappinfo.c
+ if !OS_COCOA
  platform_libadd += xdgmime/libxdgmime.la
  platform_deps += xdgmime/libxdgmime.la
+ appinfo_headers += gdesktopappinfo.h
+ endif
  unix_sources = \
        gfiledescriptorbased.c  \
 +      gkdbus.c                \
 +      gkdbus.h                \
 +      gkdbusfakedaemon.c      \
 +      gkdbusfakedaemon.h      \
        gunixconnection.c       \
        gunixcredentialsmessage.c       \
        gunixfdlist.c           \
@@@ -536,13 -605,14 +613,18 @@@ libgio_2_0_la_LDFLAGS = $(GLIB_LINK_FLA
  if OS_COCOA
  # This is dumb.  The ObjC source file should be properly named .m
  libgio_2_0_la_CFLAGS += -xobjective-c
- libgio_2_0_la_LDFLAGS += -Wl,-framework,Foundation
+ libgio_2_0_la_LDFLAGS += -Wl,-framework,Foundation -Wl,-framework,AppKit
+ endif
+ if HAVE_LIBMOUNT
+ libgio_2_0_la_CFLAGS += $(LIBMOUNT_CFLAGS)
+ libgio_2_0_la_LIBADD += $(LIBMOUNT_LIBS)
  endif
  
 +if LIBDBUSPOLICY
 +libgio_2_0_la_CPPFLAGS += $(LIBDBUSPOLICY1_CFLAGS)
 +endif
 +
  libgio_2_0_la_DEPENDENCIES = $(gio_win32_res) $(gio_def) $(platform_deps)
  
  gio-win32-res.o: gio.rc
Simple merge
  #include "gdbusprivate.h"
  #include "giomodule-priv.h"
  #include "gdbusdaemon.h"
+ #include "gstdio.h"
  
  #ifdef G_OS_UNIX
 +#include "gkdbus.h"
+ #include <unistd.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
  #include <gio/gunixsocketaddress.h>
  #endif
  
@@@ -664,10 -646,10 +672,10 @@@ g_dbus_address_connect (const gchar   *
    else if (g_strcmp0 (address_entry, "autolaunch:") == 0)
      {
        gchar *autolaunch_address;
-       autolaunch_address = get_session_address_platform_specific (error);
+       autolaunch_address = get_session_address_dbus_launch (error);
        if (autolaunch_address != NULL)
          {
 -          ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error);
 +          ret = g_dbus_address_try_connect_one (autolaunch_address, kdbus_okay, NULL, cancellable, error);
            g_free (autolaunch_address);
            goto out;
          }
@@@ -1529,11 -1579,11 +1626,12 @@@ g_dbus_address_get_for_bus_sync (GBusTy
    if (G_UNLIKELY (_g_dbus_debug_address ()))
      {
        guint n;
 +      gchar *s;
        _g_dbus_debug_print_lock ();
        s = _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type);
-       g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type '%s'\n", s);
-       g_free(s);
+       g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type '%s'\n",
+                s);
+       g_free (s);
        for (n = 0; n < 3; n++)
          {
            const gchar *k;
index 2193ea6,7c88a4e..a9d75d4
mode 100755,100644..100755
  #include "gasyncinitable.h"
  #include "giostream.h"
  #include "gasyncresult.h"
- #include "gsimpleasyncresult.h"
+ #include "gtask.h"
  
  #ifdef G_OS_UNIX
 +#include "gkdbus.h"
  #include "gunixconnection.h"
  #include "gunixfdmessage.h"
  #endif
@@@ -1513,26 -1444,12 +1485,21 @@@ g_dbus_connection_close (GDBusConnectio
    if (!check_initialized (connection))
      return;
  
-   simple = g_simple_async_result_new (G_OBJECT (connection),
-                                       callback,
-                                       user_data,
-                                       g_dbus_connection_close);
-   g_simple_async_result_set_check_cancellable (simple, cancellable);
 -  g_assert (connection->worker != NULL);
--
+   task = g_task_new (connection, cancellable, callback, user_data);
+   g_task_set_source_tag (task, g_dbus_connection_close);
 -  _g_dbus_worker_close (connection->worker, task);
 +  if (connection->worker)
 +    {
-       _g_dbus_worker_close (connection->worker, cancellable, simple);
++      _g_dbus_worker_close (connection->worker, task);
 +    }
 +#ifdef G_OS_UNIX
 +  else if (connection->kdbus_worker)
 +    {
-       _g_kdbus_worker_close (connection->kdbus_worker, cancellable, simple);
++      _g_kdbus_worker_close (connection->kdbus_worker, task);
 +    }
 +#endif
 +  else
 +    g_assert_not_reached();
-   g_object_unref (simple);
+   g_object_unref (task);
  }
  
  /**
@@@ -2661,64 -1901,42 +2590,44 @@@ g_dbus_connection_send_message_with_rep
    if (out_serial == NULL)
      out_serial = &serial;
  
-   simple = g_simple_async_result_new (G_OBJECT (connection),
-                                       callback,
-                                       user_data,
-                                       g_dbus_connection_send_message_with_reply);
-   g_simple_async_result_set_check_cancellable (simple, cancellable);
 -  if (timeout_msec == -1)
 -    timeout_msec = 25 * 1000;
 -
+   data = g_slice_new0 (SendMessageData);
+   task = g_task_new (connection, cancellable, callback, user_data);
+   g_task_set_source_tag (task,
+                          g_dbus_connection_send_message_with_reply_unlocked);
+   g_task_set_task_data (task, data, (GDestroyNotify) send_message_data_free);
  
-   if (g_cancellable_is_cancelled (cancellable))
+   if (g_task_return_error_if_cancelled (task))
      {
-       g_simple_async_result_set_error (simple,
-                                        G_IO_ERROR,
-                                        G_IO_ERROR_CANCELLED,
-                                        _("Operation was cancelled"));
-       g_simple_async_result_complete_in_idle (simple);
-       g_object_unref (simple);
-       goto out;
+       g_object_unref (task);
+       return;
      }
  
-   error = NULL;
 -  if (!g_dbus_connection_send_message_unlocked (connection, message, flags, out_serial, &error))
 +  if (!g_dbus_connection_send_message_unlocked (connection, message, flags, out_serial, &error, timeout_msec))
      {
-       g_simple_async_result_take_error (simple, error);
-       g_simple_async_result_complete_in_idle (simple);
-       g_object_unref (simple);
-       goto out;
+       g_task_return_error (task, error);
+       g_object_unref (task);
+       return;
      }
-   data = g_new0 (SendMessageData, 1);
-   data->ref_count = 1;
-   data->connection = g_object_ref (connection);
-   data->simple = simple;
    data->serial = *out_serial;
-   data->main_context = g_main_context_ref_thread_default ();
  
    if (cancellable != NULL)
      {
-       data->cancellable = g_object_ref (cancellable);
        data->cancellable_handler_id = g_cancellable_connect (cancellable,
                                                              G_CALLBACK (send_message_with_reply_cancelled_cb),
-                                                             send_message_data_ref (data),
-                                                             (GDestroyNotify) send_message_data_unref);
+                                                             g_object_ref (task),
+                                                             g_object_unref);
      }
  
 -  if (timeout_msec != G_MAXINT)
 +  if (timeout_msec != G_MAXINT
 +#ifdef G_OS_UNIX
 +        /* Userspace timeouts unnecessary on unix/kdbus - kdbus handles timeouts. */
 +        && !connection->kdbus_worker
 +#endif
 +     )
      {
 -      data->timeout_source = g_timeout_source_new (timeout_msec);
 +      data->timeout_source = g_timeout_source_new (timeout_msec == -1 ? DBUS_DEFAULT_TIMEOUT_MSEC : timeout_msec);
-       g_source_set_priority (data->timeout_source, G_PRIORITY_DEFAULT);
-       g_source_set_callback (data->timeout_source,
-                              send_message_with_reply_timeout_cb,
-                              send_message_data_ref (data),
-                              (GDestroyNotify) send_message_data_unref);
-       g_source_attach (data->timeout_source, data->main_context);
+       g_task_attach_source (task, data->timeout_source,
+                             (GSourceFunc) send_message_with_reply_timeout_cb);
        g_source_unref (data->timeout_source);
      }
  
@@@ -2931,100 -2134,32 +2825,100 @@@ g_dbus_connection_send_message_with_rep
    g_return_val_if_fail (timeout_msec >= 0 || timeout_msec == -1, NULL);
    g_return_val_if_fail (error == NULL || *error == NULL, NULL);
  
-   reply = NULL;
 -  data.res = NULL;
 -  data.context = g_main_context_new ();
 -  data.loop = g_main_loop_new (data.context, FALSE);
 +  if (connection->worker)
 +    {
-       data = g_new0 (SendMessageSyncData, 1);
-       data->context = g_main_context_new ();
-       data->loop = g_main_loop_new (data->context, FALSE);
++      data.res = NULL;
++      data.context = g_main_context_new ();
++      data.loop = g_main_loop_new (data.context, FALSE);
  
-       g_main_context_push_thread_default (data->context);
 -  g_main_context_push_thread_default (data.context);
++      g_main_context_push_thread_default (data.context);
  
 -  g_dbus_connection_send_message_with_reply (connection,
 -                                             message,
 -                                             flags,
 -                                             timeout_msec,
 -                                             out_serial,
 -                                             cancellable,
 -                                             (GAsyncReadyCallback) send_message_with_reply_sync_cb,
 -                                             &data);
 -  g_main_loop_run (data.loop);
 -  reply = g_dbus_connection_send_message_with_reply_finish (connection,
 -                                                            data.res,
 -                                                            error);
 +      g_dbus_connection_send_message_with_reply (connection,
 +                                                 message,
 +                                                 flags,
 +                                                 timeout_msec,
 +                                                 out_serial,
 +                                                 cancellable,
 +                                                 (GAsyncReadyCallback) send_message_with_reply_sync_cb,
-                                                  data);
-       g_main_loop_run (data->loop);
++                                                 &data);
++      g_main_loop_run (data.loop);
 +      reply = g_dbus_connection_send_message_with_reply_finish (connection,
-                                                                 data->res,
++                                                                data.res,
 +                                                                error);
 +
-       g_main_context_pop_thread_default (data->context);
++      g_main_context_pop_thread_default (data.context);
 +
-       g_main_context_unref (data->context);
-       g_main_loop_unref (data->loop);
-       g_object_unref (data->res);
-       g_free (data);
++      g_main_context_unref (data.context);
++      g_main_loop_unref (data.loop);
++      if (data.res)
++        g_object_unref (data.res);
 +    }
 +#ifdef G_OS_UNIX
 +  else if (connection->kdbus_worker)
 +    {
 +      /* kdbus supports blocking synchronous calls, so let's use them instead of mainloops */
 +
 +      volatile guint32 serial;
 +      guint32 serial_to_use;
  
 -  g_main_context_pop_thread_default (data.context);
++      reply = NULL;
++
 +      CONNECTION_LOCK (connection);
 +
 +      if (out_serial == NULL)
 +        out_serial = &serial;
 +      else
 +        *out_serial = 0;
  
 -  g_main_context_unref (data.context);
 -  g_main_loop_unref (data.loop);
 -  if (data.res)
 -    g_object_unref (data.res);
 +      /*
 +       * Check that we never actually send a message if the GCancellable
 +       * is already cancelled
 +       */
 +      if (g_cancellable_is_cancelled (cancellable))
 +        {
 +          g_set_error_literal (error,
 +                               G_IO_ERROR,
 +                               G_IO_ERROR_CANCELLED,
 +                               _("Operation was cancelled"));
 +          CONNECTION_UNLOCK (connection);
 +          goto out;
 +        }
  
 +      if (!check_unclosed (connection,
 +                           (flags & SEND_MESSAGE_FLAGS_INITIALIZING) ? MAY_BE_UNINITIALIZED : 0,
 +                           error))
 +        {
 +          CONNECTION_UNLOCK (connection);
 +          goto out;
 +        }
 +
 +      if (!(flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL))
 +        g_dbus_message_set_serial (message, ++connection->last_serial);
 +
 +      serial_to_use = g_dbus_message_get_serial (message);
 +
 +      g_dbus_message_lock (message);
 +
 +      if (out_serial != NULL)
 +        *out_serial = serial_to_use;
 +
 +      CONNECTION_UNLOCK (connection);
 +
 +      /* Reference is still kept for the connection, so there is no worry
 +       * that it will be freed. Same for connection->kdbus_worker - by reference
 +       * from the connection. Inside _g_kdbus_worker_send_message_sync only
 +       * initialized-once, read-only fields from kdbus_worker are used, except
 +       * 'matches', which now has got its own mutex.
 +       */
 +      _g_kdbus_worker_send_message_sync (connection->kdbus_worker, message,
 +                                         &reply, timeout_msec, cancellable, error);
 +
 +    }
 +#endif /* G_OS_UNIX */
 +  else
 +    g_assert_not_reached ();
 +
 +out:
    return reply;
  }
  
@@@ -3042,11 -2172,52 +2931,51 @@@ typedef struc
    GDBusMessageFilterFunction  filter_function;
    gpointer                    user_data;
    GDestroyNotify              user_data_free_func;
+   GMainContext               *context;
  } FilterData;
  
+ /* requires CONNECTION_LOCK */
+ static FilterData **
+ copy_filter_list (GPtrArray *filters)
+ {
+   FilterData **copy;
+   guint n;
+   copy = g_new (FilterData *, filters->len + 1);
+   for (n = 0; n < filters->len; n++)
+     {
+       copy[n] = filters->pdata[n];
+       copy[n]->ref_count++;
+     }
+   copy[n] = NULL;
+   return copy;
+ }
+ /* requires CONNECTION_LOCK */
+ static void
+ free_filter_list (FilterData **filters)
+ {
+   guint n;
+   for (n = 0; filters[n]; n++)
+     {
+       filters[n]->ref_count--;
+       if (filters[n]->ref_count == 0)
+         {
+           call_destroy_notify (filters[n]->context,
+                                filters[n]->user_data_free_func,
+                                filters[n]->user_data);
+           g_main_context_unref (filters[n]->context);
+           g_free (filters[n]);
+         }
+     }
+   g_free (filters);
+ }
  /* Called in GDBusWorker's thread - we must not block - with no lock held */
  static void
 -on_worker_message_received (GDBusWorker  *worker,
 -                            GDBusMessage *message,
 +on_worker_message_received (GDBusMessage *message,
                              gpointer      user_data)
  {
    GDBusConnection *connection;
@@@ -4383,10 -3480,8 +4347,10 @@@ g_dbus_connection_signal_subscribe_with
    subscriber.callback = callback;
    subscriber.user_data = user_data;
    subscriber.user_data_free_func = user_data_free_func;
-   subscriber.id = _global_subscriber_id++; /* TODO: overflow etc. */
+   subscriber.id = g_atomic_int_add (&_global_subscriber_id, 1); /* TODO: overflow etc. */
    subscriber.context = g_main_context_ref_thread_default ();
 +  subscriber.user_data_ref_func = user_data_ref_func;
 +  subscriber.user_data_unref_func = user_data_unref_func;
  
    /* see if we've already have this rule */
    signal_data = g_hash_table_lookup (connection->map_rule_to_signal_data, rule);
@@@ -5596,9 -4618,9 +5560,9 @@@ handle_get_all_properties (GDBusConnect
        GDBusMessage *reply;
        reply = g_dbus_message_new_method_error (message,
                                                 "org.freedesktop.DBus.Error.InvalidArgs",
-                                                _("No such interface"),
+                                                _("No such interface '%s'"),
                                                 interface_name);
 -      g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
 +      g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
        g_object_unref (reply);
        handled = TRUE;
        goto out;
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc gio/gioenums.h
Simple merge
diff --cc gio/gkdbus.c
index 03d1f54,0000000..4549dfe
mode 100755,000000..100755
--- /dev/null
@@@ -1,3871 -1,0 +1,3870 @@@
-                        GCancellable       *cancellable,
-                        GSimpleAsyncResult *result)
 +/* GIO - GLib Input, Output and Streaming Library
 + *
 + * Copyright (C) 2015 Samsung Electronics
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) any later version.
 + *
 + * This library 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General
 + * Public License along with this library; if not, write to the
 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 + * Boston, MA 02111-1307, USA.
 + *
 + * Author: Lukasz Skalski       <l.skalski@samsung.com>
 + * Author: Adrian Szyndela      <adrian.s@samsung.com>
 + * Author: Michal Eljasiewicz   <m.eljasiewic@samsung.com>
 + */
 +
 +#include "config.h"
 +#include "gdbusconnection.h" /* DBUS_DEFAULT_TIMEOUT_MSEC */
 +#include "gkdbus.h"
 +#include "glib-unix.h"
 +#include "glib-linux.h"
 +#include "glibintl.h"
 +#include "kdbus.h"
 +
 +#include <gio/gio.h>
 +#include <errno.h>
 +#include <string.h>
 +#include <sys/mman.h>
 +#include <sys/ioctl.h>
 +#include <stdio.h>
 +#include <stdint.h>
 +
 +#ifdef HAVE_SYS_FILIO_H
 +#include <sys/filio.h>
 +#endif
 +
 +#ifdef HAVE_SYS_UIO_H
 +#include <sys/uio.h>
 +#endif
 +
 +#ifdef LIBDBUSPOLICY
 +#include <dbuspolicy/libdbuspolicy1.h>
 +#endif
 +
 +#define DBUS_DAEMON_EMULATION
 +#ifdef DBUS_DAEMON_EMULATION
 +#include "gkdbusfakedaemon.h"
 +#endif
 +
 +#include <glib/gstdio.h>
 +#include <glib/glib-private.h>
 +#include <gio/gio.h>
 +#include <gio/gunixfdlist.h>
 +
 +#include "glibintl.h"
 +#include "gunixfdmessage.h"
 +
 +#define KDBUS_MSG_MAX_SIZE         8192
 +#define KDBUS_INFINITE_TIMEOUT_NS   0x3fffffffffffffffLLU
 +
 +#define RECEIVE_POOL_SIZE_DEFAULT_SIZE    (16 * 1024LU * 1024LU)
 +#define RECEIVE_POOL_SIZE_ENV_VAR_NAME    "KDBUS_MEMORY_POOL_SIZE"
 +#define RECEIVE_POOL_SIZE_MAX_MBYTES      64
 +#define RECEIVE_POOL_SIZE_MIN_KBYTES      16
 +
 +#define KDBUS_MEMFD_THRESHOLD      (512 * 1024LU)
 +
 +#define KDBUS_ALIGN8(l)            (((l) + 7) & ~7)
 +#define KDBUS_ALIGN8_PTR(p)        ((void*) (uintptr_t)(p))
 +
 +#define KDBUS_ITEM_HEADER_SIZE G_STRUCT_OFFSET(struct kdbus_item, data)
 +#define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE)
 +
 +#define KDBUS_ITEM_NEXT(item) \
 +        (typeof(item))(((guint8 *)item) + KDBUS_ALIGN8((item)->size))
 +#define KDBUS_ITEM_FOREACH(item, head, first)                    \
 +        for (item = (head)->first;                               \
 +             (guint8 *)(item) < (guint8 *)(head) + (head)->size; \
 +             item = KDBUS_ITEM_NEXT(item))
 +#define KDBUS_FOREACH(iter, first, _size)                             \
 +        for (iter = (first);                                          \
 +             ((guint8 *)(iter) < (guint8 *)(first) + (_size)) &&      \
 +               ((guint8 *)(iter) >= (guint8 *)(first));               \
 +             iter = (void*)(((guint8 *)iter) + KDBUS_ALIGN8((iter)->size)))
 +
 +#define g_alloca0(x) memset(g_alloca(x), '\0', (x))
 +
 +struct dbus_fixed_header {
 +  guint8  endian;
 +  guint8  type;
 +  guint8  flags;
 +  guint8  version;
 +  guint32 reserved;
 +  guint64 serial;
 +};
 +
 +#define DBUS_FIXED_HEADER_TYPE     ((const GVariantType *) "(yyyyut)")
 +#define DBUS_EXTENDED_HEADER_TYPE  ((const GVariantType *) "a{tv}")
 +#define DBUS_MESSAGE_TYPE          ((const GVariantType *) "((yyyyut)a{tv}v)")
 +
 +/*
 + * Macros for SipHash algorithm
 + */
 +
 +#define ROTL(x,b) (guint64)( ((x) << (b)) | ( (x) >> (64 - (b))) )
 +
 +#define U32TO8_LE(p, v)         \
 +    (p)[0] = (guint8)((v)      ); (p)[1] = (guint8)((v) >>  8); \
 +    (p)[2] = (guint8)((v) >> 16); (p)[3] = (guint8)((v) >> 24);
 +
 +#define U64TO8_LE(p, v)         \
 +  U32TO8_LE((p),     (guint32)((v)      ));   \
 +  U32TO8_LE((p) + 4, (guint32)((v) >> 32));
 +
 +#define U8TO64_LE(p) \
 +  (((guint64)((p)[0])      ) | \
 +   ((guint64)((p)[1]) <<  8) | \
 +   ((guint64)((p)[2]) << 16) | \
 +   ((guint64)((p)[3]) << 24) | \
 +   ((guint64)((p)[4]) << 32) | \
 +   ((guint64)((p)[5]) << 40) | \
 +   ((guint64)((p)[6]) << 48) | \
 +   ((guint64)((p)[7]) << 56))
 +
 +#define SIPROUND            \
 +  do {              \
 +    v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \
 +    v2 += v3; v3=ROTL(v3,16); v3 ^= v2;     \
 +    v0 += v3; v3=ROTL(v3,21); v3 ^= v0;     \
 +    v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \
 +  } while(0)
 +
 +typedef GObjectClass GKDBusWorkerClass;
 +
 +struct _GKDBusWorker
 +{
 +  GObject            parent_instance;
 +
 +  gint               fd;
 +
 +  GMainContext      *context;
 +  GMainLoop         *loop;
 +  GThread           *thread;
 +  GSource           *source;
 +
 +  gchar             *kdbus_buffer;
 +  guint64           receive_pool_size;
 +  gchar             *unique_name;
 +  guint64            unique_id;
 +
 +  guint64            flags;
 +  guint64            attach_flags_send;
 +  guint64            attach_flags_recv;
 +
 +  gsize              bloom_size;
 +  guint              bloom_n_hash;
 +
 +  guint              closed : 1;
 +  guint              inited : 1;
 +  guint              timeout;
 +  guint              timed_out : 1;
 +
 +  guchar             bus_id[16];
 +
 +  GMutex             matches_mutex;
 +  GList             *matches;
 +
 +#ifdef LIBDBUSPOLICY
 +  void              *dbuspolicy;
 +#endif
 +
 +  GDBusCapabilityFlags                     capabilities;
 +  GDBusWorkerMessageReceivedCallback       message_received_callback;
 +  GDBusWorkerMessageAboutToBeSentCallback  message_about_to_be_sent_callback;
 +  GDBusWorkerDisconnectedCallback          disconnected_callback;
 +  gpointer                                 user_data;
 +};
 +
 +static gboolean  _g_kdbus_send    (GKDBusWorker  *worker,
 +                                   GDBusMessage  *message,
 +                                   GDBusMessage **reply,
 +                                   gint           timeout_msec,
 +                                   GCancellable  *cancellable,
 +                                   GError       **error);
 +
 +static void      _g_kdbus_receive (GKDBusWorker  *worker,
 +                                   GError       **error);
 +
 +G_DEFINE_TYPE (GKDBusWorker, g_kdbus_worker, G_TYPE_OBJECT)
 +
 +/* Hash keys for bloom filters*/
 +const guint8 hash_keys[8][16] =
 +{
 +  {0xb9,0x66,0x0b,0xf0,0x46,0x70,0x47,0xc1,0x88,0x75,0xc4,0x9c,0x54,0xb9,0xbd,0x15},
 +  {0xaa,0xa1,0x54,0xa2,0xe0,0x71,0x4b,0x39,0xbf,0xe1,0xdd,0x2e,0x9f,0xc5,0x4a,0x3b},
 +  {0x63,0xfd,0xae,0xbe,0xcd,0x82,0x48,0x12,0xa1,0x6e,0x41,0x26,0xcb,0xfa,0xa0,0xc8},
 +  {0x23,0xbe,0x45,0x29,0x32,0xd2,0x46,0x2d,0x82,0x03,0x52,0x28,0xfe,0x37,0x17,0xf5},
 +  {0x56,0x3b,0xbf,0xee,0x5a,0x4f,0x43,0x39,0xaf,0xaa,0x94,0x08,0xdf,0xf0,0xfc,0x10},
 +  {0x31,0x80,0xc8,0x73,0xc7,0xea,0x46,0xd3,0xaa,0x25,0x75,0x0f,0x9e,0x4c,0x09,0x29},
 +  {0x7d,0xf7,0x18,0x4b,0x7b,0xa4,0x44,0xd5,0x85,0x3c,0x06,0xe0,0x65,0x53,0x96,0x6d},
 +  {0xf2,0x77,0xe9,0x6f,0x93,0xb5,0x4e,0x71,0x9a,0x0c,0x34,0x88,0x39,0x25,0xbf,0x35}
 +};
 +
 +enum {
 +  MATCH_ELEMENT_TYPE,
 +  MATCH_ELEMENT_SENDER,
 +  MATCH_ELEMENT_INTERFACE,
 +  MATCH_ELEMENT_MEMBER,
 +  MATCH_ELEMENT_PATH,
 +  MATCH_ELEMENT_PATH_NAMESPACE,
 +  MATCH_ELEMENT_DESTINATION,
 +  MATCH_ELEMENT_ARG0NAMESPACE,
 +  MATCH_ELEMENT_EAVESDROP,
 +  MATCH_ELEMENT_ARGN,
 +  MATCH_ELEMENT_ARGNPATH,
 +};
 +
 +static guint64 _global_match_cookie = 1;
 +
 +/* MatchElement struct */
 +typedef struct {
 +  guint16 type;
 +  guint16 arg;
 +  char *value;
 +} MatchElement;
 +
 +/* Match struct */
 +typedef struct {
 +  int n_elements;
 +  MatchElement *elements;
 +  guint64 cookie;
 +} Match;
 +
 +
 +/*
 + * SipHash algorithm
 + */
 +static void
 +_g_siphash24 (guint8         out[8],
 +              const void    *_in,
 +              gsize          inlen,
 +              const guint8   k[16])
 +{
 +  /* "somepseudorandomlygeneratedbytes" */
 +  guint64 v0 = 0x736f6d6570736575ULL;
 +  guint64 v1 = 0x646f72616e646f6dULL;
 +  guint64 v2 = 0x6c7967656e657261ULL;
 +  guint64 v3 = 0x7465646279746573ULL;
 +  guint64 b;
 +  guint64 k0 = U8TO64_LE (k);
 +  guint64 k1 = U8TO64_LE (k + 8);
 +  guint64 m;
 +  const guint8 *in = _in;
 +  const guint8 *end = in + inlen - (inlen % sizeof(guint64));
 +  const int left = inlen & 7;
 +  b = ((guint64) inlen) << 56;
 +  v3 ^= k1;
 +  v2 ^= k0;
 +  v1 ^= k1;
 +  v0 ^= k0;
 +
 +  for (; in != end; in += 8)
 +    {
 +      m = U8TO64_LE (in);
 +      v3 ^= m;
 +      SIPROUND;
 +      SIPROUND;
 +      v0 ^= m;
 +    }
 +
 +  switch (left)
 +    {
 +      case 7: b |= ((guint64) in[6]) << 48;
 +      case 6: b |= ((guint64) in[5]) << 40;
 +      case 5: b |= ((guint64) in[4]) << 32;
 +      case 4: b |= ((guint64) in[3]) << 24;
 +      case 3: b |= ((guint64) in[2]) << 16;
 +      case 2: b |= ((guint64) in[1]) <<  8;
 +      case 1: b |= ((guint64) in[0]); break;
 +      case 0: break;
 +    }
 +
 +  v3 ^= b;
 +  SIPROUND;
 +  SIPROUND;
 +  v0 ^= b;
 +
 +  v2 ^= 0xff;
 +  SIPROUND;
 +  SIPROUND;
 +  SIPROUND;
 +  SIPROUND;
 +  b = v0 ^ v1 ^ v2  ^ v3;
 +  U64TO8_LE (out, b);
 +}
 +
 +/* ---------------------------------------------------------------------------------------------------- */
 +
 +static gboolean
 +is_key (const char *key_start, const char *key_end, char *value)
 +{
 +  gsize len = strlen (value);
 +
 +  if (len != key_end - key_start)
 +    return FALSE;
 +
 +  return strncmp (key_start, value, len) == 0;
 +}
 +
 +static gboolean
 +parse_key (MatchElement *element, const char *key_start, const char *key_end)
 +{
 +  gboolean res = TRUE;
 +
 +  if (is_key (key_start, key_end, "type"))
 +    {
 +      element->type = MATCH_ELEMENT_TYPE;
 +    }
 +  else if (is_key (key_start, key_end, "sender"))
 +    {
 +      element->type = MATCH_ELEMENT_SENDER;
 +    }
 +  else if (is_key (key_start, key_end, "interface"))
 +    {
 +      element->type = MATCH_ELEMENT_INTERFACE;
 +    }
 +  else if (is_key (key_start, key_end, "member"))
 +    {
 +      element->type = MATCH_ELEMENT_MEMBER;
 +    }
 +  else if (is_key (key_start, key_end, "path"))
 +    {
 +      element->type = MATCH_ELEMENT_PATH;
 +    }
 +  else if (is_key (key_start, key_end, "path_namespace"))
 +    {
 +      element->type = MATCH_ELEMENT_PATH_NAMESPACE;
 +    }
 +  else if (is_key (key_start, key_end, "destination"))
 +    {
 +      element->type = MATCH_ELEMENT_DESTINATION;
 +    }
 +  else if (is_key (key_start, key_end, "arg0namespace"))
 +    {
 +      element->type = MATCH_ELEMENT_ARG0NAMESPACE;
 +    }
 +  else if (is_key (key_start, key_end, "eavesdrop"))
 +    {
 +      element->type = MATCH_ELEMENT_EAVESDROP;
 +    }
 +  else if (key_end - key_start > 3 && is_key (key_start, key_start + 3, "arg"))
 +    {
 +      const char *digits = key_start + 3;
 +      const char *end_digits = digits;
 +
 +      while (end_digits < key_end && g_ascii_isdigit (*end_digits))
 +        end_digits++;
 +
 +      if (end_digits == key_end) /* argN */
 +        {
 +          element->type = MATCH_ELEMENT_ARGN;
 +          element->arg = atoi (digits);
 +        }
 +      else if (is_key (end_digits, key_end, "path")) /* argNpath */
 +        {
 +          element->type = MATCH_ELEMENT_ARGNPATH;
 +          element->arg = atoi (digits);
 +        }
 +      else
 +        res = FALSE;
 +    }
 +  else
 +    res = FALSE;
 +
 +  return res;
 +}
 +
 +static const char *
 +parse_value (MatchElement *element, const char *s)
 +{
 +  char quote_char;
 +  GString *value;
 +
 +  value = g_string_new ("");
 +
 +  quote_char = 0;
 +
 +  for (;*s; s++)
 +    {
 +      if (quote_char == 0)
 +        {
 +          switch (*s)
 +            {
 +            case '\'':
 +              quote_char = '\'';
 +              break;
 +
 +            case ',':
 +              s++;
 +              goto out;
 +
 +            case '\\':
 +              quote_char = '\\';
 +              break;
 +
 +            default:
 +              g_string_append_c (value, *s);
 +              break;
 +            }
 +        }
 +      else if (quote_char == '\\')
 +        {
 +          /* \ only counts as an escape if escaping a quote mark */
 +          if (*s != '\'')
 +            g_string_append_c (value, '\\');
 +
 +          g_string_append_c (value, *s);
 +          quote_char = 0;
 +        }
 +      else /* quote_char == ' */
 +        {
 +          if (*s == '\'')
 +            quote_char = 0;
 +          else
 +            g_string_append_c (value, *s);
 +        }
 +    }
 +
 + out:
 +  if (quote_char == '\\')
 +    g_string_append_c (value, '\\');
 +  else if (quote_char == '\'')
 +    {
 +      g_string_free (value, TRUE);
 +      return NULL;
 +    }
 +
 +  element->value = g_string_free (value, FALSE);
 +  return s;
 +}
 +
 +static Match *
 +match_new (const char *str)
 +{
 +  Match *match;
 +  GArray *elements;
 +  const char *p;
 +  const char *key_start;
 +  const char *key_end;
 +  MatchElement element;
 +  int i;
 +
 +  elements = g_array_new (TRUE, TRUE, sizeof (MatchElement));
 +
 +  p = str;
 +
 +  while (*p != 0)
 +    {
 +      memset (&element, 0, sizeof (element));
 +
 +      /* Skip initial whitespace */
 +      while (*p && g_ascii_isspace (*p))
 +        p++;
 +
 +      key_start = p;
 +
 +      /* Read non-whitespace non-equals chars */
 +      while (*p && *p != '=' && !g_ascii_isspace (*p))
 +        p++;
 +
 +      key_end = p;
 +
 +      /* Skip any whitespace after key */
 +      while (*p && g_ascii_isspace (*p))
 +        p++;
 +
 +      if (key_start == key_end)
 +        continue; /* Allow trailing whitespace */
 +      if (*p != '=')
 +        goto error;
 +
 +      ++p;
 +
 +      if (!parse_key (&element, key_start, key_end))
 +        goto error;
 +
 +      p = parse_value (&element, p);
 +      if (p == NULL)
 +        goto error;
 +
 +      g_array_append_val (elements, element);
 +    }
 +
 +  match = g_new0 (Match, 1);
 +  match->n_elements = elements->len;
 +  match->elements = (MatchElement *)g_array_free (elements, FALSE);
 +  match->cookie = _global_match_cookie++;
 +
 +  return match;
 +
 + error:
 +  for (i = 0; i < elements->len; i++)
 +    g_free (g_array_index (elements, MatchElement, i).value);
 +  g_array_free (elements, TRUE);
 +  return NULL;
 +}
 +
 +static gboolean
 +match_equal (Match *a, Match *b)
 +{
 +  int i;
 +
 +  if (a->n_elements != b->n_elements)
 +    return FALSE;
 +
 +  for (i = 0; i < a->n_elements; i++)
 +    {
 +      if (a->elements[i].type != b->elements[i].type ||
 +          a->elements[i].arg != b->elements[i].arg ||
 +          strcmp (a->elements[i].value, b->elements[i].value) != 0)
 +        return FALSE;
 +    }
 +
 +  return TRUE;
 +}
 +
 +static void
 +match_free (Match *match)
 +{
 +  int i;
 +
 +  for (i = 0; i < match->n_elements; i++)
 +    g_free (match->elements[i].value);
 +
 +  g_free (match->elements);
 +  g_free (match);
 +}
 +
 +/* ---------------------------------------------------------------------------------------------------- */
 +
 +/*
 + * _g_kdbus_open
 + */
 +gboolean
 +_g_kdbus_open (GKDBusWorker  *worker,
 +               const gchar   *address,
 +               GError       **error)
 +{
 +  g_return_val_if_fail (G_IS_KDBUS_WORKER (worker), FALSE);
 +  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 +
 +  worker->fd = g_open(address, O_RDWR|O_NOCTTY|O_CLOEXEC, 0);
 +  if (worker->fd<0)
 +    {
 +      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot open kdbus endpoint"));
 +      return FALSE;
 +    }
 +
 +#ifdef LIBDBUSPOLICY
 +  worker->dbuspolicy = dbuspolicy1_init (address);
 +  if (worker->dbuspolicy == NULL)
 +    {
 +      close (worker->fd);
 +      worker->fd = -1;
 +
 +      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot load dbus policy for kdbus transport"));
 +      return FALSE;
 +    }
 +#endif
 +
 +  worker->closed = FALSE;
 +  return TRUE;
 +}
 +
 +static gboolean
 +_g_kdbus_quit_loop (gpointer loop)
 +{
 +  g_main_loop_quit ((GMainLoop*)loop);
 +  return FALSE;
 +}
 +
 +/*
 + * _g_kdbus_close
 + */
 +gboolean
 +_g_kdbus_close (GKDBusWorker *worker)
 +{
 +  g_return_val_if_fail (G_IS_KDBUS_WORKER (worker), FALSE);
 +
 +  if (worker->closed)
 +    return TRUE;
 +
 +  g_main_context_invoke (worker->context, _g_kdbus_quit_loop, worker->loop);
 +
 +  g_main_context_unref (worker->context);
 +  worker->context = NULL;
 +
 +  g_main_loop_unref (worker->loop);
 +
 +  g_thread_unref(worker->thread);
 +
 +  worker->thread = NULL;
 +
 +  close (worker->fd);
 +  worker->fd = -1;
 +
 +  worker->closed = TRUE;
 +  return TRUE;
 +}
 +
 +/*
 + * _g_kdbus_is_closed
 + */
 +gboolean
 +_g_kdbus_is_closed (GKDBusWorker *worker)
 +{
 +  g_return_val_if_fail (G_IS_KDBUS_WORKER (worker), FALSE);
 +
 +  return worker->closed;
 +}
 +
 +static void
 +g_kdbus_free_data (GKDBusWorker  *worker,
 +                   guint64        offset)
 +{
 +  struct kdbus_cmd_free cmd = {
 +    .size = sizeof(cmd),
 +    .offset = offset,
 +    .flags = 0
 +  };
 +
 +  if (ioctl (worker->fd, KDBUS_CMD_FREE, &cmd) < 0)
 +    {
 +      g_error ("kdbus: invalid KDBUS_CMD_FREE ioctl : %" G_GUINT64_FORMAT " offset\n", offset);
 +    }
 +}
 +
 +static void
 +g_kdbus_close_msg (GKDBusWorker      *worker,
 +                   struct kdbus_msg  *msg)
 +{
 +  guint64 offset;
 +
 +  offset = (guint8 *)msg - (guint8 *)worker->kdbus_buffer;
 +  g_kdbus_free_data (worker, offset);
 +}
 +
 +
 +/*
 + * g_kdbus_translate_nameowner_flags
 + */
 +static void
 +g_kdbus_translate_nameowner_flags (GBusNameOwnerFlags   flags,
 +                                   guint64             *kdbus_flags)
 +{
 +  guint64 new_flags;
 +
 +  new_flags = 0;
 +
 +  if (flags & G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT)
 +    new_flags |= KDBUS_NAME_ALLOW_REPLACEMENT;
 +
 +  if (flags & G_BUS_NAME_OWNER_FLAGS_REPLACE)
 +    new_flags |= KDBUS_NAME_REPLACE_EXISTING;
 +
 +  if (!(flags & G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE))
 +    new_flags |= KDBUS_NAME_QUEUE;
 +
 +  *kdbus_flags = new_flags;
 +}
 +
 +/* ---------------------------------------------------------------------------------------------------- */
 +
 +/* < internal >
 + *
 + * _g_kdbus_Hello:
 + *
 + * Gets the unique name.
 + *
 + * Returns: the unique name or NULL. Do not free this string,
 + * it is owned by GKDBusWorker.
 + */
 +const gchar *
 +_g_kdbus_Hello (GKDBusWorker  *worker,
 +                GError       **error)
 +{
 +  struct kdbus_cmd_hello *cmd;
 +  struct kdbus_bloom_parameter *bloom;
 +  struct kdbus_item *item, *items;
 +
 +  gchar *conn_name;
 +  size_t size, conn_name_size;
 +
 +  const gchar *env_pool;
 +  guint64 receive_pool_size = RECEIVE_POOL_SIZE_DEFAULT_SIZE;
 +
 +  conn_name = "gdbus-kdbus";
 +  conn_name_size = strlen (conn_name);
 +
 +  size = KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_cmd_hello, items)) +
 +         KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_item, str) + conn_name_size + 1);
 +
 +  cmd = g_alloca0 (size);
 +  cmd->flags = worker->flags;
 +  cmd->attach_flags_send = worker->attach_flags_send;
 +  cmd->attach_flags_recv = worker->attach_flags_recv;
 +  cmd->size = size;
 +
 +  env_pool = getenv (RECEIVE_POOL_SIZE_ENV_VAR_NAME);
 +  if(env_pool)
 +    {
 +      guint64 size;
 +      guint32 multiply = 1;
 +      gint64 page_size;
 +
 +      page_size = sysconf(_SC_PAGESIZE);
 +      if(page_size == -1)
 +        {
 +          size = 0;
 +          goto finish;
 +        }
 +
 +      errno = 0;
 +      size = strtoul(env_pool, (char**)&env_pool, 10);
 +      if(errno == EINVAL || size == 0)
 +        {
 +          size = 0;
 +          goto finish;
 +        }
 +
 +      if(*env_pool == 'k')
 +        {
 +          multiply = 1024;
 +          env_pool++;
 +        }
 +      else if (*env_pool == 'M')
 +        {
 +          multiply = 1024 * 1024;
 +          env_pool++;
 +        }
 +
 +      if(*env_pool != '\0')
 +        {
 +          size = 0;
 +          goto finish;
 +        }
 +
 +      receive_pool_size = size * multiply;
 +
 +      if((receive_pool_size > RECEIVE_POOL_SIZE_MAX_MBYTES * 1024 * 1024) ||
 +         (receive_pool_size < RECEIVE_POOL_SIZE_MIN_KBYTES * 1024) ||
 +         ((receive_pool_size & (page_size - 1)) != 0))
 +        size = 0;
 +
 +    finish:
 +      if(size == 0)
 +        {
 +          g_warning ("%s value is invalid, default value %luB will be used.", RECEIVE_POOL_SIZE_ENV_VAR_NAME,
 +                     RECEIVE_POOL_SIZE_DEFAULT_SIZE);
 +          g_warning ("Correct value must be between %ukB and %uMB and must be aligned to page size: %" G_GINT64_FORMAT "B.",
 +                     RECEIVE_POOL_SIZE_MIN_KBYTES, RECEIVE_POOL_SIZE_MAX_MBYTES, page_size);
 +
 +          receive_pool_size = RECEIVE_POOL_SIZE_DEFAULT_SIZE;
 +        }
 +    }
 +
 +  g_debug ("[KDBUS] receive pool size set to %" G_GUINT64_FORMAT "\n", receive_pool_size);
 +  worker->receive_pool_size = receive_pool_size; 
 +  cmd->pool_size = worker->receive_pool_size;
 +  
 +  item = cmd->items;
 +  item->size = G_STRUCT_OFFSET (struct kdbus_item, str) + conn_name_size + 1;
 +  item->type = KDBUS_ITEM_CONN_DESCRIPTION;
 +  memcpy (item->str, conn_name, conn_name_size+1);
 +  item = KDBUS_ITEM_NEXT (item);
 +
 +  if (worker->unique_id != -1)
 +    {
 +      g_set_error (error, G_DBUS_ERROR,
 +                   G_DBUS_ERROR_FAILED,
 +                   "Already handled an Hello message");
 +      return NULL;
 +    }
 +
 +  if (ioctl(worker->fd, KDBUS_CMD_HELLO, cmd))
 +    {
 +      g_set_error (error, G_IO_ERROR,
 +                   g_io_error_from_errno (errno),
 +                   _("Failed to send HELLO: %s"),
 +                   g_strerror (errno));
 +      return NULL;
 +    }
 +
 +  worker->kdbus_buffer = mmap(NULL, worker->receive_pool_size, PROT_READ, MAP_SHARED, worker->fd, 0);
 +  if (worker->kdbus_buffer == MAP_FAILED)
 +    {
 +      g_set_error (error, G_IO_ERROR,
 +                   g_io_error_from_errno (errno),
 +                   _("mmap error: %s"),
 +                   g_strerror (errno));
 +      return NULL;
 +    }
 +
 +  if (cmd->bus_flags > 0xFFFFFFFFULL)
 +    {
 +      g_set_error_literal (error,
 +                           G_IO_ERROR,
 +                           G_IO_ERROR_FAILED,
 +                           _("Incompatible HELLO flags"));
 +      return NULL;
 +    }
 +
 +  memcpy (worker->bus_id, cmd->id128, 16);
 +
 +  worker->unique_id = cmd->id;
 +  asprintf (&worker->unique_name, ":1.%llu", (unsigned long long) cmd->id);
 +
 +  /* read bloom filters parameters */
 +  bloom = NULL;
 +  items = (void*)(worker->kdbus_buffer + cmd->offset);
 +  KDBUS_FOREACH(item, items, cmd->items_size)
 +    {
 +      switch (item->type)
 +        {
 +          case KDBUS_ITEM_BLOOM_PARAMETER:
 +            bloom = &item->bloom_parameter;
 +          break;
 +        }
 +    }
 +
 +  if (bloom != NULL)
 +    {
 +      worker->bloom_size = (gsize) bloom->size;
 +      worker->bloom_n_hash = (guint) bloom->n_hash;
 +    }
 +  else
 +    {
 +      g_set_error_literal (error,
 +                           G_IO_ERROR,
 +                           G_IO_ERROR_FAILED,
 +                           _("Can't read bloom filter parameters"));
 +      return NULL;
 +    }
 +
 +  g_kdbus_free_data (worker, cmd->offset);
 +
 +  return worker->unique_name;
 +}
 +
 +
 +/* < internal >
 + *
 + * _g_kdbus_RequestName:
 + *
 + * Synchronously acquires name on the bus and returns status code
 + * from the GBusRequestNameReplyFlags enumeration.
 + *
 + * Returns: status code or G_BUS_REQUEST_NAME_FLAGS_ERROR
 + * if error is set.
 + */
 +GBusRequestNameReplyFlags
 +_g_kdbus_RequestName (GKDBusWorker        *worker,
 +                      const gchar         *name,
 +                      GBusNameOwnerFlags   flags,
 +                      GError             **error)
 +{
 +  GBusRequestNameReplyFlags status;
 +  struct kdbus_cmd *cmd;
 +  guint64 kdbus_flags;
 +  gssize len, size;
 +  gint ret;
 +
 +  status = G_BUS_REQUEST_NAME_FLAGS_PRIMARY_OWNER;
 +
 +  if (!g_dbus_is_name (name))
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_INVALID_ARGS,
 +                   "Given bus name \"%s\" is not valid", name);
 +      return G_BUS_REQUEST_NAME_FLAGS_ERROR;
 +    }
 +
 +  if (g_strcmp0 (name, "org.freedesktop.DBus") == 0)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_INVALID_ARGS,
 +                   "Cannot acquire a service named '%s', because that is reserved", name);
 +      return G_BUS_REQUEST_NAME_FLAGS_ERROR;
 +    }
 +
 +  if (*name == ':')
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_INVALID_ARGS,
 +                   "Cannot acquire a service starting with ':' such as \"%s\"", name);
 +      return G_BUS_REQUEST_NAME_FLAGS_ERROR;
 +    }
 +
 +#ifdef LIBDBUSPOLICY
 +  if (worker->dbuspolicy != NULL)
 +    {
 +      if (dbuspolicy1_can_own (worker->dbuspolicy, name) != 1)
 +        {
 +          g_set_error (error,
 +                       G_DBUS_ERROR,
 +                       G_DBUS_ERROR_ACCESS_DENIED,
 +                       "Connection \"%s\" is not allowed to own the "
 +                       "service \"%s\" due to security policies", worker->unique_name, name);
 +          return G_BUS_REQUEST_NAME_FLAGS_ERROR;
 +        }
 +    }
 +#endif
 +
 +  g_kdbus_translate_nameowner_flags (flags, &kdbus_flags);
 +
 +  len = strlen(name) + 1;
 +  size = G_STRUCT_OFFSET (struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(len);
 +  cmd = g_alloca0 (size);
 +  cmd->size = size;
 +  cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
 +  cmd->items[0].type = KDBUS_ITEM_NAME;
 +  cmd->flags = kdbus_flags;
 +  memcpy (cmd->items[0].str, name, len);
 +
 +  ret = ioctl(worker->fd, KDBUS_CMD_NAME_ACQUIRE, cmd);
 +  if (ret < 0)
 +    {
 +      if (errno == EEXIST)
 +        status = G_BUS_REQUEST_NAME_FLAGS_EXISTS;
 +      else if (errno == EALREADY)
 +        status = G_BUS_REQUEST_NAME_FLAGS_ALREADY_OWNER;
 +      else
 +        {
 +          g_set_error (error, G_IO_ERROR,
 +                       g_io_error_from_errno (errno),
 +                       _("Error while acquiring name: %s"),
 +                       g_strerror (errno));
 +          return G_BUS_REQUEST_NAME_FLAGS_ERROR;
 +        }
 +    }
 +  else if ((cmd->return_flags & KDBUS_NAME_PRIMARY)
 +      && !(cmd->return_flags & KDBUS_NAME_ACQUIRED))
 +    status = G_BUS_REQUEST_NAME_FLAGS_ALREADY_OWNER;
 +
 +  if (cmd->return_flags & KDBUS_NAME_IN_QUEUE)
 +    status = G_BUS_REQUEST_NAME_FLAGS_IN_QUEUE;
 +
 +  return status;
 +}
 +
 +
 +/* < internal >
 + *
 + * _g_kdbus_ReleaseName:
 + *
 + * Synchronously releases name on the bus and returns status code
 + * from the GBusReleaseNameReplyFlags enumeration.
 + *
 + * Returns: status code or G_BUS_RELEASE_NAME_FLAGS_ERROR
 + * if error is set.
 + */
 +GBusReleaseNameReplyFlags
 +_g_kdbus_ReleaseName (GKDBusWorker  *worker,
 +                      const gchar   *name,
 +                      GError       **error)
 +{
 +  GBusReleaseNameReplyFlags status;
 +  struct kdbus_cmd *cmd;
 +  gssize len, size;
 +  gint ret;
 +
 +  status = G_BUS_RELEASE_NAME_FLAGS_RELEASED;
 +
 +  if (!g_dbus_is_name (name))
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_INVALID_ARGS,
 +                   "Given bus name \"%s\" is not valid", name);
 +      return G_BUS_RELEASE_NAME_FLAGS_ERROR;
 +    }
 +
 +  if (g_strcmp0 (name, "org.freedesktop.DBus") == 0)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_INVALID_ARGS,
 +                   "Cannot release a service named '%s', because that is owned by the bus", name);
 +      return G_BUS_RELEASE_NAME_FLAGS_ERROR;
 +    }
 +
 +  if (*name == ':')
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_INVALID_ARGS,
 +                   "Cannot release a service starting with ':' such as \"%s\"", name);
 +      return G_BUS_RELEASE_NAME_FLAGS_ERROR;
 +    }
 +
 +  len = strlen(name) + 1;
 +  size = G_STRUCT_OFFSET (struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(len);
 +  cmd = g_alloca0 (size);
 +  cmd->size = size;
 +  cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
 +  cmd->items[0].type = KDBUS_ITEM_NAME;
 +  memcpy (cmd->items[0].str, name, len);
 +
 +  ret = ioctl(worker->fd, KDBUS_CMD_NAME_RELEASE, cmd);
 +  if (ret < 0)
 +    {
 +      if (errno == ESRCH)
 +        status = G_BUS_RELEASE_NAME_FLAGS_NON_EXISTENT;
 +      else if (errno == EADDRINUSE)
 +        status = G_BUS_RELEASE_NAME_FLAGS_NOT_OWNER;
 +      else
 +        {
 +          g_set_error (error, G_IO_ERROR,
 +                       g_io_error_from_errno (errno),
 +                       _("Error while releasing name: %s"),
 +                       g_strerror (errno));
 +          return G_BUS_RELEASE_NAME_FLAGS_ERROR;
 +        }
 +    }
 +
 +  return status;
 +}
 +
 +
 +/* < internal >
 + *
 + * _g_kdbus_GetBusId:
 + *
 + * Synchronously returns the unique ID of the bus.
 + *
 + * Returns: the unique ID of the bus or NULL if error is set.
 + * Free with g_free().
 + */
 +gchar *
 +_g_kdbus_GetBusId (GKDBusWorker  *worker,
 +                   GError       **error)
 +{
 +  GString  *result;
 +  guint     cnt;
 +
 +  result = g_string_new (NULL);
 +
 +  for (cnt=0; cnt<16; cnt++)
 +    g_string_append_printf (result, "%02x", worker->bus_id[cnt]);
 +
 +  return g_string_free (result, FALSE);
 +}
 +
 +
 +static void
 +expand_strv (gchar  ***strv_ptr,
 +             gchar    *value)
 +{
 +  gchar **strv;
 +  guint strv_len;
 +
 +  if (!value)
 +    return;
 +
 +  strv = *strv_ptr;
 +  strv_len = g_strv_length (strv);
 +
 +  strv = g_renew (gchar *, strv, strv_len + 2);
 +  strv[strv_len] = value;
 +  strv[strv_len + 1] = NULL;
 +
 +  *strv_ptr = strv;
 +}
 +
 +
 +/* < internal >
 + *
 + * _g_kdbus_GetListNames:
 + *
 + * Synchronously returns a list of:
 + *   - all currently-owned names on the bus (activatable = FALSE),
 + *   - all names that can be activated on the bus (activatable = TRUE),
 + *
 + * or NULL if error is set. Free with g_strfreev().
 + */
 +gchar **
 +_g_kdbus_GetListNames (GKDBusWorker  *worker,
 +                       gboolean       activatable,
 +                       GError       **error)
 +{
 +  struct kdbus_info *name_list, *name;
 +  struct kdbus_cmd_list cmd = {
 +    .size = sizeof(cmd)
 +  };
 +
 +  gchar **listnames;
 +  guint64 prev_id;
 +  gint ret;
 +
 +  prev_id = 0;
 +
 +  if (activatable)
 +    cmd.flags = KDBUS_LIST_ACTIVATORS;                /* ListActivatableNames */
 +  else
 +    cmd.flags = KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES; /* ListNames */
 +
 +  ret = ioctl(worker->fd, KDBUS_CMD_LIST, &cmd);
 +  if (ret < 0)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_FAILED,
 +                   _("Error listing names"));
 +      return NULL;
 +    }
 +
 +  listnames = g_new0 (gchar *, 1);
 +  name_list = (struct kdbus_info *) ((guint8 *) worker->kdbus_buffer + cmd.offset);
 +
 +  KDBUS_FOREACH (name, name_list, cmd.list_size)
 +    {
 +      struct kdbus_item *item;
 +
 +      if ((cmd.flags & KDBUS_LIST_UNIQUE) && name->id != prev_id)
 +        {
 +          gchar *unique_name;
 +
 +          asprintf (&unique_name, ":1.%llu", name->id);
 +          expand_strv (&listnames, unique_name);
 +          prev_id = name->id;
 +        }
 +
 +       KDBUS_ITEM_FOREACH (item, name, items)
 +         {
 +           if (item->type == KDBUS_ITEM_OWNED_NAME)
 +             {
 +               if (g_dbus_is_name (item->name.name))
 +                 expand_strv (&listnames, g_strdup (item->name.name));
 +             }
 +         }
 +    }
 +
 +  /* org.freedesktop.DBus.ListNames */
 +  if (!activatable)
 +    expand_strv (&listnames, g_strdup ("org.freedesktop.DBus"));
 +
 +  g_kdbus_free_data (worker, cmd.offset);
 +
 +  return listnames;
 +}
 +
 +
 +static gboolean
 +g_kdbus_NameHasOwner_internal (GKDBusWorker  *worker,
 +                               const gchar   *name)
 +{
 +  struct kdbus_cmd_info *cmd;
 +  struct kdbus_info *conn_info;
 +  gssize size, len;
 +  gint ret;
 +
 +  if (g_dbus_is_unique_name(name))
 +    {
 +       size = G_STRUCT_OFFSET (struct kdbus_cmd_info, items);
 +       cmd = g_alloca0 (size);
 +       cmd->id = g_ascii_strtoull (name+3, NULL, 10);
 +    }
 +  else
 +    {
 +       len = strlen(name) + 1;
 +       size = G_STRUCT_OFFSET (struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(len);
 +       cmd = g_alloca0 (size);
 +       cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
 +       cmd->items[0].type = KDBUS_ITEM_NAME;
 +       memcpy (cmd->items[0].str, name, len);
 +    }
 +  cmd->size = size;
 +
 +  ret = ioctl(worker->fd, KDBUS_CMD_CONN_INFO, cmd);
 +  if (ret < 0)
 +    return FALSE;
 +
 +  conn_info = (struct kdbus_info *) ((guint8 *) worker->kdbus_buffer + cmd->offset);
 +
 +  if (conn_info->flags & KDBUS_HELLO_ACTIVATOR)
 +    ret = -1;
 +
 +  g_kdbus_free_data (worker, cmd->offset);
 +
 +  if (ret < 0)
 +    return FALSE;
 +  else
 +    return TRUE;
 +}
 +
 +
 +/* < internal >
 + *
 + * _g_kdbus_GetListQueuedOwners:
 + *
 + * Synchronously returns the unique bus names of connections currently
 + * queued for the name.
 + *
 + * Returns: the unique bus names of connections currently queued for the
 + * 'name' or NULL if error is set. Free with g_strfreev().
 + */
 +gchar **
 +_g_kdbus_GetListQueuedOwners (GKDBusWorker  *worker,
 +                              const gchar   *name,
 +                              GError       **error)
 +{
 +  struct kdbus_info *name_list, *kname;
 +  struct kdbus_cmd_list cmd = {
 +    .size = sizeof(cmd),
 +    .flags = KDBUS_LIST_QUEUED
 +  };
 +
 +  gchar **queued_owners;
 +  gint ret;
 +
 +  if (!g_dbus_is_name (name))
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_INVALID_ARGS,
 +                   "Given bus name \"%s\" is not valid", name);
 +      return NULL;
 +    }
 +
 +  if (!g_kdbus_NameHasOwner_internal (worker, name))
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_NAME_HAS_NO_OWNER,
 +                   "Could not get owner of name '%s': no such name", name);
 +      return NULL;
 +    }
 +
 +  ret = ioctl(worker->fd, KDBUS_CMD_LIST, &cmd);
 +  if (ret < 0)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_FAILED,
 +                   _("Error listing names"));
 +      return NULL;
 +    }
 +
 +  queued_owners = g_new0 (gchar *, 1);
 +  name_list = (struct kdbus_info *) ((guint8 *) worker->kdbus_buffer + cmd.offset);
 +
 +  KDBUS_FOREACH(kname, name_list, cmd.list_size)
 +    {
 +      struct kdbus_item *item;
 +
 +      KDBUS_ITEM_FOREACH(item, kname, items)
 +        {
 +          if (item->type == KDBUS_ITEM_OWNED_NAME)
 +            {
 +              gchar *unique_name;
 +
 +              if (strcmp(item->name.name, name))
 +                continue;
 +
 +              if (asprintf (&unique_name, ":1.%llu", kname->id) != -1)
 +                expand_strv (&queued_owners, unique_name);
 +            }
 +        }
 +    }
 +
 +  g_kdbus_free_data (worker, cmd.offset);
 +
 +  return queued_owners;
 +}
 +
 +
 +/* < internal >
 + *
 + * _g_kdbus_NameHasOwner:
 + *
 + * Checks if the specified name exists (currently has an owner).
 + *
 + * Returns: TRUE if the name exists and FALSE when name doesn't exists
 + * or error is set.
 + */
 +gboolean
 +_g_kdbus_NameHasOwner (GKDBusWorker  *worker,
 +                       const gchar   *name,
 +                       GError       **error)
 +{
 +  if (!g_dbus_is_name (name))
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_INVALID_ARGS,
 +                   "Given bus name \"%s\" is not valid", name);
 +      return FALSE;
 +    }
 +
 +  if (g_strcmp0 (name, "org.freedesktop.DBus") == 0)
 +    return  TRUE;
 +
 +  if (!g_kdbus_NameHasOwner_internal (worker, name))
 +    return FALSE; /* Don't make g_set_error, otherwise NameHasOwner will fail. */
 +  else
 +    return TRUE;
 +}
 +
 +
 +GDBusCredentials *
 +_g_kdbus_GetConnInfo (GKDBusWorker  *worker,
 +                      const gchar   *name,
 +                      guint          flags,
 +                      GError       **error)
 +{
 +  GDBusCredentials *creds;
 +  struct kdbus_cmd_info *cmd;
 +  struct kdbus_info *conn_info;
 +  struct kdbus_item *item;
 +  gssize size, len;
 +  gint ret;
 +
 +  creds = g_new0 (GDBusCredentials, 1);
 +
 +  if (!g_dbus_is_name (name))
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_INVALID_ARGS,
 +                   "Given bus name \"%s\" is not valid", name);
 +      goto error;
 +    }
 +
 +  if (!g_kdbus_NameHasOwner_internal (worker, name))
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_NAME_HAS_NO_OWNER,
 +                   "Could not get owner of name '%s': no such name", name);
 +      goto error;
 +    }
 +
 +  if (g_dbus_is_unique_name(name))
 +    {
 +       size = G_STRUCT_OFFSET (struct kdbus_cmd_info, items);
 +       cmd = g_alloca0 (size);
 +       cmd->id = g_ascii_strtoull (name+3, NULL, 10);
 +    }
 +  else
 +    {
 +       len = strlen(name) + 1;
 +       size = G_STRUCT_OFFSET (struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(len);
 +       cmd = g_alloca0 (size);
 +       cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
 +       cmd->items[0].type = KDBUS_ITEM_NAME;
 +       memcpy (cmd->items[0].str, name, len);
 +    }
 +
 +  cmd->attach_flags = _KDBUS_ATTACH_ALL;
 +  cmd->size = size;
 +
 +  ret = ioctl(worker->fd, KDBUS_CMD_CONN_INFO, cmd);
 +  if (ret < 0)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_FAILED,
 +                   _("Could not get connection info"));
 +      goto error;
 +    }
 +
 +  conn_info = (struct kdbus_info *) ((guint8 *) worker->kdbus_buffer + cmd->offset);
 +
 +  if (flags & G_DBUS_CREDS_UNIQUE_NAME)
 +    {
 +       asprintf (&creds->unique_name, ":1.%llu", (unsigned long long) conn_info->id);
 +       //TODO: Error handling
 +    }
 +
 +  KDBUS_ITEM_FOREACH(item, conn_info, items)
 +   {
 +      switch (item->type)
 +        {
 +          case KDBUS_ITEM_PIDS:
 +            if (flags & G_DBUS_CREDS_PID)
 +              creds->pid = item->pids.pid;
 +          break;
 +
 +          case KDBUS_ITEM_CREDS:
 +            if (flags & G_DBUS_CREDS_UID)
 +              creds->uid = item->creds.uid;
 +          break;
 +
 +          case KDBUS_ITEM_SECLABEL:
 +            if (flags & G_DBUS_CREDS_SEC_LABEL)
 +              creds->sec_label = g_strdup (item->str);
 +          break;
 +
 +          case KDBUS_ITEM_PID_COMM:
 +          case KDBUS_ITEM_TID_COMM:
 +          case KDBUS_ITEM_EXE:
 +          case KDBUS_ITEM_CMDLINE:
 +          case KDBUS_ITEM_CGROUP:
 +          case KDBUS_ITEM_CAPS:
 +          case KDBUS_ITEM_AUDIT:
 +          case KDBUS_ITEM_CONN_DESCRIPTION:
 +          case KDBUS_ITEM_AUXGROUPS:
 +          case KDBUS_ITEM_OWNED_NAME:
 +            break;
 +        }
 +   }
 +
 +  g_kdbus_free_data (worker, cmd->offset);
 +  return creds;
 +
 +error:
 +  g_free (creds->unique_name);
 +  g_free (creds->sec_label);
 +  g_free (creds);
 +  return NULL;
 +}
 +
 +
 +/* < internal >
 + *
 + * _g_kdbus_GetNameOwner:
 + *
 + * Synchronously returns the unique connection name of the primary owner of
 + * the name given. If the requested name doesn't have an owner, an error is
 + * returned.
 + *
 + * Returns: the unique connection name of the primary owner of the
 + * name given. If the requested name doesn't have an owner, function
 + * returns NULL and error is set. Free with g_free().
 + */
 +gchar *
 +_g_kdbus_GetNameOwner (GKDBusWorker  *worker,
 +                       const gchar   *name,
 +                       GError       **error)
 +{
 +  GDBusCredentials *creds;
 +  gchar *unique_name;
 +  guint flags;
 +
 +  creds = NULL;
 +  unique_name = NULL;
 +
 +  if (g_strcmp0 (name, "org.freedesktop.DBus") == 0)
 +    return g_strdup (name);
 +
 +  flags = G_DBUS_CREDS_UNIQUE_NAME;
 +  creds = _g_kdbus_GetConnInfo (worker,
 +                                name,
 +                                flags,
 +                                error);
 +  if (creds != NULL)
 +    {
 +      unique_name = creds->unique_name;
 +      g_free (creds);
 +    }
 +
 +  return unique_name;
 +}
 +
 +
 +/* < internal >
 + *
 + * _g_kdbus_GetConnectionUnixProcessID:
 + *
 + * Synchronously returns the Unix process ID of the process connected to the
 + * bus. If unable to determine it, an error is returned.
 + *
 + * If name contains a value not compatible with the D-Bus syntax and naming
 + * conventions for bus names, the operation returns -1 and error is set.
 + *
 + * Returns: the Unix process ID of the process connected to the bus or -1
 + * if error is set.
 + */
 +pid_t
 +_g_kdbus_GetConnectionUnixProcessID (GKDBusWorker  *worker,
 +                                     const gchar   *name,
 +                                     GError       **error)
 +{
 +  GDBusCredentials *creds;
 +  guint flags;
 +  pid_t pid;
 +
 +  creds = NULL;
 +  pid = -1;
 +
 +  flags = G_DBUS_CREDS_PID;
 +  creds = _g_kdbus_GetConnInfo (worker,
 +                                name,
 +                                flags,
 +                                error);
 +  if (creds != NULL)
 +    {
 +      pid = creds->pid;
 +      g_free (creds);
 +    }
 +
 +  return pid;
 +}
 +
 +
 +/* < internal >
 + *
 + * _g_kdbus_GetConnectionUnixUser:
 + *
 + * Synchronously returns the Unix user ID of the process connected to the
 + * bus. If unable to determine it, an error is returned.
 + *
 + * If name contains a value not compatible with the D-Bus syntax and naming
 + * conventions for bus names, the operation returns -1 and error is set.
 + *
 + * Returns: the Unix user ID of the process connected to the bus or -1
 + * if error is set.
 + */
 +uid_t
 +_g_kdbus_GetConnectionUnixUser (GKDBusWorker  *worker,
 +                                const gchar   *name,
 +                                GError       **error)
 +{
 +  GDBusCredentials *creds;
 +  guint flags;
 +  uid_t uid;
 +
 +  creds = NULL;
 +  uid = -1;
 +
 +  flags = G_DBUS_CREDS_UID;
 +  creds = _g_kdbus_GetConnInfo (worker,
 +                                name,
 +                                flags,
 +                                error);
 +  if (creds != NULL)
 +    {
 +      uid = creds->uid;
 +      g_free (creds);
 +    }
 +
 +  return uid;
 +}
 +
 +
 +/* < internal >
 + *
 + * _g_kdbus_GetConnectionSecurityLabel:
 + *
 + * Synchronously returns security label of the process connected to the bus.
 + *
 + * If name contains a value not compatible with the D-Bus syntax and naming
 + * conventions for bus names, the operation returns -1 and error is set.
 + *
 + * Returns: security label of the process connected to the bus or -1
 + */
 +gchar *
 +_g_kdbus_GetConnectionSecurityLabel (GKDBusWorker  *worker,
 +                                     const gchar   *name,
 +                                     GError       **error)
 +{
 +  GDBusCredentials *creds;
 +  gchar *sec_label;
 +  guint flags;
 +
 +  creds = NULL;
 +  sec_label = NULL;
 +
 +  flags = G_DBUS_CREDS_SEC_LABEL;
 +  creds = _g_kdbus_GetConnInfo (worker,
 +                                name,
 +                                flags,
 +                                error);
 +  if (creds != NULL)
 +    {
 +      sec_label = creds->sec_label;
 +      g_free (creds);
 +    }
 +
 +  return sec_label;
 +}
 +
 +
 +/* < internal >
 + *
 + * _g_kdbus_StartServiceByName:
 + *
 + * Synchronously tries to launch the executable associated
 + * with a name.
 + *
 + * Returns: status code or G_BUS_START_SERVICE_REPLY_ERROR
 +   if error is set.
 + */
 +GBusStartServiceReplyFlags
 +_g_kdbus_StartServiceByName (GKDBusWorker  *worker,
 +                             const gchar   *name,
 +                             guint32        flags,
 +                             GError       **error)
 +{
 +  GBusStartServiceReplyFlags status;
 +
 +  if (!g_dbus_is_name (name))
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_INVALID_ARGS,
 +                   "Given bus name \"%s\" is not valid", name);
 +      return G_BUS_START_SERVICE_REPLY_ERROR;
 +    }
 +
 +  if (g_strcmp0 (name, "org.freedesktop.DBus") == 0)
 +    return G_BUS_START_SERVICE_REPLY_ALREADY_RUNNING;
 +
 +  if (!g_kdbus_NameHasOwner_internal (worker, name))
 +    {
 +      GDBusMessage *message;
 +      GDBusMessage *reply;
 +      gint ret;
 +
 +      reply = NULL;
 +
 +      message = g_dbus_message_new_method_call (name, "/", "org.freedesktop.DBus.Peer", "Ping");
 +      g_dbus_message_set_serial (message, -1);
 +
 +      ret = _g_kdbus_send (worker, message, &reply, 25000, NULL, NULL);
 +      if (!ret)
 +        {
 +          g_set_error (error,
 +                       G_DBUS_ERROR,
 +                       G_DBUS_ERROR_SERVICE_UNKNOWN,
 +                       "The name %s was not provided by any .service files", name);
 +          return G_BUS_START_SERVICE_REPLY_ERROR;
 +        }
 +      g_object_unref (reply);
 +      status = G_BUS_START_SERVICE_REPLY_SUCCESS;
 +    }
 +  else
 +    status = G_BUS_START_SERVICE_REPLY_ALREADY_RUNNING;
 +
 +  return status;
 +}
 +
 +
 +/*
 + * g_kdbus_bloom_add_data:
 + * Based on bus-bloom.c from systemd
 + * http://cgit.freedesktop.org/systemd/systemd/tree/src/libsystemd/sd-bus/bus-bloom.c
 + */
 +static void
 +g_kdbus_bloom_add_data (GKDBusWorker  *worker,
 +                        guint64        bloom_data[],
 +                        const void    *data,
 +                        gsize          n)
 +{
 +  guint8 hash[8];
 +  guint64 bit_num;
 +  guint bytes_num = 0;
 +  guint cnt_1, cnt_2;
 +  guint hash_index = 0;
 +
 +  guint c = 0;
 +  guint64 p = 0;
 +
 +  bit_num = (guint64)worker->bloom_size * 8;
 +
 +  if (bit_num > 1)
 +    bytes_num = ((__builtin_clzll(bit_num) ^ 63U) + 7) / 8;
 +
 +  for (cnt_1 = 0; cnt_1 < (worker->bloom_n_hash); cnt_1++)
 +    {
 +      for (cnt_2 = 0, hash_index = 0; cnt_2 < bytes_num; cnt_2++)
 +        {
 +          if (c <= 0)
 +            {
 +              _g_siphash24(hash, data, n, hash_keys[hash_index++]);
 +              c += 8;
 +            }
 +
 +          p = (p << 8ULL) | (guint64) hash[8 - c];
 +          c--;
 +        }
 +
 +      p &= bit_num - 1;
 +      bloom_data[p >> 6] |= 1ULL << (p & 63);
 +    }
 +}
 +
 +static void
 +g_kdbus_bloom_add_pair (GKDBusWorker  *worker,
 +                        guint64        bloom_data[],
 +                        const gchar   *parameter,
 +                        const gchar   *value)
 +{
 +  gchar buf[1024];
 +  gsize size;
 +
 +  size = strlen(parameter) + strlen(value) + 1;
 +  if (size >= 1024)
 +    return;
 +
 +  strcpy(stpcpy(stpcpy(buf, parameter), ":"), value);
 +  g_kdbus_bloom_add_data(worker, bloom_data, buf, size);
 +}
 +
 +static void
 +g_kdbus_bloom_add_prefixes (GKDBusWorker  *worker,
 +                            guint64        bloom_data[],
 +                            const gchar   *parameter,
 +                            const gchar   *value,
 +                            gchar          separator)
 +{
 +  gchar buf[1024];
 +  gsize size;
 +
 +  size = strlen(parameter) + strlen(value) + 1;
 +  if (size >= 1024)
 +    return;
 +
 +  strcpy(stpcpy(stpcpy(buf, parameter), ":"), value);
 +
 +  for (;;)
 +    {
 +      gchar *last_sep;
 +      last_sep = strrchr(buf, separator);
 +      if (!last_sep || last_sep == buf)
 +        break;
 +
 +      *last_sep = 0;
 +      g_kdbus_bloom_add_data(worker, bloom_data, buf, last_sep-buf);
 +    }
 +}
 +
 +
 +/* < internal >
 + *
 + * _g_kdbus_AddMatch:
 + *
 + * Synchronously adds a match rule to match messages.
 + *
 + * Returns: TRUE if the operation succeeded, FALSE
 + * if error is set.
 + *
 + */
 +gboolean
 +_g_kdbus_AddMatch (GKDBusWorker  *worker,
 +                   const gchar   *match_rule,
 +                   GError       **error)
 +{
 +  Match *match;
 +  MatchElement *element;
 +  const gchar *sender_name;
 +  gsize sender_len, size;
 +  struct kdbus_cmd_match *cmd;
 +  struct kdbus_item *item;
 +  guint64 *bloom;
 +  guint64 src_id;
 +  gchar *type;
 +  gint cnt, ret;
 +
 +  if (match_rule[0] == '-')
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_MATCH_RULE_INVALID,
 +                   "Invalid rule: %s", match_rule);
 +      return FALSE;
 +    }
 +
 +  match = match_new (match_rule);
 +  if (!match)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_MATCH_RULE_INVALID,
 +                   "Invalid rule: %s", match_rule);
 +      return FALSE;
 +    }
 +
 +  sender_name = NULL;
 +  src_id = KDBUS_MATCH_ID_ANY;
 +
 +  bloom = g_alloca0 (worker->bloom_size);
 +  size = KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_cmd_match, items));
 +
 +  for (cnt = 0; cnt < match->n_elements; cnt++)
 +    {
 +      element = &match->elements[cnt];
 +      switch (element->type)
 +        {
 +          case MATCH_ELEMENT_SENDER:
 +            if (g_dbus_is_unique_name(element->value))
 +              {
 +                src_id = g_ascii_strtoull ((element->value)+3, NULL, 10);
 +                size += KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_item, id) + sizeof(src_id));
 +              }
 +            else if (g_dbus_is_name (element->value))
 +              {
 +                sender_name = element->value;
 +                sender_len = strlen(element->value) + 1;
 +                size += KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_item, str) + sender_len);
 +              }
 +            else
 +              {
 +                g_set_error (error,
 +                             G_DBUS_ERROR,
 +                             G_DBUS_ERROR_MATCH_RULE_INVALID,
 +                             "Invalid rule: %s", match_rule);
 +                match_free (match);
 +                return FALSE;
 +              }
 +            break;
 +
 +          case MATCH_ELEMENT_TYPE:
 +            g_kdbus_bloom_add_pair (worker, bloom, "message-type", element->value);
 +            break;
 +
 +          case MATCH_ELEMENT_INTERFACE:
 +            g_kdbus_bloom_add_pair (worker, bloom, "interface", element->value);
 +            break;
 +
 +          case MATCH_ELEMENT_MEMBER:
 +            g_kdbus_bloom_add_pair (worker, bloom, "member", element->value);
 +            break;
 +
 +          case MATCH_ELEMENT_PATH:
 +            g_kdbus_bloom_add_pair (worker, bloom, "path", element->value);
 +            break;
 +
 +          case MATCH_ELEMENT_PATH_NAMESPACE:
 +            if (g_strcmp0 (element->value, "/"))
 +              g_kdbus_bloom_add_pair (worker, bloom, "path-slash-prefix", element->value);
 +            break;
 +
 +          case MATCH_ELEMENT_ARGN:
 +            asprintf (&type, "arg%u", element->arg);
 +            g_kdbus_bloom_add_pair (worker, bloom, type, element->value);
 +            free (type);
 +            break;
 +
 +          case MATCH_ELEMENT_ARGNPATH:
 +            asprintf (&type, "arg%u-slash-prefix", element->arg);
 +            g_kdbus_bloom_add_pair (worker, bloom, type, element->value);
 +            free (type);
 +            break;
 +
 +          case MATCH_ELEMENT_ARG0NAMESPACE:
 +            g_kdbus_bloom_add_pair (worker, bloom, "arg0-dot-prefix", element->value);
 +            break;
 +
 +          case MATCH_ELEMENT_DESTINATION:
 +          case MATCH_ELEMENT_EAVESDROP:
 +            break;
 +        }
 +    }
 +
 +  size += KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_item, data64) + worker->bloom_size);
 +  cmd = g_alloca0 (size);
 +  cmd->size = size;
 +  cmd->cookie = match->cookie;
 +
 +  item = cmd->items;
 +  item->size = G_STRUCT_OFFSET(struct kdbus_item, data64) + worker->bloom_size;
 +  item->type = KDBUS_ITEM_BLOOM_MASK;
 +  memcpy(item->data64, bloom, worker->bloom_size);
 +  item = KDBUS_ITEM_NEXT(item);
 +
 +  if (src_id != KDBUS_MATCH_ID_ANY)
 +    {
 +      item->size = G_STRUCT_OFFSET (struct kdbus_item, id) + sizeof(src_id);
 +      item->type = KDBUS_ITEM_ID;
 +      item->id = src_id;
 +      item = KDBUS_ITEM_NEXT(item);
 +    }
 +
 +  if (sender_name)
 +    {
 +      item->size = G_STRUCT_OFFSET (struct kdbus_item, str) + sender_len;
 +      item->type = KDBUS_ITEM_NAME;
 +      memcpy (item->str, sender_name, sender_len);
 +    }
 +
 +  ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
 +  if (ret < 0)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_FAILED,
 +                   "Error while adding a match");
 +      match_free (match);
 +      return FALSE;
 +    }
 +
 +  g_mutex_lock (&worker->matches_mutex);
 +  worker->matches = g_list_prepend (worker->matches, match);
 +  g_mutex_unlock (&worker->matches_mutex);
 +  return TRUE;
 +}
 +
 +
 +/* < internal >
 + *
 + * _g_kdbus_RemoveMatch:
 + *
 + * Synchronously removes the first rule that matches.
 + *
 + * Returns: TRUE if the operation succeeded, FALSE
 + * if error is set.
 + */
 +gboolean
 +_g_kdbus_RemoveMatch (GKDBusWorker  *worker,
 +                      const gchar   *match_rule,
 +                      GError       **error)
 +{
 +  Match *match, *other_match;
 +  GList *matches;
 +  guint64 cookie;
 +
 +  if (match_rule[0] == '-')
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_MATCH_RULE_INVALID,
 +                   "Invalid rule: %s", match_rule);
 +      return FALSE;
 +    }
 +
 +  match = match_new (match_rule);
 +  if (!match)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_MATCH_RULE_INVALID,
 +                   "Invalid rule: %s", match_rule);
 +      return FALSE;
 +    }
 +
 +  g_mutex_lock (&worker->matches_mutex);
 +  for (matches = worker->matches; matches != NULL; matches = matches->next)
 +    {
 +      other_match = matches->data;
 +      if (match_equal (match, other_match))
 +        {
 +          cookie = other_match->cookie;
 +          match_free (other_match);
 +          worker->matches = g_list_delete_link (worker->matches, matches);
 +          break;
 +        }
 +    }
 +  g_mutex_unlock (&worker->matches_mutex);
 +
 +  if (matches == NULL)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
 +                   "The given match rule wasn't found and can't be removed");
 +      match_free (match);
 +      return FALSE;
 +    }
 +  else
 +    {
 +      struct kdbus_cmd_match cmd = {
 +        .size = sizeof(cmd),
 +        .cookie = cookie
 +      };
 +      gint ret;
 +
 +      ret = ioctl(worker->fd, KDBUS_CMD_MATCH_REMOVE, &cmd);
 +      if (ret < 0)
 +        {
 +          if (errno == EBADSLT)
 +            {
 +              g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
 +                           "A match entry with the given cookie could not be found");
 +            }
 +          else
 +            {
 +              g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
 +                           "Error while removing a match");
 +            }
 +          match_free (match);
 +          return FALSE;
 +        }
 +    }
 +
 +  match_free (match);
 +  return TRUE;
 +}
 +
 +
 +/*
 + * _g_kdbus_subscribe_name_owner_changed_internal
 + */
 +static gboolean
 +_g_kdbus_subscribe_name_owner_changed_internal (GKDBusWorker  *worker,
 +                                                const gchar   *name,
 +                                                const gchar   *old_name,
 +                                                const gchar   *new_name,
 +                                                guint64        cookie,
 +                                                GError       **error)
 +{
 +  struct kdbus_item *item;
 +  struct kdbus_cmd_match *cmd;
 +  gssize size, len;
 +  gint ret;
 +  guint64 old_id = 0;
 +  guint64 new_id = KDBUS_MATCH_ID_ANY;
 +
 +  if (name)
 +    len = strlen(name) + 1;
 +  else
 +    len = 0;
 +
 +  size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
 +                      G_STRUCT_OFFSET (struct kdbus_item, name_change) +
 +                      G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
 +
 +  cmd = g_alloca0 (size);
 +  cmd->size = size;
 +  cmd->cookie = cookie;
 +  item = cmd->items;
 +
 +  if (old_name == NULL)
 +    {
 +      old_id = KDBUS_MATCH_ID_ANY;
 +    }
 +  else
 +    {
 +      if (g_dbus_is_unique_name(old_name))
 +        old_id = strtoull (old_name + 3, NULL, 10);
 +      else
 +        return TRUE;
 +    }
 +
 +  if (new_name == NULL)
 +    {
 +      new_id = KDBUS_MATCH_ID_ANY;
 +    }
 +  else
 +    {
 +      if (g_dbus_is_unique_name(new_name))
 +        new_id = strtoull (new_name + 3, NULL, 10);
 +      else
 +        return TRUE;
 +    }
 +
 +  cmd = g_alloca0 (size);
 +  cmd->size = size;
 +  cmd->cookie = cookie;
 +  item = cmd->items;
 +
 +  item->type = KDBUS_ITEM_NAME_CHANGE;
 +  item->name_change.old_id.id = old_id;
 +  item->name_change.new_id.id = new_id;
 +
 +  if (name)
 +    memcpy(item->name_change.name, name, len);
 +
 +  item->size = G_STRUCT_OFFSET (struct kdbus_item, name_change) +
 +               G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len;
 +  item = KDBUS_ITEM_NEXT(item);
 +
 +  ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
 +  if (ret < 0)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_FAILED,
 +                   "Error while adding a match");
 +      return FALSE;
 +    }
 +
 +  return TRUE;
 +}
 +
 +
 +/*
 + * _g_kdbus_subscribe_name_acquired
 + */
 +gboolean
 +_g_kdbus_subscribe_name_acquired (GKDBusWorker  *worker,
 +                                  const gchar   *match_rule,
 +                                  const gchar   *name,
 +                                  GError       **error)
 +{
 +  Match *match;
 +  struct kdbus_item *item;
 +  struct kdbus_cmd_match *cmd;
 +  gssize size, len;
 +  gint ret;
 +
 +  if (match_rule[0] == '-')
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_MATCH_RULE_INVALID,
 +                   "Invalid rule: %s", match_rule);
 +      return FALSE;
 +    }
 +
 +  match = match_new (match_rule);
 +  if (!match)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_MATCH_RULE_INVALID,
 +                   "Invalid rule: %s", match_rule);
 +      return FALSE;
 +    }
 +
 +  if (name)
 +    len = strlen(name) + 1;
 +  else
 +    len = 0;
 +
 +  size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
 +                      G_STRUCT_OFFSET (struct kdbus_item, name_change) +
 +                      G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
 +
 +  cmd = g_alloca0 (size);
 +  cmd->size = size;
 +  cmd->cookie = match->cookie;
 +  item = cmd->items;
 +
 +  item->type = KDBUS_ITEM_NAME_ADD;
 +  item->name_change.old_id.id = KDBUS_MATCH_ID_ANY;
 +  item->name_change.new_id.id = worker->unique_id;
 +
 +  if (name)
 +    memcpy(item->name_change.name, name, len);
 +
 +  item->size = G_STRUCT_OFFSET (struct kdbus_item, name_change) +
 +               G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len;
 +  item = KDBUS_ITEM_NEXT(item);
 +
 +  ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
 +  if (ret < 0)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_FAILED,
 +                   "Error while adding a match");
 +      match_free (match);
 +      return FALSE;
 +    }
 +
 +  if (!_g_kdbus_subscribe_name_owner_changed_internal (worker, name, NULL, worker->unique_name, match->cookie, error))
 +    {
 +      match_free (match);
 +      return FALSE;
 +    }
 +
 +  g_mutex_lock (&worker->matches_mutex);
 +  worker->matches = g_list_prepend (worker->matches, match);
 +  g_mutex_unlock (&worker->matches_mutex);
 +  return TRUE;
 +}
 +
 +
 +/*
 + * _g_kdbus_subscribe_name_lost
 + */
 +gboolean
 +_g_kdbus_subscribe_name_lost (GKDBusWorker  *worker,
 +                              const gchar   *match_rule,
 +                              const gchar   *name,
 +                              GError       **error)
 +{
 +  Match *match;
 +  struct kdbus_item *item;
 +  struct kdbus_cmd_match *cmd;
 +  gssize size, len;
 +  gint ret;
 +
 +  if (match_rule[0] == '-')
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_MATCH_RULE_INVALID,
 +                   "Invalid rule: %s", match_rule);
 +      return FALSE;
 +    }
 +
 +  match = match_new (match_rule);
 +  if (!match)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_MATCH_RULE_INVALID,
 +                   "Invalid rule: %s", match_rule);
 +      return FALSE;
 +    }
 +
 +  if (name)
 +    len = strlen(name) + 1;
 +  else
 +    len = 0;
 +
 +  size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
 +                      G_STRUCT_OFFSET (struct kdbus_item, name_change) +
 +                      G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
 +
 +  cmd = g_alloca0 (size);
 +  cmd->size = size;
 +  cmd->cookie = match->cookie;
 +  item = cmd->items;
 +
 +  item->type = KDBUS_ITEM_NAME_REMOVE;
 +  item->name_change.old_id.id = worker->unique_id;
 +  item->name_change.new_id.id = KDBUS_MATCH_ID_ANY;
 +
 +  if (name)
 +    memcpy(item->name_change.name, name, len);
 +
 +  item->size = G_STRUCT_OFFSET (struct kdbus_item, name_change) +
 +               G_STRUCT_OFFSET(struct kdbus_notify_name_change, name) + len;
 +  item = KDBUS_ITEM_NEXT(item);
 +
 +  ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
 +  if (ret < 0)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_FAILED,
 +                   "Error while adding a match");
 +      match_free (match);
 +      return FALSE;
 +    }
 +
 +  if (!_g_kdbus_subscribe_name_owner_changed_internal (worker, name, worker->unique_name, NULL, match->cookie, error))
 +    {
 +      match_free (match);
 +      return FALSE;
 +    }
 +
 +  g_mutex_lock (&worker->matches_mutex);
 +  worker->matches = g_list_prepend (worker->matches, match);
 +  g_mutex_unlock (&worker->matches_mutex);
 +  return TRUE;
 +}
 +
 +
 +/*
 + * _g_kdbus_subscribe_name_owner_changed
 + */
 +gboolean
 +_g_kdbus_subscribe_name_owner_changed (GKDBusWorker  *worker,
 +                                       const gchar   *match_rule,
 +                                       const gchar   *name,
 +                                       GError       **error)
 +{
 +  Match *match;
 +  struct kdbus_item *item;
 +  struct kdbus_cmd_match *cmd;
 +  gssize size, len;
 +  gint ret;
 +
 +  if (match_rule[0] == '-')
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_MATCH_RULE_INVALID,
 +                   "Invalid rule: %s", match_rule);
 +      return FALSE;
 +    }
 +
 +  match = match_new (match_rule);
 +  if (!match)
 +    {
 +      g_set_error (error,
 +                   G_DBUS_ERROR,
 +                   G_DBUS_ERROR_MATCH_RULE_INVALID,
 +                   "Invalid rule: %s", match_rule);
 +      return FALSE;
 +    }
 +
 +  if (name != NULL)
 +    {
 +      if (!g_dbus_is_name (name))
 +        {
 +          g_set_error (error,
 +                       G_DBUS_ERROR,
 +                       G_DBUS_ERROR_MATCH_RULE_INVALID,
 +                       "Invalid rule: %s", match_rule);
 +          return FALSE;
 +        }
 +    }
 +
 +  /* 'name' argument is missing or is a unique name */
 +  if (name == NULL || g_dbus_is_unique_name (name))
 +    {
 +      size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
 +                          G_STRUCT_OFFSET (struct kdbus_item, id_change) +
 +                          sizeof (struct kdbus_notify_id_change));
 +
 +      cmd = g_alloca0 (size);
 +      cmd->size = size;
 +      cmd->cookie = match->cookie;
 +      item = cmd->items;
 +
 +      if (name)
 +        item->id_change.id = strtoull (name + 3, NULL, 10);
 +      else
 +        item->id_change.id = KDBUS_MATCH_ID_ANY;
 +
 +      item->size = G_STRUCT_OFFSET (struct kdbus_item, id_change) +
 +                   sizeof (struct kdbus_notify_id_change);
 +
 +      item->type = KDBUS_ITEM_ID_ADD;
 +      ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
 +      if (ret < 0)
 +        {
 +          g_set_error (error,
 +                       G_DBUS_ERROR,
 +                       G_DBUS_ERROR_FAILED,
 +                       "Error while adding a match");
 +          match_free (match);
 +          return FALSE;
 +        }
 +
 +      item->type = KDBUS_ITEM_ID_REMOVE;
 +      ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
 +      if (ret < 0)
 +        {
 +          g_set_error (error,
 +                       G_DBUS_ERROR,
 +                       G_DBUS_ERROR_FAILED,
 +                       "Error while adding a match");
 +          match_free (match);
 +          return FALSE;
 +        }
 +    }
 +
 +  /* 'name' argument is missing or is a well-known name */
 +  if (name == NULL || !g_dbus_is_unique_name (name))
 +    {
 +      if (name)
 +        len = strlen(name) + 1;
 +      else
 +        len = 0;
 +
 +      size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
 +                          G_STRUCT_OFFSET (struct kdbus_item, name_change) +
 +                          G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
 +
 +      cmd = g_alloca0 (size);
 +      cmd->size = size;
 +      cmd->cookie = match->cookie;
 +      item = cmd->items;
 +
 +      item->name_change.old_id.id = KDBUS_MATCH_ID_ANY;
 +      item->name_change.new_id.id = KDBUS_MATCH_ID_ANY;
 +      item->size = G_STRUCT_OFFSET (struct kdbus_item, name_change) +
 +                   G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len;
 +
 +      if (name)
 +        memcpy(item->name_change.name, name, len);
 +
 +      item->type = KDBUS_ITEM_NAME_ADD;
 +      ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
 +      if (ret < 0)
 +        {
 +          g_set_error (error,
 +                       G_DBUS_ERROR,
 +                       G_DBUS_ERROR_FAILED,
 +                       "Error while adding a match");
 +          match_free (match);
 +          return FALSE;
 +        }
 +
 +      item->type = KDBUS_ITEM_NAME_REMOVE;
 +      ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
 +      if (ret < 0)
 +        {
 +          g_set_error (error,
 +                       G_DBUS_ERROR,
 +                       G_DBUS_ERROR_FAILED,
 +                       "Error while adding a match");
 +          match_free (match);
 +          return FALSE;
 +        }
 +
 +      item->type = KDBUS_ITEM_NAME_CHANGE;
 +      ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
 +      if (ret < 0)
 +        {
 +          g_set_error (error,
 +                       G_DBUS_ERROR,
 +                       G_DBUS_ERROR_FAILED,
 +                       "Error while adding a match");
 +          match_free (match);
 +          return FALSE;
 +        }
 +    }
 +
 +  g_mutex_lock (&worker->matches_mutex);
 +  worker->matches = g_list_prepend (worker->matches, match);
 +  g_mutex_unlock (&worker->matches_mutex);
 +  return TRUE;
 +}
 +
 +
 +/*
 + * g_kdbus_setup_bloom:
 + * Based on bus-bloom.c from systemd
 + * http://cgit.freedesktop.org/systemd/systemd/tree/src/libsystemd/sd-bus/bus-bloom.c
 + */
 +static void
 +g_kdbus_setup_bloom (GKDBusWorker               *worker,
 +                     GDBusMessage               *dbus_msg,
 +                     struct kdbus_bloom_filter  *bloom_filter)
 +{
 +  GVariant *body;
 +  gchar *message_type;
 +  const gchar *interface;
 +  const gchar *member;
 +  const gchar *path;
 +  void *bloom_data;
 +
 +  body = g_dbus_message_get_body (dbus_msg);
 +  message_type = _g_dbus_enum_to_string (G_TYPE_DBUS_MESSAGE_TYPE, g_dbus_message_get_message_type (dbus_msg));
 +  interface = g_dbus_message_get_interface (dbus_msg);
 +  member = g_dbus_message_get_member (dbus_msg);
 +  path = g_dbus_message_get_path (dbus_msg);
 +
 +  bloom_data = bloom_filter->data;
 +  memset (bloom_data, 0, worker->bloom_size);
 +  bloom_filter->generation = 0;
 +
 +  g_kdbus_bloom_add_pair(worker, bloom_data, "message-type", message_type);
 +
 +  if (interface)
 +    g_kdbus_bloom_add_pair(worker, bloom_data, "interface", interface);
 +
 +  if (member)
 +    g_kdbus_bloom_add_pair(worker, bloom_data, "member", member);
 +
 +  if (path)
 +    {
 +      g_kdbus_bloom_add_pair(worker, bloom_data, "path", path);
 +      g_kdbus_bloom_add_pair(worker, bloom_data, "path-slash-prefix", path);
 +      g_kdbus_bloom_add_prefixes(worker, bloom_data, "path-slash-prefix", path, '/');
 +    }
 +
 +  if (body != NULL)
 +    {
 +      const GVariantType *body_type;
 +      const GVariantType *arg_type;
 +      guint cnt;
 +
 +      body_type = g_variant_get_type (body);
 +
 +      for (arg_type = g_variant_type_first (body_type), cnt = 0;
 +           arg_type;
 +           arg_type = g_variant_type_next (arg_type), cnt++)
 +        {
 +          gchar type_char = g_variant_type_peek_string (arg_type)[0];
 +          gchar buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
 +          const gchar *str;
 +          GVariant *child;
 +          gchar *e;
 +
 +          if (type_char != 's' && type_char != 'o')
 +            /* XXX: kdbus docs say "stop after first non-string" but I
 +             * think they're wrong (vs. dbus-1 compat)...
 +             */
 +            continue;
 +
 +          child = g_variant_get_child_value (body, cnt);
 +          str = g_variant_get_string (child, NULL);
 +
 +          e = stpcpy(buf, "arg");
 +          if (cnt < 10)
 +            *(e++) = '0' + (char) cnt;
 +          else
 +            {
 +              *(e++) = '0' + (char) (cnt / 10);
 +              *(e++) = '0' + (char) (cnt % 10);
 +            }
 +
 +          /* We add this one for both strings and object paths */
 +          strcpy(e, "-slash-prefix");
 +          g_kdbus_bloom_add_prefixes(worker, bloom_data, buf, str, '/');
 +
 +          /* But the others are only for strings */
 +          if (type_char == 's')
 +            {
 +              strcpy(e, "-dot-prefix");
 +              g_kdbus_bloom_add_prefixes(worker, bloom_data, buf, str, '.');
 +
 +              *e = 0;
 +              g_kdbus_bloom_add_pair(worker, bloom_data, buf, str);
 +            }
 +
 +          g_variant_unref (child);
 +        }
 +    }
 +  g_free (message_type);
 +}
 +
 +
 +/*
 + * g_kdbus_translate_id_change
 + */
 +static void
 +g_kdbus_translate_id_change (GKDBusWorker       *worker,
 +                             struct kdbus_item  *item)
 +{
 +  GDBusMessage *signal_message;
 +  gchar *name;
 +
 +  signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
 +                                              "org.freedesktop.DBus",
 +                                              "NameOwnerChanged");
 +
 +  name = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) item->id_change.id);
 +
 +  g_dbus_message_set_sender (signal_message, "org.freedesktop.DBus");
 +  g_dbus_message_set_body (signal_message,
 +                           g_variant_new ("(sss)",
 +                                          name,
 +                                          item->type == KDBUS_ITEM_ID_ADD ? "" : name,
 +                                          item->type == KDBUS_ITEM_ID_ADD ? name : ""));
 +
 +  (* worker->message_received_callback) (signal_message, worker->user_data);
 +
 +  g_free (name);
 +  g_object_unref (signal_message);
 +}
 +
 +
 +/*
 + * g_kdbus_translate_name_change
 + */
 +static void
 +g_kdbus_translate_name_change (GKDBusWorker       *worker,
 +                               struct kdbus_item  *item)
 +{
 +  GDBusMessage *signal_message;
 +
 +  signal_message = NULL;
 +
 +  /* NameAcquired */
 +  if ((item->type == KDBUS_ITEM_NAME_ADD) ||
 +      (item->type == KDBUS_ITEM_NAME_CHANGE && ((guint64)item->name_change.new_id.id == worker->unique_id)))
 +    {
 +      signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
 +                                                  "org.freedesktop.DBus",
 +                                                  "NameAcquired");
 +
 +      g_dbus_message_set_sender (signal_message, "org.freedesktop.DBus");
 +      g_dbus_message_set_body (signal_message,
 +                               g_variant_new ("(s)", item->name_change.name));
 +
 +      (* worker->message_received_callback) (signal_message, worker->user_data);
 +      g_object_unref (signal_message);
 +    }
 +
 +  /* NameLost */
 +  if ((item->type == KDBUS_ITEM_NAME_REMOVE) ||
 +      (item->type == KDBUS_ITEM_NAME_CHANGE && ((guint64)item->name_change.old_id.id == worker->unique_id)))
 +    {
 +      signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
 +                                                  "org.freedesktop.DBus",
 +                                                  "NameLost");
 +
 +      g_dbus_message_set_sender (signal_message, "org.freedesktop.DBus");
 +      g_dbus_message_set_body (signal_message,
 +                               g_variant_new ("(s)", item->name_change.name));
 +
 +      (* worker->message_received_callback) (signal_message, worker->user_data);
 +      g_object_unref (signal_message);
 +    }
 +
 +  /* NameOwnerChanged */
 +  if (1)
 +    {
 +      gchar *old_name;
 +      gchar *new_name;
 +
 +      old_name = NULL;
 +      new_name = NULL;
 +
 +      /* old_name */
 +      if (!(item->type == KDBUS_ITEM_NAME_ADD || (item->name_change.old_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))))
 +        old_name = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) item->name_change.old_id.id);
 +
 +      /* new_name */
 +      if (!(item->type == KDBUS_ITEM_NAME_REMOVE || (item->name_change.new_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))))
 +        new_name = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) item->name_change.new_id.id);
 +      else
 +        if (old_name == NULL)
 +          return;
 +
 +      /* send signal */
 +      signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
 +                                                  "org.freedesktop.DBus",
 +                                                  "NameOwnerChanged");
 +      g_dbus_message_set_sender (signal_message, "org.freedesktop.DBus");
 +      g_dbus_message_set_body (signal_message,
 +                               g_variant_new ("(sss)",
 +                                              item->name_change.name,
 +                                              old_name ? old_name : "",
 +                                              new_name ? new_name : ""));
 +
 +      (* worker->message_received_callback) (signal_message, worker->user_data);
 +
 +      g_free (old_name);
 +      g_free (new_name);
 +      g_object_unref (signal_message);
 +    }
 +}
 +
 +
 +/*
 + * g_kdbus_translate_kernel_reply
 + */
 +static void
 +g_kdbus_translate_kernel_reply (GKDBusWorker       *worker,
 +                                struct kdbus_msg   *msg,
 +                                struct kdbus_item  *item)
 +{
 +  GDBusMessage *message;
 +
 +  message = g_dbus_message_new ();
 +
 +  g_dbus_message_set_message_type (message, G_DBUS_MESSAGE_TYPE_ERROR);
 +  g_dbus_message_set_flags (message, G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED);
 +  g_dbus_message_set_reply_serial (message, (guint32) msg->cookie_reply);
 +
 +  g_dbus_message_set_sender (message, "org.freedesktop.DBus");
 +  g_dbus_message_set_destination (message, worker->unique_name);
 +
 +  g_dbus_message_set_error_name (message, "org.freedesktop.DBus.Error.NoReply");
 +
 +  if (item->type == KDBUS_ITEM_REPLY_TIMEOUT)
 +    g_dbus_message_set_body (message, g_variant_new ("(s)", "Method call timed out"));
 +  else
 +    g_dbus_message_set_body (message, g_variant_new ("(s)", "Method call peer died"));
 +
 +  (* worker->message_received_callback) (message, worker->user_data);
 +
 +  g_object_unref (message);
 +}
 +
 +
 +/*
 + * g_kdbus_decode_kernel_msg
 + */
 +static void
 +g_kdbus_decode_kernel_msg (GKDBusWorker      *worker,
 +                           struct kdbus_msg  *msg)
 +{
 +  struct kdbus_item *item = NULL;
 +
 +  KDBUS_ITEM_FOREACH(item, msg, items)
 +    {
 +     switch (item->type)
 +        {
 +          case KDBUS_ITEM_ID_ADD:
 +          case KDBUS_ITEM_ID_REMOVE:
 +            g_kdbus_translate_id_change (worker, item);
 +            break;
 +
 +          case KDBUS_ITEM_NAME_ADD:
 +          case KDBUS_ITEM_NAME_REMOVE:
 +          case KDBUS_ITEM_NAME_CHANGE:
 +            g_kdbus_translate_name_change (worker, item);
 +            break;
 +
 +          case KDBUS_ITEM_REPLY_TIMEOUT:
 +          case KDBUS_ITEM_REPLY_DEAD:
 +            g_kdbus_translate_kernel_reply (worker, msg, item);
 +            break;
 +
 +          case KDBUS_ITEM_TIMESTAMP:
 +            break;
 +
 +          default:
 +            g_warning ("kdbus: unknown field in kernel message - %lld", item->type);
 +       }
 +    }
 +}
 +
 +
 +/*
 + * g_kdbus_decode_dbus_msg
 + */
 +static GKDBusMessage *
 +g_kdbus_decode_dbus_msg (GKDBusWorker      *worker,
 +                         struct kdbus_msg  *msg)
 +{
 +  GKDBusMessage *kmsg;
 +  struct kdbus_item *item;
 +  gssize data_size = 0;
 +  GArray *body_vectors;
 +  gsize body_size;
 +  GVariant *body, *value;
 +  gchar *sender;
 +  guint i;
 +  GVariant *parts[2];
 +  GVariantIter *fields_iter;
 +  GString *owned_name;
 +  guint8 endianness, type, flags, version;
 +  guint64 key, serial;
 +
 +  kmsg = g_new0 (GKDBusMessage, 1);
 +  kmsg->message = g_dbus_message_new();
 +  kmsg->sender_euid = (uid_t) -1;
 +  kmsg->sender_egid = (gid_t) -1;
 +  kmsg->sender_seclabel = NULL;
 +  kmsg->sender_names = NULL;
 +
 +  body_vectors = g_array_new (FALSE, FALSE, sizeof (GVariantVector));
 +
 +  item = msg->items;
 +  body_size = 0;
 +  owned_name = NULL;
 +
 +  KDBUS_ITEM_FOREACH(item, msg, items)
 +    {
 +      if (item->size < KDBUS_ITEM_HEADER_SIZE)
 +        g_error("kdbus: %llu bytes - invalid data record", item->size);
 +
 +      data_size = item->size - KDBUS_ITEM_HEADER_SIZE;
 +
 +      switch (item->type)
 +        {
 +         case KDBUS_ITEM_DST_NAME:
 +           /* Classic D-Bus doesn't make this known to the receiver, so
 +            * we don't do it here either (for compatibility with the
 +            * fallback case).
 +            */
 +           break;
 +
 +        case KDBUS_ITEM_PAYLOAD_OFF:
 +          {
 +            GVariantVector vector;
 +            gsize flavour;
 +
 +            /* We want to make sure the bytes are aligned the same as
 +             * they would be if they appeared in a contiguously
 +             * allocated chunk of aligned memory.
 +             *
 +             * We decide what the alignment 'should' be by consulting
 +             * body_size, which has been tracking the total size of the
 +             * message up to this point.
 +             *
 +             * We then play around with the pointer by removing as many
 +             * bytes as required to get it to the proper alignment (and
 +             * copy extra bytes accordingly).  This means that we will
 +             * grab some extra data in the 'bytes', but it won't be
 +             * shared with GVariant (which means there is no chance of
 +             * it being accidentally retransmitted).
 +             *
 +             * The kernel does the same thing, so make sure we get the
 +             * expected result.  Because of the kernel doing the same,
 +             * the result is that we will always be rounding-down to a
 +             * multiple of 8 for the pointer, which means that the
 +             * pointer will always be valid, assuming the original
 +             * address was.
 +             *
 +             * We could fix this with a new GBytes constructor that took
 +             * 'flavour' as a parameter, but it's not worth it...
 +             */
 +            flavour = body_size & 7;
 +            g_assert ((item->vec.offset & 7) == flavour);
 +
 +            vector.gbytes = g_bytes_new (((guchar *) msg) + item->vec.offset - flavour, item->vec.size + flavour);
 +            vector.data.pointer = g_bytes_get_data (vector.gbytes, NULL);
 +            vector.data.pointer += flavour;
 +            vector.size = item->vec.size;
 +
 +            g_array_append_val (body_vectors, vector);
 +            body_size += vector.size;
 +          }
 +          break;
 +
 +        case KDBUS_ITEM_PAYLOAD_MEMFD:
 +          {
 +            GVariantVector vector;
 +            const guchar *data;
 +            gsize size;
 +
 +            vector.gbytes = g_bytes_new_take_zero_copy_fd_size (item->memfd.fd, item->memfd.size);
 +            data = g_bytes_get_data (vector.gbytes, &size);
 +
 +            g_assert (item->memfd.size == size);
 +
 +            vector.data.pointer = data + item->memfd.start;
 +            vector.size = item->memfd.size;
 +
 +            g_array_append_val (body_vectors, vector);
 +            body_size += vector.size;
 +          }
 +          break;
 +
 +        case KDBUS_ITEM_FDS:
 +          {
 +            GUnixFDList *fd_list;
 +
 +            fd_list = g_unix_fd_list_new_from_array (item->fds, data_size / sizeof (int));
 +            g_dbus_message_set_unix_fd_list (kmsg->message, fd_list);
 +            g_object_unref (fd_list);
 +          }
 +          break;
 +
 +        /* [libdbuspolicy] read euid and egid values */
 +        case KDBUS_ITEM_CREDS:
 +
 +          if ((uid_t) item->creds.euid != (uid_t) -1)
 +            kmsg->sender_euid = (uid_t) item->creds.euid;
 +
 +          if ((gid_t) item->creds.egid != (gid_t) -1)
 +            kmsg->sender_egid = (gid_t) item->creds.egid;
 +
 +          break;
 +
 +        /* [libdbuspolicy] read security label value */
 +        case KDBUS_ITEM_SECLABEL:
 +
 +          /*if (item->str != NULL)*/
 +            kmsg->sender_seclabel = g_strdup (item->str);
 +
 +          break;
 +
 +        /* [libdbuspolicy] read all owned well-known names */
 +        case KDBUS_ITEM_OWNED_NAME:
 +
 +          if (g_dbus_is_name (item->name.name))
 +            {
 +              if (owned_name == NULL)
 +                owned_name = g_string_new (item->name.name);
 +              else
 +                g_string_append_printf (owned_name, " %s", item->name.name);
 +            }
 +
 +          break;
 +
 +        case KDBUS_ITEM_TIMESTAMP:
 +        case KDBUS_ITEM_PIDS:
 +        case KDBUS_ITEM_PID_COMM:
 +        case KDBUS_ITEM_TID_COMM:
 +        case KDBUS_ITEM_EXE:
 +        case KDBUS_ITEM_CMDLINE:
 +        case KDBUS_ITEM_CGROUP:
 +        case KDBUS_ITEM_AUDIT:
 +        case KDBUS_ITEM_CAPS:
 +        case KDBUS_ITEM_CONN_DESCRIPTION:
 +        case KDBUS_ITEM_AUXGROUPS:
 +        case KDBUS_ITEM_NAME:
 +        case KDBUS_ITEM_DST_ID:
 +        case KDBUS_ITEM_BLOOM_FILTER:
 +          break;
 +
 +        default:
 +          g_warning ("kdbus: unknown filed - %lld", item->type);
 +          break;
 +        }
 +    }
 +
 +  body = GLIB_PRIVATE_CALL(g_variant_from_vectors) (G_VARIANT_TYPE ("((yyyyuta{tv})v)"),
 +                                                    (GVariantVector *) body_vectors->data,
 +                                                    body_vectors->len, body_size, FALSE);
 +  g_assert (body);
 +
 +  for (i = 0; i < body_vectors->len; i++)
 +    g_bytes_unref (g_array_index (body_vectors, GVariantVector, i).gbytes);
 +
 +  g_array_free (body_vectors, TRUE);
 +
 +  parts[0] = g_variant_get_child_value (body, 0);
 +  parts[1] = g_variant_get_child_value (body, 1);
 +  g_variant_unref (body);
 +
 +  g_variant_get (parts[0], "(yyyyuta{tv})", &endianness, &type, &flags, &version, NULL, &serial, &fields_iter);
 +  g_variant_unref (parts[0]);
 +
 +  while (g_variant_iter_loop (fields_iter, "{tv}", &key, &value))
 +    {
 +      switch (key)
 +        {
 +          case G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL:
 +            g_dbus_message_set_reply_serial (kmsg->message, (guint32) g_variant_get_uint64 (value));
 +            continue;
 +
 +          default:
 +            g_dbus_message_set_header (kmsg->message, key, value);
 +            continue;
 +        }
 +    }
 +
 +  g_variant_iter_free (fields_iter);
 +
 +  g_dbus_message_set_flags (kmsg->message, flags);
 +  g_dbus_message_set_serial (kmsg->message, serial);
 +  g_dbus_message_set_message_type (kmsg->message, type);
 +
 +  body = g_variant_get_variant (parts[1]);
 +  if (!g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
 +    g_dbus_message_set_body (kmsg->message, body);
 +  else
 +    g_dbus_message_set_body (kmsg->message, NULL);
 +
 +  g_variant_unref (body);
 +  g_variant_unref (parts[1]);
 +
 +  /* set 'sender' field */
 +  sender = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) msg->src_id);
 +  g_dbus_message_set_sender (kmsg->message, sender);
 +  g_free (sender);
 +
 +  /* owned name */
 +  if (owned_name != NULL)
 +    kmsg->sender_names = g_string_free (owned_name, FALSE);
 +
 +  return kmsg;
 +}
 +
 +
 +/*
 + * _g_kdbus_receive
 + */
 +static void
 +_g_kdbus_receive (GKDBusWorker  *worker,
 +                  GError       **error)
 +{
 +  struct kdbus_cmd_recv recv;
 +  struct kdbus_msg *msg;
 +  gboolean can_receive;
 +  gint ret = 0;
 +
 +  can_receive = TRUE;
 +  memset (&recv, 0, sizeof recv);
 +  recv.size = sizeof (recv);
 +
 +again:
 +    ret = ioctl (worker->fd, KDBUS_CMD_RECV, &recv);
 +    if (ret < 0)
 +          ret = errno;
 +
 +    if (recv.return_flags & KDBUS_RECV_RETURN_DROPPED_MSGS)
 +      g_warning ("kdbus: %lld dropped broadcast messages", recv.dropped_msgs);
 +
 +    if (ret != 0)
 +      {
 +        if (ret == EINTR)
 +          goto again;
 +
 +        if (ret == EAGAIN)
 +          return;
 +
 +        g_set_error (error, G_IO_ERROR,
 +                     g_io_error_from_errno (ret),
 +                     _("Error while receiving message: %s"),
 +                     g_strerror (ret));
 +        return;
 +      }
 +
 +    msg = (struct kdbus_msg *)((guint8 *)worker->kdbus_buffer + recv.msg.offset);
 +
 +    if (msg->payload_type == KDBUS_PAYLOAD_DBUS)
 +      {
 +        GKDBusMessage *kmsg;
 +
 +        kmsg = g_kdbus_decode_dbus_msg (worker, msg);
 +
 +#ifdef LIBDBUSPOLICY
 +    if (worker->dbuspolicy != NULL)
 +      {
 +        if (g_dbus_message_get_message_type (kmsg->message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL)
 +          {
 +            if ((kmsg->sender_euid != (uid_t) -1) && (kmsg->sender_egid != (gid_t) -1) &&
 +                (kmsg->sender_seclabel != NULL))
 +              {
 +                gint check;
 +
 +                check = dbuspolicy1_check_in (worker->dbuspolicy,
 +                                              g_dbus_message_get_destination (kmsg->message),
 +                                              kmsg->sender_names,
 +                                              kmsg->sender_seclabel,
 +                                              kmsg->sender_euid,
 +                                              kmsg->sender_egid,
 +                                              g_dbus_message_get_path (kmsg->message),
 +                                              g_dbus_message_get_interface (kmsg->message),
 +                                              g_dbus_message_get_member (kmsg->message),
 +                                              g_dbus_message_get_message_type (kmsg->message),
 +                                              NULL, 0, 0);
 +                if (check != 1)
 +                  {
 +                    can_receive = FALSE;
 +                  }
 +              }
 +            else
 +              {
 +                can_receive = FALSE;
 +              }
 +          }
 +      }
 +#endif
 +
 +       if (can_receive)
 +         (* worker->message_received_callback) (kmsg->message, worker->user_data);
 +
 +       if (kmsg->sender_seclabel != NULL)
 +         g_free (kmsg->sender_seclabel);
 +
 +       if (kmsg->sender_names != NULL)
 +         g_free (kmsg->sender_names);
 +
 +       g_object_unref (kmsg->message);
 +       g_free (kmsg);
 +     }
 +   else if (msg->payload_type == KDBUS_PAYLOAD_KERNEL)
 +     g_kdbus_decode_kernel_msg (worker, msg);
 +   else
 +     {
 +       g_set_error (error,
 +                    G_DBUS_ERROR,
 +                    G_DBUS_ERROR_FAILED,
 +                    _("Received unknown payload type"));
 +     }
 +
 +  g_kdbus_close_msg (worker, msg);
 +  return;
 +}
 +
 +static gboolean
 +g_kdbus_msg_append_item (struct kdbus_msg  *msg,
 +                         gsize              type,
 +                         gconstpointer      data,
 +                         gsize              size)
 +{
 +  struct kdbus_item *item;
 +  gsize item_size;
 +
 +  item_size = size + G_STRUCT_OFFSET(struct kdbus_item, data);
 +
 +  if (msg->size + item_size > KDBUS_MSG_MAX_SIZE)
 +    return FALSE;
 +
 +  msg->size += (-msg->size) & 7;
 +  item = (struct kdbus_item *) ((guchar *) msg + msg->size);
 +  item->type = type;
 +  item->size = item_size;
 +  memcpy (item->data, data, size);
 +
 +  msg->size += item_size;
 +
 +  return TRUE;
 +}
 +
 +static gboolean
 +g_kdbus_msg_append_payload_vec (struct kdbus_msg  *msg,
 +                                gconstpointer      data,
 +                                gsize              size)
 +{
 +  struct kdbus_vec vec = {
 +    .size = size,
 +    .address = (gsize) data
 +  };
 +
 +  return g_kdbus_msg_append_item (msg, KDBUS_ITEM_PAYLOAD_VEC, &vec, sizeof vec);
 +}
 +
 +static gboolean
 +g_kdbus_msg_append_payload_memfd (struct kdbus_msg  *msg,
 +                                  gint               fd,
 +                                  gsize              offset,
 +                                  gsize              size)
 +{
 +  struct kdbus_memfd mfd = {
 +   .start = offset,
 +   .size = size,
 +   .fd = fd,
 +  };
 +
 +  return g_kdbus_msg_append_item (msg, KDBUS_ITEM_PAYLOAD_MEMFD, &mfd, sizeof mfd);
 +}
 +
 +static struct kdbus_bloom_filter *
 +g_kdbus_msg_append_bloom (struct kdbus_msg  *msg,
 +                          gsize              size)
 +{
 +  struct kdbus_item *bloom_item;
 +  gsize bloom_item_size;
 +
 +  bloom_item_size = G_STRUCT_OFFSET (struct kdbus_item, bloom_filter) +
 +                    G_STRUCT_OFFSET (struct kdbus_bloom_filter, data) +
 +                    size;
 +  if (msg->size + bloom_item_size > KDBUS_MSG_MAX_SIZE)
 +    return NULL;
 +
 +  msg->size += (-msg->size) & 7;
 +  bloom_item = (struct kdbus_item *) ((guchar *) msg + msg->size);
 +
 +  bloom_item->size = bloom_item_size;
 +  bloom_item->type = KDBUS_ITEM_BLOOM_FILTER;
 +
 +  msg->size += bloom_item->size;
 +  return &bloom_item->bloom_filter;
 +}
 +
 +
 +/*
 + * _g_kdbus_send
 + */
 +static gboolean
 +_g_kdbus_send (GKDBusWorker  *worker,
 +               GDBusMessage  *message,
 +               GDBusMessage **out_reply,
 +               gint           timeout_msec,
 +               GCancellable  *cancellable,
 +               GError       **error)
 +{
 +  struct kdbus_msg *msg;
 +  GVariantVectors body_vectors;
 +  struct kdbus_cmd_send *send;
 +  gsize send_size;
 +  const gchar *dst_name;
 +  gboolean result;
 +
 +  gint memfd_fd;
 +  gint cancel_fd;
 +
 +  g_return_val_if_fail (G_IS_KDBUS_WORKER (worker), FALSE);
 +
 +  send = NULL;
 +  send_size = sizeof(*send);
 +
 +  msg = alloca (KDBUS_MSG_MAX_SIZE);
 +  result = TRUE;
 +
 +  memfd_fd = -1;
 +  cancel_fd = -1;
 +
 +  /* fill in as we go... */
 +  memset (msg, 0, sizeof (struct kdbus_msg));
 +  msg->size = sizeof (struct kdbus_msg);
 +  msg->payload_type = KDBUS_PAYLOAD_DBUS;
 +  msg->cookie = g_dbus_message_get_serial(message);
 +
 +  /* Message destination */
 +  dst_name = g_dbus_message_get_destination (message);
 +  if (dst_name != NULL)
 +    {
 +      if (g_dbus_is_unique_name (dst_name))
 +        {
 +          if (dst_name[1] != '1' || dst_name[2] != '.')
 +            {
 +              g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
 +                           "Invalid unique D-Bus name '%s'", dst_name);
 +              return FALSE;
 +            }
 +
 +          /* We already know that it passes the checks for unique
 +           * names, so no need to perform error checking on strtoull.
 +           */
 +          msg->dst_id = strtoull (dst_name + 3, NULL, 10);
 +        }
 +      else
 +        {
 +          g_kdbus_msg_append_item (msg, KDBUS_ITEM_DST_NAME, dst_name, strlen (dst_name) + 1);
 +          msg->dst_id = KDBUS_DST_ID_NAME;
 +        }
 +    }
 +  else
 +    msg->dst_id = KDBUS_DST_ID_BROADCAST;
 +
 +  /* File descriptors */
 +  {
 +    GUnixFDList *fd_list;
 +
 +    fd_list = g_dbus_message_get_unix_fd_list (message);
 +
 +    if (fd_list != NULL)
 +      {
 +        const gint *fds;
 +        gint n_fds;
 +
 +        fds = g_unix_fd_list_peek_fds (fd_list, &n_fds);
 +
 +        if (n_fds)
 +          g_kdbus_msg_append_item (msg, KDBUS_ITEM_FDS, fds, sizeof (gint) * n_fds);
 +      }
 +  }
 +
 +  /* Message body */
 +  {
 +    struct dbus_fixed_header fh;
 +    GHashTableIter header_iter;
 +    GVariantBuilder builder;
 +    gpointer key, value;
 +    GVariant *parts[3];
 +    GVariant *body;
 +
 +    fh.endian = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ? 'l': 'B';
 +    fh.type = g_dbus_message_get_message_type (message);
 +    fh.flags = g_dbus_message_get_flags (message);
 +    fh.version = 2;
 +    fh.reserved = 0;
 +    fh.serial = g_dbus_message_get_serial (message);
 +    parts[0] = g_variant_new_from_data (DBUS_FIXED_HEADER_TYPE, &fh, sizeof fh, TRUE, NULL, NULL);
 +
 +    g_dbus_message_init_header_iter (message, &header_iter);
 +    g_variant_builder_init (&builder, DBUS_EXTENDED_HEADER_TYPE);
 +
 +    /* We set the sender field to the correct value for ourselves */
 +    g_variant_builder_add (&builder, "{tv}",
 +                           (guint64) G_DBUS_MESSAGE_HEADER_FIELD_SENDER,
 +                           g_variant_new_printf (":1.%"G_GUINT64_FORMAT, worker->unique_id));
 +
 +    while (g_hash_table_iter_next (&header_iter, &key, &value))
 +      {
 +        guint64 key_int = (gsize) key;
 +
 +        switch (key_int)
 +          {
 +            /* These are the normal header fields that get passed
 +             * straight through.
 +             */
 +            case G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL:
 +              g_variant_builder_add (&builder, "{tv}", key_int, g_variant_new_uint64 (g_dbus_message_get_reply_serial(message)));
 +              continue;
 +
 +            case G_DBUS_MESSAGE_HEADER_FIELD_PATH:
 +            case G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE:
 +            case G_DBUS_MESSAGE_HEADER_FIELD_MEMBER:
 +            case G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME:
 +            case G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION:
 +              g_variant_builder_add (&builder, "{tv}", key_int, value);
 +              /* This is a little bit gross.
 +               *
 +               * We must send the header part of the message in a single
 +               * vector as per kdbus rules, but the GVariant serialiser
 +               * code will split any item >= 128 bytes into its own
 +               * vector to save the copy.
 +               *
 +               * No header field should be that big anyway... right?
 +               */
 +              g_assert_cmpint (g_variant_get_size (value), <, 128);
 +              continue;
 +
 +            /* We send this one unconditionally, but set it ourselves */
 +            case G_DBUS_MESSAGE_HEADER_FIELD_SENDER:
 +              continue;
 +
 +            /* We don't send these at all in GVariant format */
 +            case G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE:
 +            case G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS:
 +              continue;
 +
 +            default:
 +              g_assert_not_reached ();
 +          }
 +      }
 +    parts[1] = g_variant_builder_end (&builder);
 +    if (parts[1] == NULL)
 +          g_warning ("failed to make builder");
 +
 +    body = g_dbus_message_get_body (message);
 +    if (!body)
 +      body = g_variant_new ("()");
 +    parts[2] = g_variant_new_variant (body);
 +
 +    body = g_variant_ref_sink (g_variant_new_tuple (parts, G_N_ELEMENTS (parts)));
 +    GLIB_PRIVATE_CALL(g_variant_to_vectors) (body, &body_vectors);
 +
 +    /* Sanity check to make sure the header is really contiguous:
 +     *
 +     *  - we must have at least one vector in the output
 +     *  - the first vector must completely contain at least the header
 +     */
 +    g_assert_cmpint (body_vectors.vectors->len, >, 0);
 +    g_assert_cmpint (g_array_index (body_vectors.vectors, GVariantVector, 0).size, >=,
 +                     g_variant_get_size (parts[0]) + g_variant_get_size (parts[1]));
 +
 +    g_variant_unref (body);
 +  }
 +
 +  {
 +    guint i;
 +
 +    for (i = 0; i < body_vectors.vectors->len; i++)
 +      {
 +        GVariantVector vector = g_array_index (body_vectors.vectors, GVariantVector, i);
 +
 +        if (vector.gbytes)
 +          {
 +            const guchar *bytes_data;
 +            gboolean use_memfd;
 +            gsize bytes_size;
 +
 +            use_memfd = FALSE;
 +            bytes_data = g_bytes_get_data (vector.gbytes, &bytes_size);
 +
 +            /* check whether we can and should use memfd */
 +            if ((msg->dst_id != KDBUS_DST_ID_BROADCAST) && (bytes_size > KDBUS_MEMFD_THRESHOLD))
 +              use_memfd = TRUE;
 +
 +            if (use_memfd)
 +              {
 +                const guchar *bytes_data_wr;
 +                gint64 wr;
 +
 +                /* create memfd object */
 +                memfd_fd = glib_linux_memfd_create ("glib-kdbus-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING);
 +                if (memfd_fd == -1)
 +                  {
 +                    g_warning ("kdbus: missing kernel memfd support");
 +                    use_memfd = FALSE; /* send as PAYLOAD_VEC item */
 +                  }
 +                else
 +                  {
 +                    /* write data to memfd */
 +                    bytes_data_wr = bytes_data;
 +                    while (bytes_size)
 +                      {
 +                        wr = write (memfd_fd, bytes_data_wr, bytes_size);
 +                        if (wr < 0)
 +                          g_warning ("kdbus: writing to memfd failed: (%d) %m", errno);
 +
 +                        bytes_size -= wr;
 +                        bytes_data_wr += wr;
 +                      }
 +
 +                    /* seal memfd */
 +                    if (!g_unix_fd_ensure_zero_copy_safe (memfd_fd))
 +                      {
 +                        g_warning ("kdbus: memfd sealing failed");
 +                      use_memfd = FALSE; /* send as PAYLOAD_VEC item */
 +                      }
 +                    else
 +                      {
 +                        /* attach memfd item */
 +                        if (!g_kdbus_msg_append_payload_memfd (msg, memfd_fd, vector.data.pointer - bytes_data, vector.size))
 +                          goto need_compact;
 +                      }
 +                  } /* memfd_fd == -1 */
 +              } /* use_memfd */
 +
 +            if (!use_memfd)
 +              if (!g_kdbus_msg_append_payload_vec (msg, vector.data.pointer, vector.size))
 +                goto need_compact;
 +          }
 +        else
 +          if (!g_kdbus_msg_append_payload_vec (msg, body_vectors.extra_bytes->data + vector.data.offset, vector.size))
 +            goto need_compact;
 +      }
 +  }
 +
 +  /*
 +   * set message flags
 +   */
 +  msg->flags = ((g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_EXPECT_REPLY) |
 +                ((g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_AUTO_START) ? KDBUS_MSG_NO_AUTO_START : 0);
 +
 +  if ((msg->flags) & KDBUS_MSG_EXPECT_REPLY)
 +    msg->timeout_ns = 1U | ( /* ensure nonzero */
 +                        1000U * g_get_monotonic_time() + (
 +                          timeout_msec == -1 ? DBUS_DEFAULT_TIMEOUT_MSEC * 1000000LLU :
 +                          timeout_msec == G_MAXINT ? KDBUS_INFINITE_TIMEOUT_NS :
 +                          (guint64)timeout_msec * 1000000U
 +                        )
 +                      );
 +  else
 +    msg->cookie_reply = g_dbus_message_get_reply_serial(message);
 +
 +  /*
 +   * append bloom filter item for broadcast signals
 +   */
 +  if (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_SIGNAL)
 +    {
 +      struct kdbus_bloom_filter *bloom_filter;
 +
 +      msg->flags |= KDBUS_MSG_SIGNAL;
 +      bloom_filter = g_kdbus_msg_append_bloom (msg, worker->bloom_size);
 +      if (bloom_filter == NULL)
 +        goto need_compact;
 +      g_kdbus_setup_bloom (worker, message, bloom_filter);
 +    }
 +
 +  if (out_reply != NULL && cancellable)
 +    {
 +      cancel_fd = g_cancellable_get_fd (cancellable);
 +      if (cancel_fd != -1)
 +        send_size += KDBUS_ITEM_SIZE (sizeof(cancel_fd));
 +    }
 +
 +  send = g_alloca0 (send_size);
 +  send->size = send_size;
 +  send->msg_address = (gsize) msg;
 +
 +  if (out_reply != NULL)
 +    {
 +      /* synchronous call */
 +      send->flags = KDBUS_SEND_SYNC_REPLY;
 +
 +      if (cancel_fd != -1)
 +        {
 +          struct kdbus_item *item;
 +
 +          item = send->items;
 +          item->type = KDBUS_ITEM_CANCEL_FD;
 +          item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(cancel_fd);
 +          item->fds[0] = cancel_fd;
 +        }
 +    }
 +  else
 +    {
 +      /* asynchronous call */
 +      send->flags = 0;
 +    }
 +
 +  /*
 +   * show debug
 +   */
 +  if (G_UNLIKELY (_g_dbus_debug_message ()))
 +    {
 +      gchar *s;
 +      _g_dbus_debug_print_lock ();
 +      g_print ("========================================================================\n"
 +               "GDBus-debug:Message:\n"
 +               "  >>>> SENT D-Bus/kdbus message\n");
 +      s = g_dbus_message_print (message, 2);
 +      g_print ("%s", s);
 +      g_free (s);
 +      _g_dbus_debug_print_unlock ();
 +    }
 +
 +  /*
 +   * check policy
 +   */
 +#ifdef LIBDBUSPOLICY
 +  if (worker->dbuspolicy != NULL)
 +    {
 +      if (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL)
 +        {
 +          gint check;
 +
 +          check = dbuspolicy1_check_out (worker->dbuspolicy,
 +                                         g_dbus_message_get_destination (message),
 +                                         g_dbus_message_get_sender (message),
 +                                         g_dbus_message_get_path (message),
 +                                         g_dbus_message_get_interface (message),
 +                                         g_dbus_message_get_member (message),
 +                                         g_dbus_message_get_message_type (message),
 +                                         NULL, 0, 0);
 +          if (check != DBUSPOLICY_RESULT_ALLOW)
 +            {
 +              switch (check)
 +                {
 +                  case DBUSPOLICY_RESULT_DENY:
 +                    g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
 +                                 "Cannot send message - message rejected due to XML security policies");
 +                  break;
 +
 +                  case DBUSPOLICY_RESULT_DEST_NOT_AVAILABLE:
 +                    g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
 +                                 "Cannot send message - destination not known");
 +                  break;
 +
 +                  case DBUSPOLICY_RESULT_KDBUS_ERROR:
 +                    g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
 +                                 "Cannot send message - message rejected due to internal libdbuspolicy error (kdbus)");
 +                  break;
 +
 +                  case DBUSPOLICY_RESULT_CYNARA_ERROR:
 +                    g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
 +                                 "Cannot send message - message rejected due to internal libdbuspolicy error (Cynara)");
 +                  break;
 +
 +                  default:
 +                    g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
 +                                 "Cannot send message - unknown libdbuspolicy error");
 +                  break;
 +                }
 +
 +              result = FALSE;
 +              goto out;
 +            }
 +        }
 +    }
 +#endif
 +
 +  /*
 +   * send message
 +   */
 +  if (ioctl(worker->fd, KDBUS_CMD_SEND, send))
 +    {
 +      int ret = errno;
 +      gchar *info;
 +      asprintf (&info, "sender=%s destination=%s path=%s interface=%s member=%s type=%d",
 +                       g_dbus_message_get_sender (message),
 +                       g_dbus_message_get_destination (message),
 +                       g_dbus_message_get_path (message),
 +                       g_dbus_message_get_interface (message),
 +                       g_dbus_message_get_member (message),
 +                       g_dbus_message_get_message_type (message));
 +
 +      errno = ret;
 +      if (errno == ENXIO || errno == ESRCH)
 +        {
 +          g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
 +                       "Destination '%s' not known, %s", dst_name, info);
 +        }
 +      else if (errno == EADDRNOTAVAIL)
 +        {
 +          g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
 +                       "No support for activation for name: %s, %s", dst_name, info);
 +        }
 +      else if (errno == EXFULL)
 +        {
 +          g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_LIMITS_EXCEEDED,
 +                       "The memory pool of the receiver is full, %s", info);
 +        }
 +      else if (errno == ENOBUFS)
 +        {
 +          g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_LIMITS_EXCEEDED,
 +                       "Too many pending messages on the receiver side, %s", info);
 +        }
 +      else if (errno == EMSGSIZE)
 +        {
 +          g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_LIMITS_EXCEEDED,
 +                       "The size of the message is excessive, %s", info);
 +        }
 +      else if (errno == ECANCELED)
 +        {
 +          g_set_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
 +                       "Operation was cancelled, %s", info);
 +        }
 +      else if (errno == ETIMEDOUT)
 +        {
 +          g_set_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT,
 +                       "Timeout was reached, %s", info);
 +        }
 +      else if (errno == EPERM)
 +        {
 +          g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
 +                       "Permission denied, %s", info);
 +        }
 +      else
 +        {
 +          g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "%s, %s", g_strerror(errno), info);
 +          g_warning ("kdbus: %s, %s", g_strerror(errno), info);
 +        }
 +      result = FALSE;
 +      free(info);
 +    }
 +  else if (out_reply != NULL)
 +    {
 +      GKDBusMessage *kmsg;
 +      struct kdbus_msg *kdbus_msg;
 +
 +      kdbus_msg = (struct kdbus_msg *)((guint8 *)worker->kdbus_buffer + send->reply.offset);
 +
 +      kmsg = g_kdbus_decode_dbus_msg (worker, kdbus_msg);
 +      g_kdbus_close_msg (worker, kdbus_msg);
 +
 +      *out_reply = kmsg->message;
 +
 +      if (kmsg->sender_seclabel != NULL)
 +        g_free (kmsg->sender_seclabel);
 +
 +      if (kmsg->sender_names != NULL)
 +        g_free (kmsg->sender_names);
 +
 +      g_free (kmsg);
 +
 +      if (G_UNLIKELY (_g_dbus_debug_message ()))
 +        {
 +          gchar *s;
 +          _g_dbus_debug_print_lock ();
 +          g_print ("========================================================================\n"
 +                   "GDBus-debug:Message:\n"
 +                   "  <<<< RECEIVED D-Bus message\n");
 +          s = g_dbus_message_print (*out_reply, 2);
 +          g_print ("%s", s);
 +          g_free (s);
 +          _g_dbus_debug_print_unlock ();
 +        }
 +    }
 +
 +out:
 +
 +  if (cancel_fd != -1)
 +    g_cancellable_release_fd (cancellable);
 +
 +  if (memfd_fd != -1)
 +    close (memfd_fd);
 +
 +  GLIB_PRIVATE_CALL(g_variant_vectors_deinit) (&body_vectors);
 +
 +  return result;
 +
 +need_compact:
 +  /* We end up here if:
 +   *  - too many kdbus_items
 +   *  - too large kdbus_msg size
 +   *  - too much vector data
 +   */
 +  g_warning ("kdbus: message serialisation error");
 +  g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
 +               "message serialisation error");
 +
 +  if (memfd_fd != -1)
 +    close (memfd_fd);
 +
 +  GLIB_PRIVATE_CALL(g_variant_vectors_deinit) (&body_vectors);
 +  return FALSE;
 +}
 +
 +/* ---------------------------------------------------------------------------------------------------- */
 +
 +static void
 +g_kdbus_worker_finalize (GObject *object)
 +{
 +  GKDBusWorker *worker;
 +  GList *match;
 +
 +  worker = G_KDBUS_WORKER (object);
 +
 +  if (worker->kdbus_buffer != NULL)
 +    {
 +      munmap (worker->kdbus_buffer, worker->receive_pool_size);
 +      worker->kdbus_buffer = NULL;
 +      worker->receive_pool_size = 0;
 +    }
 +
 +  if (worker->unique_name != NULL)
 +    g_free (worker->unique_name);
 +  worker->unique_name = NULL;
 +
 +  for (match = worker->matches; match != NULL; match = match->next)
 +    match_free (match->data);
 +  g_list_free (worker->matches);
 +  g_mutex_clear (&worker->matches_mutex);
 +
 +#ifdef LIBDBUSPOLICY
 +  if (worker->dbuspolicy != NULL)
 +    dbuspolicy1_free (worker->dbuspolicy);
 +#endif
 +
 +  if (worker->fd != -1 && !worker->closed)
 +    _g_kdbus_close (worker);
 +
 +  G_OBJECT_CLASS (g_kdbus_worker_parent_class)->finalize (object);
 +}
 +
 +static void
 +g_kdbus_worker_class_init (GKDBusWorkerClass *class)
 +{
 +  class->finalize = g_kdbus_worker_finalize;
 +}
 +
 +static void
 +g_kdbus_worker_init (GKDBusWorker *worker)
 +{
 +  worker->fd = -1;
 +
 +  worker->context = NULL;
 +  worker->loop = NULL;
 +  worker->thread = NULL;
 +  worker->source = 0;
 +
 +  worker->kdbus_buffer = NULL;
 +  worker->receive_pool_size = 0;
 +  worker->unique_name = NULL;
 +  worker->unique_id = -1;
 +
 +  worker->flags = KDBUS_HELLO_ACCEPT_FD;
 +  worker->attach_flags_send = _KDBUS_ATTACH_ALL;
 +  worker->attach_flags_recv = _KDBUS_ATTACH_ALL;
 +
 +  worker->bloom_size = 0;
 +  worker->bloom_n_hash = 0;
 +  worker->matches = NULL;
 +  g_mutex_init (&worker->matches_mutex);
 +
 +#ifdef LIBDBUSPOLICY
 +  worker->dbuspolicy = NULL;
 +#endif
 +}
 +
 +static gpointer
 +_g_kdbus_worker_thread (gpointer _data)
 +{
 +  GMainLoop *loop = (GMainLoop *) _data;
 +
 +  g_main_loop_run (loop);
 +
 +  g_main_loop_unref (loop);
 +
 +  return NULL;
 +}
 +
 +GKDBusWorker *
 +_g_kdbus_worker_new (const gchar  *address,
 +                     GError      **error)
 +{
 +  GKDBusWorker *worker;
 +
 +  worker = g_object_new (G_TYPE_KDBUS_WORKER, NULL);
 +  if (!_g_kdbus_open (worker, address, error))
 +    {
 +      g_object_unref (worker);
 +      return NULL;
 +    }
 +
 +  worker->context = g_main_context_new ();
 +  worker->loop = g_main_loop_new (worker->context, FALSE);
 +  worker->thread = g_thread_new ("gkdbus", _g_kdbus_worker_thread, g_main_loop_ref(worker->loop));
 +
 +  return worker;
 +}
 +
 +void
 +_g_kdbus_worker_associate (GKDBusWorker                            *worker,
 +                           GDBusCapabilityFlags                     capabilities,
 +                           GDBusWorkerMessageReceivedCallback       message_received_callback,
 +                           GDBusWorkerMessageAboutToBeSentCallback  message_about_to_be_sent_callback,
 +                           GDBusWorkerDisconnectedCallback          disconnected_callback,
 +                           gpointer                                 user_data)
 +{
 +  worker->capabilities = capabilities;
 +  worker->message_received_callback = message_received_callback;
 +  worker->message_about_to_be_sent_callback = message_about_to_be_sent_callback;
 +  worker->disconnected_callback = disconnected_callback;
 +  worker->user_data = user_data;
 +}
 +
 +static gboolean
 +g_kdbus_ready (gint           fd,
 +               GIOCondition   condition,
 +               gpointer       user_data)
 +{
 +  GKDBusWorker *worker;
 +  GError *error;
 +
 +  worker = user_data;
 +  error = NULL;
 +
 +  _g_kdbus_receive (worker, &error);
 +  g_assert_no_error (error);
 +
 +  return G_SOURCE_CONTINUE;
 +}
 +
 +typedef struct
 +{
 +  GKDBusWorker  *worker;
 +  GDBusMessage  *message;
 +} SyntheticReplyData;
 +
 +static gboolean
 +deliver_synthetic_reply (gpointer user_data)
 +{
 +  SyntheticReplyData *data;
 +  GKDBusWorker *worker;
 +  GDBusMessage *message;
 +
 +  data = user_data;
 +  worker = data->worker;
 +  message = data->message;
 +
 +  (* worker->message_received_callback) (message, worker->user_data);
 +
 +  g_object_unref (message);
 +  g_free (data);
 +
 +  return FALSE;
 +}
 +
 +void
 +_g_kdbus_worker_unfreeze (GKDBusWorker *worker)
 +{
 +  gchar *name;
 +
 +  if (worker->source != NULL)
 +    return;
 +
 +  worker->source = g_unix_fd_source_new (worker->fd, G_IO_IN);
 +
 +  g_source_set_callback (worker->source, (GSourceFunc) g_kdbus_ready,
 +                         g_object_ref (worker), g_object_unref);
 +  name = g_strdup_printf ("kdbus worker");
 +  g_source_set_name (worker->source, name);
 +  g_free (name);
 +
 +  g_source_attach (worker->source, worker->context);
 +}
 +
 +gboolean
 +_g_kdbus_worker_send_message (GKDBusWorker  *worker,
 +                              GDBusMessage  *message,
 +                              gint           timeout_msec,
 +                              GError       **error)
 +{
 +#ifdef DBUS_DAEMON_EMULATION
 +  if (_is_message_to_dbus_daemon (message))
 +    {
 +      SyntheticReplyData *data;
 +
 +      data = g_new0 (SyntheticReplyData, 1);
 +
 +      data->worker = worker;
 +      data->message = _dbus_daemon_synthetic_reply (worker, message);
 +
 +      g_main_context_invoke (worker->context, deliver_synthetic_reply, data);
 +
 +      return TRUE;
 +    }
 +#endif /* DBUS_DAEMON_EMULATION */
 +
 +  return _g_kdbus_send (worker, message, NULL, timeout_msec, NULL, error);
 +}
 +
 +gboolean
 +_g_kdbus_worker_send_message_sync (GKDBusWorker  *worker,
 +                                   GDBusMessage  *message,
 +                                   GDBusMessage **out_reply,
 +                                   gint           timeout_msec,
 +                                   GCancellable  *cancellable,
 +                                   GError       **error)
 +{
 +#ifdef DBUS_DAEMON_EMULATION
 +  if (_is_message_to_dbus_daemon (message))
 +    {
 +      *out_reply = _dbus_daemon_synthetic_reply (worker, message);
 +      return TRUE;
 +    }
 +#endif /* DBUS_DAEMON_EMULATION */
 +
 +  return _g_kdbus_send (worker, message, out_reply, timeout_msec, cancellable, error);
 +}
 +
 +gboolean
 +_g_kdbus_worker_flush_sync (GKDBusWorker *worker)
 +{
 +  return TRUE;
 +}
 +
 +void
 +_g_kdbus_worker_stop (GKDBusWorker *worker)
 +{
 +  g_source_destroy (worker->source);
 +  g_source_unref (worker->source);
 +  worker->source = 0;
 +
 +  g_object_unref (worker);
 +}
 +
 +void
 +_g_kdbus_worker_close (GKDBusWorker       *worker,
-   g_simple_async_result_complete_in_idle (result);
++                       GTask              *task)
 +{
 +  worker->disconnected_callback (FALSE, NULL, worker->user_data);
++  g_task_return_boolean (task, TRUE);
 +}
diff --cc gio/gkdbus.h
index 8a4a831,0000000..34e4410
mode 100644,000000..100644
--- /dev/null
@@@ -1,200 -1,0 +1,199 @@@
-                                                               GCancellable        *cancellable,
-                                                               GSimpleAsyncResult  *result);
 +/* GIO - GLib Input, Output and Streaming Library
 + *
 + * Copyright (C) 2015 Samsung Electronics
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) any later version.
 + *
 + * This library 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General
 + * Public License along with this library; if not, write to the
 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 + * Boston, MA 02111-1307, USA.
 + *
 + * Author: Lukasz Skalski       <l.skalski@samsung.com>
 + * Author: Michal Eljasiewicz   <m.eljasiewic@samsung.com>
 + */
 +
 +#ifndef __G_KDBUS_H__
 +#define __G_KDBUS_H__
 +
 +#if !defined (GIO_COMPILATION)
 +#error "gkdbus.h is a private header file."
 +#endif
 +
 +#include <gio/giotypes.h>
 +#include "gdbusprivate.h"
 +
 +#define G_TYPE_KDBUS_WORKER                                (g_kdbus_worker_get_type ())
 +#define G_KDBUS_WORKER(inst)                               (G_TYPE_CHECK_INSTANCE_CAST ((inst),                     \
 +                                                            G_TYPE_KDBUS_WORKER, GKDBusWorker))
 +#define G_KDBUS_WORKER_CLASS(class)                        (G_TYPE_CHECK_CLASS_CAST ((class),                       \
 +                                                            G_TYPE_KDBUS_WORKER, GKDBusWorkerClass))
 +#define G_IS_KDBUS_WORKER(inst)                            (G_TYPE_CHECK_INSTANCE_TYPE ((inst),                     \
 +                                                            G_TYPE_KDBUS_WORKER))
 +#define G_IS_KDBUS_WORKER_CLASS(class)                     (G_TYPE_CHECK_CLASS_TYPE ((class),                       \
 +                                                            G_TYPE_KDBUS_WORKER))
 +#define G_KDBUS_WORKER_GET_CLASS(inst)                     (G_TYPE_INSTANCE_GET_CLASS ((inst),                      \
 +                                                            G_TYPE_KDBUS_WORKER, GKDBusWorkerClass))
 +typedef enum {
 +  G_DBUS_CREDS_NONE = 0,
 +  G_DBUS_CREDS_PID = (1<<0),
 +  G_DBUS_CREDS_UID = (1<<1),
 +  G_DBUS_CREDS_UNIQUE_NAME = (1<<2),
 +  G_DBUS_CREDS_SEC_LABEL = (1<<3)
 +} GDBusCredentialsFlags;
 +
 +typedef struct
 +{
 +  guint   pid;
 +  guint   uid;
 +  gchar  *unique_name;
 +  gchar  *sec_label;
 +} GDBusCredentials;
 +
 +typedef struct
 +{
 +  GDBusMessage  *message;
 +  uid_t          sender_euid;
 +  gid_t          sender_egid;
 +  gchar         *sender_seclabel;
 +  gchar         *sender_names;
 +} GKDBusMessage;
 +
 +typedef struct _GKDBusWorker                                  GKDBusWorker;
 +
 +void                  _g_kdbus_worker_associate              (GKDBusWorker                             *worker,
 +                                                              GDBusCapabilityFlags                      capabilities,
 +                                                              GDBusWorkerMessageReceivedCallback        message_received_callback,
 +                                                              GDBusWorkerMessageAboutToBeSentCallback   message_about_to_be_sent_callback,
 +                                                              GDBusWorkerDisconnectedCallback           disconnected_callback,
 +                                                              gpointer                                  user_data);
 +
 +GType                  g_kdbus_worker_get_type               (void);
 +
 +GKDBusWorker *        _g_kdbus_worker_new                    (const gchar         *address,
 +                                                              GError             **error);
 +
 +void                  _g_kdbus_worker_unfreeze               (GKDBusWorker        *worker);
 +
 +gboolean              _g_kdbus_worker_send_message           (GKDBusWorker        *worker,
 +                                                              GDBusMessage        *message,
 +                                                              gint                 timeout_msec,
 +                                                              GError             **error);
 +
 +gboolean              _g_kdbus_worker_send_message_sync      (GKDBusWorker        *worker,
 +                                                              GDBusMessage        *message,
 +                                                              GDBusMessage       **out_reply,
 +                                                              gint                 timeout_msec,
 +                                                              GCancellable        *cancellable,
 +                                                              GError             **error);
 +
 +void                  _g_kdbus_worker_stop                   (GKDBusWorker        *worker);
 +
 +gboolean              _g_kdbus_worker_flush_sync             (GKDBusWorker        *worker);
 +
 +void                  _g_kdbus_worker_close                  (GKDBusWorker        *worker,
++                                                              GTask               *task);
 +
 +/* ---------------------------------------------------------------------------------------------------- */
 +
 +gboolean              _g_kdbus_open                          (GKDBusWorker        *worker,
 +                                                              const gchar         *address,
 +                                                              GError             **error);
 +
 +gboolean              _g_kdbus_close                         (GKDBusWorker        *worker);
 +
 +gboolean              _g_kdbus_is_closed                     (GKDBusWorker        *worker);
 +
 +/* ---------------------------------------------------------------------------------------------------- */
 +
 +const gchar *               _g_kdbus_Hello                           (GKDBusWorker        *worker,
 +                                                                      GError             **error);
 +
 +gchar *                     _g_kdbus_GetBusId                        (GKDBusWorker        *worker,
 +                                                                      GError             **error);
 +
 +GBusRequestNameReplyFlags   _g_kdbus_RequestName                     (GKDBusWorker        *worker,
 +                                                                      const gchar         *name,
 +                                                                      GBusNameOwnerFlags   flags,
 +                                                                      GError             **error);
 +
 +GBusReleaseNameReplyFlags   _g_kdbus_ReleaseName                     (GKDBusWorker     *worker,
 +                                                                      const gchar      *name,
 +                                                                      GError          **error);
 +
 +gchar **                    _g_kdbus_GetListNames                    (GKDBusWorker     *worker,
 +                                                                      gboolean          activatable,
 +                                                                      GError          **error);
 +
 +gchar **                    _g_kdbus_GetListQueuedOwners             (GKDBusWorker     *worker,
 +                                                                      const gchar      *name,
 +                                                                      GError          **error);
 +
 +gboolean                    _g_kdbus_NameHasOwner                    (GKDBusWorker     *connection,
 +                                                                      const gchar      *name,
 +                                                                      GError          **error);
 +
 +gchar *                     _g_kdbus_GetNameOwner                    (GKDBusWorker     *worker,
 +                                                                      const gchar      *name,
 +                                                                      GError          **error);
 +
 +pid_t                       _g_kdbus_GetConnectionUnixProcessID      (GKDBusWorker     *worker,
 +                                                                      const gchar      *name,
 +                                                                      GError          **error);
 +
 +uid_t                       _g_kdbus_GetConnectionUnixUser           (GKDBusWorker     *worker,
 +                                                                      const gchar      *name,
 +                                                                      GError          **error);
 +
 +gchar *                     _g_kdbus_GetConnectionSecurityLabel      (GKDBusWorker     *worker,
 +                                                                      const gchar      *name,
 +                                                                      GError          **error);
 +
 +GBusStartServiceReplyFlags  _g_kdbus_StartServiceByName              (GKDBusWorker     *worker,
 +                                                                      const gchar      *name,
 +                                                                      guint32           flags,
 +                                                                      GError          **error);
 +
 +gboolean                    _g_kdbus_AddMatch                        (GKDBusWorker     *worker,
 +                                                                      const gchar      *match_rule,
 +                                                                      GError          **error);
 +
 +gboolean                    _g_kdbus_RemoveMatch                     (GKDBusWorker     *worker,
 +                                                                      const gchar      *match_rule,
 +                                                                      GError          **error);
 +
 +GDBusCredentials *          _g_kdbus_GetConnInfo                     (GKDBusWorker     *worker,
 +                                                                      const gchar      *name,
 +                                                                      guint             flags,
 +                                                                      GError          **error);
 +
 +/* ---------------------------------------------------------------------------------------------------- */
 +
 +gboolean              _g_kdbus_subscribe_name_acquired               (GKDBusWorker     *worker,
 +                                                                      const gchar      *match_rule,
 +                                                                      const gchar      *name,
 +                                                                      GError          **error);
 +
 +gboolean              _g_kdbus_subscribe_name_lost                   (GKDBusWorker     *worker,
 +                                                                      const gchar      *match_rule,
 +                                                                      const gchar      *name,
 +                                                                      GError          **error);
 +
 +gboolean              _g_kdbus_subscribe_name_owner_changed          (GKDBusWorker     *worker,
 +                                                                      const gchar      *match_rule,
 +                                                                      const gchar      *name,
 +                                                                      GError          **error);
 +
 +/* ---------------------------------------------------------------------------------------------------- */
 +
 +G_END_DECLS
 +
 +#endif /* __G_KDBUS_H__ */
index a6d8135,0000000..c13bf49
mode 100644,000000..100644
--- /dev/null
@@@ -1,684 -1,0 +1,684 @@@
-       reply = g_dbus_message_new_method_error (message, dbus_error_name, local_error->message);
 +/* GIO - GLib Input, Output and Streaming Library
 + *
 + * Copyright (C) 2015 Samsung Electronics
 + *
 + * This library is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU Lesser General Public
 + * License as published by the Free Software Foundation; either
 + * version 2 of the License, or (at your option) any later version.
 + *
 + * This library 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
 + * Lesser General Public License for more details.
 + *
 + * You should have received a copy of the GNU Lesser General
 + * Public License along with this library; if not, write to the
 + * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 + * Boston, MA 02111-1307, USA.
 + *
 + * Author: Lukasz Skalski <l.skalski@samsung.com>
 + */
 +
 +#include "config.h"
 +#include "gkdbus.h"
 +#include "gkdbusfakedaemon.h"
 +
 +#include <gio/gio.h>
 +#include <string.h>
 +
 +static gchar *introspect =
 +  "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
 +  "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
 +  "<node>\n"
 +  " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
 +  "  <method name=\"Introspect\">\n"
 +  "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  " </interface>\n"
 +  " <interface name=\"org.freedesktop.DBus\">\n"
 +  "  <method name=\"AddMatch\">\n"
 +  "   <arg type=\"s\" direction=\"in\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"RemoveMatch\">\n"
 +  "   <arg type=\"s\" direction=\"in\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"GetConnectionCredentials\">\n"
 +  "   <arg type=\"s\" direction=\"in\"/>\n"
 +  "   <arg type=\"a{sv}\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"GetConnectionSELinuxSecurityContext\">\n"
 +  "   <arg type=\"s\" direction=\"in\"/>\n"
 +  "   <arg type=\"ay\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"GetConnectionUnixProcessID\">\n"
 +  "   <arg type=\"s\" direction=\"in\"/>\n"
 +  "   <arg type=\"u\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"GetConnectionUnixUser\">\n"
 +  "   <arg type=\"s\" direction=\"in\"/>\n"
 +  "   <arg type=\"u\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"GetId\">\n"
 +  "   <arg type=\"s\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"GetNameOwner\">\n"
 +  "   <arg type=\"s\" direction=\"in\"/>\n"
 +  "   <arg type=\"s\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"Hello\">\n"
 +  "   <arg type=\"s\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"ListActivatableNames\">\n"
 +  "   <arg type=\"as\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"ListNames\">\n"
 +  "   <arg type=\"as\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"ListQueuedOwners\">\n"
 +  "   <arg type=\"s\" direction=\"in\"/>\n"
 +  "   <arg type=\"as\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"NameHasOwner\">\n"
 +  "   <arg type=\"s\" direction=\"in\"/>\n"
 +  "   <arg type=\"b\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"ReleaseName\">\n"
 +  "   <arg type=\"s\" direction=\"in\"/>\n"
 +  "   <arg type=\"u\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"ReloadConfig\">\n"
 +  "  </method>\n"
 +  "  <method name=\"RequestName\">\n"
 +  "   <arg type=\"s\" direction=\"in\"/>\n"
 +  "   <arg type=\"u\" direction=\"in\"/>\n"
 +  "   <arg type=\"u\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"StartServiceByName\">\n"
 +  "   <arg type=\"s\" direction=\"in\"/>\n"
 +  "   <arg type=\"u\" direction=\"in\"/>\n"
 +  "   <arg type=\"u\" direction=\"out\"/>\n"
 +  "  </method>\n"
 +  "  <method name=\"UpdateActivationEnvironment\">\n"
 +  "   <arg type=\"a{ss}\" direction=\"in\"/>\n"
 +  "  </method>\n"
 +  "  <signal name=\"NameAcquired\">\n"
 +  "   <arg type=\"s\"/>\n"
 +  "  </signal>\n"
 +  "  <signal name=\"NameLost\">\n"
 +  "   <arg type=\"s\"/>\n"
 +  "  </signal>\n"
 +  "  <signal name=\"NameOwnerChanged\">\n"
 +  "   <arg type=\"s\"/>\n"
 +  "   <arg type=\"s\"/>\n"
 +  "   <arg type=\"s\"/>\n"
 +  "  </signal>\n"
 +  " </interface>\n"
 +  "</node>\n";
 +
 +static gboolean
 +_mac_smack_use (void)
 +{
 +  static int cached_use = -1;
 +
 +  if (cached_use < 0)
 +    cached_use = access("/sys/fs/smackfs/", F_OK) >= 0;
 +
 +  return cached_use;
 +}
 +
 +/**
 + * _is_message_to_dbus_daemon()
 + */
 +gboolean
 +_is_message_to_dbus_daemon (GDBusMessage  *message)
 +{
 +  return g_strcmp0 (g_dbus_message_get_destination (message), "org.freedesktop.DBus") == 0 &&
 +         (g_strcmp0 (g_dbus_message_get_interface (message), "org.freedesktop.DBus") == 0 ||
 +          g_strcmp0 (g_dbus_message_get_interface (message), "org.freedesktop.DBus.Introspectable") == 0) &&
 +         (g_strcmp0 (g_dbus_message_get_path (message), "/org/freedesktop/DBus") == 0 ||
 +          g_strcmp0 (g_dbus_message_get_path (message), "/") == 0);
 +}
 +
 +
 +/**
 + * _dbus_daemon_synthetic_reply()
 + */
 +GDBusMessage *
 +_dbus_daemon_synthetic_reply (GKDBusWorker  *worker,
 +                              GDBusMessage  *message)
 +{
 +  GDBusMessage *reply;
 +  GVariant     *reply_body;
 +  GVariant     *body;
 +  GError       *local_error;
 +  const gchar  *member;
 +
 +  reply = NULL;
 +  reply_body = NULL;
 +  local_error = NULL;
 +
 +  member = g_dbus_message_get_member (message);
 +  body = g_dbus_message_get_body (message);
 +
 +  /* show debug */
 +  if (G_UNLIKELY (_g_dbus_debug_message ()))
 +    {
 +      gchar *s;
 +      _g_dbus_debug_print_lock ();
 +      g_print ("========================================================================\n"
 +               "GDBus-debug:Message:\n"
 +               "  >>>> SENT D-Bus/kdbus message\n");
 +      s = g_dbus_message_print (message, 2);
 +      g_print ("%s", s);
 +      g_free (s);
 +      _g_dbus_debug_print_unlock ();
 +    }
 +
 +  /*
 +   * Introspect
 +   */
 +  if (!g_strcmp0 (member, "Introspect"))
 +    {
 +      reply_body = g_variant_new ("(s)", introspect);
 +    }
 +
 +  /*
 +   * AddMatch
 +   */
 +  else if (!g_strcmp0 (member, "AddMatch"))
 +    {
 +      if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
 +        {
 +          gchar *rule;
 +
 +          g_variant_get (body, "(&s)", &rule);
 +
 +          _g_kdbus_AddMatch (worker, rule, &local_error);
 +          if (local_error == NULL)
 +            reply_body = g_variant_new ("()", NULL);
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'AddMatch' has wrong args (expected s)");
 +    }
 +
 +  /*
 +   * RemoveMatch
 +   */
 +  else if (!g_strcmp0 (member, "RemoveMatch"))
 +    {
 +      if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
 +        {
 +          gchar *rule;
 +
 +          g_variant_get (body, "(&s)", &rule);
 +
 +          _g_kdbus_RemoveMatch (worker, rule, &local_error);
 +          if (local_error == NULL)
 +            reply_body = g_variant_new ("()", NULL);
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'RemoveMatch' has wrong args (expected s)");
 +    }
 +
 +  /*
 +   * GetConnectionCredentials
 +   */
 +  else if (!g_strcmp0 (member, "GetConnectionCredentials"))
 +    {
 +      if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
 +        {
 +          GDBusCredentials *creds;
 +          gchar *name;
 +          guint flags;
 +
 +          creds = NULL;
 +          flags = G_DBUS_CREDS_PID | G_DBUS_CREDS_UID | G_DBUS_CREDS_SEC_LABEL;
 +
 +          g_variant_get (body, "(&s)", &name);
 +
 +          creds = _g_kdbus_GetConnInfo (worker,
 +                                        name,
 +                                        flags,
 +                                        &local_error);
 +          if (local_error == NULL)
 +            {
 +              GVariantBuilder builder;
 +
 +              g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a{sv})"));
 +              g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
 +
 +              g_variant_builder_add (&builder, "{sv}", "UnixUserID", g_variant_new_uint32 (creds->uid));
 +              g_variant_builder_add (&builder, "{sv}", "ProcessID", g_variant_new_uint32 (creds->pid));
 +
 +              if (creds->sec_label != NULL)
 +                {
 +                  GVariantBuilder *label_builder;
 +                  gint counter;
 +                  gint label_size;
 +
 +                  label_size = strlen (creds->sec_label);
 +                  label_builder = g_variant_builder_new (G_VARIANT_TYPE ("ay"));
 +                  for (counter = 0 ; counter < label_size + 1; counter++)   /* label_size + 1 : include the \0 in the payload, for zero-copy reading. From dbus/bus/driver.c */
 +                    g_variant_builder_add (label_builder, "y", creds->sec_label[counter]);
 +
 +                  g_variant_builder_add (&builder, "{sv}", "LinuxSecurityLabel", g_variant_new ("ay", label_builder));
 +
 +                  g_variant_builder_unref (label_builder);
 +                  g_free (creds->sec_label);
 +                }
 +
 +              g_variant_builder_close (&builder);
 +              reply_body = g_variant_builder_end (&builder);
 +              g_free (creds);
 +            }
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'GetConnectionCredentials' has wrong args (expected s)");
 +    }
 +
 +  /*
 +   * GetConnectionSELinuxSecurityContext
 +   */
 +  else if (!g_strcmp0 (member, "GetConnectionSELinuxSecurityContext"))
 +    {
 +      if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
 +        {
 +          gchar *name;
 +          gchar *label;
 +
 +          g_variant_get (body, "(&s)", &name);
 +
 +          label = _g_kdbus_GetConnectionSecurityLabel (worker, name, &local_error);
 +          if (label == NULL && local_error == NULL)
 +            g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "Operation not supported");
 +          else if (local_error == NULL)
 +            {
 +              /* 'label' (KDBUS_ITEM_SECLABEL item) contains valid LSM security label... */
 +              if (_mac_smack_use())
 +                {
 +                  /* but if we are using SMACK - to keep compatibility with legacy dbus1 - return error */
 +                  g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN,
 +                               "Could not determine security context for '%s'", name);
 +                }
 +              else
 +                {
 +                  /* if it is not SMACK - let's assume that it's SELinux label */
 +                  GVariantBuilder builder;
 +                  gint counter;
 +
 +                  g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ay)"));
 +                  g_variant_builder_open (&builder, G_VARIANT_TYPE ("ay"));
 +
 +                  for (counter = 0 ; counter < strlen (label) ; counter++)
 +                    g_variant_builder_add (&builder, "y", label[counter]);
 +
 +                  g_variant_builder_close (&builder);
 +                  reply_body = g_variant_builder_end (&builder);
 +                }
 +              g_free (label);
 +            }
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'GetConnectionSELinuxSecurityContext' has wrong args (expected s)");
 +    }
 +
 +  /*
 +   * GetConnectionUnixProcessID
 +   */
 +  else if (!g_strcmp0 (member, "GetConnectionUnixProcessID"))
 +    {
 +      if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
 +        {
 +          gchar *name;
 +          pid_t pid;
 +
 +          g_variant_get (body, "(&s)", &name);
 +          pid = _g_kdbus_GetConnectionUnixProcessID (worker, name, &local_error);
 +          if (local_error == NULL)
 +            reply_body = g_variant_new ("(u)", pid);
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'GetConnectionUnixProcessID' has wrong args (expected s)");
 +    }
 +
 +  /*
 +   * GetConnectionUnixUser
 +   */
 +  else if (!g_strcmp0 (member, "GetConnectionUnixUser"))
 +    {
 +      if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
 +        {
 +          gchar *name;
 +          uid_t uid;
 +
 +          g_variant_get (body, "(&s)", &name);
 +          uid = _g_kdbus_GetConnectionUnixUser (worker, name, &local_error);
 +          if (local_error == NULL)
 +            reply_body = g_variant_new ("(u)", uid);
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'GetConnectionUnixUser' has wrong args (expected s)");
 +    }
 +
 +  /*
 +   * GetId
 +   */
 +  else if (!g_strcmp0 (member, "GetId"))
 +    {
 +      if ((body == NULL) || g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
 +        {
 +          gchar *bus_id;
 +
 +          bus_id = _g_kdbus_GetBusId (worker, NULL);
 +          reply_body = g_variant_new ("(s)", bus_id);
 +
 +          g_free (bus_id);
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'GetId' has wrong args");
 +    }
 +
 +  /*
 +   * GetNameOwner
 +   */
 +  else if (!g_strcmp0 (member, "GetNameOwner"))
 +    {
 +      if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
 +        {
 +          gchar *unique_name;
 +          gchar *name;
 +
 +          g_variant_get (body, "(&s)", &name);
 +
 +          unique_name = _g_kdbus_GetNameOwner (worker, name, &local_error);
 +          if (local_error == NULL)
 +            reply_body = g_variant_new ("(s)", unique_name);
 +          g_free (unique_name);
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'GetNameOwner' has wrong args (expected s)");
 +    }
 +
 +  /*
 +   * Hello
 +   */
 +  else if (!g_strcmp0 (member, "Hello"))
 +    {
 +      if ((body == NULL) || g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
 +        {
 +          const gchar *unique_name;
 +
 +          unique_name = _g_kdbus_Hello (worker, &local_error);
 +          if (local_error == NULL)
 +            reply_body = g_variant_new ("(s)", unique_name);
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'Hello' has wrong args");
 +    }
 +
 +  /*
 +   * ListActivatableNames
 +   */
 +  else if (!g_strcmp0 (member, "ListActivatableNames"))
 +    {
 +      if ((body == NULL) || g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
 +        {
 +          gchar **strv;
 +          gint cnt;
 +
 +          cnt = 0;
 +
 +          strv = _g_kdbus_GetListNames (worker, TRUE, &local_error);
 +          if (local_error == NULL)
 +            {
 +              GVariantBuilder *builder;
 +
 +              builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
 +
 +              while (strv[cnt])
 +                g_variant_builder_add (builder, "s", strv[cnt++]);
 +
 +              reply_body = g_variant_new ("(as)", builder);
 +
 +              g_variant_builder_unref (builder);
 +            }
 +          g_strfreev (strv);
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'ListActivatableNames' has wrong args");
 +    }
 +
 +  /*
 +   * ListNames
 +   */
 +  else if (!g_strcmp0 (member, "ListNames"))
 +    {
 +      if ((body == NULL) || g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
 +        {
 +          gchar **strv;
 +          gint cnt;
 +
 +          cnt = 0;
 +
 +          strv = _g_kdbus_GetListNames (worker, FALSE, &local_error);
 +          if (local_error == NULL)
 +            {
 +              GVariantBuilder *builder;
 +
 +              builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
 +
 +              while (strv[cnt])
 +                g_variant_builder_add (builder, "s", strv[cnt++]);
 +
 +              reply_body = g_variant_new ("(as)", builder);
 +
 +              g_variant_builder_unref (builder);
 +            }
 +          g_strfreev (strv);
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'ListNames' has wrong args");
 +    }
 +
 +  /*
 +   * ListQueuedOwners
 +   */
 +  else if (!g_strcmp0 (member, "ListQueuedOwners"))
 +    {
 +      if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
 +        {
 +          gchar **strv;
 +          gchar *name;
 +          gint cnt;
 +
 +          cnt = 0;
 +
 +          g_variant_get (body, "(&s)", &name);
 +          strv = _g_kdbus_GetListQueuedOwners (worker, name, &local_error);
 +          if (local_error == NULL)
 +            {
 +              GVariantBuilder *builder;
 +
 +              builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
 +
 +              while (strv[cnt])
 +                g_variant_builder_add (builder, "s", strv[cnt++]);
 +
 +              reply_body = g_variant_new ("(as)", builder);
 +
 +              g_variant_builder_unref (builder);
 +            }
 +          g_strfreev (strv);
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'ListQueuedOwners' has wrong args (expected s)");
 +    }
 +
 +  /*
 +   * NameHasOwner
 +   */
 +  else if (!g_strcmp0 (member, "NameHasOwner"))
 +    {
 +      if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
 +        {
 +          gboolean ret;
 +          gchar *name;
 +
 +          g_variant_get (body, "(&s)", &name);
 +
 +          ret = _g_kdbus_NameHasOwner (worker, name, &local_error);
 +          if (local_error == NULL)
 +            {
 +              if (ret)
 +                reply_body = g_variant_new ("(b)", TRUE);
 +              else
 +                reply_body = g_variant_new ("(b)", FALSE);
 +            }
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'NameHasOwner' has wrong args (expected s)");
 +    }
 +
 +  /*
 +   * ReleaseName
 +   */
 +  else if (!g_strcmp0 (member, "ReleaseName"))
 +    {
 +      if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
 +        {
 +          GBusReleaseNameReplyFlags status;
 +          gchar *name;
 +
 +          g_variant_get (body, "(&s)", &name);
 +
 +          status = _g_kdbus_ReleaseName (worker, name, &local_error);
 +          if (local_error == NULL)
 +            reply_body = g_variant_new ("(u)", status);
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'ReleaseName' has wrong args (expected s)");
 +    }
 +
 +  /*
 +   * ReloadConfig
 +   */
 +  else if (!g_strcmp0 (member, "ReloadConfig"))
 +    {
 +      if ((body == NULL) || g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
 +        reply_body = g_variant_new ("()", NULL);
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'ReloadConfig' has wrong args");
 +    }
 +
 +  /*
 +   * RequestName
 +   */
 +  else if (!g_strcmp0 (member, "RequestName"))
 +    {
 +      if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(su)")))
 +        {
 +          GBusRequestNameReplyFlags status;
 +          guint32 flags;
 +          gchar *name;
 +
 +          g_variant_get (body, "(&su)", &name, &flags);
 +
 +          status = _g_kdbus_RequestName (worker, name, flags, &local_error);
 +          if (local_error == NULL)
 +            reply_body = g_variant_new ("(u)", status);
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'RequestName' has wrong args (expected su)");
 +    }
 +
 +  /*
 +   * StartServiceByName
 +   */
 +  else if (!g_strcmp0 (member, "StartServiceByName"))
 +    {
 +      if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(su)")))
 +        {
 +          GBusStartServiceReplyFlags status;
 +          gchar *name;
 +          guint32 flags;
 +
 +          g_variant_get (body, "(&su)", &name, &flags);
 +
 +          status = _g_kdbus_StartServiceByName (worker, name, flags, &local_error);
 +          if (local_error == NULL)
 +            reply_body = g_variant_new ("(u)", status);
 +        }
 +      else
 +        g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
 +                     "Call to 'StartServiceByName' has wrong args (expected su)");
 +    }
 +
 +  /*
 +   * UpdateActivationEnvironment
 +   */
 +  else if (!g_strcmp0 (member, "UpdateActivationEnvironment"))
 +    {
 +      g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED,
 +                   "'%s' method not supported", member);
 +    }
 +
 +  /*
 +   * Method not supported
 +   */
 +  else
 +    {
 +      g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD,
 +                   "org.freedesktop.DBus does not understand message %s", member);
 +    }
 +
 +  if (reply_body == NULL && local_error)
 +    {
 +      gchar *dbus_error_name;
 +
 +      dbus_error_name = g_dbus_error_encode_gerror (local_error);
++      reply = g_dbus_message_new_method_error (message, dbus_error_name, "%s", local_error->message);
 +      g_free (dbus_error_name);
 +    }
 +  else
 +    {
 +      reply = g_dbus_message_new_method_reply (message);
 +      g_dbus_message_set_body (reply, reply_body);
 +    }
 +
 +  g_dbus_message_set_serial (reply, -1);
 +
 +  if (local_error)
 +    g_error_free (local_error);
 +
 +  if (G_UNLIKELY (_g_dbus_debug_message ()))
 +    {
 +      gchar *s;
 +      _g_dbus_debug_print_lock ();
 +      g_print ("========================================================================\n"
 +               "GDBus-debug:Message:\n"
 +               "  <<<< RECEIVED synthetic D-Bus message\n");
 +      s = g_dbus_message_print (reply, 2);
 +      g_print ("%s", s);
 +      g_free (s);
 +      _g_dbus_debug_print_unlock ();
 +    }
 +
 +  return reply;
 +}
Simple merge
diff --cc glib/gbytes.c
  
  struct _GBytes
  {
 -  gconstpointer data;  /* may be NULL iff (size == 0) */
 -  gsize size;  /* may be 0 */
 -  gint ref_count;
 -  GDestroyNotify free_func;
 -  gpointer user_data;
 +  gsize size;
 +  gint  ref_count;
 +  gint  type_or_fd;
  };
  
 +typedef struct
 +{
 +  GBytes bytes;
 +#if GLIB_SIZEOF_SIZE_T == 4
 +  guint pad;
 +#endif
 +
 +  guchar data[1];
 +} GBytesInline;
 +
 +/* important: the ->data field of GBytesInline should always be 'nicely
 + * aligned'.
 + */
 +G_STATIC_ASSERT (G_STRUCT_OFFSET (GBytesInline, data) % (2 * sizeof (gpointer)) == 0);
 +G_STATIC_ASSERT (G_STRUCT_OFFSET (GBytesInline, data) % 8 == 0);
 +
 +
 +typedef struct
 +{
 +  GBytes   bytes;
 +
 +  gpointer data;
 +} GBytesData;
 +
 +typedef struct
 +{
 +  GBytesData     data_bytes;
 +
 +  GDestroyNotify notify;
 +  gpointer       user_data;
 +} GBytesNotify;
 +
 +#define G_BYTES_TYPE_INLINE        (-1)
 +#define G_BYTES_TYPE_STATIC        (-2)
 +#define G_BYTES_TYPE_FREE          (-3)
 +#define G_BYTES_TYPE_NOTIFY        (-4)
 +
 +/* All bytes are either inline or subtypes of GBytesData */
 +#define G_BYTES_IS_INLINE(bytes)   ((bytes)->type_or_fd == G_BYTES_TYPE_INLINE)
 +#define G_BYTES_IS_DATA(bytes)     (!G_BYTES_IS_INLINE(bytes))
 +
 +/* More specific subtypes of GBytesData */
 +#define G_BYTES_IS_STATIC(bytes)   ((bytes)->type_or_fd == G_BYTES_TYPE_STATIC)
 +#define G_BYTES_IS_FREE(bytes)     ((bytes)->type_or_fd == G_BYTES_TYPE_FREE)
 +#define G_BYTES_IS_NOTIFY(bytes)   ((bytes)->type_or_fd == G_BYTES_TYPE_NOTIFY)
 +
 +/* we have a memfd if type_or_fd >= 0 */
 +#define G_BYTES_IS_MEMFD(bytes)    ((bytes)->type_or_fd >= 0)
 +
 +static gpointer
 +g_bytes_allocate (guint struct_size,
 +                  guint type_or_fd,
 +                  gsize data_size)
 +{
 +  GBytes *bytes;
 +
 +  bytes = g_slice_alloc (struct_size);
 +  bytes->size = data_size;
 +  bytes->ref_count = 1;
 +  bytes->type_or_fd = type_or_fd;
 +
 +  return bytes;
 +}
 +
  /**
   * g_bytes_new:
-  * @data: (transfer none) (array length=size) (element-type guint8) (allow-none):
+  * @data: (transfer none) (array length=size) (element-type guint8) (nullable):
   *        the data to be used for the bytes
   * @size: the size of @data
   *
@@@ -172,67 -97,8 +172,67 @@@ g_bytes_new (gconstpointer data
  }
  
  /**
 + * g_bytes_new_take_zero_copy_fd:
 + * @fd: a file descriptor capable of being zero-copy-safe
 + *
 + * Creates a new #GBytes from @fd.
 + *
 + * @fd must be capable of being made zero-copy-safe.  In concrete terms,
 + * this means that a call to g_unix_fd_ensure_zero_copy_safe() on @fd
 + * will succeed.  This call will be made before returning.
 + *
 + * This call consumes @fd, transferring ownership to the returned
 + * #GBytes.
 + *
 + * Returns: (transfer full): a new #GBytes
 + *
 + */
 +#ifdef G_OS_UNIX
 +GBytes *
 +g_bytes_new_take_zero_copy_fd (gint fd)
 +{
 +  GBytesData *bytes;
 +  struct stat buf;
 +
 +  /* We already checked this is a memfd... */
 +  g_assert_se (fstat (fd, &buf) == 0);
 +
 +  bytes = g_bytes_new_take_zero_copy_fd_size(fd, buf.st_size);
 +
 +  if (buf.st_size == 0)
 +    {
 +      g_assert_se (close (fd) == 0);
 +    }
 +
 +  return (GBytes *) bytes;
 +}
 +
 +GBytes *
 +g_bytes_new_take_zero_copy_fd_size (gint fd, gsize size)
 +{
 +  GBytesData *bytes;
 +
 +  g_return_val_if_fail_se (g_unix_fd_ensure_zero_copy_safe (fd), NULL);
 +
 +  /* We already checked this is a memfd... */
 +  if (size == 0)
 +    {
 +      return g_bytes_new (NULL, 0);
 +    }
 +
 +  bytes = g_bytes_allocate (sizeof (GBytesData), fd, size);
 +  bytes->data = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
 +  if (bytes->data == MAP_FAILED)
 +    /* this is similar to malloc() failing, so do the same... */
 +    g_error ("mmap() on memfd failed: %s\n", g_strerror (errno));
 +
 +  return (GBytes *) bytes;
 +}
 +#endif /* G_OS_UNIX */
 +
 +/**
   * g_bytes_new_take:
-  * @data: (transfer full) (array length=size) (element-type guint8) (allow-none):
+  * @data: (transfer full) (array length=size) (element-type guint8) (nullable):
            the data to be used for the bytes
   * @size: the size of @data
   *
@@@ -46,9 -47,7 +47,11 @@@ glib__private__ (void
      g_dir_open_with_errno,
      g_dir_new_from_dirp,
  
 -    glib_init,
 +    g_variant_to_vectors,
 +    g_variant_from_vectors,
-     g_variant_vectors_deinit
++    g_variant_vectors_deinit,
++
++    glib_init
    };
  
    return &table;
@@@ -69,15 -61,9 +69,18 @@@ typedef struct 
                                                           guint        flags);
    GDir *                (* g_dir_new_from_dirp)         (gpointer dirp);
  
 +  void                  (* g_variant_to_vectors)        (GVariant    *value,
 +                                                         GVariantVectors *vectors);
 +  GVariant *            (* g_variant_from_vectors)      (const GVariantType *type,
 +                                                         GVariantVector  *vectors,
 +                                                         gsize            n_vectors,
 +                                                         gsize size,
 +                                                         gboolean trusted);
 +  void                  (* g_variant_vectors_deinit)    (GVariantVectors *vectors);
 +
+   /* See glib-init.c */
+   void                  (* glib_init)                   (void);
    /* Add other private functions here, initialize them in glib-private.c */
  } GLibPrivateVTable;
  
Simple merge
   * an error message is logged and the application is terminated.
   *
   * The macro can be turned off in final releases of code by defining
-  * `G_DISABLE_ASSERT` when compiling the application.
+  * `G_DISABLE_ASSERT` when compiling the application, so code must
+  * not depend on any side effects from @expr.
 + *
 + * For a version which is guaranteed to evaluate side effects in @expr,
 + * see g_assert_se().
 + */
 +
 +/**
 + * g_assert_se:
 + * @expr: the expression to check
 + *
 + * Debugging macro to terminate the application if the assertion
 + * fails. If the assertion fails (i.e. the expression is not true),
 + * an error message is logged and the application is terminated.
 + *
 + * The check can be turned off in final releases of code by defining
 + * `G_DISABLE_ASSERT` when compiling the application.
 + *
 + * Unlike g_assert(), this macro is guaranteed to evaluate side effects
 + * of @expr, even if checks are disabled.  It is still undefined if the
 + * program will actually be aborted or not.
   */
  
  /**
Simple merge
Simple merge
Simple merge
Simple merge
diff --cc glib/gvariant.c
Simple merge
diff --cc glib/gvariant.h
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -4612,81 -4533,72 +4611,147 @@@ G_GNUC_BEGIN_IGNORE_DEPRECATION
  G_GNUC_END_IGNORE_DEPRECATIONS
  }
  
 +static GByteArray *
 +flatten_vectors (GVariantVectors *v)
 +{
 +  GByteArray *result;
 +  guint i;
 +
 +  result = g_byte_array_new ();
 +
 +  for (i = 0; i < v->vectors->len; i++)
 +    {
 +      GVariantVector vec = g_array_index (v->vectors, GVariantVector, i);
 +
 +      if (vec.gbytes)
 +        g_byte_array_append (result, vec.data.pointer, vec.size);
 +      else
 +        g_byte_array_append (result, v->extra_bytes->data + vec.data.offset, vec.size);
 +    }
 +
 +  return result;
 +}
 +
 +static void
 +test_vector_serialiser (void)
 +{
 +  GVariantVectors vectors;
 +  GByteArray *flattened;
 +  GVariant *value;
 +  guint i;
 +
 +  for (i = 0; i < 100; i++)
 +    {
 +      guint j;
 +
 +      value = create_random_gvariant (2);
 +      //g_print (">>> %s\n", g_variant_print (value, TRUE));
 +
 +      GLIB_PRIVATE_CALL(g_variant_to_vectors) (value, &vectors);
 +      for (j = 0; j < vectors.vectors->len; j++)
 +        {
 +          GVariantVector *v = &g_array_index (vectors.vectors, GVariantVector, j);
 +
 +          if (!v->gbytes)
 +            {
 +              v->gbytes = g_bytes_new (NULL, 0);
 +              v->data.pointer = v->data.offset + vectors.extra_bytes->data;
 +            }
 +
 +          //g_print ("  V %p %p %d\n", v, v->data.pointer, (guint) v->size);
 +        }
 +      GLIB_PRIVATE_CALL(g_variant_from_vectors) (g_variant_get_type (value), (GVariantVector *) vectors.vectors->data, vectors.vectors->len, g_variant_get_size (value), TRUE);
 +      continue;
 +      flattened = flatten_vectors (&vectors);
 +      g_byte_array_free (vectors.extra_bytes, TRUE);
 +      g_byte_array_free (vectors.offsets, TRUE);
 +      g_array_free (vectors.vectors, TRUE);
 +
 +#if 0
 +      if (flattened->len != g_variant_get_size (value) ||
 +          memcmp (flattened->data, g_variant_get_data (value), flattened->len) != 0)
 +        {
 +          g_file_set_contents ("flattened", flattened->data, flattened->len, NULL);
 +          g_file_set_contents ("serialised", g_variant_get_data (value), g_variant_get_size (value), NULL);
 +          g_print ("type is %s\n", g_variant_get_type_string (value));
 +          g_assert_not_reached ();
 +        }
 +#endif
 +
 +      g_assert_cmpint (flattened->len, ==, g_variant_get_size (value));
 +      g_assert (memcmp (flattened->data, g_variant_get_data (value), flattened->len) == 0);
 +
 +      g_byte_array_free (flattened, TRUE);
 +      g_variant_unref (value);
 +    }
 +}
 +
+ static void
+ test_stack_builder_init (void)
+ {
+   GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_BYTESTRING);
+   GVariant *variant;
+   g_variant_builder_add_value (&builder, g_variant_new_byte ('g'));
+   g_variant_builder_add_value (&builder, g_variant_new_byte ('l'));
+   g_variant_builder_add_value (&builder, g_variant_new_byte ('i'));
+   g_variant_builder_add_value (&builder, g_variant_new_byte ('b'));
+   g_variant_builder_add_value (&builder, g_variant_new_byte ('\0'));
+   variant = g_variant_ref_sink (g_variant_builder_end (&builder));
+   g_assert_nonnull (variant);
+   g_assert (g_variant_type_equal (g_variant_get_type (variant),
+                                   G_VARIANT_TYPE_BYTESTRING));
+   g_assert_cmpuint (g_variant_n_children (variant), ==, 5);
+   g_assert_cmpstr (g_variant_get_bytestring (variant), ==, "glib");
+   g_variant_unref (variant);
+ }
+ static GVariant *
+ get_asv (void)
+ {
+   GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
+   g_variant_builder_add (&builder, "{s@v}", "foo", g_variant_new_variant (g_variant_new_string ("FOO")));
+   g_variant_builder_add (&builder, "{s@v}", "bar", g_variant_new_variant (g_variant_new_string ("BAR")));
+   return g_variant_ref_sink (g_variant_builder_end (&builder));
+ }
+ static void
+ test_stack_dict_init (void)
+ {
+   GVariant *asv = get_asv ();
+   GVariantDict dict = G_VARIANT_DICT_INIT (asv);
+   GVariant *variant;
+   GVariantIter iter;
+   gchar *key;
+   GVariant *value;
+   g_variant_dict_insert_value (&dict, "baz", g_variant_new_string ("BAZ"));
+   g_variant_dict_insert_value (&dict, "quux", g_variant_new_string ("QUUX"));
+   variant = g_variant_ref_sink (g_variant_dict_end (&dict));
+   g_assert_nonnull (variant);
+   g_assert (g_variant_type_equal (g_variant_get_type (variant),
+                                   G_VARIANT_TYPE_VARDICT));
+   g_assert_cmpuint (g_variant_n_children (variant), ==, 4);
+   g_variant_iter_init (&iter, variant);
+   while (g_variant_iter_next (&iter, "{sv}", &key, &value))
+     {
+       gchar *strup = g_ascii_strup (key, -1);
+       g_assert_cmpstr (strup, ==, g_variant_get_string (value, NULL));
+       g_free (key);
+       g_free (strup);
+       g_variant_unref (value);
+     }
+   g_variant_unref (asv);
+   g_variant_unref (variant);
+ }
  int
  main (int argc, char **argv)
  {
    g_test_add_func ("/gvariant/gbytes", test_gbytes);
    g_test_add_func ("/gvariant/print-context", test_print_context);
    g_test_add_func ("/gvariant/error-quark", test_error_quark);
 +  g_test_add_func ("/gvariant/vector-serialiser", test_vector_serialiser);
  
+   g_test_add_func ("/gvariant/stack-builder-init", test_stack_builder_init);
+   g_test_add_func ("/gvariant/stack-dict-init", test_stack_dict_init);
    return g_test_run ();
  }