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