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