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