mention inline use of floating variants
[platform/upstream/glib.git] / gio / gdbusconnection.c
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: David Zeuthen <davidz@redhat.com>
21  */
22
23 /*
24  * TODO for GDBus:
25  *
26  * - Validate all data (e.g. UTF-8) and check all the required D-Bus headers
27  *   are present and forbidden ones aren't
28  *   - When writing: g_dbus_message_to_blob()
29  *   - When reading: g_dbus_message_new_from_blob()
30  *
31  * - would be nice to expose GDBusAuthMechanism and an extension point
32  *
33  * - Need to rewrite GDBusAuth and rework GDBusAuthMechanism. In particular
34  *   the mechanism VFuncs need to be able to set an error.
35  *
36  * - Need to document other mechanisms/sources for determining the D-Bus
37  *   address of a well-known bus.
38  *
39  *   - e.g. on Win32 we need code like from here
40  *
41  *     http://cgit.freedesktop.org/~david/gdbus-standalone/tree/gdbus/gdbusaddress.c#n900
42  *
43  *     that was never copied over here because it originally was copy-paste
44  *     from the GPLv2 / AFL 2.1 libdbus sources.
45  *
46  *   - on OS X we need to look in launchd for the address
47  *
48  *     https://bugs.freedesktop.org/show_bug.cgi?id=14259
49  *
50  *   - on X11 we need to look in a X11 property on the X server
51  *     - (we can also just use dbus-launch(1) from the D-Bus
52  *        distribution)
53  *
54  *   - (ideally) this requires D-Bus spec work because none of
55  *     this has never really been specced out properly (excect
56  *     the X11 bits)
57  *
58  * - Related to the above, we also need to be able to launch a message bus
59  *   instance.... Since we don't want to write our own bus daemon we should
60  *   launch dbus-daemon(1) (thus: Win32 and OS X need to bundle it)
61  *
62  * - probably want a G_DBUS_NONCE_TCP_TMPDIR environment variable
63  *   to specify where the nonce is stored. This will allow people to use
64  *   G_DBUS_NONCE_TCP_TMPDIR=/mnt/secure.company.server/dbus-nonce-dir
65  *   to easily acheive secure RPC via nonce-tcp.
66  *
67  * - need to expose an extension point for resolving D-Bus address and
68  *   turning them into GIOStream objects. This will allow us to implement
69  *   e.g. X11 D-Bus transports without dlopen()'ing or linking against
70  *   libX11 from libgio.
71  *   - see g_dbus_address_connect() in gdbusaddress.c
72  *
73  * - would be cute to use kernel-specific APIs to resolve fds for
74  *   debug output when using G_DBUS_DEBUG=messages, e.g. in addition to
75  *
76  *     fd 21: dev=8:1,mode=0100644,ino=1171231,uid=0,gid=0,rdev=0:0,size=234,atime=1273070640,mtime=1267126160,ctime=1267126160
77  *
78  *   maybe we can show more information about what fd 21 really is.
79  *   Ryan suggests looking in /proc/self/fd for clues / symlinks!
80  *   Initial experiments on Linux 2.6 suggests that the symlink looks
81  *   like this:
82  *
83  *    3 -> /proc/18068/fd
84  *
85  *   e.g. not of much use.
86  *
87  *  - GDBus High-Level docs
88  *    - Proxy: properties, signals...
89  *    - Connection: IOStream based, ::close, connection setup steps
90  *                  mainloop integration, threading
91  *    - Differences from libdbus (extend "Migrating from")
92  *      - the message handling thread
93  *      - Using GVariant instead of GValue
94  *    - Explain why the high-level API is a good thing and what
95  *      kind of pitfalls it avoids
96  *      - Export objects before claiming names
97  *    - Talk about auto-starting services (cf. GBusNameWatcherFlags)
98  *
99  *  - Mention in all API that the GVariant is sunk. Also mention
100  *    when the returned GVariant is floating.
101  *
102  *  - Small example snippet for each method where useful (won't
103  *    have to compile) where it makes sense (e.g. connetion_call()
104  *    and using a floating GVariant).
105  *
106  *  - Consistent timeout handling (25s vs 30s?)
107  *
108  *  - GDBusProxy subclass example
109  *
110  *  - Update GDBusAuthObserver (is_same_user(), s/deny/authorize/)
111  */
112
113 #include "config.h"
114
115 #include <stdlib.h>
116 #include <string.h>
117
118 #include "gdbusauth.h"
119 #include "gdbusutils.h"
120 #include "gdbusaddress.h"
121 #include "gdbusmessage.h"
122 #include "gdbusconnection.h"
123 #include "gdbuserror.h"
124 #include "gioenumtypes.h"
125 #include "gdbusintrospection.h"
126 #include "gdbusmethodinvocation.h"
127 #include "gdbusprivate.h"
128 #include "gdbusauthobserver.h"
129 #include "gio-marshal.h"
130 #include "ginitable.h"
131 #include "gasyncinitable.h"
132 #include "giostream.h"
133 #include "gasyncresult.h"
134 #include "gsimpleasyncresult.h"
135
136 #ifdef G_OS_UNIX
137 #include <gio/gunixconnection.h>
138 #include <gio/gunixfdmessage.h>
139 #include <unistd.h>
140 #include <sys/types.h>
141 #endif
142
143 #include "glibintl.h"
144 #include "gioalias.h"
145
146 /**
147  * SECTION:gdbusconnection
148  * @short_description: D-Bus Connections
149  * @include: gio/gio.h
150  *
151  * The #GDBusConnection type is used for D-Bus connections to remote
152  * peers such as a message buses. It is a low-level API that offers a
153  * lot of flexibility. For instance, it lets you establish a connection
154  * over any transport that can by represented as an #GIOStream.
155  *
156  * This class is rarely used directly in D-Bus clients. If you are writing
157  * an D-Bus client, it is often easier to use the g_bus_own_name(),
158  * g_bus_watch_name() or g_bus_watch_proxy() APIs.
159  *
160  * <example id="gdbus-server"><title>D-Bus server example</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-server.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
161  *
162  * <example id="gdbus-subtree-server"><title>D-Bus subtree example</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-subtree.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
163  *
164  * <example id="gdbus-unix-fd-client"><title>D-Bus UNIX File Descriptor example</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gdbus-example-unix-fd-client.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
165  */
166
167 /* ---------------------------------------------------------------------------------------------------- */
168
169 G_LOCK_DEFINE_STATIC (message_bus_lock);
170
171 static GDBusConnection *the_session_bus = NULL;
172 static GDBusConnection *the_system_bus = NULL;
173
174 /* ---------------------------------------------------------------------------------------------------- */
175
176 static gboolean
177 _g_strv_has_string (const gchar* const *haystack,
178                     const gchar        *needle)
179 {
180   guint n;
181
182   for (n = 0; haystack != NULL && haystack[n] != NULL; n++)
183     {
184       if (g_strcmp0 (haystack[n], needle) == 0)
185         return TRUE;
186     }
187   return FALSE;
188 }
189
190 /* ---------------------------------------------------------------------------------------------------- */
191
192 #ifdef G_OS_WIN32
193 #define CONNECTION_ENSURE_LOCK(obj) do { ; } while (FALSE)
194 #else
195 // TODO: for some reason this doesn't work on Windows
196 #define CONNECTION_ENSURE_LOCK(obj) do {                                \
197     if (G_UNLIKELY (g_mutex_trylock((obj)->priv->lock)))                \
198       {                                                                 \
199         g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
200                              "CONNECTION_ENSURE_LOCK: GDBusConnection object lock is not locked"); \
201       }                                                                 \
202   } while (FALSE)
203 #endif
204
205 #define CONNECTION_LOCK(obj) do {                                       \
206     g_mutex_lock ((obj)->priv->lock);                                   \
207   } while (FALSE)
208
209 #define CONNECTION_UNLOCK(obj) do {                                     \
210     g_mutex_unlock ((obj)->priv->lock);                                 \
211   } while (FALSE)
212
213 struct _GDBusConnectionPrivate
214 {
215   /* ------------------------------------------------------------------------ */
216   /* -- General object state ------------------------------------------------ */
217   /* ------------------------------------------------------------------------ */
218
219   /* object-wide lock */
220   GMutex *lock;
221
222   /* A lock used in the init() method of the GInitable interface - see comments
223    * in initable_init() for why a separate lock is needed
224    */
225   GMutex *init_lock;
226
227   /* Set (by loading the contents of /var/lib/dbus/machine-id) the first time
228    * someone calls org.freedesktop.DBus.GetMachineId()
229    */
230   gchar *machine_id;
231
232   /* The underlying stream used for communication */
233   GIOStream *stream;
234
235   /* The object used for authentication (if any) */
236   GDBusAuth *auth;
237
238   /* Set to TRUE if the connection has been closed */
239   gboolean closed;
240
241   /* Last serial used */
242   guint32 last_serial;
243
244   /* The object used to send/receive message */
245   GDBusWorker *worker;
246
247   /* If connected to a message bus, this contains the unique name assigned to
248    * us by the bus (e.g. ":1.42")
249    */
250   gchar *bus_unique_name;
251
252   /* The GUID returned by the other side if we authenticed as a client or
253    * the GUID to use if authenticating as a server
254    */
255   gchar *guid;
256
257   /* set to TRUE exactly when initable_init() has finished running */
258   gboolean is_initialized;
259
260   /* If the connection could not be established during initable_init(), this GError will set */
261   GError *initialization_error;
262
263   /* The result of g_main_context_get_thread_default() when the object
264    * was created (the GObject _init() function) - this is used for delivery
265    * of the :closed GObject signal.
266    */
267   GMainContext *main_context_at_construction;
268
269   /* construct properties */
270   gchar *address;
271   GDBusConnectionFlags flags;
272
273   /* Map used for managing method replies */
274   GHashTable *map_method_serial_to_send_message_data;  /* guint32 -> SendMessageData* */
275
276   /* Maps used for managing signal subscription */
277   GHashTable *map_rule_to_signal_data;          /* gchar* -> SignalData */
278   GHashTable *map_id_to_signal_data;            /* guint  -> SignalData */
279   GHashTable *map_sender_to_signal_data_array;  /* gchar* -> GPtrArray* of SignalData */
280
281   /* Maps used for managing exported objects and subtrees */
282   GHashTable *map_object_path_to_eo;  /* gchar* -> ExportedObject* */
283   GHashTable *map_id_to_ei;           /* guint  -> ExportedInterface* */
284   GHashTable *map_object_path_to_es;  /* gchar* -> ExportedSubtree* */
285   GHashTable *map_id_to_es;           /* guint  -> ExportedSubtree* */
286
287   /* Structure used for message filters */
288   GPtrArray *filters;
289
290   /* Whether to exit on close */
291   gboolean exit_on_close;
292
293   /* Capabilities negotiated during authentication */
294   GDBusCapabilityFlags capabilities;
295
296   GDBusAuthObserver *authentication_observer;
297   GCredentials *crendentials;
298 };
299
300 typedef struct ExportedObject ExportedObject;
301 static void exported_object_free (ExportedObject *eo);
302
303 typedef struct ExportedSubtree ExportedSubtree;
304 static void exported_subtree_free (ExportedSubtree *es);
305
306 enum
307 {
308   CLOSED_SIGNAL,
309   LAST_SIGNAL,
310 };
311
312 enum
313 {
314   PROP_0,
315   PROP_STREAM,
316   PROP_ADDRESS,
317   PROP_FLAGS,
318   PROP_GUID,
319   PROP_UNIQUE_NAME,
320   PROP_CLOSED,
321   PROP_EXIT_ON_CLOSE,
322   PROP_CAPABILITY_FLAGS,
323   PROP_AUTHENTICATION_OBSERVER,
324 };
325
326 static void distribute_signals (GDBusConnection  *connection,
327                                 GDBusMessage     *message);
328
329 static void distribute_method_call (GDBusConnection  *connection,
330                                     GDBusMessage     *message);
331
332 static gboolean handle_generic_unlocked (GDBusConnection *connection,
333                                          GDBusMessage    *message);
334
335
336 static void purge_all_signal_subscriptions (GDBusConnection *connection);
337 static void purge_all_filters (GDBusConnection *connection);
338
339 #define _G_ENSURE_LOCK(name) do {                                       \
340     if (G_UNLIKELY (G_TRYLOCK(name)))                                   \
341       {                                                                 \
342         g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
343                              "_G_ENSURE_LOCK: Lock `" #name "' is not locked"); \
344       }                                                                 \
345   } while (FALSE)                                                       \
346
347 static guint signals[LAST_SIGNAL] = { 0 };
348
349 static void initable_iface_init       (GInitableIface      *initable_iface);
350 static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
351
352 G_DEFINE_TYPE_WITH_CODE (GDBusConnection, g_dbus_connection, G_TYPE_OBJECT,
353                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
354                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
355                          );
356
357 static void
358 g_dbus_connection_dispose (GObject *object)
359 {
360   GDBusConnection *connection = G_DBUS_CONNECTION (object);
361
362   G_LOCK (message_bus_lock);
363   //g_debug ("disposing %p", connection);
364   if (connection == the_session_bus)
365     {
366       the_session_bus = NULL;
367     }
368   else if (connection == the_system_bus)
369     {
370       the_system_bus = NULL;
371     }
372   if (connection->priv->worker != NULL)
373     {
374       _g_dbus_worker_stop (connection->priv->worker);
375       connection->priv->worker = NULL;
376     }
377   G_UNLOCK (message_bus_lock);
378
379   if (G_OBJECT_CLASS (g_dbus_connection_parent_class)->dispose != NULL)
380     G_OBJECT_CLASS (g_dbus_connection_parent_class)->dispose (object);
381 }
382
383 static void
384 g_dbus_connection_finalize (GObject *object)
385 {
386   GDBusConnection *connection = G_DBUS_CONNECTION (object);
387
388   if (connection->priv->authentication_observer != NULL)
389     g_object_unref (connection->priv->authentication_observer);
390
391   if (connection->priv->auth != NULL)
392     g_object_unref (connection->priv->auth);
393
394   //g_debug ("finalizing %p", connection);
395   if (connection->priv->stream != NULL)
396     {
397       /* We don't really care if closing the stream succeeds or not */
398       g_io_stream_close_async (connection->priv->stream,
399                                G_PRIORITY_DEFAULT,
400                                NULL,  /* GCancellable */
401                                NULL,  /* GAsyncReadyCallback */
402                                NULL); /* userdata */
403       g_object_unref (connection->priv->stream);
404       connection->priv->stream = NULL;
405     }
406
407   g_free (connection->priv->address);
408
409   g_free (connection->priv->guid);
410   g_free (connection->priv->bus_unique_name);
411
412   if (connection->priv->initialization_error != NULL)
413     g_error_free (connection->priv->initialization_error);
414
415   g_hash_table_unref (connection->priv->map_method_serial_to_send_message_data);
416
417   purge_all_signal_subscriptions (connection);
418   g_hash_table_unref (connection->priv->map_rule_to_signal_data);
419   g_hash_table_unref (connection->priv->map_id_to_signal_data);
420   g_hash_table_unref (connection->priv->map_sender_to_signal_data_array);
421
422   g_hash_table_unref (connection->priv->map_id_to_ei);
423   g_hash_table_unref (connection->priv->map_object_path_to_eo);
424   g_hash_table_unref (connection->priv->map_id_to_es);
425   g_hash_table_unref (connection->priv->map_object_path_to_es);
426
427   purge_all_filters (connection);
428   g_ptr_array_unref (connection->priv->filters);
429
430   if (connection->priv->main_context_at_construction != NULL)
431     g_main_context_unref (connection->priv->main_context_at_construction);
432
433   g_free (connection->priv->machine_id);
434
435   g_mutex_free (connection->priv->init_lock);
436   g_mutex_free (connection->priv->lock);
437
438   G_OBJECT_CLASS (g_dbus_connection_parent_class)->finalize (object);
439 }
440
441 static void
442 g_dbus_connection_get_property (GObject    *object,
443                                 guint       prop_id,
444                                 GValue     *value,
445                                 GParamSpec *pspec)
446 {
447   GDBusConnection *connection = G_DBUS_CONNECTION (object);
448
449   switch (prop_id)
450     {
451     case PROP_STREAM:
452       g_value_set_object (value, g_dbus_connection_get_stream (connection));
453       break;
454
455     case PROP_GUID:
456       g_value_set_string (value, g_dbus_connection_get_guid (connection));
457       break;
458
459     case PROP_UNIQUE_NAME:
460       g_value_set_string (value, g_dbus_connection_get_unique_name (connection));
461       break;
462
463     case PROP_CLOSED:
464       g_value_set_boolean (value, g_dbus_connection_is_closed (connection));
465       break;
466
467     case PROP_EXIT_ON_CLOSE:
468       g_value_set_boolean (value, g_dbus_connection_get_exit_on_close (connection));
469       break;
470
471     case PROP_CAPABILITY_FLAGS:
472       g_value_set_flags (value, g_dbus_connection_get_capabilities (connection));
473       break;
474
475     default:
476       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
477       break;
478     }
479 }
480
481 static void
482 g_dbus_connection_set_property (GObject      *object,
483                                 guint         prop_id,
484                                 const GValue *value,
485                                 GParamSpec   *pspec)
486 {
487   GDBusConnection *connection = G_DBUS_CONNECTION (object);
488
489   switch (prop_id)
490     {
491     case PROP_STREAM:
492       connection->priv->stream = g_value_dup_object (value);
493       break;
494
495     case PROP_GUID:
496       connection->priv->guid = g_value_dup_string (value);
497       break;
498
499     case PROP_ADDRESS:
500       connection->priv->address = g_value_dup_string (value);
501       break;
502
503     case PROP_FLAGS:
504       connection->priv->flags = g_value_get_flags (value);
505       break;
506
507     case PROP_EXIT_ON_CLOSE:
508       g_dbus_connection_set_exit_on_close (connection, g_value_get_boolean (value));
509       break;
510
511     case PROP_AUTHENTICATION_OBSERVER:
512       connection->priv->authentication_observer = g_value_dup_object (value);
513       break;
514
515     default:
516       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
517       break;
518     }
519 }
520
521 static void
522 g_dbus_connection_real_closed (GDBusConnection *connection,
523                                gboolean         remote_peer_vanished,
524                                GError          *error)
525 {
526   if (remote_peer_vanished && connection->priv->exit_on_close)
527     {
528       g_print ("%s: Remote peer vanished. Exiting.\n", G_STRFUNC);
529       raise (SIGTERM);
530     }
531 }
532
533 static void
534 g_dbus_connection_class_init (GDBusConnectionClass *klass)
535 {
536   GObjectClass *gobject_class;
537
538   g_type_class_add_private (klass, sizeof (GDBusConnectionPrivate));
539
540   gobject_class = G_OBJECT_CLASS (klass);
541
542   gobject_class->finalize     = g_dbus_connection_finalize;
543   gobject_class->dispose      = g_dbus_connection_dispose;
544   gobject_class->set_property = g_dbus_connection_set_property;
545   gobject_class->get_property = g_dbus_connection_get_property;
546
547   klass->closed = g_dbus_connection_real_closed;
548
549   /**
550    * GDBusConnection:stream:
551    *
552    * The underlying #GIOStream used for I/O.
553    *
554    * Since: 2.26
555    */
556   g_object_class_install_property (gobject_class,
557                                    PROP_STREAM,
558                                    g_param_spec_object ("stream",
559                                                         P_("IO Stream"),
560                                                         P_("The underlying streams used for I/O"),
561                                                         G_TYPE_IO_STREAM,
562                                                         G_PARAM_READABLE |
563                                                         G_PARAM_WRITABLE |
564                                                         G_PARAM_CONSTRUCT_ONLY |
565                                                         G_PARAM_STATIC_NAME |
566                                                         G_PARAM_STATIC_BLURB |
567                                                         G_PARAM_STATIC_NICK));
568
569   /**
570    * GDBusConnection:address:
571    *
572    * A D-Bus address specifying potential endpoints that can be used
573    * when establishing the connection.
574    *
575    * Since: 2.26
576    */
577   g_object_class_install_property (gobject_class,
578                                    PROP_ADDRESS,
579                                    g_param_spec_string ("address",
580                                                         P_("Address"),
581                                                         P_("D-Bus address specifying potential socket endpoints"),
582                                                         NULL,
583                                                         G_PARAM_WRITABLE |
584                                                         G_PARAM_CONSTRUCT_ONLY |
585                                                         G_PARAM_STATIC_NAME |
586                                                         G_PARAM_STATIC_BLURB |
587                                                         G_PARAM_STATIC_NICK));
588
589   /**
590    * GDBusConnection:flags:
591    *
592    * Flags from the #GDBusConnectionFlags enumeration.
593    *
594    * Since: 2.26
595    */
596   g_object_class_install_property (gobject_class,
597                                    PROP_FLAGS,
598                                    g_param_spec_flags ("flags",
599                                                        P_("Flags"),
600                                                        P_("Flags"),
601                                                        G_TYPE_DBUS_CONNECTION_FLAGS,
602                                                        G_DBUS_CONNECTION_FLAGS_NONE,
603                                                        G_PARAM_WRITABLE |
604                                                        G_PARAM_CONSTRUCT_ONLY |
605                                                        G_PARAM_STATIC_NAME |
606                                                        G_PARAM_STATIC_BLURB |
607                                                        G_PARAM_STATIC_NICK));
608
609   /**
610    * GDBusConnection:guid:
611    *
612    * The GUID of the peer performing the role of server when
613    * authenticating.
614    *
615    * If you are constructing a #GDBusConnection and pass
616    * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER in the
617    * #GDBusConnection:flags property then you MUST also set this
618    * property to a valid guid.
619    *
620    * If you are constructing a #GDBusConnection and pass
621    * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT in the
622    * #GDBusConnection:flags property you will be able to read the GUID
623    * of the other peer here after the connection has been successfully
624    * initialized.
625    *
626    * Since: 2.26
627    */
628   g_object_class_install_property (gobject_class,
629                                    PROP_GUID,
630                                    g_param_spec_string ("guid",
631                                                         P_("GUID"),
632                                                         P_("GUID of the server peer"),
633                                                         NULL,
634                                                         G_PARAM_READABLE |
635                                                         G_PARAM_WRITABLE |
636                                                         G_PARAM_CONSTRUCT_ONLY |
637                                                         G_PARAM_STATIC_NAME |
638                                                         G_PARAM_STATIC_BLURB |
639                                                         G_PARAM_STATIC_NICK));
640
641   /**
642    * GDBusConnection:unique-name:
643    *
644    * The unique name as assigned by the message bus or %NULL if the
645    * connection is not open or not a message bus connection.
646    *
647    * Since: 2.26
648    */
649   g_object_class_install_property (gobject_class,
650                                    PROP_UNIQUE_NAME,
651                                    g_param_spec_string ("unique-name",
652                                                         P_("unique-name"),
653                                                         P_("Unique name of bus connection"),
654                                                         NULL,
655                                                         G_PARAM_READABLE |
656                                                         G_PARAM_STATIC_NAME |
657                                                         G_PARAM_STATIC_BLURB |
658                                                         G_PARAM_STATIC_NICK));
659
660   /**
661    * GDBusConnection:closed:
662    *
663    * A boolean specifying whether the connection has been closed.
664    *
665    * Since: 2.26
666    */
667   g_object_class_install_property (gobject_class,
668                                    PROP_CLOSED,
669                                    g_param_spec_boolean ("closed",
670                                                          P_("Closed"),
671                                                          P_("Whether the connection is closed"),
672                                                          FALSE,
673                                                          G_PARAM_READABLE |
674                                                          G_PARAM_STATIC_NAME |
675                                                          G_PARAM_STATIC_BLURB |
676                                                          G_PARAM_STATIC_NICK));
677
678   /**
679    * GDBusConnection:exit-on-close:
680    *
681    * A boolean specifying whether the process will be terminated (by
682    * calling <literal>raise(SIGTERM)</literal>) if the connection
683    * is closed by the remote peer.
684    *
685    * Since: 2.26
686    */
687   g_object_class_install_property (gobject_class,
688                                    PROP_EXIT_ON_CLOSE,
689                                    g_param_spec_boolean ("exit-on-close",
690                                                          P_("Exit on close"),
691                                                          P_("Whether the process is terminated when the connection is closed"),
692                                                          FALSE,
693                                                          G_PARAM_READABLE |
694                                                          G_PARAM_WRITABLE |
695                                                          G_PARAM_STATIC_NAME |
696                                                          G_PARAM_STATIC_BLURB |
697                                                          G_PARAM_STATIC_NICK));
698
699   /**
700    * GDBusConnection:capabilities:
701    *
702    * Flags from the #GDBusCapabilityFlags enumeration
703    * representing connection features negotiated with the other peer.
704    *
705    * Since: 2.26
706    */
707   g_object_class_install_property (gobject_class,
708                                    PROP_CAPABILITY_FLAGS,
709                                    g_param_spec_flags ("capabilities",
710                                                        P_("Capabilities"),
711                                                        P_("Capabilities"),
712                                                        G_TYPE_DBUS_CAPABILITY_FLAGS,
713                                                        G_DBUS_CAPABILITY_FLAGS_NONE,
714                                                        G_PARAM_READABLE |
715                                                        G_PARAM_STATIC_NAME |
716                                                        G_PARAM_STATIC_BLURB |
717                                                        G_PARAM_STATIC_NICK));
718
719   /**
720    * GDBusConnection:authentication-observer:
721    *
722    * A #GDBusAuthObserver object to assist in the authentication process or %NULL.
723    *
724    * Since: 2.26
725    */
726   g_object_class_install_property (gobject_class,
727                                    PROP_AUTHENTICATION_OBSERVER,
728                                    g_param_spec_object ("authentication-observer",
729                                                         P_("Authentication Observer"),
730                                                         P_("Object used to assist in the authentication process"),
731                                                         G_TYPE_DBUS_AUTH_OBSERVER,
732                                                         G_PARAM_WRITABLE |
733                                                         G_PARAM_CONSTRUCT_ONLY |
734                                                         G_PARAM_STATIC_NAME |
735                                                         G_PARAM_STATIC_BLURB |
736                                                         G_PARAM_STATIC_NICK));
737
738   /**
739    * GDBusConnection::closed:
740    * @connection: The #GDBusConnection emitting the signal.
741    * @remote_peer_vanished: %TRUE if @connection is closed because the
742    * remote peer closed its end of the connection.
743    * @error: A #GError with more details about the event or %NULL.
744    *
745    * Emitted when the connection is closed.
746    *
747    * The cause of this event can be
748    * <itemizedlist>
749    * <listitem><para>
750    *    If g_dbus_connection_close() is called. In this case
751    *    @remote_peer_vanished is set to %FALSE and @error is %NULL.
752    * </para></listitem>
753    * <listitem><para>
754    *    If the remote peer closes the connection. In this case
755    *    @remote_peer_vanished is set to %TRUE and @error is set.
756    * </para></listitem>
757    * <listitem><para>
758    *    If the remote peer sends invalid or malformed data. In this
759    *    case @remote_peer_vanished is set to %FALSE and @error
760    *    is set.
761    * </para></listitem>
762    * </itemizedlist>
763    *
764    * Upon receiving this signal, you should give up your reference to
765    * @connection. You are guaranteed that this signal is emitted only
766    * once.
767    *
768    * Since: 2.26
769    */
770   signals[CLOSED_SIGNAL] = g_signal_new ("closed",
771                                          G_TYPE_DBUS_CONNECTION,
772                                          G_SIGNAL_RUN_LAST,
773                                          G_STRUCT_OFFSET (GDBusConnectionClass, closed),
774                                          NULL,
775                                          NULL,
776                                          _gio_marshal_VOID__BOOLEAN_BOXED,
777                                          G_TYPE_NONE,
778                                          2,
779                                          G_TYPE_BOOLEAN,
780                                          G_TYPE_ERROR);
781 }
782
783 static void
784 g_dbus_connection_init (GDBusConnection *connection)
785 {
786   connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection, G_TYPE_DBUS_CONNECTION, GDBusConnectionPrivate);
787
788   connection->priv->lock = g_mutex_new ();
789   connection->priv->init_lock = g_mutex_new ();
790
791   connection->priv->map_method_serial_to_send_message_data = g_hash_table_new (g_direct_hash, g_direct_equal);
792
793   connection->priv->map_rule_to_signal_data = g_hash_table_new (g_str_hash,
794                                                                 g_str_equal);
795   connection->priv->map_id_to_signal_data = g_hash_table_new (g_direct_hash,
796                                                               g_direct_equal);
797   connection->priv->map_sender_to_signal_data_array = g_hash_table_new_full (g_str_hash,
798                                                                              g_str_equal,
799                                                                              g_free,
800                                                                              NULL);
801
802   connection->priv->map_object_path_to_eo = g_hash_table_new_full (g_str_hash,
803                                                                    g_str_equal,
804                                                                    NULL,
805                                                                    (GDestroyNotify) exported_object_free);
806
807   connection->priv->map_id_to_ei = g_hash_table_new (g_direct_hash,
808                                                      g_direct_equal);
809
810   connection->priv->map_object_path_to_es = g_hash_table_new_full (g_str_hash,
811                                                                    g_str_equal,
812                                                                    NULL,
813                                                                    (GDestroyNotify) exported_subtree_free);
814
815   connection->priv->map_id_to_es = g_hash_table_new (g_direct_hash,
816                                                      g_direct_equal);
817
818   connection->priv->main_context_at_construction = g_main_context_get_thread_default ();
819   if (connection->priv->main_context_at_construction != NULL)
820     g_main_context_ref (connection->priv->main_context_at_construction);
821
822   connection->priv->filters = g_ptr_array_new ();
823 }
824
825 /**
826  * g_dbus_connection_get_stream:
827  * @connection: a #GDBusConnection
828  *
829  * Gets the underlying stream used for IO.
830  *
831  * Returns: the stream used for IO
832  *
833  * Since: 2.26
834  */
835 GIOStream *
836 g_dbus_connection_get_stream (GDBusConnection *connection)
837 {
838   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
839   return connection->priv->stream;
840 }
841
842
843 /**
844  * g_dbus_connection_is_closed:
845  * @connection: A #GDBusConnection.
846  *
847  * Gets whether @connection is closed.
848  *
849  * Returns: %TRUE if the connection is closed, %FALSE otherwise.
850  *
851  * Since: 2.26
852  */
853 gboolean
854 g_dbus_connection_is_closed (GDBusConnection *connection)
855 {
856   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
857   return connection->priv->closed;
858 }
859
860 /**
861  * g_dbus_connection_get_capabilities:
862  * @connection: A #GDBusConnection.
863  *
864  * Gets the capabilities negotiated with the remote peer
865  *
866  * Returns: Zero or more flags from the #GDBusCapabilityFlags enumeration.
867  *
868  * Since: 2.26
869  */
870 GDBusCapabilityFlags
871 g_dbus_connection_get_capabilities (GDBusConnection *connection)
872 {
873   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), G_DBUS_CAPABILITY_FLAGS_NONE);
874   return connection->priv->capabilities;
875 }
876
877
878 /* ---------------------------------------------------------------------------------------------------- */
879
880 typedef struct
881 {
882   GDBusConnection *connection;
883   GError *error;
884   gboolean remote_peer_vanished;
885 } EmitClosedData;
886
887 static void
888 emit_closed_data_free (EmitClosedData *data)
889 {
890   g_object_unref (data->connection);
891   if (data->error != NULL)
892     g_error_free (data->error);
893   g_free (data);
894 }
895
896 static gboolean
897 emit_closed_in_idle (gpointer user_data)
898 {
899   EmitClosedData *data = user_data;
900   gboolean result;
901
902   g_object_notify (G_OBJECT (data->connection), "closed");
903   g_signal_emit (data->connection,
904                  signals[CLOSED_SIGNAL],
905                  0,
906                  data->remote_peer_vanished,
907                  data->error,
908                  &result);
909   return FALSE;
910 }
911
912 /* Can be called from any thread, must hold lock */
913 static void
914 set_closed_unlocked (GDBusConnection *connection,
915                      gboolean         remote_peer_vanished,
916                      GError          *error)
917 {
918   GSource *idle_source;
919   EmitClosedData *data;
920
921   CONNECTION_ENSURE_LOCK (connection);
922
923   g_assert (!connection->priv->closed);
924
925   connection->priv->closed = TRUE;
926
927   data = g_new0 (EmitClosedData, 1);
928   data->connection = g_object_ref (connection);
929   data->remote_peer_vanished = remote_peer_vanished;
930   data->error = error != NULL ? g_error_copy (error) : NULL;
931
932   idle_source = g_idle_source_new ();
933   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
934   g_source_set_callback (idle_source,
935                          emit_closed_in_idle,
936                          data,
937                          (GDestroyNotify) emit_closed_data_free);
938   g_source_attach (idle_source, connection->priv->main_context_at_construction);
939   g_source_unref (idle_source);
940 }
941
942 /* ---------------------------------------------------------------------------------------------------- */
943
944 /**
945  * g_dbus_connection_close:
946  * @connection: A #GDBusConnection.
947  *
948  * Closes @connection. Note that this never causes the process to
949  * exit (this might only happen if the other end of a shared message
950  * bus connection disconnects).
951  *
952  * If @connection is already closed, this method does nothing.
953  *
954  * Since: 2.26
955  */
956 void
957 g_dbus_connection_close (GDBusConnection *connection)
958 {
959   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
960
961   CONNECTION_LOCK (connection);
962   if (!connection->priv->closed)
963     {
964       GError *error = NULL;
965
966       /* TODO: do this async */
967       //g_debug ("closing connection %p's stream %p", connection, connection->priv->stream);
968       if (!g_io_stream_close (connection->priv->stream, NULL, &error))
969         {
970           g_warning ("Error closing stream: %s", error->message);
971           g_error_free (error);
972         }
973
974       set_closed_unlocked (connection, FALSE, NULL);
975     }
976   CONNECTION_UNLOCK (connection);
977 }
978
979 /* ---------------------------------------------------------------------------------------------------- */
980
981 static gboolean
982 g_dbus_connection_send_message_unlocked (GDBusConnection   *connection,
983                                          GDBusMessage      *message,
984                                          volatile guint32  *out_serial,
985                                          GError           **error)
986 {
987   guchar *blob;
988   gsize blob_size;
989   guint32 serial_to_use;
990   gboolean ret;
991
992   CONNECTION_ENSURE_LOCK (connection);
993
994   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
995   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
996
997   /* TODO: check all necessary headers are present */
998
999   ret = FALSE;
1000   blob = NULL;
1001
1002   if (out_serial != NULL)
1003     *out_serial = 0;
1004
1005   if (connection->priv->closed)
1006     {
1007       g_set_error_literal (error,
1008                            G_IO_ERROR,
1009                            G_IO_ERROR_CLOSED,
1010                            _("The connection is closed"));
1011       goto out;
1012     }
1013
1014   blob = g_dbus_message_to_blob (message,
1015                                  &blob_size,
1016                                  error);
1017   if (blob == NULL)
1018     goto out;
1019
1020   serial_to_use = ++connection->priv->last_serial; /* TODO: handle overflow */
1021
1022   switch (blob[0])
1023     {
1024     case 'l':
1025       ((guint32 *) blob)[2] = GUINT32_TO_LE (serial_to_use);
1026       break;
1027     case 'B':
1028       ((guint32 *) blob)[2] = GUINT32_TO_BE (serial_to_use);
1029       break;
1030     default:
1031       g_assert_not_reached ();
1032       break;
1033     }
1034
1035 #if 0
1036   g_printerr ("Writing message of %" G_GSIZE_FORMAT " bytes (serial %d) on %p:\n",
1037               blob_size, serial_to_use, connection);
1038   g_printerr ("----\n");
1039   hexdump (blob, blob_size);
1040   g_printerr ("----\n");
1041 #endif
1042
1043   /* TODO: use connection->priv->auth to encode the blob */
1044
1045   if (out_serial != NULL)
1046     *out_serial = serial_to_use;
1047
1048   g_dbus_message_set_serial (message, serial_to_use);
1049
1050   _g_dbus_worker_send_message (connection->priv->worker,
1051                                message,
1052                                (gchar*) blob,
1053                                blob_size);
1054   blob = NULL; /* since _g_dbus_worker_send_message() steals the blob */
1055
1056   ret = TRUE;
1057
1058  out:
1059   g_free (blob);
1060
1061   return ret;
1062 }
1063
1064 /**
1065  * g_dbus_connection_send_message:
1066  * @connection: A #GDBusConnection.
1067  * @message: A #GDBusMessage
1068  * @out_serial: Return location for serial number assigned to @message when sending it or %NULL.
1069  * @error: Return location for error or %NULL.
1070  *
1071  * Asynchronously sends @message to the peer represented by @connection.
1072  *
1073  * If @out_serial is not %NULL, then the serial number assigned to
1074  * @message by @connection will be written to this location prior to
1075  * submitting the message to the underlying transport.
1076  *
1077  * If @connection is closed then the operation will fail with
1078  * %G_IO_ERROR_CLOSED. If @cancellable is canceled, the operation will
1079  * fail with %G_IO_ERROR_CANCELLED. If @message is not well-formed,
1080  * the operation fails with %G_IO_ERROR_INVALID_ARGUMENT.
1081  *
1082  * See <xref linkend="gdbus-server"/> and <xref
1083  * linkend="gdbus-unix-fd-client"/> for an example of how to use this
1084  * low-level API to send and receive UNIX file descriptors.
1085  *
1086  * Returns: %TRUE if the message was well-formed and queued for
1087  * transmission, %FALSE if @error is set.
1088  *
1089  * Since: 2.26
1090  */
1091 gboolean
1092 g_dbus_connection_send_message (GDBusConnection   *connection,
1093                                 GDBusMessage      *message,
1094                                 volatile guint32  *out_serial,
1095                                 GError           **error)
1096 {
1097   gboolean ret;
1098
1099   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
1100   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
1101   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1102
1103   CONNECTION_LOCK (connection);
1104   ret = g_dbus_connection_send_message_unlocked (connection, message, out_serial, error);
1105   CONNECTION_UNLOCK (connection);
1106   return ret;
1107 }
1108
1109 /* ---------------------------------------------------------------------------------------------------- */
1110
1111 typedef struct
1112 {
1113   volatile gint ref_count;
1114   GDBusConnection *connection;
1115   guint32 serial;
1116   GSimpleAsyncResult *simple;
1117
1118   GMainContext *main_context;
1119
1120   GCancellable *cancellable;
1121
1122   gulong cancellable_handler_id;
1123
1124   GSource *timeout_source;
1125
1126   gboolean delivered;
1127 } SendMessageData;
1128
1129 static SendMessageData *
1130 send_message_data_ref (SendMessageData *data)
1131 {
1132   g_atomic_int_inc (&data->ref_count);
1133   return data;
1134 }
1135
1136 static void
1137 send_message_data_unref (SendMessageData *data)
1138 {
1139   if (g_atomic_int_dec_and_test (&data->ref_count))
1140     {
1141       g_assert (data->timeout_source == NULL);
1142       g_assert (data->simple == NULL);
1143       g_assert (data->cancellable_handler_id == 0);
1144       g_object_unref (data->connection);
1145       if (data->cancellable != NULL)
1146         g_object_unref (data->cancellable);
1147       if (data->main_context != NULL)
1148         g_main_context_unref (data->main_context);
1149       g_free (data);
1150     }
1151 }
1152
1153 /* ---------------------------------------------------------------------------------------------------- */
1154
1155 /* can be called from any thread with lock held - caller must have prepared GSimpleAsyncResult already */
1156 static void
1157 send_message_with_reply_deliver (SendMessageData *data)
1158 {
1159   CONNECTION_ENSURE_LOCK (data->connection);
1160
1161   g_assert (!data->delivered);
1162
1163   data->delivered = TRUE;
1164
1165   g_simple_async_result_complete_in_idle (data->simple);
1166   g_object_unref (data->simple);
1167   data->simple = NULL;
1168
1169   if (data->timeout_source != NULL)
1170     {
1171       g_source_destroy (data->timeout_source);
1172       data->timeout_source = NULL;
1173     }
1174   if (data->cancellable_handler_id > 0)
1175     {
1176       g_cancellable_disconnect (data->cancellable, data->cancellable_handler_id);
1177       data->cancellable_handler_id = 0;
1178     }
1179
1180   g_warn_if_fail (g_hash_table_remove (data->connection->priv->map_method_serial_to_send_message_data,
1181                                        GUINT_TO_POINTER (data->serial)));
1182
1183   send_message_data_unref (data);
1184 }
1185
1186 /* ---------------------------------------------------------------------------------------------------- */
1187
1188 /* must hold lock */
1189 static void
1190 send_message_data_deliver_reply_unlocked (SendMessageData *data,
1191                                           GDBusMessage    *reply)
1192 {
1193   if (data->delivered)
1194     goto out;
1195
1196   g_simple_async_result_set_op_res_gpointer (data->simple,
1197                                              g_object_ref (reply),
1198                                              g_object_unref);
1199
1200   send_message_with_reply_deliver (data);
1201
1202  out:
1203   ;
1204 }
1205
1206 /* ---------------------------------------------------------------------------------------------------- */
1207
1208 static gboolean
1209 send_message_with_reply_cancelled_idle_cb (gpointer user_data)
1210 {
1211   SendMessageData *data = user_data;
1212
1213   CONNECTION_LOCK (data->connection);
1214   if (data->delivered)
1215     goto out;
1216
1217   g_simple_async_result_set_error (data->simple,
1218                                    G_IO_ERROR,
1219                                    G_IO_ERROR_CANCELLED,
1220                                    _("Operation was cancelled"));
1221
1222   send_message_with_reply_deliver (data);
1223
1224  out:
1225   CONNECTION_UNLOCK (data->connection);
1226   return FALSE;
1227 }
1228
1229 /* Can be called from any thread with or without lock held */
1230 static void
1231 send_message_with_reply_cancelled_cb (GCancellable *cancellable,
1232                                       gpointer      user_data)
1233 {
1234   SendMessageData *data = user_data;
1235   GSource *idle_source;
1236
1237   /* postpone cancellation to idle handler since we may be called directly
1238    * via g_cancellable_connect() (e.g. holding lock)
1239    */
1240   idle_source = g_idle_source_new ();
1241   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
1242   g_source_set_callback (idle_source,
1243                          send_message_with_reply_cancelled_idle_cb,
1244                          send_message_data_ref (data),
1245                          (GDestroyNotify) send_message_data_unref);
1246   g_source_attach (idle_source, data->main_context);
1247   g_source_unref (idle_source);
1248 }
1249
1250 /* ---------------------------------------------------------------------------------------------------- */
1251
1252 static gboolean
1253 send_message_with_reply_timeout_cb (gpointer user_data)
1254 {
1255   SendMessageData *data = user_data;
1256
1257   CONNECTION_LOCK (data->connection);
1258   if (data->delivered)
1259     goto out;
1260
1261   g_simple_async_result_set_error (data->simple,
1262                                    G_IO_ERROR,
1263                                    G_IO_ERROR_TIMED_OUT,
1264                                    _("Timeout was reached"));
1265
1266   send_message_with_reply_deliver (data);
1267
1268  out:
1269   CONNECTION_UNLOCK (data->connection);
1270
1271   return FALSE;
1272 }
1273
1274 /* ---------------------------------------------------------------------------------------------------- */
1275
1276 static void
1277 g_dbus_connection_send_message_with_reply_unlocked (GDBusConnection     *connection,
1278                                                     GDBusMessage        *message,
1279                                                     gint                 timeout_msec,
1280                                                     volatile guint32    *out_serial,
1281                                                     GCancellable        *cancellable,
1282                                                     GAsyncReadyCallback  callback,
1283                                                     gpointer             user_data)
1284 {
1285   GSimpleAsyncResult *simple;
1286   SendMessageData *data;
1287   GError *error;
1288   volatile guint32 serial;
1289
1290   data = NULL;
1291
1292   if (out_serial == NULL)
1293     out_serial = &serial;
1294
1295   if (timeout_msec == -1)
1296     timeout_msec = 30 * 1000; /* TODO: check 30 secs is the default timeout */
1297
1298   simple = g_simple_async_result_new (G_OBJECT (connection),
1299                                       callback,
1300                                       user_data,
1301                                       g_dbus_connection_send_message_with_reply);
1302
1303   if (g_cancellable_is_cancelled (cancellable))
1304     {
1305       g_simple_async_result_set_error (simple,
1306                                        G_IO_ERROR,
1307                                        G_IO_ERROR_CANCELLED,
1308                                        _("Operation was cancelled"));
1309       g_simple_async_result_complete_in_idle (simple);
1310       g_object_unref (simple);
1311       goto out;
1312     }
1313
1314   if (connection->priv->closed)
1315     {
1316       g_simple_async_result_set_error (simple,
1317                                        G_IO_ERROR,
1318                                        G_IO_ERROR_CLOSED,
1319                                        _("The connection is closed"));
1320       g_simple_async_result_complete_in_idle (simple);
1321       g_object_unref (simple);
1322       goto out;
1323     }
1324
1325   error = NULL;
1326   if (!g_dbus_connection_send_message_unlocked (connection, message, out_serial, &error))
1327     {
1328       g_simple_async_result_set_from_error (simple, error);
1329       g_simple_async_result_complete_in_idle (simple);
1330       g_object_unref (simple);
1331       goto out;
1332     }
1333
1334   data = g_new0 (SendMessageData, 1);
1335   data->ref_count = 1;
1336   data->connection = g_object_ref (connection);
1337   data->simple = simple;
1338   data->serial = *out_serial;
1339   data->main_context = g_main_context_get_thread_default ();
1340   if (data->main_context != NULL)
1341     g_main_context_ref (data->main_context);
1342
1343   if (cancellable != NULL)
1344     {
1345       data->cancellable = g_object_ref (cancellable);
1346       data->cancellable_handler_id = g_cancellable_connect (cancellable,
1347                                                             G_CALLBACK (send_message_with_reply_cancelled_cb),
1348                                                             send_message_data_ref (data),
1349                                                             (GDestroyNotify) send_message_data_unref);
1350       g_object_set_data_full (G_OBJECT (simple),
1351                               "cancellable",
1352                               g_object_ref (cancellable),
1353                               (GDestroyNotify) g_object_unref);
1354     }
1355
1356   data->timeout_source = g_timeout_source_new (timeout_msec);
1357   g_source_set_priority (data->timeout_source, G_PRIORITY_DEFAULT);
1358   g_source_set_callback (data->timeout_source,
1359                          send_message_with_reply_timeout_cb,
1360                          send_message_data_ref (data),
1361                          (GDestroyNotify) send_message_data_unref);
1362   g_source_attach (data->timeout_source, data->main_context);
1363   g_source_unref (data->timeout_source);
1364
1365   g_hash_table_insert (connection->priv->map_method_serial_to_send_message_data,
1366                        GUINT_TO_POINTER (*out_serial),
1367                        data);
1368
1369  out:
1370   ;
1371 }
1372
1373 /**
1374  * g_dbus_connection_send_message_with_reply:
1375  * @connection: A #GDBusConnection.
1376  * @message: A #GDBusMessage.
1377  * @timeout_msec: The timeout in milliseconds or -1 to use the default timeout.
1378  * @out_serial: Return location for serial number assigned to @message when sending it or %NULL.
1379  * @cancellable: A #GCancellable or %NULL.
1380  * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL if you don't
1381  * care about the result.
1382  * @user_data: The data to pass to @callback.
1383  *
1384  * Asynchronously sends @message to the peer represented by @connection.
1385  *
1386  * If @out_serial is not %NULL, then the serial number assigned to
1387  * @message by @connection will be written to this location prior to
1388  * submitting the message to the underlying transport.
1389  *
1390  * If @connection is closed then the operation will fail with
1391  * %G_IO_ERROR_CLOSED. If @cancellable is canceled, the operation will
1392  * fail with %G_IO_ERROR_CANCELLED. If @message is not well-formed,
1393  * the operation fails with %G_IO_ERROR_INVALID_ARGUMENT.
1394  *
1395  * This is an asynchronous method. When the operation is finished, @callback will be invoked
1396  * in the <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
1397  * of the thread you are calling this method from. You can then call
1398  * g_dbus_connection_send_message_with_reply_finish() to get the result of the operation.
1399  * See g_dbus_connection_send_message_with_reply_sync() for the synchronous version.
1400  *
1401  * See <xref linkend="gdbus-server"/> and <xref
1402  * linkend="gdbus-unix-fd-client"/> for an example of how to use this
1403  * low-level API to send and receive UNIX file descriptors.
1404  *
1405  * Since: 2.26
1406  */
1407 void
1408 g_dbus_connection_send_message_with_reply (GDBusConnection     *connection,
1409                                            GDBusMessage        *message,
1410                                            gint                 timeout_msec,
1411                                            volatile guint32    *out_serial,
1412                                            GCancellable        *cancellable,
1413                                            GAsyncReadyCallback  callback,
1414                                            gpointer             user_data)
1415 {
1416   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
1417   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
1418   g_return_if_fail (timeout_msec >= 0 || timeout_msec == -1);
1419
1420   CONNECTION_LOCK (connection);
1421   g_dbus_connection_send_message_with_reply_unlocked (connection,
1422                                                       message,
1423                                                       timeout_msec,
1424                                                       out_serial,
1425                                                       cancellable,
1426                                                       callback,
1427                                                       user_data);
1428   CONNECTION_UNLOCK (connection);
1429 }
1430
1431 /**
1432  * g_dbus_connection_send_message_with_reply_finish:
1433  * @connection: a #GDBusConnection
1434  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_connection_send_message_with_reply().
1435  * @error: Return location for error or %NULL.
1436  *
1437  * Finishes an operation started with g_dbus_connection_send_message_with_reply().
1438  *
1439  * Note that @error is only set if a local in-process error
1440  * occured. That is to say that the returned #GDBusMessage object may
1441  * be of type %G_DBUS_MESSAGE_TYPE_ERROR. Use
1442  * g_dbus_message_to_gerror() to transcode this to a #GError.
1443  *
1444  * See <xref linkend="gdbus-server"/> and <xref
1445  * linkend="gdbus-unix-fd-client"/> for an example of how to use this
1446  * low-level API to send and receive UNIX file descriptors.
1447  *
1448  * Returns: A #GDBusMessage or %NULL if @error is set.
1449  *
1450  * Since: 2.26
1451  */
1452 GDBusMessage *
1453 g_dbus_connection_send_message_with_reply_finish (GDBusConnection  *connection,
1454                                                   GAsyncResult     *res,
1455                                                   GError          **error)
1456 {
1457   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
1458   GDBusMessage *reply;
1459   GCancellable *cancellable;
1460
1461   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
1462   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1463
1464   reply = NULL;
1465
1466   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_connection_send_message_with_reply);
1467
1468   if (g_simple_async_result_propagate_error (simple, error))
1469     goto out;
1470
1471   reply = g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
1472   cancellable = g_object_get_data (G_OBJECT (simple), "cancellable");
1473   if (cancellable != NULL && g_cancellable_is_cancelled (cancellable))
1474     {
1475       g_object_unref (reply);
1476       reply = NULL;
1477       g_set_error_literal (error,
1478                            G_IO_ERROR,
1479                            G_IO_ERROR_CANCELLED,
1480                            _("Operation was cancelled"));
1481     }
1482  out:
1483   return reply;
1484 }
1485
1486 /* ---------------------------------------------------------------------------------------------------- */
1487
1488 typedef struct
1489 {
1490   GAsyncResult *res;
1491   GMainContext *context;
1492   GMainLoop *loop;
1493 } SendMessageSyncData;
1494
1495 static void
1496 send_message_with_reply_sync_cb (GDBusConnection *connection,
1497                                  GAsyncResult    *res,
1498                                  gpointer         user_data)
1499 {
1500   SendMessageSyncData *data = user_data;
1501   data->res = g_object_ref (res);
1502   g_main_loop_quit (data->loop);
1503 }
1504
1505 /**
1506  * g_dbus_connection_send_message_with_reply_sync:
1507  * @connection: A #GDBusConnection.
1508  * @message: A #GDBusMessage.
1509  * @timeout_msec: The timeout in milliseconds or -1 to use the default timeout.
1510  * @out_serial: Return location for serial number assigned to @message when sending it or %NULL.
1511  * @cancellable: A #GCancellable or %NULL.
1512  * @error: Return location for error or %NULL.
1513  *
1514  * Synchronously sends @message to the peer represented by @connection
1515  * and blocks the calling thread until a reply is received or the
1516  * timeout is reached. See g_dbus_connection_send_message_with_reply()
1517  * for the asynchronous version of this method.
1518  *
1519  * If @out_serial is not %NULL, then the serial number assigned to
1520  * @message by @connection will be written to this location prior to
1521  * submitting the message to the underlying transport.
1522  *
1523  * If @connection is closed then the operation will fail with
1524  * %G_IO_ERROR_CLOSED. If @cancellable is canceled, the operation will
1525  * fail with %G_IO_ERROR_CANCELLED. If @message is not well-formed,
1526  * the operation fails with %G_IO_ERROR_INVALID_ARGUMENT.
1527  *
1528  * Note that @error is only set if a local in-process error
1529  * occured. That is to say that the returned #GDBusMessage object may
1530  * be of type %G_DBUS_MESSAGE_TYPE_ERROR. Use
1531  * g_dbus_message_to_gerror() to transcode this to a #GError.
1532  *
1533  * See <xref linkend="gdbus-server"/> and <xref
1534  * linkend="gdbus-unix-fd-client"/> for an example of how to use this
1535  * low-level API to send and receive UNIX file descriptors.
1536  *
1537  * Returns: A #GDBusMessage that is the reply to @message or %NULL if @error is set.
1538  *
1539  * Since: 2.26
1540  */
1541 GDBusMessage *
1542 g_dbus_connection_send_message_with_reply_sync (GDBusConnection   *connection,
1543                                                 GDBusMessage      *message,
1544                                                 gint               timeout_msec,
1545                                                 volatile guint32  *out_serial,
1546                                                 GCancellable      *cancellable,
1547                                                 GError           **error)
1548 {
1549   SendMessageSyncData *data;
1550   GDBusMessage *reply;
1551
1552   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
1553   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
1554   g_return_val_if_fail (timeout_msec >= 0 || timeout_msec == -1, NULL);
1555   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1556
1557   data = g_new0 (SendMessageSyncData, 1);
1558   data->context = g_main_context_new ();
1559   data->loop = g_main_loop_new (data->context, FALSE);
1560
1561   g_main_context_push_thread_default (data->context);
1562
1563   g_dbus_connection_send_message_with_reply (connection,
1564                                              message,
1565                                              timeout_msec,
1566                                              out_serial,
1567                                              cancellable,
1568                                              (GAsyncReadyCallback) send_message_with_reply_sync_cb,
1569                                              data);
1570   g_main_loop_run (data->loop);
1571   reply = g_dbus_connection_send_message_with_reply_finish (connection,
1572                                                             data->res,
1573                                                             error);
1574
1575   g_main_context_pop_thread_default (data->context);
1576
1577   g_main_context_unref (data->context);
1578   g_main_loop_unref (data->loop);
1579   g_object_unref (data->res);
1580   g_free (data);
1581
1582   return reply;
1583 }
1584
1585 /* ---------------------------------------------------------------------------------------------------- */
1586
1587 typedef struct
1588 {
1589   GDBusMessageFilterFunction func;
1590   gpointer user_data;
1591 } FilterCallback;
1592
1593 typedef struct
1594 {
1595   guint                       id;
1596   GDBusMessageFilterFunction  filter_function;
1597   gpointer                    user_data;
1598   GDestroyNotify              user_data_free_func;
1599 } FilterData;
1600
1601 /* Called in worker's thread - we must not block */
1602 static void
1603 on_worker_message_received (GDBusWorker  *worker,
1604                             GDBusMessage *message,
1605                             gpointer      user_data)
1606 {
1607   GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
1608   FilterCallback *filters;
1609   gboolean consumed_by_filter;
1610   guint num_filters;
1611   guint n;
1612
1613   //g_debug ("in on_worker_message_received");
1614
1615   g_object_ref (connection);
1616
1617   /* First collect the set of callback functions */
1618   CONNECTION_LOCK (connection);
1619   num_filters = connection->priv->filters->len;
1620   filters = g_new0 (FilterCallback, num_filters);
1621   for (n = 0; n < num_filters; n++)
1622     {
1623       FilterData *data = connection->priv->filters->pdata[n];
1624       filters[n].func = data->filter_function;
1625       filters[n].user_data = data->user_data;
1626     }
1627   CONNECTION_UNLOCK (connection);
1628
1629   /* the call the filters in order (without holding the lock) */
1630   consumed_by_filter = FALSE;
1631   for (n = 0; n < num_filters; n++)
1632     {
1633       consumed_by_filter = filters[n].func (connection,
1634                                             message,
1635                                             filters[n].user_data);
1636       if (consumed_by_filter)
1637         break;
1638     }
1639
1640   /* Standard dispatch unless the filter ate the message */
1641   if (!consumed_by_filter)
1642     {
1643       GDBusMessageType message_type;
1644
1645       message_type = g_dbus_message_get_message_type (message);
1646       if (message_type == G_DBUS_MESSAGE_TYPE_METHOD_RETURN || message_type == G_DBUS_MESSAGE_TYPE_ERROR)
1647         {
1648           guint32 reply_serial;
1649           SendMessageData *send_message_data;
1650
1651           reply_serial = g_dbus_message_get_reply_serial (message);
1652           CONNECTION_LOCK (connection);
1653           send_message_data = g_hash_table_lookup (connection->priv->map_method_serial_to_send_message_data,
1654                                                    GUINT_TO_POINTER (reply_serial));
1655           if (send_message_data != NULL)
1656             {
1657               //g_debug ("delivering reply/error for serial %d for %p", reply_serial, connection);
1658               send_message_data_deliver_reply_unlocked (send_message_data, message);
1659             }
1660           else
1661             {
1662               //g_debug ("message reply/error for serial %d but no SendMessageData found for %p", reply_serial, connection);
1663             }
1664           CONNECTION_UNLOCK (connection);
1665         }
1666       else if (message_type == G_DBUS_MESSAGE_TYPE_SIGNAL)
1667         {
1668           CONNECTION_LOCK (connection);
1669           distribute_signals (connection, message);
1670           CONNECTION_UNLOCK (connection);
1671         }
1672       else if (message_type == G_DBUS_MESSAGE_TYPE_METHOD_CALL)
1673         {
1674           CONNECTION_LOCK (connection);
1675           distribute_method_call (connection, message);
1676           CONNECTION_UNLOCK (connection);
1677         }
1678     }
1679
1680   g_object_unref (connection);
1681   g_free (filters);
1682 }
1683
1684 /* Called in worker's thread - we must not block */
1685 static void
1686 on_worker_closed (GDBusWorker *worker,
1687                   gboolean     remote_peer_vanished,
1688                   GError      *error,
1689                   gpointer     user_data)
1690 {
1691   GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
1692
1693   //g_debug ("in on_worker_closed: %s", error->message);
1694
1695   CONNECTION_LOCK (connection);
1696   if (!connection->priv->closed)
1697     set_closed_unlocked (connection, remote_peer_vanished, error);
1698   CONNECTION_UNLOCK (connection);
1699 }
1700
1701 /* ---------------------------------------------------------------------------------------------------- */
1702
1703 /* Determines the biggest set of capabilities we can support on this connection */
1704 static GDBusCapabilityFlags
1705 get_offered_capabilities_max (GDBusConnection *connection)
1706 {
1707       GDBusCapabilityFlags ret;
1708       ret = G_DBUS_CAPABILITY_FLAGS_NONE;
1709 #ifdef G_OS_UNIX
1710       if (G_IS_UNIX_CONNECTION (connection->priv->stream))
1711         ret |= G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING;
1712 #endif
1713       return ret;
1714 }
1715
1716 static gboolean
1717 initable_init (GInitable     *initable,
1718                GCancellable  *cancellable,
1719                GError       **error)
1720 {
1721   GDBusConnection *connection = G_DBUS_CONNECTION (initable);
1722   gboolean ret;
1723
1724   /* This method needs to be idempotent to work with the singleton
1725    * pattern. See the docs for g_initable_init(). We implement this by
1726    * locking.
1727    *
1728    * Unfortunately we can't use the main lock since the on_worker_*()
1729    * callbacks above needs the lock during initialization (for message
1730    * bus connections we do a synchronous Hello() call on the bus).
1731    */
1732   g_mutex_lock (connection->priv->init_lock);
1733
1734   ret = FALSE;
1735
1736   if (connection->priv->is_initialized)
1737     {
1738       if (connection->priv->stream != NULL)
1739         ret = TRUE;
1740       else
1741         g_assert (connection->priv->initialization_error != NULL);
1742       goto out;
1743     }
1744   g_assert (connection->priv->initialization_error == NULL);
1745
1746   /* The user can pass multiple (but mutally exclusive) construct
1747    * properties:
1748    *
1749    *  - stream (of type GIOStream)
1750    *  - address (of type gchar*)
1751    *
1752    * At the end of the day we end up with a non-NULL GIOStream
1753    * object in connection->priv->stream.
1754    */
1755   if (connection->priv->address != NULL)
1756     {
1757       g_assert (connection->priv->stream == NULL);
1758
1759       if ((connection->priv->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER) ||
1760           (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS))
1761         {
1762           g_set_error_literal (error,
1763                                G_IO_ERROR,
1764                                G_IO_ERROR_INVALID_ARGUMENT,
1765                                _("Unsupported flags encountered when constructing a client-side connection"));
1766           goto out;
1767         }
1768
1769       connection->priv->stream = g_dbus_address_get_stream_sync (connection->priv->address,
1770                                                                  NULL, /* TODO: out_guid */
1771                                                                  cancellable,
1772                                                                  &connection->priv->initialization_error);
1773       if (connection->priv->stream == NULL)
1774         goto out;
1775     }
1776   else if (connection->priv->stream != NULL)
1777     {
1778       /* nothing to do */
1779     }
1780   else
1781     {
1782       g_assert_not_reached ();
1783     }
1784
1785   /* Authenticate the connection */
1786   if (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER)
1787     {
1788       g_assert (!(connection->priv->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT));
1789       g_assert (connection->priv->guid != NULL);
1790       connection->priv->auth = _g_dbus_auth_new (connection->priv->stream);
1791       if (!_g_dbus_auth_run_server (connection->priv->auth,
1792                                     connection->priv->authentication_observer,
1793                                     connection->priv->guid,
1794                                     (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS),
1795                                     get_offered_capabilities_max (connection),
1796                                     &connection->priv->capabilities,
1797                                     &connection->priv->crendentials,
1798                                     cancellable,
1799                                     &connection->priv->initialization_error))
1800         goto out;
1801     }
1802   else if (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT)
1803     {
1804       g_assert (!(connection->priv->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER));
1805       g_assert (connection->priv->guid == NULL);
1806       connection->priv->auth = _g_dbus_auth_new (connection->priv->stream);
1807       connection->priv->guid = _g_dbus_auth_run_client (connection->priv->auth,
1808                                                         get_offered_capabilities_max (connection),
1809                                                         &connection->priv->capabilities,
1810                                                         cancellable,
1811                                                         &connection->priv->initialization_error);
1812       if (connection->priv->guid == NULL)
1813         goto out;
1814     }
1815
1816   if (connection->priv->authentication_observer != NULL)
1817     {
1818       g_object_unref (connection->priv->authentication_observer);
1819       connection->priv->authentication_observer = NULL;
1820     }
1821
1822   //g_output_stream_flush (G_SOCKET_CONNECTION (connection->priv->stream)
1823
1824   //g_debug ("haz unix fd passing powers: %d", connection->priv->capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
1825
1826   /* Hack used until
1827    *
1828    *  https://bugzilla.gnome.org/show_bug.cgi?id=616458
1829    *
1830    * has been resolved
1831    */
1832   if (G_IS_SOCKET_CONNECTION (connection->priv->stream))
1833     {
1834       g_socket_set_blocking (g_socket_connection_get_socket (G_SOCKET_CONNECTION (connection->priv->stream)), FALSE);
1835     }
1836
1837   connection->priv->worker = _g_dbus_worker_new (connection->priv->stream,
1838                                                  connection->priv->capabilities,
1839                                                  on_worker_message_received,
1840                                                  on_worker_closed,
1841                                                  connection);
1842
1843   /* if a bus connection, invoke org.freedesktop.DBus.Hello - this is how we're getting a name */
1844   if (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
1845     {
1846       GVariant *hello_result;
1847       const gchar *s;
1848
1849       hello_result = g_dbus_connection_call_sync (connection,
1850                                                   "org.freedesktop.DBus", /* name */
1851                                                   "/org/freedesktop/DBus", /* path */
1852                                                   "org.freedesktop.DBus", /* interface */
1853                                                   "Hello",
1854                                                   NULL, /* parameters */
1855                                                   G_DBUS_CALL_FLAGS_NONE,
1856                                                   -1,
1857                                                   NULL, /* TODO: cancellable */
1858                                                   &connection->priv->initialization_error);
1859       if (hello_result == NULL)
1860         goto out;
1861
1862       g_variant_get (hello_result, "(s)", &s);
1863       connection->priv->bus_unique_name = g_strdup (s);
1864       g_variant_unref (hello_result);
1865       //g_debug ("unique name is `%s'", connection->priv->bus_unique_name);
1866     }
1867
1868   connection->priv->is_initialized = TRUE;
1869
1870   ret = TRUE;
1871  out:
1872   if (!ret)
1873     {
1874       g_assert (connection->priv->initialization_error != NULL);
1875       g_propagate_error (error, g_error_copy (connection->priv->initialization_error));
1876     }
1877
1878   g_mutex_unlock (connection->priv->init_lock);
1879
1880   return ret;
1881 }
1882
1883 static void
1884 initable_iface_init (GInitableIface *initable_iface)
1885 {
1886   initable_iface->init = initable_init;
1887 }
1888
1889 /* ---------------------------------------------------------------------------------------------------- */
1890
1891 static void
1892 async_init_thread (GSimpleAsyncResult *res,
1893                    GObject            *object,
1894                    GCancellable       *cancellable)
1895 {
1896   GError *error = NULL;
1897
1898   if (!g_initable_init (G_INITABLE (object), cancellable, &error))
1899     {
1900       g_simple_async_result_set_from_error (res, error);
1901       g_error_free (error);
1902     }
1903 }
1904
1905 static void
1906 async_initable_init_async (GAsyncInitable      *initable,
1907                            gint                 io_priority,
1908                            GCancellable        *cancellable,
1909                            GAsyncReadyCallback  callback,
1910                            gpointer             user_data)
1911 {
1912   GSimpleAsyncResult *res;
1913
1914   g_return_if_fail (G_IS_INITABLE (initable));
1915
1916   res = g_simple_async_result_new (G_OBJECT (initable), callback, user_data,
1917                                    async_initable_init_async);
1918   g_simple_async_result_run_in_thread (res, async_init_thread,
1919                                        io_priority, cancellable);
1920   g_object_unref (res);
1921 }
1922
1923 static gboolean
1924 async_initable_init_finish (GAsyncInitable  *initable,
1925                             GAsyncResult    *res,
1926                             GError         **error)
1927 {
1928   return TRUE; /* Errors handled by base impl */
1929 }
1930
1931 static void
1932 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
1933 {
1934   /* We basically just want to use GIO's default implementation - though that one is
1935    * unfortunately broken, see #615111. So we copy-paste a fixed-up version.
1936    */
1937   async_initable_iface->init_async = async_initable_init_async;
1938   async_initable_iface->init_finish = async_initable_init_finish;
1939 }
1940
1941 /* ---------------------------------------------------------------------------------------------------- */
1942
1943 /**
1944  * g_dbus_connection_new:
1945  * @stream: A #GIOStream.
1946  * @guid: The GUID to use if a authenticating as a server or %NULL.
1947  * @flags: Flags describing how to make the connection.
1948  * @observer: A #GDBusAuthObserver or %NULL.
1949  * @cancellable: A #GCancellable or %NULL.
1950  * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
1951  * @user_data: The data to pass to @callback.
1952  *
1953  * Asynchronously sets up a D-Bus connection for exchanging D-Bus messages
1954  * with the end represented by @stream.
1955  *
1956  * If %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER is set in @flags,
1957  * @observer (if not %NULL) is used to assist in the client
1958  * authentication process.
1959  *
1960  * When the operation is finished, @callback will be invoked. You can
1961  * then call g_dbus_connection_new_finish() to get the result of the
1962  * operation.
1963  *
1964  * This is a asynchronous failable constructor. See
1965  * g_dbus_connection_new_sync() for the synchronous
1966  * version.
1967  *
1968  * Since: 2.26
1969  */
1970 void
1971 g_dbus_connection_new (GIOStream            *stream,
1972                        const gchar          *guid,
1973                        GDBusConnectionFlags  flags,
1974                        GDBusAuthObserver    *observer,
1975                        GCancellable         *cancellable,
1976                        GAsyncReadyCallback   callback,
1977                        gpointer              user_data)
1978 {
1979   g_return_if_fail (G_IS_IO_STREAM (stream));
1980   g_async_initable_new_async (G_TYPE_DBUS_CONNECTION,
1981                               G_PRIORITY_DEFAULT,
1982                               cancellable,
1983                               callback,
1984                               user_data,
1985                               "stream", stream,
1986                               "guid", guid,
1987                               "flags", flags,
1988                               "authentication-observer", observer,
1989                               NULL);
1990 }
1991
1992 /**
1993  * g_dbus_connection_new_finish:
1994  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_connection_new().
1995  * @error: Return location for error or %NULL.
1996  *
1997  * Finishes an operation started with g_dbus_connection_new().
1998  *
1999  * Returns: A #GDBusConnection or %NULL if @error is set. Free with g_object_unref().
2000  *
2001  * Since: 2.26
2002  */
2003 GDBusConnection *
2004 g_dbus_connection_new_finish (GAsyncResult  *res,
2005                               GError       **error)
2006 {
2007   GObject *object;
2008   GObject *source_object;
2009
2010   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
2011   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2012
2013   source_object = g_async_result_get_source_object (res);
2014   g_assert (source_object != NULL);
2015   object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
2016                                         res,
2017                                         error);
2018   g_object_unref (source_object);
2019   if (object != NULL)
2020     return G_DBUS_CONNECTION (object);
2021   else
2022     return NULL;
2023 }
2024
2025 /**
2026  * g_dbus_connection_new_sync:
2027  * @stream: A #GIOStream.
2028  * @guid: The GUID to use if a authenticating as a server or %NULL.
2029  * @flags: Flags describing how to make the connection.
2030  * @observer: A #GDBusAuthObserver or %NULL.
2031  * @cancellable: A #GCancellable or %NULL.
2032  * @error: Return location for error or %NULL.
2033  *
2034  * Synchronously sets up a D-Bus connection for exchanging D-Bus messages
2035  * with the end represented by @stream.
2036  *
2037  * If %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER is set in @flags,
2038  * @observer (if not %NULL) is used to assist in the client
2039  * authentication process.
2040  *
2041  * This is a synchronous failable constructor. See
2042  * g_dbus_connection_new() for the asynchronous version.
2043  *
2044  * Returns: A #GDBusConnection or %NULL if @error is set. Free with g_object_unref().
2045  *
2046  * Since: 2.26
2047  */
2048 GDBusConnection *
2049 g_dbus_connection_new_sync (GIOStream             *stream,
2050                             const gchar           *guid,
2051                             GDBusConnectionFlags   flags,
2052                             GDBusAuthObserver     *observer,
2053                             GCancellable          *cancellable,
2054                             GError               **error)
2055 {
2056   g_return_val_if_fail (G_IS_IO_STREAM (stream), NULL);
2057   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2058   return g_initable_new (G_TYPE_DBUS_CONNECTION,
2059                          cancellable,
2060                          error,
2061                          "stream", stream,
2062                          "guid", guid,
2063                          "flags", flags,
2064                          "authentication-observer", observer,
2065                          NULL);
2066 }
2067
2068 /* ---------------------------------------------------------------------------------------------------- */
2069
2070 /**
2071  * g_dbus_connection_new_for_address:
2072  * @address: A D-Bus address.
2073  * @flags: Flags describing how to make the connection.
2074  * @cancellable: A #GCancellable or %NULL.
2075  * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
2076  * @user_data: The data to pass to @callback.
2077  *
2078  * Asynchronously connects and sets up a D-Bus client connection for
2079  * exchanging D-Bus messages with an endpoint specified by @address
2080  * which must be in the D-Bus address format.
2081  *
2082  * This constructor can only be used to initiate client-side
2083  * connections - use g_dbus_connection_new() if you need to act as the
2084  * server. In particular, @flags cannot contain the
2085  * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER or
2086  * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS flags.
2087  *
2088  * When the operation is finished, @callback will be invoked. You can
2089  * then call g_dbus_connection_new_finish() to get the result of the
2090  * operation.
2091  *
2092  * This is a asynchronous failable constructor. See
2093  * g_dbus_connection_new_for_address_sync() for the synchronous
2094  * version.
2095  *
2096  * Since: 2.26
2097  */
2098 void
2099 g_dbus_connection_new_for_address (const gchar          *address,
2100                                    GDBusConnectionFlags  flags,
2101                                    GCancellable         *cancellable,
2102                                    GAsyncReadyCallback   callback,
2103                                    gpointer              user_data)
2104 {
2105   g_return_if_fail (address != NULL);
2106   g_async_initable_new_async (G_TYPE_DBUS_CONNECTION,
2107                               G_PRIORITY_DEFAULT,
2108                               cancellable,
2109                               callback,
2110                               user_data,
2111                               "address", address,
2112                               "flags", flags,
2113                               NULL);
2114 }
2115
2116 /**
2117  * g_dbus_connection_new_for_address_finish:
2118  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_connection_new().
2119  * @error: Return location for error or %NULL.
2120  *
2121  * Finishes an operation started with g_dbus_connection_new_for_address().
2122  *
2123  * Returns: A #GDBusConnection or %NULL if @error is set. Free with g_object_unref().
2124  *
2125  * Since: 2.26
2126  */
2127 GDBusConnection *
2128 g_dbus_connection_new_for_address_finish (GAsyncResult  *res,
2129                                           GError       **error)
2130 {
2131   GObject *object;
2132   GObject *source_object;
2133
2134   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
2135   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2136
2137   source_object = g_async_result_get_source_object (res);
2138   g_assert (source_object != NULL);
2139   object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
2140                                         res,
2141                                         error);
2142   g_object_unref (source_object);
2143   if (object != NULL)
2144     return G_DBUS_CONNECTION (object);
2145   else
2146     return NULL;
2147 }
2148
2149 /**
2150  * g_dbus_connection_new_for_address_sync:
2151  * @address: A D-Bus address.
2152  * @flags: Flags describing how to make the connection.
2153  * @cancellable: A #GCancellable or %NULL.
2154  * @error: Return location for error or %NULL.
2155  *
2156  * Synchronously connects and sets up a D-Bus client connection for
2157  * exchanging D-Bus messages with an endpoint specified by @address
2158  * which must be in the D-Bus address format.
2159  *
2160  * This constructor can only be used to initiate client-side
2161  * connections - use g_dbus_connection_new_sync() if you need to act
2162  * as the server. In particular, @flags cannot contain the
2163  * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER or
2164  * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS flags.
2165  *
2166  * This is a synchronous failable constructor. See
2167  * g_dbus_connection_new_for_address() for the asynchronous version.
2168  *
2169  * Returns: A #GDBusConnection or %NULL if @error is set. Free with g_object_unref().
2170  *
2171  * Since: 2.26
2172  */
2173 GDBusConnection *
2174 g_dbus_connection_new_for_address_sync (const gchar           *address,
2175                                         GDBusConnectionFlags   flags,
2176                                         GCancellable          *cancellable,
2177                                         GError               **error)
2178 {
2179   g_return_val_if_fail (address != NULL, NULL);
2180   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2181   return g_initable_new (G_TYPE_DBUS_CONNECTION,
2182                          cancellable,
2183                          error,
2184                          "address", address,
2185                          "flags", flags,
2186                          NULL);
2187 }
2188
2189 /* ---------------------------------------------------------------------------------------------------- */
2190
2191 /**
2192  * g_dbus_connection_set_exit_on_close:
2193  * @connection: A #GDBusConnection.
2194  * @exit_on_close: Whether the process should be terminated
2195  * when @connection is closed by the remote peer.
2196  *
2197  * Sets whether the process should be terminated when @connection is
2198  * closed by the remote peer. See #GDBusConnection:exit-on-close for
2199  * more details.
2200  *
2201  * Since: 2.26
2202  */
2203 void
2204 g_dbus_connection_set_exit_on_close (GDBusConnection *connection,
2205                                      gboolean         exit_on_close)
2206 {
2207   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
2208   connection->priv->exit_on_close = exit_on_close;
2209 }
2210
2211 /**
2212  * g_dbus_connection_get_exit_on_close:
2213  * @connection: A #GDBusConnection.
2214  *
2215  * Gets whether the process is terminated when @connection is
2216  * closed by the remote peer. See
2217  * #GDBusConnection:exit-on-close for more details.
2218  *
2219  * Returns: Whether the process is terminated when @connection is
2220  * closed by the remote peer.
2221  *
2222  * Since: 2.26
2223  */
2224 gboolean
2225 g_dbus_connection_get_exit_on_close (GDBusConnection *connection)
2226 {
2227   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
2228   return connection->priv->exit_on_close;
2229 }
2230
2231 /**
2232  * g_dbus_connection_get_guid:
2233  * @connection: A #GDBusConnection.
2234  *
2235  * The GUID of the peer performing the role of server when
2236  * authenticating. See #GDBusConnection:guid for more details.
2237  *
2238  * Returns: The GUID. Do not free this string, it is owned by
2239  * @connection.
2240  *
2241  * Since: 2.26
2242  */
2243 const gchar *
2244 g_dbus_connection_get_guid (GDBusConnection *connection)
2245 {
2246   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
2247   return connection->priv->guid;
2248 }
2249
2250 /**
2251  * g_dbus_connection_get_unique_name:
2252  * @connection: A #GDBusConnection.
2253  *
2254  * Gets the unique name of @connection as assigned by the message
2255  * bus. This can also be used to figure out if @connection is a
2256  * message bus connection.
2257  *
2258  * Returns: The unique name or %NULL if @connection is not a message
2259  * bus connection. Do not free this string, it is owned by
2260  * @connection.
2261  *
2262  * Since: 2.26
2263  */
2264 const gchar *
2265 g_dbus_connection_get_unique_name (GDBusConnection *connection)
2266 {
2267   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
2268   return connection->priv->bus_unique_name;
2269 }
2270
2271 /**
2272  * g_dbus_connection_get_peer_credentials:
2273  * @connection: A #GDBusConnection.
2274  *
2275  * Gets the credentials of the authenticated peer. This will always
2276  * return %NULL unless @connection acted as a server
2277  * (e.g. %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER was passed)
2278  * when set up and the client passed credentials as part of the
2279  * authentication process.
2280  *
2281  * In a message bus setup, the message bus is always the server and
2282  * each application is a client. So this method will always return
2283  * %NULL for message bus clients.
2284  *
2285  * Returns: A #GCredentials or %NULL if not available. Do not free
2286  * this object, it is owned by @connection.
2287  *
2288  * Since: 2.26
2289  */
2290 GCredentials *
2291 g_dbus_connection_get_peer_credentials (GDBusConnection *connection)
2292 {
2293   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
2294   return connection->priv->crendentials;
2295 }
2296
2297 /* ---------------------------------------------------------------------------------------------------- */
2298
2299 static guint _global_filter_id = 1;
2300
2301 /**
2302  * g_dbus_connection_add_filter:
2303  * @connection: A #GDBusConnection.
2304  * @filter_function: A filter function.
2305  * @user_data: User data to pass to @filter_function.
2306  * @user_data_free_func: Function to free @user_data with when filter
2307  * is removed or %NULL.
2308  *
2309  * Adds a message filter. Filters are handlers that are run on all
2310  * incoming messages, prior to standard dispatch. Filters are run in
2311  * the order that they were added.  The same handler can be added as a
2312  * filter more than once, in which case it will be run more than once.
2313  * Filters added during a filter callback won't be run on the message
2314  * being processed.
2315  *
2316  * Note that filters are run in a dedicated message handling thread so
2317  * they can't block and, generally, can't do anything but signal a
2318  * worker thread. Also note that filters are rarely needed - use API
2319  * such as g_dbus_connection_send_message_with_reply(),
2320  * g_dbus_connection_signal_subscribe() or
2321  * g_dbus_connection_call() instead.
2322  *
2323  * Returns: A filter identifier that can be used with
2324  * g_dbus_connection_remove_filter().
2325  *
2326  * Since: 2.26
2327  */
2328 guint
2329 g_dbus_connection_add_filter (GDBusConnection            *connection,
2330                               GDBusMessageFilterFunction  filter_function,
2331                               gpointer                    user_data,
2332                               GDestroyNotify              user_data_free_func)
2333 {
2334   FilterData *data;
2335
2336   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
2337   g_return_val_if_fail (filter_function != NULL, 0);
2338
2339   CONNECTION_LOCK (connection);
2340   data = g_new0 (FilterData, 1);
2341   data->id = _global_filter_id++; /* TODO: overflow etc. */
2342   data->filter_function = filter_function;
2343   data->user_data = user_data;
2344   data->user_data_free_func = user_data_free_func;
2345   g_ptr_array_add (connection->priv->filters, data);
2346   CONNECTION_UNLOCK (connection);
2347
2348   return data->id;
2349 }
2350
2351 /* only called from finalize(), removes all filters */
2352 static void
2353 purge_all_filters (GDBusConnection *connection)
2354 {
2355   guint n;
2356   for (n = 0; n < connection->priv->filters->len; n++)
2357     {
2358       FilterData *data = connection->priv->filters->pdata[n];
2359       if (data->user_data_free_func != NULL)
2360         data->user_data_free_func (data->user_data);
2361       g_free (data);
2362     }
2363 }
2364
2365 /**
2366  * g_dbus_connection_remove_filter:
2367  * @connection: a #GDBusConnection
2368  * @filter_id: an identifier obtained from g_dbus_connection_add_filter()
2369  *
2370  * Removes a filter.
2371  *
2372  * Since: 2.26
2373  */
2374 void
2375 g_dbus_connection_remove_filter (GDBusConnection *connection,
2376                                  guint            filter_id)
2377 {
2378   guint n;
2379   FilterData *to_destroy;
2380
2381   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
2382
2383   CONNECTION_LOCK (connection);
2384   to_destroy = NULL;
2385   for (n = 0; n < connection->priv->filters->len; n++)
2386     {
2387       FilterData *data = connection->priv->filters->pdata[n];
2388       if (data->id == filter_id)
2389         {
2390           g_ptr_array_remove_index (connection->priv->filters, n);
2391           to_destroy = data;
2392           break;
2393         }
2394     }
2395   CONNECTION_UNLOCK (connection);
2396
2397   /* do free without holding lock */
2398   if (to_destroy != NULL)
2399     {
2400       if (to_destroy->user_data_free_func != NULL)
2401         to_destroy->user_data_free_func (to_destroy->user_data);
2402       g_free (to_destroy);
2403     }
2404   else
2405     {
2406       g_warning ("g_dbus_connection_remove_filter: No filter found for filter_id %d", filter_id);
2407     }
2408 }
2409
2410 /* ---------------------------------------------------------------------------------------------------- */
2411
2412 typedef struct
2413 {
2414   gchar *rule;
2415   gchar *sender;
2416   gchar *interface_name;
2417   gchar *member;
2418   gchar *object_path;
2419   gchar *arg0;
2420   GArray *subscribers;
2421 } SignalData;
2422
2423 typedef struct
2424 {
2425   GDBusSignalCallback callback;
2426   gpointer user_data;
2427   GDestroyNotify user_data_free_func;
2428   guint id;
2429   GMainContext *context;
2430 } SignalSubscriber;
2431
2432 static void
2433 signal_data_free (SignalData *data)
2434 {
2435   g_free (data->rule);
2436   g_free (data->sender);
2437   g_free (data->interface_name);
2438   g_free (data->member);
2439   g_free (data->object_path);
2440   g_free (data->arg0);
2441   g_array_free (data->subscribers, TRUE);
2442   g_free (data);
2443 }
2444
2445 static gchar *
2446 args_to_rule (const gchar *sender,
2447               const gchar *interface_name,
2448               const gchar *member,
2449               const gchar *object_path,
2450               const gchar *arg0)
2451 {
2452   GString *rule;
2453
2454   rule = g_string_new ("type='signal'");
2455   if (sender != NULL)
2456     g_string_append_printf (rule, ",sender='%s'", sender);
2457   if (interface_name != NULL)
2458     g_string_append_printf (rule, ",interface='%s'", interface_name);
2459   if (member != NULL)
2460     g_string_append_printf (rule, ",member='%s'", member);
2461   if (object_path != NULL)
2462     g_string_append_printf (rule, ",path='%s'", object_path);
2463   if (arg0 != NULL)
2464     g_string_append_printf (rule, ",arg0='%s'", arg0);
2465
2466   return g_string_free (rule, FALSE);
2467 }
2468
2469 static guint _global_subscriber_id = 1;
2470 static guint _global_registration_id = 1;
2471 static guint _global_subtree_registration_id = 1;
2472
2473 /* ---------------------------------------------------------------------------------------------------- */
2474
2475 /* must hold lock when calling */
2476 static void
2477 add_match_rule (GDBusConnection *connection,
2478                 const gchar     *match_rule)
2479 {
2480   GError *error;
2481   GDBusMessage *message;
2482
2483   message = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */
2484                                             "/org/freedesktop/DBus", /* path */
2485                                             "org.freedesktop.DBus", /* interface */
2486                                             "AddMatch");
2487   g_dbus_message_set_body (message, g_variant_new ("(s)", match_rule));
2488
2489   error = NULL;
2490   if (!g_dbus_connection_send_message_unlocked (connection,
2491                                                 message,
2492                                                 NULL,
2493                                                 &error))
2494     {
2495       g_critical ("Error while sending AddMatch() message: %s", error->message);
2496       g_error_free (error);
2497     }
2498   g_object_unref (message);
2499 }
2500
2501 /* ---------------------------------------------------------------------------------------------------- */
2502
2503 /* must hold lock when calling */
2504 static void
2505 remove_match_rule (GDBusConnection *connection,
2506                    const gchar     *match_rule)
2507 {
2508   GError *error;
2509   GDBusMessage *message;
2510
2511   message = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */
2512                                             "/org/freedesktop/DBus", /* path */
2513                                             "org.freedesktop.DBus", /* interface */
2514                                             "RemoveMatch");
2515   g_dbus_message_set_body (message, g_variant_new ("(s)", match_rule));
2516
2517   error = NULL;
2518   if (!g_dbus_connection_send_message_unlocked (connection,
2519                                                 message,
2520                                                 NULL,
2521                                                 &error))
2522     {
2523       g_critical ("Error while sending RemoveMatch() message: %s", error->message);
2524       g_error_free (error);
2525     }
2526   g_object_unref (message);
2527 }
2528
2529 /* ---------------------------------------------------------------------------------------------------- */
2530
2531 static gboolean
2532 is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
2533 {
2534   return g_strcmp0 (signal_data->sender, "org.freedesktop.DBus") == 0 &&
2535          g_strcmp0 (signal_data->interface_name, "org.freedesktop.DBus") == 0 &&
2536          g_strcmp0 (signal_data->object_path, "/org/freedesktop/DBus") == 0 &&
2537          (g_strcmp0 (signal_data->member, "NameLost") == 0 ||
2538           g_strcmp0 (signal_data->member, "NameAcquired") == 0);
2539 }
2540
2541 /* ---------------------------------------------------------------------------------------------------- */
2542
2543 /**
2544  * g_dbus_connection_signal_subscribe:
2545  * @connection: A #GDBusConnection.
2546  * @sender: Sender name to match on. Must be either <literal>org.freedesktop.DBus</literal> (for listening to signals from the message bus daemon) or a unique name or %NULL to listen from all senders.
2547  * @interface_name: D-Bus interface name to match on or %NULL to match on all interfaces.
2548  * @member: D-Bus signal name to match on or %NULL to match on all signals.
2549  * @object_path: Object path to match on or %NULL to match on all object paths.
2550  * @arg0: Contents of first string argument to match on or %NULL to match on all kinds of arguments.
2551  * @callback: Callback to invoke when there is a signal matching the requested data.
2552  * @user_data: User data to pass to @callback.
2553  * @user_data_free_func: Function to free @user_data with when subscription is removed or %NULL.
2554  *
2555  * Subscribes to signals on @connection and invokes @callback with a
2556  * whenever the signal is received. Note that @callback
2557  * will be invoked in the <link
2558  * linkend="g-main-context-push-thread-default">thread-default main
2559  * loop</link> of the thread you are calling this method from.
2560  *
2561  * It is considered a programming error to use this function if @connection is closed.
2562  *
2563  * Note that if @sender is not <literal>org.freedesktop.DBus</literal> (for listening to signals from the
2564  * message bus daemon), then it needs to be a unique bus name or %NULL (for listening to signals from any
2565  * name) - you cannot pass a name like <literal>com.example.MyApp</literal>.
2566  * Use e.g. g_bus_watch_name() to find the unique name for the owner of the name you are interested in. Also note
2567  * that this function does not remove a subscription if @sender vanishes from the bus. You have to manually
2568  * call g_dbus_connection_signal_unsubscribe() to remove a subscription.
2569  *
2570  * Returns: A subscription identifier that can be used with g_dbus_connection_signal_unsubscribe().
2571  *
2572  * Since: 2.26
2573  */
2574 guint
2575 g_dbus_connection_signal_subscribe (GDBusConnection     *connection,
2576                                     const gchar         *sender,
2577                                     const gchar         *interface_name,
2578                                     const gchar         *member,
2579                                     const gchar         *object_path,
2580                                     const gchar         *arg0,
2581                                     GDBusSignalCallback  callback,
2582                                     gpointer             user_data,
2583                                     GDestroyNotify       user_data_free_func)
2584 {
2585   gchar *rule;
2586   SignalData *signal_data;
2587   SignalSubscriber subscriber;
2588   GPtrArray *signal_data_array;
2589
2590   /* Right now we abort if AddMatch() fails since it can only fail with the bus being in
2591    * an OOM condition. We might want to change that but that would involve making
2592    * g_dbus_connection_signal_subscribe() asynchronous and having the call sites
2593    * handle that. And there's really no sensible way of handling this short of retrying
2594    * to add the match rule... and then there's the little thing that, hey, maybe there's
2595    * a reason the bus in an OOM condition.
2596    *
2597    * Doable, but not really sure it's worth it...
2598    */
2599
2600   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
2601   g_return_val_if_fail (!g_dbus_connection_is_closed (connection), 0);
2602   g_return_val_if_fail (sender == NULL || ((strcmp (sender, "org.freedesktop.DBus") == 0 || sender[0] == ':') &&
2603                                            (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)), 0);
2604   g_return_val_if_fail (interface_name == NULL || g_dbus_is_interface_name (interface_name), 0);
2605   g_return_val_if_fail (member == NULL || g_dbus_is_member_name (member), 0);
2606   g_return_val_if_fail (object_path == NULL || g_variant_is_object_path (object_path), 0);
2607   g_return_val_if_fail (callback != NULL, 0);
2608
2609   CONNECTION_LOCK (connection);
2610
2611   rule = args_to_rule (sender, interface_name, member, object_path, arg0);
2612
2613   if (sender == NULL)
2614     sender = "";
2615
2616   subscriber.callback = callback;
2617   subscriber.user_data = user_data;
2618   subscriber.user_data_free_func = user_data_free_func;
2619   subscriber.id = _global_subscriber_id++; /* TODO: overflow etc. */
2620   subscriber.context = g_main_context_get_thread_default ();
2621   if (subscriber.context != NULL)
2622     g_main_context_ref (subscriber.context);
2623
2624   /* see if we've already have this rule */
2625   signal_data = g_hash_table_lookup (connection->priv->map_rule_to_signal_data, rule);
2626   if (signal_data != NULL)
2627     {
2628       g_array_append_val (signal_data->subscribers, subscriber);
2629       g_free (rule);
2630       goto out;
2631     }
2632
2633   signal_data = g_new0 (SignalData, 1);
2634   signal_data->rule           = rule;
2635   signal_data->sender         = g_strdup (sender);
2636   signal_data->interface_name = g_strdup (interface_name);
2637   signal_data->member         = g_strdup (member);
2638   signal_data->object_path    = g_strdup (object_path);
2639   signal_data->arg0           = g_strdup (arg0);
2640   signal_data->subscribers    = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber));
2641   g_array_append_val (signal_data->subscribers, subscriber);
2642
2643   g_hash_table_insert (connection->priv->map_rule_to_signal_data,
2644                        signal_data->rule,
2645                        signal_data);
2646
2647   /* Add the match rule to the bus...
2648    *
2649    * Avoid adding match rules for NameLost and NameAcquired messages - the bus will
2650    * always send such messages to us.
2651    */
2652   if (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
2653     {
2654       if (!is_signal_data_for_name_lost_or_acquired (signal_data))
2655         add_match_rule (connection, signal_data->rule);
2656     }
2657
2658  out:
2659   g_hash_table_insert (connection->priv->map_id_to_signal_data,
2660                        GUINT_TO_POINTER (subscriber.id),
2661                        signal_data);
2662
2663   signal_data_array = g_hash_table_lookup (connection->priv->map_sender_to_signal_data_array,
2664                                            signal_data->sender);
2665   if (signal_data_array == NULL)
2666     {
2667       signal_data_array = g_ptr_array_new ();
2668       g_hash_table_insert (connection->priv->map_sender_to_signal_data_array,
2669                            g_strdup (signal_data->sender),
2670                            signal_data_array);
2671     }
2672   g_ptr_array_add (signal_data_array, signal_data);
2673
2674   CONNECTION_UNLOCK (connection);
2675
2676   return subscriber.id;
2677 }
2678
2679 /* ---------------------------------------------------------------------------------------------------- */
2680
2681 /* must hold lock when calling this */
2682 static void
2683 unsubscribe_id_internal (GDBusConnection *connection,
2684                          guint            subscription_id,
2685                          GArray          *out_removed_subscribers)
2686 {
2687   SignalData *signal_data;
2688   GPtrArray *signal_data_array;
2689   guint n;
2690
2691   signal_data = g_hash_table_lookup (connection->priv->map_id_to_signal_data,
2692                                      GUINT_TO_POINTER (subscription_id));
2693   if (signal_data == NULL)
2694     {
2695       /* Don't warn here, we may have thrown all subscriptions out when the connection was closed */
2696       goto out;
2697     }
2698
2699   for (n = 0; n < signal_data->subscribers->len; n++)
2700     {
2701       SignalSubscriber *subscriber;
2702
2703       subscriber = &(g_array_index (signal_data->subscribers, SignalSubscriber, n));
2704       if (subscriber->id != subscription_id)
2705         continue;
2706
2707       g_warn_if_fail (g_hash_table_remove (connection->priv->map_id_to_signal_data,
2708                                            GUINT_TO_POINTER (subscription_id)));
2709       g_array_append_val (out_removed_subscribers, *subscriber);
2710       g_array_remove_index (signal_data->subscribers, n);
2711
2712       if (signal_data->subscribers->len == 0)
2713         g_warn_if_fail (g_hash_table_remove (connection->priv->map_rule_to_signal_data, signal_data->rule));
2714
2715       signal_data_array = g_hash_table_lookup (connection->priv->map_sender_to_signal_data_array,
2716                                                signal_data->sender);
2717       g_warn_if_fail (signal_data_array != NULL);
2718       g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data));
2719
2720       if (signal_data_array->len == 0)
2721         {
2722           g_warn_if_fail (g_hash_table_remove (connection->priv->map_sender_to_signal_data_array, signal_data->sender));
2723
2724           /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */
2725           if (connection->priv->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
2726             {
2727               if (!is_signal_data_for_name_lost_or_acquired (signal_data))
2728                 remove_match_rule (connection, signal_data->rule);
2729             }
2730
2731           signal_data_free (signal_data);
2732         }
2733
2734       goto out;
2735     }
2736
2737   g_assert_not_reached ();
2738
2739  out:
2740   ;
2741 }
2742
2743 /**
2744  * g_dbus_connection_signal_unsubscribe:
2745  * @connection: A #GDBusConnection.
2746  * @subscription_id: A subscription id obtained from g_dbus_connection_signal_subscribe().
2747  *
2748  * Unsubscribes from signals.
2749  *
2750  * Since: 2.26
2751  */
2752 void
2753 g_dbus_connection_signal_unsubscribe (GDBusConnection *connection,
2754                                       guint            subscription_id)
2755 {
2756   GArray *subscribers;
2757   guint n;
2758
2759   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
2760
2761   subscribers = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber));
2762
2763   CONNECTION_LOCK (connection);
2764   unsubscribe_id_internal (connection,
2765                            subscription_id,
2766                            subscribers);
2767   CONNECTION_UNLOCK (connection);
2768
2769   /* invariant */
2770   g_assert (subscribers->len == 0 || subscribers->len == 1);
2771
2772   /* call GDestroyNotify without lock held */
2773   for (n = 0; n < subscribers->len; n++)
2774     {
2775       SignalSubscriber *subscriber;
2776       subscriber = &(g_array_index (subscribers, SignalSubscriber, n));
2777       if (subscriber->user_data_free_func != NULL)
2778         subscriber->user_data_free_func (subscriber->user_data);
2779       if (subscriber->context != NULL)
2780         g_main_context_unref (subscriber->context);
2781     }
2782
2783   g_array_free (subscribers, TRUE);
2784 }
2785
2786 /* ---------------------------------------------------------------------------------------------------- */
2787
2788 typedef struct
2789 {
2790   guint                subscription_id;
2791   GDBusSignalCallback  callback;
2792   gpointer             user_data;
2793   GDBusMessage        *message;
2794   GDBusConnection     *connection;
2795   const gchar         *sender;
2796   const gchar         *path;
2797   const gchar         *interface;
2798   const gchar         *member;
2799 } SignalInstance;
2800
2801 /* called on delivery thread (e.g. where g_dbus_connection_signal_subscribe() was called) with
2802  * no locks held
2803  */
2804 static gboolean
2805 emit_signal_instance_in_idle_cb (gpointer data)
2806 {
2807   SignalInstance *signal_instance = data;
2808   GVariant *parameters;
2809   gboolean has_subscription;
2810
2811   parameters = g_dbus_message_get_body (signal_instance->message);
2812   if (parameters == NULL)
2813     {
2814       parameters = g_variant_new ("()");
2815       g_variant_ref_sink (parameters);
2816     }
2817   else
2818     {
2819       g_variant_ref_sink (parameters);
2820     }
2821
2822 #if 0
2823   g_debug ("in emit_signal_instance_in_idle_cb (sender=%s path=%s interface=%s member=%s params=%s)",
2824            signal_instance->sender,
2825            signal_instance->path,
2826            signal_instance->interface,
2827            signal_instance->member,
2828            g_variant_print (parameters, TRUE));
2829 #endif
2830
2831   /* Careful here, don't do the callback if we no longer has the subscription */
2832   CONNECTION_LOCK (signal_instance->connection);
2833   has_subscription = FALSE;
2834   if (g_hash_table_lookup (signal_instance->connection->priv->map_id_to_signal_data,
2835                            GUINT_TO_POINTER (signal_instance->subscription_id)) != NULL)
2836     has_subscription = TRUE;
2837   CONNECTION_UNLOCK (signal_instance->connection);
2838
2839   if (has_subscription)
2840     signal_instance->callback (signal_instance->connection,
2841                                signal_instance->sender,
2842                                signal_instance->path,
2843                                signal_instance->interface,
2844                                signal_instance->member,
2845                                parameters,
2846                                signal_instance->user_data);
2847
2848   if (parameters != NULL)
2849     g_variant_unref (parameters);
2850
2851   return FALSE;
2852 }
2853
2854 static void
2855 signal_instance_free (SignalInstance *signal_instance)
2856 {
2857   g_object_unref (signal_instance->message);
2858   g_object_unref (signal_instance->connection);
2859   g_free (signal_instance);
2860 }
2861
2862 /* called in message handler thread WITH lock held */
2863 static void
2864 schedule_callbacks (GDBusConnection *connection,
2865                     GPtrArray       *signal_data_array,
2866                     GDBusMessage    *message,
2867                     const gchar     *sender)
2868 {
2869   guint n, m;
2870   const gchar *interface;
2871   const gchar *member;
2872   const gchar *path;
2873   const gchar *arg0;
2874
2875   interface = NULL;
2876   member = NULL;
2877   path = NULL;
2878   arg0 = NULL;
2879
2880   interface = g_dbus_message_get_interface (message);
2881   member = g_dbus_message_get_member (message);
2882   path = g_dbus_message_get_path (message);
2883   arg0 = g_dbus_message_get_arg0 (message);
2884
2885 #if 0
2886   g_debug ("sender    = `%s'", sender);
2887   g_debug ("interface = `%s'", interface);
2888   g_debug ("member    = `%s'", member);
2889   g_debug ("path      = `%s'", path);
2890   g_debug ("arg0      = `%s'", arg0);
2891 #endif
2892
2893   /* TODO: if this is slow, then we can change signal_data_array into
2894    *       map_object_path_to_signal_data_array or something.
2895    */
2896   for (n = 0; n < signal_data_array->len; n++)
2897     {
2898       SignalData *signal_data = signal_data_array->pdata[n];
2899
2900       if (signal_data->interface_name != NULL && g_strcmp0 (signal_data->interface_name, interface) != 0)
2901         continue;
2902
2903       if (signal_data->member != NULL && g_strcmp0 (signal_data->member, member) != 0)
2904         continue;
2905
2906       if (signal_data->object_path != NULL && g_strcmp0 (signal_data->object_path, path) != 0)
2907         continue;
2908
2909       if (signal_data->arg0 != NULL && g_strcmp0 (signal_data->arg0, arg0) != 0)
2910         continue;
2911
2912       for (m = 0; m < signal_data->subscribers->len; m++)
2913         {
2914           SignalSubscriber *subscriber;
2915           GSource *idle_source;
2916           SignalInstance *signal_instance;
2917
2918           subscriber = &(g_array_index (signal_data->subscribers, SignalSubscriber, m));
2919
2920           signal_instance = g_new0 (SignalInstance, 1);
2921           signal_instance->subscription_id = subscriber->id;
2922           signal_instance->callback = subscriber->callback;
2923           signal_instance->user_data = subscriber->user_data;
2924           signal_instance->message = g_object_ref (message);
2925           signal_instance->connection = g_object_ref (connection);
2926           signal_instance->sender = sender;
2927           signal_instance->path = path;
2928           signal_instance->interface = interface;
2929           signal_instance->member = member;
2930
2931           idle_source = g_idle_source_new ();
2932           g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
2933           g_source_set_callback (idle_source,
2934                                  emit_signal_instance_in_idle_cb,
2935                                  signal_instance,
2936                                  (GDestroyNotify) signal_instance_free);
2937           g_source_attach (idle_source, subscriber->context);
2938           g_source_unref (idle_source);
2939         }
2940     }
2941 }
2942
2943 /* called in message handler thread with lock held */
2944 static void
2945 distribute_signals (GDBusConnection *connection,
2946                     GDBusMessage    *message)
2947 {
2948   GPtrArray *signal_data_array;
2949   const gchar *sender;
2950
2951   sender = g_dbus_message_get_sender (message);
2952
2953   /* collect subscribers that match on sender */
2954   if (sender != NULL)
2955     {
2956       signal_data_array = g_hash_table_lookup (connection->priv->map_sender_to_signal_data_array, sender);
2957       if (signal_data_array != NULL)
2958         schedule_callbacks (connection, signal_data_array, message, sender);
2959     }
2960
2961   /* collect subscribers not matching on sender */
2962   signal_data_array = g_hash_table_lookup (connection->priv->map_sender_to_signal_data_array, "");
2963   if (signal_data_array != NULL)
2964     schedule_callbacks (connection, signal_data_array, message, sender);
2965 }
2966
2967 /* ---------------------------------------------------------------------------------------------------- */
2968
2969 /* only called from finalize(), removes all subscriptions */
2970 static void
2971 purge_all_signal_subscriptions (GDBusConnection *connection)
2972 {
2973   GHashTableIter iter;
2974   gpointer key;
2975   GArray *ids;
2976   GArray *subscribers;
2977   guint n;
2978
2979   ids = g_array_new (FALSE, FALSE, sizeof (guint));
2980   g_hash_table_iter_init (&iter, connection->priv->map_id_to_signal_data);
2981   while (g_hash_table_iter_next (&iter, &key, NULL))
2982     {
2983       guint subscription_id = GPOINTER_TO_UINT (key);
2984       g_array_append_val (ids, subscription_id);
2985     }
2986
2987   subscribers = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber));
2988   for (n = 0; n < ids->len; n++)
2989     {
2990       guint subscription_id = g_array_index (ids, guint, n);
2991       unsubscribe_id_internal (connection,
2992                                subscription_id,
2993                                subscribers);
2994     }
2995   g_array_free (ids, TRUE);
2996
2997   /* call GDestroyNotify without lock held */
2998   for (n = 0; n < subscribers->len; n++)
2999     {
3000       SignalSubscriber *subscriber;
3001       subscriber = &(g_array_index (subscribers, SignalSubscriber, n));
3002       if (subscriber->user_data_free_func != NULL)
3003         subscriber->user_data_free_func (subscriber->user_data);
3004       if (subscriber->context != NULL)
3005         g_main_context_unref (subscriber->context);
3006     }
3007
3008   g_array_free (subscribers, TRUE);
3009 }
3010
3011 /* ---------------------------------------------------------------------------------------------------- */
3012
3013 struct ExportedObject
3014 {
3015   gchar *object_path;
3016   GDBusConnection *connection;
3017
3018   /* maps gchar* -> ExportedInterface* */
3019   GHashTable *map_if_name_to_ei;
3020 };
3021
3022 /* only called with lock held */
3023 static void
3024 exported_object_free (ExportedObject *eo)
3025 {
3026   g_free (eo->object_path);
3027   g_hash_table_unref (eo->map_if_name_to_ei);
3028   g_free (eo);
3029 }
3030
3031 typedef struct
3032 {
3033   ExportedObject *eo;
3034
3035   guint                       id;
3036   gchar                      *interface_name;
3037   const GDBusInterfaceVTable *vtable;
3038   const GDBusInterfaceInfo   *introspection_data;
3039
3040   GMainContext               *context;
3041   gpointer                    user_data;
3042   GDestroyNotify              user_data_free_func;
3043 } ExportedInterface;
3044
3045 /* called with lock held */
3046 static void
3047 exported_interface_free (ExportedInterface *ei)
3048 {
3049   if (ei->user_data_free_func != NULL)
3050     /* TODO: push to thread-default mainloop */
3051     ei->user_data_free_func (ei->user_data);
3052
3053   if (ei->context != NULL)
3054     g_main_context_unref (ei->context);
3055
3056   g_free (ei->interface_name);
3057   g_free (ei);
3058 }
3059
3060 /* ---------------------------------------------------------------------------------------------------- */
3061
3062 typedef struct
3063 {
3064   GDBusConnection *connection;
3065   GDBusMessage *message;
3066   gpointer user_data;
3067   const char *property_name;
3068   const GDBusInterfaceVTable *vtable;
3069   const GDBusInterfaceInfo *interface_info;
3070   const GDBusPropertyInfo *property_info;
3071 } PropertyData;
3072
3073 static void
3074 property_data_free (PropertyData *data)
3075 {
3076   g_object_unref (data->connection);
3077   g_object_unref (data->message);
3078   g_free (data);
3079 }
3080
3081 /* called in thread where object was registered - no locks held */
3082 static gboolean
3083 invoke_get_property_in_idle_cb (gpointer _data)
3084 {
3085   PropertyData *data = _data;
3086   GVariant *value;
3087   GError *error;
3088   GDBusMessage *reply;
3089
3090   error = NULL;
3091   value = data->vtable->get_property (data->connection,
3092                                       g_dbus_message_get_sender (data->message),
3093                                       g_dbus_message_get_path (data->message),
3094                                       data->interface_info->name,
3095                                       data->property_name,
3096                                       &error,
3097                                       data->user_data);
3098
3099
3100   if (value != NULL)
3101     {
3102       g_assert_no_error (error);
3103
3104       g_variant_ref_sink (value);
3105       reply = g_dbus_message_new_method_reply (data->message);
3106       g_dbus_message_set_body (reply, g_variant_new ("(v)", value));
3107       g_dbus_connection_send_message (data->connection, reply, NULL, NULL);
3108       g_variant_unref (value);
3109       g_object_unref (reply);
3110     }
3111   else
3112     {
3113       gchar *dbus_error_name;
3114
3115       g_assert (error != NULL);
3116
3117       dbus_error_name = g_dbus_error_encode_gerror (error);
3118       reply = g_dbus_message_new_method_error_literal (data->message,
3119                                                        dbus_error_name,
3120                                                        error->message);
3121       g_dbus_connection_send_message (data->connection, reply, NULL, NULL);
3122       g_free (dbus_error_name);
3123       g_error_free (error);
3124       g_object_unref (reply);
3125     }
3126
3127   return FALSE;
3128 }
3129
3130 /* called in thread where object was registered - no locks held */
3131 static gboolean
3132 invoke_set_property_in_idle_cb (gpointer _data)
3133 {
3134   PropertyData *data = _data;
3135   GError *error;
3136   GDBusMessage *reply;
3137   GVariant *value;
3138
3139   error = NULL;
3140   value = NULL;
3141
3142   g_variant_get (g_dbus_message_get_body (data->message),
3143                  "(ssv)",
3144                  NULL,
3145                  NULL,
3146                  &value);
3147
3148   /* Fail with org.freedesktop.DBus.Error.InvalidArgs if the type
3149    * of the given value is wrong
3150    */
3151   if (g_strcmp0 (g_variant_get_type_string (value), data->property_info->signature) != 0)
3152     {
3153       reply = g_dbus_message_new_method_error (data->message,
3154                                                "org.freedesktop.DBus.Error.InvalidArgs",
3155                                                _("Error setting property `%s': Expected type `%s' but got `%s'"),
3156                                                data->property_info->name,
3157                                                data->property_info->signature,
3158                                                g_variant_get_type_string (value));
3159       goto out;
3160     }
3161
3162   if (!data->vtable->set_property (data->connection,
3163                                    g_dbus_message_get_sender (data->message),
3164                                    g_dbus_message_get_path (data->message),
3165                                    data->interface_info->name,
3166                                    data->property_name,
3167                                    value,
3168                                    &error,
3169                                    data->user_data))
3170     {
3171       gchar *dbus_error_name;
3172       g_assert (error != NULL);
3173       dbus_error_name = g_dbus_error_encode_gerror (error);
3174       reply = g_dbus_message_new_method_error_literal (data->message,
3175                                                        dbus_error_name,
3176                                                        error->message);
3177       g_free (dbus_error_name);
3178       g_error_free (error);
3179     }
3180   else
3181     {
3182       reply = g_dbus_message_new_method_reply (data->message);
3183     }
3184
3185  out:
3186   g_assert (reply != NULL);
3187   g_dbus_connection_send_message (data->connection, reply, NULL, NULL);
3188   g_object_unref (reply);
3189
3190   return FALSE;
3191 }
3192
3193 /* called with lock held */
3194 static gboolean
3195 validate_and_maybe_schedule_property_getset (GDBusConnection            *connection,
3196                                              GDBusMessage               *message,
3197                                              gboolean                    is_get,
3198                                              const GDBusInterfaceInfo   *introspection_data,
3199                                              const GDBusInterfaceVTable *vtable,
3200                                              GMainContext               *main_context,
3201                                              gpointer                    user_data)
3202 {
3203   gboolean handled;
3204   const char *interface_name;
3205   const char *property_name;
3206   const GDBusPropertyInfo *property_info;
3207   GSource *idle_source;
3208   PropertyData *property_data;
3209   GDBusMessage *reply;
3210
3211   handled = FALSE;
3212
3213   if (is_get)
3214     g_variant_get (g_dbus_message_get_body (message),
3215                    "(ss)",
3216                    &interface_name,
3217                    &property_name);
3218   else
3219     g_variant_get (g_dbus_message_get_body (message),
3220                    "(ssv)",
3221                    &interface_name,
3222                    &property_name,
3223                    NULL);
3224
3225
3226   if (is_get)
3227     {
3228       if (vtable == NULL || vtable->get_property == NULL)
3229         goto out;
3230     }
3231   else
3232     {
3233       if (vtable == NULL || vtable->set_property == NULL)
3234         goto out;
3235     }
3236
3237   /* Check that the property exists - if not fail with org.freedesktop.DBus.Error.InvalidArgs
3238    */
3239   property_info = NULL;
3240
3241   /* TODO: the cost of this is O(n) - it might be worth caching the result */
3242   property_info = g_dbus_interface_info_lookup_property (introspection_data, property_name);
3243   if (property_info == NULL)
3244     {
3245       reply = g_dbus_message_new_method_error (message,
3246                                                "org.freedesktop.DBus.Error.InvalidArgs",
3247                                                _("No such property `%s'"),
3248                                                property_name);
3249       g_dbus_connection_send_message_unlocked (connection, reply, NULL, NULL);
3250       g_object_unref (reply);
3251       handled = TRUE;
3252       goto out;
3253     }
3254
3255   if (is_get && !(property_info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE))
3256     {
3257       reply = g_dbus_message_new_method_error (message,
3258                                                "org.freedesktop.DBus.Error.InvalidArgs",
3259                                                _("Property `%s' is not readable"),
3260                                                property_name);
3261       g_dbus_connection_send_message_unlocked (connection, reply, NULL, NULL);
3262       g_object_unref (reply);
3263       handled = TRUE;
3264       goto out;
3265     }
3266   else if (!is_get && !(property_info->flags & G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
3267     {
3268       reply = g_dbus_message_new_method_error (message,
3269                                                "org.freedesktop.DBus.Error.InvalidArgs",
3270                                                _("Property `%s' is not writable"),
3271                                                property_name);
3272       g_dbus_connection_send_message_unlocked (connection, reply, NULL, NULL);
3273       g_object_unref (reply);
3274       handled = TRUE;
3275       goto out;
3276     }
3277
3278   /* ok, got the property info - call user code in an idle handler */
3279   property_data = g_new0 (PropertyData, 1);
3280   property_data->connection = g_object_ref (connection);
3281   property_data->message = g_object_ref (message);
3282   property_data->user_data = user_data;
3283   property_data->property_name = property_name;
3284   property_data->vtable = vtable;
3285   property_data->interface_info = introspection_data;
3286   property_data->property_info = property_info;
3287
3288   idle_source = g_idle_source_new ();
3289   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
3290   g_source_set_callback (idle_source,
3291                          is_get ? invoke_get_property_in_idle_cb : invoke_set_property_in_idle_cb,
3292                          property_data,
3293                          (GDestroyNotify) property_data_free);
3294   g_source_attach (idle_source, main_context);
3295   g_source_unref (idle_source);
3296
3297   handled = TRUE;
3298
3299  out:
3300   return handled;
3301 }
3302
3303 /* called with lock held */
3304 static gboolean
3305 handle_getset_property (GDBusConnection *connection,
3306                         ExportedObject  *eo,
3307                         GDBusMessage    *message,
3308                         gboolean         is_get)
3309 {
3310   ExportedInterface *ei;
3311   gboolean handled;
3312   const char *interface_name;
3313   const char *property_name;
3314
3315   handled = FALSE;
3316
3317   if (is_get)
3318     g_variant_get (g_dbus_message_get_body (message),
3319                    "(ss)",
3320                    &interface_name,
3321                    &property_name);
3322   else
3323     g_variant_get (g_dbus_message_get_body (message),
3324                    "(ssv)",
3325                    &interface_name,
3326                    &property_name,
3327                    NULL);
3328
3329   /* Fail with org.freedesktop.DBus.Error.InvalidArgs if there is
3330    * no such interface registered
3331    */
3332   ei = g_hash_table_lookup (eo->map_if_name_to_ei, interface_name);
3333   if (ei == NULL)
3334     {
3335       GDBusMessage *reply;
3336       reply = g_dbus_message_new_method_error (message,
3337                                                "org.freedesktop.DBus.Error.InvalidArgs",
3338                                                _("No such interface `%s'"),
3339                                                interface_name);
3340       g_dbus_connection_send_message_unlocked (eo->connection, reply, NULL, NULL);
3341       g_object_unref (reply);
3342       handled = TRUE;
3343       goto out;
3344     }
3345
3346   handled = validate_and_maybe_schedule_property_getset (eo->connection,
3347                                                          message,
3348                                                          is_get,
3349                                                          ei->introspection_data,
3350                                                          ei->vtable,
3351                                                          ei->context,
3352                                                          ei->user_data);
3353  out:
3354   return handled;
3355 }
3356
3357 /* ---------------------------------------------------------------------------------------------------- */
3358
3359 typedef struct
3360 {
3361   GDBusConnection *connection;
3362   GDBusMessage *message;
3363   gpointer user_data;
3364   const GDBusInterfaceVTable *vtable;
3365   const GDBusInterfaceInfo *interface_info;
3366 } PropertyGetAllData;
3367
3368 static void
3369 property_get_all_data_free (PropertyData *data)
3370 {
3371   g_object_unref (data->connection);
3372   g_object_unref (data->message);
3373   g_free (data);
3374 }
3375
3376 /* called in thread where object was registered - no locks held */
3377 static gboolean
3378 invoke_get_all_properties_in_idle_cb (gpointer _data)
3379 {
3380   PropertyGetAllData *data = _data;
3381   GVariantBuilder *builder;
3382   GVariant *packed;
3383   GVariant *result;
3384   GError *error;
3385   GDBusMessage *reply;
3386   guint n;
3387
3388   error = NULL;
3389
3390   /* TODO: Right now we never fail this call - we just omit values if
3391    *       a get_property() call is failing.
3392    *
3393    *       We could fail the whole call if just a single get_property() call
3394    *       returns an error. We need clarification in the D-Bus spec about this.
3395    */
3396   builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
3397   for (n = 0; data->interface_info->properties != NULL && data->interface_info->properties[n] != NULL; n++)
3398     {
3399       const GDBusPropertyInfo *property_info = data->interface_info->properties[n];
3400       GVariant *value;
3401
3402       if (!(property_info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE))
3403         continue;
3404
3405       value = data->vtable->get_property (data->connection,
3406                                           g_dbus_message_get_sender (data->message),
3407                                           g_dbus_message_get_path (data->message),
3408                                           data->interface_info->name,
3409                                           property_info->name,
3410                                           NULL,
3411                                           data->user_data);
3412
3413       if (value == NULL)
3414         continue;
3415
3416       g_variant_ref_sink (value);
3417       g_variant_builder_add (builder,
3418                              "{sv}",
3419                              property_info->name,
3420                              value);
3421       g_variant_unref (value);
3422     }
3423   result = g_variant_builder_end (builder);
3424
3425   builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
3426   g_variant_builder_add_value (builder, result); /* steals result since result is floating */
3427   packed = g_variant_builder_end (builder);
3428
3429   reply = g_dbus_message_new_method_reply (data->message);
3430   g_dbus_message_set_body (reply, packed);
3431   g_dbus_connection_send_message (data->connection, reply, NULL, NULL);
3432   g_object_unref (reply);
3433
3434   return FALSE;
3435 }
3436
3437 /* called with lock held */
3438 static gboolean
3439 validate_and_maybe_schedule_property_get_all (GDBusConnection            *connection,
3440                                               GDBusMessage               *message,
3441                                               const GDBusInterfaceInfo   *introspection_data,
3442                                               const GDBusInterfaceVTable *vtable,
3443                                               GMainContext               *main_context,
3444                                               gpointer                    user_data)
3445 {
3446   gboolean handled;
3447   const char *interface_name;
3448   GSource *idle_source;
3449   PropertyGetAllData *property_get_all_data;
3450
3451   handled = FALSE;
3452
3453   g_variant_get (g_dbus_message_get_body (message),
3454                  "(s)",
3455                  &interface_name);
3456
3457   if (vtable == NULL || vtable->get_property == NULL)
3458     goto out;
3459
3460   /* ok, got the property info - call user in an idle handler */
3461   property_get_all_data = g_new0 (PropertyGetAllData, 1);
3462   property_get_all_data->connection = g_object_ref (connection);
3463   property_get_all_data->message = g_object_ref (message);
3464   property_get_all_data->user_data = user_data;
3465   property_get_all_data->vtable = vtable;
3466   property_get_all_data->interface_info = introspection_data;
3467
3468   idle_source = g_idle_source_new ();
3469   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
3470   g_source_set_callback (idle_source,
3471                          invoke_get_all_properties_in_idle_cb,
3472                          property_get_all_data,
3473                          (GDestroyNotify) property_get_all_data_free);
3474   g_source_attach (idle_source, main_context);
3475   g_source_unref (idle_source);
3476
3477   handled = TRUE;
3478
3479  out:
3480   return handled;
3481 }
3482
3483 /* called with lock held */
3484 static gboolean
3485 handle_get_all_properties (GDBusConnection *connection,
3486                            ExportedObject  *eo,
3487                            GDBusMessage    *message)
3488 {
3489   ExportedInterface *ei;
3490   gboolean handled;
3491   const char *interface_name;
3492
3493   handled = FALSE;
3494
3495   g_variant_get (g_dbus_message_get_body (message),
3496                  "(s)",
3497                  &interface_name);
3498
3499   /* Fail with org.freedesktop.DBus.Error.InvalidArgs if there is
3500    * no such interface registered
3501    */
3502   ei = g_hash_table_lookup (eo->map_if_name_to_ei, interface_name);
3503   if (ei == NULL)
3504     {
3505       GDBusMessage *reply;
3506       reply = g_dbus_message_new_method_error (message,
3507                                                "org.freedesktop.DBus.Error.InvalidArgs",
3508                                                _("No such interface"),
3509                                                interface_name);
3510       g_dbus_connection_send_message_unlocked (eo->connection, reply, NULL, NULL);
3511       g_object_unref (reply);
3512       handled = TRUE;
3513       goto out;
3514     }
3515
3516   handled = validate_and_maybe_schedule_property_get_all (eo->connection,
3517                                                           message,
3518                                                           ei->introspection_data,
3519                                                           ei->vtable,
3520                                                           ei->context,
3521                                                           ei->user_data);
3522  out:
3523   return handled;
3524 }
3525
3526 /* ---------------------------------------------------------------------------------------------------- */
3527
3528 static const gchar introspect_header[] =
3529   "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
3530   "                      \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
3531   "<!-- GDBus " PACKAGE_VERSION " -->\n"
3532   "<node>\n";
3533
3534 static const gchar introspect_tail[] =
3535   "</node>\n";
3536
3537 static const gchar introspect_standard_interfaces[] =
3538   "  <interface name=\"org.freedesktop.DBus.Properties\">\n"
3539   "    <method name=\"Get\">\n"
3540   "      <arg type=\"s\" name=\"interface_name\" direction=\"in\"/>\n"
3541   "      <arg type=\"s\" name=\"property_name\" direction=\"in\"/>\n"
3542   "      <arg type=\"v\" name=\"value\" direction=\"out\"/>\n"
3543   "    </method>\n"
3544   "    <method name=\"GetAll\">\n"
3545   "      <arg type=\"s\" name=\"interface_name\" direction=\"in\"/>\n"
3546   "      <arg type=\"a{sv}\" name=\"properties\" direction=\"out\"/>\n"
3547   "    </method>\n"
3548   "    <method name=\"Set\">\n"
3549   "      <arg type=\"s\" name=\"interface_name\" direction=\"in\"/>\n"
3550   "      <arg type=\"s\" name=\"property_name\" direction=\"in\"/>\n"
3551   "      <arg type=\"v\" name=\"value\" direction=\"in\"/>\n"
3552   "    </method>\n"
3553   "    <signal name=\"PropertiesChanged\">\n"
3554   "      <arg type=\"s\" name=\"interface_name\"/>\n"
3555   "      <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"
3556   "    </signal>\n"
3557   "  </interface>\n"
3558   "  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
3559   "    <method name=\"Introspect\">\n"
3560   "      <arg type=\"s\" name=\"xml_data\" direction=\"out\"/>\n"
3561   "    </method>\n"
3562   "  </interface>\n"
3563   "  <interface name=\"org.freedesktop.DBus.Peer\">\n"
3564   "    <method name=\"Ping\"/>\n"
3565   "    <method name=\"GetMachineId\">\n"
3566   "      <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n"
3567   "    </method>\n"
3568   "  </interface>\n";
3569
3570 static void
3571 introspect_append_header (GString *s)
3572 {
3573   g_string_append (s, introspect_header);
3574 }
3575
3576 static void
3577 introspect_append_standard_interfaces (GString *s)
3578 {
3579   g_string_append (s, introspect_standard_interfaces);
3580 }
3581
3582 static void
3583 maybe_add_path (const gchar *path, gsize path_len, const gchar *object_path, GHashTable *set)
3584 {
3585   if (g_str_has_prefix (object_path, path) && strlen (object_path) >= path_len)
3586     {
3587       const gchar *begin;
3588       const gchar *end;
3589       gchar *s;
3590
3591       begin = object_path + path_len;
3592       end = strchr (begin, '/');
3593
3594       if (end != NULL)
3595         s = g_strndup (begin, end - begin);
3596       else
3597         s = g_strdup (begin);
3598
3599       if (g_hash_table_lookup (set, s) == NULL)
3600         g_hash_table_insert (set, s, GUINT_TO_POINTER (1));
3601       else
3602         g_free (s);
3603     }
3604 }
3605
3606 /* TODO: we want a nicer public interface for this */
3607 static gchar **
3608 g_dbus_connection_list_registered_unlocked (GDBusConnection *connection,
3609                                             const gchar     *path)
3610 {
3611   GPtrArray *p;
3612   gchar **ret;
3613   GHashTableIter hash_iter;
3614   const gchar *object_path;
3615   gsize path_len;
3616   GHashTable *set;
3617   GList *keys;
3618   GList *l;
3619
3620   CONNECTION_ENSURE_LOCK (connection);
3621
3622   path_len = strlen (path);
3623   if (path_len > 1)
3624     path_len++;
3625
3626   set = g_hash_table_new (g_str_hash, g_str_equal);
3627
3628   g_hash_table_iter_init (&hash_iter, connection->priv->map_object_path_to_eo);
3629   while (g_hash_table_iter_next (&hash_iter, (gpointer) &object_path, NULL))
3630     maybe_add_path (path, path_len, object_path, set);
3631
3632   g_hash_table_iter_init (&hash_iter, connection->priv->map_object_path_to_es);
3633   while (g_hash_table_iter_next (&hash_iter, (gpointer) &object_path, NULL))
3634     maybe_add_path (path, path_len, object_path, set);
3635
3636   p = g_ptr_array_new ();
3637   keys = g_hash_table_get_keys (set);
3638   for (l = keys; l != NULL; l = l->next)
3639     g_ptr_array_add (p, l->data);
3640   g_hash_table_unref (set);
3641   g_list_free (keys);
3642
3643   g_ptr_array_add (p, NULL);
3644   ret = (gchar **) g_ptr_array_free (p, FALSE);
3645   return ret;
3646 }
3647
3648 static gchar **
3649 g_dbus_connection_list_registered (GDBusConnection *connection,
3650                                    const gchar     *path)
3651 {
3652   gchar **ret;
3653   CONNECTION_LOCK (connection);
3654   ret = g_dbus_connection_list_registered_unlocked (connection, path);
3655   CONNECTION_UNLOCK (connection);
3656   return ret;
3657 }
3658
3659 /* called in message handler thread with lock held */
3660 static gboolean
3661 handle_introspect (GDBusConnection *connection,
3662                    ExportedObject  *eo,
3663                    GDBusMessage    *message)
3664 {
3665   guint n;
3666   GString *s;
3667   GDBusMessage *reply;
3668   GHashTableIter hash_iter;
3669   ExportedInterface *ei;
3670   gchar **registered;
3671
3672   /* first the header with the standard interfaces */
3673   s = g_string_sized_new (sizeof (introspect_header) +
3674                           sizeof (introspect_standard_interfaces) +
3675                           sizeof (introspect_tail));
3676   introspect_append_header (s);
3677   introspect_append_standard_interfaces (s);
3678
3679   /* then include the registered interfaces */
3680   g_hash_table_iter_init (&hash_iter, eo->map_if_name_to_ei);
3681   while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &ei))
3682     g_dbus_interface_info_generate_xml (ei->introspection_data, 2, s);
3683
3684   /* finally include nodes registered below us */
3685   registered = g_dbus_connection_list_registered_unlocked (connection, eo->object_path);
3686   for (n = 0; registered != NULL && registered[n] != NULL; n++)
3687     g_string_append_printf (s, "  <node name=\"%s\"/>\n", registered[n]);
3688   g_strfreev (registered);
3689   g_string_append (s, introspect_tail);
3690
3691   reply = g_dbus_message_new_method_reply (message);
3692   g_dbus_message_set_body (reply, g_variant_new ("(s)", s->str));
3693   g_dbus_connection_send_message_unlocked (connection, reply, NULL, NULL);
3694   g_object_unref (reply);
3695   g_string_free (s, TRUE);
3696
3697   return TRUE;
3698 }
3699
3700 /* called in thread where object was registered - no locks held */
3701 static gboolean
3702 call_in_idle_cb (gpointer user_data)
3703 {
3704   GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (user_data);
3705   GDBusInterfaceVTable *vtable;
3706
3707   vtable = g_object_get_data (G_OBJECT (invocation), "g-dbus-interface-vtable");
3708   g_assert (vtable != NULL && vtable->method_call != NULL);
3709
3710   vtable->method_call (g_dbus_method_invocation_get_connection (invocation),
3711                        g_dbus_method_invocation_get_sender (invocation),
3712                        g_dbus_method_invocation_get_object_path (invocation),
3713                        g_dbus_method_invocation_get_interface_name (invocation),
3714                        g_dbus_method_invocation_get_method_name (invocation),
3715                        g_dbus_method_invocation_get_parameters (invocation),
3716                        g_object_ref (invocation),
3717                        g_dbus_method_invocation_get_user_data (invocation));
3718
3719   return FALSE;
3720 }
3721
3722 /* called in message handler thread with lock held */
3723 static gboolean
3724 validate_and_maybe_schedule_method_call (GDBusConnection            *connection,
3725                                          GDBusMessage               *message,
3726                                          const GDBusInterfaceInfo   *introspection_data,
3727                                          const GDBusInterfaceVTable *vtable,
3728                                          GMainContext               *main_context,
3729                                          gpointer                    user_data)
3730 {
3731   GDBusMethodInvocation *invocation;
3732   const GDBusMethodInfo *method_info;
3733   GDBusMessage *reply;
3734   GVariant *parameters;
3735   GSource *idle_source;
3736   gboolean handled;
3737   gchar *in_signature;
3738
3739   handled = FALSE;
3740
3741   /* TODO: the cost of this is O(n) - it might be worth caching the result */
3742   method_info = g_dbus_interface_info_lookup_method (introspection_data, g_dbus_message_get_member (message));
3743
3744   /* if the method doesn't exist, return the org.freedesktop.DBus.Error.UnknownMethod
3745    * error to the caller
3746    */
3747   if (method_info == NULL)
3748     {
3749       reply = g_dbus_message_new_method_error (message,
3750                                                "org.freedesktop.DBus.Error.UnknownMethod",
3751                                                _("No such method `%s'"),
3752                                                g_dbus_message_get_member (message));
3753       g_dbus_connection_send_message_unlocked (connection, reply, NULL, NULL);
3754       g_object_unref (reply);
3755       handled = TRUE;
3756       goto out;
3757     }
3758
3759   /* Check that the incoming args are of the right type - if they are not, return
3760    * the org.freedesktop.DBus.Error.InvalidArgs error to the caller
3761    *
3762    * TODO: might also be worth caching the combined signature.
3763    */
3764   in_signature = _g_dbus_compute_complete_signature (method_info->in_args, FALSE);
3765   if (g_strcmp0 (g_dbus_message_get_signature (message), in_signature) != 0)
3766     {
3767       reply = g_dbus_message_new_method_error (message,
3768                                                "org.freedesktop.DBus.Error.InvalidArgs",
3769                                                _("Signature of message, `%s', does not match expected signature `%s'"),
3770                                                g_dbus_message_get_signature (message),
3771                                                in_signature);
3772       g_dbus_connection_send_message_unlocked (connection, reply, NULL, NULL);
3773       g_object_unref (reply);
3774       g_free (in_signature);
3775       handled = TRUE;
3776       goto out;
3777     }
3778   g_free (in_signature);
3779
3780   parameters = g_dbus_message_get_body (message);
3781   if (parameters == NULL)
3782     {
3783       parameters = g_variant_new ("()");
3784       g_variant_ref_sink (parameters);
3785     }
3786   else
3787     {
3788       g_variant_ref (parameters);
3789     }
3790
3791   /* schedule the call in idle */
3792   invocation = g_dbus_method_invocation_new (g_dbus_message_get_sender (message),
3793                                              g_dbus_message_get_path (message),
3794                                              g_dbus_message_get_interface (message),
3795                                              g_dbus_message_get_member (message),
3796                                              method_info,
3797                                              connection,
3798                                              message,
3799                                              parameters,
3800                                              user_data);
3801   g_variant_unref (parameters);
3802   g_object_set_data (G_OBJECT (invocation),
3803                      "g-dbus-interface-vtable",
3804                      (gpointer) vtable);
3805
3806   idle_source = g_idle_source_new ();
3807   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
3808   g_source_set_callback (idle_source,
3809                          call_in_idle_cb,
3810                          invocation,
3811                          g_object_unref);
3812   g_source_attach (idle_source, main_context);
3813   g_source_unref (idle_source);
3814
3815   handled = TRUE;
3816
3817  out:
3818   return handled;
3819 }
3820
3821 /* ---------------------------------------------------------------------------------------------------- */
3822
3823 /* called in message handler thread with lock held */
3824 static gboolean
3825 obj_message_func (GDBusConnection *connection,
3826                   ExportedObject  *eo,
3827                   GDBusMessage    *message)
3828 {
3829   const gchar *interface_name;
3830   const gchar *member;
3831   const gchar *signature;
3832   gboolean handled;
3833
3834   handled = FALSE;
3835
3836   interface_name = g_dbus_message_get_interface (message);
3837   member = g_dbus_message_get_member (message);
3838   signature = g_dbus_message_get_signature (message);
3839
3840   /* see if we have an interface for handling this call */
3841   if (interface_name != NULL)
3842     {
3843       ExportedInterface *ei;
3844       ei = g_hash_table_lookup (eo->map_if_name_to_ei, interface_name);
3845       if (ei != NULL)
3846         {
3847           /* we do - invoke the handler in idle in the right thread */
3848
3849           /* handle no vtable or handler being present */
3850           if (ei->vtable == NULL || ei->vtable->method_call == NULL)
3851             goto out;
3852
3853           handled = validate_and_maybe_schedule_method_call (connection,
3854                                                              message,
3855                                                              ei->introspection_data,
3856                                                              ei->vtable,
3857                                                              ei->context,
3858                                                              ei->user_data);
3859           goto out;
3860         }
3861     }
3862
3863   if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Introspectable") == 0 &&
3864       g_strcmp0 (member, "Introspect") == 0 &&
3865       g_strcmp0 (signature, "") == 0)
3866     {
3867       handled = handle_introspect (connection, eo, message);
3868       goto out;
3869     }
3870   else if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0 &&
3871            g_strcmp0 (member, "Get") == 0 &&
3872            g_strcmp0 (signature, "ss") == 0)
3873     {
3874       handled = handle_getset_property (connection, eo, message, TRUE);
3875       goto out;
3876     }
3877   else if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0 &&
3878            g_strcmp0 (member, "Set") == 0 &&
3879            g_strcmp0 (signature, "ssv") == 0)
3880     {
3881       handled = handle_getset_property (connection, eo, message, FALSE);
3882       goto out;
3883     }
3884   else if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0 &&
3885            g_strcmp0 (member, "GetAll") == 0 &&
3886            g_strcmp0 (signature, "s") == 0)
3887     {
3888       handled = handle_get_all_properties (connection, eo, message);
3889       goto out;
3890     }
3891
3892  out:
3893   return handled;
3894 }
3895
3896 /**
3897  * g_dbus_connection_register_object:
3898  * @connection: A #GDBusConnection.
3899  * @object_path: The object path to register at.
3900  * @interface_name: The D-Bus interface to register.
3901  * @introspection_data: Introspection data for the interface.
3902  * @vtable: A #GDBusInterfaceVTable to call into or %NULL.
3903  * @user_data: Data to pass to functions in @vtable.
3904  * @user_data_free_func: Function to call when the object path is unregistered.
3905  * @error: Return location for error or %NULL.
3906  *
3907  * Registers callbacks for exported objects at @object_path with the
3908  * D-Bus interface @interface_name.
3909  *
3910  * Calls to functions in @vtable (and @user_data_free_func) will
3911  * happen in the <link linkend="g-main-context-push-thread-default">thread-default main
3912  * loop</link> of the thread you are calling this method from.
3913  *
3914  * Note that all #GVariant values passed to functions in @vtable will match
3915  * the signature given in @introspection_data - if a remote caller passes
3916  * incorrect values, the <literal>org.freedesktop.DBus.Error.InvalidArgs</literal>
3917  * is returned to the remote caller.
3918  *
3919  * Additionally, if the remote caller attempts to invoke methods or
3920  * access properties not mentioned in @introspection_data the
3921  * <literal>org.freedesktop.DBus.Error.UnknownMethod</literal> resp.
3922  * <literal>org.freedesktop.DBus.Error.InvalidArgs</literal> errors
3923  * are returned to the caller.
3924  *
3925  * It is considered a programming error if the
3926  * #GDBusInterfaceGetPropertyFunc function in @vtable returns a
3927  * #GVariant of incorrect type.
3928  *
3929  * If an existing callback is already registered at @object_path and
3930  * @interface_name, then @error is set to #G_IO_ERROR_EXISTS.
3931  *
3932  * See <xref linkend="gdbus-server"/> for an example of how to use this method.
3933  *
3934  * Returns: 0 if @error is set, otherwise a registration id (never 0)
3935  * that can be used with g_dbus_connection_unregister_object() .
3936  *
3937  * Since: 2.26
3938  */
3939 guint
3940 g_dbus_connection_register_object (GDBusConnection            *connection,
3941                                    const gchar                *object_path,
3942                                    const gchar                *interface_name,
3943                                    const GDBusInterfaceInfo   *introspection_data,
3944                                    const GDBusInterfaceVTable *vtable,
3945                                    gpointer                    user_data,
3946                                    GDestroyNotify              user_data_free_func,
3947                                    GError                    **error)
3948 {
3949   ExportedObject *eo;
3950   ExportedInterface *ei;
3951   guint ret;
3952
3953   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
3954   g_return_val_if_fail (!g_dbus_connection_is_closed (connection), 0);
3955   g_return_val_if_fail (object_path != NULL && g_variant_is_object_path (object_path), 0);
3956   g_return_val_if_fail (interface_name == NULL || g_dbus_is_interface_name (interface_name), 0);
3957   g_return_val_if_fail (introspection_data != NULL, 0);
3958   g_return_val_if_fail (error == NULL || *error == NULL, 0);
3959
3960   ret = 0;
3961
3962   CONNECTION_LOCK (connection);
3963
3964   eo = g_hash_table_lookup (connection->priv->map_object_path_to_eo, object_path);
3965   if (eo == NULL)
3966     {
3967       eo = g_new0 (ExportedObject, 1);
3968       eo->object_path = g_strdup (object_path);
3969       eo->connection = connection;
3970       eo->map_if_name_to_ei = g_hash_table_new_full (g_str_hash,
3971                                                      g_str_equal,
3972                                                      NULL,
3973                                                      (GDestroyNotify) exported_interface_free);
3974       g_hash_table_insert (connection->priv->map_object_path_to_eo, eo->object_path, eo);
3975     }
3976
3977   ei = g_hash_table_lookup (eo->map_if_name_to_ei, interface_name);
3978   if (ei != NULL)
3979     {
3980       g_set_error (error,
3981                    G_IO_ERROR,
3982                    G_IO_ERROR_EXISTS,
3983                    _("An object is already exported for the interface %s at %s"),
3984                    interface_name,
3985                    object_path);
3986       goto out;
3987     }
3988
3989   ei = g_new0 (ExportedInterface, 1);
3990   ei->id = _global_registration_id++; /* TODO: overflow etc. */
3991   ei->eo = eo;
3992   ei->user_data = user_data;
3993   ei->user_data_free_func = user_data_free_func;
3994   ei->vtable = vtable;
3995   ei->introspection_data = introspection_data;
3996   ei->interface_name = g_strdup (interface_name);
3997   ei->context = g_main_context_get_thread_default ();
3998   if (ei->context != NULL)
3999     g_main_context_ref (ei->context);
4000
4001   g_hash_table_insert (eo->map_if_name_to_ei,
4002                        (gpointer) ei->interface_name,
4003                        ei);
4004   g_hash_table_insert (connection->priv->map_id_to_ei,
4005                        GUINT_TO_POINTER (ei->id),
4006                        ei);
4007
4008   ret = ei->id;
4009
4010  out:
4011   CONNECTION_UNLOCK (connection);
4012
4013   return ret;
4014 }
4015
4016 /**
4017  * g_dbus_connection_unregister_object:
4018  * @connection: A #GDBusConnection.
4019  * @registration_id: A registration id obtained from g_dbus_connection_register_object().
4020  *
4021  * Unregisters an object.
4022  *
4023  * Returns: %TRUE if the object was unregistered, %FALSE otherwise.
4024  *
4025  * Since: 2.26
4026  */
4027 gboolean
4028 g_dbus_connection_unregister_object (GDBusConnection *connection,
4029                                      guint            registration_id)
4030 {
4031   ExportedInterface *ei;
4032   ExportedObject *eo;
4033   gboolean ret;
4034
4035   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
4036
4037   ret = FALSE;
4038
4039   CONNECTION_LOCK (connection);
4040
4041   ei = g_hash_table_lookup (connection->priv->map_id_to_ei,
4042                             GUINT_TO_POINTER (registration_id));
4043   if (ei == NULL)
4044     goto out;
4045
4046   eo = ei->eo;
4047
4048   g_warn_if_fail (g_hash_table_remove (connection->priv->map_id_to_ei, GUINT_TO_POINTER (ei->id)));
4049   g_warn_if_fail (g_hash_table_remove (eo->map_if_name_to_ei, ei->interface_name));
4050   /* unregister object path if we have no more exported interfaces */
4051   if (g_hash_table_size (eo->map_if_name_to_ei) == 0)
4052     g_warn_if_fail (g_hash_table_remove (connection->priv->map_object_path_to_eo,
4053                                          eo->object_path));
4054
4055   ret = TRUE;
4056
4057  out:
4058   CONNECTION_UNLOCK (connection);
4059
4060   return ret;
4061 }
4062
4063 /* ---------------------------------------------------------------------------------------------------- */
4064
4065 /**
4066  * g_dbus_connection_emit_signal:
4067  * @connection: A #GDBusConnection.
4068  * @destination_bus_name: The unique bus name for the destination for the signal or %NULL to emit to all listeners.
4069  * @object_path: Path of remote object.
4070  * @interface_name: D-Bus interface to emit a signal on.
4071  * @signal_name: The name of the signal to emit.
4072  * @parameters: A #GVariant tuple with parameters for the signal or %NULL if not passing parameters.
4073  * @error: Return location for error or %NULL.
4074  *
4075  * Emits a signal.
4076  *
4077  * This can only fail if @parameters is not compatible with the D-Bus protocol.
4078  *
4079  * Returns: %TRUE unless @error is set.
4080  *
4081  * Since: 2.26
4082  */
4083 gboolean
4084 g_dbus_connection_emit_signal (GDBusConnection  *connection,
4085                                const gchar      *destination_bus_name,
4086                                const gchar      *object_path,
4087                                const gchar      *interface_name,
4088                                const gchar      *signal_name,
4089                                GVariant         *parameters,
4090                                GError          **error)
4091 {
4092   GDBusMessage *message;
4093   gboolean ret;
4094
4095   message = NULL;
4096   ret = FALSE;
4097
4098   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
4099   g_return_val_if_fail (destination_bus_name == NULL || g_dbus_is_name (destination_bus_name), FALSE);
4100   g_return_val_if_fail (object_path != NULL && g_variant_is_object_path (object_path), FALSE);
4101   g_return_val_if_fail (interface_name != NULL && g_dbus_is_interface_name (interface_name), FALSE);
4102   g_return_val_if_fail (signal_name != NULL && g_dbus_is_member_name (signal_name), FALSE);
4103   g_return_val_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), FALSE);
4104
4105   message = g_dbus_message_new_signal (object_path,
4106                                        interface_name,
4107                                        signal_name);
4108
4109   if (destination_bus_name != NULL)
4110     g_dbus_message_set_header (message,
4111                                G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION,
4112                                g_variant_new_string (destination_bus_name));
4113
4114   if (parameters != NULL)
4115     g_dbus_message_set_body (message, parameters);
4116
4117   ret = g_dbus_connection_send_message (connection, message, NULL, error);
4118   g_object_unref (message);
4119
4120   return ret;
4121 }
4122
4123 static void
4124 add_call_flags (GDBusMessage           *message,
4125                          GDBusCallFlags  flags)
4126 {
4127   if (flags & G_DBUS_CALL_FLAGS_NO_AUTO_START)
4128     g_dbus_message_set_flags (message, G_DBUS_MESSAGE_FLAGS_NO_AUTO_START);
4129 }
4130
4131 /**
4132  * g_dbus_connection_call:
4133  * @connection: A #GDBusConnection.
4134  * @bus_name: A unique or well-known bus name or %NULL if @connection is not a message bus connection.
4135  * @object_path: Path of remote object.
4136  * @interface_name: D-Bus interface to invoke method on.
4137  * @method_name: The name of the method to invoke.
4138  * @parameters: A #GVariant tuple with parameters for the method or %NULL if not passing parameters.
4139  * @flags: Flags from the #GDBusCallFlags enumeration.
4140  * @timeout_msec: The timeout in milliseconds or -1 to use the default timeout.
4141  * @cancellable: A #GCancellable or %NULL.
4142  * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL if you don't
4143  * care about the result of the method invocation.
4144  * @user_data: The data to pass to @callback.
4145  *
4146  * Asynchronously invokes the @method_name method on the
4147  * @interface_name D-Bus interface on the remote object at
4148  * @object_path owned by @bus_name.
4149  *
4150  * If @connection is closed then the operation will fail with
4151  * %G_IO_ERROR_CLOSED. If @cancellable is canceled, the operation will
4152  * fail with %G_IO_ERROR_CANCELLED. If @parameters contains a value
4153  * not compatible with the D-Bus protocol, the operation fails with
4154  * %G_IO_ERROR_INVALID_ARGUMENT.
4155  *
4156  * If the @parameters #GVariant is floating, it is consumed. This allows
4157  * convenient 'inline' use of g_variant_new(), e.g.:
4158  * |[
4159  *  g_dbus_connection_call (connection,
4160  *                          "org.freedesktop.StringThings",
4161  *                          "/org/freedesktop/StringThings",
4162  *                          "org.freedesktop.StringThings",
4163  *                          "TwoStrings",
4164  *                          g_variant_new ("(ss)",
4165  *                                         "Thing One",
4166  *                                         "Thing Two"),
4167  *                          G_DBUS_CALL_FLAGS_NONE,
4168  *                          -1,
4169  *                          NULL,
4170  *                          (GAsyncReadyCallback) two_strings_done,
4171  *                          NULL);
4172  * ]|
4173  *
4174  * This is an asynchronous method. When the operation is finished, @callback will be invoked
4175  * in the <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
4176  * of the thread you are calling this method from. You can then call
4177  * g_dbus_connection_call_finish() to get the result of the operation.
4178  * See g_dbus_connection_call_sync() for the synchronous version of this
4179  * function.
4180  *
4181  * Since: 2.26
4182  */
4183 void
4184 g_dbus_connection_call (GDBusConnection        *connection,
4185                         const gchar            *bus_name,
4186                         const gchar            *object_path,
4187                         const gchar            *interface_name,
4188                         const gchar            *method_name,
4189                         GVariant               *parameters,
4190                         GDBusCallFlags          flags,
4191                         gint                    timeout_msec,
4192                         GCancellable           *cancellable,
4193                         GAsyncReadyCallback     callback,
4194                         gpointer                user_data)
4195 {
4196   GDBusMessage *message;
4197
4198   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
4199   g_return_if_fail (bus_name == NULL || g_dbus_is_name (bus_name));
4200   g_return_if_fail (object_path != NULL && g_variant_is_object_path (object_path));
4201   g_return_if_fail (interface_name != NULL && g_dbus_is_interface_name (interface_name));
4202   g_return_if_fail (method_name != NULL && g_dbus_is_member_name (method_name));
4203   g_return_if_fail (timeout_msec >= 0 || timeout_msec == -1);
4204   g_return_if_fail ((parameters == NULL) || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
4205
4206   message = g_dbus_message_new_method_call (bus_name,
4207                                             object_path,
4208                                             interface_name,
4209                                             method_name);
4210   add_call_flags (message, flags);
4211   if (parameters != NULL)
4212     g_dbus_message_set_body (message, parameters);
4213
4214   g_dbus_connection_send_message_with_reply (connection,
4215                                              message,
4216                                              timeout_msec,
4217                                              NULL, /* volatile guint32 *out_serial */
4218                                              cancellable,
4219                                              callback,
4220                                              user_data);
4221
4222   if (message != NULL)
4223     g_object_unref (message);
4224 }
4225
4226 static GVariant *
4227 decode_method_reply (GDBusMessage  *reply,
4228                      GError       **error)
4229 {
4230   GVariant *result;
4231
4232   result = NULL;
4233   switch (g_dbus_message_get_message_type (reply))
4234     {
4235     case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
4236       result = g_dbus_message_get_body (reply);
4237       if (result == NULL)
4238         {
4239           result = g_variant_new ("()");
4240           g_variant_ref_sink (result);
4241         }
4242       else
4243         {
4244           g_variant_ref (result);
4245         }
4246       break;
4247
4248     case G_DBUS_MESSAGE_TYPE_ERROR:
4249       g_dbus_message_to_gerror (reply, error);
4250       break;
4251
4252     default:
4253       g_assert_not_reached ();
4254       break;
4255     }
4256
4257   return result;
4258 }
4259
4260 /**
4261  * g_dbus_connection_call_finish:
4262  * @connection: A #GDBusConnection.
4263  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_connection_call().
4264  * @error: Return location for error or %NULL.
4265  *
4266  * Finishes an operation started with g_dbus_connection_call().
4267  *
4268  * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
4269  * return values. Free with g_variant_unref().
4270  *
4271  * Since: 2.26
4272  */
4273 GVariant *
4274 g_dbus_connection_call_finish (GDBusConnection  *connection,
4275                                GAsyncResult     *res,
4276                                GError          **error)
4277 {
4278   GDBusMessage *reply;
4279   GVariant *result;
4280
4281   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
4282   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
4283   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
4284
4285   result = NULL;
4286
4287   reply = g_dbus_connection_send_message_with_reply_finish (connection, res, error);
4288   if (reply == NULL)
4289     goto out;
4290
4291   result = decode_method_reply (reply, error);
4292
4293   g_object_unref (reply);
4294
4295  out:
4296   return result;
4297 }
4298
4299 /* ---------------------------------------------------------------------------------------------------- */
4300
4301 /**
4302  * g_dbus_connection_call_sync:
4303  * @connection: A #GDBusConnection.
4304  * @bus_name: A unique or well-known bus name.
4305  * @object_path: Path of remote object.
4306  * @interface_name: D-Bus interface to invoke method on.
4307  * @method_name: The name of the method to invoke.
4308  * @parameters: A #GVariant tuple with parameters for the method or %NULL if not passing parameters.
4309  * @flags: Flags from the #GDBusCallFlags enumeration.
4310  * @timeout_msec: The timeout in milliseconds or -1 to use the default timeout.
4311  * @cancellable: A #GCancellable or %NULL.
4312  * @error: Return location for error or %NULL.
4313  *
4314  * Synchronously invokes the @method_name method on the
4315  * @interface_name D-Bus interface on the remote object at
4316  * @object_path owned by @bus_name.
4317  *
4318  * If @connection is closed then the operation will fail with
4319  * %G_IO_ERROR_CLOSED. If @cancellable is canceled, the
4320  * operation will fail with %G_IO_ERROR_CANCELLED. If @parameters
4321  * contains a value not compatible with the D-Bus protocol, the operation
4322  * fails with %G_IO_ERROR_INVALID_ARGUMENT.
4323  *
4324  * If the @parameters #GVariant is floating, it is consumed.
4325  * This allows convenient 'inline' use of g_variant_new(), e.g.:
4326  * |[
4327  *  g_dbus_connection_call_sync (connection,
4328  *                               "org.freedesktop.StringThings",
4329  *                               "/org/freedesktop/StringThings",
4330  *                               "org.freedesktop.StringThings",
4331  *                               "TwoStrings",
4332  *                               g_variant_new ("(ss)",
4333  *                                              "Thing One",
4334  *                                              "Thing Two"),
4335  *                               G_DBUS_CALL_FLAGS_NONE,
4336  *                               -1,
4337  *                               NULL,
4338  *                               &amp;error);
4339  * ]|
4340  *
4341  * The calling thread is blocked until a reply is received. See
4342  * g_dbus_connection_call() for the asynchronous version of
4343  * this method.
4344  *
4345  * Returns: %NULL if @error is set. Otherwise a #GVariant tuple with
4346  * return values. Free with g_variant_unref().
4347  *
4348  * Since: 2.26
4349  */
4350 GVariant *
4351 g_dbus_connection_call_sync (GDBusConnection         *connection,
4352                              const gchar             *bus_name,
4353                              const gchar             *object_path,
4354                              const gchar             *interface_name,
4355                              const gchar             *method_name,
4356                              GVariant                *parameters,
4357                              GDBusCallFlags           flags,
4358                              gint                     timeout_msec,
4359                              GCancellable            *cancellable,
4360                              GError                 **error)
4361 {
4362   GDBusMessage *message;
4363   GDBusMessage *reply;
4364   GVariant *result;
4365
4366   message = NULL;
4367   reply = NULL;
4368   result = NULL;
4369
4370   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
4371   g_return_val_if_fail (bus_name == NULL || g_dbus_is_name (bus_name), NULL);
4372   g_return_val_if_fail (object_path != NULL && g_variant_is_object_path (object_path), NULL);
4373   g_return_val_if_fail (interface_name != NULL && g_dbus_is_interface_name (interface_name), NULL);
4374   g_return_val_if_fail (method_name != NULL && g_dbus_is_member_name (method_name), NULL);
4375   g_return_val_if_fail (timeout_msec >= 0 || timeout_msec == -1, NULL);
4376   g_return_val_if_fail ((parameters == NULL) || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL);
4377
4378   message = g_dbus_message_new_method_call (bus_name,
4379                                             object_path,
4380                                             interface_name,
4381                                             method_name);
4382   add_call_flags (message, flags);
4383   if (parameters != NULL)
4384     g_dbus_message_set_body (message, parameters);
4385
4386   reply = g_dbus_connection_send_message_with_reply_sync (connection,
4387                                                           message,
4388                                                           timeout_msec,
4389                                                           NULL, /* volatile guint32 *out_serial */
4390                                                           cancellable,
4391                                                           error);
4392
4393   if (reply == NULL)
4394     goto out;
4395
4396   result = decode_method_reply (reply, error);
4397
4398  out:
4399   if (message != NULL)
4400     g_object_unref (message);
4401   if (reply != NULL)
4402     g_object_unref (reply);
4403
4404   return result;
4405 }
4406
4407 /* ---------------------------------------------------------------------------------------------------- */
4408
4409 struct ExportedSubtree
4410 {
4411   guint                     id;
4412   gchar                    *object_path;
4413   GDBusConnection          *connection;
4414   const GDBusSubtreeVTable *vtable;
4415   GDBusSubtreeFlags         flags;
4416
4417   GMainContext             *context;
4418   gpointer                  user_data;
4419   GDestroyNotify            user_data_free_func;
4420 };
4421
4422 static void
4423 exported_subtree_free (ExportedSubtree *es)
4424 {
4425   if (es->user_data_free_func != NULL)
4426     /* TODO: push to thread-default mainloop */
4427     es->user_data_free_func (es->user_data);
4428
4429   if (es->context != NULL)
4430     g_main_context_unref (es->context);
4431
4432   g_free (es->object_path);
4433   g_free (es);
4434 }
4435
4436 /* called without lock held */
4437 static gboolean
4438 handle_subtree_introspect (GDBusConnection *connection,
4439                            ExportedSubtree *es,
4440                            GDBusMessage    *message)
4441 {
4442   GString *s;
4443   gboolean handled;
4444   GDBusMessage *reply;
4445   gchar **children;
4446   gboolean is_root;
4447   const gchar *sender;
4448   const gchar *requested_object_path;
4449   const gchar *requested_node;
4450   GPtrArray *interfaces;
4451   guint n;
4452   gchar **subnode_paths;
4453
4454   handled = FALSE;
4455
4456   requested_object_path = g_dbus_message_get_path (message);
4457   sender = g_dbus_message_get_sender (message);
4458   is_root = (g_strcmp0 (requested_object_path, es->object_path) == 0);
4459
4460   s = g_string_new (NULL);
4461   introspect_append_header (s);
4462
4463   /* Strictly we don't need the children in dynamic mode, but we avoid the
4464    * conditionals to preserve code clarity
4465    */
4466   children = es->vtable->enumerate (es->connection,
4467                                     sender,
4468                                     es->object_path,
4469                                     es->user_data);
4470
4471   if (!is_root)
4472     {
4473       requested_node = strrchr (requested_object_path, '/') + 1;
4474
4475       /* Assert existence of object if we are not dynamic */
4476       if (!(es->flags & G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES) &&
4477           !_g_strv_has_string ((const gchar * const *) children, requested_node))
4478         goto out;
4479     }
4480   else
4481     {
4482       requested_node = "/";
4483     }
4484
4485   interfaces = es->vtable->introspect (es->connection,
4486                                        sender,
4487                                        es->object_path,
4488                                        requested_node,
4489                                        es->user_data);
4490   if (interfaces != NULL)
4491     {
4492       if (interfaces->len > 0)
4493         {
4494           /* we're in business */
4495           introspect_append_standard_interfaces (s);
4496
4497           for (n = 0; n < interfaces->len; n++)
4498             {
4499               const GDBusInterfaceInfo *interface_info = interfaces->pdata[n];
4500               g_dbus_interface_info_generate_xml (interface_info, 2, s);
4501             }
4502         }
4503       g_ptr_array_unref (interfaces);
4504     }
4505
4506   /* then include <node> entries from the Subtree for the root */
4507   if (is_root)
4508     {
4509       for (n = 0; children != NULL && children[n] != NULL; n++)
4510         g_string_append_printf (s, "  <node name=\"%s\"/>\n", children[n]);
4511     }
4512
4513   /* finally include nodes registered below us */
4514   subnode_paths = g_dbus_connection_list_registered (es->connection, requested_object_path);
4515   for (n = 0; subnode_paths != NULL && subnode_paths[n] != NULL; n++)
4516     g_string_append_printf (s, "  <node name=\"%s\"/>\n", subnode_paths[n]);
4517   g_strfreev (subnode_paths);
4518
4519   g_string_append (s, "</node>\n");
4520
4521   reply = g_dbus_message_new_method_reply (message);
4522   g_dbus_message_set_body (reply, g_variant_new ("(s)", s->str));
4523   g_dbus_connection_send_message (connection, reply, NULL, NULL);
4524   g_object_unref (reply);
4525
4526   handled = TRUE;
4527
4528  out:
4529   g_string_free (s, TRUE);
4530   g_strfreev (children);
4531   return handled;
4532 }
4533
4534 /* called without lock held */
4535 static gboolean
4536 handle_subtree_method_invocation (GDBusConnection *connection,
4537                                   ExportedSubtree *es,
4538                                   GDBusMessage    *message)
4539 {
4540   gboolean handled;;
4541   const gchar *sender;
4542   const gchar *interface_name;
4543   const gchar *member;
4544   const gchar *signature;
4545   const gchar *requested_object_path;
4546   const gchar *requested_node;
4547   gboolean is_root;
4548   gchar **children;
4549   const GDBusInterfaceInfo *introspection_data;
4550   const GDBusInterfaceVTable *interface_vtable;
4551   gpointer interface_user_data;
4552   guint n;
4553   GPtrArray *interfaces;
4554   gboolean is_property_get;
4555   gboolean is_property_set;
4556   gboolean is_property_get_all;
4557
4558   handled = FALSE;
4559   interfaces = NULL;
4560
4561   requested_object_path = g_dbus_message_get_path (message);
4562   sender = g_dbus_message_get_sender (message);
4563   interface_name = g_dbus_message_get_interface (message);
4564   member = g_dbus_message_get_member (message);
4565   signature = g_dbus_message_get_signature (message);
4566   is_root = (g_strcmp0 (requested_object_path, es->object_path) == 0);
4567
4568   is_property_get = FALSE;
4569   is_property_set = FALSE;
4570   is_property_get_all = FALSE;
4571   if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0)
4572     {
4573       if (g_strcmp0 (member, "Get") == 0 && g_strcmp0 (signature, "ss") == 0)
4574         is_property_get = TRUE;
4575       else if (g_strcmp0 (member, "Set") == 0 && g_strcmp0 (signature, "ssv") == 0)
4576         is_property_set = TRUE;
4577       else if (g_strcmp0 (member, "GetAll") == 0 && g_strcmp0 (signature, "s") == 0)
4578         is_property_get_all = TRUE;
4579     }
4580
4581   children = es->vtable->enumerate (es->connection,
4582                                     sender,
4583                                     es->object_path,
4584                                     es->user_data);
4585
4586   if (!is_root)
4587     {
4588       requested_node = strrchr (requested_object_path, '/') + 1;
4589
4590       /* If not dynamic, skip if requested node is not part of children */
4591       if (!(es->flags & G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES) &&
4592           !_g_strv_has_string ((const gchar * const *) children, requested_node))
4593         goto out;
4594     }
4595   else
4596     {
4597       requested_node = "/";
4598     }
4599
4600   /* get introspection data for the node */
4601   interfaces = es->vtable->introspect (es->connection,
4602                                        sender,
4603                                        requested_object_path,
4604                                        requested_node,
4605                                        es->user_data);
4606   g_assert (interfaces != NULL);
4607   introspection_data = NULL;
4608   for (n = 0; n < interfaces->len; n++)
4609     {
4610       const GDBusInterfaceInfo *id_n = (const GDBusInterfaceInfo *) interfaces->pdata[n];
4611       if (g_strcmp0 (id_n->name, interface_name) == 0)
4612         introspection_data = id_n;
4613     }
4614
4615   /* dispatch the call if the user wants to handle it */
4616   if (introspection_data != NULL)
4617     {
4618       /* figure out where to dispatch the method call */
4619       interface_user_data = NULL;
4620       interface_vtable = es->vtable->dispatch (es->connection,
4621                                                sender,
4622                                                es->object_path,
4623                                                interface_name,
4624                                                requested_node,
4625                                                &interface_user_data,
4626                                                es->user_data);
4627       if (interface_vtable == NULL)
4628         goto out;
4629
4630       CONNECTION_LOCK (connection);
4631       handled = validate_and_maybe_schedule_method_call (es->connection,
4632                                                          message,
4633                                                          introspection_data,
4634                                                          interface_vtable,
4635                                                          es->context,
4636                                                          interface_user_data);
4637       CONNECTION_UNLOCK (connection);
4638     }
4639   /* handle org.freedesktop.DBus.Properties interface if not explicitly handled */
4640   else if (is_property_get || is_property_set || is_property_get_all)
4641     {
4642       if (is_property_get)
4643         g_variant_get (g_dbus_message_get_body (message), "(ss)", &interface_name, NULL);
4644       else if (is_property_set)
4645         g_variant_get (g_dbus_message_get_body (message), "(ssv)", &interface_name, NULL, NULL);
4646       else if (is_property_get_all)
4647         g_variant_get (g_dbus_message_get_body (message), "(s)", &interface_name, NULL, NULL);
4648       else
4649         g_assert_not_reached ();
4650
4651       /* see if the object supports this interface at all */
4652       for (n = 0; n < interfaces->len; n++)
4653         {
4654           const GDBusInterfaceInfo *id_n = (const GDBusInterfaceInfo *) interfaces->pdata[n];
4655           if (g_strcmp0 (id_n->name, interface_name) == 0)
4656             introspection_data = id_n;
4657         }
4658
4659       /* Fail with org.freedesktop.DBus.Error.InvalidArgs if the user-code
4660        * claims it won't support the interface
4661        */
4662       if (introspection_data == NULL)
4663         {
4664           GDBusMessage *reply;
4665           reply = g_dbus_message_new_method_error (message,
4666                                                    "org.freedesktop.DBus.Error.InvalidArgs",
4667                                                    _("No such interface `%s'"),
4668                                                    interface_name);
4669           g_dbus_connection_send_message (es->connection, reply, NULL, NULL);
4670           g_object_unref (reply);
4671           handled = TRUE;
4672           goto out;
4673         }
4674
4675       /* figure out where to dispatch the property get/set/getall calls */
4676       interface_user_data = NULL;
4677       interface_vtable = es->vtable->dispatch (es->connection,
4678                                                sender,
4679                                                es->object_path,
4680                                                interface_name,
4681                                                requested_node,
4682                                                &interface_user_data,
4683                                                es->user_data);
4684       if (interface_vtable == NULL)
4685         goto out;
4686
4687       if (is_property_get || is_property_set)
4688         {
4689           CONNECTION_LOCK (connection);
4690           handled = validate_and_maybe_schedule_property_getset (es->connection,
4691                                                                  message,
4692                                                                  is_property_get,
4693                                                                  introspection_data,
4694                                                                  interface_vtable,
4695                                                                  es->context,
4696                                                                  interface_user_data);
4697           CONNECTION_UNLOCK (connection);
4698         }
4699       else if (is_property_get_all)
4700         {
4701           CONNECTION_LOCK (connection);
4702           handled = validate_and_maybe_schedule_property_get_all (es->connection,
4703                                                                   message,
4704                                                                   introspection_data,
4705                                                                   interface_vtable,
4706                                                                   es->context,
4707                                                                   interface_user_data);
4708           CONNECTION_UNLOCK (connection);
4709         }
4710     }
4711
4712  out:
4713   if (interfaces != NULL)
4714     g_ptr_array_unref (interfaces);
4715   g_strfreev (children);
4716   return handled;
4717 }
4718
4719 typedef struct
4720 {
4721   GDBusMessage *message;
4722   ExportedSubtree *es;
4723 } SubtreeDeferredData;
4724
4725 static void
4726 subtree_deferred_data_free (SubtreeDeferredData *data)
4727 {
4728   g_object_unref (data->message);
4729   g_free (data);
4730 }
4731
4732 /* called without lock held in the thread where the caller registered the subtree */
4733 static gboolean
4734 process_subtree_vtable_message_in_idle_cb (gpointer _data)
4735 {
4736   SubtreeDeferredData *data = _data;
4737   gboolean handled;
4738
4739   handled = FALSE;
4740
4741   if (g_strcmp0 (g_dbus_message_get_interface (data->message), "org.freedesktop.DBus.Introspectable") == 0 &&
4742       g_strcmp0 (g_dbus_message_get_member (data->message), "Introspect") == 0 &&
4743       g_strcmp0 (g_dbus_message_get_signature (data->message), "") == 0)
4744     handled = handle_subtree_introspect (data->es->connection,
4745                                          data->es,
4746                                          data->message);
4747   else
4748     handled = handle_subtree_method_invocation (data->es->connection,
4749                                                 data->es,
4750                                                 data->message);
4751
4752   if (!handled)
4753     {
4754       CONNECTION_LOCK (data->es->connection);
4755       handled = handle_generic_unlocked (data->es->connection, data->message);
4756       CONNECTION_UNLOCK (data->es->connection);
4757     }
4758
4759   /* if we couldn't handle the request, just bail with the UnknownMethod error */
4760   if (!handled)
4761     {
4762       GDBusMessage *reply;
4763       reply = g_dbus_message_new_method_error (data->message,
4764                                                "org.freedesktop.DBus.Error.UnknownMethod",
4765                                                _("Method `%s' on interface `%s' with signature `%s' does not exist"),
4766                                                g_dbus_message_get_member (data->message),
4767                                                g_dbus_message_get_interface (data->message),
4768                                                g_dbus_message_get_signature (data->message));
4769       g_dbus_connection_send_message (data->es->connection, reply, NULL, NULL);
4770       g_object_unref (reply);
4771     }
4772
4773   return FALSE;
4774 }
4775
4776 /* called in message handler thread with lock held */
4777 static gboolean
4778 subtree_message_func (GDBusConnection *connection,
4779                       ExportedSubtree *es,
4780                       GDBusMessage    *message)
4781 {
4782   GSource *idle_source;
4783   SubtreeDeferredData *data;
4784
4785   data = g_new0 (SubtreeDeferredData, 1);
4786   data->message = g_object_ref (message);
4787   data->es = es;
4788
4789   /* defer this call to an idle handler in the right thread */
4790   idle_source = g_idle_source_new ();
4791   g_source_set_priority (idle_source, G_PRIORITY_HIGH);
4792   g_source_set_callback (idle_source,
4793                          process_subtree_vtable_message_in_idle_cb,
4794                          data,
4795                          (GDestroyNotify) subtree_deferred_data_free);
4796   g_source_attach (idle_source, es->context);
4797   g_source_unref (idle_source);
4798
4799   /* since we own the entire subtree, handlers for objects not in the subtree have been
4800    * tried already by libdbus-1 - so we just need to ensure that we're always going
4801    * to reply to the message
4802    */
4803   return TRUE;
4804 }
4805
4806 /**
4807  * g_dbus_connection_register_subtree:
4808  * @connection: A #GDBusConnection.
4809  * @object_path: The object path to register the subtree at.
4810  * @vtable: A #GDBusSubtreeVTable to enumerate, introspect and dispatch nodes in the subtree.
4811  * @flags: Flags used to fine tune the behavior of the subtree.
4812  * @user_data: Data to pass to functions in @vtable.
4813  * @user_data_free_func: Function to call when the subtree is unregistered.
4814  * @error: Return location for error or %NULL.
4815  *
4816  * Registers a whole subtree of <quote>dynamic</quote> objects.
4817  *
4818  * The @enumerate and @introspection functions in @vtable are used to
4819  * convey, to remote callers, what nodes exist in the subtree rooted
4820  * by @object_path.
4821  *
4822  * When handling remote calls into any node in the subtree, first the
4823  * @enumerate function is used to check if the node exists. If the node exists
4824  * or the #G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES flag is set
4825  * the @introspection function is used to check if the node supports the
4826  * requested method. If so, the @dispatch function is used to determine
4827  * where to dispatch the call. The collected #GDBusInterfaceVTable and
4828  * #gpointer will be used to call into the interface vtable for processing
4829  * the request.
4830  *
4831  * All calls into user-provided code will be invoked in the <link
4832  * linkend="g-main-context-push-thread-default">thread-default main
4833  * loop</link> of the thread you are calling this method from.
4834  *
4835  * If an existing subtree is already registered at @object_path or
4836  * then @error is set to #G_IO_ERROR_EXISTS.
4837  *
4838  * Note that it is valid to register regular objects (using
4839  * g_dbus_connection_register_object()) in a subtree registered with
4840  * g_dbus_connection_register_subtree() - if so, the subtree handler
4841  * is tried as the last resort. One way to think about a subtree
4842  * handler is to consider it a <quote>fallback handler</quote>
4843  * for object paths not registered via g_dbus_connection_register_object()
4844  * or other bindings.
4845  *
4846  * See <xref linkend="gdbus-subtree-server"/> for an example of how to use this method.
4847  *
4848  * Returns: 0 if @error is set, otherwise a subtree registration id (never 0)
4849  * that can be used with g_dbus_connection_unregister_subtree() .
4850  *
4851  * Since: 2.26
4852  */
4853 guint
4854 g_dbus_connection_register_subtree (GDBusConnection           *connection,
4855                                     const gchar               *object_path,
4856                                     const GDBusSubtreeVTable  *vtable,
4857                                     GDBusSubtreeFlags          flags,
4858                                     gpointer                   user_data,
4859                                     GDestroyNotify             user_data_free_func,
4860                                     GError                   **error)
4861 {
4862   guint ret;
4863   ExportedSubtree *es;
4864
4865   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
4866   g_return_val_if_fail (object_path != NULL && g_variant_is_object_path (object_path), 0);
4867   g_return_val_if_fail (vtable != NULL, 0);
4868   g_return_val_if_fail (error == NULL || *error == NULL, 0);
4869
4870   ret = 0;
4871
4872   CONNECTION_LOCK (connection);
4873
4874   es = g_hash_table_lookup (connection->priv->map_object_path_to_es, object_path);
4875   if (es != NULL)
4876     {
4877       g_set_error (error,
4878                    G_IO_ERROR,
4879                    G_IO_ERROR_EXISTS,
4880                    _("A subtree is already exported for %s"),
4881                    object_path);
4882       goto out;
4883     }
4884
4885   es = g_new0 (ExportedSubtree, 1);
4886   es->object_path = g_strdup (object_path);
4887   es->connection = connection;
4888
4889   es->vtable = vtable;
4890   es->flags = flags;
4891   es->id = _global_subtree_registration_id++; /* TODO: overflow etc. */
4892   es->user_data = user_data;
4893   es->user_data_free_func = user_data_free_func;
4894   es->context = g_main_context_get_thread_default ();
4895   if (es->context != NULL)
4896     g_main_context_ref (es->context);
4897
4898   g_hash_table_insert (connection->priv->map_object_path_to_es, es->object_path, es);
4899   g_hash_table_insert (connection->priv->map_id_to_es,
4900                        GUINT_TO_POINTER (es->id),
4901                        es);
4902
4903   ret = es->id;
4904
4905  out:
4906   CONNECTION_UNLOCK (connection);
4907
4908   return ret;
4909 }
4910
4911 /* ---------------------------------------------------------------------------------------------------- */
4912
4913 /**
4914  * g_dbus_connection_unregister_subtree:
4915  * @connection: A #GDBusConnection.
4916  * @registration_id: A subtree registration id obtained from g_dbus_connection_register_subtree().
4917  *
4918  * Unregisters a subtree.
4919  *
4920  * Returns: %TRUE if the subtree was unregistered, %FALSE otherwise.
4921  *
4922  * Since: 2.26
4923  */
4924 gboolean
4925 g_dbus_connection_unregister_subtree (GDBusConnection *connection,
4926                                       guint            registration_id)
4927 {
4928   ExportedSubtree *es;
4929   gboolean ret;
4930
4931   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
4932
4933   ret = FALSE;
4934
4935   CONNECTION_LOCK (connection);
4936
4937   es = g_hash_table_lookup (connection->priv->map_id_to_es,
4938                             GUINT_TO_POINTER (registration_id));
4939   if (es == NULL)
4940     goto out;
4941
4942   g_warn_if_fail (g_hash_table_remove (connection->priv->map_id_to_es, GUINT_TO_POINTER (es->id)));
4943   g_warn_if_fail (g_hash_table_remove (connection->priv->map_object_path_to_es, es->object_path));
4944
4945   ret = TRUE;
4946
4947  out:
4948   CONNECTION_UNLOCK (connection);
4949
4950   return ret;
4951 }
4952
4953 /* ---------------------------------------------------------------------------------------------------- */
4954
4955 /* must be called with lock held */
4956 static void
4957 handle_generic_ping_unlocked (GDBusConnection *connection,
4958                               const gchar     *object_path,
4959                               GDBusMessage    *message)
4960 {
4961   GDBusMessage *reply;
4962   reply = g_dbus_message_new_method_reply (message);
4963   g_dbus_connection_send_message_unlocked (connection, reply, NULL, NULL);
4964   g_object_unref (reply);
4965 }
4966
4967 /* must be called with lock held */
4968 static void
4969 handle_generic_get_machine_id_unlocked (GDBusConnection *connection,
4970                                         const gchar     *object_path,
4971                                         GDBusMessage    *message)
4972 {
4973   GDBusMessage *reply;
4974
4975   reply = NULL;
4976   if (connection->priv->machine_id == NULL)
4977     {
4978       GError *error;
4979       error = NULL;
4980       /* TODO: use PACKAGE_LOCALSTATEDIR ? */
4981       if (!g_file_get_contents ("/var/lib/dbus/machine-id",
4982                                 &connection->priv->machine_id,
4983                                 NULL,
4984                                 &error))
4985         {
4986           reply = g_dbus_message_new_method_error (message,
4987                                                    "org.freedesktop.DBus.Error.Failed",
4988                                                    _("Unable to load /var/lib/dbus/machine-id: %s"),
4989                                                    error->message);
4990           g_error_free (error);
4991         }
4992       else
4993         {
4994           g_strstrip (connection->priv->machine_id);
4995           /* TODO: validate value */
4996         }
4997     }
4998
4999   if (reply == NULL)
5000     {
5001       reply = g_dbus_message_new_method_reply (message);
5002       g_dbus_message_set_body (reply, g_variant_new ("(s)", connection->priv->machine_id));
5003     }
5004   g_dbus_connection_send_message_unlocked (connection, reply, NULL, NULL);
5005   g_object_unref (reply);
5006 }
5007
5008 /* must be called with lock held */
5009 static void
5010 handle_generic_introspect_unlocked (GDBusConnection *connection,
5011                                     const gchar     *object_path,
5012                                     GDBusMessage    *message)
5013 {
5014   guint n;
5015   GString *s;
5016   gchar **registered;
5017   GDBusMessage *reply;
5018
5019   /* first the header */
5020   s = g_string_new (NULL);
5021   introspect_append_header (s);
5022
5023   registered = g_dbus_connection_list_registered_unlocked (connection, object_path);
5024   for (n = 0; registered != NULL && registered[n] != NULL; n++)
5025       g_string_append_printf (s, "  <node name=\"%s\"/>\n", registered[n]);
5026   g_strfreev (registered);
5027   g_string_append (s, "</node>\n");
5028
5029   reply = g_dbus_message_new_method_reply (message);
5030   g_dbus_message_set_body (reply, g_variant_new ("(s)", s->str));
5031   g_dbus_connection_send_message_unlocked (connection, reply, NULL, NULL);
5032   g_object_unref (reply);
5033   g_string_free (s, TRUE);
5034 }
5035
5036 /* must be called with lock held */
5037 static gboolean
5038 handle_generic_unlocked (GDBusConnection *connection,
5039                          GDBusMessage    *message)
5040 {
5041   gboolean handled;
5042   const gchar *interface_name;
5043   const gchar *member;
5044   const gchar *signature;
5045   const gchar *path;
5046
5047   CONNECTION_ENSURE_LOCK (connection);
5048
5049   handled = FALSE;
5050
5051   interface_name = g_dbus_message_get_interface (message);
5052   member = g_dbus_message_get_member (message);
5053   signature = g_dbus_message_get_signature (message);
5054   path = g_dbus_message_get_path (message);
5055
5056   if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Introspectable") == 0 &&
5057       g_strcmp0 (member, "Introspect") == 0 &&
5058       g_strcmp0 (signature, "") == 0)
5059     {
5060       handle_generic_introspect_unlocked (connection, path, message);
5061       handled = TRUE;
5062     }
5063   else if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Peer") == 0 &&
5064            g_strcmp0 (member, "Ping") == 0 &&
5065            g_strcmp0 (signature, "") == 0)
5066     {
5067       handle_generic_ping_unlocked (connection, path, message);
5068       handled = TRUE;
5069     }
5070   else if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Peer") == 0 &&
5071            g_strcmp0 (member, "GetMachineId") == 0 &&
5072            g_strcmp0 (signature, "") == 0)
5073     {
5074       handle_generic_get_machine_id_unlocked (connection, path, message);
5075       handled = TRUE;
5076     }
5077
5078   return handled;
5079 }
5080
5081 /* ---------------------------------------------------------------------------------------------------- */
5082
5083 /* called in message handler thread with lock held */
5084 static void
5085 distribute_method_call (GDBusConnection *connection,
5086                         GDBusMessage    *message)
5087 {
5088   ExportedObject *eo;
5089   ExportedSubtree *es;
5090   const gchar *object_path;
5091   const gchar *interface_name;
5092   const gchar *member;
5093   const gchar *signature;
5094   const gchar *path;
5095   gchar *subtree_path;
5096   gchar *needle;
5097
5098   g_assert (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL);
5099
5100   interface_name = g_dbus_message_get_interface (message);
5101   member = g_dbus_message_get_member (message);
5102   signature = g_dbus_message_get_signature (message);
5103   path = g_dbus_message_get_path (message);
5104   subtree_path = g_strdup (path);
5105   needle = strrchr (subtree_path, '/');
5106   if (needle != NULL && needle != subtree_path)
5107     {
5108       *needle = '\0';
5109     }
5110   else
5111     {
5112       g_free (subtree_path);
5113       subtree_path = NULL;
5114     }
5115
5116 #if 0
5117   g_debug ("interface    = `%s'", interface_name);
5118   g_debug ("member       = `%s'", member);
5119   g_debug ("signature    = `%s'", signature);
5120   g_debug ("path         = `%s'", path);
5121   g_debug ("subtree_path = `%s'", subtree_path != NULL ? subtree_path : "N/A");
5122 #endif
5123
5124   object_path = g_dbus_message_get_path (message);
5125   g_assert (object_path != NULL);
5126
5127   eo = g_hash_table_lookup (connection->priv->map_object_path_to_eo, object_path);
5128   if (eo != NULL)
5129     {
5130       if (obj_message_func (connection, eo, message))
5131         goto out;
5132     }
5133
5134   es = g_hash_table_lookup (connection->priv->map_object_path_to_es, object_path);
5135   if (es != NULL)
5136     {
5137       if (subtree_message_func (connection, es, message))
5138         goto out;
5139     }
5140
5141   if (subtree_path != NULL)
5142     {
5143       es = g_hash_table_lookup (connection->priv->map_object_path_to_es, subtree_path);
5144       if (es != NULL)
5145         {
5146           if (subtree_message_func (connection, es, message))
5147             goto out;
5148         }
5149     }
5150
5151   if (handle_generic_unlocked (connection, message))
5152     goto out;
5153
5154   /* if we end up here, the message has not been not handled */
5155
5156  out:
5157   g_free (subtree_path);
5158 }
5159
5160 /* ---------------------------------------------------------------------------------------------------- */
5161
5162 static GDBusConnection **
5163 message_bus_get_singleton (GBusType   bus_type,
5164                            GError   **error)
5165 {
5166   GDBusConnection **ret;
5167   const gchar *starter_bus;
5168
5169   ret = NULL;
5170
5171   switch (bus_type)
5172     {
5173     case G_BUS_TYPE_SESSION:
5174       ret = &the_session_bus;
5175       break;
5176
5177     case G_BUS_TYPE_SYSTEM:
5178       ret = &the_system_bus;
5179       break;
5180
5181     case G_BUS_TYPE_STARTER:
5182       starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
5183       if (g_strcmp0 (starter_bus, "session") == 0)
5184         {
5185           ret = message_bus_get_singleton (G_BUS_TYPE_SESSION, error);
5186           goto out;
5187         }
5188       else if (g_strcmp0 (starter_bus, "system") == 0)
5189         {
5190           ret = message_bus_get_singleton (G_BUS_TYPE_SYSTEM, error);
5191           goto out;
5192         }
5193       else
5194         {
5195           if (starter_bus != NULL)
5196             {
5197               g_set_error (error,
5198                            G_IO_ERROR,
5199                            G_IO_ERROR_INVALID_ARGUMENT,
5200                            _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
5201                              " - unknown value `%s'"),
5202                            starter_bus);
5203             }
5204           else
5205             {
5206               g_set_error_literal (error,
5207                                    G_IO_ERROR,
5208                                    G_IO_ERROR_INVALID_ARGUMENT,
5209                                    _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
5210                                      "variable is not set"));
5211             }
5212         }
5213       break;
5214
5215     default:
5216       g_assert_not_reached ();
5217       break;
5218     }
5219
5220  out:
5221   return ret;
5222 }
5223
5224 static GDBusConnection *
5225 get_uninitialized_connection (GBusType       bus_type,
5226                               GCancellable  *cancellable,
5227                               GError       **error)
5228 {
5229   GDBusConnection **singleton;
5230   GDBusConnection *ret;
5231
5232   ret = NULL;
5233
5234   G_LOCK (message_bus_lock);
5235   singleton = message_bus_get_singleton (bus_type, error);
5236   if (singleton == NULL)
5237     goto out;
5238
5239   if (*singleton == NULL)
5240     {
5241       gchar *address;
5242       address = g_dbus_address_get_for_bus_sync (bus_type, cancellable, error);
5243       if (address == NULL)
5244         goto out;
5245       ret = *singleton = g_object_new (G_TYPE_DBUS_CONNECTION,
5246                                        "address", address,
5247                                        "flags", G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
5248                                                 G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
5249                                        "exit-on-close", TRUE,
5250                                        NULL);
5251     }
5252   else
5253     {
5254       ret = g_object_ref (*singleton);
5255     }
5256
5257   g_assert (ret != NULL);
5258
5259  out:
5260   G_UNLOCK (message_bus_lock);
5261   return ret;
5262 }
5263
5264 /**
5265  * g_bus_get_sync:
5266  * @bus_type: A #GBusType.
5267  * @cancellable: A #GCancellable or %NULL.
5268  * @error: Return location for error or %NULL.
5269  *
5270  * Synchronously connects to the message bus specified by @bus_type.
5271  * Note that the returned object may shared with other callers,
5272  * e.g. if two separate parts of a process calls this function with
5273  * the same @bus_type, they will share the same object.
5274  *
5275  * This is a synchronous failable function. See g_bus_get() and
5276  * g_bus_get_finish() for the asynchronous version.
5277  *
5278  * The returned object is a singleton, that is, shared with other
5279  * callers of g_bus_get() and g_bus_get_sync() for @bus_type. In the
5280  * event that you need a private message bus connection, use
5281  * g_dbus_address_get_for_bus_sync() and
5282  * g_dbus_connection_new_for_address().
5283  *
5284  * Note that the returned #GDBusConnection object will (usually) have
5285  * the #GDBusConnection:exit-on-close property set to %TRUE.
5286  *
5287  * Returns: A #GDBusConnection or %NULL if @error is set. Free with g_object_unref().
5288  *
5289  * Since: 2.26
5290  */
5291 GDBusConnection *
5292 g_bus_get_sync (GBusType       bus_type,
5293                 GCancellable  *cancellable,
5294                 GError       **error)
5295 {
5296   GDBusConnection *connection;
5297
5298   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
5299
5300   connection = get_uninitialized_connection (bus_type, cancellable, error);
5301   if (connection == NULL)
5302     goto out;
5303
5304   if (!g_initable_init (G_INITABLE (connection), cancellable, error))
5305     {
5306       g_object_unref (connection);
5307       connection = NULL;
5308     }
5309
5310  out:
5311   return connection;
5312 }
5313
5314 static void
5315 bus_get_async_initable_cb (GObject      *source_object,
5316                            GAsyncResult *res,
5317                            gpointer      user_data)
5318 {
5319   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
5320   GError *error;
5321
5322   error = NULL;
5323   if (!g_async_initable_init_finish (G_ASYNC_INITABLE (source_object),
5324                                      res,
5325                                      &error))
5326     {
5327       g_assert (error != NULL);
5328       g_simple_async_result_set_from_error (simple, error);
5329       g_error_free (error);
5330       g_object_unref (source_object);
5331     }
5332   else
5333     {
5334       g_simple_async_result_set_op_res_gpointer (simple,
5335                                                  source_object,
5336                                                  g_object_unref);
5337     }
5338   g_simple_async_result_complete_in_idle (simple);
5339   g_object_unref (simple);
5340 }
5341
5342 /**
5343  * g_bus_get:
5344  * @bus_type: A #GBusType.
5345  * @cancellable: A #GCancellable or %NULL.
5346  * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
5347  * @user_data: The data to pass to @callback.
5348  *
5349  * Asynchronously connects to the message bus specified by @bus_type.
5350  *
5351  * When the operation is finished, @callback will be invoked. You can
5352  * then call g_bus_get_finish() to get the result of the operation.
5353  *
5354  * This is a asynchronous failable function. See g_bus_get_sync() for
5355  * the synchronous version.
5356  *
5357  * Since: 2.26
5358  */
5359 void
5360 g_bus_get (GBusType             bus_type,
5361            GCancellable        *cancellable,
5362            GAsyncReadyCallback  callback,
5363            gpointer             user_data)
5364 {
5365   GDBusConnection *connection;
5366   GSimpleAsyncResult *simple;
5367   GError *error;
5368
5369   simple = g_simple_async_result_new (NULL,
5370                                       callback,
5371                                       user_data,
5372                                       g_bus_get);
5373
5374   error = NULL;
5375   connection = get_uninitialized_connection (bus_type, cancellable, &error);
5376   if (connection == NULL)
5377     {
5378       g_assert (error != NULL);
5379       g_simple_async_result_set_from_error (simple, error);
5380       g_error_free (error);
5381       g_simple_async_result_complete_in_idle (simple);
5382       g_object_unref (simple);
5383     }
5384   else
5385     {
5386       g_async_initable_init_async (G_ASYNC_INITABLE (connection),
5387                                    G_PRIORITY_DEFAULT,
5388                                    cancellable,
5389                                    bus_get_async_initable_cb,
5390                                    simple);
5391     }
5392 }
5393
5394 /**
5395  * g_bus_get_finish:
5396  * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_bus_get().
5397  * @error: Return location for error or %NULL.
5398  *
5399  * Finishes an operation started with g_bus_get().
5400  *
5401  * The returned object is a singleton, that is, shared with other
5402  * callers of g_bus_get() and g_bus_get_sync() for @bus_type. In the
5403  * event that you need a private message bus connection, use
5404  * g_dbus_address_get_for_bus() and
5405  * g_dbus_connection_new_for_address().
5406  *
5407  * Note that the returned #GDBusConnection object will (usually) have
5408  * the #GDBusConnection:exit-on-close property set to %TRUE.
5409  *
5410  * Returns: A #GDBusConnection or %NULL if @error is set. Free with g_object_unref().
5411  *
5412  * Since: 2.26
5413  */
5414 GDBusConnection *
5415 g_bus_get_finish (GAsyncResult  *res,
5416                   GError       **error)
5417 {
5418   GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
5419   GObject *object;
5420   GDBusConnection *ret;
5421
5422   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
5423
5424   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_bus_get);
5425
5426   ret = NULL;
5427
5428   if (g_simple_async_result_propagate_error (simple, error))
5429     goto out;
5430
5431   object = g_simple_async_result_get_op_res_gpointer (simple);
5432   g_assert (object != NULL);
5433   ret = g_object_ref (G_DBUS_CONNECTION (object));
5434
5435  out:
5436   return ret;
5437 }
5438
5439 /* ---------------------------------------------------------------------------------------------------- */
5440
5441 #define __G_DBUS_CONNECTION_C__
5442 #include "gioaliasdef.c"