• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GDBus - GLib D-Bus Library
2  *
3  * Copyright (C) 2008-2010 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 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, see <http://www.gnu.org/licenses/>.
17  *
18  * Author: David Zeuthen <davidz@redhat.com>
19  */
20 
21 /*
22  * TODO for GDBus:
23  *
24  * - would be nice to expose GDBusAuthMechanism and an extension point
25  *
26  * - Need to rewrite GDBusAuth and rework GDBusAuthMechanism. In particular
27  *   the mechanism VFuncs need to be able to set an error.
28  *
29  * - Need to document other mechanisms/sources for determining the D-Bus
30  *   address of a well-known bus.
31  *
32  *   - e.g. on Win32 we need code like from here
33  *
34  *     http://cgit.freedesktop.org/~david/gdbus-standalone/tree/gdbus/gdbusaddress.c#n900
35  *
36  *     that was never copied over here because it originally was copy-paste
37  *     from the GPLv2 / AFL 2.1 libdbus sources.
38  *
39  *   - on OS X we need to look in launchd for the address
40  *
41  *     https://bugs.freedesktop.org/show_bug.cgi?id=14259
42  *
43  *   - on X11 we need to look in a X11 property on the X server
44  *     - (we can also just use dbus-launch(1) from the D-Bus
45  *        distribution)
46  *
47  *   - (ideally) this requires D-Bus spec work because none of
48  *     this has never really been specced out properly (except
49  *     the X11 bits)
50  *
51  * - Related to the above, we also need to be able to launch a message bus
52  *   instance.... Since we don't want to write our own bus daemon we should
53  *   launch dbus-daemon(1) (thus: Win32 and OS X need to bundle it)
54  *
55  * - probably want a G_DBUS_NONCE_TCP_TMPDIR environment variable
56  *   to specify where the nonce is stored. This will allow people to use
57  *   G_DBUS_NONCE_TCP_TMPDIR=/mnt/secure.company.server/dbus-nonce-dir
58  *   to easily achieve secure RPC via nonce-tcp.
59  *
60  * - need to expose an extension point for resolving D-Bus address and
61  *   turning them into GIOStream objects. This will allow us to implement
62  *   e.g. X11 D-Bus transports without dlopen()'ing or linking against
63  *   libX11 from libgio.
64  *   - see g_dbus_address_connect() in gdbusaddress.c
65  *
66  * - would be cute to use kernel-specific APIs to resolve fds for
67  *   debug output when using G_DBUS_DEBUG=message, e.g. in addition to
68  *
69  *     fd 21: dev=8:1,mode=0100644,ino=1171231,uid=0,gid=0,rdev=0:0,size=234,atime=1273070640,mtime=1267126160,ctime=1267126160
70  *
71  *   maybe we can show more information about what fd 21 really is.
72  *   Ryan suggests looking in /proc/self/fd for clues / symlinks!
73  *   Initial experiments on Linux 2.6 suggests that the symlink looks
74  *   like this:
75  *
76  *    3 -> /proc/18068/fd
77  *
78  *   e.g. not of much use.
79  *
80  *  - GDBus High-Level docs
81  *    - Proxy: properties, signals...
82  *    - Connection: IOStream based, ::close, connection setup steps
83  *                  mainloop integration, threading
84  *    - Differences from libdbus (extend "Migrating from")
85  *      - the message handling thread
86  *      - Using GVariant instead of GValue
87  *    - Explain why the high-level API is a good thing and what
88  *      kind of pitfalls it avoids
89  *      - Export objects before claiming names
90  *    - Talk about auto-starting services (cf. GBusNameWatcherFlags)
91  */
92 
93 #include "config.h"
94 
95 #include <stdlib.h>
96 #include <string.h>
97 
98 #include "gdbusauth.h"
99 #include "gdbusutils.h"
100 #include "gdbusaddress.h"
101 #include "gdbusmessage.h"
102 #include "gdbusconnection.h"
103 #include "gdbuserror.h"
104 #include "gioenumtypes.h"
105 #include "gdbusintrospection.h"
106 #include "gdbusmethodinvocation.h"
107 #include "gdbusprivate.h"
108 #include "gdbusauthobserver.h"
109 #include "ginitable.h"
110 #include "gasyncinitable.h"
111 #include "giostream.h"
112 #include "gasyncresult.h"
113 #include "gtask.h"
114 #include "gmarshal-internal.h"
115 
116 #ifdef G_OS_UNIX
117 #include "gunixconnection.h"
118 #include "gunixfdmessage.h"
119 #endif
120 
121 #include "glibintl.h"
122 
123 #define G_DBUS_CONNECTION_FLAGS_ALL \
124   (G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | \
125    G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER | \
126    G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS | \
127    G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION | \
128    G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING | \
129    G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER)
130 
131 /**
132  * SECTION:gdbusconnection
133  * @short_description: D-Bus Connections
134  * @include: gio/gio.h
135  *
136  * The #GDBusConnection type is used for D-Bus connections to remote
137  * peers such as a message buses. It is a low-level API that offers a
138  * lot of flexibility. For instance, it lets you establish a connection
139  * over any transport that can by represented as a #GIOStream.
140  *
141  * This class is rarely used directly in D-Bus clients. If you are writing
142  * a D-Bus client, it is often easier to use the g_bus_own_name(),
143  * g_bus_watch_name() or g_dbus_proxy_new_for_bus() APIs.
144  *
145  * As an exception to the usual GLib rule that a particular object must not
146  * be used by two threads at the same time, #GDBusConnection's methods may be
147  * called from any thread. This is so that g_bus_get() and g_bus_get_sync()
148  * can safely return the same #GDBusConnection when called from any thread.
149  *
150  * Most of the ways to obtain a #GDBusConnection automatically initialize it
151  * (i.e. connect to D-Bus): for instance, g_dbus_connection_new() and
152  * g_bus_get(), and the synchronous versions of those methods, give you an
153  * initialized connection. Language bindings for GIO should use
154  * g_initable_new() or g_async_initable_new_async(), which also initialize the
155  * connection.
156  *
157  * If you construct an uninitialized #GDBusConnection, such as via
158  * g_object_new(), you must initialize it via g_initable_init() or
159  * g_async_initable_init_async() before using its methods or properties.
160  * Calling methods or accessing properties on a #GDBusConnection that has not
161  * completed initialization successfully is considered to be invalid, and leads
162  * to undefined behaviour. In particular, if initialization fails with a
163  * #GError, the only valid thing you can do with that #GDBusConnection is to
164  * free it with g_object_unref().
165  *
166  * ## An example D-Bus server # {#gdbus-server}
167  *
168  * Here is an example for a D-Bus server:
169  * [gdbus-example-server.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-server.c)
170  *
171  * ## An example for exporting a subtree # {#gdbus-subtree-server}
172  *
173  * Here is an example for exporting a subtree:
174  * [gdbus-example-subtree.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-subtree.c)
175  *
176  * ## An example for file descriptor passing # {#gdbus-unix-fd-client}
177  *
178  * Here is an example for passing UNIX file descriptors:
179  * [gdbus-unix-fd-client.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-unix-fd-client.c)
180  *
181  * ## An example for exporting a GObject # {#gdbus-export}
182  *
183  * Here is an example for exporting a #GObject:
184  * [gdbus-example-export.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-export.c)
185  */
186 
187 /* ---------------------------------------------------------------------------------------------------- */
188 
189 typedef struct _GDBusConnectionClass GDBusConnectionClass;
190 
191 /**
192  * GDBusConnectionClass:
193  * @closed: Signal class handler for the #GDBusConnection::closed signal.
194  *
195  * Class structure for #GDBusConnection.
196  *
197  * Since: 2.26
198  */
199 struct _GDBusConnectionClass
200 {
201   /*< private >*/
202   GObjectClass parent_class;
203 
204   /*< public >*/
205   /* Signals */
206   void (*closed) (GDBusConnection *connection,
207                   gboolean         remote_peer_vanished,
208                   GError          *error);
209 };
210 
211 G_LOCK_DEFINE_STATIC (message_bus_lock);
212 
213 static GWeakRef the_session_bus;
214 static GWeakRef the_system_bus;
215 
216 /* Extra pseudo-member of GDBusSendMessageFlags.
217  * Set by initable_init() to indicate that despite not being initialized yet,
218  * enough of the only-valid-after-init members are set that we can send a
219  * message, and we're being called from its thread, so no memory barrier is
220  * required before accessing them.
221  */
222 #define SEND_MESSAGE_FLAGS_INITIALIZING (1u << 31)
223 
224 /* Same as SEND_MESSAGE_FLAGS_INITIALIZING, but in GDBusCallFlags */
225 #define CALL_FLAGS_INITIALIZING (1u << 31)
226 
227 /* ---------------------------------------------------------------------------------------------------- */
228 
229 typedef struct
230 {
231   GDestroyNotify              callback;
232   gpointer                    user_data;
233 } CallDestroyNotifyData;
234 
235 static gboolean
call_destroy_notify_data_in_idle(gpointer user_data)236 call_destroy_notify_data_in_idle (gpointer user_data)
237 {
238   CallDestroyNotifyData *data = user_data;
239   data->callback (data->user_data);
240   return FALSE;
241 }
242 
243 static void
call_destroy_notify_data_free(CallDestroyNotifyData * data)244 call_destroy_notify_data_free (CallDestroyNotifyData *data)
245 {
246   g_free (data);
247 }
248 
249 /*
250  * call_destroy_notify: <internal>
251  * @context: (nullable): A #GMainContext or %NULL.
252  * @callback: (nullable): A #GDestroyNotify or %NULL.
253  * @user_data: Data to pass to @callback.
254  *
255  * Schedules @callback to run in @context.
256  */
257 static void
call_destroy_notify(GMainContext * context,GDestroyNotify callback,gpointer user_data)258 call_destroy_notify (GMainContext  *context,
259                      GDestroyNotify callback,
260                      gpointer       user_data)
261 {
262   GSource *idle_source;
263   CallDestroyNotifyData *data;
264 
265   if (callback == NULL)
266     return;
267 
268   data = g_new0 (CallDestroyNotifyData, 1);
269   data->callback = callback;
270   data->user_data = user_data;
271 
272   idle_source = g_idle_source_new ();
273   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
274   g_source_set_callback (idle_source,
275                          call_destroy_notify_data_in_idle,
276                          data,
277                          (GDestroyNotify) call_destroy_notify_data_free);
278   g_source_set_name (idle_source, "[gio] call_destroy_notify_data_in_idle");
279   g_source_attach (idle_source, context);
280   g_source_unref (idle_source);
281 }
282 
283 /* ---------------------------------------------------------------------------------------------------- */
284 
285 static gboolean
_g_strv_has_string(const gchar * const * haystack,const gchar * needle)286 _g_strv_has_string (const gchar* const *haystack,
287                     const gchar        *needle)
288 {
289   guint n;
290 
291   for (n = 0; haystack != NULL && haystack[n] != NULL; n++)
292     {
293       if (g_strcmp0 (haystack[n], needle) == 0)
294         return TRUE;
295     }
296   return FALSE;
297 }
298 
299 /* ---------------------------------------------------------------------------------------------------- */
300 
301 #ifdef G_OS_WIN32
302 #define CONNECTION_ENSURE_LOCK(obj) do { ; } while (FALSE)
303 #else
304 // TODO: for some reason this doesn't work on Windows
305 #define CONNECTION_ENSURE_LOCK(obj) do {                                \
306     if (G_UNLIKELY (g_mutex_trylock(&(obj)->lock)))                     \
307       {                                                                 \
308         g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
309                              "CONNECTION_ENSURE_LOCK: GDBusConnection object lock is not locked"); \
310       }                                                                 \
311   } while (FALSE)
312 #endif
313 
314 #define CONNECTION_LOCK(obj) do {                                       \
315     g_mutex_lock (&(obj)->lock);                                        \
316   } while (FALSE)
317 
318 #define CONNECTION_UNLOCK(obj) do {                                     \
319     g_mutex_unlock (&(obj)->lock);                                      \
320   } while (FALSE)
321 
322 /* Flags in connection->atomic_flags */
323 enum {
324     FLAG_INITIALIZED = 1 << 0,
325     FLAG_EXIT_ON_CLOSE = 1 << 1,
326     FLAG_CLOSED = 1 << 2
327 };
328 
329 /**
330  * GDBusConnection:
331  *
332  * The #GDBusConnection structure contains only private data and
333  * should only be accessed using the provided API.
334  *
335  * Since: 2.26
336  */
337 struct _GDBusConnection
338 {
339   /*< private >*/
340   GObject parent_instance;
341 
342   /* ------------------------------------------------------------------------ */
343   /* -- General object state ------------------------------------------------ */
344   /* ------------------------------------------------------------------------ */
345 
346   /* General-purpose lock for most fields */
347   GMutex lock;
348 
349   /* A lock used in the init() method of the GInitable interface - see comments
350    * in initable_init() for why a separate lock is needed.
351    *
352    * If you need both @lock and @init_lock, you must take @init_lock first.
353    */
354   GMutex init_lock;
355 
356   /* Set (by loading the contents of /var/lib/dbus/machine-id) the first time
357    * someone calls org.freedesktop.DBus.Peer.GetMachineId(). Protected by @lock.
358    */
359   gchar *machine_id;
360 
361   /* The underlying stream used for communication
362    * Read-only after initable_init(), so it may be read if you either
363    * hold @init_lock or check for initialization first.
364    */
365   GIOStream *stream;
366 
367   /* The object used for authentication (if any).
368    * Read-only after initable_init(), so it may be read if you either
369    * hold @init_lock or check for initialization first.
370    */
371   GDBusAuth *auth;
372 
373   /* Last serial used. Protected by @lock. */
374   guint32 last_serial;
375 
376   /* The object used to send/receive messages.
377    * Read-only after initable_init(), so it may be read if you either
378    * hold @init_lock or check for initialization first.
379    */
380   GDBusWorker *worker;
381 
382   /* If connected to a message bus, this contains the unique name assigned to
383    * us by the bus (e.g. ":1.42").
384    * Read-only after initable_init(), so it may be read if you either
385    * hold @init_lock or check for initialization first.
386    */
387   gchar *bus_unique_name;
388 
389   /* The GUID returned by the other side if we authenticed as a client or
390    * the GUID to use if authenticating as a server.
391    * Read-only after initable_init(), so it may be read if you either
392    * hold @init_lock or check for initialization first.
393    */
394   gchar *guid;
395 
396   /* FLAG_INITIALIZED is set exactly when initable_init() has finished running.
397    * Inspect @initialization_error to see whether it succeeded or failed.
398    *
399    * FLAG_EXIT_ON_CLOSE is the exit-on-close property.
400    *
401    * FLAG_CLOSED is the closed property. It may be read at any time, but
402    * may only be written while holding @lock.
403    */
404   gint atomic_flags;  /* (atomic) */
405 
406   /* If the connection could not be established during initable_init(),
407    * this GError will be set.
408    * Read-only after initable_init(), so it may be read if you either
409    * hold @init_lock or check for initialization first.
410    */
411   GError *initialization_error;
412 
413   /* The result of g_main_context_ref_thread_default() when the object
414    * was created (the GObject _init() function) - this is used for delivery
415    * of the :closed GObject signal.
416    *
417    * Only set in the GObject init function, so no locks are needed.
418    */
419   GMainContext *main_context_at_construction;
420 
421   /* Read-only construct properties, no locks needed */
422   gchar *address;
423   GDBusConnectionFlags flags;
424 
425   /* Map used for managing method replies, protected by @lock */
426   GHashTable *map_method_serial_to_task;  /* guint32 -> GTask* */
427 
428   /* Maps used for managing signal subscription, protected by @lock */
429   GHashTable *map_rule_to_signal_data;                      /* match rule (gchar*)    -> SignalData */
430   GHashTable *map_id_to_signal_data;                        /* id (guint)             -> SignalData */
431   GHashTable *map_sender_unique_name_to_signal_data_array;  /* unique sender (gchar*) -> GPtrArray* of SignalData */
432 
433   /* Maps used for managing exported objects and subtrees,
434    * protected by @lock
435    */
436   GHashTable *map_object_path_to_eo;  /* gchar* -> ExportedObject* */
437   GHashTable *map_id_to_ei;           /* guint  -> ExportedInterface* */
438   GHashTable *map_object_path_to_es;  /* gchar* -> ExportedSubtree* */
439   GHashTable *map_id_to_es;           /* guint  -> ExportedSubtree* */
440 
441   /* Map used for storing last used serials for each thread, protected by @lock */
442   GHashTable *map_thread_to_last_serial;
443 
444   /* Structure used for message filters, protected by @lock */
445   GPtrArray *filters;
446 
447   /* Capabilities negotiated during authentication
448    * Read-only after initable_init(), so it may be read without holding a
449    * lock, if you check for initialization first.
450    */
451   GDBusCapabilityFlags capabilities;
452 
453   /* Protected by @init_lock */
454   GDBusAuthObserver *authentication_observer;
455 
456   /* Read-only after initable_init(), so it may be read if you either
457    * hold @init_lock or check for initialization first.
458    */
459   GCredentials *credentials;
460 
461   /* set to TRUE when finalizing */
462   gboolean finalizing;
463 };
464 
465 typedef struct ExportedObject ExportedObject;
466 static void exported_object_free (ExportedObject *eo);
467 
468 typedef struct ExportedSubtree ExportedSubtree;
469 static void exported_subtree_free (ExportedSubtree *es);
470 
471 enum
472 {
473   CLOSED_SIGNAL,
474   LAST_SIGNAL,
475 };
476 
477 enum
478 {
479   PROP_0,
480   PROP_STREAM,
481   PROP_ADDRESS,
482   PROP_FLAGS,
483   PROP_GUID,
484   PROP_UNIQUE_NAME,
485   PROP_CLOSED,
486   PROP_EXIT_ON_CLOSE,
487   PROP_CAPABILITY_FLAGS,
488   PROP_AUTHENTICATION_OBSERVER,
489 };
490 
491 static void distribute_signals (GDBusConnection  *connection,
492                                 GDBusMessage     *message);
493 
494 static void distribute_method_call (GDBusConnection  *connection,
495                                     GDBusMessage     *message);
496 
497 static gboolean handle_generic_unlocked (GDBusConnection *connection,
498                                          GDBusMessage    *message);
499 
500 
501 static void purge_all_signal_subscriptions (GDBusConnection *connection);
502 static void purge_all_filters (GDBusConnection *connection);
503 
504 static void schedule_method_call (GDBusConnection            *connection,
505                                   GDBusMessage               *message,
506                                   guint                       registration_id,
507                                   guint                       subtree_registration_id,
508                                   const GDBusInterfaceInfo   *interface_info,
509                                   const GDBusMethodInfo      *method_info,
510                                   const GDBusPropertyInfo    *property_info,
511                                   GVariant                   *parameters,
512                                   const GDBusInterfaceVTable *vtable,
513                                   GMainContext               *main_context,
514                                   gpointer                    user_data);
515 
516 #define _G_ENSURE_LOCK(name) do {                                       \
517     if (G_UNLIKELY (G_TRYLOCK(name)))                                   \
518       {                                                                 \
519         g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
520                              "_G_ENSURE_LOCK: Lock '" #name "' is not locked"); \
521       }                                                                 \
522   } while (FALSE)                                                       \
523 
524 static guint signals[LAST_SIGNAL] = { 0 };
525 
526 static void initable_iface_init       (GInitableIface      *initable_iface);
527 static void async_initable_iface_init (GAsyncInitableIface *async_initable_iface);
528 
529 G_DEFINE_TYPE_WITH_CODE (GDBusConnection, g_dbus_connection, G_TYPE_OBJECT,
530                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init)
531                          G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, async_initable_iface_init)
532                          );
533 
534 /*
535  * Check that all members of @connection that can only be accessed after
536  * the connection is initialized can safely be accessed. If not,
537  * log a critical warning. This function is a memory barrier.
538  *
539  * Returns: %TRUE if initialized
540  */
541 static gboolean
check_initialized(GDBusConnection * connection)542 check_initialized (GDBusConnection *connection)
543 {
544   /* The access to @atomic_flags isn't conditional, so that this function
545    * provides a memory barrier for thread-safety even if checks are disabled.
546    * (If you don't want this stricter guarantee, you can call
547    * g_return_if_fail (check_initialized (c)).)
548    *
549    * This isn't strictly necessary now that we've decided use of an
550    * uninitialized GDBusConnection is undefined behaviour, but it seems
551    * better to be as deterministic as is feasible.
552    *
553    * (Anything that could suffer a crash from seeing undefined values
554    * must have a race condition - thread A initializes the connection while
555    * thread B calls a method without initialization, hoping that thread A will
556    * win the race - so its behaviour is undefined anyway.)
557    */
558   gint flags = g_atomic_int_get (&connection->atomic_flags);
559 
560   g_return_val_if_fail (flags & FLAG_INITIALIZED, FALSE);
561 
562   /* We can safely access this, due to the memory barrier above */
563   g_return_val_if_fail (connection->initialization_error == NULL, FALSE);
564 
565   return TRUE;
566 }
567 
568 typedef enum {
569     MAY_BE_UNINITIALIZED = (1<<1)
570 } CheckUnclosedFlags;
571 
572 /*
573  * Check the same thing as check_initialized(), and also that the
574  * connection is not closed. If the connection is uninitialized,
575  * raise a critical warning (it's programmer error); if it's closed,
576  * raise a recoverable GError (it's a runtime error).
577  *
578  * This function is a memory barrier.
579  *
580  * Returns: %TRUE if initialized and not closed
581  */
582 static gboolean
check_unclosed(GDBusConnection * connection,CheckUnclosedFlags check,GError ** error)583 check_unclosed (GDBusConnection     *connection,
584                 CheckUnclosedFlags   check,
585                 GError             **error)
586 {
587   /* check_initialized() is effectively inlined, so we don't waste time
588    * doing two memory barriers
589    */
590   gint flags = g_atomic_int_get (&connection->atomic_flags);
591 
592   if (!(check & MAY_BE_UNINITIALIZED))
593     {
594       g_return_val_if_fail (flags & FLAG_INITIALIZED, FALSE);
595       g_return_val_if_fail (connection->initialization_error == NULL, FALSE);
596     }
597 
598   if (flags & FLAG_CLOSED)
599     {
600       g_set_error_literal (error,
601                            G_IO_ERROR,
602                            G_IO_ERROR_CLOSED,
603                            _("The connection is closed"));
604       return FALSE;
605     }
606 
607   return TRUE;
608 }
609 
610 static GHashTable *alive_connections = NULL;
611 
612 static void
g_dbus_connection_dispose(GObject * object)613 g_dbus_connection_dispose (GObject *object)
614 {
615   GDBusConnection *connection = G_DBUS_CONNECTION (object);
616 
617   G_LOCK (message_bus_lock);
618   CONNECTION_LOCK (connection);
619   if (connection->worker != NULL)
620     {
621       _g_dbus_worker_stop (connection->worker);
622       connection->worker = NULL;
623       if (alive_connections != NULL)
624         g_warn_if_fail (g_hash_table_remove (alive_connections, connection));
625     }
626   else
627     {
628       if (alive_connections != NULL)
629         g_warn_if_fail (!g_hash_table_contains (alive_connections, connection));
630     }
631   CONNECTION_UNLOCK (connection);
632   G_UNLOCK (message_bus_lock);
633 
634   if (G_OBJECT_CLASS (g_dbus_connection_parent_class)->dispose != NULL)
635     G_OBJECT_CLASS (g_dbus_connection_parent_class)->dispose (object);
636 }
637 
638 static void
g_dbus_connection_finalize(GObject * object)639 g_dbus_connection_finalize (GObject *object)
640 {
641   GDBusConnection *connection = G_DBUS_CONNECTION (object);
642 
643   connection->finalizing = TRUE;
644 
645   purge_all_signal_subscriptions (connection);
646 
647   purge_all_filters (connection);
648   g_ptr_array_unref (connection->filters);
649 
650   if (connection->authentication_observer != NULL)
651     g_object_unref (connection->authentication_observer);
652 
653   if (connection->auth != NULL)
654     g_object_unref (connection->auth);
655 
656   if (connection->credentials)
657     g_object_unref (connection->credentials);
658 
659   if (connection->stream != NULL)
660     {
661       g_object_unref (connection->stream);
662       connection->stream = NULL;
663     }
664 
665   g_free (connection->address);
666 
667   g_free (connection->guid);
668   g_free (connection->bus_unique_name);
669 
670   if (connection->initialization_error != NULL)
671     g_error_free (connection->initialization_error);
672 
673   g_hash_table_unref (connection->map_method_serial_to_task);
674 
675   g_hash_table_unref (connection->map_rule_to_signal_data);
676   g_hash_table_unref (connection->map_id_to_signal_data);
677   g_hash_table_unref (connection->map_sender_unique_name_to_signal_data_array);
678 
679   g_hash_table_unref (connection->map_id_to_ei);
680   g_hash_table_unref (connection->map_object_path_to_eo);
681   g_hash_table_unref (connection->map_id_to_es);
682   g_hash_table_unref (connection->map_object_path_to_es);
683 
684   g_hash_table_unref (connection->map_thread_to_last_serial);
685 
686   g_main_context_unref (connection->main_context_at_construction);
687 
688   g_free (connection->machine_id);
689 
690   g_mutex_clear (&connection->init_lock);
691   g_mutex_clear (&connection->lock);
692 
693   G_OBJECT_CLASS (g_dbus_connection_parent_class)->finalize (object);
694 }
695 
696 /* called in any user thread, with the connection's lock not held */
697 static void
g_dbus_connection_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)698 g_dbus_connection_get_property (GObject    *object,
699                                 guint       prop_id,
700                                 GValue     *value,
701                                 GParamSpec *pspec)
702 {
703   GDBusConnection *connection = G_DBUS_CONNECTION (object);
704 
705   switch (prop_id)
706     {
707     case PROP_STREAM:
708       g_value_set_object (value, g_dbus_connection_get_stream (connection));
709       break;
710 
711     case PROP_GUID:
712       g_value_set_string (value, g_dbus_connection_get_guid (connection));
713       break;
714 
715     case PROP_UNIQUE_NAME:
716       g_value_set_string (value, g_dbus_connection_get_unique_name (connection));
717       break;
718 
719     case PROP_CLOSED:
720       g_value_set_boolean (value, g_dbus_connection_is_closed (connection));
721       break;
722 
723     case PROP_EXIT_ON_CLOSE:
724       g_value_set_boolean (value, g_dbus_connection_get_exit_on_close (connection));
725       break;
726 
727     case PROP_CAPABILITY_FLAGS:
728       g_value_set_flags (value, g_dbus_connection_get_capabilities (connection));
729       break;
730 
731     case PROP_FLAGS:
732       g_value_set_flags (value, g_dbus_connection_get_flags (connection));
733       break;
734 
735     default:
736       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
737       break;
738     }
739 }
740 
741 /* called in any user thread, with the connection's lock not held */
742 static void
g_dbus_connection_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)743 g_dbus_connection_set_property (GObject      *object,
744                                 guint         prop_id,
745                                 const GValue *value,
746                                 GParamSpec   *pspec)
747 {
748   GDBusConnection *connection = G_DBUS_CONNECTION (object);
749 
750   switch (prop_id)
751     {
752     case PROP_STREAM:
753       connection->stream = g_value_dup_object (value);
754       break;
755 
756     case PROP_GUID:
757       connection->guid = g_value_dup_string (value);
758       break;
759 
760     case PROP_ADDRESS:
761       connection->address = g_value_dup_string (value);
762       break;
763 
764     case PROP_FLAGS:
765       connection->flags = g_value_get_flags (value);
766       break;
767 
768     case PROP_EXIT_ON_CLOSE:
769       g_dbus_connection_set_exit_on_close (connection, g_value_get_boolean (value));
770       break;
771 
772     case PROP_AUTHENTICATION_OBSERVER:
773       connection->authentication_observer = g_value_dup_object (value);
774       break;
775 
776     default:
777       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
778       break;
779     }
780 }
781 
782 /* Base-class implementation of GDBusConnection::closed.
783  *
784  * Called in a user thread, by the main context that was thread-default when
785  * the object was constructed.
786  */
787 static void
g_dbus_connection_real_closed(GDBusConnection * connection,gboolean remote_peer_vanished,GError * error)788 g_dbus_connection_real_closed (GDBusConnection *connection,
789                                gboolean         remote_peer_vanished,
790                                GError          *error)
791 {
792   gint flags = g_atomic_int_get (&connection->atomic_flags);
793 
794   /* Because atomic int access is a memory barrier, we can safely read
795    * initialization_error without a lock, as long as we do it afterwards.
796    */
797   if (remote_peer_vanished &&
798       (flags & FLAG_EXIT_ON_CLOSE) != 0 &&
799       (flags & FLAG_INITIALIZED) != 0 &&
800       connection->initialization_error == NULL)
801     {
802       raise (SIGTERM);
803     }
804 }
805 
806 static void
g_dbus_connection_class_init(GDBusConnectionClass * klass)807 g_dbus_connection_class_init (GDBusConnectionClass *klass)
808 {
809   GObjectClass *gobject_class;
810 
811   gobject_class = G_OBJECT_CLASS (klass);
812 
813   gobject_class->finalize     = g_dbus_connection_finalize;
814   gobject_class->dispose      = g_dbus_connection_dispose;
815   gobject_class->set_property = g_dbus_connection_set_property;
816   gobject_class->get_property = g_dbus_connection_get_property;
817 
818   klass->closed = g_dbus_connection_real_closed;
819 
820   /**
821    * GDBusConnection:stream:
822    *
823    * The underlying #GIOStream used for I/O.
824    *
825    * If this is passed on construction and is a #GSocketConnection,
826    * then the corresponding #GSocket will be put into non-blocking mode.
827    *
828    * While the #GDBusConnection is active, it will interact with this
829    * stream from a worker thread, so it is not safe to interact with
830    * the stream directly.
831    *
832    * Since: 2.26
833    */
834   g_object_class_install_property (gobject_class,
835                                    PROP_STREAM,
836                                    g_param_spec_object ("stream",
837                                                         P_("IO Stream"),
838                                                         P_("The underlying streams used for I/O"),
839                                                         G_TYPE_IO_STREAM,
840                                                         G_PARAM_READABLE |
841                                                         G_PARAM_WRITABLE |
842                                                         G_PARAM_CONSTRUCT_ONLY |
843                                                         G_PARAM_STATIC_NAME |
844                                                         G_PARAM_STATIC_BLURB |
845                                                         G_PARAM_STATIC_NICK));
846 
847   /**
848    * GDBusConnection:address:
849    *
850    * A D-Bus address specifying potential endpoints that can be used
851    * when establishing the connection.
852    *
853    * Since: 2.26
854    */
855   g_object_class_install_property (gobject_class,
856                                    PROP_ADDRESS,
857                                    g_param_spec_string ("address",
858                                                         P_("Address"),
859                                                         P_("D-Bus address specifying potential socket endpoints"),
860                                                         NULL,
861                                                         G_PARAM_WRITABLE |
862                                                         G_PARAM_CONSTRUCT_ONLY |
863                                                         G_PARAM_STATIC_NAME |
864                                                         G_PARAM_STATIC_BLURB |
865                                                         G_PARAM_STATIC_NICK));
866 
867   /**
868    * GDBusConnection:flags:
869    *
870    * Flags from the #GDBusConnectionFlags enumeration.
871    *
872    * Since: 2.26
873    */
874   g_object_class_install_property (gobject_class,
875                                    PROP_FLAGS,
876                                    g_param_spec_flags ("flags",
877                                                        P_("Flags"),
878                                                        P_("Flags"),
879                                                        G_TYPE_DBUS_CONNECTION_FLAGS,
880                                                        G_DBUS_CONNECTION_FLAGS_NONE,
881                                                        G_PARAM_READABLE |
882                                                        G_PARAM_WRITABLE |
883                                                        G_PARAM_CONSTRUCT_ONLY |
884                                                        G_PARAM_STATIC_NAME |
885                                                        G_PARAM_STATIC_BLURB |
886                                                        G_PARAM_STATIC_NICK));
887 
888   /**
889    * GDBusConnection:guid:
890    *
891    * The GUID of the peer performing the role of server when
892    * authenticating.
893    *
894    * If you are constructing a #GDBusConnection and pass
895    * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER in the
896    * #GDBusConnection:flags property then you **must** also set this
897    * property to a valid guid.
898    *
899    * If you are constructing a #GDBusConnection and pass
900    * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT in the
901    * #GDBusConnection:flags property you will be able to read the GUID
902    * of the other peer here after the connection has been successfully
903    * initialized.
904    *
905    * Since: 2.26
906    */
907   g_object_class_install_property (gobject_class,
908                                    PROP_GUID,
909                                    g_param_spec_string ("guid",
910                                                         P_("GUID"),
911                                                         P_("GUID of the server peer"),
912                                                         NULL,
913                                                         G_PARAM_READABLE |
914                                                         G_PARAM_WRITABLE |
915                                                         G_PARAM_CONSTRUCT_ONLY |
916                                                         G_PARAM_STATIC_NAME |
917                                                         G_PARAM_STATIC_BLURB |
918                                                         G_PARAM_STATIC_NICK));
919 
920   /**
921    * GDBusConnection:unique-name:
922    *
923    * The unique name as assigned by the message bus or %NULL if the
924    * connection is not open or not a message bus connection.
925    *
926    * Since: 2.26
927    */
928   g_object_class_install_property (gobject_class,
929                                    PROP_UNIQUE_NAME,
930                                    g_param_spec_string ("unique-name",
931                                                         P_("unique-name"),
932                                                         P_("Unique name of bus connection"),
933                                                         NULL,
934                                                         G_PARAM_READABLE |
935                                                         G_PARAM_STATIC_NAME |
936                                                         G_PARAM_STATIC_BLURB |
937                                                         G_PARAM_STATIC_NICK));
938 
939   /**
940    * GDBusConnection:closed:
941    *
942    * A boolean specifying whether the connection has been closed.
943    *
944    * Since: 2.26
945    */
946   g_object_class_install_property (gobject_class,
947                                    PROP_CLOSED,
948                                    g_param_spec_boolean ("closed",
949                                                          P_("Closed"),
950                                                          P_("Whether the connection is closed"),
951                                                          FALSE,
952                                                          G_PARAM_READABLE |
953                                                          G_PARAM_STATIC_NAME |
954                                                          G_PARAM_STATIC_BLURB |
955                                                          G_PARAM_STATIC_NICK));
956 
957   /**
958    * GDBusConnection:exit-on-close:
959    *
960    * A boolean specifying whether the process will be terminated (by
961    * calling `raise(SIGTERM)`) if the connection is closed by the
962    * remote peer.
963    *
964    * Note that #GDBusConnection objects returned by g_bus_get_finish()
965    * and g_bus_get_sync() will (usually) have this property set to %TRUE.
966    *
967    * Since: 2.26
968    */
969   g_object_class_install_property (gobject_class,
970                                    PROP_EXIT_ON_CLOSE,
971                                    g_param_spec_boolean ("exit-on-close",
972                                                          P_("Exit on close"),
973                                                          P_("Whether the process is terminated when the connection is closed"),
974                                                          FALSE,
975                                                          G_PARAM_READABLE |
976                                                          G_PARAM_WRITABLE |
977                                                          G_PARAM_STATIC_NAME |
978                                                          G_PARAM_STATIC_BLURB |
979                                                          G_PARAM_STATIC_NICK));
980 
981   /**
982    * GDBusConnection:capabilities:
983    *
984    * Flags from the #GDBusCapabilityFlags enumeration
985    * representing connection features negotiated with the other peer.
986    *
987    * Since: 2.26
988    */
989   g_object_class_install_property (gobject_class,
990                                    PROP_CAPABILITY_FLAGS,
991                                    g_param_spec_flags ("capabilities",
992                                                        P_("Capabilities"),
993                                                        P_("Capabilities"),
994                                                        G_TYPE_DBUS_CAPABILITY_FLAGS,
995                                                        G_DBUS_CAPABILITY_FLAGS_NONE,
996                                                        G_PARAM_READABLE |
997                                                        G_PARAM_STATIC_NAME |
998                                                        G_PARAM_STATIC_BLURB |
999                                                        G_PARAM_STATIC_NICK));
1000 
1001   /**
1002    * GDBusConnection:authentication-observer:
1003    *
1004    * A #GDBusAuthObserver object to assist in the authentication process or %NULL.
1005    *
1006    * Since: 2.26
1007    */
1008   g_object_class_install_property (gobject_class,
1009                                    PROP_AUTHENTICATION_OBSERVER,
1010                                    g_param_spec_object ("authentication-observer",
1011                                                         P_("Authentication Observer"),
1012                                                         P_("Object used to assist in the authentication process"),
1013                                                         G_TYPE_DBUS_AUTH_OBSERVER,
1014                                                         G_PARAM_WRITABLE |
1015                                                         G_PARAM_CONSTRUCT_ONLY |
1016                                                         G_PARAM_STATIC_NAME |
1017                                                         G_PARAM_STATIC_BLURB |
1018                                                         G_PARAM_STATIC_NICK));
1019 
1020   /**
1021    * GDBusConnection::closed:
1022    * @connection: the #GDBusConnection emitting the signal
1023    * @remote_peer_vanished: %TRUE if @connection is closed because the
1024    *     remote peer closed its end of the connection
1025    * @error: (nullable): a #GError with more details about the event or %NULL
1026    *
1027    * Emitted when the connection is closed.
1028    *
1029    * The cause of this event can be
1030    *
1031    * - If g_dbus_connection_close() is called. In this case
1032    *   @remote_peer_vanished is set to %FALSE and @error is %NULL.
1033    *
1034    * - If the remote peer closes the connection. In this case
1035    *   @remote_peer_vanished is set to %TRUE and @error is set.
1036    *
1037    * - If the remote peer sends invalid or malformed data. In this
1038    *   case @remote_peer_vanished is set to %FALSE and @error is set.
1039    *
1040    * Upon receiving this signal, you should give up your reference to
1041    * @connection. You are guaranteed that this signal is emitted only
1042    * once.
1043    *
1044    * Since: 2.26
1045    */
1046   signals[CLOSED_SIGNAL] = g_signal_new (I_("closed"),
1047                                          G_TYPE_DBUS_CONNECTION,
1048                                          G_SIGNAL_RUN_LAST,
1049                                          G_STRUCT_OFFSET (GDBusConnectionClass, closed),
1050                                          NULL,
1051                                          NULL,
1052                                          _g_cclosure_marshal_VOID__BOOLEAN_BOXED,
1053                                          G_TYPE_NONE,
1054                                          2,
1055                                          G_TYPE_BOOLEAN,
1056                                          G_TYPE_ERROR);
1057   g_signal_set_va_marshaller (signals[CLOSED_SIGNAL],
1058                               G_TYPE_FROM_CLASS (klass),
1059                               _g_cclosure_marshal_VOID__BOOLEAN_BOXEDv);
1060 }
1061 
1062 static void
g_dbus_connection_init(GDBusConnection * connection)1063 g_dbus_connection_init (GDBusConnection *connection)
1064 {
1065   g_mutex_init (&connection->lock);
1066   g_mutex_init (&connection->init_lock);
1067 
1068   connection->map_method_serial_to_task = g_hash_table_new (g_direct_hash, g_direct_equal);
1069 
1070   connection->map_rule_to_signal_data = g_hash_table_new (g_str_hash,
1071                                                           g_str_equal);
1072   connection->map_id_to_signal_data = g_hash_table_new (g_direct_hash,
1073                                                         g_direct_equal);
1074   connection->map_sender_unique_name_to_signal_data_array = g_hash_table_new_full (g_str_hash,
1075                                                                                    g_str_equal,
1076                                                                                    g_free,
1077                                                                                    (GDestroyNotify) g_ptr_array_unref);
1078 
1079   connection->map_object_path_to_eo = g_hash_table_new_full (g_str_hash,
1080                                                              g_str_equal,
1081                                                              NULL,
1082                                                              (GDestroyNotify) exported_object_free);
1083 
1084   connection->map_id_to_ei = g_hash_table_new (g_direct_hash,
1085                                                g_direct_equal);
1086 
1087   connection->map_object_path_to_es = g_hash_table_new_full (g_str_hash,
1088                                                              g_str_equal,
1089                                                              NULL,
1090                                                              (GDestroyNotify) exported_subtree_free);
1091 
1092   connection->map_id_to_es = g_hash_table_new (g_direct_hash,
1093                                                g_direct_equal);
1094 
1095   connection->map_thread_to_last_serial = g_hash_table_new (g_direct_hash,
1096                                                             g_direct_equal);
1097 
1098   connection->main_context_at_construction = g_main_context_ref_thread_default ();
1099 
1100   connection->filters = g_ptr_array_new ();
1101 }
1102 
1103 /**
1104  * g_dbus_connection_get_stream:
1105  * @connection: a #GDBusConnection
1106  *
1107  * Gets the underlying stream used for IO.
1108  *
1109  * While the #GDBusConnection is active, it will interact with this
1110  * stream from a worker thread, so it is not safe to interact with
1111  * the stream directly.
1112  *
1113  * Returns: (transfer none) (not nullable): the stream used for IO
1114  *
1115  * Since: 2.26
1116  */
1117 GIOStream *
g_dbus_connection_get_stream(GDBusConnection * connection)1118 g_dbus_connection_get_stream (GDBusConnection *connection)
1119 {
1120   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
1121 
1122   /* do not use g_return_val_if_fail(), we want the memory barrier */
1123   if (!check_initialized (connection))
1124     return NULL;
1125 
1126   return connection->stream;
1127 }
1128 
1129 /**
1130  * g_dbus_connection_start_message_processing:
1131  * @connection: a #GDBusConnection
1132  *
1133  * If @connection was created with
1134  * %G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING, this method
1135  * starts processing messages. Does nothing on if @connection wasn't
1136  * created with this flag or if the method has already been called.
1137  *
1138  * Since: 2.26
1139  */
1140 void
g_dbus_connection_start_message_processing(GDBusConnection * connection)1141 g_dbus_connection_start_message_processing (GDBusConnection *connection)
1142 {
1143   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
1144 
1145   /* do not use g_return_val_if_fail(), we want the memory barrier */
1146   if (!check_initialized (connection))
1147     return;
1148 
1149   g_assert (connection->worker != NULL);
1150   _g_dbus_worker_unfreeze (connection->worker);
1151 }
1152 
1153 /**
1154  * g_dbus_connection_is_closed:
1155  * @connection: a #GDBusConnection
1156  *
1157  * Gets whether @connection is closed.
1158  *
1159  * Returns: %TRUE if the connection is closed, %FALSE otherwise
1160  *
1161  * Since: 2.26
1162  */
1163 gboolean
g_dbus_connection_is_closed(GDBusConnection * connection)1164 g_dbus_connection_is_closed (GDBusConnection *connection)
1165 {
1166   gint flags;
1167 
1168   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
1169 
1170   flags = g_atomic_int_get (&connection->atomic_flags);
1171 
1172   return (flags & FLAG_CLOSED) ? TRUE : FALSE;
1173 }
1174 
1175 /**
1176  * g_dbus_connection_get_capabilities:
1177  * @connection: a #GDBusConnection
1178  *
1179  * Gets the capabilities negotiated with the remote peer
1180  *
1181  * Returns: zero or more flags from the #GDBusCapabilityFlags enumeration
1182  *
1183  * Since: 2.26
1184  */
1185 GDBusCapabilityFlags
g_dbus_connection_get_capabilities(GDBusConnection * connection)1186 g_dbus_connection_get_capabilities (GDBusConnection *connection)
1187 {
1188   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), G_DBUS_CAPABILITY_FLAGS_NONE);
1189 
1190   /* do not use g_return_val_if_fail(), we want the memory barrier */
1191   if (!check_initialized (connection))
1192     return G_DBUS_CAPABILITY_FLAGS_NONE;
1193 
1194   return connection->capabilities;
1195 }
1196 
1197 /**
1198  * g_dbus_connection_get_flags:
1199  * @connection: a #GDBusConnection
1200  *
1201  * Gets the flags used to construct this connection
1202  *
1203  * Returns: zero or more flags from the #GDBusConnectionFlags enumeration
1204  *
1205  * Since: 2.60
1206  */
1207 GDBusConnectionFlags
g_dbus_connection_get_flags(GDBusConnection * connection)1208 g_dbus_connection_get_flags (GDBusConnection *connection)
1209 {
1210   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), G_DBUS_CONNECTION_FLAGS_NONE);
1211 
1212   /* do not use g_return_val_if_fail(), we want the memory barrier */
1213   if (!check_initialized (connection))
1214     return G_DBUS_CONNECTION_FLAGS_NONE;
1215 
1216   return connection->flags;
1217 }
1218 
1219 /* ---------------------------------------------------------------------------------------------------- */
1220 
1221 /* Called in a temporary thread without holding locks. */
1222 static void
flush_in_thread_func(GTask * task,gpointer source_object,gpointer task_data,GCancellable * cancellable)1223 flush_in_thread_func (GTask         *task,
1224                       gpointer       source_object,
1225                       gpointer       task_data,
1226                       GCancellable  *cancellable)
1227 {
1228   GError *error = NULL;
1229 
1230   if (g_dbus_connection_flush_sync (source_object,
1231                                     cancellable,
1232                                     &error))
1233     g_task_return_boolean (task, TRUE);
1234   else
1235     g_task_return_error (task, error);
1236 }
1237 
1238 /**
1239  * g_dbus_connection_flush:
1240  * @connection: a #GDBusConnection
1241  * @cancellable: (nullable): a #GCancellable or %NULL
1242  * @callback: (nullable): a #GAsyncReadyCallback to call when the
1243  *     request is satisfied or %NULL if you don't care about the result
1244  * @user_data: The data to pass to @callback
1245  *
1246  * Asynchronously flushes @connection, that is, writes all queued
1247  * outgoing message to the transport and then flushes the transport
1248  * (using g_output_stream_flush_async()). This is useful in programs
1249  * that wants to emit a D-Bus signal and then exit immediately. Without
1250  * flushing the connection, there is no guaranteed that the message has
1251  * been sent to the networking buffers in the OS kernel.
1252  *
1253  * This is an asynchronous method. When the operation is finished,
1254  * @callback will be invoked in the
1255  * [thread-default main context][g-main-context-push-thread-default]
1256  * of the thread you are calling this method from. You can
1257  * then call g_dbus_connection_flush_finish() to get the result of the
1258  * operation. See g_dbus_connection_flush_sync() for the synchronous
1259  * version.
1260  *
1261  * Since: 2.26
1262  */
1263 void
g_dbus_connection_flush(GDBusConnection * connection,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1264 g_dbus_connection_flush (GDBusConnection     *connection,
1265                          GCancellable        *cancellable,
1266                          GAsyncReadyCallback  callback,
1267                          gpointer             user_data)
1268 {
1269   GTask *task;
1270 
1271   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
1272 
1273   task = g_task_new (connection, cancellable, callback, user_data);
1274   g_task_set_source_tag (task, g_dbus_connection_flush);
1275   g_task_run_in_thread (task, flush_in_thread_func);
1276   g_object_unref (task);
1277 }
1278 
1279 /**
1280  * g_dbus_connection_flush_finish:
1281  * @connection: a #GDBusConnection
1282  * @res: a #GAsyncResult obtained from the #GAsyncReadyCallback passed
1283  *     to g_dbus_connection_flush()
1284  * @error: return location for error or %NULL
1285  *
1286  * Finishes an operation started with g_dbus_connection_flush().
1287  *
1288  * Returns: %TRUE if the operation succeeded, %FALSE if @error is set
1289  *
1290  * Since: 2.26
1291  */
1292 gboolean
g_dbus_connection_flush_finish(GDBusConnection * connection,GAsyncResult * res,GError ** error)1293 g_dbus_connection_flush_finish (GDBusConnection  *connection,
1294                                 GAsyncResult     *res,
1295                                 GError          **error)
1296 {
1297   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
1298   g_return_val_if_fail (g_task_is_valid (res, connection), FALSE);
1299   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1300 
1301   return g_task_propagate_boolean (G_TASK (res), error);
1302 }
1303 
1304 /**
1305  * g_dbus_connection_flush_sync:
1306  * @connection: a #GDBusConnection
1307  * @cancellable: (nullable): a #GCancellable or %NULL
1308  * @error: return location for error or %NULL
1309  *
1310  * Synchronously flushes @connection. The calling thread is blocked
1311  * until this is done. See g_dbus_connection_flush() for the
1312  * asynchronous version of this method and more details about what it
1313  * does.
1314  *
1315  * Returns: %TRUE if the operation succeeded, %FALSE if @error is set
1316  *
1317  * Since: 2.26
1318  */
1319 gboolean
g_dbus_connection_flush_sync(GDBusConnection * connection,GCancellable * cancellable,GError ** error)1320 g_dbus_connection_flush_sync (GDBusConnection  *connection,
1321                               GCancellable     *cancellable,
1322                               GError          **error)
1323 {
1324   gboolean ret;
1325 
1326   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
1327   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1328 
1329   ret = FALSE;
1330 
1331   /* This is only a best-effort attempt to see whether the connection is
1332    * closed, so it doesn't need the lock. If the connection closes just
1333    * after this check, but before scheduling the flush operation, the
1334    * result will be more or less the same as if the connection closed while
1335    * the flush operation was pending - it'll fail with either CLOSED or
1336    * CANCELLED.
1337    */
1338   if (!check_unclosed (connection, 0, error))
1339     goto out;
1340 
1341   g_assert (connection->worker != NULL);
1342 
1343   ret = _g_dbus_worker_flush_sync (connection->worker,
1344                                    cancellable,
1345                                    error);
1346 
1347  out:
1348   return ret;
1349 }
1350 
1351 /* ---------------------------------------------------------------------------------------------------- */
1352 
1353 typedef struct
1354 {
1355   GDBusConnection *connection;
1356   GError *error;
1357   gboolean remote_peer_vanished;
1358 } EmitClosedData;
1359 
1360 static void
emit_closed_data_free(EmitClosedData * data)1361 emit_closed_data_free (EmitClosedData *data)
1362 {
1363   g_object_unref (data->connection);
1364   if (data->error != NULL)
1365     g_error_free (data->error);
1366   g_free (data);
1367 }
1368 
1369 /* Called in a user thread that has acquired the main context that was
1370  * thread-default when the object was constructed
1371  */
1372 static gboolean
emit_closed_in_idle(gpointer user_data)1373 emit_closed_in_idle (gpointer user_data)
1374 {
1375   EmitClosedData *data = user_data;
1376   gboolean result;
1377 
1378   g_object_notify (G_OBJECT (data->connection), "closed");
1379   g_signal_emit (data->connection,
1380                  signals[CLOSED_SIGNAL],
1381                  0,
1382                  data->remote_peer_vanished,
1383                  data->error,
1384                  &result);
1385   return FALSE;
1386 }
1387 
1388 /* Can be called from any thread, must hold lock.
1389  * FLAG_CLOSED must already have been set.
1390  */
1391 static void
schedule_closed_unlocked(GDBusConnection * connection,gboolean remote_peer_vanished,GError * error)1392 schedule_closed_unlocked (GDBusConnection *connection,
1393                           gboolean         remote_peer_vanished,
1394                           GError          *error)
1395 {
1396   GSource *idle_source;
1397   EmitClosedData *data;
1398 
1399   CONNECTION_ENSURE_LOCK (connection);
1400 
1401   data = g_new0 (EmitClosedData, 1);
1402   data->connection = g_object_ref (connection);
1403   data->remote_peer_vanished = remote_peer_vanished;
1404   data->error = error != NULL ? g_error_copy (error) : NULL;
1405 
1406   idle_source = g_idle_source_new ();
1407   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
1408   g_source_set_callback (idle_source,
1409                          emit_closed_in_idle,
1410                          data,
1411                          (GDestroyNotify) emit_closed_data_free);
1412   g_source_set_name (idle_source, "[gio] emit_closed_in_idle");
1413   g_source_attach (idle_source, connection->main_context_at_construction);
1414   g_source_unref (idle_source);
1415 }
1416 
1417 /* ---------------------------------------------------------------------------------------------------- */
1418 
1419 /**
1420  * g_dbus_connection_close:
1421  * @connection: a #GDBusConnection
1422  * @cancellable: (nullable): a #GCancellable or %NULL
1423  * @callback: (nullable): a #GAsyncReadyCallback to call when the request is
1424  *     satisfied or %NULL if you don't care about the result
1425  * @user_data: The data to pass to @callback
1426  *
1427  * Closes @connection. Note that this never causes the process to
1428  * exit (this might only happen if the other end of a shared message
1429  * bus connection disconnects, see #GDBusConnection:exit-on-close).
1430  *
1431  * Once the connection is closed, operations such as sending a message
1432  * will return with the error %G_IO_ERROR_CLOSED. Closing a connection
1433  * will not automatically flush the connection so queued messages may
1434  * be lost. Use g_dbus_connection_flush() if you need such guarantees.
1435  *
1436  * If @connection is already closed, this method fails with
1437  * %G_IO_ERROR_CLOSED.
1438  *
1439  * When @connection has been closed, the #GDBusConnection::closed
1440  * signal is emitted in the
1441  * [thread-default main context][g-main-context-push-thread-default]
1442  * of the thread that @connection was constructed in.
1443  *
1444  * This is an asynchronous method. When the operation is finished,
1445  * @callback will be invoked in the
1446  * [thread-default main context][g-main-context-push-thread-default]
1447  * of the thread you are calling this method from. You can
1448  * then call g_dbus_connection_close_finish() to get the result of the
1449  * operation. See g_dbus_connection_close_sync() for the synchronous
1450  * version.
1451  *
1452  * Since: 2.26
1453  */
1454 void
g_dbus_connection_close(GDBusConnection * connection,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1455 g_dbus_connection_close (GDBusConnection     *connection,
1456                          GCancellable        *cancellable,
1457                          GAsyncReadyCallback  callback,
1458                          gpointer             user_data)
1459 {
1460   GTask *task;
1461 
1462   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
1463 
1464   /* do not use g_return_val_if_fail(), we want the memory barrier */
1465   if (!check_initialized (connection))
1466     return;
1467 
1468   g_assert (connection->worker != NULL);
1469 
1470   task = g_task_new (connection, cancellable, callback, user_data);
1471   g_task_set_source_tag (task, g_dbus_connection_close);
1472   _g_dbus_worker_close (connection->worker, task);
1473   g_object_unref (task);
1474 }
1475 
1476 /**
1477  * g_dbus_connection_close_finish:
1478  * @connection: a #GDBusConnection
1479  * @res: a #GAsyncResult obtained from the #GAsyncReadyCallback passed
1480  *     to g_dbus_connection_close()
1481  * @error: return location for error or %NULL
1482  *
1483  * Finishes an operation started with g_dbus_connection_close().
1484  *
1485  * Returns: %TRUE if the operation succeeded, %FALSE if @error is set
1486  *
1487  * Since: 2.26
1488  */
1489 gboolean
g_dbus_connection_close_finish(GDBusConnection * connection,GAsyncResult * res,GError ** error)1490 g_dbus_connection_close_finish (GDBusConnection  *connection,
1491                                 GAsyncResult     *res,
1492                                 GError          **error)
1493 {
1494   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
1495   g_return_val_if_fail (g_task_is_valid (res, connection), FALSE);
1496   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1497 
1498   return g_task_propagate_boolean (G_TASK (res), error);
1499 }
1500 
1501 typedef struct {
1502     GMainLoop *loop;
1503     GAsyncResult *result;
1504 } SyncCloseData;
1505 
1506 /* Can be called by any thread, without the connection lock */
1507 static void
sync_close_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)1508 sync_close_cb (GObject *source_object,
1509                GAsyncResult *res,
1510                gpointer user_data)
1511 {
1512   SyncCloseData *data = user_data;
1513 
1514   data->result = g_object_ref (res);
1515   g_main_loop_quit (data->loop);
1516 }
1517 
1518 /**
1519  * g_dbus_connection_close_sync:
1520  * @connection: a #GDBusConnection
1521  * @cancellable: (nullable): a #GCancellable or %NULL
1522  * @error: return location for error or %NULL
1523  *
1524  * Synchronously closes @connection. The calling thread is blocked
1525  * until this is done. See g_dbus_connection_close() for the
1526  * asynchronous version of this method and more details about what it
1527  * does.
1528  *
1529  * Returns: %TRUE if the operation succeeded, %FALSE if @error is set
1530  *
1531  * Since: 2.26
1532  */
1533 gboolean
g_dbus_connection_close_sync(GDBusConnection * connection,GCancellable * cancellable,GError ** error)1534 g_dbus_connection_close_sync (GDBusConnection  *connection,
1535                               GCancellable     *cancellable,
1536                               GError          **error)
1537 {
1538   gboolean ret;
1539 
1540   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
1541   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1542 
1543   ret = FALSE;
1544 
1545   if (check_unclosed (connection, 0, error))
1546     {
1547       GMainContext *context;
1548       SyncCloseData data;
1549 
1550       context = g_main_context_new ();
1551       g_main_context_push_thread_default (context);
1552       data.loop = g_main_loop_new (context, TRUE);
1553       data.result = NULL;
1554 
1555       g_dbus_connection_close (connection, cancellable, sync_close_cb, &data);
1556       g_main_loop_run (data.loop);
1557       ret = g_dbus_connection_close_finish (connection, data.result, error);
1558 
1559       g_object_unref (data.result);
1560       g_main_loop_unref (data.loop);
1561       g_main_context_pop_thread_default (context);
1562       g_main_context_unref (context);
1563     }
1564 
1565   return ret;
1566 }
1567 
1568 /* ---------------------------------------------------------------------------------------------------- */
1569 
1570 /**
1571  * g_dbus_connection_get_last_serial:
1572  * @connection: a #GDBusConnection
1573  *
1574  * Retrieves the last serial number assigned to a #GDBusMessage on
1575  * the current thread. This includes messages sent via both low-level
1576  * API such as g_dbus_connection_send_message() as well as
1577  * high-level API such as g_dbus_connection_emit_signal(),
1578  * g_dbus_connection_call() or g_dbus_proxy_call().
1579  *
1580  * Returns: the last used serial or zero when no message has been sent
1581  *     within the current thread
1582  *
1583  * Since: 2.34
1584  */
1585 guint32
g_dbus_connection_get_last_serial(GDBusConnection * connection)1586 g_dbus_connection_get_last_serial (GDBusConnection *connection)
1587 {
1588   guint32 ret;
1589 
1590   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
1591 
1592   CONNECTION_LOCK (connection);
1593   ret = GPOINTER_TO_UINT (g_hash_table_lookup (connection->map_thread_to_last_serial,
1594                                                g_thread_self ()));
1595   CONNECTION_UNLOCK (connection);
1596 
1597   return ret;
1598 }
1599 
1600 /* ---------------------------------------------------------------------------------------------------- */
1601 
1602 /* Can be called by any thread, with the connection lock held */
1603 static gboolean
g_dbus_connection_send_message_unlocked(GDBusConnection * connection,GDBusMessage * message,GDBusSendMessageFlags flags,guint32 * out_serial,GError ** error)1604 g_dbus_connection_send_message_unlocked (GDBusConnection   *connection,
1605                                          GDBusMessage      *message,
1606                                          GDBusSendMessageFlags flags,
1607                                          guint32           *out_serial,
1608                                          GError           **error)
1609 {
1610   guchar *blob;
1611   gsize blob_size;
1612   guint32 serial_to_use;
1613   gboolean ret;
1614 
1615   CONNECTION_ENSURE_LOCK (connection);
1616 
1617   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
1618   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
1619 
1620   /* TODO: check all necessary headers are present */
1621 
1622   ret = FALSE;
1623   blob = NULL;
1624 
1625   if (out_serial != NULL)
1626     *out_serial = 0;
1627 
1628   /* If we're in initable_init(), don't check for being initialized, to avoid
1629    * chicken-and-egg problems. initable_init() is responsible for setting up
1630    * our prerequisites (mainly connection->worker), and only calling us
1631    * from its own thread (so no memory barrier is needed).
1632    */
1633   if (!check_unclosed (connection,
1634                        (flags & SEND_MESSAGE_FLAGS_INITIALIZING) ? MAY_BE_UNINITIALIZED : 0,
1635                        error))
1636     goto out;
1637 
1638   blob = g_dbus_message_to_blob (message,
1639                                  &blob_size,
1640                                  connection->capabilities,
1641                                  error);
1642   if (blob == NULL)
1643     goto out;
1644 
1645   if (flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL)
1646     serial_to_use = g_dbus_message_get_serial (message);
1647   else
1648     serial_to_use = ++connection->last_serial; /* TODO: handle overflow */
1649 
1650   switch (blob[0])
1651     {
1652     case 'l':
1653       ((guint32 *) blob)[2] = GUINT32_TO_LE (serial_to_use);
1654       break;
1655     case 'B':
1656       ((guint32 *) blob)[2] = GUINT32_TO_BE (serial_to_use);
1657       break;
1658     default:
1659       g_assert_not_reached ();
1660       break;
1661     }
1662 
1663 #if 0
1664   g_printerr ("Writing message of %" G_GSIZE_FORMAT " bytes (serial %d) on %p:\n",
1665               blob_size, serial_to_use, connection);
1666   g_printerr ("----\n");
1667   hexdump (blob, blob_size);
1668   g_printerr ("----\n");
1669 #endif
1670 
1671   /* TODO: use connection->auth to encode the blob */
1672 
1673   if (out_serial != NULL)
1674     *out_serial = serial_to_use;
1675 
1676   /* store used serial for the current thread */
1677   /* TODO: watch the thread disposal and remove associated record
1678    *       from hashtable
1679    *  - see https://bugzilla.gnome.org/show_bug.cgi?id=676825#c7
1680    */
1681   g_hash_table_replace (connection->map_thread_to_last_serial,
1682                         g_thread_self (),
1683                         GUINT_TO_POINTER (serial_to_use));
1684 
1685   if (!(flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL))
1686     g_dbus_message_set_serial (message, serial_to_use);
1687 
1688   g_dbus_message_lock (message);
1689   _g_dbus_worker_send_message (connection->worker,
1690                                message,
1691                                (gchar*) blob,
1692                                blob_size);
1693   blob = NULL; /* since _g_dbus_worker_send_message() steals the blob */
1694 
1695   ret = TRUE;
1696 
1697  out:
1698   g_free (blob);
1699 
1700   return ret;
1701 }
1702 
1703 /**
1704  * g_dbus_connection_send_message:
1705  * @connection: a #GDBusConnection
1706  * @message: a #GDBusMessage
1707  * @flags: flags affecting how the message is sent
1708  * @out_serial: (out) (optional): return location for serial number assigned
1709  *     to @message when sending it or %NULL
1710  * @error: Return location for error or %NULL
1711  *
1712  * Asynchronously sends @message to the peer represented by @connection.
1713  *
1714  * Unless @flags contain the
1715  * %G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL flag, the serial number
1716  * will be assigned by @connection and set on @message via
1717  * g_dbus_message_set_serial(). If @out_serial is not %NULL, then the
1718  * serial number used will be written to this location prior to
1719  * submitting the message to the underlying transport. While it has a `volatile`
1720  * qualifier, this is a historical artifact and the argument passed to it should
1721  * not be `volatile`.
1722  *
1723  * If @connection is closed then the operation will fail with
1724  * %G_IO_ERROR_CLOSED. If @message is not well-formed,
1725  * the operation fails with %G_IO_ERROR_INVALID_ARGUMENT.
1726  *
1727  * See this [server][gdbus-server] and [client][gdbus-unix-fd-client]
1728  * for an example of how to use this low-level API to send and receive
1729  * UNIX file descriptors.
1730  *
1731  * Note that @message must be unlocked, unless @flags contain the
1732  * %G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL flag.
1733  *
1734  * Returns: %TRUE if the message was well-formed and queued for
1735  *     transmission, %FALSE if @error is set
1736  *
1737  * Since: 2.26
1738  */
1739 gboolean
g_dbus_connection_send_message(GDBusConnection * connection,GDBusMessage * message,GDBusSendMessageFlags flags,volatile guint32 * out_serial,GError ** error)1740 g_dbus_connection_send_message (GDBusConnection        *connection,
1741                                 GDBusMessage           *message,
1742                                 GDBusSendMessageFlags   flags,
1743                                 volatile guint32       *out_serial,
1744                                 GError                **error)
1745 {
1746   gboolean ret;
1747 
1748   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
1749   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
1750   g_return_val_if_fail ((flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL) || !g_dbus_message_get_locked (message), FALSE);
1751   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1752 
1753   CONNECTION_LOCK (connection);
1754   ret = g_dbus_connection_send_message_unlocked (connection, message, flags, (guint32 *) out_serial, error);
1755   CONNECTION_UNLOCK (connection);
1756   return ret;
1757 }
1758 
1759 /* ---------------------------------------------------------------------------------------------------- */
1760 
1761 typedef struct
1762 {
1763   guint32 serial;
1764 
1765   gulong cancellable_handler_id;
1766 
1767   GSource *timeout_source;
1768 
1769   gboolean delivered;
1770 } SendMessageData;
1771 
1772 /* Can be called from any thread with or without lock held */
1773 static void
send_message_data_free(SendMessageData * data)1774 send_message_data_free (SendMessageData *data)
1775 {
1776   g_assert (data->timeout_source == NULL);
1777   g_assert (data->cancellable_handler_id == 0);
1778 
1779   g_slice_free (SendMessageData, data);
1780 }
1781 
1782 /* ---------------------------------------------------------------------------------------------------- */
1783 
1784 /* can be called from any thread with lock held; @task is (transfer full) */
1785 static void
send_message_with_reply_cleanup(GTask * task,gboolean remove)1786 send_message_with_reply_cleanup (GTask *task, gboolean remove)
1787 {
1788   GDBusConnection *connection = g_task_get_source_object (task);
1789   SendMessageData *data = g_task_get_task_data (task);
1790 
1791   CONNECTION_ENSURE_LOCK (connection);
1792 
1793   g_assert (!data->delivered);
1794 
1795   data->delivered = TRUE;
1796 
1797   if (data->timeout_source != NULL)
1798     {
1799       g_source_destroy (data->timeout_source);
1800       data->timeout_source = NULL;
1801     }
1802   if (data->cancellable_handler_id > 0)
1803     {
1804       g_cancellable_disconnect (g_task_get_cancellable (task), data->cancellable_handler_id);
1805       data->cancellable_handler_id = 0;
1806     }
1807 
1808   if (remove)
1809     {
1810       gboolean removed = g_hash_table_remove (connection->map_method_serial_to_task,
1811                                               GUINT_TO_POINTER (data->serial));
1812       g_warn_if_fail (removed);
1813     }
1814 
1815   g_object_unref (task);
1816 }
1817 
1818 /* ---------------------------------------------------------------------------------------------------- */
1819 
1820 /* Called from GDBus worker thread with lock held; @task is (transfer full). */
1821 static void
send_message_data_deliver_reply_unlocked(GTask * task,GDBusMessage * reply)1822 send_message_data_deliver_reply_unlocked (GTask           *task,
1823                                           GDBusMessage    *reply)
1824 {
1825   SendMessageData *data = g_task_get_task_data (task);
1826 
1827   if (data->delivered)
1828     goto out;
1829 
1830   g_task_return_pointer (task, g_object_ref (reply), g_object_unref);
1831 
1832   send_message_with_reply_cleanup (task, TRUE);
1833 
1834  out:
1835   ;
1836 }
1837 
1838 /* Called from a user thread, lock is not held */
1839 static void
send_message_data_deliver_error(GTask * task,GQuark domain,gint code,const char * message)1840 send_message_data_deliver_error (GTask      *task,
1841                                  GQuark      domain,
1842                                  gint        code,
1843                                  const char *message)
1844 {
1845   GDBusConnection *connection = g_task_get_source_object (task);
1846   SendMessageData *data = g_task_get_task_data (task);
1847 
1848   CONNECTION_LOCK (connection);
1849   if (data->delivered)
1850     {
1851       CONNECTION_UNLOCK (connection);
1852       return;
1853     }
1854 
1855   g_object_ref (task);
1856   send_message_with_reply_cleanup (task, TRUE);
1857   CONNECTION_UNLOCK (connection);
1858 
1859   g_task_return_new_error (task, domain, code, "%s", message);
1860   g_object_unref (task);
1861 }
1862 
1863 /* ---------------------------------------------------------------------------------------------------- */
1864 
1865 /* Called from a user thread, lock is not held; @task is (transfer full) */
1866 static gboolean
send_message_with_reply_cancelled_idle_cb(gpointer user_data)1867 send_message_with_reply_cancelled_idle_cb (gpointer user_data)
1868 {
1869   GTask *task = user_data;
1870 
1871   send_message_data_deliver_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED,
1872                                    _("Operation was cancelled"));
1873   return FALSE;
1874 }
1875 
1876 /* Can be called from any thread with or without lock held */
1877 static void
send_message_with_reply_cancelled_cb(GCancellable * cancellable,gpointer user_data)1878 send_message_with_reply_cancelled_cb (GCancellable *cancellable,
1879                                       gpointer      user_data)
1880 {
1881   GTask *task = user_data;
1882   GSource *idle_source;
1883 
1884   /* postpone cancellation to idle handler since we may be called directly
1885    * via g_cancellable_connect() (e.g. holding lock)
1886    */
1887   idle_source = g_idle_source_new ();
1888   g_source_set_name (idle_source, "[gio] send_message_with_reply_cancelled_idle_cb");
1889   g_task_attach_source (task, idle_source, send_message_with_reply_cancelled_idle_cb);
1890   g_source_unref (idle_source);
1891 }
1892 
1893 /* ---------------------------------------------------------------------------------------------------- */
1894 
1895 /* Called from a user thread, lock is not held; @task is (transfer full) */
1896 static gboolean
send_message_with_reply_timeout_cb(gpointer user_data)1897 send_message_with_reply_timeout_cb (gpointer user_data)
1898 {
1899   GTask *task = user_data;
1900 
1901   send_message_data_deliver_error (task, G_IO_ERROR, G_IO_ERROR_TIMED_OUT,
1902                                    _("Timeout was reached"));
1903   return FALSE;
1904 }
1905 
1906 /* ---------------------------------------------------------------------------------------------------- */
1907 
1908 /* Called from a user thread, connection's lock is held */
1909 static void
g_dbus_connection_send_message_with_reply_unlocked(GDBusConnection * connection,GDBusMessage * message,GDBusSendMessageFlags flags,gint timeout_msec,guint32 * out_serial,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1910 g_dbus_connection_send_message_with_reply_unlocked (GDBusConnection     *connection,
1911                                                     GDBusMessage        *message,
1912                                                     GDBusSendMessageFlags flags,
1913                                                     gint                 timeout_msec,
1914                                                     guint32             *out_serial,
1915                                                     GCancellable        *cancellable,
1916                                                     GAsyncReadyCallback  callback,
1917                                                     gpointer             user_data)
1918 {
1919   GTask *task;
1920   SendMessageData *data;
1921   GError *error = NULL;
1922   guint32 serial;
1923 
1924   if (out_serial == NULL)
1925     out_serial = &serial;
1926 
1927   if (timeout_msec == -1)
1928     timeout_msec = 25 * 1000;
1929 
1930   data = g_slice_new0 (SendMessageData);
1931   task = g_task_new (connection, cancellable, callback, user_data);
1932   g_task_set_source_tag (task,
1933                          g_dbus_connection_send_message_with_reply_unlocked);
1934   g_task_set_task_data (task, data, (GDestroyNotify) send_message_data_free);
1935 
1936   if (g_task_return_error_if_cancelled (task))
1937     {
1938       g_object_unref (task);
1939       return;
1940     }
1941 
1942   if (!g_dbus_connection_send_message_unlocked (connection, message, flags, out_serial, &error))
1943     {
1944       g_task_return_error (task, error);
1945       g_object_unref (task);
1946       return;
1947     }
1948   data->serial = *out_serial;
1949 
1950   if (cancellable != NULL)
1951     {
1952       data->cancellable_handler_id = g_cancellable_connect (cancellable,
1953                                                             G_CALLBACK (send_message_with_reply_cancelled_cb),
1954                                                             g_object_ref (task),
1955                                                             g_object_unref);
1956     }
1957 
1958   if (timeout_msec != G_MAXINT)
1959     {
1960       data->timeout_source = g_timeout_source_new (timeout_msec);
1961       g_task_attach_source (task, data->timeout_source,
1962                             (GSourceFunc) send_message_with_reply_timeout_cb);
1963       g_source_unref (data->timeout_source);
1964     }
1965 
1966   g_hash_table_insert (connection->map_method_serial_to_task,
1967                        GUINT_TO_POINTER (*out_serial),
1968                        g_steal_pointer (&task));
1969 }
1970 
1971 /**
1972  * g_dbus_connection_send_message_with_reply:
1973  * @connection: a #GDBusConnection
1974  * @message: a #GDBusMessage
1975  * @flags: flags affecting how the message is sent
1976  * @timeout_msec: the timeout in milliseconds, -1 to use the default
1977  *     timeout or %G_MAXINT for no timeout
1978  * @out_serial: (out) (optional): return location for serial number assigned
1979  *     to @message when sending it or %NULL
1980  * @cancellable: (nullable): a #GCancellable or %NULL
1981  * @callback: (nullable): a #GAsyncReadyCallback to call when the request
1982  *     is satisfied or %NULL if you don't care about the result
1983  * @user_data: The data to pass to @callback
1984  *
1985  * Asynchronously sends @message to the peer represented by @connection.
1986  *
1987  * Unless @flags contain the
1988  * %G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL flag, the serial number
1989  * will be assigned by @connection and set on @message via
1990  * g_dbus_message_set_serial(). If @out_serial is not %NULL, then the
1991  * serial number used will be written to this location prior to
1992  * submitting the message to the underlying transport. While it has a `volatile`
1993  * qualifier, this is a historical artifact and the argument passed to it should
1994  * not be `volatile`.
1995  *
1996  * If @connection is closed then the operation will fail with
1997  * %G_IO_ERROR_CLOSED. If @cancellable is canceled, the operation will
1998  * fail with %G_IO_ERROR_CANCELLED. If @message is not well-formed,
1999  * the operation fails with %G_IO_ERROR_INVALID_ARGUMENT.
2000  *
2001  * This is an asynchronous method. When the operation is finished, @callback
2002  * will be invoked in the
2003  * [thread-default main context][g-main-context-push-thread-default]
2004  * of the thread you are calling this method from. You can then call
2005  * g_dbus_connection_send_message_with_reply_finish() to get the result of the operation.
2006  * See g_dbus_connection_send_message_with_reply_sync() for the synchronous version.
2007  *
2008  * Note that @message must be unlocked, unless @flags contain the
2009  * %G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL flag.
2010  *
2011  * See this [server][gdbus-server] and [client][gdbus-unix-fd-client]
2012  * for an example of how to use this low-level API to send and receive
2013  * UNIX file descriptors.
2014  *
2015  * Since: 2.26
2016  */
2017 void
g_dbus_connection_send_message_with_reply(GDBusConnection * connection,GDBusMessage * message,GDBusSendMessageFlags flags,gint timeout_msec,volatile guint32 * out_serial,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2018 g_dbus_connection_send_message_with_reply (GDBusConnection       *connection,
2019                                            GDBusMessage          *message,
2020                                            GDBusSendMessageFlags  flags,
2021                                            gint                   timeout_msec,
2022                                            volatile guint32      *out_serial,
2023                                            GCancellable          *cancellable,
2024                                            GAsyncReadyCallback    callback,
2025                                            gpointer               user_data)
2026 {
2027   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
2028   g_return_if_fail (G_IS_DBUS_MESSAGE (message));
2029   g_return_if_fail ((flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL) || !g_dbus_message_get_locked (message));
2030   g_return_if_fail (timeout_msec >= 0 || timeout_msec == -1);
2031 
2032   CONNECTION_LOCK (connection);
2033   g_dbus_connection_send_message_with_reply_unlocked (connection,
2034                                                       message,
2035                                                       flags,
2036                                                       timeout_msec,
2037                                                       (guint32 *) out_serial,
2038                                                       cancellable,
2039                                                       callback,
2040                                                       user_data);
2041   CONNECTION_UNLOCK (connection);
2042 }
2043 
2044 /**
2045  * g_dbus_connection_send_message_with_reply_finish:
2046  * @connection: a #GDBusConnection
2047  * @res: a #GAsyncResult obtained from the #GAsyncReadyCallback passed to
2048  *     g_dbus_connection_send_message_with_reply()
2049  * @error: teturn location for error or %NULL
2050  *
2051  * Finishes an operation started with g_dbus_connection_send_message_with_reply().
2052  *
2053  * Note that @error is only set if a local in-process error
2054  * occurred. That is to say that the returned #GDBusMessage object may
2055  * be of type %G_DBUS_MESSAGE_TYPE_ERROR. Use
2056  * g_dbus_message_to_gerror() to transcode this to a #GError.
2057  *
2058  * See this [server][gdbus-server] and [client][gdbus-unix-fd-client]
2059  * for an example of how to use this low-level API to send and receive
2060  * UNIX file descriptors.
2061  *
2062  * Returns: (transfer full): a locked #GDBusMessage or %NULL if @error is set
2063  *
2064  * Since: 2.26
2065  */
2066 GDBusMessage *
g_dbus_connection_send_message_with_reply_finish(GDBusConnection * connection,GAsyncResult * res,GError ** error)2067 g_dbus_connection_send_message_with_reply_finish (GDBusConnection  *connection,
2068                                                   GAsyncResult     *res,
2069                                                   GError          **error)
2070 {
2071   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
2072   g_return_val_if_fail (g_task_is_valid (res, connection), NULL);
2073   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2074 
2075   return g_task_propagate_pointer (G_TASK (res), error);
2076 }
2077 
2078 /* ---------------------------------------------------------------------------------------------------- */
2079 
2080 typedef struct
2081 {
2082   GAsyncResult *res;
2083   GMainContext *context;
2084   GMainLoop *loop;
2085 } SendMessageSyncData;
2086 
2087 /* Called from a user thread, lock is not held */
2088 static void
send_message_with_reply_sync_cb(GDBusConnection * connection,GAsyncResult * res,gpointer user_data)2089 send_message_with_reply_sync_cb (GDBusConnection *connection,
2090                                  GAsyncResult    *res,
2091                                  gpointer         user_data)
2092 {
2093   SendMessageSyncData *data = user_data;
2094   data->res = g_object_ref (res);
2095   g_main_loop_quit (data->loop);
2096 }
2097 
2098 /**
2099  * g_dbus_connection_send_message_with_reply_sync:
2100  * @connection: a #GDBusConnection
2101  * @message: a #GDBusMessage
2102  * @flags: flags affecting how the message is sent.
2103  * @timeout_msec: the timeout in milliseconds, -1 to use the default
2104  *     timeout or %G_MAXINT for no timeout
2105  * @out_serial: (out) (optional): return location for serial number
2106  *     assigned to @message when sending it or %NULL
2107  * @cancellable: (nullable): a #GCancellable or %NULL
2108  * @error: return location for error or %NULL
2109  *
2110  * Synchronously sends @message to the peer represented by @connection
2111  * and blocks the calling thread until a reply is received or the
2112  * timeout is reached. See g_dbus_connection_send_message_with_reply()
2113  * for the asynchronous version of this method.
2114  *
2115  * Unless @flags contain the
2116  * %G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL flag, the serial number
2117  * will be assigned by @connection and set on @message via
2118  * g_dbus_message_set_serial(). If @out_serial is not %NULL, then the
2119  * serial number used will be written to this location prior to
2120  * submitting the message to the underlying transport. While it has a `volatile`
2121  * qualifier, this is a historical artifact and the argument passed to it should
2122  * not be `volatile`.
2123  *
2124  * If @connection is closed then the operation will fail with
2125  * %G_IO_ERROR_CLOSED. If @cancellable is canceled, the operation will
2126  * fail with %G_IO_ERROR_CANCELLED. If @message is not well-formed,
2127  * the operation fails with %G_IO_ERROR_INVALID_ARGUMENT.
2128  *
2129  * Note that @error is only set if a local in-process error
2130  * occurred. That is to say that the returned #GDBusMessage object may
2131  * be of type %G_DBUS_MESSAGE_TYPE_ERROR. Use
2132  * g_dbus_message_to_gerror() to transcode this to a #GError.
2133  *
2134  * See this [server][gdbus-server] and [client][gdbus-unix-fd-client]
2135  * for an example of how to use this low-level API to send and receive
2136  * UNIX file descriptors.
2137  *
2138  * Note that @message must be unlocked, unless @flags contain the
2139  * %G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL flag.
2140  *
2141  * Returns: (transfer full): a locked #GDBusMessage that is the reply
2142  *     to @message or %NULL if @error is set
2143  *
2144  * Since: 2.26
2145  */
2146 GDBusMessage *
g_dbus_connection_send_message_with_reply_sync(GDBusConnection * connection,GDBusMessage * message,GDBusSendMessageFlags flags,gint timeout_msec,volatile guint32 * out_serial,GCancellable * cancellable,GError ** error)2147 g_dbus_connection_send_message_with_reply_sync (GDBusConnection        *connection,
2148                                                 GDBusMessage           *message,
2149                                                 GDBusSendMessageFlags   flags,
2150                                                 gint                    timeout_msec,
2151                                                 volatile guint32       *out_serial,
2152                                                 GCancellable           *cancellable,
2153                                                 GError                **error)
2154 {
2155   SendMessageSyncData data;
2156   GDBusMessage *reply;
2157 
2158   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
2159   g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
2160   g_return_val_if_fail ((flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL) || !g_dbus_message_get_locked (message), NULL);
2161   g_return_val_if_fail (timeout_msec >= 0 || timeout_msec == -1, NULL);
2162   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2163 
2164   data.res = NULL;
2165   data.context = g_main_context_new ();
2166   data.loop = g_main_loop_new (data.context, FALSE);
2167 
2168   g_main_context_push_thread_default (data.context);
2169 
2170   g_dbus_connection_send_message_with_reply (connection,
2171                                              message,
2172                                              flags,
2173                                              timeout_msec,
2174                                              out_serial,
2175                                              cancellable,
2176                                              (GAsyncReadyCallback) send_message_with_reply_sync_cb,
2177                                              &data);
2178   g_main_loop_run (data.loop);
2179   reply = g_dbus_connection_send_message_with_reply_finish (connection,
2180                                                             data.res,
2181                                                             error);
2182 
2183   g_main_context_pop_thread_default (data.context);
2184 
2185   g_main_context_unref (data.context);
2186   g_main_loop_unref (data.loop);
2187   if (data.res)
2188     g_object_unref (data.res);
2189 
2190   return reply;
2191 }
2192 
2193 /* ---------------------------------------------------------------------------------------------------- */
2194 
2195 typedef struct
2196 {
2197   guint                       id;
2198   guint                       ref_count;
2199   GDBusMessageFilterFunction  filter_function;
2200   gpointer                    user_data;
2201   GDestroyNotify              user_data_free_func;
2202   GMainContext               *context;
2203 } FilterData;
2204 
2205 /* requires CONNECTION_LOCK */
2206 static FilterData **
copy_filter_list(GPtrArray * filters)2207 copy_filter_list (GPtrArray *filters)
2208 {
2209   FilterData **copy;
2210   guint n;
2211 
2212   copy = g_new (FilterData *, filters->len + 1);
2213   for (n = 0; n < filters->len; n++)
2214     {
2215       copy[n] = filters->pdata[n];
2216       copy[n]->ref_count++;
2217     }
2218   copy[n] = NULL;
2219 
2220   return copy;
2221 }
2222 
2223 /* requires CONNECTION_LOCK */
2224 static void
free_filter_list(FilterData ** filters)2225 free_filter_list (FilterData **filters)
2226 {
2227   guint n;
2228 
2229   for (n = 0; filters[n]; n++)
2230     {
2231       filters[n]->ref_count--;
2232       if (filters[n]->ref_count == 0)
2233         {
2234           call_destroy_notify (filters[n]->context,
2235                                filters[n]->user_data_free_func,
2236                                filters[n]->user_data);
2237           g_main_context_unref (filters[n]->context);
2238           g_free (filters[n]);
2239         }
2240     }
2241   g_free (filters);
2242 }
2243 
2244 /* Called in GDBusWorker's thread - we must not block - with no lock held */
2245 static void
on_worker_message_received(GDBusWorker * worker,GDBusMessage * message,gpointer user_data)2246 on_worker_message_received (GDBusWorker  *worker,
2247                             GDBusMessage *message,
2248                             gpointer      user_data)
2249 {
2250   GDBusConnection *connection;
2251   FilterData **filters;
2252   guint n;
2253   gboolean alive;
2254 
2255   G_LOCK (message_bus_lock);
2256   alive = g_hash_table_contains (alive_connections, user_data);
2257   if (!alive)
2258     {
2259       G_UNLOCK (message_bus_lock);
2260       return;
2261     }
2262   connection = G_DBUS_CONNECTION (user_data);
2263   g_object_ref (connection);
2264   G_UNLOCK (message_bus_lock);
2265 
2266   //g_debug ("in on_worker_message_received");
2267 
2268   g_object_ref (message);
2269   g_dbus_message_lock (message);
2270 
2271   //g_debug ("boo ref_count = %d %p %p", G_OBJECT (connection)->ref_count, connection, connection->worker);
2272 
2273   /* First collect the set of callback functions */
2274   CONNECTION_LOCK (connection);
2275   filters = copy_filter_list (connection->filters);
2276   CONNECTION_UNLOCK (connection);
2277 
2278   /* then call the filters in order (without holding the lock) */
2279   for (n = 0; filters[n]; n++)
2280     {
2281       message = filters[n]->filter_function (connection,
2282                                              message,
2283                                              TRUE,
2284                                              filters[n]->user_data);
2285       if (message == NULL)
2286         break;
2287       g_dbus_message_lock (message);
2288     }
2289 
2290   CONNECTION_LOCK (connection);
2291   free_filter_list (filters);
2292   CONNECTION_UNLOCK (connection);
2293 
2294   /* Standard dispatch unless the filter ate the message - no need to
2295    * do anything if the message was altered
2296    */
2297   if (message != NULL)
2298     {
2299       GDBusMessageType message_type;
2300 
2301       message_type = g_dbus_message_get_message_type (message);
2302       if (message_type == G_DBUS_MESSAGE_TYPE_METHOD_RETURN || message_type == G_DBUS_MESSAGE_TYPE_ERROR)
2303         {
2304           guint32 reply_serial;
2305           GTask *task;
2306 
2307           reply_serial = g_dbus_message_get_reply_serial (message);
2308           CONNECTION_LOCK (connection);
2309           task = g_hash_table_lookup (connection->map_method_serial_to_task,
2310                                       GUINT_TO_POINTER (reply_serial));
2311           if (task != NULL)
2312             {
2313               /* This removes @task from @map_method_serial_to_task. */
2314               //g_debug ("delivering reply/error for serial %d for %p", reply_serial, connection);
2315               send_message_data_deliver_reply_unlocked (task, message);
2316             }
2317           else
2318             {
2319               //g_debug ("message reply/error for serial %d but no SendMessageData found for %p", reply_serial, connection);
2320             }
2321           CONNECTION_UNLOCK (connection);
2322         }
2323       else if (message_type == G_DBUS_MESSAGE_TYPE_SIGNAL)
2324         {
2325           CONNECTION_LOCK (connection);
2326           distribute_signals (connection, message);
2327           CONNECTION_UNLOCK (connection);
2328         }
2329       else if (message_type == G_DBUS_MESSAGE_TYPE_METHOD_CALL)
2330         {
2331           CONNECTION_LOCK (connection);
2332           distribute_method_call (connection, message);
2333           CONNECTION_UNLOCK (connection);
2334         }
2335     }
2336 
2337   if (message != NULL)
2338     g_object_unref (message);
2339   g_object_unref (connection);
2340 }
2341 
2342 /* Called in GDBusWorker's thread, lock is not held */
2343 static GDBusMessage *
on_worker_message_about_to_be_sent(GDBusWorker * worker,GDBusMessage * message,gpointer user_data)2344 on_worker_message_about_to_be_sent (GDBusWorker  *worker,
2345                                     GDBusMessage *message,
2346                                     gpointer      user_data)
2347 {
2348   GDBusConnection *connection;
2349   FilterData **filters;
2350   guint n;
2351   gboolean alive;
2352 
2353   G_LOCK (message_bus_lock);
2354   alive = g_hash_table_contains (alive_connections, user_data);
2355   if (!alive)
2356     {
2357       G_UNLOCK (message_bus_lock);
2358       return message;
2359     }
2360   connection = G_DBUS_CONNECTION (user_data);
2361   g_object_ref (connection);
2362   G_UNLOCK (message_bus_lock);
2363 
2364   //g_debug ("in on_worker_message_about_to_be_sent");
2365 
2366   /* First collect the set of callback functions */
2367   CONNECTION_LOCK (connection);
2368   filters = copy_filter_list (connection->filters);
2369   CONNECTION_UNLOCK (connection);
2370 
2371   /* then call the filters in order (without holding the lock) */
2372   for (n = 0; filters[n]; n++)
2373     {
2374       g_dbus_message_lock (message);
2375       message = filters[n]->filter_function (connection,
2376                                              message,
2377                                              FALSE,
2378                                              filters[n]->user_data);
2379       if (message == NULL)
2380         break;
2381     }
2382 
2383   CONNECTION_LOCK (connection);
2384   free_filter_list (filters);
2385   CONNECTION_UNLOCK (connection);
2386 
2387   g_object_unref (connection);
2388 
2389   return message;
2390 }
2391 
2392 /* called with connection lock held, in GDBusWorker thread */
2393 static gboolean
cancel_method_on_close(gpointer key,gpointer value,gpointer user_data)2394 cancel_method_on_close (gpointer key, gpointer value, gpointer user_data)
2395 {
2396   GTask *task = value;
2397   SendMessageData *data = g_task_get_task_data (task);
2398 
2399   if (data->delivered)
2400     return FALSE;
2401 
2402   g_task_return_new_error (task,
2403                            G_IO_ERROR,
2404                            G_IO_ERROR_CLOSED,
2405                            _("The connection is closed"));
2406 
2407   /* Ask send_message_with_reply_cleanup not to remove the element from the
2408    * hash table - we're in the middle of a foreach; that would be unsafe.
2409    * Instead, return TRUE from this function so that it gets removed safely.
2410    */
2411   send_message_with_reply_cleanup (task, FALSE);
2412   return TRUE;
2413 }
2414 
2415 /* Called in GDBusWorker's thread - we must not block - without lock held */
2416 static void
on_worker_closed(GDBusWorker * worker,gboolean remote_peer_vanished,GError * error,gpointer user_data)2417 on_worker_closed (GDBusWorker *worker,
2418                   gboolean     remote_peer_vanished,
2419                   GError      *error,
2420                   gpointer     user_data)
2421 {
2422   GDBusConnection *connection;
2423   gboolean alive;
2424   guint old_atomic_flags;
2425 
2426   G_LOCK (message_bus_lock);
2427   alive = g_hash_table_contains (alive_connections, user_data);
2428   if (!alive)
2429     {
2430       G_UNLOCK (message_bus_lock);
2431       return;
2432     }
2433   connection = G_DBUS_CONNECTION (user_data);
2434   g_object_ref (connection);
2435   G_UNLOCK (message_bus_lock);
2436 
2437   //g_debug ("in on_worker_closed: %s", error->message);
2438 
2439   CONNECTION_LOCK (connection);
2440   /* Even though this is atomic, we do it inside the lock to avoid breaking
2441    * assumptions in remove_match_rule(). We'd need the lock in a moment
2442    * anyway, so, no loss.
2443    */
2444   old_atomic_flags = g_atomic_int_or (&connection->atomic_flags, FLAG_CLOSED);
2445 
2446   if (!(old_atomic_flags & FLAG_CLOSED))
2447     {
2448       g_hash_table_foreach_remove (connection->map_method_serial_to_task, cancel_method_on_close, NULL);
2449       schedule_closed_unlocked (connection, remote_peer_vanished, error);
2450     }
2451   CONNECTION_UNLOCK (connection);
2452 
2453   g_object_unref (connection);
2454 }
2455 
2456 /* ---------------------------------------------------------------------------------------------------- */
2457 
2458 /* Determines the biggest set of capabilities we can support on this
2459  * connection.
2460  *
2461  * Called with the init_lock held.
2462  */
2463 static GDBusCapabilityFlags
get_offered_capabilities_max(GDBusConnection * connection)2464 get_offered_capabilities_max (GDBusConnection *connection)
2465 {
2466       GDBusCapabilityFlags ret;
2467       ret = G_DBUS_CAPABILITY_FLAGS_NONE;
2468 #ifdef G_OS_UNIX
2469       if (G_IS_UNIX_CONNECTION (connection->stream))
2470         ret |= G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING;
2471 #endif
2472       return ret;
2473 }
2474 
2475 /* Called in a user thread, lock is not held */
2476 static gboolean
initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)2477 initable_init (GInitable     *initable,
2478                GCancellable  *cancellable,
2479                GError       **error)
2480 {
2481   GDBusConnection *connection = G_DBUS_CONNECTION (initable);
2482   gboolean ret;
2483 
2484   /* This method needs to be idempotent to work with the singleton
2485    * pattern. See the docs for g_initable_init(). We implement this by
2486    * locking.
2487    *
2488    * Unfortunately we can't use the main lock since the on_worker_*()
2489    * callbacks above needs the lock during initialization (for message
2490    * bus connections we do a synchronous Hello() call on the bus).
2491    */
2492   g_mutex_lock (&connection->init_lock);
2493 
2494   ret = FALSE;
2495 
2496   /* Make this a no-op if we're already initialized (successfully or
2497    * unsuccessfully)
2498    */
2499   if ((g_atomic_int_get (&connection->atomic_flags) & FLAG_INITIALIZED))
2500     {
2501       ret = (connection->initialization_error == NULL);
2502       goto out;
2503     }
2504 
2505   /* Because of init_lock, we can't get here twice in different threads */
2506   g_assert (connection->initialization_error == NULL);
2507 
2508   /* The user can pass multiple (but mutally exclusive) construct
2509    * properties:
2510    *
2511    *  - stream (of type GIOStream)
2512    *  - address (of type gchar*)
2513    *
2514    * At the end of the day we end up with a non-NULL GIOStream
2515    * object in connection->stream.
2516    */
2517   if (connection->address != NULL)
2518     {
2519       g_assert (connection->stream == NULL);
2520 
2521       if ((connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER) ||
2522           (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS) ||
2523           (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER))
2524         {
2525           g_set_error_literal (&connection->initialization_error,
2526                                G_IO_ERROR,
2527                                G_IO_ERROR_INVALID_ARGUMENT,
2528                                _("Unsupported flags encountered when constructing a client-side connection"));
2529           goto out;
2530         }
2531 
2532       connection->stream = g_dbus_address_get_stream_sync (connection->address,
2533                                                            NULL, /* TODO: out_guid */
2534                                                            cancellable,
2535                                                            &connection->initialization_error);
2536       if (connection->stream == NULL)
2537         goto out;
2538     }
2539   else if (connection->stream != NULL)
2540     {
2541       /* nothing to do */
2542     }
2543   else
2544     {
2545       g_assert_not_reached ();
2546     }
2547 
2548   /* Authenticate the connection */
2549   if (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER)
2550     {
2551       g_assert (!(connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT));
2552       g_assert (connection->guid != NULL);
2553       connection->auth = _g_dbus_auth_new (connection->stream);
2554       if (!_g_dbus_auth_run_server (connection->auth,
2555                                     connection->authentication_observer,
2556                                     connection->guid,
2557                                     (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS),
2558                                     (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER),
2559                                     get_offered_capabilities_max (connection),
2560                                     &connection->capabilities,
2561                                     &connection->credentials,
2562                                     cancellable,
2563                                     &connection->initialization_error))
2564         goto out;
2565     }
2566   else if (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT)
2567     {
2568       g_assert (!(connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER));
2569       g_assert (connection->guid == NULL);
2570       connection->auth = _g_dbus_auth_new (connection->stream);
2571       connection->guid = _g_dbus_auth_run_client (connection->auth,
2572                                                   connection->authentication_observer,
2573                                                   get_offered_capabilities_max (connection),
2574                                                   &connection->capabilities,
2575                                                   cancellable,
2576                                                   &connection->initialization_error);
2577       if (connection->guid == NULL)
2578         goto out;
2579     }
2580 
2581   if (connection->authentication_observer != NULL)
2582     {
2583       g_object_unref (connection->authentication_observer);
2584       connection->authentication_observer = NULL;
2585     }
2586 
2587   //g_output_stream_flush (G_SOCKET_CONNECTION (connection->stream)
2588 
2589   //g_debug ("haz unix fd passing powers: %d", connection->capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
2590 
2591 #ifdef G_OS_UNIX
2592   /* We want all IO operations to be non-blocking since they happen in
2593    * the worker thread which is shared by _all_ connections.
2594    */
2595   if (G_IS_SOCKET_CONNECTION (connection->stream))
2596     {
2597       g_socket_set_blocking (g_socket_connection_get_socket (G_SOCKET_CONNECTION (connection->stream)), FALSE);
2598     }
2599 #endif
2600 
2601   G_LOCK (message_bus_lock);
2602   if (alive_connections == NULL)
2603     alive_connections = g_hash_table_new (g_direct_hash, g_direct_equal);
2604   g_hash_table_add (alive_connections, connection);
2605   G_UNLOCK (message_bus_lock);
2606 
2607   connection->worker = _g_dbus_worker_new (connection->stream,
2608                                            connection->capabilities,
2609                                            ((connection->flags & G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING) != 0),
2610                                            on_worker_message_received,
2611                                            on_worker_message_about_to_be_sent,
2612                                            on_worker_closed,
2613                                            connection);
2614 
2615   /* if a bus connection, call org.freedesktop.DBus.Hello - this is how we're getting a name */
2616   if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
2617     {
2618       GVariant *hello_result;
2619 
2620       /* we could lift this restriction by adding code in gdbusprivate.c */
2621       if (connection->flags & G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING)
2622         {
2623           g_set_error_literal (&connection->initialization_error,
2624                                G_IO_ERROR,
2625                                G_IO_ERROR_FAILED,
2626                                "Cannot use DELAY_MESSAGE_PROCESSING with MESSAGE_BUS_CONNECTION");
2627           goto out;
2628         }
2629 
2630       hello_result = g_dbus_connection_call_sync (connection,
2631                                                   "org.freedesktop.DBus", /* name */
2632                                                   "/org/freedesktop/DBus", /* path */
2633                                                   "org.freedesktop.DBus", /* interface */
2634                                                   "Hello",
2635                                                   NULL, /* parameters */
2636                                                   G_VARIANT_TYPE ("(s)"),
2637                                                   CALL_FLAGS_INITIALIZING,
2638                                                   -1,
2639                                                   NULL, /* TODO: cancellable */
2640                                                   &connection->initialization_error);
2641       if (hello_result == NULL)
2642         goto out;
2643 
2644       g_variant_get (hello_result, "(s)", &connection->bus_unique_name);
2645       g_variant_unref (hello_result);
2646       //g_debug ("unique name is '%s'", connection->bus_unique_name);
2647     }
2648 
2649   ret = TRUE;
2650  out:
2651   if (!ret)
2652     {
2653       g_assert (connection->initialization_error != NULL);
2654       g_propagate_error (error, g_error_copy (connection->initialization_error));
2655     }
2656 
2657   g_atomic_int_or (&connection->atomic_flags, FLAG_INITIALIZED);
2658   g_mutex_unlock (&connection->init_lock);
2659 
2660   return ret;
2661 }
2662 
2663 static void
initable_iface_init(GInitableIface * initable_iface)2664 initable_iface_init (GInitableIface *initable_iface)
2665 {
2666   initable_iface->init = initable_init;
2667 }
2668 
2669 /* ---------------------------------------------------------------------------------------------------- */
2670 
2671 static void
async_initable_iface_init(GAsyncInitableIface * async_initable_iface)2672 async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
2673 {
2674   /* Use default */
2675 }
2676 
2677 /* ---------------------------------------------------------------------------------------------------- */
2678 
2679 /**
2680  * g_dbus_connection_new:
2681  * @stream: a #GIOStream
2682  * @guid: (nullable): the GUID to use if authenticating as a server or %NULL
2683  * @flags: flags describing how to make the connection
2684  * @observer: (nullable): a #GDBusAuthObserver or %NULL
2685  * @cancellable: (nullable): a #GCancellable or %NULL
2686  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2687  * @user_data: the data to pass to @callback
2688  *
2689  * Asynchronously sets up a D-Bus connection for exchanging D-Bus messages
2690  * with the end represented by @stream.
2691  *
2692  * If @stream is a #GSocketConnection, then the corresponding #GSocket
2693  * will be put into non-blocking mode.
2694  *
2695  * The D-Bus connection will interact with @stream from a worker thread.
2696  * As a result, the caller should not interact with @stream after this
2697  * method has been called, except by calling g_object_unref() on it.
2698  *
2699  * If @observer is not %NULL it may be used to control the
2700  * authentication process.
2701  *
2702  * When the operation is finished, @callback will be invoked. You can
2703  * then call g_dbus_connection_new_finish() to get the result of the
2704  * operation.
2705  *
2706  * This is an asynchronous failable constructor. See
2707  * g_dbus_connection_new_sync() for the synchronous
2708  * version.
2709  *
2710  * Since: 2.26
2711  */
2712 void
g_dbus_connection_new(GIOStream * stream,const gchar * guid,GDBusConnectionFlags flags,GDBusAuthObserver * observer,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2713 g_dbus_connection_new (GIOStream            *stream,
2714                        const gchar          *guid,
2715                        GDBusConnectionFlags  flags,
2716                        GDBusAuthObserver    *observer,
2717                        GCancellable         *cancellable,
2718                        GAsyncReadyCallback   callback,
2719                        gpointer              user_data)
2720 {
2721   _g_dbus_initialize ();
2722 
2723   g_return_if_fail (G_IS_IO_STREAM (stream));
2724   g_return_if_fail ((flags & ~G_DBUS_CONNECTION_FLAGS_ALL) == 0);
2725 
2726   g_async_initable_new_async (G_TYPE_DBUS_CONNECTION,
2727                               G_PRIORITY_DEFAULT,
2728                               cancellable,
2729                               callback,
2730                               user_data,
2731                               "stream", stream,
2732                               "guid", guid,
2733                               "flags", flags,
2734                               "authentication-observer", observer,
2735                               NULL);
2736 }
2737 
2738 /**
2739  * g_dbus_connection_new_finish:
2740  * @res: a #GAsyncResult obtained from the #GAsyncReadyCallback
2741  *     passed to g_dbus_connection_new().
2742  * @error: return location for error or %NULL
2743  *
2744  * Finishes an operation started with g_dbus_connection_new().
2745  *
2746  * Returns: (transfer full): a #GDBusConnection or %NULL if @error is set. Free
2747  *     with g_object_unref().
2748  *
2749  * Since: 2.26
2750  */
2751 GDBusConnection *
g_dbus_connection_new_finish(GAsyncResult * res,GError ** error)2752 g_dbus_connection_new_finish (GAsyncResult  *res,
2753                               GError       **error)
2754 {
2755   GObject *object;
2756   GObject *source_object;
2757 
2758   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
2759   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2760 
2761   source_object = g_async_result_get_source_object (res);
2762   g_assert (source_object != NULL);
2763   object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
2764                                         res,
2765                                         error);
2766   g_object_unref (source_object);
2767   if (object != NULL)
2768     return G_DBUS_CONNECTION (object);
2769   else
2770     return NULL;
2771 }
2772 
2773 /**
2774  * g_dbus_connection_new_sync:
2775  * @stream: a #GIOStream
2776  * @guid: (nullable): the GUID to use if authenticating as a server or %NULL
2777  * @flags: flags describing how to make the connection
2778  * @observer: (nullable): a #GDBusAuthObserver or %NULL
2779  * @cancellable: (nullable): a #GCancellable or %NULL
2780  * @error: return location for error or %NULL
2781  *
2782  * Synchronously sets up a D-Bus connection for exchanging D-Bus messages
2783  * with the end represented by @stream.
2784  *
2785  * If @stream is a #GSocketConnection, then the corresponding #GSocket
2786  * will be put into non-blocking mode.
2787  *
2788  * The D-Bus connection will interact with @stream from a worker thread.
2789  * As a result, the caller should not interact with @stream after this
2790  * method has been called, except by calling g_object_unref() on it.
2791  *
2792  * If @observer is not %NULL it may be used to control the
2793  * authentication process.
2794  *
2795  * This is a synchronous failable constructor. See
2796  * g_dbus_connection_new() for the asynchronous version.
2797  *
2798  * Returns: (transfer full): a #GDBusConnection or %NULL if @error is set.
2799  *     Free with g_object_unref().
2800  *
2801  * Since: 2.26
2802  */
2803 GDBusConnection *
g_dbus_connection_new_sync(GIOStream * stream,const gchar * guid,GDBusConnectionFlags flags,GDBusAuthObserver * observer,GCancellable * cancellable,GError ** error)2804 g_dbus_connection_new_sync (GIOStream             *stream,
2805                             const gchar           *guid,
2806                             GDBusConnectionFlags   flags,
2807                             GDBusAuthObserver     *observer,
2808                             GCancellable          *cancellable,
2809                             GError               **error)
2810 {
2811   _g_dbus_initialize ();
2812   g_return_val_if_fail (G_IS_IO_STREAM (stream), NULL);
2813   g_return_val_if_fail ((flags & ~G_DBUS_CONNECTION_FLAGS_ALL) == 0, NULL);
2814   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2815   return g_initable_new (G_TYPE_DBUS_CONNECTION,
2816                          cancellable,
2817                          error,
2818                          "stream", stream,
2819                          "guid", guid,
2820                          "flags", flags,
2821                          "authentication-observer", observer,
2822                          NULL);
2823 }
2824 
2825 /* ---------------------------------------------------------------------------------------------------- */
2826 
2827 /**
2828  * g_dbus_connection_new_for_address:
2829  * @address: a D-Bus address
2830  * @flags: flags describing how to make the connection
2831  * @observer: (nullable): a #GDBusAuthObserver or %NULL
2832  * @cancellable: (nullable): a #GCancellable or %NULL
2833  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2834  * @user_data: the data to pass to @callback
2835  *
2836  * Asynchronously connects and sets up a D-Bus client connection for
2837  * exchanging D-Bus messages with an endpoint specified by @address
2838  * which must be in the
2839  * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
2840  *
2841  * This constructor can only be used to initiate client-side
2842  * connections - use g_dbus_connection_new() if you need to act as the
2843  * server. In particular, @flags cannot contain the
2844  * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
2845  * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS or
2846  * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER flags.
2847  *
2848  * When the operation is finished, @callback will be invoked. You can
2849  * then call g_dbus_connection_new_for_address_finish() to get the result of
2850  * the operation.
2851  *
2852  * If @observer is not %NULL it may be used to control the
2853  * authentication process.
2854  *
2855  * This is an asynchronous failable constructor. See
2856  * g_dbus_connection_new_for_address_sync() for the synchronous
2857  * version.
2858  *
2859  * Since: 2.26
2860  */
2861 void
g_dbus_connection_new_for_address(const gchar * address,GDBusConnectionFlags flags,GDBusAuthObserver * observer,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)2862 g_dbus_connection_new_for_address (const gchar          *address,
2863                                    GDBusConnectionFlags  flags,
2864                                    GDBusAuthObserver    *observer,
2865                                    GCancellable         *cancellable,
2866                                    GAsyncReadyCallback   callback,
2867                                    gpointer              user_data)
2868 {
2869   _g_dbus_initialize ();
2870 
2871   g_return_if_fail (address != NULL);
2872   g_return_if_fail ((flags & ~G_DBUS_CONNECTION_FLAGS_ALL) == 0);
2873 
2874   g_async_initable_new_async (G_TYPE_DBUS_CONNECTION,
2875                               G_PRIORITY_DEFAULT,
2876                               cancellable,
2877                               callback,
2878                               user_data,
2879                               "address", address,
2880                               "flags", flags,
2881                               "authentication-observer", observer,
2882                               NULL);
2883 }
2884 
2885 /**
2886  * g_dbus_connection_new_for_address_finish:
2887  * @res: a #GAsyncResult obtained from the #GAsyncReadyCallback passed
2888  *     to g_dbus_connection_new()
2889  * @error: return location for error or %NULL
2890  *
2891  * Finishes an operation started with g_dbus_connection_new_for_address().
2892  *
2893  * Returns: (transfer full): a #GDBusConnection or %NULL if @error is set.
2894  *     Free with g_object_unref().
2895  *
2896  * Since: 2.26
2897  */
2898 GDBusConnection *
g_dbus_connection_new_for_address_finish(GAsyncResult * res,GError ** error)2899 g_dbus_connection_new_for_address_finish (GAsyncResult  *res,
2900                                           GError       **error)
2901 {
2902   GObject *object;
2903   GObject *source_object;
2904 
2905   g_return_val_if_fail (G_IS_ASYNC_RESULT (res), NULL);
2906   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2907 
2908   source_object = g_async_result_get_source_object (res);
2909   g_assert (source_object != NULL);
2910   object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object),
2911                                         res,
2912                                         error);
2913   g_object_unref (source_object);
2914   if (object != NULL)
2915     return G_DBUS_CONNECTION (object);
2916   else
2917     return NULL;
2918 }
2919 
2920 /**
2921  * g_dbus_connection_new_for_address_sync:
2922  * @address: a D-Bus address
2923  * @flags: flags describing how to make the connection
2924  * @observer: (nullable): a #GDBusAuthObserver or %NULL
2925  * @cancellable: (nullable): a #GCancellable or %NULL
2926  * @error: return location for error or %NULL
2927  *
2928  * Synchronously connects and sets up a D-Bus client connection for
2929  * exchanging D-Bus messages with an endpoint specified by @address
2930  * which must be in the
2931  * [D-Bus address format](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
2932  *
2933  * This constructor can only be used to initiate client-side
2934  * connections - use g_dbus_connection_new_sync() if you need to act
2935  * as the server. In particular, @flags cannot contain the
2936  * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER,
2937  * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS or
2938  * %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER flags.
2939  *
2940  * This is a synchronous failable constructor. See
2941  * g_dbus_connection_new_for_address() for the asynchronous version.
2942  *
2943  * If @observer is not %NULL it may be used to control the
2944  * authentication process.
2945  *
2946  * Returns: (transfer full): a #GDBusConnection or %NULL if @error is set.
2947  *     Free with g_object_unref().
2948  *
2949  * Since: 2.26
2950  */
2951 GDBusConnection *
g_dbus_connection_new_for_address_sync(const gchar * address,GDBusConnectionFlags flags,GDBusAuthObserver * observer,GCancellable * cancellable,GError ** error)2952 g_dbus_connection_new_for_address_sync (const gchar           *address,
2953                                         GDBusConnectionFlags   flags,
2954                                         GDBusAuthObserver     *observer,
2955                                         GCancellable          *cancellable,
2956                                         GError               **error)
2957 {
2958   _g_dbus_initialize ();
2959 
2960   g_return_val_if_fail (address != NULL, NULL);
2961   g_return_val_if_fail ((flags & ~G_DBUS_CONNECTION_FLAGS_ALL) == 0, NULL);
2962   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2963   return g_initable_new (G_TYPE_DBUS_CONNECTION,
2964                          cancellable,
2965                          error,
2966                          "address", address,
2967                          "flags", flags,
2968                          "authentication-observer", observer,
2969                          NULL);
2970 }
2971 
2972 /* ---------------------------------------------------------------------------------------------------- */
2973 
2974 /**
2975  * g_dbus_connection_set_exit_on_close:
2976  * @connection: a #GDBusConnection
2977  * @exit_on_close: whether the process should be terminated
2978  *     when @connection is closed by the remote peer
2979  *
2980  * Sets whether the process should be terminated when @connection is
2981  * closed by the remote peer. See #GDBusConnection:exit-on-close for
2982  * more details.
2983  *
2984  * Note that this function should be used with care. Most modern UNIX
2985  * desktops tie the notion of a user session with the session bus, and expect
2986  * all of a user's applications to quit when their bus connection goes away.
2987  * If you are setting @exit_on_close to %FALSE for the shared session
2988  * bus connection, you should make sure that your application exits
2989  * when the user session ends.
2990  *
2991  * Since: 2.26
2992  */
2993 void
g_dbus_connection_set_exit_on_close(GDBusConnection * connection,gboolean exit_on_close)2994 g_dbus_connection_set_exit_on_close (GDBusConnection *connection,
2995                                      gboolean         exit_on_close)
2996 {
2997   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
2998 
2999   if (exit_on_close)
3000     g_atomic_int_or (&connection->atomic_flags, FLAG_EXIT_ON_CLOSE);
3001   else
3002     g_atomic_int_and (&connection->atomic_flags, ~FLAG_EXIT_ON_CLOSE);
3003 
3004 }
3005 
3006 /**
3007  * g_dbus_connection_get_exit_on_close:
3008  * @connection: a #GDBusConnection
3009  *
3010  * Gets whether the process is terminated when @connection is
3011  * closed by the remote peer. See
3012  * #GDBusConnection:exit-on-close for more details.
3013  *
3014  * Returns: whether the process is terminated when @connection is
3015  *     closed by the remote peer
3016  *
3017  * Since: 2.26
3018  */
3019 gboolean
g_dbus_connection_get_exit_on_close(GDBusConnection * connection)3020 g_dbus_connection_get_exit_on_close (GDBusConnection *connection)
3021 {
3022   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
3023 
3024   if (g_atomic_int_get (&connection->atomic_flags) & FLAG_EXIT_ON_CLOSE)
3025     return TRUE;
3026   else
3027     return FALSE;
3028 }
3029 
3030 /**
3031  * g_dbus_connection_get_guid:
3032  * @connection: a #GDBusConnection
3033  *
3034  * The GUID of the peer performing the role of server when
3035  * authenticating. See #GDBusConnection:guid for more details.
3036  *
3037  * Returns: (not nullable): The GUID. Do not free this string, it is owned by
3038  *     @connection.
3039  *
3040  * Since: 2.26
3041  */
3042 const gchar *
g_dbus_connection_get_guid(GDBusConnection * connection)3043 g_dbus_connection_get_guid (GDBusConnection *connection)
3044 {
3045   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
3046   return connection->guid;
3047 }
3048 
3049 /**
3050  * g_dbus_connection_get_unique_name:
3051  * @connection: a #GDBusConnection
3052  *
3053  * Gets the unique name of @connection as assigned by the message
3054  * bus. This can also be used to figure out if @connection is a
3055  * message bus connection.
3056  *
3057  * Returns: (nullable): the unique name or %NULL if @connection is not a message
3058  *     bus connection. Do not free this string, it is owned by
3059  *     @connection.
3060  *
3061  * Since: 2.26
3062  */
3063 const gchar *
g_dbus_connection_get_unique_name(GDBusConnection * connection)3064 g_dbus_connection_get_unique_name (GDBusConnection *connection)
3065 {
3066   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
3067 
3068   /* do not use g_return_val_if_fail(), we want the memory barrier */
3069   if (!check_initialized (connection))
3070     return NULL;
3071 
3072   return connection->bus_unique_name;
3073 }
3074 
3075 /**
3076  * g_dbus_connection_get_peer_credentials:
3077  * @connection: a #GDBusConnection
3078  *
3079  * Gets the credentials of the authenticated peer. This will always
3080  * return %NULL unless @connection acted as a server
3081  * (e.g. %G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER was passed)
3082  * when set up and the client passed credentials as part of the
3083  * authentication process.
3084  *
3085  * In a message bus setup, the message bus is always the server and
3086  * each application is a client. So this method will always return
3087  * %NULL for message bus clients.
3088  *
3089  * Returns: (transfer none) (nullable): a #GCredentials or %NULL if not
3090  *     available. Do not free this object, it is owned by @connection.
3091  *
3092  * Since: 2.26
3093  */
3094 GCredentials *
g_dbus_connection_get_peer_credentials(GDBusConnection * connection)3095 g_dbus_connection_get_peer_credentials (GDBusConnection *connection)
3096 {
3097   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
3098 
3099   /* do not use g_return_val_if_fail(), we want the memory barrier */
3100   if (!check_initialized (connection))
3101     return NULL;
3102 
3103   return connection->credentials;
3104 }
3105 
3106 /* ---------------------------------------------------------------------------------------------------- */
3107 
3108 static guint _global_filter_id = 1;  /* (atomic) */
3109 
3110 /**
3111  * g_dbus_connection_add_filter:
3112  * @connection: a #GDBusConnection
3113  * @filter_function: a filter function
3114  * @user_data: user data to pass to @filter_function
3115  * @user_data_free_func: function to free @user_data with when filter
3116  *     is removed or %NULL
3117  *
3118  * Adds a message filter. Filters are handlers that are run on all
3119  * incoming and outgoing messages, prior to standard dispatch. Filters
3120  * are run in the order that they were added.  The same handler can be
3121  * added as a filter more than once, in which case it will be run more
3122  * than once.  Filters added during a filter callback won't be run on
3123  * the message being processed. Filter functions are allowed to modify
3124  * and even drop messages.
3125  *
3126  * Note that filters are run in a dedicated message handling thread so
3127  * they can't block and, generally, can't do anything but signal a
3128  * worker thread. Also note that filters are rarely needed - use API
3129  * such as g_dbus_connection_send_message_with_reply(),
3130  * g_dbus_connection_signal_subscribe() or g_dbus_connection_call() instead.
3131  *
3132  * If a filter consumes an incoming message the message is not
3133  * dispatched anywhere else - not even the standard dispatch machinery
3134  * (that API such as g_dbus_connection_signal_subscribe() and
3135  * g_dbus_connection_send_message_with_reply() relies on) will see the
3136  * message. Similarly, if a filter consumes an outgoing message, the
3137  * message will not be sent to the other peer.
3138  *
3139  * If @user_data_free_func is non-%NULL, it will be called (in the
3140  * thread-default main context of the thread you are calling this
3141  * method from) at some point after @user_data is no longer
3142  * needed. (It is not guaranteed to be called synchronously when the
3143  * filter is removed, and may be called after @connection has been
3144  * destroyed.)
3145  *
3146  * Returns: a filter identifier that can be used with
3147  *     g_dbus_connection_remove_filter()
3148  *
3149  * Since: 2.26
3150  */
3151 guint
g_dbus_connection_add_filter(GDBusConnection * connection,GDBusMessageFilterFunction filter_function,gpointer user_data,GDestroyNotify user_data_free_func)3152 g_dbus_connection_add_filter (GDBusConnection            *connection,
3153                               GDBusMessageFilterFunction  filter_function,
3154                               gpointer                    user_data,
3155                               GDestroyNotify              user_data_free_func)
3156 {
3157   FilterData *data;
3158 
3159   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
3160   g_return_val_if_fail (filter_function != NULL, 0);
3161   g_return_val_if_fail (check_initialized (connection), 0);
3162 
3163   CONNECTION_LOCK (connection);
3164   data = g_new0 (FilterData, 1);
3165   data->id = (guint) g_atomic_int_add (&_global_filter_id, 1); /* TODO: overflow etc. */
3166   data->ref_count = 1;
3167   data->filter_function = filter_function;
3168   data->user_data = user_data;
3169   data->user_data_free_func = user_data_free_func;
3170   data->context = g_main_context_ref_thread_default ();
3171   g_ptr_array_add (connection->filters, data);
3172   CONNECTION_UNLOCK (connection);
3173 
3174   return data->id;
3175 }
3176 
3177 /* only called from finalize(), removes all filters */
3178 static void
purge_all_filters(GDBusConnection * connection)3179 purge_all_filters (GDBusConnection *connection)
3180 {
3181   guint n;
3182   for (n = 0; n < connection->filters->len; n++)
3183     {
3184       FilterData *data = connection->filters->pdata[n];
3185 
3186       call_destroy_notify (data->context,
3187                            data->user_data_free_func,
3188                            data->user_data);
3189       g_main_context_unref (data->context);
3190       g_free (data);
3191     }
3192 }
3193 
3194 /**
3195  * g_dbus_connection_remove_filter:
3196  * @connection: a #GDBusConnection
3197  * @filter_id: an identifier obtained from g_dbus_connection_add_filter()
3198  *
3199  * Removes a filter.
3200  *
3201  * Note that since filters run in a different thread, there is a race
3202  * condition where it is possible that the filter will be running even
3203  * after calling g_dbus_connection_remove_filter(), so you cannot just
3204  * free data that the filter might be using. Instead, you should pass
3205  * a #GDestroyNotify to g_dbus_connection_add_filter(), which will be
3206  * called when it is guaranteed that the data is no longer needed.
3207  *
3208  * Since: 2.26
3209  */
3210 void
g_dbus_connection_remove_filter(GDBusConnection * connection,guint filter_id)3211 g_dbus_connection_remove_filter (GDBusConnection *connection,
3212                                  guint            filter_id)
3213 {
3214   guint n;
3215   gboolean found;
3216   FilterData *to_destroy;
3217 
3218   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
3219   g_return_if_fail (check_initialized (connection));
3220 
3221   CONNECTION_LOCK (connection);
3222   found = FALSE;
3223   to_destroy = NULL;
3224   for (n = 0; n < connection->filters->len; n++)
3225     {
3226       FilterData *data = connection->filters->pdata[n];
3227       if (data->id == filter_id)
3228         {
3229           found = TRUE;
3230           g_ptr_array_remove_index (connection->filters, n);
3231           data->ref_count--;
3232           if (data->ref_count == 0)
3233             to_destroy = data;
3234           break;
3235         }
3236     }
3237   CONNECTION_UNLOCK (connection);
3238 
3239   /* do free without holding lock */
3240   if (to_destroy != NULL)
3241     {
3242       if (to_destroy->user_data_free_func != NULL)
3243         to_destroy->user_data_free_func (to_destroy->user_data);
3244       g_main_context_unref (to_destroy->context);
3245       g_free (to_destroy);
3246     }
3247   else if (!found)
3248     {
3249       g_warning ("g_dbus_connection_remove_filter: No filter found for filter_id %d", filter_id);
3250     }
3251 }
3252 
3253 /* ---------------------------------------------------------------------------------------------------- */
3254 
3255 typedef struct
3256 {
3257   gchar *rule;
3258   gchar *sender;
3259   gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */
3260   gchar *interface_name;
3261   gchar *member;
3262   gchar *object_path;
3263   gchar *arg0;
3264   GDBusSignalFlags flags;
3265   GPtrArray *subscribers;  /* (owned) (element-type SignalSubscriber) */
3266 } SignalData;
3267 
3268 static void
signal_data_free(SignalData * signal_data)3269 signal_data_free (SignalData *signal_data)
3270 {
3271   g_free (signal_data->rule);
3272   g_free (signal_data->sender);
3273   g_free (signal_data->sender_unique_name);
3274   g_free (signal_data->interface_name);
3275   g_free (signal_data->member);
3276   g_free (signal_data->object_path);
3277   g_free (signal_data->arg0);
3278   g_ptr_array_unref (signal_data->subscribers);
3279   g_free (signal_data);
3280 }
3281 
3282 typedef struct
3283 {
3284   /* All fields are immutable after construction. */
3285   gatomicrefcount ref_count;
3286   GDBusSignalCallback callback;
3287   gpointer user_data;
3288   GDestroyNotify user_data_free_func;
3289   guint id;
3290   GMainContext *context;
3291 } SignalSubscriber;
3292 
3293 static SignalSubscriber *
signal_subscriber_ref(SignalSubscriber * subscriber)3294 signal_subscriber_ref (SignalSubscriber *subscriber)
3295 {
3296   g_atomic_ref_count_inc (&subscriber->ref_count);
3297   return subscriber;
3298 }
3299 
3300 static void
signal_subscriber_unref(SignalSubscriber * subscriber)3301 signal_subscriber_unref (SignalSubscriber *subscriber)
3302 {
3303   if (g_atomic_ref_count_dec (&subscriber->ref_count))
3304     {
3305       /* Destroy the user data. It doesn’t matter which thread
3306        * signal_subscriber_unref() is called in (or whether it’s called with a
3307        * lock held), as call_destroy_notify() always defers to the next
3308        * #GMainContext iteration. */
3309       call_destroy_notify (subscriber->context,
3310                            subscriber->user_data_free_func,
3311                            subscriber->user_data);
3312 
3313       g_main_context_unref (subscriber->context);
3314       g_free (subscriber);
3315     }
3316 }
3317 
3318 static gchar *
args_to_rule(const gchar * sender,const gchar * interface_name,const gchar * member,const gchar * object_path,const gchar * arg0,GDBusSignalFlags flags)3319 args_to_rule (const gchar      *sender,
3320               const gchar      *interface_name,
3321               const gchar      *member,
3322               const gchar      *object_path,
3323               const gchar      *arg0,
3324               GDBusSignalFlags  flags)
3325 {
3326   GString *rule;
3327 
3328   rule = g_string_new ("type='signal'");
3329   if (flags & G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE)
3330     g_string_prepend_c (rule, '-');
3331   if (sender != NULL)
3332     g_string_append_printf (rule, ",sender='%s'", sender);
3333   if (interface_name != NULL)
3334     g_string_append_printf (rule, ",interface='%s'", interface_name);
3335   if (member != NULL)
3336     g_string_append_printf (rule, ",member='%s'", member);
3337   if (object_path != NULL)
3338     g_string_append_printf (rule, ",path='%s'", object_path);
3339 
3340   if (arg0 != NULL)
3341     {
3342       if (flags & G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH)
3343         g_string_append_printf (rule, ",arg0path='%s'", arg0);
3344       else if (flags & G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE)
3345         g_string_append_printf (rule, ",arg0namespace='%s'", arg0);
3346       else
3347         g_string_append_printf (rule, ",arg0='%s'", arg0);
3348     }
3349 
3350   return g_string_free (rule, FALSE);
3351 }
3352 
3353 static guint _global_subscriber_id = 1;  /* (atomic) */
3354 static guint _global_registration_id = 1;  /* (atomic) */
3355 static guint _global_subtree_registration_id = 1;  /* (atomic) */
3356 
3357 /* ---------------------------------------------------------------------------------------------------- */
3358 
3359 /* Called in a user thread, lock is held */
3360 static void
add_match_rule(GDBusConnection * connection,const gchar * match_rule)3361 add_match_rule (GDBusConnection *connection,
3362                 const gchar     *match_rule)
3363 {
3364   GError *error;
3365   GDBusMessage *message;
3366 
3367   if (match_rule[0] == '-')
3368     return;
3369 
3370   message = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */
3371                                             "/org/freedesktop/DBus", /* path */
3372                                             "org.freedesktop.DBus", /* interface */
3373                                             "AddMatch");
3374   g_dbus_message_set_body (message, g_variant_new ("(s)", match_rule));
3375   error = NULL;
3376   if (!g_dbus_connection_send_message_unlocked (connection,
3377                                                 message,
3378                                                 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
3379                                                 NULL,
3380                                                 &error))
3381     {
3382       g_critical ("Error while sending AddMatch() message: %s", error->message);
3383       g_error_free (error);
3384     }
3385   g_object_unref (message);
3386 }
3387 
3388 /* ---------------------------------------------------------------------------------------------------- */
3389 
3390 /* Called in a user thread, lock is held */
3391 static void
remove_match_rule(GDBusConnection * connection,const gchar * match_rule)3392 remove_match_rule (GDBusConnection *connection,
3393                    const gchar     *match_rule)
3394 {
3395   GError *error;
3396   GDBusMessage *message;
3397 
3398   if (match_rule[0] == '-')
3399     return;
3400 
3401   message = g_dbus_message_new_method_call ("org.freedesktop.DBus", /* name */
3402                                             "/org/freedesktop/DBus", /* path */
3403                                             "org.freedesktop.DBus", /* interface */
3404                                             "RemoveMatch");
3405   g_dbus_message_set_body (message, g_variant_new ("(s)", match_rule));
3406 
3407   error = NULL;
3408   if (!g_dbus_connection_send_message_unlocked (connection,
3409                                                 message,
3410                                                 G_DBUS_SEND_MESSAGE_FLAGS_NONE,
3411                                                 NULL,
3412                                                 &error))
3413     {
3414       /* If we could get G_IO_ERROR_CLOSED here, it wouldn't be reasonable to
3415        * critical; but we're holding the lock, and our caller checked whether
3416        * we were already closed, so we can't get that error.
3417        */
3418       g_critical ("Error while sending RemoveMatch() message: %s", error->message);
3419       g_error_free (error);
3420     }
3421   g_object_unref (message);
3422 }
3423 
3424 /* ---------------------------------------------------------------------------------------------------- */
3425 
3426 static gboolean
is_signal_data_for_name_lost_or_acquired(SignalData * signal_data)3427 is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
3428 {
3429   return g_strcmp0 (signal_data->sender_unique_name, "org.freedesktop.DBus") == 0 &&
3430          g_strcmp0 (signal_data->interface_name, "org.freedesktop.DBus") == 0 &&
3431          g_strcmp0 (signal_data->object_path, "/org/freedesktop/DBus") == 0 &&
3432          (g_strcmp0 (signal_data->member, "NameLost") == 0 ||
3433           g_strcmp0 (signal_data->member, "NameAcquired") == 0);
3434 }
3435 
3436 /* ---------------------------------------------------------------------------------------------------- */
3437 
3438 /**
3439  * g_dbus_connection_signal_subscribe:
3440  * @connection: a #GDBusConnection
3441  * @sender: (nullable): sender name to match on (unique or well-known name)
3442  *     or %NULL to listen from all senders
3443  * @interface_name: (nullable): D-Bus interface name to match on or %NULL to
3444  *     match on all interfaces
3445  * @member: (nullable): D-Bus signal name to match on or %NULL to match on
3446  *     all signals
3447  * @object_path: (nullable): object path to match on or %NULL to match on
3448  *     all object paths
3449  * @arg0: (nullable): contents of first string argument to match on or %NULL
3450  *     to match on all kinds of arguments
3451  * @flags: #GDBusSignalFlags describing how arg0 is used in subscribing to the
3452  *     signal
3453  * @callback: callback to invoke when there is a signal matching the requested data
3454  * @user_data: user data to pass to @callback
3455  * @user_data_free_func: (nullable): function to free @user_data with when
3456  *     subscription is removed or %NULL
3457  *
3458  * Subscribes to signals on @connection and invokes @callback with a whenever
3459  * the signal is received. Note that @callback will be invoked in the
3460  * [thread-default main context][g-main-context-push-thread-default]
3461  * of the thread you are calling this method from.
3462  *
3463  * If @connection is not a message bus connection, @sender must be
3464  * %NULL.
3465  *
3466  * If @sender is a well-known name note that @callback is invoked with
3467  * the unique name for the owner of @sender, not the well-known name
3468  * as one would expect. This is because the message bus rewrites the
3469  * name. As such, to avoid certain race conditions, users should be
3470  * tracking the name owner of the well-known name and use that when
3471  * processing the received signal.
3472  *
3473  * If one of %G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE or
3474  * %G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH are given, @arg0 is
3475  * interpreted as part of a namespace or path.  The first argument
3476  * of a signal is matched against that part as specified by D-Bus.
3477  *
3478  * If @user_data_free_func is non-%NULL, it will be called (in the
3479  * thread-default main context of the thread you are calling this
3480  * method from) at some point after @user_data is no longer
3481  * needed. (It is not guaranteed to be called synchronously when the
3482  * signal is unsubscribed from, and may be called after @connection
3483  * has been destroyed.)
3484  *
3485  * As @callback is potentially invoked in a different thread from where it’s
3486  * emitted, it’s possible for this to happen after
3487  * g_dbus_connection_signal_unsubscribe() has been called in another thread.
3488  * Due to this, @user_data should have a strong reference which is freed with
3489  * @user_data_free_func, rather than pointing to data whose lifecycle is tied
3490  * to the signal subscription. For example, if a #GObject is used to store the
3491  * subscription ID from g_dbus_connection_signal_subscribe(), a strong reference
3492  * to that #GObject must be passed to @user_data, and g_object_unref() passed to
3493  * @user_data_free_func. You are responsible for breaking the resulting
3494  * reference count cycle by explicitly unsubscribing from the signal when
3495  * dropping the last external reference to the #GObject. Alternatively, a weak
3496  * reference may be used.
3497  *
3498  * It is guaranteed that if you unsubscribe from a signal using
3499  * g_dbus_connection_signal_unsubscribe() from the same thread which made the
3500  * corresponding g_dbus_connection_signal_subscribe() call, @callback will not
3501  * be invoked after g_dbus_connection_signal_unsubscribe() returns.
3502  *
3503  * The returned subscription identifier is an opaque value which is guaranteed
3504  * to never be zero.
3505  *
3506  * This function can never fail.
3507  *
3508  * Returns: a subscription identifier that can be used with g_dbus_connection_signal_unsubscribe()
3509  *
3510  * Since: 2.26
3511  */
3512 guint
g_dbus_connection_signal_subscribe(GDBusConnection * connection,const gchar * sender,const gchar * interface_name,const gchar * member,const gchar * object_path,const gchar * arg0,GDBusSignalFlags flags,GDBusSignalCallback callback,gpointer user_data,GDestroyNotify user_data_free_func)3513 g_dbus_connection_signal_subscribe (GDBusConnection     *connection,
3514                                     const gchar         *sender,
3515                                     const gchar         *interface_name,
3516                                     const gchar         *member,
3517                                     const gchar         *object_path,
3518                                     const gchar         *arg0,
3519                                     GDBusSignalFlags     flags,
3520                                     GDBusSignalCallback  callback,
3521                                     gpointer             user_data,
3522                                     GDestroyNotify       user_data_free_func)
3523 {
3524   gchar *rule;
3525   SignalData *signal_data;
3526   SignalSubscriber *subscriber;
3527   GPtrArray *signal_data_array;
3528   const gchar *sender_unique_name;
3529 
3530   /* Right now we abort if AddMatch() fails since it can only fail with the bus being in
3531    * an OOM condition. We might want to change that but that would involve making
3532    * g_dbus_connection_signal_subscribe() asynchronous and having the call sites
3533    * handle that. And there's really no sensible way of handling this short of retrying
3534    * to add the match rule... and then there's the little thing that, hey, maybe there's
3535    * a reason the bus in an OOM condition.
3536    *
3537    * Doable, but not really sure it's worth it...
3538    */
3539 
3540   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
3541   g_return_val_if_fail (sender == NULL || (g_dbus_is_name (sender) && (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)), 0);
3542   g_return_val_if_fail (interface_name == NULL || g_dbus_is_interface_name (interface_name), 0);
3543   g_return_val_if_fail (member == NULL || g_dbus_is_member_name (member), 0);
3544   g_return_val_if_fail (object_path == NULL || g_variant_is_object_path (object_path), 0);
3545   g_return_val_if_fail (callback != NULL, 0);
3546   g_return_val_if_fail (check_initialized (connection), 0);
3547   g_return_val_if_fail (!((flags & G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH) && (flags & G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE)), 0);
3548   g_return_val_if_fail (!(arg0 == NULL && (flags & (G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH | G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE))), 0);
3549 
3550   CONNECTION_LOCK (connection);
3551 
3552   /* If G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE was specified, we will end up
3553    * with a '-' character to prefix the rule (which will otherwise be
3554    * normal).
3555    *
3556    * This allows us to hash the rule and do our lifecycle tracking in
3557    * the usual way, but the '-' prevents the match rule from ever
3558    * actually being send to the bus (either for add or remove).
3559    */
3560   rule = args_to_rule (sender, interface_name, member, object_path, arg0, flags);
3561 
3562   if (sender != NULL && (g_dbus_is_unique_name (sender) || g_strcmp0 (sender, "org.freedesktop.DBus") == 0))
3563     sender_unique_name = sender;
3564   else
3565     sender_unique_name = "";
3566 
3567   subscriber = g_new0 (SignalSubscriber, 1);
3568   subscriber->ref_count = 1;
3569   subscriber->callback = callback;
3570   subscriber->user_data = user_data;
3571   subscriber->user_data_free_func = user_data_free_func;
3572   subscriber->id = (guint) g_atomic_int_add (&_global_subscriber_id, 1); /* TODO: overflow etc. */
3573   subscriber->context = g_main_context_ref_thread_default ();
3574 
3575   /* see if we've already have this rule */
3576   signal_data = g_hash_table_lookup (connection->map_rule_to_signal_data, rule);
3577   if (signal_data != NULL)
3578     {
3579       g_ptr_array_add (signal_data->subscribers, subscriber);
3580       g_free (rule);
3581       goto out;
3582     }
3583 
3584   signal_data = g_new0 (SignalData, 1);
3585   signal_data->rule                  = rule;
3586   signal_data->sender                = g_strdup (sender);
3587   signal_data->sender_unique_name    = g_strdup (sender_unique_name);
3588   signal_data->interface_name        = g_strdup (interface_name);
3589   signal_data->member                = g_strdup (member);
3590   signal_data->object_path           = g_strdup (object_path);
3591   signal_data->arg0                  = g_strdup (arg0);
3592   signal_data->flags                 = flags;
3593   signal_data->subscribers           = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref);
3594   g_ptr_array_add (signal_data->subscribers, subscriber);
3595 
3596   g_hash_table_insert (connection->map_rule_to_signal_data,
3597                        signal_data->rule,
3598                        signal_data);
3599 
3600   /* Add the match rule to the bus...
3601    *
3602    * Avoid adding match rules for NameLost and NameAcquired messages - the bus will
3603    * always send such messages to us.
3604    */
3605   if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
3606     {
3607       if (!is_signal_data_for_name_lost_or_acquired (signal_data))
3608         add_match_rule (connection, signal_data->rule);
3609     }
3610 
3611   signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
3612                                            signal_data->sender_unique_name);
3613   if (signal_data_array == NULL)
3614     {
3615       signal_data_array = g_ptr_array_new ();
3616       g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array,
3617                            g_strdup (signal_data->sender_unique_name),
3618                            signal_data_array);
3619     }
3620   g_ptr_array_add (signal_data_array, signal_data);
3621 
3622  out:
3623   g_hash_table_insert (connection->map_id_to_signal_data,
3624                        GUINT_TO_POINTER (subscriber->id),
3625                        signal_data);
3626 
3627   CONNECTION_UNLOCK (connection);
3628 
3629   return subscriber->id;
3630 }
3631 
3632 /* ---------------------------------------------------------------------------------------------------- */
3633 
3634 /* called in any thread */
3635 /* must hold lock when calling this (except if connection->finalizing is TRUE)
3636  * returns the number of removed subscribers */
3637 static guint
unsubscribe_id_internal(GDBusConnection * connection,guint subscription_id)3638 unsubscribe_id_internal (GDBusConnection *connection,
3639                          guint            subscription_id)
3640 {
3641   SignalData *signal_data;
3642   GPtrArray *signal_data_array;
3643   guint n;
3644   guint n_removed = 0;
3645 
3646   signal_data = g_hash_table_lookup (connection->map_id_to_signal_data,
3647                                      GUINT_TO_POINTER (subscription_id));
3648   if (signal_data == NULL)
3649     {
3650       /* Don't warn here, we may have thrown all subscriptions out when the connection was closed */
3651       goto out;
3652     }
3653 
3654   for (n = 0; n < signal_data->subscribers->len; n++)
3655     {
3656       SignalSubscriber *subscriber = signal_data->subscribers->pdata[n];
3657 
3658       if (subscriber->id != subscription_id)
3659         continue;
3660 
3661       /* It’s OK to rearrange the array order using the ‘fast’ #GPtrArray
3662        * removal functions, since we’re going to exit the loop below anyway — we
3663        * never move on to the next element. Secondly, subscription IDs are
3664        * guaranteed to be unique. */
3665       g_warn_if_fail (g_hash_table_remove (connection->map_id_to_signal_data,
3666                                            GUINT_TO_POINTER (subscription_id)));
3667       n_removed++;
3668       g_ptr_array_remove_index_fast (signal_data->subscribers, n);
3669 
3670       if (signal_data->subscribers->len == 0)
3671         {
3672           g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule));
3673 
3674           signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
3675                                                    signal_data->sender_unique_name);
3676           g_warn_if_fail (signal_data_array != NULL);
3677           g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data));
3678 
3679           if (signal_data_array->len == 0)
3680             {
3681               g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array,
3682                                                    signal_data->sender_unique_name));
3683             }
3684 
3685           /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */
3686           if ((connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) &&
3687               !is_signal_data_for_name_lost_or_acquired (signal_data) &&
3688               !g_dbus_connection_is_closed (connection) &&
3689               !connection->finalizing)
3690             {
3691               /* The check for g_dbus_connection_is_closed() means that
3692                * sending the RemoveMatch message can't fail with
3693                * G_IO_ERROR_CLOSED, because we're holding the lock,
3694                * so on_worker_closed() can't happen between the check we just
3695                * did, and releasing the lock later.
3696                */
3697               remove_match_rule (connection, signal_data->rule);
3698             }
3699 
3700           signal_data_free (signal_data);
3701         }
3702 
3703       goto out;
3704     }
3705 
3706   g_assert_not_reached ();
3707 
3708  out:
3709   return n_removed;
3710 }
3711 
3712 /**
3713  * g_dbus_connection_signal_unsubscribe:
3714  * @connection: a #GDBusConnection
3715  * @subscription_id: a subscription id obtained from
3716  *     g_dbus_connection_signal_subscribe()
3717  *
3718  * Unsubscribes from signals.
3719  *
3720  * Note that there may still be D-Bus traffic to process (relating to this
3721  * signal subscription) in the current thread-default #GMainContext after this
3722  * function has returned. You should continue to iterate the #GMainContext
3723  * until the #GDestroyNotify function passed to
3724  * g_dbus_connection_signal_subscribe() is called, in order to avoid memory
3725  * leaks through callbacks queued on the #GMainContext after it’s stopped being
3726  * iterated.
3727  *
3728  * Since: 2.26
3729  */
3730 void
g_dbus_connection_signal_unsubscribe(GDBusConnection * connection,guint subscription_id)3731 g_dbus_connection_signal_unsubscribe (GDBusConnection *connection,
3732                                       guint            subscription_id)
3733 {
3734   guint n_subscribers_removed G_GNUC_UNUSED  /* when compiling with G_DISABLE_ASSERT */;
3735 
3736   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
3737   g_return_if_fail (check_initialized (connection));
3738 
3739   CONNECTION_LOCK (connection);
3740   n_subscribers_removed = unsubscribe_id_internal (connection, subscription_id);
3741   CONNECTION_UNLOCK (connection);
3742 
3743   /* invariant */
3744   g_assert (n_subscribers_removed == 0 || n_subscribers_removed == 1);
3745 }
3746 
3747 /* ---------------------------------------------------------------------------------------------------- */
3748 
3749 typedef struct
3750 {
3751   SignalSubscriber    *subscriber;  /* (owned) */
3752   GDBusMessage        *message;
3753   GDBusConnection     *connection;
3754   const gchar         *sender;  /* (nullable) for peer-to-peer connections */
3755   const gchar         *path;
3756   const gchar         *interface;
3757   const gchar         *member;
3758 } SignalInstance;
3759 
3760 /* called on delivery thread (e.g. where g_dbus_connection_signal_subscribe() was called) with
3761  * no locks held
3762  */
3763 static gboolean
emit_signal_instance_in_idle_cb(gpointer data)3764 emit_signal_instance_in_idle_cb (gpointer data)
3765 {
3766   SignalInstance *signal_instance = data;
3767   GVariant *parameters;
3768   gboolean has_subscription;
3769 
3770   parameters = g_dbus_message_get_body (signal_instance->message);
3771   if (parameters == NULL)
3772     {
3773       parameters = g_variant_new ("()");
3774       g_variant_ref_sink (parameters);
3775     }
3776   else
3777     {
3778       g_variant_ref_sink (parameters);
3779     }
3780 
3781 #if 0
3782   g_print ("in emit_signal_instance_in_idle_cb (id=%d sender=%s path=%s interface=%s member=%s params=%s)\n",
3783            signal_instance->subscriber->id,
3784            signal_instance->sender,
3785            signal_instance->path,
3786            signal_instance->interface,
3787            signal_instance->member,
3788            g_variant_print (parameters, TRUE));
3789 #endif
3790 
3791   /* Careful here, don't do the callback if we no longer has the subscription */
3792   CONNECTION_LOCK (signal_instance->connection);
3793   has_subscription = FALSE;
3794   if (g_hash_table_lookup (signal_instance->connection->map_id_to_signal_data,
3795                            GUINT_TO_POINTER (signal_instance->subscriber->id)) != NULL)
3796     has_subscription = TRUE;
3797   CONNECTION_UNLOCK (signal_instance->connection);
3798 
3799   if (has_subscription)
3800     signal_instance->subscriber->callback (signal_instance->connection,
3801                                            signal_instance->sender,
3802                                            signal_instance->path,
3803                                            signal_instance->interface,
3804                                            signal_instance->member,
3805                                            parameters,
3806                                            signal_instance->subscriber->user_data);
3807 
3808   g_variant_unref (parameters);
3809 
3810   return FALSE;
3811 }
3812 
3813 static void
signal_instance_free(SignalInstance * signal_instance)3814 signal_instance_free (SignalInstance *signal_instance)
3815 {
3816   g_object_unref (signal_instance->message);
3817   g_object_unref (signal_instance->connection);
3818   signal_subscriber_unref (signal_instance->subscriber);
3819   g_free (signal_instance);
3820 }
3821 
3822 static gboolean
namespace_rule_matches(const gchar * namespace,const gchar * name)3823 namespace_rule_matches (const gchar *namespace,
3824                         const gchar *name)
3825 {
3826   gint len_namespace;
3827   gint len_name;
3828 
3829   len_namespace = strlen (namespace);
3830   len_name = strlen (name);
3831 
3832   if (len_name < len_namespace)
3833     return FALSE;
3834 
3835   if (memcmp (namespace, name, len_namespace) != 0)
3836     return FALSE;
3837 
3838   return len_namespace == len_name || name[len_namespace] == '.';
3839 }
3840 
3841 static gboolean
path_rule_matches(const gchar * path_a,const gchar * path_b)3842 path_rule_matches (const gchar *path_a,
3843                    const gchar *path_b)
3844 {
3845   gint len_a, len_b;
3846 
3847   len_a = strlen (path_a);
3848   len_b = strlen (path_b);
3849 
3850   if (len_a < len_b && (len_a == 0 || path_a[len_a - 1] != '/'))
3851     return FALSE;
3852 
3853   if (len_b < len_a && (len_b == 0 || path_b[len_b - 1] != '/'))
3854     return FALSE;
3855 
3856   return memcmp (path_a, path_b, MIN (len_a, len_b)) == 0;
3857 }
3858 
3859 /* called in GDBusWorker thread WITH lock held
3860  *
3861  * @sender is (nullable) for peer-to-peer connections */
3862 static void
schedule_callbacks(GDBusConnection * connection,GPtrArray * signal_data_array,GDBusMessage * message,const gchar * sender)3863 schedule_callbacks (GDBusConnection *connection,
3864                     GPtrArray       *signal_data_array,
3865                     GDBusMessage    *message,
3866                     const gchar     *sender)
3867 {
3868   guint n, m;
3869   const gchar *interface;
3870   const gchar *member;
3871   const gchar *path;
3872   const gchar *arg0;
3873 
3874   interface = NULL;
3875   member = NULL;
3876   path = NULL;
3877   arg0 = NULL;
3878 
3879   interface = g_dbus_message_get_interface (message);
3880   member = g_dbus_message_get_member (message);
3881   path = g_dbus_message_get_path (message);
3882   arg0 = g_dbus_message_get_arg0 (message);
3883 
3884 #if 0
3885   g_print ("In schedule_callbacks:\n"
3886            "  sender    = '%s'\n"
3887            "  interface = '%s'\n"
3888            "  member    = '%s'\n"
3889            "  path      = '%s'\n"
3890            "  arg0      = '%s'\n",
3891            sender,
3892            interface,
3893            member,
3894            path,
3895            arg0);
3896 #endif
3897 
3898   /* TODO: if this is slow, then we can change signal_data_array into
3899    *       map_object_path_to_signal_data_array or something.
3900    */
3901   for (n = 0; n < signal_data_array->len; n++)
3902     {
3903       SignalData *signal_data = signal_data_array->pdata[n];
3904 
3905       if (signal_data->interface_name != NULL && g_strcmp0 (signal_data->interface_name, interface) != 0)
3906         continue;
3907 
3908       if (signal_data->member != NULL && g_strcmp0 (signal_data->member, member) != 0)
3909         continue;
3910 
3911       if (signal_data->object_path != NULL && g_strcmp0 (signal_data->object_path, path) != 0)
3912         continue;
3913 
3914       if (signal_data->arg0 != NULL)
3915         {
3916           if (arg0 == NULL)
3917             continue;
3918 
3919           if (signal_data->flags & G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE)
3920             {
3921               if (!namespace_rule_matches (signal_data->arg0, arg0))
3922                 continue;
3923             }
3924           else if (signal_data->flags & G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH)
3925             {
3926               if (!path_rule_matches (signal_data->arg0, arg0))
3927                 continue;
3928             }
3929           else if (!g_str_equal (signal_data->arg0, arg0))
3930             continue;
3931         }
3932 
3933       for (m = 0; m < signal_data->subscribers->len; m++)
3934         {
3935           SignalSubscriber *subscriber = signal_data->subscribers->pdata[m];
3936           GSource *idle_source;
3937           SignalInstance *signal_instance;
3938 
3939           signal_instance = g_new0 (SignalInstance, 1);
3940           signal_instance->subscriber = signal_subscriber_ref (subscriber);
3941           signal_instance->message = g_object_ref (message);
3942           signal_instance->connection = g_object_ref (connection);
3943           signal_instance->sender = sender;
3944           signal_instance->path = path;
3945           signal_instance->interface = interface;
3946           signal_instance->member = member;
3947 
3948           idle_source = g_idle_source_new ();
3949           g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
3950           g_source_set_callback (idle_source,
3951                                  emit_signal_instance_in_idle_cb,
3952                                  signal_instance,
3953                                  (GDestroyNotify) signal_instance_free);
3954           g_source_set_name (idle_source, "[gio] emit_signal_instance_in_idle_cb");
3955           g_source_attach (idle_source, subscriber->context);
3956           g_source_unref (idle_source);
3957         }
3958     }
3959 }
3960 
3961 /* called in GDBusWorker thread with lock held */
3962 static void
distribute_signals(GDBusConnection * connection,GDBusMessage * message)3963 distribute_signals (GDBusConnection *connection,
3964                     GDBusMessage    *message)
3965 {
3966   GPtrArray *signal_data_array;
3967   const gchar *sender;
3968 
3969   sender = g_dbus_message_get_sender (message);
3970 
3971   if (G_UNLIKELY (_g_dbus_debug_signal ()))
3972     {
3973       _g_dbus_debug_print_lock ();
3974       g_print ("========================================================================\n"
3975                "GDBus-debug:Signal:\n"
3976                " <<<< RECEIVED SIGNAL %s.%s\n"
3977                "      on object %s\n"
3978                "      sent by name %s\n",
3979                g_dbus_message_get_interface (message),
3980                g_dbus_message_get_member (message),
3981                g_dbus_message_get_path (message),
3982                sender != NULL ? sender : "(none)");
3983       _g_dbus_debug_print_unlock ();
3984     }
3985 
3986   /* collect subscribers that match on sender */
3987   if (sender != NULL)
3988     {
3989       signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, sender);
3990       if (signal_data_array != NULL)
3991         schedule_callbacks (connection, signal_data_array, message, sender);
3992     }
3993 
3994   /* collect subscribers not matching on sender */
3995   signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, "");
3996   if (signal_data_array != NULL)
3997     schedule_callbacks (connection, signal_data_array, message, sender);
3998 }
3999 
4000 /* ---------------------------------------------------------------------------------------------------- */
4001 
4002 /* only called from finalize(), removes all subscriptions */
4003 static void
purge_all_signal_subscriptions(GDBusConnection * connection)4004 purge_all_signal_subscriptions (GDBusConnection *connection)
4005 {
4006   GHashTableIter iter;
4007   gpointer key;
4008   GArray *ids;
4009   guint n;
4010 
4011   ids = g_array_new (FALSE, FALSE, sizeof (guint));
4012   g_hash_table_iter_init (&iter, connection->map_id_to_signal_data);
4013   while (g_hash_table_iter_next (&iter, &key, NULL))
4014     {
4015       guint subscription_id = GPOINTER_TO_UINT (key);
4016       g_array_append_val (ids, subscription_id);
4017     }
4018 
4019   for (n = 0; n < ids->len; n++)
4020     {
4021       guint subscription_id = g_array_index (ids, guint, n);
4022       unsubscribe_id_internal (connection, subscription_id);
4023     }
4024   g_array_free (ids, TRUE);
4025 }
4026 
4027 /* ---------------------------------------------------------------------------------------------------- */
4028 
4029 static GDBusInterfaceVTable *
_g_dbus_interface_vtable_copy(const GDBusInterfaceVTable * vtable)4030 _g_dbus_interface_vtable_copy (const GDBusInterfaceVTable *vtable)
4031 {
4032   /* Don't waste memory by copying padding - remember to update this
4033    * when changing struct _GDBusInterfaceVTable in gdbusconnection.h
4034    */
4035   return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer));
4036 }
4037 
4038 static void
_g_dbus_interface_vtable_free(GDBusInterfaceVTable * vtable)4039 _g_dbus_interface_vtable_free (GDBusInterfaceVTable *vtable)
4040 {
4041   g_free (vtable);
4042 }
4043 
4044 /* ---------------------------------------------------------------------------------------------------- */
4045 
4046 static GDBusSubtreeVTable *
_g_dbus_subtree_vtable_copy(const GDBusSubtreeVTable * vtable)4047 _g_dbus_subtree_vtable_copy (const GDBusSubtreeVTable *vtable)
4048 {
4049   /* Don't waste memory by copying padding - remember to update this
4050    * when changing struct _GDBusSubtreeVTable in gdbusconnection.h
4051    */
4052   return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer));
4053 }
4054 
4055 static void
_g_dbus_subtree_vtable_free(GDBusSubtreeVTable * vtable)4056 _g_dbus_subtree_vtable_free (GDBusSubtreeVTable *vtable)
4057 {
4058   g_free (vtable);
4059 }
4060 
4061 /* ---------------------------------------------------------------------------------------------------- */
4062 
4063 struct ExportedObject
4064 {
4065   gchar *object_path;
4066   GDBusConnection *connection;
4067 
4068   /* maps gchar* -> ExportedInterface* */
4069   GHashTable *map_if_name_to_ei;
4070 };
4071 
4072 /* only called with lock held */
4073 static void
exported_object_free(ExportedObject * eo)4074 exported_object_free (ExportedObject *eo)
4075 {
4076   g_free (eo->object_path);
4077   g_hash_table_unref (eo->map_if_name_to_ei);
4078   g_free (eo);
4079 }
4080 
4081 typedef struct
4082 {
4083   ExportedObject *eo;
4084 
4085   guint                       id;
4086   gchar                      *interface_name;
4087   GDBusInterfaceVTable       *vtable;
4088   GDBusInterfaceInfo         *interface_info;
4089 
4090   GMainContext               *context;
4091   gpointer                    user_data;
4092   GDestroyNotify              user_data_free_func;
4093 } ExportedInterface;
4094 
4095 /* called with lock held */
4096 static void
exported_interface_free(ExportedInterface * ei)4097 exported_interface_free (ExportedInterface *ei)
4098 {
4099   g_dbus_interface_info_cache_release (ei->interface_info);
4100   g_dbus_interface_info_unref ((GDBusInterfaceInfo *) ei->interface_info);
4101 
4102   call_destroy_notify (ei->context,
4103                        ei->user_data_free_func,
4104                        ei->user_data);
4105 
4106   g_main_context_unref (ei->context);
4107 
4108   g_free (ei->interface_name);
4109   _g_dbus_interface_vtable_free (ei->vtable);
4110   g_free (ei);
4111 }
4112 
4113 /* ---------------------------------------------------------------------------------------------------- */
4114 
4115 /* Convenience function to check if @registration_id (if not zero) or
4116  * @subtree_registration_id (if not zero) has been unregistered. If
4117  * so, returns %TRUE.
4118  *
4119  * May be called by any thread. Caller must *not* hold lock.
4120  */
4121 static gboolean
has_object_been_unregistered(GDBusConnection * connection,guint registration_id,guint subtree_registration_id)4122 has_object_been_unregistered (GDBusConnection  *connection,
4123                               guint             registration_id,
4124                               guint             subtree_registration_id)
4125 {
4126   gboolean ret;
4127 
4128   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
4129 
4130   ret = FALSE;
4131 
4132   CONNECTION_LOCK (connection);
4133   if (registration_id != 0 && g_hash_table_lookup (connection->map_id_to_ei,
4134                                                    GUINT_TO_POINTER (registration_id)) == NULL)
4135     {
4136       ret = TRUE;
4137     }
4138   else if (subtree_registration_id != 0 && g_hash_table_lookup (connection->map_id_to_es,
4139                                                                 GUINT_TO_POINTER (subtree_registration_id)) == NULL)
4140     {
4141       ret = TRUE;
4142     }
4143   CONNECTION_UNLOCK (connection);
4144 
4145   return ret;
4146 }
4147 
4148 /* ---------------------------------------------------------------------------------------------------- */
4149 
4150 typedef struct
4151 {
4152   GDBusConnection *connection;
4153   GDBusMessage *message;
4154   gpointer user_data;
4155   const gchar *property_name;
4156   const GDBusInterfaceVTable *vtable;
4157   GDBusInterfaceInfo *interface_info;
4158   const GDBusPropertyInfo *property_info;
4159   guint registration_id;
4160   guint subtree_registration_id;
4161 } PropertyData;
4162 
4163 static void
property_data_free(PropertyData * data)4164 property_data_free (PropertyData *data)
4165 {
4166   g_object_unref (data->connection);
4167   g_object_unref (data->message);
4168   g_free (data);
4169 }
4170 
4171 /* called in thread where object was registered - no locks held */
4172 static gboolean
invoke_get_property_in_idle_cb(gpointer _data)4173 invoke_get_property_in_idle_cb (gpointer _data)
4174 {
4175   PropertyData *data = _data;
4176   GVariant *value;
4177   GError *error;
4178   GDBusMessage *reply;
4179 
4180   if (has_object_been_unregistered (data->connection,
4181                                     data->registration_id,
4182                                     data->subtree_registration_id))
4183     {
4184       reply = g_dbus_message_new_method_error (data->message,
4185                                                "org.freedesktop.DBus.Error.UnknownMethod",
4186                                                _("No such interface “org.freedesktop.DBus.Properties” on object at path %s"),
4187                                                g_dbus_message_get_path (data->message));
4188       g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4189       g_object_unref (reply);
4190       goto out;
4191     }
4192 
4193   error = NULL;
4194   value = data->vtable->get_property (data->connection,
4195                                       g_dbus_message_get_sender (data->message),
4196                                       g_dbus_message_get_path (data->message),
4197                                       data->interface_info->name,
4198                                       data->property_name,
4199                                       &error,
4200                                       data->user_data);
4201 
4202 
4203   if (value != NULL)
4204     {
4205       g_assert_no_error (error);
4206 
4207       g_variant_take_ref (value);
4208       reply = g_dbus_message_new_method_reply (data->message);
4209       g_dbus_message_set_body (reply, g_variant_new ("(v)", value));
4210       g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4211       g_variant_unref (value);
4212       g_object_unref (reply);
4213     }
4214   else
4215     {
4216       gchar *dbus_error_name;
4217       g_assert (error != NULL);
4218       dbus_error_name = g_dbus_error_encode_gerror (error);
4219       reply = g_dbus_message_new_method_error_literal (data->message,
4220                                                        dbus_error_name,
4221                                                        error->message);
4222       g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4223       g_free (dbus_error_name);
4224       g_error_free (error);
4225       g_object_unref (reply);
4226     }
4227 
4228  out:
4229   return FALSE;
4230 }
4231 
4232 /* called in thread where object was registered - no locks held */
4233 static gboolean
invoke_set_property_in_idle_cb(gpointer _data)4234 invoke_set_property_in_idle_cb (gpointer _data)
4235 {
4236   PropertyData *data = _data;
4237   GError *error;
4238   GDBusMessage *reply;
4239   GVariant *value;
4240 
4241   error = NULL;
4242   value = NULL;
4243 
4244   g_variant_get (g_dbus_message_get_body (data->message),
4245                  "(ssv)",
4246                  NULL,
4247                  NULL,
4248                  &value);
4249 
4250   if (!data->vtable->set_property (data->connection,
4251                                    g_dbus_message_get_sender (data->message),
4252                                    g_dbus_message_get_path (data->message),
4253                                    data->interface_info->name,
4254                                    data->property_name,
4255                                    value,
4256                                    &error,
4257                                    data->user_data))
4258     {
4259       gchar *dbus_error_name;
4260       g_assert (error != NULL);
4261       dbus_error_name = g_dbus_error_encode_gerror (error);
4262       reply = g_dbus_message_new_method_error_literal (data->message,
4263                                                        dbus_error_name,
4264                                                        error->message);
4265       g_free (dbus_error_name);
4266       g_error_free (error);
4267     }
4268   else
4269     {
4270       reply = g_dbus_message_new_method_reply (data->message);
4271     }
4272 
4273   g_assert (reply != NULL);
4274   g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4275   g_object_unref (reply);
4276   g_variant_unref (value);
4277 
4278   return FALSE;
4279 }
4280 
4281 /* called in any thread with connection's lock held */
4282 static gboolean
validate_and_maybe_schedule_property_getset(GDBusConnection * connection,GDBusMessage * message,guint registration_id,guint subtree_registration_id,gboolean is_get,GDBusInterfaceInfo * interface_info,const GDBusInterfaceVTable * vtable,GMainContext * main_context,gpointer user_data)4283 validate_and_maybe_schedule_property_getset (GDBusConnection            *connection,
4284                                              GDBusMessage               *message,
4285                                              guint                       registration_id,
4286                                              guint                       subtree_registration_id,
4287                                              gboolean                    is_get,
4288                                              GDBusInterfaceInfo         *interface_info,
4289                                              const GDBusInterfaceVTable *vtable,
4290                                              GMainContext               *main_context,
4291                                              gpointer                    user_data)
4292 {
4293   gboolean handled;
4294   const char *interface_name;
4295   const char *property_name;
4296   const GDBusPropertyInfo *property_info;
4297   GSource *idle_source;
4298   PropertyData *property_data;
4299   GDBusMessage *reply;
4300 
4301   handled = FALSE;
4302 
4303   if (is_get)
4304     g_variant_get (g_dbus_message_get_body (message),
4305                    "(&s&s)",
4306                    &interface_name,
4307                    &property_name);
4308   else
4309     g_variant_get (g_dbus_message_get_body (message),
4310                    "(&s&sv)",
4311                    &interface_name,
4312                    &property_name,
4313                    NULL);
4314 
4315   if (vtable == NULL)
4316     goto out;
4317 
4318   /* Check that the property exists - if not fail with org.freedesktop.DBus.Error.InvalidArgs
4319    */
4320   property_info = NULL;
4321 
4322   /* TODO: the cost of this is O(n) - it might be worth caching the result */
4323   property_info = g_dbus_interface_info_lookup_property (interface_info, property_name);
4324   if (property_info == NULL)
4325     {
4326       reply = g_dbus_message_new_method_error (message,
4327                                                "org.freedesktop.DBus.Error.InvalidArgs",
4328                                                _("No such property “%s”"),
4329                                                property_name);
4330       g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4331       g_object_unref (reply);
4332       handled = TRUE;
4333       goto out;
4334     }
4335 
4336   if (is_get && !(property_info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE))
4337     {
4338       reply = g_dbus_message_new_method_error (message,
4339                                                "org.freedesktop.DBus.Error.InvalidArgs",
4340                                                _("Property “%s” is not readable"),
4341                                                property_name);
4342       g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4343       g_object_unref (reply);
4344       handled = TRUE;
4345       goto out;
4346     }
4347   else if (!is_get && !(property_info->flags & G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
4348     {
4349       reply = g_dbus_message_new_method_error (message,
4350                                                "org.freedesktop.DBus.Error.InvalidArgs",
4351                                                _("Property “%s” is not writable"),
4352                                                property_name);
4353       g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4354       g_object_unref (reply);
4355       handled = TRUE;
4356       goto out;
4357     }
4358 
4359   if (!is_get)
4360     {
4361       GVariant *value;
4362 
4363       /* Fail with org.freedesktop.DBus.Error.InvalidArgs if the type
4364        * of the given value is wrong
4365        */
4366       g_variant_get_child (g_dbus_message_get_body (message), 2, "v", &value);
4367       if (g_strcmp0 (g_variant_get_type_string (value), property_info->signature) != 0)
4368         {
4369           reply = g_dbus_message_new_method_error (message,
4370                                                    "org.freedesktop.DBus.Error.InvalidArgs",
4371                                                    _("Error setting property “%s”: Expected type “%s” but got “%s”"),
4372                                                    property_name, property_info->signature,
4373                                                    g_variant_get_type_string (value));
4374           g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4375           g_variant_unref (value);
4376           g_object_unref (reply);
4377           handled = TRUE;
4378           goto out;
4379         }
4380 
4381       g_variant_unref (value);
4382     }
4383 
4384   /* If the vtable pointer for get_property() resp. set_property() is
4385    * NULL then dispatch the call via the method_call() handler.
4386    */
4387   if (is_get)
4388     {
4389       if (vtable->get_property == NULL)
4390         {
4391           schedule_method_call (connection, message, registration_id, subtree_registration_id,
4392                                 interface_info, NULL, property_info, g_dbus_message_get_body (message),
4393                                 vtable, main_context, user_data);
4394           handled = TRUE;
4395           goto out;
4396         }
4397     }
4398   else
4399     {
4400       if (vtable->set_property == NULL)
4401         {
4402           schedule_method_call (connection, message, registration_id, subtree_registration_id,
4403                                 interface_info, NULL, property_info, g_dbus_message_get_body (message),
4404                                 vtable, main_context, user_data);
4405           handled = TRUE;
4406           goto out;
4407         }
4408     }
4409 
4410   /* ok, got the property info - call user code in an idle handler */
4411   property_data = g_new0 (PropertyData, 1);
4412   property_data->connection = g_object_ref (connection);
4413   property_data->message = g_object_ref (message);
4414   property_data->user_data = user_data;
4415   property_data->property_name = property_name;
4416   property_data->vtable = vtable;
4417   property_data->interface_info = interface_info;
4418   property_data->property_info = property_info;
4419   property_data->registration_id = registration_id;
4420   property_data->subtree_registration_id = subtree_registration_id;
4421 
4422   idle_source = g_idle_source_new ();
4423   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
4424   g_source_set_callback (idle_source,
4425                          is_get ? invoke_get_property_in_idle_cb : invoke_set_property_in_idle_cb,
4426                          property_data,
4427                          (GDestroyNotify) property_data_free);
4428   if (is_get)
4429     g_source_set_name (idle_source, "[gio] invoke_get_property_in_idle_cb");
4430   else
4431     g_source_set_name (idle_source, "[gio] invoke_set_property_in_idle_cb");
4432   g_source_attach (idle_source, main_context);
4433   g_source_unref (idle_source);
4434 
4435   handled = TRUE;
4436 
4437  out:
4438   return handled;
4439 }
4440 
4441 /* called in GDBusWorker thread with connection's lock held */
4442 static gboolean
handle_getset_property(GDBusConnection * connection,ExportedObject * eo,GDBusMessage * message,gboolean is_get)4443 handle_getset_property (GDBusConnection *connection,
4444                         ExportedObject  *eo,
4445                         GDBusMessage    *message,
4446                         gboolean         is_get)
4447 {
4448   ExportedInterface *ei;
4449   gboolean handled;
4450   const char *interface_name;
4451   const char *property_name;
4452 
4453   handled = FALSE;
4454 
4455   if (is_get)
4456     g_variant_get (g_dbus_message_get_body (message),
4457                    "(&s&s)",
4458                    &interface_name,
4459                    &property_name);
4460   else
4461     g_variant_get (g_dbus_message_get_body (message),
4462                    "(&s&sv)",
4463                    &interface_name,
4464                    &property_name,
4465                    NULL);
4466 
4467   /* Fail with org.freedesktop.DBus.Error.InvalidArgs if there is
4468    * no such interface registered
4469    */
4470   ei = g_hash_table_lookup (eo->map_if_name_to_ei, interface_name);
4471   if (ei == NULL)
4472     {
4473       GDBusMessage *reply;
4474       reply = g_dbus_message_new_method_error (message,
4475                                                "org.freedesktop.DBus.Error.InvalidArgs",
4476                                                _("No such interface “%s”"),
4477                                                interface_name);
4478       g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4479       g_object_unref (reply);
4480       handled = TRUE;
4481       goto out;
4482     }
4483 
4484   handled = validate_and_maybe_schedule_property_getset (eo->connection,
4485                                                          message,
4486                                                          ei->id,
4487                                                          0,
4488                                                          is_get,
4489                                                          ei->interface_info,
4490                                                          ei->vtable,
4491                                                          ei->context,
4492                                                          ei->user_data);
4493  out:
4494   return handled;
4495 }
4496 
4497 /* ---------------------------------------------------------------------------------------------------- */
4498 
4499 typedef struct
4500 {
4501   GDBusConnection *connection;
4502   GDBusMessage *message;
4503   gpointer user_data;
4504   const GDBusInterfaceVTable *vtable;
4505   GDBusInterfaceInfo *interface_info;
4506   guint registration_id;
4507   guint subtree_registration_id;
4508 } PropertyGetAllData;
4509 
4510 static void
property_get_all_data_free(PropertyData * data)4511 property_get_all_data_free (PropertyData *data)
4512 {
4513   g_object_unref (data->connection);
4514   g_object_unref (data->message);
4515   g_free (data);
4516 }
4517 
4518 /* called in thread where object was registered - no locks held */
4519 static gboolean
invoke_get_all_properties_in_idle_cb(gpointer _data)4520 invoke_get_all_properties_in_idle_cb (gpointer _data)
4521 {
4522   PropertyGetAllData *data = _data;
4523   GVariantBuilder builder;
4524   GDBusMessage *reply;
4525   guint n;
4526 
4527   if (has_object_been_unregistered (data->connection,
4528                                     data->registration_id,
4529                                     data->subtree_registration_id))
4530     {
4531       reply = g_dbus_message_new_method_error (data->message,
4532                                                "org.freedesktop.DBus.Error.UnknownMethod",
4533                                                _("No such interface “org.freedesktop.DBus.Properties” on object at path %s"),
4534                                                g_dbus_message_get_path (data->message));
4535       g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4536       g_object_unref (reply);
4537       goto out;
4538     }
4539 
4540   /* TODO: Right now we never fail this call - we just omit values if
4541    *       a get_property() call is failing.
4542    *
4543    *       We could fail the whole call if just a single get_property() call
4544    *       returns an error. We need clarification in the D-Bus spec about this.
4545    */
4546   g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a{sv})"));
4547   g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
4548   for (n = 0; data->interface_info->properties != NULL && data->interface_info->properties[n] != NULL; n++)
4549     {
4550       const GDBusPropertyInfo *property_info = data->interface_info->properties[n];
4551       GVariant *value;
4552 
4553       if (!(property_info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE))
4554         continue;
4555 
4556       value = data->vtable->get_property (data->connection,
4557                                           g_dbus_message_get_sender (data->message),
4558                                           g_dbus_message_get_path (data->message),
4559                                           data->interface_info->name,
4560                                           property_info->name,
4561                                           NULL,
4562                                           data->user_data);
4563 
4564       if (value == NULL)
4565         continue;
4566 
4567       g_variant_take_ref (value);
4568       g_variant_builder_add (&builder,
4569                              "{sv}",
4570                              property_info->name,
4571                              value);
4572       g_variant_unref (value);
4573     }
4574   g_variant_builder_close (&builder);
4575 
4576   reply = g_dbus_message_new_method_reply (data->message);
4577   g_dbus_message_set_body (reply, g_variant_builder_end (&builder));
4578   g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4579   g_object_unref (reply);
4580 
4581  out:
4582   return FALSE;
4583 }
4584 
4585 static gboolean
interface_has_readable_properties(GDBusInterfaceInfo * interface_info)4586 interface_has_readable_properties (GDBusInterfaceInfo *interface_info)
4587 {
4588   gint i;
4589 
4590   if (!interface_info->properties)
4591     return FALSE;
4592 
4593   for (i = 0; interface_info->properties[i]; i++)
4594     if (interface_info->properties[i]->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
4595       return TRUE;
4596 
4597   return FALSE;
4598 }
4599 
4600 /* called in any thread with connection's lock held */
4601 static gboolean
validate_and_maybe_schedule_property_get_all(GDBusConnection * connection,GDBusMessage * message,guint registration_id,guint subtree_registration_id,GDBusInterfaceInfo * interface_info,const GDBusInterfaceVTable * vtable,GMainContext * main_context,gpointer user_data)4602 validate_and_maybe_schedule_property_get_all (GDBusConnection            *connection,
4603                                               GDBusMessage               *message,
4604                                               guint                       registration_id,
4605                                               guint                       subtree_registration_id,
4606                                               GDBusInterfaceInfo         *interface_info,
4607                                               const GDBusInterfaceVTable *vtable,
4608                                               GMainContext               *main_context,
4609                                               gpointer                    user_data)
4610 {
4611   gboolean handled;
4612   GSource *idle_source;
4613   PropertyGetAllData *property_get_all_data;
4614 
4615   handled = FALSE;
4616 
4617   if (vtable == NULL)
4618     goto out;
4619 
4620   /* If the vtable pointer for get_property() is NULL but we have a
4621    * non-zero number of readable properties, then dispatch the call via
4622    * the method_call() handler.
4623    */
4624   if (vtable->get_property == NULL && interface_has_readable_properties (interface_info))
4625     {
4626       schedule_method_call (connection, message, registration_id, subtree_registration_id,
4627                             interface_info, NULL, NULL, g_dbus_message_get_body (message),
4628                             vtable, main_context, user_data);
4629       handled = TRUE;
4630       goto out;
4631     }
4632 
4633   /* ok, got the property info - call user in an idle handler */
4634   property_get_all_data = g_new0 (PropertyGetAllData, 1);
4635   property_get_all_data->connection = g_object_ref (connection);
4636   property_get_all_data->message = g_object_ref (message);
4637   property_get_all_data->user_data = user_data;
4638   property_get_all_data->vtable = vtable;
4639   property_get_all_data->interface_info = interface_info;
4640   property_get_all_data->registration_id = registration_id;
4641   property_get_all_data->subtree_registration_id = subtree_registration_id;
4642 
4643   idle_source = g_idle_source_new ();
4644   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
4645   g_source_set_callback (idle_source,
4646                          invoke_get_all_properties_in_idle_cb,
4647                          property_get_all_data,
4648                          (GDestroyNotify) property_get_all_data_free);
4649   g_source_set_name (idle_source, "[gio] invoke_get_all_properties_in_idle_cb");
4650   g_source_attach (idle_source, main_context);
4651   g_source_unref (idle_source);
4652 
4653   handled = TRUE;
4654 
4655  out:
4656   return handled;
4657 }
4658 
4659 /* called in GDBusWorker thread with connection's lock held */
4660 static gboolean
handle_get_all_properties(GDBusConnection * connection,ExportedObject * eo,GDBusMessage * message)4661 handle_get_all_properties (GDBusConnection *connection,
4662                            ExportedObject  *eo,
4663                            GDBusMessage    *message)
4664 {
4665   ExportedInterface *ei;
4666   gboolean handled;
4667   const char *interface_name;
4668 
4669   handled = FALSE;
4670 
4671   g_variant_get (g_dbus_message_get_body (message),
4672                  "(&s)",
4673                  &interface_name);
4674 
4675   /* Fail with org.freedesktop.DBus.Error.InvalidArgs if there is
4676    * no such interface registered
4677    */
4678   ei = g_hash_table_lookup (eo->map_if_name_to_ei, interface_name);
4679   if (ei == NULL)
4680     {
4681       GDBusMessage *reply;
4682       reply = g_dbus_message_new_method_error (message,
4683                                                "org.freedesktop.DBus.Error.InvalidArgs",
4684                                                _("No such interface “%s”"),
4685                                                interface_name);
4686       g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4687       g_object_unref (reply);
4688       handled = TRUE;
4689       goto out;
4690     }
4691 
4692   handled = validate_and_maybe_schedule_property_get_all (eo->connection,
4693                                                           message,
4694                                                           ei->id,
4695                                                           0,
4696                                                           ei->interface_info,
4697                                                           ei->vtable,
4698                                                           ei->context,
4699                                                           ei->user_data);
4700  out:
4701   return handled;
4702 }
4703 
4704 /* ---------------------------------------------------------------------------------------------------- */
4705 
4706 static const gchar introspect_header[] =
4707   "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
4708   "                      \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
4709   "<!-- GDBus " PACKAGE_VERSION " -->\n"
4710   "<node>\n";
4711 
4712 static const gchar introspect_tail[] =
4713   "</node>\n";
4714 
4715 static const gchar introspect_properties_interface[] =
4716   "  <interface name=\"org.freedesktop.DBus.Properties\">\n"
4717   "    <method name=\"Get\">\n"
4718   "      <arg type=\"s\" name=\"interface_name\" direction=\"in\"/>\n"
4719   "      <arg type=\"s\" name=\"property_name\" direction=\"in\"/>\n"
4720   "      <arg type=\"v\" name=\"value\" direction=\"out\"/>\n"
4721   "    </method>\n"
4722   "    <method name=\"GetAll\">\n"
4723   "      <arg type=\"s\" name=\"interface_name\" direction=\"in\"/>\n"
4724   "      <arg type=\"a{sv}\" name=\"properties\" direction=\"out\"/>\n"
4725   "    </method>\n"
4726   "    <method name=\"Set\">\n"
4727   "      <arg type=\"s\" name=\"interface_name\" direction=\"in\"/>\n"
4728   "      <arg type=\"s\" name=\"property_name\" direction=\"in\"/>\n"
4729   "      <arg type=\"v\" name=\"value\" direction=\"in\"/>\n"
4730   "    </method>\n"
4731   "    <signal name=\"PropertiesChanged\">\n"
4732   "      <arg type=\"s\" name=\"interface_name\"/>\n"
4733   "      <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"
4734   "      <arg type=\"as\" name=\"invalidated_properties\"/>\n"
4735   "    </signal>\n"
4736   "  </interface>\n";
4737 
4738 static const gchar introspect_introspectable_interface[] =
4739   "  <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
4740   "    <method name=\"Introspect\">\n"
4741   "      <arg type=\"s\" name=\"xml_data\" direction=\"out\"/>\n"
4742   "    </method>\n"
4743   "  </interface>\n"
4744   "  <interface name=\"org.freedesktop.DBus.Peer\">\n"
4745   "    <method name=\"Ping\"/>\n"
4746   "    <method name=\"GetMachineId\">\n"
4747   "      <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n"
4748   "    </method>\n"
4749   "  </interface>\n";
4750 
4751 static void
introspect_append_header(GString * s)4752 introspect_append_header (GString *s)
4753 {
4754   g_string_append (s, introspect_header);
4755 }
4756 
4757 static void
maybe_add_path(const gchar * path,gsize path_len,const gchar * object_path,GHashTable * set)4758 maybe_add_path (const gchar *path, gsize path_len, const gchar *object_path, GHashTable *set)
4759 {
4760   if (g_str_has_prefix (object_path, path) && strlen (object_path) > path_len && object_path[path_len-1] == '/')
4761     {
4762       const gchar *begin;
4763       const gchar *end;
4764       gchar *s;
4765 
4766       begin = object_path + path_len;
4767       end = strchr (begin, '/');
4768       if (end != NULL)
4769         s = g_strndup (begin, end - begin);
4770       else
4771         s = g_strdup (begin);
4772 
4773       if (!g_hash_table_contains (set, s))
4774         g_hash_table_add (set, s);
4775       else
4776         g_free (s);
4777     }
4778 }
4779 
4780 /* TODO: we want a nicer public interface for this */
4781 /* called in any thread with connection's lock held */
4782 static gchar **
g_dbus_connection_list_registered_unlocked(GDBusConnection * connection,const gchar * path)4783 g_dbus_connection_list_registered_unlocked (GDBusConnection *connection,
4784                                             const gchar     *path)
4785 {
4786   GPtrArray *p;
4787   gchar **ret;
4788   GHashTableIter hash_iter;
4789   const gchar *object_path;
4790   gsize path_len;
4791   GHashTable *set;
4792   GList *keys;
4793   GList *l;
4794 
4795   CONNECTION_ENSURE_LOCK (connection);
4796 
4797   path_len = strlen (path);
4798   if (path_len > 1)
4799     path_len++;
4800 
4801   set = g_hash_table_new (g_str_hash, g_str_equal);
4802 
4803   g_hash_table_iter_init (&hash_iter, connection->map_object_path_to_eo);
4804   while (g_hash_table_iter_next (&hash_iter, (gpointer) &object_path, NULL))
4805     maybe_add_path (path, path_len, object_path, set);
4806 
4807   g_hash_table_iter_init (&hash_iter, connection->map_object_path_to_es);
4808   while (g_hash_table_iter_next (&hash_iter, (gpointer) &object_path, NULL))
4809     maybe_add_path (path, path_len, object_path, set);
4810 
4811   p = g_ptr_array_new ();
4812   keys = g_hash_table_get_keys (set);
4813   for (l = keys; l != NULL; l = l->next)
4814     g_ptr_array_add (p, l->data);
4815   g_hash_table_unref (set);
4816   g_list_free (keys);
4817 
4818   g_ptr_array_add (p, NULL);
4819   ret = (gchar **) g_ptr_array_free (p, FALSE);
4820   return ret;
4821 }
4822 
4823 /* called in any thread with connection's lock not held */
4824 static gchar **
g_dbus_connection_list_registered(GDBusConnection * connection,const gchar * path)4825 g_dbus_connection_list_registered (GDBusConnection *connection,
4826                                    const gchar     *path)
4827 {
4828   gchar **ret;
4829   CONNECTION_LOCK (connection);
4830   ret = g_dbus_connection_list_registered_unlocked (connection, path);
4831   CONNECTION_UNLOCK (connection);
4832   return ret;
4833 }
4834 
4835 /* called in GDBusWorker thread with connection's lock held */
4836 static gboolean
handle_introspect(GDBusConnection * connection,ExportedObject * eo,GDBusMessage * message)4837 handle_introspect (GDBusConnection *connection,
4838                    ExportedObject  *eo,
4839                    GDBusMessage    *message)
4840 {
4841   guint n;
4842   GString *s;
4843   GDBusMessage *reply;
4844   GHashTableIter hash_iter;
4845   ExportedInterface *ei;
4846   gchar **registered;
4847 
4848   /* first the header with the standard interfaces */
4849   s = g_string_sized_new (sizeof (introspect_header) +
4850                           sizeof (introspect_properties_interface) +
4851                           sizeof (introspect_introspectable_interface) +
4852                           sizeof (introspect_tail));
4853   introspect_append_header (s);
4854   if (!g_hash_table_lookup (eo->map_if_name_to_ei,
4855                             "org.freedesktop.DBus.Properties"))
4856     g_string_append (s, introspect_properties_interface);
4857 
4858   if (!g_hash_table_lookup (eo->map_if_name_to_ei,
4859                             "org.freedesktop.DBus.Introspectable"))
4860     g_string_append (s, introspect_introspectable_interface);
4861 
4862   /* then include the registered interfaces */
4863   g_hash_table_iter_init (&hash_iter, eo->map_if_name_to_ei);
4864   while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &ei))
4865     g_dbus_interface_info_generate_xml (ei->interface_info, 2, s);
4866 
4867   /* finally include nodes registered below us */
4868   registered = g_dbus_connection_list_registered_unlocked (connection, eo->object_path);
4869   for (n = 0; registered != NULL && registered[n] != NULL; n++)
4870     g_string_append_printf (s, "  <node name=\"%s\"/>\n", registered[n]);
4871   g_strfreev (registered);
4872   g_string_append (s, introspect_tail);
4873 
4874   reply = g_dbus_message_new_method_reply (message);
4875   g_dbus_message_set_body (reply, g_variant_new ("(s)", s->str));
4876   g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4877   g_object_unref (reply);
4878   g_string_free (s, TRUE);
4879 
4880   return TRUE;
4881 }
4882 
4883 /* called in thread where object was registered - no locks held */
4884 static gboolean
call_in_idle_cb(gpointer user_data)4885 call_in_idle_cb (gpointer user_data)
4886 {
4887   GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (user_data);
4888   GDBusInterfaceVTable *vtable;
4889   guint registration_id;
4890   guint subtree_registration_id;
4891 
4892   registration_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (invocation), "g-dbus-registration-id"));
4893   subtree_registration_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (invocation), "g-dbus-subtree-registration-id"));
4894 
4895   if (has_object_been_unregistered (g_dbus_method_invocation_get_connection (invocation),
4896                                     registration_id,
4897                                     subtree_registration_id))
4898     {
4899       GDBusMessage *reply;
4900       reply = g_dbus_message_new_method_error (g_dbus_method_invocation_get_message (invocation),
4901                                                "org.freedesktop.DBus.Error.UnknownMethod",
4902                                                _("No such interface “%s” on object at path %s"),
4903                                                g_dbus_method_invocation_get_interface_name (invocation),
4904                                                g_dbus_method_invocation_get_object_path (invocation));
4905       g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4906       g_object_unref (reply);
4907       goto out;
4908     }
4909 
4910   vtable = g_object_get_data (G_OBJECT (invocation), "g-dbus-interface-vtable");
4911   g_assert (vtable != NULL && vtable->method_call != NULL);
4912 
4913   vtable->method_call (g_dbus_method_invocation_get_connection (invocation),
4914                        g_dbus_method_invocation_get_sender (invocation),
4915                        g_dbus_method_invocation_get_object_path (invocation),
4916                        g_dbus_method_invocation_get_interface_name (invocation),
4917                        g_dbus_method_invocation_get_method_name (invocation),
4918                        g_dbus_method_invocation_get_parameters (invocation),
4919                        g_object_ref (invocation),
4920                        g_dbus_method_invocation_get_user_data (invocation));
4921 
4922  out:
4923   return FALSE;
4924 }
4925 
4926 /* called in GDBusWorker thread with connection's lock held */
4927 static void
schedule_method_call(GDBusConnection * connection,GDBusMessage * message,guint registration_id,guint subtree_registration_id,const GDBusInterfaceInfo * interface_info,const GDBusMethodInfo * method_info,const GDBusPropertyInfo * property_info,GVariant * parameters,const GDBusInterfaceVTable * vtable,GMainContext * main_context,gpointer user_data)4928 schedule_method_call (GDBusConnection            *connection,
4929                       GDBusMessage               *message,
4930                       guint                       registration_id,
4931                       guint                       subtree_registration_id,
4932                       const GDBusInterfaceInfo   *interface_info,
4933                       const GDBusMethodInfo      *method_info,
4934                       const GDBusPropertyInfo    *property_info,
4935                       GVariant                   *parameters,
4936                       const GDBusInterfaceVTable *vtable,
4937                       GMainContext               *main_context,
4938                       gpointer                    user_data)
4939 {
4940   GDBusMethodInvocation *invocation;
4941   GSource *idle_source;
4942 
4943   invocation = _g_dbus_method_invocation_new (g_dbus_message_get_sender (message),
4944                                               g_dbus_message_get_path (message),
4945                                               g_dbus_message_get_interface (message),
4946                                               g_dbus_message_get_member (message),
4947                                               method_info,
4948                                               property_info,
4949                                               connection,
4950                                               message,
4951                                               parameters,
4952                                               user_data);
4953 
4954   /* TODO: would be nicer with a real MethodData like we already
4955    * have PropertyData and PropertyGetAllData... */
4956   g_object_set_data (G_OBJECT (invocation), "g-dbus-interface-vtable", (gpointer) vtable);
4957   g_object_set_data (G_OBJECT (invocation), "g-dbus-registration-id", GUINT_TO_POINTER (registration_id));
4958   g_object_set_data (G_OBJECT (invocation), "g-dbus-subtree-registration-id", GUINT_TO_POINTER (subtree_registration_id));
4959 
4960   idle_source = g_idle_source_new ();
4961   g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
4962   g_source_set_callback (idle_source,
4963                          call_in_idle_cb,
4964                          invocation,
4965                          g_object_unref);
4966   g_source_set_name (idle_source, "[gio, " __FILE__ "] call_in_idle_cb");
4967   g_source_attach (idle_source, main_context);
4968   g_source_unref (idle_source);
4969 }
4970 
4971 /* called in GDBusWorker thread with connection's lock held */
4972 static gboolean
validate_and_maybe_schedule_method_call(GDBusConnection * connection,GDBusMessage * message,guint registration_id,guint subtree_registration_id,GDBusInterfaceInfo * interface_info,const GDBusInterfaceVTable * vtable,GMainContext * main_context,gpointer user_data)4973 validate_and_maybe_schedule_method_call (GDBusConnection            *connection,
4974                                          GDBusMessage               *message,
4975                                          guint                       registration_id,
4976                                          guint                       subtree_registration_id,
4977                                          GDBusInterfaceInfo         *interface_info,
4978                                          const GDBusInterfaceVTable *vtable,
4979                                          GMainContext               *main_context,
4980                                          gpointer                    user_data)
4981 {
4982   GDBusMethodInfo *method_info;
4983   GDBusMessage *reply;
4984   GVariant *parameters;
4985   gboolean handled;
4986   GVariantType *in_type;
4987 
4988   handled = FALSE;
4989 
4990   /* TODO: the cost of this is O(n) - it might be worth caching the result */
4991   method_info = g_dbus_interface_info_lookup_method (interface_info, g_dbus_message_get_member (message));
4992 
4993   /* if the method doesn't exist, return the org.freedesktop.DBus.Error.UnknownMethod
4994    * error to the caller
4995    */
4996   if (method_info == NULL)
4997     {
4998       reply = g_dbus_message_new_method_error (message,
4999                                                "org.freedesktop.DBus.Error.UnknownMethod",
5000                                                _("No such method “%s”"),
5001                                                g_dbus_message_get_member (message));
5002       g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
5003       g_object_unref (reply);
5004       handled = TRUE;
5005       goto out;
5006     }
5007 
5008   parameters = g_dbus_message_get_body (message);
5009   if (parameters == NULL)
5010     {
5011       parameters = g_variant_new ("()");
5012       g_variant_ref_sink (parameters);
5013     }
5014   else
5015     {
5016       g_variant_ref (parameters);
5017     }
5018 
5019   /* Check that the incoming args are of the right type - if they are not, return
5020    * the org.freedesktop.DBus.Error.InvalidArgs error to the caller
5021    */
5022   in_type = _g_dbus_compute_complete_signature (method_info->in_args);
5023   if (!g_variant_is_of_type (parameters, in_type))
5024     {
5025       gchar *type_string;
5026 
5027       type_string = g_variant_type_dup_string (in_type);
5028 
5029       reply = g_dbus_message_new_method_error (message,
5030                                                "org.freedesktop.DBus.Error.InvalidArgs",
5031                                                _("Type of message, “%s”, does not match expected type “%s”"),
5032                                                g_variant_get_type_string (parameters),
5033                                                type_string);
5034       g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
5035       g_variant_type_free (in_type);
5036       g_variant_unref (parameters);
5037       g_object_unref (reply);
5038       g_free (type_string);
5039       handled = TRUE;
5040       goto out;
5041     }
5042   g_variant_type_free (in_type);
5043 
5044   /* schedule the call in idle */
5045   schedule_method_call (connection, message, registration_id, subtree_registration_id,
5046                         interface_info, method_info, NULL, parameters,
5047                         vtable, main_context, user_data);
5048   g_variant_unref (parameters);
5049   handled = TRUE;
5050 
5051  out:
5052   return handled;
5053 }
5054 
5055 /* ---------------------------------------------------------------------------------------------------- */
5056 
5057 /* called in GDBusWorker thread with connection's lock held */
5058 static gboolean
obj_message_func(GDBusConnection * connection,ExportedObject * eo,GDBusMessage * message)5059 obj_message_func (GDBusConnection *connection,
5060                   ExportedObject  *eo,
5061                   GDBusMessage    *message)
5062 {
5063   const gchar *interface_name;
5064   const gchar *member;
5065   const gchar *signature;
5066   gboolean handled;
5067 
5068   handled = FALSE;
5069 
5070   interface_name = g_dbus_message_get_interface (message);
5071   member = g_dbus_message_get_member (message);
5072   signature = g_dbus_message_get_signature (message);
5073 
5074   /* see if we have an interface for handling this call */
5075   if (interface_name != NULL)
5076     {
5077       ExportedInterface *ei;
5078       ei = g_hash_table_lookup (eo->map_if_name_to_ei, interface_name);
5079       if (ei != NULL)
5080         {
5081           /* we do - invoke the handler in idle in the right thread */
5082 
5083           /* handle no vtable or handler being present */
5084           if (ei->vtable == NULL || ei->vtable->method_call == NULL)
5085             goto out;
5086 
5087           handled = validate_and_maybe_schedule_method_call (connection,
5088                                                              message,
5089                                                              ei->id,
5090                                                              0,
5091                                                              ei->interface_info,
5092                                                              ei->vtable,
5093                                                              ei->context,
5094                                                              ei->user_data);
5095           goto out;
5096         }
5097     }
5098 
5099   if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Introspectable") == 0 &&
5100       g_strcmp0 (member, "Introspect") == 0 &&
5101       g_strcmp0 (signature, "") == 0)
5102     {
5103       handled = handle_introspect (connection, eo, message);
5104       goto out;
5105     }
5106   else if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0 &&
5107            g_strcmp0 (member, "Get") == 0 &&
5108            g_strcmp0 (signature, "ss") == 0)
5109     {
5110       handled = handle_getset_property (connection, eo, message, TRUE);
5111       goto out;
5112     }
5113   else if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0 &&
5114            g_strcmp0 (member, "Set") == 0 &&
5115            g_strcmp0 (signature, "ssv") == 0)
5116     {
5117       handled = handle_getset_property (connection, eo, message, FALSE);
5118       goto out;
5119     }
5120   else if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0 &&
5121            g_strcmp0 (member, "GetAll") == 0 &&
5122            g_strcmp0 (signature, "s") == 0)
5123     {
5124       handled = handle_get_all_properties (connection, eo, message);
5125       goto out;
5126     }
5127 
5128  out:
5129   return handled;
5130 }
5131 
5132 /**
5133  * g_dbus_connection_register_object:
5134  * @connection: a #GDBusConnection
5135  * @object_path: the object path to register at
5136  * @interface_info: introspection data for the interface
5137  * @vtable: (nullable): a #GDBusInterfaceVTable to call into or %NULL
5138  * @user_data: (nullable): data to pass to functions in @vtable
5139  * @user_data_free_func: function to call when the object path is unregistered
5140  * @error: return location for error or %NULL
5141  *
5142  * Registers callbacks for exported objects at @object_path with the
5143  * D-Bus interface that is described in @interface_info.
5144  *
5145  * Calls to functions in @vtable (and @user_data_free_func) will happen
5146  * in the
5147  * [thread-default main context][g-main-context-push-thread-default]
5148  * of the thread you are calling this method from.
5149  *
5150  * Note that all #GVariant values passed to functions in @vtable will match
5151  * the signature given in @interface_info - if a remote caller passes
5152  * incorrect values, the `org.freedesktop.DBus.Error.InvalidArgs`
5153  * is returned to the remote caller.
5154  *
5155  * Additionally, if the remote caller attempts to invoke methods or
5156  * access properties not mentioned in @interface_info the
5157  * `org.freedesktop.DBus.Error.UnknownMethod` resp.
5158  * `org.freedesktop.DBus.Error.InvalidArgs` errors
5159  * are returned to the caller.
5160  *
5161  * It is considered a programming error if the
5162  * #GDBusInterfaceGetPropertyFunc function in @vtable returns a
5163  * #GVariant of incorrect type.
5164  *
5165  * If an existing callback is already registered at @object_path and
5166  * @interface_name, then @error is set to #G_IO_ERROR_EXISTS.
5167  *
5168  * GDBus automatically implements the standard D-Bus interfaces
5169  * org.freedesktop.DBus.Properties, org.freedesktop.DBus.Introspectable
5170  * and org.freedesktop.Peer, so you don't have to implement those for the
5171  * objects you export. You can implement org.freedesktop.DBus.Properties
5172  * yourself, e.g. to handle getting and setting of properties asynchronously.
5173  *
5174  * Note that the reference count on @interface_info will be
5175  * incremented by 1 (unless allocated statically, e.g. if the
5176  * reference count is -1, see g_dbus_interface_info_ref()) for as long
5177  * as the object is exported. Also note that @vtable will be copied.
5178  *
5179  * See this [server][gdbus-server] for an example of how to use this method.
5180  *
5181  * Returns: 0 if @error is set, otherwise a registration id (never 0)
5182  *     that can be used with g_dbus_connection_unregister_object()
5183  *
5184  * Since: 2.26
5185  */
5186 guint
g_dbus_connection_register_object(GDBusConnection * connection,const gchar * object_path,GDBusInterfaceInfo * interface_info,const GDBusInterfaceVTable * vtable,gpointer user_data,GDestroyNotify user_data_free_func,GError ** error)5187 g_dbus_connection_register_object (GDBusConnection             *connection,
5188                                    const gchar                 *object_path,
5189                                    GDBusInterfaceInfo          *interface_info,
5190                                    const GDBusInterfaceVTable  *vtable,
5191                                    gpointer                     user_data,
5192                                    GDestroyNotify               user_data_free_func,
5193                                    GError                     **error)
5194 {
5195   ExportedObject *eo;
5196   ExportedInterface *ei;
5197   guint ret;
5198 
5199   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
5200   g_return_val_if_fail (object_path != NULL && g_variant_is_object_path (object_path), 0);
5201   g_return_val_if_fail (interface_info != NULL, 0);
5202   g_return_val_if_fail (g_dbus_is_interface_name (interface_info->name), 0);
5203   g_return_val_if_fail (error == NULL || *error == NULL, 0);
5204   g_return_val_if_fail (check_initialized (connection), 0);
5205 
5206   ret = 0;
5207 
5208   CONNECTION_LOCK (connection);
5209 
5210   eo = g_hash_table_lookup (connection->map_object_path_to_eo, object_path);
5211   if (eo == NULL)
5212     {
5213       eo = g_new0 (ExportedObject, 1);
5214       eo->object_path = g_strdup (object_path);
5215       eo->connection = connection;
5216       eo->map_if_name_to_ei = g_hash_table_new_full (g_str_hash,
5217                                                      g_str_equal,
5218                                                      NULL,
5219                                                      (GDestroyNotify) exported_interface_free);
5220       g_hash_table_insert (connection->map_object_path_to_eo, eo->object_path, eo);
5221     }
5222 
5223   ei = g_hash_table_lookup (eo->map_if_name_to_ei, interface_info->name);
5224   if (ei != NULL)
5225     {
5226       g_set_error (error,
5227                    G_IO_ERROR,
5228                    G_IO_ERROR_EXISTS,
5229                    _("An object is already exported for the interface %s at %s"),
5230                    interface_info->name,
5231                    object_path);
5232       goto out;
5233     }
5234 
5235   ei = g_new0 (ExportedInterface, 1);
5236   ei->id = (guint) g_atomic_int_add (&_global_registration_id, 1); /* TODO: overflow etc. */
5237   ei->eo = eo;
5238   ei->user_data = user_data;
5239   ei->user_data_free_func = user_data_free_func;
5240   ei->vtable = _g_dbus_interface_vtable_copy (vtable);
5241   ei->interface_info = g_dbus_interface_info_ref (interface_info);
5242   g_dbus_interface_info_cache_build (ei->interface_info);
5243   ei->interface_name = g_strdup (interface_info->name);
5244   ei->context = g_main_context_ref_thread_default ();
5245 
5246   g_hash_table_insert (eo->map_if_name_to_ei,
5247                        (gpointer) ei->interface_name,
5248                        ei);
5249   g_hash_table_insert (connection->map_id_to_ei,
5250                        GUINT_TO_POINTER (ei->id),
5251                        ei);
5252 
5253   ret = ei->id;
5254 
5255  out:
5256   CONNECTION_UNLOCK (connection);
5257 
5258   return ret;
5259 }
5260 
5261 /**
5262  * g_dbus_connection_unregister_object:
5263  * @connection: a #GDBusConnection
5264  * @registration_id: a registration id obtained from
5265  *     g_dbus_connection_register_object()
5266  *
5267  * Unregisters an object.
5268  *
5269  * Returns: %TRUE if the object was unregistered, %FALSE otherwise
5270  *
5271  * Since: 2.26
5272  */
5273 gboolean
g_dbus_connection_unregister_object(GDBusConnection * connection,guint registration_id)5274 g_dbus_connection_unregister_object (GDBusConnection *connection,
5275                                      guint            registration_id)
5276 {
5277   ExportedInterface *ei;
5278   ExportedObject *eo;
5279   gboolean ret;
5280 
5281   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
5282   g_return_val_if_fail (check_initialized (connection), FALSE);
5283 
5284   ret = FALSE;
5285 
5286   CONNECTION_LOCK (connection);
5287 
5288   ei = g_hash_table_lookup (connection->map_id_to_ei,
5289                             GUINT_TO_POINTER (registration_id));
5290   if (ei == NULL)
5291     goto out;
5292 
5293   eo = ei->eo;
5294 
5295   g_warn_if_fail (g_hash_table_remove (connection->map_id_to_ei, GUINT_TO_POINTER (ei->id)));
5296   g_warn_if_fail (g_hash_table_remove (eo->map_if_name_to_ei, ei->interface_name));
5297   /* unregister object path if we have no more exported interfaces */
5298   if (g_hash_table_size (eo->map_if_name_to_ei) == 0)
5299     g_warn_if_fail (g_hash_table_remove (connection->map_object_path_to_eo,
5300                                          eo->object_path));
5301 
5302   ret = TRUE;
5303 
5304  out:
5305   CONNECTION_UNLOCK (connection);
5306 
5307   return ret;
5308 }
5309 
5310 typedef struct {
5311   GClosure *method_call_closure;
5312   GClosure *get_property_closure;
5313   GClosure *set_property_closure;
5314 } RegisterObjectData;
5315 
5316 static RegisterObjectData *
register_object_data_new(GClosure * method_call_closure,GClosure * get_property_closure,GClosure * set_property_closure)5317 register_object_data_new (GClosure *method_call_closure,
5318                           GClosure *get_property_closure,
5319                           GClosure *set_property_closure)
5320 {
5321   RegisterObjectData *data;
5322 
5323   data = g_new0 (RegisterObjectData, 1);
5324 
5325   if (method_call_closure != NULL)
5326     {
5327       data->method_call_closure = g_closure_ref (method_call_closure);
5328       g_closure_sink (method_call_closure);
5329       if (G_CLOSURE_NEEDS_MARSHAL (method_call_closure))
5330         g_closure_set_marshal (method_call_closure, g_cclosure_marshal_generic);
5331     }
5332 
5333   if (get_property_closure != NULL)
5334     {
5335       data->get_property_closure = g_closure_ref (get_property_closure);
5336       g_closure_sink (get_property_closure);
5337       if (G_CLOSURE_NEEDS_MARSHAL (get_property_closure))
5338         g_closure_set_marshal (get_property_closure, g_cclosure_marshal_generic);
5339     }
5340 
5341   if (set_property_closure != NULL)
5342     {
5343       data->set_property_closure = g_closure_ref (set_property_closure);
5344       g_closure_sink (set_property_closure);
5345       if (G_CLOSURE_NEEDS_MARSHAL (set_property_closure))
5346         g_closure_set_marshal (set_property_closure, g_cclosure_marshal_generic);
5347     }
5348 
5349   return data;
5350 }
5351 
5352 static void
register_object_free_func(gpointer user_data)5353 register_object_free_func (gpointer user_data)
5354 {
5355   RegisterObjectData *data = user_data;
5356 
5357   g_clear_pointer (&data->method_call_closure, g_closure_unref);
5358   g_clear_pointer (&data->get_property_closure, g_closure_unref);
5359   g_clear_pointer (&data->set_property_closure, g_closure_unref);
5360 
5361   g_free (data);
5362 }
5363 
5364 static void
register_with_closures_on_method_call(GDBusConnection * connection,const gchar * sender,const gchar * object_path,const gchar * interface_name,const gchar * method_name,GVariant * parameters,GDBusMethodInvocation * invocation,gpointer user_data)5365 register_with_closures_on_method_call (GDBusConnection       *connection,
5366                                        const gchar           *sender,
5367                                        const gchar           *object_path,
5368                                        const gchar           *interface_name,
5369                                        const gchar           *method_name,
5370                                        GVariant              *parameters,
5371                                        GDBusMethodInvocation *invocation,
5372                                        gpointer               user_data)
5373 {
5374   RegisterObjectData *data = user_data;
5375   GValue params[] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
5376 
5377   g_value_init (&params[0], G_TYPE_DBUS_CONNECTION);
5378   g_value_set_object (&params[0], connection);
5379 
5380   g_value_init (&params[1], G_TYPE_STRING);
5381   g_value_set_string (&params[1], sender);
5382 
5383   g_value_init (&params[2], G_TYPE_STRING);
5384   g_value_set_string (&params[2], object_path);
5385 
5386   g_value_init (&params[3], G_TYPE_STRING);
5387   g_value_set_string (&params[3], interface_name);
5388 
5389   g_value_init (&params[4], G_TYPE_STRING);
5390   g_value_set_string (&params[4], method_name);
5391 
5392   g_value_init (&params[5], G_TYPE_VARIANT);
5393   g_value_set_variant (&params[5], parameters);
5394 
5395   g_value_init (&params[6], G_TYPE_DBUS_METHOD_INVOCATION);
5396   g_value_set_object (&params[6], invocation);
5397 
5398   g_closure_invoke (data->method_call_closure, NULL, G_N_ELEMENTS (params), params, NULL);
5399 
5400   g_value_unset (params + 0);
5401   g_value_unset (params + 1);
5402   g_value_unset (params + 2);
5403   g_value_unset (params + 3);
5404   g_value_unset (params + 4);
5405   g_value_unset (params + 5);
5406   g_value_unset (params + 6);
5407 }
5408 
5409 static GVariant *
register_with_closures_on_get_property(GDBusConnection * connection,const gchar * sender,const gchar * object_path,const gchar * interface_name,const gchar * property_name,GError ** error,gpointer user_data)5410 register_with_closures_on_get_property (GDBusConnection *connection,
5411                                         const gchar     *sender,
5412                                         const gchar     *object_path,
5413                                         const gchar     *interface_name,
5414                                         const gchar     *property_name,
5415                                         GError         **error,
5416                                         gpointer         user_data)
5417 {
5418   RegisterObjectData *data = user_data;
5419   GValue params[] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
5420   GValue result_value = G_VALUE_INIT;
5421   GVariant *result;
5422 
5423   g_value_init (&params[0], G_TYPE_DBUS_CONNECTION);
5424   g_value_set_object (&params[0], connection);
5425 
5426   g_value_init (&params[1], G_TYPE_STRING);
5427   g_value_set_string (&params[1], sender);
5428 
5429   g_value_init (&params[2], G_TYPE_STRING);
5430   g_value_set_string (&params[2], object_path);
5431 
5432   g_value_init (&params[3], G_TYPE_STRING);
5433   g_value_set_string (&params[3], interface_name);
5434 
5435   g_value_init (&params[4], G_TYPE_STRING);
5436   g_value_set_string (&params[4], property_name);
5437 
5438   g_value_init (&result_value, G_TYPE_VARIANT);
5439 
5440   g_closure_invoke (data->get_property_closure, &result_value, G_N_ELEMENTS (params), params, NULL);
5441 
5442   result = g_value_get_variant (&result_value);
5443   if (result)
5444     g_variant_ref (result);
5445 
5446   g_value_unset (params + 0);
5447   g_value_unset (params + 1);
5448   g_value_unset (params + 2);
5449   g_value_unset (params + 3);
5450   g_value_unset (params + 4);
5451   g_value_unset (&result_value);
5452 
5453   if (!result)
5454     g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
5455                  _("Unable to retrieve property %s.%s"),
5456                  interface_name, property_name);
5457 
5458   return result;
5459 }
5460 
5461 static gboolean
register_with_closures_on_set_property(GDBusConnection * connection,const gchar * sender,const gchar * object_path,const gchar * interface_name,const gchar * property_name,GVariant * value,GError ** error,gpointer user_data)5462 register_with_closures_on_set_property (GDBusConnection *connection,
5463                                         const gchar     *sender,
5464                                         const gchar     *object_path,
5465                                         const gchar     *interface_name,
5466                                         const gchar     *property_name,
5467                                         GVariant        *value,
5468                                         GError         **error,
5469                                         gpointer         user_data)
5470 {
5471   RegisterObjectData *data = user_data;
5472   GValue params[] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
5473   GValue result_value = G_VALUE_INIT;
5474   gboolean result;
5475 
5476   g_value_init (&params[0], G_TYPE_DBUS_CONNECTION);
5477   g_value_set_object (&params[0], connection);
5478 
5479   g_value_init (&params[1], G_TYPE_STRING);
5480   g_value_set_string (&params[1], sender);
5481 
5482   g_value_init (&params[2], G_TYPE_STRING);
5483   g_value_set_string (&params[2], object_path);
5484 
5485   g_value_init (&params[3], G_TYPE_STRING);
5486   g_value_set_string (&params[3], interface_name);
5487 
5488   g_value_init (&params[4], G_TYPE_STRING);
5489   g_value_set_string (&params[4], property_name);
5490 
5491   g_value_init (&params[5], G_TYPE_VARIANT);
5492   g_value_set_variant (&params[5], value);
5493 
5494   g_value_init (&result_value, G_TYPE_BOOLEAN);
5495 
5496   g_closure_invoke (data->set_property_closure, &result_value, G_N_ELEMENTS (params), params, NULL);
5497 
5498   result = g_value_get_boolean (&result_value);
5499 
5500   g_value_unset (params + 0);
5501   g_value_unset (params + 1);
5502   g_value_unset (params + 2);
5503   g_value_unset (params + 3);
5504   g_value_unset (params + 4);
5505   g_value_unset (params + 5);
5506   g_value_unset (&result_value);
5507 
5508   if (!result)
5509     g_set_error (error,
5510                  G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
5511                  _("Unable to set property %s.%s"),
5512                  interface_name, property_name);
5513 
5514   return result;
5515 }
5516 
5517 /**
5518  * g_dbus_connection_register_object_with_closures: (rename-to g_dbus_connection_register_object)
5519  * @connection: A #GDBusConnection.
5520  * @object_path: The object path to register at.
5521  * @interface_info: Introspection data for the interface.
5522  * @method_call_closure: (nullable): #GClosure for handling incoming method calls.
5523  * @get_property_closure: (nullable): #GClosure for getting a property.
5524  * @set_property_closure: (nullable): #GClosure for setting a property.
5525  * @error: Return location for error or %NULL.
5526  *
5527  * Version of g_dbus_connection_register_object() using closures instead of a
5528  * #GDBusInterfaceVTable for easier binding in other languages.
5529  *
5530  * Returns: 0 if @error is set, otherwise a registration ID (never 0)
5531  * that can be used with g_dbus_connection_unregister_object() .
5532  *
5533  * Since: 2.46
5534  */
5535 guint
g_dbus_connection_register_object_with_closures(GDBusConnection * connection,const gchar * object_path,GDBusInterfaceInfo * interface_info,GClosure * method_call_closure,GClosure * get_property_closure,GClosure * set_property_closure,GError ** error)5536 g_dbus_connection_register_object_with_closures (GDBusConnection     *connection,
5537                                                  const gchar         *object_path,
5538                                                  GDBusInterfaceInfo  *interface_info,
5539                                                  GClosure            *method_call_closure,
5540                                                  GClosure            *get_property_closure,
5541                                                  GClosure            *set_property_closure,
5542                                                  GError             **error)
5543 {
5544   RegisterObjectData *data;
5545   GDBusInterfaceVTable vtable =
5546     {
5547       method_call_closure != NULL  ? register_with_closures_on_method_call  : NULL,
5548       get_property_closure != NULL ? register_with_closures_on_get_property : NULL,
5549       set_property_closure != NULL ? register_with_closures_on_set_property : NULL,
5550       { 0 }
5551     };
5552 
5553   data = register_object_data_new (method_call_closure, get_property_closure, set_property_closure);
5554 
5555   return g_dbus_connection_register_object (connection,
5556                                             object_path,
5557                                             interface_info,
5558                                             &vtable,
5559                                             data,
5560                                             register_object_free_func,
5561                                             error);
5562 }
5563 
5564 /* ---------------------------------------------------------------------------------------------------- */
5565 
5566 /**
5567  * g_dbus_connection_emit_signal:
5568  * @connection: a #GDBusConnection
5569  * @destination_bus_name: (nullable): the unique bus name for the destination
5570  *     for the signal or %NULL to emit to all listeners
5571  * @object_path: path of remote object
5572  * @interface_name: D-Bus interface to emit a signal on
5573  * @signal_name: the name of the signal to emit
5574  * @parameters: (nullable): a #GVariant tuple with parameters for the signal
5575  *              or %NULL if not passing parameters
5576  * @error: Return location for error or %NULL
5577  *
5578  * Emits a signal.
5579  *
5580  * If the parameters GVariant is floating, it is consumed.
5581  *
5582  * This can only fail if @parameters is not compatible with the D-Bus protocol
5583  * (%G_IO_ERROR_INVALID_ARGUMENT), or if @connection has been closed
5584  * (%G_IO_ERROR_CLOSED).
5585  *
5586  * Returns: %TRUE unless @error is set
5587  *
5588  * Since: 2.26
5589  */
5590 gboolean
g_dbus_connection_emit_signal(GDBusConnection * connection,const gchar * destination_bus_name,const gchar * object_path,const gchar * interface_name,const gchar * signal_name,GVariant * parameters,GError ** error)5591 g_dbus_connection_emit_signal (GDBusConnection  *connection,
5592                                const gchar      *destination_bus_name,
5593                                const gchar      *object_path,
5594                                const gchar      *interface_name,
5595                                const gchar      *signal_name,
5596                                GVariant         *parameters,
5597                                GError          **error)
5598 {
5599   GDBusMessage *message;
5600   gboolean ret;
5601 
5602   message = NULL;
5603   ret = FALSE;
5604 
5605   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
5606   g_return_val_if_fail (destination_bus_name == NULL || g_dbus_is_name (destination_bus_name), FALSE);
5607   g_return_val_if_fail (object_path != NULL && g_variant_is_object_path (object_path), FALSE);
5608   g_return_val_if_fail (interface_name != NULL && g_dbus_is_interface_name (interface_name), FALSE);
5609   g_return_val_if_fail (signal_name != NULL && g_dbus_is_member_name (signal_name), FALSE);
5610   g_return_val_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), FALSE);
5611   g_return_val_if_fail (check_initialized (connection), FALSE);
5612 
5613   if (G_UNLIKELY (_g_dbus_debug_emission ()))
5614     {
5615       _g_dbus_debug_print_lock ();
5616       g_print ("========================================================================\n"
5617                "GDBus-debug:Emission:\n"
5618                " >>>> SIGNAL EMISSION %s.%s()\n"
5619                "      on object %s\n"
5620                "      destination %s\n",
5621                interface_name, signal_name,
5622                object_path,
5623                destination_bus_name != NULL ? destination_bus_name : "(none)");
5624       _g_dbus_debug_print_unlock ();
5625     }
5626 
5627   message = g_dbus_message_new_signal (object_path,
5628                                        interface_name,
5629                                        signal_name);
5630 
5631   if (destination_bus_name != NULL)
5632     g_dbus_message_set_header (message,
5633                                G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION,
5634                                g_variant_new_string (destination_bus_name));
5635 
5636   if (parameters != NULL)
5637     g_dbus_message_set_body (message, parameters);
5638 
5639   ret = g_dbus_connection_send_message (connection, message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, error);
5640   g_object_unref (message);
5641 
5642   return ret;
5643 }
5644 
5645 static void
add_call_flags(GDBusMessage * message,GDBusCallFlags flags)5646 add_call_flags (GDBusMessage           *message,
5647                          GDBusCallFlags  flags)
5648 {
5649   GDBusMessageFlags msg_flags = 0;
5650 
5651   if (flags & G_DBUS_CALL_FLAGS_NO_AUTO_START)
5652     msg_flags |= G_DBUS_MESSAGE_FLAGS_NO_AUTO_START;
5653   if (flags & G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION)
5654     msg_flags |= G_DBUS_MESSAGE_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION;
5655   if (msg_flags)
5656     g_dbus_message_set_flags (message, msg_flags);
5657 }
5658 
5659 static GVariant *
decode_method_reply(GDBusMessage * reply,const gchar * method_name,const GVariantType * reply_type,GUnixFDList ** out_fd_list,GError ** error)5660 decode_method_reply (GDBusMessage        *reply,
5661                      const gchar         *method_name,
5662                      const GVariantType  *reply_type,
5663                      GUnixFDList        **out_fd_list,
5664                      GError             **error)
5665 {
5666   GVariant *result;
5667 
5668   result = NULL;
5669   switch (g_dbus_message_get_message_type (reply))
5670     {
5671     case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
5672       result = g_dbus_message_get_body (reply);
5673       if (result == NULL)
5674         {
5675           result = g_variant_new ("()");
5676           g_variant_ref_sink (result);
5677         }
5678       else
5679         {
5680           g_variant_ref (result);
5681         }
5682 
5683       if (!g_variant_is_of_type (result, reply_type))
5684         {
5685           gchar *type_string = g_variant_type_dup_string (reply_type);
5686 
5687           g_set_error (error,
5688                        G_IO_ERROR,
5689                        G_IO_ERROR_INVALID_ARGUMENT,
5690                        _("Method “%s” returned type “%s”, but expected “%s”"),
5691                        method_name, g_variant_get_type_string (result), type_string);
5692 
5693           g_variant_unref (result);
5694           g_free (type_string);
5695           result = NULL;
5696         }
5697 
5698 #ifdef G_OS_UNIX
5699       if (result != NULL)
5700         {
5701           if (out_fd_list != NULL)
5702             {
5703               *out_fd_list = g_dbus_message_get_unix_fd_list (reply);
5704               if (*out_fd_list != NULL)
5705                 g_object_ref (*out_fd_list);
5706             }
5707         }
5708 #endif
5709       break;
5710 
5711     case G_DBUS_MESSAGE_TYPE_ERROR:
5712       g_dbus_message_to_gerror (reply, error);
5713       break;
5714 
5715     default:
5716       g_assert_not_reached ();
5717       break;
5718     }
5719 
5720   return result;
5721 }
5722 
5723 
5724 typedef struct
5725 {
5726   GVariantType *reply_type;
5727   gchar *method_name; /* for error message */
5728 
5729   GUnixFDList *fd_list;
5730 } CallState;
5731 
5732 static void
call_state_free(CallState * state)5733 call_state_free (CallState *state)
5734 {
5735   g_variant_type_free (state->reply_type);
5736   g_free (state->method_name);
5737 
5738   if (state->fd_list != NULL)
5739     g_object_unref (state->fd_list);
5740   g_slice_free (CallState, state);
5741 }
5742 
5743 /* called in any thread, with the connection's lock not held */
5744 static void
g_dbus_connection_call_done(GObject * source,GAsyncResult * result,gpointer user_data)5745 g_dbus_connection_call_done (GObject      *source,
5746                              GAsyncResult *result,
5747                              gpointer      user_data)
5748 {
5749   GDBusConnection *connection = G_DBUS_CONNECTION (source);
5750   GTask *task = user_data;
5751   CallState *state = g_task_get_task_data (task);
5752   GError *error = NULL;
5753   GDBusMessage *reply;
5754   GVariant *value = NULL;
5755 
5756   reply = g_dbus_connection_send_message_with_reply_finish (connection,
5757                                                             result,
5758                                                             &error);
5759 
5760   if (G_UNLIKELY (_g_dbus_debug_call ()))
5761     {
5762       _g_dbus_debug_print_lock ();
5763       g_print ("========================================================================\n"
5764                "GDBus-debug:Call:\n"
5765                " <<<< ASYNC COMPLETE %s()",
5766                state->method_name);
5767 
5768       if (reply != NULL)
5769         {
5770           g_print (" (serial %d)\n"
5771                    "      SUCCESS\n",
5772                    g_dbus_message_get_reply_serial (reply));
5773         }
5774       else
5775         {
5776           g_print ("\n"
5777                    "      FAILED: %s\n",
5778                    error->message);
5779         }
5780       _g_dbus_debug_print_unlock ();
5781     }
5782 
5783   if (reply != NULL)
5784     value = decode_method_reply (reply, state->method_name, state->reply_type, &state->fd_list, &error);
5785 
5786   if (error != NULL)
5787     g_task_return_error (task, error);
5788   else
5789     g_task_return_pointer (task, value, (GDestroyNotify) g_variant_unref);
5790 
5791   g_clear_object (&reply);
5792   g_object_unref (task);
5793 }
5794 
5795 /* called in any thread, with the connection's lock not held */
5796 static void
g_dbus_connection_call_internal(GDBusConnection * connection,const gchar * bus_name,const gchar * object_path,const gchar * interface_name,const gchar * method_name,GVariant * parameters,const GVariantType * reply_type,GDBusCallFlags flags,gint timeout_msec,GUnixFDList * fd_list,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)5797 g_dbus_connection_call_internal (GDBusConnection        *connection,
5798                                  const gchar            *bus_name,
5799                                  const gchar            *object_path,
5800                                  const gchar            *interface_name,
5801                                  const gchar            *method_name,
5802                                  GVariant               *parameters,
5803                                  const GVariantType     *reply_type,
5804                                  GDBusCallFlags          flags,
5805                                  gint                    timeout_msec,
5806                                  GUnixFDList            *fd_list,
5807                                  GCancellable           *cancellable,
5808                                  GAsyncReadyCallback     callback,
5809                                  gpointer                user_data)
5810 {
5811   GDBusMessage *message;
5812   guint32 serial;
5813 
5814   g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
5815   g_return_if_fail (bus_name == NULL || g_dbus_is_name (bus_name));
5816   g_return_if_fail (object_path != NULL && g_variant_is_object_path (object_path));
5817   g_return_if_fail (interface_name != NULL && g_dbus_is_interface_name (interface_name));
5818   g_return_if_fail (method_name != NULL && g_dbus_is_member_name (method_name));
5819   g_return_if_fail (timeout_msec >= 0 || timeout_msec == -1);
5820   g_return_if_fail ((parameters == NULL) || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
5821   g_return_if_fail (check_initialized (connection));
5822 #ifdef G_OS_UNIX
5823   g_return_if_fail (fd_list == NULL || G_IS_UNIX_FD_LIST (fd_list));
5824 #else
5825   g_return_if_fail (fd_list == NULL);
5826 #endif
5827 
5828   message = g_dbus_message_new_method_call (bus_name,
5829                                             object_path,
5830                                             interface_name,
5831                                             method_name);
5832   add_call_flags (message, flags);
5833   if (parameters != NULL)
5834     g_dbus_message_set_body (message, parameters);
5835 
5836 #ifdef G_OS_UNIX
5837   if (fd_list != NULL)
5838     g_dbus_message_set_unix_fd_list (message, fd_list);
5839 #endif
5840 
5841   /* If the user has no callback then we can just send the message with
5842    * the G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED flag set and skip all
5843    * the logic for processing the reply.  If the service sends the reply
5844    * anyway then it will just be ignored.
5845    */
5846   if (callback != NULL)
5847     {
5848       CallState *state;
5849       GTask *task;
5850 
5851       state = g_slice_new0 (CallState);
5852       state->method_name = g_strjoin (".", interface_name, method_name, NULL);
5853 
5854       if (reply_type == NULL)
5855         reply_type = G_VARIANT_TYPE_ANY;
5856 
5857       state->reply_type = g_variant_type_copy (reply_type);
5858 
5859       task = g_task_new (connection, cancellable, callback, user_data);
5860       g_task_set_source_tag (task, g_dbus_connection_call_internal);
5861       g_task_set_task_data (task, state, (GDestroyNotify) call_state_free);
5862 
5863       g_dbus_connection_send_message_with_reply (connection,
5864                                                  message,
5865                                                  G_DBUS_SEND_MESSAGE_FLAGS_NONE,
5866                                                  timeout_msec,
5867                                                  &serial,
5868                                                  cancellable,
5869                                                  g_dbus_connection_call_done,
5870                                                  task);
5871     }
5872   else
5873     {
5874       GDBusMessageFlags flags;
5875 
5876       flags = g_dbus_message_get_flags (message);
5877       flags |= G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED;
5878       g_dbus_message_set_flags (message, flags);
5879 
5880       g_dbus_connection_send_message (connection,
5881                                       message,
5882                                       G_DBUS_SEND_MESSAGE_FLAGS_NONE,
5883                                       &serial, NULL);
5884     }
5885 
5886   if (G_UNLIKELY (_g_dbus_debug_call ()))
5887     {
5888       _g_dbus_debug_print_lock ();
5889       g_print ("========================================================================\n"
5890                "GDBus-debug:Call:\n"
5891                " >>>> ASYNC %s.%s()\n"
5892                "      on object %s\n"
5893                "      owned by name %s (serial %d)\n",
5894                interface_name,
5895                method_name,
5896                object_path,
5897                bus_name != NULL ? bus_name : "(none)",
5898                serial);
5899       _g_dbus_debug_print_unlock ();
5900     }
5901 
5902   if (message != NULL)
5903     g_object_unref (message);
5904 }
5905 
5906 /* called in any thread, with the connection's lock not held */
5907 static GVariant *
g_dbus_connection_call_finish_internal(GDBusConnection * connection,GUnixFDList ** out_fd_list,GAsyncResult * res,GError ** error)5908 g_dbus_connection_call_finish_internal (GDBusConnection  *connection,
5909                                         GUnixFDList     **out_fd_list,
5910                                         GAsyncResult     *res,
5911                                         GError          **error)
5912 {
5913   GTask *task;
5914   CallState *state;
5915   GVariant *ret;
5916 
5917   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
5918   g_return_val_if_fail (g_task_is_valid (res, connection), NULL);
5919   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
5920 
5921   task = G_TASK (res);
5922   state = g_task_get_task_data (task);
5923 
5924   ret = g_task_propagate_pointer (task, error);
5925   if (!ret)
5926     return NULL;
5927 
5928   if (out_fd_list != NULL)
5929     *out_fd_list = state->fd_list != NULL ? g_object_ref (state->fd_list) : NULL;
5930   return ret;
5931 }
5932 
5933 /* called in any user thread, with the connection's lock not held */
5934 static GVariant *
g_dbus_connection_call_sync_internal(GDBusConnection * connection,const gchar * bus_name,const gchar * object_path,const gchar * interface_name,const gchar * method_name,GVariant * parameters,const GVariantType * reply_type,GDBusCallFlags flags,gint timeout_msec,GUnixFDList * fd_list,GUnixFDList ** out_fd_list,GCancellable * cancellable,GError ** error)5935 g_dbus_connection_call_sync_internal (GDBusConnection         *connection,
5936                                       const gchar             *bus_name,
5937                                       const gchar             *object_path,
5938                                       const gchar             *interface_name,
5939                                       const gchar             *method_name,
5940                                       GVariant                *parameters,
5941                                       const GVariantType      *reply_type,
5942                                       GDBusCallFlags           flags,
5943                                       gint                     timeout_msec,
5944                                       GUnixFDList             *fd_list,
5945                                       GUnixFDList            **out_fd_list,
5946                                       GCancellable            *cancellable,
5947                                       GError                 **error)
5948 {
5949   GDBusMessage *message;
5950   GDBusMessage *reply;
5951   GVariant *result;
5952   GError *local_error;
5953   GDBusSendMessageFlags send_flags;
5954 
5955   message = NULL;
5956   reply = NULL;
5957   result = NULL;
5958 
5959   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
5960   g_return_val_if_fail (bus_name == NULL || g_dbus_is_name (bus_name), NULL);
5961   g_return_val_if_fail (object_path != NULL && g_variant_is_object_path (object_path), NULL);
5962   g_return_val_if_fail (interface_name != NULL && g_dbus_is_interface_name (interface_name), NULL);
5963   g_return_val_if_fail (method_name != NULL && g_dbus_is_member_name (method_name), NULL);
5964   g_return_val_if_fail (timeout_msec >= 0 || timeout_msec == -1, NULL);
5965   g_return_val_if_fail ((parameters == NULL) || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL);
5966 #ifdef G_OS_UNIX
5967   g_return_val_if_fail (fd_list == NULL || G_IS_UNIX_FD_LIST (fd_list), NULL);
5968 #else
5969   g_return_val_if_fail (fd_list == NULL, NULL);
5970 #endif
5971   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
5972 
5973   if (!(flags & CALL_FLAGS_INITIALIZING))
5974     g_return_val_if_fail (check_initialized (connection), FALSE);
5975 
5976   if (reply_type == NULL)
5977     reply_type = G_VARIANT_TYPE_ANY;
5978 
5979   message = g_dbus_message_new_method_call (bus_name,
5980                                             object_path,
5981                                             interface_name,
5982                                             method_name);
5983   add_call_flags (message, flags);
5984   if (parameters != NULL)
5985     g_dbus_message_set_body (message, parameters);
5986 
5987 #ifdef G_OS_UNIX
5988   if (fd_list != NULL)
5989     g_dbus_message_set_unix_fd_list (message, fd_list);
5990 #endif
5991 
5992   if (G_UNLIKELY (_g_dbus_debug_call ()))
5993     {
5994       _g_dbus_debug_print_lock ();
5995       g_print ("========================================================================\n"
5996                "GDBus-debug:Call:\n"
5997                " >>>> SYNC %s.%s()\n"
5998                "      on object %s\n"
5999                "      owned by name %s\n",
6000                interface_name,
6001                method_name,
6002                object_path,
6003                bus_name != NULL ? bus_name : "(none)");
6004       _g_dbus_debug_print_unlock ();
6005     }
6006 
6007   local_error = NULL;
6008 
6009   send_flags = G_DBUS_SEND_MESSAGE_FLAGS_NONE;
6010 
6011   /* translate from one flavour of flags to another... */
6012   if (flags & CALL_FLAGS_INITIALIZING)
6013     send_flags |= SEND_MESSAGE_FLAGS_INITIALIZING;
6014 
6015   reply = g_dbus_connection_send_message_with_reply_sync (connection,
6016                                                           message,
6017                                                           send_flags,
6018                                                           timeout_msec,
6019                                                           NULL, /* guint32 *out_serial */
6020                                                           cancellable,
6021                                                           &local_error);
6022 
6023   if (G_UNLIKELY (_g_dbus_debug_call ()))
6024     {
6025       _g_dbus_debug_print_lock ();
6026       g_print ("========================================================================\n"
6027                "GDBus-debug:Call:\n"
6028                " <<<< SYNC COMPLETE %s.%s()\n"
6029                "      ",
6030                interface_name,
6031                method_name);
6032       if (reply != NULL)
6033         {
6034           g_print ("SUCCESS\n");
6035         }
6036       else
6037         {
6038           g_print ("FAILED: %s\n",
6039                    local_error->message);
6040         }
6041       _g_dbus_debug_print_unlock ();
6042     }
6043 
6044   if (reply == NULL)
6045     {
6046       if (error != NULL)
6047         *error = local_error;
6048       else
6049         g_error_free (local_error);
6050       goto out;
6051     }
6052 
6053   result = decode_method_reply (reply, method_name, reply_type, out_fd_list, error);
6054 
6055  out:
6056   if (message != NULL)
6057     g_object_unref (message);
6058   if (reply != NULL)
6059     g_object_unref (reply);
6060 
6061   return result;
6062 }
6063 
6064 /* ---------------------------------------------------------------------------------------------------- */
6065 
6066 /**
6067  * g_dbus_connection_call:
6068  * @connection: a #GDBusConnection
6069  * @bus_name: (nullable): a unique or well-known bus name or %NULL if
6070  *     @connection is not a message bus connection
6071  * @object_path: path of remote object
6072  * @interface_name: D-Bus interface to invoke method on
6073  * @method_name: the name of the method to invoke
6074  * @parameters: (nullable): a #GVariant tuple with parameters for the method
6075  *     or %NULL if not passing parameters
6076  * @reply_type: (nullable): the expected type of the reply (which will be a
6077  *     tuple), or %NULL
6078  * @flags: flags from the #GDBusCallFlags enumeration
6079  * @timeout_msec: the timeout in milliseconds, -1 to use the default
6080  *     timeout or %G_MAXINT for no timeout
6081  * @cancellable: (nullable): a #GCancellable or %NULL
6082  * @callback: (nullable): a #GAsyncReadyCallback to call when the request
6083  *     is satisfied or %NULL if you don't care about the result of the
6084  *     method invocation
6085  * @user_data: the data to pass to @callback
6086  *
6087  * Asynchronously invokes the @method_name method on the
6088  * @interface_name D-Bus interface on the remote object at
6089  * @object_path owned by @bus_name.
6090  *
6091  * If @connection is closed then the operation will fail with
6092  * %G_IO_ERROR_CLOSED. If @cancellable is canceled, the operation will
6093  * fail with %G_IO_ERROR_CANCELLED. If @parameters contains a value
6094  * not compatible with the D-Bus protocol, the operation fails with
6095  * %G_IO_ERROR_INVALID_ARGUMENT.
6096  *
6097  * If @reply_type is non-%NULL then the reply will be checked for having this type and an
6098  * error will be raised if it does not match.  Said another way, if you give a @reply_type
6099  * then any non-%NULL return value will be of this type. Unless it’s
6100  * %G_VARIANT_TYPE_UNIT, the @reply_type will be a tuple containing one or more
6101  * values.
6102  *
6103  * If the @parameters #GVariant is floating, it is consumed. This allows
6104  * convenient 'inline' use of g_variant_new(), e.g.:
6105  * |[<!-- language="C" -->
6106  *  g_dbus_connection_call (connection,
6107  *                          "org.freedesktop.StringThings",
6108  *                          "/org/freedesktop/StringThings",
6109  *                          "org.freedesktop.StringThings",
6110  *                          "TwoStrings",
6111  *                          g_variant_new ("(ss)",
6112  *                                         "Thing One",
6113  *                                         "Thing Two"),
6114  *                          NULL,
6115  *                          G_DBUS_CALL_FLAGS_NONE,
6116  *                          -1,
6117  *                          NULL,
6118  *                          (GAsyncReadyCallback) two_strings_done,
6119  *                          NULL);
6120  * ]|
6121  *
6122  * This is an asynchronous method. When the operation is finished,
6123  * @callback will be invoked in the
6124  * [thread-default main context][g-main-context-push-thread-default]
6125  * of the thread you are calling this method from. You can then call
6126  * g_dbus_connection_call_finish() to get the result of the operation.
6127  * See g_dbus_connection_call_sync() for the synchronous version of this
6128  * function.
6129  *
6130  * If @callback is %NULL then the D-Bus method call message will be sent with
6131  * the %G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED flag set.
6132  *
6133  * Since: 2.26
6134  */
6135 void
g_dbus_connection_call(GDBusConnection * connection,const gchar * bus_name,const gchar * object_path,const gchar * interface_name,const gchar * method_name,GVariant * parameters,const GVariantType * reply_type,GDBusCallFlags flags,gint timeout_msec,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)6136 g_dbus_connection_call (GDBusConnection     *connection,
6137                         const gchar         *bus_name,
6138                         const gchar         *object_path,
6139                         const gchar         *interface_name,
6140                         const gchar         *method_name,
6141                         GVariant            *parameters,
6142                         const GVariantType  *reply_type,
6143                         GDBusCallFlags       flags,
6144                         gint                 timeout_msec,
6145                         GCancellable        *cancellable,
6146                         GAsyncReadyCallback  callback,
6147                         gpointer             user_data)
6148 {
6149   g_dbus_connection_call_internal (connection, bus_name, object_path, interface_name, method_name, parameters, reply_type, flags, timeout_msec, NULL, cancellable, callback, user_data);
6150 }
6151 
6152 /**
6153  * g_dbus_connection_call_finish:
6154  * @connection: a #GDBusConnection
6155  * @res: a #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_connection_call()
6156  * @error: return location for error or %NULL
6157  *
6158  * Finishes an operation started with g_dbus_connection_call().
6159  *
6160  * Returns: (transfer full): %NULL if @error is set. Otherwise a non-floating
6161  *     #GVariant tuple with return values. Free with g_variant_unref().
6162  *
6163  * Since: 2.26
6164  */
6165 GVariant *
g_dbus_connection_call_finish(GDBusConnection * connection,GAsyncResult * res,GError ** error)6166 g_dbus_connection_call_finish (GDBusConnection  *connection,
6167                                GAsyncResult     *res,
6168                                GError          **error)
6169 {
6170   return g_dbus_connection_call_finish_internal (connection, NULL, res, error);
6171 }
6172 
6173 /**
6174  * g_dbus_connection_call_sync:
6175  * @connection: a #GDBusConnection
6176  * @bus_name: (nullable): a unique or well-known bus name or %NULL if
6177  *     @connection is not a message bus connection
6178  * @object_path: path of remote object
6179  * @interface_name: D-Bus interface to invoke method on
6180  * @method_name: the name of the method to invoke
6181  * @parameters: (nullable): a #GVariant tuple with parameters for the method
6182  *     or %NULL if not passing parameters
6183  * @reply_type: (nullable): the expected type of the reply, or %NULL
6184  * @flags: flags from the #GDBusCallFlags enumeration
6185  * @timeout_msec: the timeout in milliseconds, -1 to use the default
6186  *     timeout or %G_MAXINT for no timeout
6187  * @cancellable: (nullable): a #GCancellable or %NULL
6188  * @error: return location for error or %NULL
6189  *
6190  * Synchronously invokes the @method_name method on the
6191  * @interface_name D-Bus interface on the remote object at
6192  * @object_path owned by @bus_name.
6193  *
6194  * If @connection is closed then the operation will fail with
6195  * %G_IO_ERROR_CLOSED. If @cancellable is canceled, the
6196  * operation will fail with %G_IO_ERROR_CANCELLED. If @parameters
6197  * contains a value not compatible with the D-Bus protocol, the operation
6198  * fails with %G_IO_ERROR_INVALID_ARGUMENT.
6199  *
6200  * If @reply_type is non-%NULL then the reply will be checked for having
6201  * this type and an error will be raised if it does not match.  Said
6202  * another way, if you give a @reply_type then any non-%NULL return
6203  * value will be of this type.
6204  *
6205  * If the @parameters #GVariant is floating, it is consumed.
6206  * This allows convenient 'inline' use of g_variant_new(), e.g.:
6207  * |[<!-- language="C" -->
6208  *  g_dbus_connection_call_sync (connection,
6209  *                               "org.freedesktop.StringThings",
6210  *                               "/org/freedesktop/StringThings",
6211  *                               "org.freedesktop.StringThings",
6212  *                               "TwoStrings",
6213  *                               g_variant_new ("(ss)",
6214  *                                              "Thing One",
6215  *                                              "Thing Two"),
6216  *                               NULL,
6217  *                               G_DBUS_CALL_FLAGS_NONE,
6218  *                               -1,
6219  *                               NULL,
6220  *                               &error);
6221  * ]|
6222  *
6223  * The calling thread is blocked until a reply is received. See
6224  * g_dbus_connection_call() for the asynchronous version of
6225  * this method.
6226  *
6227  * Returns: (transfer full): %NULL if @error is set. Otherwise a non-floating
6228  *     #GVariant tuple with return values. Free with g_variant_unref().
6229  *
6230  * Since: 2.26
6231  */
6232 GVariant *
g_dbus_connection_call_sync(GDBusConnection * connection,const gchar * bus_name,const gchar * object_path,const gchar * interface_name,const gchar * method_name,GVariant * parameters,const GVariantType * reply_type,GDBusCallFlags flags,gint timeout_msec,GCancellable * cancellable,GError ** error)6233 g_dbus_connection_call_sync (GDBusConnection     *connection,
6234                              const gchar         *bus_name,
6235                              const gchar         *object_path,
6236                              const gchar         *interface_name,
6237                              const gchar         *method_name,
6238                              GVariant            *parameters,
6239                              const GVariantType  *reply_type,
6240                              GDBusCallFlags       flags,
6241                              gint                 timeout_msec,
6242                              GCancellable        *cancellable,
6243                              GError             **error)
6244 {
6245   return g_dbus_connection_call_sync_internal (connection, bus_name, object_path, interface_name, method_name, parameters, reply_type, flags, timeout_msec, NULL, NULL, cancellable, error);
6246 }
6247 
6248 /* ---------------------------------------------------------------------------------------------------- */
6249 
6250 #ifdef G_OS_UNIX
6251 
6252 /**
6253  * g_dbus_connection_call_with_unix_fd_list:
6254  * @connection: a #GDBusConnection
6255  * @bus_name: (nullable): a unique or well-known bus name or %NULL if
6256  *     @connection is not a message bus connection
6257  * @object_path: path of remote object
6258  * @interface_name: D-Bus interface to invoke method on
6259  * @method_name: the name of the method to invoke
6260  * @parameters: (nullable): a #GVariant tuple with parameters for the method
6261  *     or %NULL if not passing parameters
6262  * @reply_type: (nullable): the expected type of the reply, or %NULL
6263  * @flags: flags from the #GDBusCallFlags enumeration
6264  * @timeout_msec: the timeout in milliseconds, -1 to use the default
6265  *     timeout or %G_MAXINT for no timeout
6266  * @fd_list: (nullable): a #GUnixFDList or %NULL
6267  * @cancellable: (nullable): a #GCancellable or %NULL
6268  * @callback: (nullable): a #GAsyncReadyCallback to call when the request is
6269  *     satisfied or %NULL if you don't * care about the result of the
6270  *     method invocation
6271  * @user_data: The data to pass to @callback.
6272  *
6273  * Like g_dbus_connection_call() but also takes a #GUnixFDList object.
6274  *
6275  * The file descriptors normally correspond to %G_VARIANT_TYPE_HANDLE
6276  * values in the body of the message. For example, if a message contains
6277  * two file descriptors, @fd_list would have length 2, and
6278  * `g_variant_new_handle (0)` and `g_variant_new_handle (1)` would appear
6279  * somewhere in the body of the message (not necessarily in that order!)
6280  * to represent the file descriptors at indexes 0 and 1 respectively.
6281  *
6282  * When designing D-Bus APIs that are intended to be interoperable,
6283  * please note that non-GDBus implementations of D-Bus can usually only
6284  * access file descriptors if they are referenced in this way by a
6285  * value of type %G_VARIANT_TYPE_HANDLE in the body of the message.
6286  *
6287  * This method is only available on UNIX.
6288  *
6289  * Since: 2.30
6290  */
6291 void
g_dbus_connection_call_with_unix_fd_list(GDBusConnection * connection,const gchar * bus_name,const gchar * object_path,const gchar * interface_name,const gchar * method_name,GVariant * parameters,const GVariantType * reply_type,GDBusCallFlags flags,gint timeout_msec,GUnixFDList * fd_list,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)6292 g_dbus_connection_call_with_unix_fd_list (GDBusConnection     *connection,
6293                                           const gchar         *bus_name,
6294                                           const gchar         *object_path,
6295                                           const gchar         *interface_name,
6296                                           const gchar         *method_name,
6297                                           GVariant            *parameters,
6298                                           const GVariantType  *reply_type,
6299                                           GDBusCallFlags       flags,
6300                                           gint                 timeout_msec,
6301                                           GUnixFDList         *fd_list,
6302                                           GCancellable        *cancellable,
6303                                           GAsyncReadyCallback  callback,
6304                                           gpointer             user_data)
6305 {
6306   g_dbus_connection_call_internal (connection, bus_name, object_path, interface_name, method_name, parameters, reply_type, flags, timeout_msec, fd_list, cancellable, callback, user_data);
6307 }
6308 
6309 /**
6310  * g_dbus_connection_call_with_unix_fd_list_finish:
6311  * @connection: a #GDBusConnection
6312  * @out_fd_list: (out) (optional): return location for a #GUnixFDList or %NULL
6313  * @res: a #GAsyncResult obtained from the #GAsyncReadyCallback passed to
6314  *     g_dbus_connection_call_with_unix_fd_list()
6315  * @error: return location for error or %NULL
6316  *
6317  * Finishes an operation started with g_dbus_connection_call_with_unix_fd_list().
6318  *
6319  * The file descriptors normally correspond to %G_VARIANT_TYPE_HANDLE
6320  * values in the body of the message. For example,
6321  * if g_variant_get_handle() returns 5, that is intended to be a reference
6322  * to the file descriptor that can be accessed by
6323  * `g_unix_fd_list_get (*out_fd_list, 5, ...)`.
6324  *
6325  * When designing D-Bus APIs that are intended to be interoperable,
6326  * please note that non-GDBus implementations of D-Bus can usually only
6327  * access file descriptors if they are referenced in this way by a
6328  * value of type %G_VARIANT_TYPE_HANDLE in the body of the message.
6329  *
6330  * Returns: (transfer full): %NULL if @error is set. Otherwise a non-floating
6331  *     #GVariant tuple with return values. Free with g_variant_unref().
6332  *
6333  * Since: 2.30
6334  */
6335 GVariant *
g_dbus_connection_call_with_unix_fd_list_finish(GDBusConnection * connection,GUnixFDList ** out_fd_list,GAsyncResult * res,GError ** error)6336 g_dbus_connection_call_with_unix_fd_list_finish (GDBusConnection  *connection,
6337                                                  GUnixFDList     **out_fd_list,
6338                                                  GAsyncResult     *res,
6339                                                  GError          **error)
6340 {
6341   return g_dbus_connection_call_finish_internal (connection, out_fd_list, res, error);
6342 }
6343 
6344 /**
6345  * g_dbus_connection_call_with_unix_fd_list_sync:
6346  * @connection: a #GDBusConnection
6347  * @bus_name: (nullable): a unique or well-known bus name or %NULL
6348  *     if @connection is not a message bus connection
6349  * @object_path: path of remote object
6350  * @interface_name: D-Bus interface to invoke method on
6351  * @method_name: the name of the method to invoke
6352  * @parameters: (nullable): a #GVariant tuple with parameters for
6353  *     the method or %NULL if not passing parameters
6354  * @reply_type: (nullable): the expected type of the reply, or %NULL
6355  * @flags: flags from the #GDBusCallFlags enumeration
6356  * @timeout_msec: the timeout in milliseconds, -1 to use the default
6357  *     timeout or %G_MAXINT for no timeout
6358  * @fd_list: (nullable): a #GUnixFDList or %NULL
6359  * @out_fd_list: (out) (optional): return location for a #GUnixFDList or %NULL
6360  * @cancellable: (nullable): a #GCancellable or %NULL
6361  * @error: return location for error or %NULL
6362  *
6363  * Like g_dbus_connection_call_sync() but also takes and returns #GUnixFDList objects.
6364  * See g_dbus_connection_call_with_unix_fd_list() and
6365  * g_dbus_connection_call_with_unix_fd_list_finish() for more details.
6366  *
6367  * This method is only available on UNIX.
6368  *
6369  * Returns: (transfer full): %NULL if @error is set. Otherwise a non-floating
6370  *     #GVariant tuple with return values. Free with g_variant_unref().
6371  *
6372  * Since: 2.30
6373  */
6374 GVariant *
g_dbus_connection_call_with_unix_fd_list_sync(GDBusConnection * connection,const gchar * bus_name,const gchar * object_path,const gchar * interface_name,const gchar * method_name,GVariant * parameters,const GVariantType * reply_type,GDBusCallFlags flags,gint timeout_msec,GUnixFDList * fd_list,GUnixFDList ** out_fd_list,GCancellable * cancellable,GError ** error)6375 g_dbus_connection_call_with_unix_fd_list_sync (GDBusConnection     *connection,
6376                                                const gchar         *bus_name,
6377                                                const gchar         *object_path,
6378                                                const gchar         *interface_name,
6379                                                const gchar         *method_name,
6380                                                GVariant            *parameters,
6381                                                const GVariantType  *reply_type,
6382                                                GDBusCallFlags       flags,
6383                                                gint                 timeout_msec,
6384                                                GUnixFDList         *fd_list,
6385                                                GUnixFDList        **out_fd_list,
6386                                                GCancellable        *cancellable,
6387                                                GError             **error)
6388 {
6389   return g_dbus_connection_call_sync_internal (connection, bus_name, object_path, interface_name, method_name, parameters, reply_type, flags, timeout_msec, fd_list, out_fd_list, cancellable, error);
6390 }
6391 
6392 #endif /* G_OS_UNIX */
6393 
6394 /* ---------------------------------------------------------------------------------------------------- */
6395 
6396 struct ExportedSubtree
6397 {
6398   guint                     id;
6399   gchar                    *object_path;
6400   GDBusConnection          *connection;
6401   GDBusSubtreeVTable       *vtable;
6402   GDBusSubtreeFlags         flags;
6403 
6404   GMainContext             *context;
6405   gpointer                  user_data;
6406   GDestroyNotify            user_data_free_func;
6407 };
6408 
6409 static void
exported_subtree_free(ExportedSubtree * es)6410 exported_subtree_free (ExportedSubtree *es)
6411 {
6412   call_destroy_notify (es->context,
6413                        es->user_data_free_func,
6414                        es->user_data);
6415 
6416   g_main_context_unref (es->context);
6417 
6418   _g_dbus_subtree_vtable_free (es->vtable);
6419   g_free (es->object_path);
6420   g_free (es);
6421 }
6422 
6423 /* called without lock held in the thread where the caller registered
6424  * the subtree
6425  */
6426 static gboolean
handle_subtree_introspect(GDBusConnection * connection,ExportedSubtree * es,GDBusMessage * message)6427 handle_subtree_introspect (GDBusConnection *connection,
6428                            ExportedSubtree *es,
6429                            GDBusMessage    *message)
6430 {
6431   GString *s;
6432   gboolean handled;
6433   GDBusMessage *reply;
6434   gchar **children;
6435   gboolean is_root;
6436   const gchar *sender;
6437   const gchar *requested_object_path;
6438   const gchar *requested_node;
6439   GDBusInterfaceInfo **interfaces;
6440   guint n;
6441   gchar **subnode_paths;
6442   gboolean has_properties_interface;
6443   gboolean has_introspectable_interface;
6444 
6445   handled = FALSE;
6446 
6447   requested_object_path = g_dbus_message_get_path (message);
6448   sender = g_dbus_message_get_sender (message);
6449   is_root = (g_strcmp0 (requested_object_path, es->object_path) == 0);
6450 
6451   s = g_string_new (NULL);
6452   introspect_append_header (s);
6453 
6454   /* Strictly we don't need the children in dynamic mode, but we avoid the
6455    * conditionals to preserve code clarity
6456    */
6457   children = es->vtable->enumerate (es->connection,
6458                                     sender,
6459                                     es->object_path,
6460                                     es->user_data);
6461 
6462   if (!is_root)
6463     {
6464       requested_node = strrchr (requested_object_path, '/') + 1;
6465 
6466       /* Assert existence of object if we are not dynamic */
6467       if (!(es->flags & G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES) &&
6468           !_g_strv_has_string ((const gchar * const *) children, requested_node))
6469         goto out;
6470     }
6471   else
6472     {
6473       requested_node = NULL;
6474     }
6475 
6476   interfaces = es->vtable->introspect (es->connection,
6477                                        sender,
6478                                        es->object_path,
6479                                        requested_node,
6480                                        es->user_data);
6481   if (interfaces != NULL)
6482     {
6483       has_properties_interface = FALSE;
6484       has_introspectable_interface = FALSE;
6485 
6486       for (n = 0; interfaces[n] != NULL; n++)
6487         {
6488           if (strcmp (interfaces[n]->name, "org.freedesktop.DBus.Properties") == 0)
6489             has_properties_interface = TRUE;
6490           else if (strcmp (interfaces[n]->name, "org.freedesktop.DBus.Introspectable") == 0)
6491             has_introspectable_interface = TRUE;
6492         }
6493       if (!has_properties_interface)
6494         g_string_append (s, introspect_properties_interface);
6495       if (!has_introspectable_interface)
6496         g_string_append (s, introspect_introspectable_interface);
6497 
6498       for (n = 0; interfaces[n] != NULL; n++)
6499         {
6500           g_dbus_interface_info_generate_xml (interfaces[n], 2, s);
6501           g_dbus_interface_info_unref (interfaces[n]);
6502         }
6503       g_free (interfaces);
6504     }
6505 
6506   /* then include <node> entries from the Subtree for the root */
6507   if (is_root)
6508     {
6509       for (n = 0; children != NULL && children[n] != NULL; n++)
6510         g_string_append_printf (s, "  <node name=\"%s\"/>\n", children[n]);
6511     }
6512 
6513   /* finally include nodes registered below us */
6514   subnode_paths = g_dbus_connection_list_registered (es->connection, requested_object_path);
6515   for (n = 0; subnode_paths != NULL && subnode_paths[n] != NULL; n++)
6516     g_string_append_printf (s, "  <node name=\"%s\"/>\n", subnode_paths[n]);
6517   g_strfreev (subnode_paths);
6518 
6519   g_string_append (s, "</node>\n");
6520 
6521   reply = g_dbus_message_new_method_reply (message);
6522   g_dbus_message_set_body (reply, g_variant_new ("(s)", s->str));
6523   g_dbus_connection_send_message (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
6524   g_object_unref (reply);
6525 
6526   handled = TRUE;
6527 
6528  out:
6529   g_string_free (s, TRUE);
6530   g_strfreev (children);
6531   return handled;
6532 }
6533 
6534 /* called without lock held in the thread where the caller registered
6535  * the subtree
6536  */
6537 static gboolean
handle_subtree_method_invocation(GDBusConnection * connection,ExportedSubtree * es,GDBusMessage * message)6538 handle_subtree_method_invocation (GDBusConnection *connection,
6539                                   ExportedSubtree *es,
6540                                   GDBusMessage    *message)
6541 {
6542   gboolean handled;
6543   const gchar *sender;
6544   const gchar *interface_name;
6545   const gchar *member;
6546   const gchar *signature;
6547   const gchar *requested_object_path;
6548   const gchar *requested_node;
6549   gboolean is_root;
6550   GDBusInterfaceInfo *interface_info;
6551   const GDBusInterfaceVTable *interface_vtable;
6552   gpointer interface_user_data;
6553   guint n;
6554   GDBusInterfaceInfo **interfaces;
6555   gboolean is_property_get;
6556   gboolean is_property_set;
6557   gboolean is_property_get_all;
6558 
6559   handled = FALSE;
6560   interfaces = NULL;
6561 
6562   requested_object_path = g_dbus_message_get_path (message);
6563   sender = g_dbus_message_get_sender (message);
6564   interface_name = g_dbus_message_get_interface (message);
6565   member = g_dbus_message_get_member (message);
6566   signature = g_dbus_message_get_signature (message);
6567   is_root = (g_strcmp0 (requested_object_path, es->object_path) == 0);
6568 
6569   is_property_get = FALSE;
6570   is_property_set = FALSE;
6571   is_property_get_all = FALSE;
6572   if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Properties") == 0)
6573     {
6574       if (g_strcmp0 (member, "Get") == 0 && g_strcmp0 (signature, "ss") == 0)
6575         is_property_get = TRUE;
6576       else if (g_strcmp0 (member, "Set") == 0 && g_strcmp0 (signature, "ssv") == 0)
6577         is_property_set = TRUE;
6578       else if (g_strcmp0 (member, "GetAll") == 0 && g_strcmp0 (signature, "s") == 0)
6579         is_property_get_all = TRUE;
6580     }
6581 
6582   if (!is_root)
6583     {
6584       requested_node = strrchr (requested_object_path, '/') + 1;
6585 
6586       if (~es->flags & G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES)
6587         {
6588           /* We don't want to dispatch to unenumerated
6589            * nodes, so ensure that the child exists.
6590            */
6591           gchar **children;
6592           gboolean exists;
6593 
6594           children = es->vtable->enumerate (es->connection,
6595                                             sender,
6596                                             es->object_path,
6597                                             es->user_data);
6598 
6599           exists = _g_strv_has_string ((const gchar * const *) children, requested_node);
6600           g_strfreev (children);
6601 
6602           if (!exists)
6603             goto out;
6604         }
6605     }
6606   else
6607     {
6608       requested_node = NULL;
6609     }
6610 
6611   /* get introspection data for the node */
6612   interfaces = es->vtable->introspect (es->connection,
6613                                        sender,
6614                                        requested_object_path,
6615                                        requested_node,
6616                                        es->user_data);
6617 
6618   if (interfaces == NULL)
6619     goto out;
6620 
6621   interface_info = NULL;
6622   for (n = 0; interfaces[n] != NULL; n++)
6623     {
6624       if (g_strcmp0 (interfaces[n]->name, interface_name) == 0)
6625         interface_info = interfaces[n];
6626     }
6627 
6628   /* dispatch the call if the user wants to handle it */
6629   if (interface_info != NULL)
6630     {
6631       /* figure out where to dispatch the method call */
6632       interface_user_data = NULL;
6633       interface_vtable = es->vtable->dispatch (es->connection,
6634                                                sender,
6635                                                es->object_path,
6636                                                interface_name,
6637                                                requested_node,
6638                                                &interface_user_data,
6639                                                es->user_data);
6640       if (interface_vtable == NULL)
6641         goto out;
6642 
6643       CONNECTION_LOCK (connection);
6644       handled = validate_and_maybe_schedule_method_call (es->connection,
6645                                                          message,
6646                                                          0,
6647                                                          es->id,
6648                                                          interface_info,
6649                                                          interface_vtable,
6650                                                          es->context,
6651                                                          interface_user_data);
6652       CONNECTION_UNLOCK (connection);
6653     }
6654   /* handle org.freedesktop.DBus.Properties interface if not explicitly handled */
6655   else if (is_property_get || is_property_set || is_property_get_all)
6656     {
6657       if (is_property_get)
6658         g_variant_get (g_dbus_message_get_body (message), "(&s&s)", &interface_name, NULL);
6659       else if (is_property_set)
6660         g_variant_get (g_dbus_message_get_body (message), "(&s&sv)", &interface_name, NULL, NULL);
6661       else if (is_property_get_all)
6662         g_variant_get (g_dbus_message_get_body (message), "(&s)", &interface_name, NULL, NULL);
6663       else
6664         g_assert_not_reached ();
6665 
6666       /* see if the object supports this interface at all */
6667       for (n = 0; interfaces[n] != NULL; n++)
6668         {
6669           if (g_strcmp0 (interfaces[n]->name, interface_name) == 0)
6670             interface_info = interfaces[n];
6671         }
6672 
6673       /* Fail with org.freedesktop.DBus.Error.InvalidArgs if the user-code
6674        * claims it won't support the interface
6675        */
6676       if (interface_info == NULL)
6677         {
6678           GDBusMessage *reply;
6679           reply = g_dbus_message_new_method_error (message,
6680                                                    "org.freedesktop.DBus.Error.InvalidArgs",
6681                                                    _("No such interface “%s”"),
6682                                                    interface_name);
6683           g_dbus_connection_send_message (es->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
6684           g_object_unref (reply);
6685           handled = TRUE;
6686           goto out;
6687         }
6688 
6689       /* figure out where to dispatch the property get/set/getall calls */
6690       interface_user_data = NULL;
6691       interface_vtable = es->vtable->dispatch (es->connection,
6692                                                sender,
6693                                                es->object_path,
6694                                                interface_name,
6695                                                requested_node,
6696                                                &interface_user_data,
6697                                                es->user_data);
6698       if (interface_vtable == NULL)
6699         {
6700           g_warning ("The subtree introspection function indicates that '%s' "
6701                      "is a valid interface name, but calling the dispatch "
6702                      "function on that interface gave us NULL", interface_name);
6703           goto out;
6704         }
6705 
6706       if (is_property_get || is_property_set)
6707         {
6708           CONNECTION_LOCK (connection);
6709           handled = validate_and_maybe_schedule_property_getset (es->connection,
6710                                                                  message,
6711                                                                  0,
6712                                                                  es->id,
6713                                                                  is_property_get,
6714                                                                  interface_info,
6715                                                                  interface_vtable,
6716                                                                  es->context,
6717                                                                  interface_user_data);
6718           CONNECTION_UNLOCK (connection);
6719         }
6720       else if (is_property_get_all)
6721         {
6722           CONNECTION_LOCK (connection);
6723           handled = validate_and_maybe_schedule_property_get_all (es->connection,
6724                                                                   message,
6725                                                                   0,
6726                                                                   es->id,
6727                                                                   interface_info,
6728                                                                   interface_vtable,
6729                                                                   es->context,
6730                                                                   interface_user_data);
6731           CONNECTION_UNLOCK (connection);
6732         }
6733     }
6734 
6735  out:
6736   if (interfaces != NULL)
6737     {
6738       for (n = 0; interfaces[n] != NULL; n++)
6739         g_dbus_interface_info_unref (interfaces[n]);
6740       g_free (interfaces);
6741     }
6742 
6743   return handled;
6744 }
6745 
6746 typedef struct
6747 {
6748   GDBusMessage *message;
6749   ExportedSubtree *es;
6750 } SubtreeDeferredData;
6751 
6752 static void
subtree_deferred_data_free(SubtreeDeferredData * data)6753 subtree_deferred_data_free (SubtreeDeferredData *data)
6754 {
6755   g_object_unref (data->message);
6756   g_free (data);
6757 }
6758 
6759 /* called without lock held in the thread where the caller registered the subtree */
6760 static gboolean
process_subtree_vtable_message_in_idle_cb(gpointer _data)6761 process_subtree_vtable_message_in_idle_cb (gpointer _data)
6762 {
6763   SubtreeDeferredData *data = _data;
6764   gboolean handled;
6765 
6766   handled = FALSE;
6767 
6768   if (g_strcmp0 (g_dbus_message_get_interface (data->message), "org.freedesktop.DBus.Introspectable") == 0 &&
6769       g_strcmp0 (g_dbus_message_get_member (data->message), "Introspect") == 0 &&
6770       g_strcmp0 (g_dbus_message_get_signature (data->message), "") == 0)
6771     handled = handle_subtree_introspect (data->es->connection,
6772                                          data->es,
6773                                          data->message);
6774   else
6775     handled = handle_subtree_method_invocation (data->es->connection,
6776                                                 data->es,
6777                                                 data->message);
6778 
6779   if (!handled)
6780     {
6781       CONNECTION_LOCK (data->es->connection);
6782       handled = handle_generic_unlocked (data->es->connection, data->message);
6783       CONNECTION_UNLOCK (data->es->connection);
6784     }
6785 
6786   /* if we couldn't handle the request, just bail with the UnknownMethod error */
6787   if (!handled)
6788     {
6789       GDBusMessage *reply;
6790       reply = g_dbus_message_new_method_error (data->message,
6791                                                "org.freedesktop.DBus.Error.UnknownMethod",
6792                                                _("Method “%s” on interface “%s” with signature “%s” does not exist"),
6793                                                g_dbus_message_get_member (data->message),
6794                                                g_dbus_message_get_interface (data->message),
6795                                                g_dbus_message_get_signature (data->message));
6796       g_dbus_connection_send_message (data->es->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
6797       g_object_unref (reply);
6798     }
6799 
6800   return FALSE;
6801 }
6802 
6803 /* called in GDBusWorker thread with connection's lock held */
6804 static gboolean
subtree_message_func(GDBusConnection * connection,ExportedSubtree * es,GDBusMessage * message)6805 subtree_message_func (GDBusConnection *connection,
6806                       ExportedSubtree *es,
6807                       GDBusMessage    *message)
6808 {
6809   GSource *idle_source;
6810   SubtreeDeferredData *data;
6811 
6812   data = g_new0 (SubtreeDeferredData, 1);
6813   data->message = g_object_ref (message);
6814   data->es = es;
6815 
6816   /* defer this call to an idle handler in the right thread */
6817   idle_source = g_idle_source_new ();
6818   g_source_set_priority (idle_source, G_PRIORITY_HIGH);
6819   g_source_set_callback (idle_source,
6820                          process_subtree_vtable_message_in_idle_cb,
6821                          data,
6822                          (GDestroyNotify) subtree_deferred_data_free);
6823   g_source_set_name (idle_source, "[gio] process_subtree_vtable_message_in_idle_cb");
6824   g_source_attach (idle_source, es->context);
6825   g_source_unref (idle_source);
6826 
6827   /* since we own the entire subtree, handlers for objects not in the subtree have been
6828    * tried already by libdbus-1 - so we just need to ensure that we're always going
6829    * to reply to the message
6830    */
6831   return TRUE;
6832 }
6833 
6834 /**
6835  * g_dbus_connection_register_subtree:
6836  * @connection: a #GDBusConnection
6837  * @object_path: the object path to register the subtree at
6838  * @vtable: a #GDBusSubtreeVTable to enumerate, introspect and
6839  *     dispatch nodes in the subtree
6840  * @flags: flags used to fine tune the behavior of the subtree
6841  * @user_data: data to pass to functions in @vtable
6842  * @user_data_free_func: function to call when the subtree is unregistered
6843  * @error: return location for error or %NULL
6844  *
6845  * Registers a whole subtree of dynamic objects.
6846  *
6847  * The @enumerate and @introspection functions in @vtable are used to
6848  * convey, to remote callers, what nodes exist in the subtree rooted
6849  * by @object_path.
6850  *
6851  * When handling remote calls into any node in the subtree, first the
6852  * @enumerate function is used to check if the node exists. If the node exists
6853  * or the #G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES flag is set
6854  * the @introspection function is used to check if the node supports the
6855  * requested method. If so, the @dispatch function is used to determine
6856  * where to dispatch the call. The collected #GDBusInterfaceVTable and
6857  * #gpointer will be used to call into the interface vtable for processing
6858  * the request.
6859  *
6860  * All calls into user-provided code will be invoked in the
6861  * [thread-default main context][g-main-context-push-thread-default]
6862  * of the thread you are calling this method from.
6863  *
6864  * If an existing subtree is already registered at @object_path or
6865  * then @error is set to #G_IO_ERROR_EXISTS.
6866  *
6867  * Note that it is valid to register regular objects (using
6868  * g_dbus_connection_register_object()) in a subtree registered with
6869  * g_dbus_connection_register_subtree() - if so, the subtree handler
6870  * is tried as the last resort. One way to think about a subtree
6871  * handler is to consider it a fallback handler for object paths not
6872  * registered via g_dbus_connection_register_object() or other bindings.
6873  *
6874  * Note that @vtable will be copied so you cannot change it after
6875  * registration.
6876  *
6877  * See this [server][gdbus-subtree-server] for an example of how to use
6878  * this method.
6879  *
6880  * Returns: 0 if @error is set, otherwise a subtree registration ID (never 0)
6881  * that can be used with g_dbus_connection_unregister_subtree()
6882  *
6883  * Since: 2.26
6884  */
6885 guint
g_dbus_connection_register_subtree(GDBusConnection * connection,const gchar * object_path,const GDBusSubtreeVTable * vtable,GDBusSubtreeFlags flags,gpointer user_data,GDestroyNotify user_data_free_func,GError ** error)6886 g_dbus_connection_register_subtree (GDBusConnection           *connection,
6887                                     const gchar               *object_path,
6888                                     const GDBusSubtreeVTable  *vtable,
6889                                     GDBusSubtreeFlags          flags,
6890                                     gpointer                   user_data,
6891                                     GDestroyNotify             user_data_free_func,
6892                                     GError                   **error)
6893 {
6894   guint ret;
6895   ExportedSubtree *es;
6896 
6897   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
6898   g_return_val_if_fail (object_path != NULL && g_variant_is_object_path (object_path), 0);
6899   g_return_val_if_fail (vtable != NULL, 0);
6900   g_return_val_if_fail (error == NULL || *error == NULL, 0);
6901   g_return_val_if_fail (check_initialized (connection), 0);
6902 
6903   ret = 0;
6904 
6905   CONNECTION_LOCK (connection);
6906 
6907   es = g_hash_table_lookup (connection->map_object_path_to_es, object_path);
6908   if (es != NULL)
6909     {
6910       g_set_error (error,
6911                    G_IO_ERROR,
6912                    G_IO_ERROR_EXISTS,
6913                    _("A subtree is already exported for %s"),
6914                    object_path);
6915       goto out;
6916     }
6917 
6918   es = g_new0 (ExportedSubtree, 1);
6919   es->object_path = g_strdup (object_path);
6920   es->connection = connection;
6921 
6922   es->vtable = _g_dbus_subtree_vtable_copy (vtable);
6923   es->flags = flags;
6924   es->id = (guint) g_atomic_int_add (&_global_subtree_registration_id, 1); /* TODO: overflow etc. */
6925   es->user_data = user_data;
6926   es->user_data_free_func = user_data_free_func;
6927   es->context = g_main_context_ref_thread_default ();
6928 
6929   g_hash_table_insert (connection->map_object_path_to_es, es->object_path, es);
6930   g_hash_table_insert (connection->map_id_to_es,
6931                        GUINT_TO_POINTER (es->id),
6932                        es);
6933 
6934   ret = es->id;
6935 
6936  out:
6937   CONNECTION_UNLOCK (connection);
6938 
6939   return ret;
6940 }
6941 
6942 /* ---------------------------------------------------------------------------------------------------- */
6943 
6944 /**
6945  * g_dbus_connection_unregister_subtree:
6946  * @connection: a #GDBusConnection
6947  * @registration_id: a subtree registration id obtained from
6948  *     g_dbus_connection_register_subtree()
6949  *
6950  * Unregisters a subtree.
6951  *
6952  * Returns: %TRUE if the subtree was unregistered, %FALSE otherwise
6953  *
6954  * Since: 2.26
6955  */
6956 gboolean
g_dbus_connection_unregister_subtree(GDBusConnection * connection,guint registration_id)6957 g_dbus_connection_unregister_subtree (GDBusConnection *connection,
6958                                       guint            registration_id)
6959 {
6960   ExportedSubtree *es;
6961   gboolean ret;
6962 
6963   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
6964   g_return_val_if_fail (check_initialized (connection), FALSE);
6965 
6966   ret = FALSE;
6967 
6968   CONNECTION_LOCK (connection);
6969 
6970   es = g_hash_table_lookup (connection->map_id_to_es,
6971                             GUINT_TO_POINTER (registration_id));
6972   if (es == NULL)
6973     goto out;
6974 
6975   g_warn_if_fail (g_hash_table_remove (connection->map_id_to_es, GUINT_TO_POINTER (es->id)));
6976   g_warn_if_fail (g_hash_table_remove (connection->map_object_path_to_es, es->object_path));
6977 
6978   ret = TRUE;
6979 
6980  out:
6981   CONNECTION_UNLOCK (connection);
6982 
6983   return ret;
6984 }
6985 
6986 /* ---------------------------------------------------------------------------------------------------- */
6987 
6988 /* may be called in any thread, with connection's lock held */
6989 static void
handle_generic_ping_unlocked(GDBusConnection * connection,const gchar * object_path,GDBusMessage * message)6990 handle_generic_ping_unlocked (GDBusConnection *connection,
6991                               const gchar     *object_path,
6992                               GDBusMessage    *message)
6993 {
6994   GDBusMessage *reply;
6995   reply = g_dbus_message_new_method_reply (message);
6996   g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
6997   g_object_unref (reply);
6998 }
6999 
7000 /* may be called in any thread, with connection's lock held */
7001 static void
handle_generic_get_machine_id_unlocked(GDBusConnection * connection,const gchar * object_path,GDBusMessage * message)7002 handle_generic_get_machine_id_unlocked (GDBusConnection *connection,
7003                                         const gchar     *object_path,
7004                                         GDBusMessage    *message)
7005 {
7006   GDBusMessage *reply;
7007 
7008   reply = NULL;
7009   if (connection->machine_id == NULL)
7010     {
7011       GError *error;
7012 
7013       error = NULL;
7014       connection->machine_id = _g_dbus_get_machine_id (&error);
7015       if (connection->machine_id == NULL)
7016         {
7017           reply = g_dbus_message_new_method_error_literal (message,
7018                                                            "org.freedesktop.DBus.Error.Failed",
7019                                                            error->message);
7020           g_error_free (error);
7021         }
7022     }
7023 
7024   if (reply == NULL)
7025     {
7026       reply = g_dbus_message_new_method_reply (message);
7027       g_dbus_message_set_body (reply, g_variant_new ("(s)", connection->machine_id));
7028     }
7029   g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
7030   g_object_unref (reply);
7031 }
7032 
7033 /* may be called in any thread, with connection's lock held */
7034 static void
handle_generic_introspect_unlocked(GDBusConnection * connection,const gchar * object_path,GDBusMessage * message)7035 handle_generic_introspect_unlocked (GDBusConnection *connection,
7036                                     const gchar     *object_path,
7037                                     GDBusMessage    *message)
7038 {
7039   guint n;
7040   GString *s;
7041   gchar **registered;
7042   GDBusMessage *reply;
7043 
7044   /* first the header */
7045   s = g_string_new (NULL);
7046   introspect_append_header (s);
7047 
7048   registered = g_dbus_connection_list_registered_unlocked (connection, object_path);
7049   for (n = 0; registered != NULL && registered[n] != NULL; n++)
7050       g_string_append_printf (s, "  <node name=\"%s\"/>\n", registered[n]);
7051   g_strfreev (registered);
7052   g_string_append (s, "</node>\n");
7053 
7054   reply = g_dbus_message_new_method_reply (message);
7055   g_dbus_message_set_body (reply, g_variant_new ("(s)", s->str));
7056   g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
7057   g_object_unref (reply);
7058   g_string_free (s, TRUE);
7059 }
7060 
7061 /* may be called in any thread, with connection's lock held */
7062 static gboolean
handle_generic_unlocked(GDBusConnection * connection,GDBusMessage * message)7063 handle_generic_unlocked (GDBusConnection *connection,
7064                          GDBusMessage    *message)
7065 {
7066   gboolean handled;
7067   const gchar *interface_name;
7068   const gchar *member;
7069   const gchar *signature;
7070   const gchar *path;
7071 
7072   CONNECTION_ENSURE_LOCK (connection);
7073 
7074   handled = FALSE;
7075 
7076   interface_name = g_dbus_message_get_interface (message);
7077   member = g_dbus_message_get_member (message);
7078   signature = g_dbus_message_get_signature (message);
7079   path = g_dbus_message_get_path (message);
7080 
7081   if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Introspectable") == 0 &&
7082       g_strcmp0 (member, "Introspect") == 0 &&
7083       g_strcmp0 (signature, "") == 0)
7084     {
7085       handle_generic_introspect_unlocked (connection, path, message);
7086       handled = TRUE;
7087     }
7088   else if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Peer") == 0 &&
7089            g_strcmp0 (member, "Ping") == 0 &&
7090            g_strcmp0 (signature, "") == 0)
7091     {
7092       handle_generic_ping_unlocked (connection, path, message);
7093       handled = TRUE;
7094     }
7095   else if (g_strcmp0 (interface_name, "org.freedesktop.DBus.Peer") == 0 &&
7096            g_strcmp0 (member, "GetMachineId") == 0 &&
7097            g_strcmp0 (signature, "") == 0)
7098     {
7099       handle_generic_get_machine_id_unlocked (connection, path, message);
7100       handled = TRUE;
7101     }
7102 
7103   return handled;
7104 }
7105 
7106 /* ---------------------------------------------------------------------------------------------------- */
7107 
7108 /* called in GDBusWorker thread with connection's lock held */
7109 static void
distribute_method_call(GDBusConnection * connection,GDBusMessage * message)7110 distribute_method_call (GDBusConnection *connection,
7111                         GDBusMessage    *message)
7112 {
7113   GDBusMessage *reply;
7114   ExportedObject *eo;
7115   ExportedSubtree *es;
7116   const gchar *object_path;
7117   const gchar *interface_name;
7118   const gchar *member;
7119   const gchar *path;
7120   gchar *subtree_path;
7121   gchar *needle;
7122 
7123   g_assert (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL);
7124 
7125   interface_name = g_dbus_message_get_interface (message);
7126   member = g_dbus_message_get_member (message);
7127   path = g_dbus_message_get_path (message);
7128   subtree_path = g_strdup (path);
7129   needle = strrchr (subtree_path, '/');
7130   if (needle != NULL && needle != subtree_path)
7131     {
7132       *needle = '\0';
7133     }
7134   else
7135     {
7136       g_free (subtree_path);
7137       subtree_path = NULL;
7138     }
7139 
7140 
7141   if (G_UNLIKELY (_g_dbus_debug_incoming ()))
7142     {
7143       _g_dbus_debug_print_lock ();
7144       g_print ("========================================================================\n"
7145                "GDBus-debug:Incoming:\n"
7146                " <<<< METHOD INVOCATION %s.%s()\n"
7147                "      on object %s\n"
7148                "      invoked by name %s\n"
7149                "      serial %d\n",
7150                interface_name, member,
7151                path,
7152                g_dbus_message_get_sender (message) != NULL ? g_dbus_message_get_sender (message) : "(none)",
7153                g_dbus_message_get_serial (message));
7154       _g_dbus_debug_print_unlock ();
7155     }
7156 
7157   object_path = g_dbus_message_get_path (message);
7158   g_assert (object_path != NULL);
7159 
7160   eo = g_hash_table_lookup (connection->map_object_path_to_eo, object_path);
7161   if (eo != NULL)
7162     {
7163       if (obj_message_func (connection, eo, message))
7164         goto out;
7165     }
7166 
7167   es = g_hash_table_lookup (connection->map_object_path_to_es, object_path);
7168   if (es != NULL)
7169     {
7170       if (subtree_message_func (connection, es, message))
7171         goto out;
7172     }
7173 
7174   if (subtree_path != NULL)
7175     {
7176       es = g_hash_table_lookup (connection->map_object_path_to_es, subtree_path);
7177       if (es != NULL)
7178         {
7179           if (subtree_message_func (connection, es, message))
7180             goto out;
7181         }
7182     }
7183 
7184   if (handle_generic_unlocked (connection, message))
7185     goto out;
7186 
7187   /* if we end up here, the message has not been not handled - so return an error saying this */
7188   reply = g_dbus_message_new_method_error (message,
7189                                            "org.freedesktop.DBus.Error.UnknownMethod",
7190                                            _("No such interface “%s” on object at path %s"),
7191                                            interface_name,
7192                                            object_path);
7193   g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
7194   g_object_unref (reply);
7195 
7196  out:
7197   g_free (subtree_path);
7198 }
7199 
7200 /* ---------------------------------------------------------------------------------------------------- */
7201 
7202 /* Called in any user thread, with the message_bus_lock held. */
7203 static GWeakRef *
message_bus_get_singleton(GBusType bus_type,GError ** error)7204 message_bus_get_singleton (GBusType   bus_type,
7205                            GError   **error)
7206 {
7207   GWeakRef *ret;
7208   const gchar *starter_bus;
7209 
7210   ret = NULL;
7211 
7212   switch (bus_type)
7213     {
7214     case G_BUS_TYPE_SESSION:
7215       ret = &the_session_bus;
7216       break;
7217 
7218     case G_BUS_TYPE_SYSTEM:
7219       ret = &the_system_bus;
7220       break;
7221 
7222     case G_BUS_TYPE_STARTER:
7223       starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
7224       if (g_strcmp0 (starter_bus, "session") == 0)
7225         {
7226           ret = message_bus_get_singleton (G_BUS_TYPE_SESSION, error);
7227           goto out;
7228         }
7229       else if (g_strcmp0 (starter_bus, "system") == 0)
7230         {
7231           ret = message_bus_get_singleton (G_BUS_TYPE_SYSTEM, error);
7232           goto out;
7233         }
7234       else
7235         {
7236           if (starter_bus != NULL)
7237             {
7238               g_set_error (error,
7239                            G_IO_ERROR,
7240                            G_IO_ERROR_INVALID_ARGUMENT,
7241                            _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
7242                              " — unknown value “%s”"),
7243                            starter_bus);
7244             }
7245           else
7246             {
7247               g_set_error_literal (error,
7248                                    G_IO_ERROR,
7249                                    G_IO_ERROR_INVALID_ARGUMENT,
7250                                    _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
7251                                      "variable is not set"));
7252             }
7253         }
7254       break;
7255 
7256     default:
7257       g_assert_not_reached ();
7258       break;
7259     }
7260 
7261  out:
7262   return ret;
7263 }
7264 
7265 /* Called in any user thread, without holding locks. */
7266 static GDBusConnection *
get_uninitialized_connection(GBusType bus_type,GCancellable * cancellable,GError ** error)7267 get_uninitialized_connection (GBusType       bus_type,
7268                               GCancellable  *cancellable,
7269                               GError       **error)
7270 {
7271   GWeakRef *singleton;
7272   GDBusConnection *ret;
7273 
7274   ret = NULL;
7275 
7276   G_LOCK (message_bus_lock);
7277   singleton = message_bus_get_singleton (bus_type, error);
7278   if (singleton == NULL)
7279     goto out;
7280 
7281   ret = g_weak_ref_get (singleton);
7282 
7283   if (ret == NULL)
7284     {
7285       gchar *address;
7286       address = g_dbus_address_get_for_bus_sync (bus_type, cancellable, error);
7287       if (address == NULL)
7288         goto out;
7289       ret = g_object_new (G_TYPE_DBUS_CONNECTION,
7290                           "address", address,
7291                           "flags", G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
7292                                    G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
7293                           "exit-on-close", TRUE,
7294                           NULL);
7295 
7296       g_weak_ref_set (singleton, ret);
7297       g_free (address);
7298     }
7299 
7300   g_assert (ret != NULL);
7301 
7302  out:
7303   G_UNLOCK (message_bus_lock);
7304   return ret;
7305 }
7306 
7307 /* May be called from any thread. Must not hold message_bus_lock. */
7308 GDBusConnection *
_g_bus_get_singleton_if_exists(GBusType bus_type)7309 _g_bus_get_singleton_if_exists (GBusType bus_type)
7310 {
7311   GWeakRef *singleton;
7312   GDBusConnection *ret = NULL;
7313 
7314   G_LOCK (message_bus_lock);
7315   singleton = message_bus_get_singleton (bus_type, NULL);
7316   if (singleton == NULL)
7317     goto out;
7318 
7319   ret = g_weak_ref_get (singleton);
7320 
7321  out:
7322   G_UNLOCK (message_bus_lock);
7323   return ret;
7324 }
7325 
7326 /* May be called from any thread. Must not hold message_bus_lock. */
7327 void
_g_bus_forget_singleton(GBusType bus_type)7328 _g_bus_forget_singleton (GBusType bus_type)
7329 {
7330   GWeakRef *singleton;
7331 
7332   G_LOCK (message_bus_lock);
7333 
7334   singleton = message_bus_get_singleton (bus_type, NULL);
7335 
7336   if (singleton != NULL)
7337     g_weak_ref_set (singleton, NULL);
7338 
7339   G_UNLOCK (message_bus_lock);
7340 }
7341 
7342 /**
7343  * g_bus_get_sync:
7344  * @bus_type: a #GBusType
7345  * @cancellable: (nullable): a #GCancellable or %NULL
7346  * @error: return location for error or %NULL
7347  *
7348  * Synchronously connects to the message bus specified by @bus_type.
7349  * Note that the returned object may shared with other callers,
7350  * e.g. if two separate parts of a process calls this function with
7351  * the same @bus_type, they will share the same object.
7352  *
7353  * This is a synchronous failable function. See g_bus_get() and
7354  * g_bus_get_finish() for the asynchronous version.
7355  *
7356  * The returned object is a singleton, that is, shared with other
7357  * callers of g_bus_get() and g_bus_get_sync() for @bus_type. In the
7358  * event that you need a private message bus connection, use
7359  * g_dbus_address_get_for_bus_sync() and
7360  * g_dbus_connection_new_for_address().
7361  *
7362  * Note that the returned #GDBusConnection object will (usually) have
7363  * the #GDBusConnection:exit-on-close property set to %TRUE.
7364  *
7365  * Returns: (transfer full): a #GDBusConnection or %NULL if @error is set.
7366  *     Free with g_object_unref().
7367  *
7368  * Since: 2.26
7369  */
7370 GDBusConnection *
g_bus_get_sync(GBusType bus_type,GCancellable * cancellable,GError ** error)7371 g_bus_get_sync (GBusType       bus_type,
7372                 GCancellable  *cancellable,
7373                 GError       **error)
7374 {
7375   GDBusConnection *connection;
7376 
7377   _g_dbus_initialize ();
7378 
7379   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
7380 
7381   connection = get_uninitialized_connection (bus_type, cancellable, error);
7382   if (connection == NULL)
7383     goto out;
7384 
7385   if (!g_initable_init (G_INITABLE (connection), cancellable, error))
7386     {
7387       g_object_unref (connection);
7388       connection = NULL;
7389     }
7390 
7391  out:
7392   return connection;
7393 }
7394 
7395 static void
bus_get_async_initable_cb(GObject * source_object,GAsyncResult * res,gpointer user_data)7396 bus_get_async_initable_cb (GObject      *source_object,
7397                            GAsyncResult *res,
7398                            gpointer      user_data)
7399 {
7400   GTask *task = user_data;
7401   GError *error = NULL;
7402 
7403   if (!g_async_initable_init_finish (G_ASYNC_INITABLE (source_object),
7404                                      res,
7405                                      &error))
7406     {
7407       g_assert (error != NULL);
7408       g_task_return_error (task, error);
7409       g_object_unref (source_object);
7410     }
7411   else
7412     {
7413       g_task_return_pointer (task, source_object, g_object_unref);
7414     }
7415   g_object_unref (task);
7416 }
7417 
7418 /**
7419  * g_bus_get:
7420  * @bus_type: a #GBusType
7421  * @cancellable: (nullable): a #GCancellable or %NULL
7422  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
7423  * @user_data: the data to pass to @callback
7424  *
7425  * Asynchronously connects to the message bus specified by @bus_type.
7426  *
7427  * When the operation is finished, @callback will be invoked. You can
7428  * then call g_bus_get_finish() to get the result of the operation.
7429  *
7430  * This is an asynchronous failable function. See g_bus_get_sync() for
7431  * the synchronous version.
7432  *
7433  * Since: 2.26
7434  */
7435 void
g_bus_get(GBusType bus_type,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)7436 g_bus_get (GBusType             bus_type,
7437            GCancellable        *cancellable,
7438            GAsyncReadyCallback  callback,
7439            gpointer             user_data)
7440 {
7441   GDBusConnection *connection;
7442   GTask *task;
7443   GError *error = NULL;
7444 
7445   _g_dbus_initialize ();
7446 
7447   task = g_task_new (NULL, cancellable, callback, user_data);
7448   g_task_set_source_tag (task, g_bus_get);
7449 
7450   connection = get_uninitialized_connection (bus_type, cancellable, &error);
7451   if (connection == NULL)
7452     {
7453       g_assert (error != NULL);
7454       g_task_return_error (task, error);
7455       g_object_unref (task);
7456     }
7457   else
7458     {
7459       g_async_initable_init_async (G_ASYNC_INITABLE (connection),
7460                                    G_PRIORITY_DEFAULT,
7461                                    cancellable,
7462                                    bus_get_async_initable_cb,
7463                                    task);
7464     }
7465 }
7466 
7467 /**
7468  * g_bus_get_finish:
7469  * @res: a #GAsyncResult obtained from the #GAsyncReadyCallback passed
7470  *     to g_bus_get()
7471  * @error: return location for error or %NULL
7472  *
7473  * Finishes an operation started with g_bus_get().
7474  *
7475  * The returned object is a singleton, that is, shared with other
7476  * callers of g_bus_get() and g_bus_get_sync() for @bus_type. In the
7477  * event that you need a private message bus connection, use
7478  * g_dbus_address_get_for_bus_sync() and
7479  * g_dbus_connection_new_for_address().
7480  *
7481  * Note that the returned #GDBusConnection object will (usually) have
7482  * the #GDBusConnection:exit-on-close property set to %TRUE.
7483  *
7484  * Returns: (transfer full): a #GDBusConnection or %NULL if @error is set.
7485  *     Free with g_object_unref().
7486  *
7487  * Since: 2.26
7488  */
7489 GDBusConnection *
g_bus_get_finish(GAsyncResult * res,GError ** error)7490 g_bus_get_finish (GAsyncResult  *res,
7491                   GError       **error)
7492 {
7493   g_return_val_if_fail (g_task_is_valid (res, NULL), NULL);
7494   g_return_val_if_fail (error == NULL || *error == NULL, NULL);
7495 
7496   return g_task_propagate_pointer (G_TASK (res), error);
7497 }
7498 
7499 /* ---------------------------------------------------------------------------------------------------- */
7500