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