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