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 : 202092 : call_destroy_notify_data_in_idle (gpointer user_data)
243 : : {
244 : 202092 : CallDestroyNotifyData *data = user_data;
245 : 202092 : data->callback (data->user_data);
246 : 202092 : return FALSE;
247 : : }
248 : :
249 : : static void
250 : 202092 : call_destroy_notify_data_free (CallDestroyNotifyData *data)
251 : : {
252 : 202092 : g_free (data);
253 : 202092 : }
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 : 202478 : call_destroy_notify (GMainContext *context,
265 : : GDestroyNotify callback,
266 : : gpointer user_data)
267 : : {
268 : : GSource *idle_source;
269 : : CallDestroyNotifyData *data;
270 : :
271 : 202478 : if (callback == NULL)
272 : 321 : return;
273 : :
274 : 202157 : data = g_new0 (CallDestroyNotifyData, 1);
275 : 202157 : data->callback = callback;
276 : 202157 : data->user_data = user_data;
277 : :
278 : 202157 : idle_source = g_idle_source_new ();
279 : 202157 : g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
280 : 202157 : g_source_set_callback (idle_source,
281 : : call_destroy_notify_data_in_idle,
282 : : data,
283 : : (GDestroyNotify) call_destroy_notify_data_free);
284 : 202157 : g_source_set_static_name (idle_source, "[gio] call_destroy_notify_data_in_idle");
285 : 202157 : g_source_attach (idle_source, context);
286 : 202157 : 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 : 11185 : signal_subscriber_ref (SignalSubscriber *subscriber)
304 : : {
305 : 11185 : g_atomic_ref_count_inc (&subscriber->ref_count);
306 : 11185 : return subscriber;
307 : : }
308 : :
309 : : static void
310 : 11951 : signal_subscriber_unref (SignalSubscriber *subscriber)
311 : : {
312 : 11951 : 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 : 863 : call_destroy_notify (subscriber->context,
319 : : subscriber->user_data_free_func,
320 : : subscriber->user_data);
321 : :
322 : 863 : g_main_context_unref (subscriber->context);
323 : 863 : g_free (subscriber);
324 : : }
325 : 11951 : }
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 : 51 : watched_name_new (void)
342 : : {
343 : 51 : WatchedName *watched_name = g_new0 (WatchedName, 1);
344 : :
345 : 51 : g_ref_count_init (&watched_name->ref_count);
346 : 51 : watched_name->owner = NULL;
347 : 51 : 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 : 445 : 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 : 445 : SignalData *signal_data = g_new0 (SignalData, 1);
399 : :
400 : 445 : signal_data->rule = rule;
401 : 445 : signal_data->sender = sender;
402 : 445 : signal_data->interface_name = interface_name;
403 : 445 : signal_data->member = member;
404 : 445 : signal_data->object_path = object_path;
405 : 445 : signal_data->arg0 = arg0;
406 : 445 : signal_data->flags = flags;
407 : 445 : signal_data->subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref);
408 : 445 : return g_steal_pointer (&signal_data);
409 : : }
410 : :
411 : : static void
412 : 445 : signal_data_free (SignalData *signal_data)
413 : : {
414 : : /* The SignalData should not be freed while it still has subscribers */
415 : 445 : 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 : 445 : 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 : 445 : g_assert (signal_data->shared_name_watcher == NULL);
424 : :
425 : 445 : g_free (signal_data->rule);
426 : 445 : g_free (signal_data->sender);
427 : 445 : g_free (signal_data->interface_name);
428 : 445 : g_free (signal_data->member);
429 : 445 : g_free (signal_data->object_path);
430 : 445 : g_free (signal_data->arg0);
431 : 445 : g_ptr_array_unref (signal_data->subscribers);
432 : :
433 : 445 : g_free (signal_data);
434 : 445 : }
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 : 549443 : 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 : 418797 : 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 : 418797 : gint flags = g_atomic_int_get (&connection->atomic_flags);
690 : :
691 : 418797 : g_return_val_if_fail (flags & FLAG_INITIALIZED, FALSE);
692 : :
693 : : /* We can safely access this, due to the memory barrier above */
694 : 418797 : g_return_val_if_fail (connection->initialization_error == NULL, FALSE);
695 : :
696 : 418797 : 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 : 16602 : 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 : 16602 : gint flags = g_atomic_int_get (&connection->atomic_flags);
722 : :
723 : 16602 : if (!(check & MAY_BE_UNINITIALIZED))
724 : : {
725 : 14412 : g_return_val_if_fail (flags & FLAG_INITIALIZED, FALSE);
726 : 14412 : g_return_val_if_fail (connection->initialization_error == NULL, FALSE);
727 : : }
728 : :
729 : 16602 : if (flags & FLAG_CLOSED)
730 : : {
731 : 4 : g_set_error_literal (error,
732 : : G_IO_ERROR,
733 : : G_IO_ERROR_CLOSED,
734 : : _("The connection is closed"));
735 : 4 : return FALSE;
736 : : }
737 : :
738 : 16598 : return TRUE;
739 : : }
740 : :
741 : : static GHashTable *alive_connections = NULL;
742 : :
743 : : static void
744 : 2614 : g_dbus_connection_dispose (GObject *object)
745 : : {
746 : 2614 : GDBusConnection *connection = G_DBUS_CONNECTION (object);
747 : :
748 : 2614 : G_LOCK (message_bus_lock);
749 : 2614 : CONNECTION_LOCK (connection);
750 : 2614 : if (connection->worker != NULL)
751 : : {
752 : 2573 : _g_dbus_worker_stop (connection->worker);
753 : 2573 : connection->worker = NULL;
754 : 2573 : if (alive_connections != NULL)
755 : 2573 : 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 : 2614 : CONNECTION_UNLOCK (connection);
763 : 2614 : G_UNLOCK (message_bus_lock);
764 : :
765 : 2614 : if (G_OBJECT_CLASS (g_dbus_connection_parent_class)->dispose != NULL)
766 : 2614 : G_OBJECT_CLASS (g_dbus_connection_parent_class)->dispose (object);
767 : 2614 : }
768 : :
769 : : static void
770 : 2613 : g_dbus_connection_finalize (GObject *object)
771 : : {
772 : 2613 : GDBusConnection *connection = G_DBUS_CONNECTION (object);
773 : :
774 : 2613 : connection->finalizing = TRUE;
775 : :
776 : 2613 : purge_all_signal_subscriptions (connection);
777 : :
778 : 2613 : purge_all_filters (connection);
779 : 2613 : g_ptr_array_unref (connection->filters);
780 : :
781 : 2613 : if (connection->authentication_observer != NULL)
782 : 3 : g_object_unref (connection->authentication_observer);
783 : :
784 : 2613 : if (connection->auth != NULL)
785 : 2586 : g_object_unref (connection->auth);
786 : :
787 : 2613 : if (connection->credentials)
788 : 22 : g_object_unref (connection->credentials);
789 : :
790 : 2613 : if (connection->stream != NULL)
791 : : {
792 : 2586 : g_object_unref (connection->stream);
793 : 2586 : connection->stream = NULL;
794 : : }
795 : :
796 : 2613 : g_free (connection->address);
797 : :
798 : 2613 : g_free (connection->guid);
799 : 2613 : g_free (connection->bus_unique_name);
800 : :
801 : 2613 : if (connection->initialization_error != NULL)
802 : 40 : g_error_free (connection->initialization_error);
803 : :
804 : 2613 : g_hash_table_unref (connection->map_method_serial_to_task);
805 : 2613 : g_hash_table_unref (connection->map_method_serial_to_name_watcher);
806 : :
807 : 2613 : g_hash_table_unref (connection->map_rule_to_signal_data);
808 : 2613 : g_hash_table_unref (connection->map_id_to_signal_data);
809 : 2613 : g_hash_table_unref (connection->map_sender_unique_name_to_signal_data_array);
810 : :
811 : 2613 : g_hash_table_unref (connection->map_id_to_ei);
812 : 2613 : g_hash_table_unref (connection->map_object_path_to_eo);
813 : 2613 : g_hash_table_unref (connection->map_id_to_es);
814 : 2613 : g_hash_table_unref (connection->map_object_path_to_es);
815 : :
816 : 2613 : g_hash_table_unref (connection->map_thread_to_last_serial);
817 : :
818 : 2613 : g_main_context_unref (connection->main_context_at_construction);
819 : :
820 : 2613 : g_free (connection->machine_id);
821 : :
822 : 2613 : g_mutex_clear (&connection->init_lock);
823 : 2613 : g_mutex_clear (&connection->lock);
824 : :
825 : 2613 : G_OBJECT_CLASS (g_dbus_connection_parent_class)->finalize (object);
826 : 2613 : }
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 : 16489 : g_dbus_connection_set_property (GObject *object,
876 : : guint prop_id,
877 : : const GValue *value,
878 : : GParamSpec *pspec)
879 : : {
880 : 16489 : GDBusConnection *connection = G_DBUS_CONNECTION (object);
881 : :
882 : 16489 : switch (prop_id)
883 : : {
884 : 2879 : case PROP_STREAM:
885 : 2879 : connection->stream = g_value_dup_object (value);
886 : 2879 : break;
887 : :
888 : 2879 : case PROP_GUID:
889 : 2879 : connection->guid = g_value_dup_string (value);
890 : 2879 : break;
891 : :
892 : 2879 : case PROP_ADDRESS:
893 : 2879 : connection->address = g_value_dup_string (value);
894 : 2879 : break;
895 : :
896 : 2879 : case PROP_FLAGS:
897 : 2879 : connection->flags = g_value_get_flags (value);
898 : 2879 : break;
899 : :
900 : 2094 : case PROP_EXIT_ON_CLOSE:
901 : 2094 : g_dbus_connection_set_exit_on_close (connection, g_value_get_boolean (value));
902 : 2094 : break;
903 : :
904 : 2879 : case PROP_AUTHENTICATION_OBSERVER:
905 : 2879 : connection->authentication_observer = g_value_dup_object (value);
906 : 2879 : break;
907 : :
908 : 0 : default:
909 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
910 : 0 : break;
911 : : }
912 : 16489 : }
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 : 522 : g_dbus_connection_real_closed (GDBusConnection *connection,
921 : : gboolean remote_peer_vanished,
922 : : GError *error)
923 : : {
924 : 522 : 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 : 522 : if (remote_peer_vanished &&
930 : 417 : (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 : 522 : }
937 : :
938 : : static void
939 : 132 : g_dbus_connection_class_init (GDBusConnectionClass *klass)
940 : : {
941 : : GObjectClass *gobject_class;
942 : :
943 : 132 : gobject_class = G_OBJECT_CLASS (klass);
944 : :
945 : 132 : gobject_class->finalize = g_dbus_connection_finalize;
946 : 132 : gobject_class->dispose = g_dbus_connection_dispose;
947 : 132 : gobject_class->set_property = g_dbus_connection_set_property;
948 : 132 : gobject_class->get_property = g_dbus_connection_get_property;
949 : :
950 : 132 : 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 : 132 : 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 : 132 : 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 : 132 : 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 : 132 : 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 : 132 : 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 : 132 : 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 : 132 : 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 : 132 : 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 : 132 : 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 : 132 : 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 : 132 : g_signal_set_va_marshaller (signals[CLOSED_SIGNAL],
1181 : : G_TYPE_FROM_CLASS (klass),
1182 : : _g_cclosure_marshal_VOID__BOOLEAN_BOXEDv);
1183 : 132 : }
1184 : :
1185 : : static void
1186 : 2879 : g_dbus_connection_init (GDBusConnection *connection)
1187 : : {
1188 : 2879 : g_mutex_init (&connection->lock);
1189 : 2879 : g_mutex_init (&connection->init_lock);
1190 : :
1191 : 2879 : connection->map_method_serial_to_task = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
1192 : 2879 : connection->map_method_serial_to_name_watcher = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
1193 : :
1194 : 2879 : connection->map_rule_to_signal_data = g_hash_table_new (g_str_hash,
1195 : : g_str_equal);
1196 : 2879 : connection->map_id_to_signal_data = g_hash_table_new (g_direct_hash,
1197 : : g_direct_equal);
1198 : 2879 : 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 : 2879 : 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 : 2879 : connection->map_id_to_ei = g_hash_table_new (g_direct_hash,
1209 : : g_direct_equal);
1210 : :
1211 : 2879 : 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 : 2879 : connection->map_id_to_es = g_hash_table_new (g_direct_hash,
1217 : : g_direct_equal);
1218 : :
1219 : 2879 : connection->map_thread_to_last_serial = g_hash_table_new (g_direct_hash,
1220 : : g_direct_equal);
1221 : :
1222 : 2879 : connection->main_context_at_construction = g_main_context_ref_thread_default ();
1223 : :
1224 : 2879 : connection->filters = g_ptr_array_new ();
1225 : 2879 : }
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 : 686 : g_dbus_connection_is_closed (GDBusConnection *connection)
1289 : : {
1290 : : gint flags;
1291 : :
1292 : 686 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
1293 : :
1294 : 686 : flags = g_atomic_int_get (&connection->atomic_flags);
1295 : :
1296 : 686 : 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 : 24 : g_task_return_boolean (task, TRUE);
1358 : : else
1359 : 2 : 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 : 2 : goto out;
1464 : :
1465 : 111 : g_assert (connection->worker != NULL);
1466 : :
1467 : 111 : 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 : 522 : emit_closed_data_free (EmitClosedData *data)
1486 : : {
1487 : 522 : g_object_unref (data->connection);
1488 : 522 : if (data->error != NULL)
1489 : 417 : g_error_free (data->error);
1490 : 522 : g_free (data);
1491 : 522 : }
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 : 528 : emit_closed_in_idle (gpointer user_data)
1498 : : {
1499 : 528 : EmitClosedData *data = user_data;
1500 : : gboolean result;
1501 : :
1502 : 528 : g_object_notify (G_OBJECT (data->connection), "closed");
1503 : 528 : g_signal_emit (data->connection,
1504 : : signals[CLOSED_SIGNAL],
1505 : : 0,
1506 : : data->remote_peer_vanished,
1507 : : data->error,
1508 : : &result);
1509 : 522 : 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 : 545 : schedule_closed_unlocked (GDBusConnection *connection,
1517 : : gboolean remote_peer_vanished,
1518 : : GError *error)
1519 : : {
1520 : : GSource *idle_source;
1521 : : EmitClosedData *data;
1522 : :
1523 : 545 : CONNECTION_ENSURE_LOCK (connection);
1524 : :
1525 : 545 : data = g_new0 (EmitClosedData, 1);
1526 : 545 : data->connection = g_object_ref (connection);
1527 : 545 : data->remote_peer_vanished = remote_peer_vanished;
1528 : 545 : data->error = error != NULL ? g_error_copy (error) : NULL;
1529 : :
1530 : 545 : idle_source = g_idle_source_new ();
1531 : 545 : g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
1532 : 545 : g_source_set_callback (idle_source,
1533 : : emit_closed_in_idle,
1534 : : data,
1535 : : (GDestroyNotify) emit_closed_data_free);
1536 : 545 : g_source_set_static_name (idle_source, "[gio] emit_closed_in_idle");
1537 : 545 : g_source_attach (idle_source, connection->main_context_at_construction);
1538 : 545 : g_source_unref (idle_source);
1539 : 545 : }
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 : 16384 : 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 : 16384 : CONNECTION_ENSURE_LOCK (connection);
1739 : :
1740 : 16384 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
1741 : 16384 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
1742 : :
1743 : : /* TODO: check all necessary headers are present */
1744 : :
1745 : 16384 : if (out_serial != NULL)
1746 : 12530 : *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 : 16384 : if (!check_unclosed (connection,
1754 : 16384 : (flags & SEND_MESSAGE_FLAGS_INITIALIZING) ? MAY_BE_UNINITIALIZED : 0,
1755 : : error))
1756 : 1 : return FALSE;
1757 : :
1758 : 16383 : blob = g_dbus_message_to_blob (message,
1759 : : &blob_size,
1760 : : connection->capabilities,
1761 : : error);
1762 : 16383 : if (blob == NULL)
1763 : 0 : return FALSE;
1764 : :
1765 : 16383 : 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 : 16382 : if (connection->last_serial == G_MAXUINT32)
1774 : 0 : connection->last_serial = 1;
1775 : : else
1776 : 16382 : connection->last_serial++;
1777 : :
1778 : 16382 : serial_to_use = connection->last_serial;
1779 : : }
1780 : :
1781 : 16383 : g_assert (serial_to_use != 0);
1782 : :
1783 : 16383 : switch (blob[0])
1784 : : {
1785 : 16383 : case 'l':
1786 : 16383 : ((guint32 *) blob)[2] = GUINT32_TO_LE (serial_to_use);
1787 : 16383 : 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 : 16383 : if (out_serial != NULL)
1807 : 12529 : *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 : 16383 : g_hash_table_replace (connection->map_thread_to_last_serial,
1815 : 16383 : g_thread_self (),
1816 : 16383 : GUINT_TO_POINTER (serial_to_use));
1817 : :
1818 : 16383 : if (!(flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL))
1819 : 16382 : g_dbus_message_set_serial (message, serial_to_use);
1820 : :
1821 : 16383 : g_dbus_message_lock (message);
1822 : :
1823 : 16383 : _g_dbus_worker_send_message (connection->worker,
1824 : : message,
1825 : : (gchar*) blob, /* transfer ownership */
1826 : : blob_size);
1827 : :
1828 : 16383 : 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 : 7455 : 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 : 7455 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
1878 : 7455 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), FALSE);
1879 : 7455 : g_return_val_if_fail ((flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL) || !g_dbus_message_get_locked (message), FALSE);
1880 : 7455 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1881 : :
1882 : 7455 : CONNECTION_LOCK (connection);
1883 : 7455 : ret = g_dbus_connection_send_message_unlocked (connection, message, flags, (guint32 *) out_serial, error);
1884 : 7455 : CONNECTION_UNLOCK (connection);
1885 : 7455 : 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 : 7096 : send_message_data_free (SendMessageData *data)
1905 : : {
1906 : : /* These should already have been cleared by send_message_with_reply_cleanup(). */
1907 : 7096 : g_assert (data->timeout_source == NULL);
1908 : 7096 : g_assert (data->cancellable_handler_id == 0);
1909 : :
1910 : 7096 : g_slice_free (SendMessageData, data);
1911 : 7096 : }
1912 : :
1913 : : /* ---------------------------------------------------------------------------------------------------- */
1914 : :
1915 : : /* can be called from any thread with lock held; @task is (transfer none) */
1916 : : static void
1917 : 7094 : send_message_with_reply_cleanup (GTask *task, gboolean remove)
1918 : : {
1919 : 7094 : GDBusConnection *connection = g_task_get_source_object (task);
1920 : 7094 : SendMessageData *data = g_task_get_task_data (task);
1921 : :
1922 : 7094 : CONNECTION_ENSURE_LOCK (connection);
1923 : :
1924 : 7094 : g_assert (!data->delivered);
1925 : :
1926 : 7094 : data->delivered = TRUE;
1927 : :
1928 : 7094 : if (data->timeout_source != NULL)
1929 : : {
1930 : 6970 : g_source_destroy (data->timeout_source);
1931 : 6970 : g_clear_pointer (&data->timeout_source, g_source_unref);
1932 : : }
1933 : 7094 : 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 : 7094 : 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 : 7094 : if (remove)
1945 : : {
1946 : 7082 : gboolean removed = g_hash_table_remove (connection->map_method_serial_to_task,
1947 : 7082 : GUINT_TO_POINTER (data->serial));
1948 : 7082 : g_warn_if_fail (removed);
1949 : : }
1950 : 7094 : }
1951 : :
1952 : : /* ---------------------------------------------------------------------------------------------------- */
1953 : :
1954 : : /* Called from GDBus worker thread with lock held; @task is (transfer none). */
1955 : : static void
1956 : 7068 : send_message_data_deliver_reply_unlocked (GTask *task,
1957 : : GDBusMessage *reply)
1958 : : {
1959 : 7068 : SendMessageData *data = g_task_get_task_data (task);
1960 : :
1961 : 7068 : if (data->delivered)
1962 : 0 : goto out;
1963 : :
1964 : 7068 : g_task_return_pointer (task, g_object_ref (reply), g_object_unref);
1965 : :
1966 : 7068 : send_message_with_reply_cleanup (task, TRUE);
1967 : :
1968 : 7068 : out:
1969 : : ;
1970 : 7068 : }
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 : 7097 : 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 : 7097 : GError *error = NULL;
2061 : : guint32 serial;
2062 : :
2063 : 7097 : if (out_serial == NULL)
2064 : 4790 : out_serial = &serial;
2065 : 7097 : *out_serial = 0;
2066 : :
2067 : 7097 : if (timeout_msec == -1)
2068 : 6959 : timeout_msec = 25 * 1000;
2069 : :
2070 : 7097 : data = g_slice_new0 (SendMessageData);
2071 : 7097 : task = g_task_new (connection, cancellable, callback, user_data);
2072 : 7097 : g_task_set_source_tag (task,
2073 : : g_dbus_connection_send_message_with_reply_unlocked);
2074 : 7097 : g_task_set_task_data (task, data, (GDestroyNotify) send_message_data_free);
2075 : :
2076 : 7097 : if (g_task_return_error_if_cancelled (task))
2077 : : {
2078 : 2 : g_object_unref (task);
2079 : 3 : return;
2080 : : }
2081 : :
2082 : 7095 : 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 : 7094 : data->serial = *out_serial;
2089 : :
2090 : 7094 : 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 : 7094 : if (timeout_msec != G_MAXINT)
2099 : : {
2100 : 6970 : data->timeout_source = g_timeout_source_new (timeout_msec);
2101 : 6970 : g_source_set_static_name (data->timeout_source, "[gio] send_message_with_reply_unlocked");
2102 : 6970 : g_task_attach_source (task, data->timeout_source,
2103 : : (GSourceFunc) send_message_with_reply_timeout_cb);
2104 : : }
2105 : :
2106 : 7094 : g_hash_table_insert (connection->map_method_serial_to_task,
2107 : 7094 : 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 : 7097 : 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 : 7097 : g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
2169 : 7097 : g_return_if_fail (G_IS_DBUS_MESSAGE (message));
2170 : 7097 : g_return_if_fail ((flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL) || !g_dbus_message_get_locked (message));
2171 : 7097 : g_return_if_fail (timeout_msec >= 0 || timeout_msec == -1);
2172 : :
2173 : 7097 : CONNECTION_LOCK (connection);
2174 : 7097 : 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 : 7097 : 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 : 7096 : g_dbus_connection_send_message_with_reply_finish (GDBusConnection *connection,
2210 : : GAsyncResult *res,
2211 : : GError **error)
2212 : : {
2213 : 7096 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
2214 : 7096 : g_return_val_if_fail (g_task_is_valid (res, connection), NULL);
2215 : 7096 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2216 : :
2217 : 7096 : 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 : 4769 : send_message_with_reply_sync_cb (GDBusConnection *connection,
2232 : : GAsyncResult *res,
2233 : : gpointer user_data)
2234 : : {
2235 : 4769 : SendMessageSyncData *data = user_data;
2236 : 4769 : data->res = g_object_ref (res);
2237 : 4769 : g_main_loop_quit (data->loop);
2238 : 4769 : }
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 : 4769 : 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 : 4769 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
2302 : 4769 : g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL);
2303 : 4769 : g_return_val_if_fail ((flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL) || !g_dbus_message_get_locked (message), NULL);
2304 : 4769 : g_return_val_if_fail (timeout_msec >= 0 || timeout_msec == -1, NULL);
2305 : 4769 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2306 : :
2307 : 4769 : data.res = NULL;
2308 : 4769 : data.context = g_main_context_new ();
2309 : 4769 : data.loop = g_main_loop_new (data.context, FALSE);
2310 : :
2311 : 4769 : g_main_context_push_thread_default (data.context);
2312 : :
2313 : 4769 : 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 : 4769 : g_main_loop_run (data.loop);
2322 : 4769 : reply = g_dbus_connection_send_message_with_reply_finish (connection,
2323 : : data.res,
2324 : : error);
2325 : :
2326 : 4769 : g_main_context_pop_thread_default (data.context);
2327 : :
2328 : 4769 : g_main_context_unref (data.context);
2329 : 4769 : g_main_loop_unref (data.loop);
2330 : 4769 : if (data.res)
2331 : 4769 : g_object_unref (data.res);
2332 : :
2333 : 4769 : 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 : 84 : name_watcher_unref_watched_name (GDBusConnection *connection,
2345 : : SignalData *name_watcher)
2346 : : {
2347 : 84 : WatchedName *watched_name = name_watcher->watched_name;
2348 : :
2349 : 84 : g_assert (watched_name != NULL);
2350 : :
2351 : 84 : 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 : 51 : 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 : 51 : name_watcher->watched_name = NULL;
2366 : 51 : g_free (watched_name->owner);
2367 : 51 : g_free (watched_name);
2368 : : }
2369 : :
2370 : : /* called in GDBusWorker thread with lock held */
2371 : : static void
2372 : 5246 : name_watcher_set_name_owner_unlocked (SignalData *name_watcher,
2373 : : const char *new_owner)
2374 : : {
2375 : 5246 : if (new_owner != NULL && new_owner[0] == '\0')
2376 : 2605 : new_owner = NULL;
2377 : :
2378 : 5246 : g_assert (name_watcher->watched_name != NULL);
2379 : 5246 : g_set_str (&name_watcher->watched_name->owner, new_owner);
2380 : 5246 : }
2381 : :
2382 : : /* called in GDBusWorker thread with lock held */
2383 : : static void
2384 : 5213 : name_watcher_deliver_name_owner_changed_unlocked (SignalData *name_watcher,
2385 : : GDBusMessage *message)
2386 : : {
2387 : : GVariant *body;
2388 : :
2389 : 5213 : body = g_dbus_message_get_body (message);
2390 : :
2391 : 5213 : if (G_LIKELY (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(sss)"))))
2392 : 5213 : {
2393 : : const char *name;
2394 : : const char *new_owner;
2395 : :
2396 : 5213 : g_variant_get (body, "(&s&s&s)", &name, NULL, &new_owner);
2397 : :
2398 : : /* Our caller already checked this */
2399 : 5213 : 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 : 5213 : if (G_LIKELY (new_owner[0] == '\0' || g_dbus_is_name (new_owner)))
2405 : 5213 : 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 : 5213 : }
2418 : :
2419 : : /* called in GDBusWorker thread with lock held */
2420 : : static void
2421 : 49 : 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 : 49 : watched_name = name_watcher->watched_name;
2430 : 49 : g_assert (watched_name != NULL);
2431 : 49 : g_assert (watched_name->get_name_owner_serial != 0);
2432 : :
2433 : 49 : type = g_dbus_message_get_message_type (message);
2434 : 49 : body = g_dbus_message_get_body (message);
2435 : :
2436 : 49 : if (type == G_DBUS_MESSAGE_TYPE_ERROR)
2437 : : {
2438 : 16 : 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 : 33 : 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 : 33 : else if (G_LIKELY (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)"))))
2451 : 33 : {
2452 : : const char *new_owner;
2453 : :
2454 : 33 : 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 : 33 : if (G_LIKELY (g_dbus_is_name (new_owner)))
2460 : 33 : 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 : 49 : g_hash_table_remove (connection->map_method_serial_to_name_watcher,
2472 : 49 : GUINT_TO_POINTER (watched_name->get_name_owner_serial));
2473 : 49 : watched_name->get_name_owner_serial = 0;
2474 : 49 : }
2475 : :
2476 : : /* Called in a user thread, lock is held */
2477 : : static void
2478 : 51 : name_watcher_call_get_name_owner_unlocked (GDBusConnection *connection,
2479 : : SignalData *name_watcher)
2480 : : {
2481 : : GDBusMessage *message;
2482 : 51 : GError *local_error = NULL;
2483 : : WatchedName *watched_name;
2484 : :
2485 : 51 : g_assert (g_strcmp0 (name_watcher->sender, DBUS_SERVICE_DBUS) == 0);
2486 : 51 : g_assert (g_strcmp0 (name_watcher->interface_name, DBUS_INTERFACE_DBUS) == 0);
2487 : 51 : g_assert (g_strcmp0 (name_watcher->member, "NameOwnerChanged") == 0);
2488 : 51 : 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 : 51 : g_assert (g_dbus_is_name (name_watcher->arg0));
2492 : 51 : g_assert (name_watcher->flags == G_DBUS_SIGNAL_FLAGS_NONE);
2493 : :
2494 : 51 : watched_name = name_watcher->watched_name;
2495 : 51 : g_assert (watched_name != NULL);
2496 : 51 : g_assert (watched_name->owner == NULL);
2497 : 51 : g_assert (watched_name->get_name_owner_serial == 0);
2498 : 51 : g_assert (name_watcher->shared_name_watcher == NULL);
2499 : :
2500 : 51 : message = g_dbus_message_new_method_call (DBUS_SERVICE_DBUS,
2501 : : DBUS_PATH_DBUS,
2502 : : DBUS_INTERFACE_DBUS,
2503 : : "GetNameOwner");
2504 : 51 : g_dbus_message_set_body (message, g_variant_new ("(s)", name_watcher->arg0));
2505 : :
2506 : 51 : 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 : 51 : g_assert (watched_name->get_name_owner_serial != 0);
2512 : 51 : g_hash_table_insert (connection->map_method_serial_to_name_watcher,
2513 : 51 : 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 : 51 : g_object_unref (message);
2525 : 51 : }
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 : 44791 : copy_filter_list (GPtrArray *filters)
2560 : : {
2561 : : FilterData **copy;
2562 : : guint n;
2563 : :
2564 : 44791 : copy = g_new (FilterData *, filters->len + 1);
2565 : 45184 : for (n = 0; n < filters->len; n++)
2566 : : {
2567 : 393 : copy[n] = filters->pdata[n];
2568 : 393 : copy[n]->ref_count++;
2569 : : }
2570 : 44791 : copy[n] = NULL;
2571 : :
2572 : 44791 : return copy;
2573 : : }
2574 : :
2575 : : /* requires CONNECTION_LOCK */
2576 : : static void
2577 : 44791 : free_filter_list (FilterData **filters)
2578 : : {
2579 : : guint n;
2580 : :
2581 : 45184 : 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 : 44791 : g_free (filters);
2588 : 44791 : }
2589 : :
2590 : : /* Called in GDBusWorker's thread - we must not block - with no lock held */
2591 : : static void
2592 : 28694 : 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 : 28694 : G_LOCK (message_bus_lock);
2602 : 28694 : alive = g_hash_table_contains (alive_connections, user_data);
2603 : 28694 : if (!alive)
2604 : : {
2605 : 0 : G_UNLOCK (message_bus_lock);
2606 : 0 : return;
2607 : : }
2608 : 28694 : connection = G_DBUS_CONNECTION (user_data);
2609 : 28694 : g_object_ref (connection);
2610 : 28694 : G_UNLOCK (message_bus_lock);
2611 : :
2612 : : //g_debug ("in on_worker_message_received");
2613 : :
2614 : 28694 : g_object_ref (message);
2615 : 28694 : 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 : 28694 : CONNECTION_LOCK (connection);
2621 : 28694 : filters = copy_filter_list (connection->filters);
2622 : 28694 : CONNECTION_UNLOCK (connection);
2623 : :
2624 : : /* then call the filters in order (without holding the lock) */
2625 : 28702 : 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 : 28694 : CONNECTION_LOCK (connection);
2637 : 28694 : free_filter_list (filters);
2638 : 28694 : 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 : 28694 : if (message != NULL)
2644 : : {
2645 : : GDBusMessageType message_type;
2646 : :
2647 : 28505 : message_type = g_dbus_message_get_message_type (message);
2648 : 28505 : if (message_type == G_DBUS_MESSAGE_TYPE_METHOD_RETURN || message_type == G_DBUS_MESSAGE_TYPE_ERROR)
2649 : 12760 : {
2650 : : guint32 reply_serial;
2651 : : GTask *task;
2652 : : SignalData *name_watcher;
2653 : :
2654 : 12760 : reply_serial = g_dbus_message_get_reply_serial (message);
2655 : 12760 : CONNECTION_LOCK (connection);
2656 : 12760 : task = g_hash_table_lookup (connection->map_method_serial_to_task,
2657 : 12760 : GUINT_TO_POINTER (reply_serial));
2658 : 12760 : 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 : 7068 : 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 : 12760 : name_watcher = g_hash_table_lookup (connection->map_method_serial_to_name_watcher,
2670 : 12760 : GUINT_TO_POINTER (reply_serial));
2671 : :
2672 : 12760 : if (name_watcher != NULL)
2673 : : {
2674 : 49 : g_assert (name_watcher->watched_name != NULL);
2675 : 49 : g_assert (name_watcher->watched_name->get_name_owner_serial == reply_serial);
2676 : 49 : name_watcher_deliver_get_name_owner_reply_unlocked (name_watcher,
2677 : : connection,
2678 : : message);
2679 : : }
2680 : :
2681 : 12760 : CONNECTION_UNLOCK (connection);
2682 : : }
2683 : 15745 : else if (message_type == G_DBUS_MESSAGE_TYPE_SIGNAL)
2684 : : {
2685 : 13452 : CONNECTION_LOCK (connection);
2686 : 13452 : distribute_signals (connection, message);
2687 : 13452 : CONNECTION_UNLOCK (connection);
2688 : : }
2689 : 2293 : else if (message_type == G_DBUS_MESSAGE_TYPE_METHOD_CALL)
2690 : : {
2691 : 2293 : CONNECTION_LOCK (connection);
2692 : 2293 : distribute_method_call (connection, message);
2693 : 2293 : CONNECTION_UNLOCK (connection);
2694 : : }
2695 : : }
2696 : :
2697 : 28694 : if (message != NULL)
2698 : 28505 : g_object_unref (message);
2699 : 28694 : g_object_unref (connection);
2700 : : }
2701 : :
2702 : : /* Called in GDBusWorker's thread, lock is not held */
2703 : : static GDBusMessage *
2704 : 16097 : 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 : 16097 : G_LOCK (message_bus_lock);
2714 : 16097 : alive = g_hash_table_contains (alive_connections, user_data);
2715 : 16097 : if (!alive)
2716 : : {
2717 : 0 : G_UNLOCK (message_bus_lock);
2718 : 0 : return message;
2719 : : }
2720 : 16097 : connection = G_DBUS_CONNECTION (user_data);
2721 : 16097 : g_object_ref (connection);
2722 : 16097 : 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 : 16097 : CONNECTION_LOCK (connection);
2728 : 16097 : filters = copy_filter_list (connection->filters);
2729 : 16097 : CONNECTION_UNLOCK (connection);
2730 : :
2731 : : /* then call the filters in order (without holding the lock) */
2732 : 16293 : 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 : 16097 : CONNECTION_LOCK (connection);
2744 : 16097 : free_filter_list (filters);
2745 : 16097 : CONNECTION_UNLOCK (connection);
2746 : :
2747 : 16097 : g_object_unref (connection);
2748 : :
2749 : 16097 : 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 : 598 : 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 : 598 : G_LOCK (message_bus_lock);
2788 : 598 : alive = g_hash_table_contains (alive_connections, user_data);
2789 : 598 : if (!alive)
2790 : : {
2791 : 0 : G_UNLOCK (message_bus_lock);
2792 : 0 : return;
2793 : : }
2794 : 598 : connection = G_DBUS_CONNECTION (user_data);
2795 : 598 : g_object_ref (connection);
2796 : 598 : G_UNLOCK (message_bus_lock);
2797 : :
2798 : : //g_debug ("in on_worker_closed: %s", error->message);
2799 : :
2800 : 598 : 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 : 598 : old_atomic_flags = g_atomic_int_or (&connection->atomic_flags, FLAG_CLOSED);
2806 : :
2807 : 598 : if (!(old_atomic_flags & FLAG_CLOSED))
2808 : : {
2809 : 545 : g_hash_table_foreach_remove (connection->map_method_serial_to_task, cancel_method_on_close, NULL);
2810 : 545 : schedule_closed_unlocked (connection, remote_peer_vanished, error);
2811 : : }
2812 : 598 : CONNECTION_UNLOCK (connection);
2813 : :
2814 : 598 : 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 : 2850 : get_offered_capabilities_max (GDBusConnection *connection)
2826 : : {
2827 : : GDBusCapabilityFlags ret;
2828 : 2850 : ret = G_DBUS_CAPABILITY_FLAGS_NONE;
2829 : : #ifdef G_OS_UNIX
2830 : 2850 : if (G_IS_UNIX_CONNECTION (connection->stream))
2831 : 2374 : ret |= G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING;
2832 : : #endif
2833 : 2850 : return ret;
2834 : : }
2835 : :
2836 : : /* Called in a user thread, lock is not held */
2837 : : static gboolean
2838 : 3467 : initable_init (GInitable *initable,
2839 : : GCancellable *cancellable,
2840 : : GError **error)
2841 : : {
2842 : 3467 : 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 : 3467 : g_mutex_lock (&connection->init_lock);
2854 : :
2855 : 3467 : ret = FALSE;
2856 : :
2857 : : /* Make this a no-op if we're already initialized (successfully or
2858 : : * unsuccessfully)
2859 : : */
2860 : 3467 : if ((g_atomic_int_get (&connection->atomic_flags) & FLAG_INITIALIZED))
2861 : : {
2862 : 587 : ret = (connection->initialization_error == NULL);
2863 : 587 : goto out;
2864 : : }
2865 : :
2866 : : /* Because of init_lock, we can't get here twice in different threads */
2867 : 2880 : 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 : 2880 : if (connection->address != NULL)
2879 : : {
2880 : 2253 : g_assert (connection->stream == NULL);
2881 : :
2882 : 2253 : if ((connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER) ||
2883 : 2253 : (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS) ||
2884 : 2253 : (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 : 2253 : connection->stream = g_dbus_address_get_stream_sync (connection->address,
2894 : : NULL, /* TODO: out_guid */
2895 : : cancellable,
2896 : : &connection->initialization_error);
2897 : 2253 : 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 : 2850 : 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 : 2428 : else if (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT)
2928 : : {
2929 : 2428 : g_assert (!(connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER));
2930 : 2428 : g_assert (connection->guid == NULL);
2931 : 2428 : connection->auth = _g_dbus_auth_new (connection->stream);
2932 : 2428 : 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 : 2428 : if (connection->guid == NULL)
2940 : 4 : goto out;
2941 : : }
2942 : :
2943 : 2837 : 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 : 2837 : if (G_IS_SOCKET_CONNECTION (connection->stream))
2958 : : {
2959 : 2432 : g_socket_set_blocking (g_socket_connection_get_socket (G_SOCKET_CONNECTION (connection->stream)), FALSE);
2960 : : }
2961 : : #endif
2962 : :
2963 : 2837 : G_LOCK (message_bus_lock);
2964 : 2837 : if (alive_connections == NULL)
2965 : 97 : alive_connections = g_hash_table_new (g_direct_hash, g_direct_equal);
2966 : 2837 : g_hash_table_add (alive_connections, connection);
2967 : 2837 : G_UNLOCK (message_bus_lock);
2968 : :
2969 : 5674 : connection->worker = _g_dbus_worker_new (connection->stream,
2970 : : connection->capabilities,
2971 : 2837 : ((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 : 2837 : 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 : 2190 : 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 : 2190 : 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 : 2190 : if (hello_result == NULL)
3004 : 0 : goto out;
3005 : :
3006 : 2190 : g_variant_get (hello_result, "(s)", &connection->bus_unique_name);
3007 : 2190 : g_variant_unref (hello_result);
3008 : : //g_debug ("unique name is '%s'", connection->bus_unique_name);
3009 : : }
3010 : :
3011 : 2837 : ret = TRUE;
3012 : 3467 : out:
3013 : 3467 : 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 : 3467 : 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 : 3466 : g_atomic_int_or (&connection->atomic_flags, FLAG_INITIALIZED);
3039 : 3467 : g_mutex_unlock (&connection->init_lock);
3040 : :
3041 : 3467 : return ret;
3042 : : }
3043 : :
3044 : : static void
3045 : 132 : initable_iface_init (GInitableIface *initable_iface)
3046 : : {
3047 : 132 : initable_iface->init = initable_init;
3048 : 132 : }
3049 : :
3050 : : /* ---------------------------------------------------------------------------------------------------- */
3051 : :
3052 : : static void
3053 : 132 : async_initable_iface_init (GAsyncInitableIface *async_initable_iface)
3054 : : {
3055 : : /* Use default */
3056 : 132 : }
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 : 2143 : g_dbus_connection_set_exit_on_close (GDBusConnection *connection,
3376 : : gboolean exit_on_close)
3377 : : {
3378 : 2143 : g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
3379 : :
3380 : 2143 : if (exit_on_close)
3381 : 2095 : g_atomic_int_or (&connection->atomic_flags, FLAG_EXIT_ON_CLOSE);
3382 : : else
3383 : 48 : 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 : 1653 : g_dbus_connection_get_unique_name (GDBusConnection *connection)
3446 : : {
3447 : 1653 : 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 : 1653 : if (!check_initialized (connection))
3451 : 0 : return NULL;
3452 : :
3453 : 1653 : 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 : 2613 : purge_all_filters (GDBusConnection *connection)
3561 : : {
3562 : : guint n;
3563 : :
3564 : 2614 : for (n = 0; n < connection->filters->len; n++)
3565 : 1 : filter_data_destroy (connection->filters->pdata[n], FALSE);
3566 : 2613 : }
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 : 967 : 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 : 967 : rule = g_string_new ("type='signal'");
3635 : 967 : if (flags & G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE)
3636 : 13 : g_string_prepend_c (rule, '-');
3637 : 967 : if (sender != NULL)
3638 : 876 : g_string_append_printf (rule, ",sender='%s'", sender);
3639 : 967 : if (interface_name != NULL)
3640 : 957 : g_string_append_printf (rule, ",interface='%s'", interface_name);
3641 : 967 : if (member != NULL)
3642 : 665 : g_string_append_printf (rule, ",member='%s'", member);
3643 : 967 : if (object_path != NULL)
3644 : 954 : g_string_append_printf (rule, ",path='%s'", object_path);
3645 : :
3646 : 967 : if (arg0 != NULL)
3647 : : {
3648 : 602 : if (flags & G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH)
3649 : 12 : g_string_append_printf (rule, ",arg0path='%s'", arg0);
3650 : 590 : else if (flags & G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE)
3651 : 5 : g_string_append_printf (rule, ",arg0namespace='%s'", arg0);
3652 : : else
3653 : 585 : g_string_append_printf (rule, ",arg0='%s'", arg0);
3654 : : }
3655 : :
3656 : 967 : 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 : 332 : add_match_rule (GDBusConnection *connection,
3668 : : const gchar *match_rule)
3669 : : {
3670 : : GError *error;
3671 : : GDBusMessage *message;
3672 : :
3673 : 332 : if (match_rule[0] == '-')
3674 : 11 : return;
3675 : :
3676 : 321 : message = g_dbus_message_new_method_call (DBUS_SERVICE_DBUS,
3677 : : DBUS_PATH_DBUS,
3678 : : DBUS_INTERFACE_DBUS,
3679 : : "AddMatch");
3680 : 321 : g_dbus_message_set_body (message, g_variant_new ("(s)", match_rule));
3681 : 321 : error = NULL;
3682 : 321 : 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 : 321 : g_object_unref (message);
3692 : : }
3693 : :
3694 : : /* ---------------------------------------------------------------------------------------------------- */
3695 : :
3696 : : /* Called in a user thread, lock is held */
3697 : : static void
3698 : 319 : remove_match_rule (GDBusConnection *connection,
3699 : : const gchar *match_rule)
3700 : : {
3701 : : GError *error;
3702 : : GDBusMessage *message;
3703 : :
3704 : 319 : if (match_rule[0] == '-')
3705 : 11 : return;
3706 : :
3707 : 308 : message = g_dbus_message_new_method_call (DBUS_SERVICE_DBUS,
3708 : : DBUS_PATH_DBUS,
3709 : : DBUS_INTERFACE_DBUS,
3710 : : "RemoveMatch");
3711 : 308 : g_dbus_message_set_body (message, g_variant_new ("(s)", match_rule));
3712 : :
3713 : 308 : error = NULL;
3714 : 308 : 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 : 308 : g_object_unref (message);
3728 : : }
3729 : :
3730 : : /* ---------------------------------------------------------------------------------------------------- */
3731 : :
3732 : : static gboolean
3733 : 858 : is_signal_data_for_name_lost_or_acquired (SignalData *signal_data)
3734 : : {
3735 : 1334 : return g_strcmp0 (signal_data->sender, DBUS_SERVICE_DBUS) == 0 &&
3736 : 952 : g_strcmp0 (signal_data->interface_name, DBUS_INTERFACE_DBUS) == 0 &&
3737 : 2186 : g_strcmp0 (signal_data->object_path, DBUS_PATH_DBUS) == 0 &&
3738 : 852 : (g_strcmp0 (signal_data->member, "NameLost") == 0 ||
3739 : 376 : g_strcmp0 (signal_data->member, "NameAcquired") == 0);
3740 : : }
3741 : :
3742 : : /* ---------------------------------------------------------------------------------------------------- */
3743 : :
3744 : : /* called in any thread, connection lock is held */
3745 : : static void
3746 : 445 : add_signal_data (GDBusConnection *connection,
3747 : : SignalData *signal_data,
3748 : : const char *sender_unique_name)
3749 : : {
3750 : : GPtrArray *signal_data_array;
3751 : :
3752 : 445 : g_hash_table_insert (connection->map_rule_to_signal_data,
3753 : 445 : 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 : 445 : if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
3762 : : {
3763 : 429 : if (!is_signal_data_for_name_lost_or_acquired (signal_data))
3764 : 332 : add_match_rule (connection, signal_data->rule);
3765 : : }
3766 : :
3767 : 445 : signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
3768 : : sender_unique_name);
3769 : 445 : if (signal_data_array == NULL)
3770 : : {
3771 : 273 : signal_data_array = g_ptr_array_new ();
3772 : 273 : g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array,
3773 : 273 : g_strdup (sender_unique_name),
3774 : : signal_data_array);
3775 : : }
3776 : 445 : g_ptr_array_add (signal_data_array, signal_data);
3777 : 445 : }
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 : 485 : g_ptr_array_add (signal_data->subscribers, subscriber);
3929 : 485 : g_free (rule);
3930 : 485 : goto out;
3931 : : }
3932 : :
3933 : 398 : signal_data = signal_data_new_take (g_steal_pointer (&rule),
3934 : 398 : g_strdup (sender),
3935 : 398 : g_strdup (interface_name),
3936 : 398 : g_strdup (member),
3937 : 398 : g_strdup (object_path),
3938 : 398 : g_strdup (arg0),
3939 : : flags);
3940 : 398 : 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 : 398 : if (sender != NULL && !sender_is_its_own_owner)
3947 : : {
3948 : 84 : gchar *name_owner_rule = NULL;
3949 : :
3950 : : /* We already checked that sender != NULL implies MESSAGE_BUS_CONNECTION */
3951 : 84 : g_assert (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION);
3952 : :
3953 : 84 : 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 : 84 : name_watcher = g_hash_table_lookup (connection->map_rule_to_signal_data, name_owner_rule);
3960 : :
3961 : 84 : if (name_watcher == NULL)
3962 : : {
3963 : 47 : name_watcher = signal_data_new_take (g_steal_pointer (&name_owner_rule),
3964 : 47 : g_strdup (DBUS_SERVICE_DBUS),
3965 : 47 : g_strdup (DBUS_INTERFACE_DBUS),
3966 : 47 : g_strdup ("NameOwnerChanged"),
3967 : 47 : g_strdup (DBUS_PATH_DBUS),
3968 : 47 : g_strdup (sender),
3969 : : G_DBUS_SIGNAL_FLAGS_NONE);
3970 : 47 : add_signal_data (connection, name_watcher, DBUS_SERVICE_DBUS);
3971 : : }
3972 : :
3973 : 84 : if (name_watcher->watched_name == NULL)
3974 : : {
3975 : 51 : name_watcher->watched_name = watched_name_new ();
3976 : 51 : 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 : 84 : signal_data->shared_name_watcher = name_watcher;
3984 : :
3985 : 84 : g_clear_pointer (&name_owner_rule, g_free);
3986 : : }
3987 : :
3988 : 398 : 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 : 967 : 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 : 967 : if (signal_data->subscribers->len != 0)
4017 : 453 : 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 : 514 : if (signal_data->watched_name != NULL)
4022 : 69 : return;
4023 : :
4024 : : /* Point of no return: we have committed to removing it */
4025 : :
4026 : 445 : if (signal_data->sender != NULL && signal_data->shared_name_watcher == NULL)
4027 : 270 : sender_unique_name = signal_data->sender;
4028 : : else
4029 : 175 : sender_unique_name = "";
4030 : :
4031 : 445 : g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule));
4032 : :
4033 : 445 : signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
4034 : : sender_unique_name);
4035 : 445 : g_warn_if_fail (signal_data_array != NULL);
4036 : 445 : g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data));
4037 : :
4038 : 445 : if (signal_data_array->len == 0)
4039 : : {
4040 : 273 : 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 : 874 : if ((connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) &&
4046 : 761 : !is_signal_data_for_name_lost_or_acquired (signal_data) &&
4047 : 332 : !g_dbus_connection_is_closed (connection) &&
4048 : 320 : !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 : 319 : remove_match_rule (connection, signal_data->rule);
4057 : : }
4058 : :
4059 : 445 : if (signal_data->shared_name_watcher != NULL)
4060 : : {
4061 : 84 : SignalData *name_watcher = g_steal_pointer (&signal_data->shared_name_watcher);
4062 : :
4063 : 84 : name_watcher_unref_watched_name (connection, name_watcher);
4064 : : /* May free signal_data */
4065 : 84 : remove_signal_data_if_unused (connection, name_watcher);
4066 : : }
4067 : :
4068 : 445 : 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 : 1023 : for (n = 0; n < signal_data->subscribers->len; n++)
4091 : : {
4092 : 1023 : SignalSubscriber *subscriber = signal_data->subscribers->pdata[n];
4093 : :
4094 : 1023 : if (subscriber->id != subscription_id)
4095 : 140 : 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 : 11068 : emit_signal_instance_in_idle_cb (gpointer data)
4172 : : {
4173 : 11068 : SignalInstance *signal_instance = data;
4174 : : GVariant *parameters;
4175 : : gboolean has_subscription;
4176 : :
4177 : 11068 : parameters = g_dbus_message_get_body (signal_instance->message);
4178 : 11068 : if (parameters == NULL)
4179 : : {
4180 : 157 : parameters = g_variant_new ("()");
4181 : 157 : g_variant_ref_sink (parameters);
4182 : : }
4183 : : else
4184 : : {
4185 : 10911 : 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 : 11068 : CONNECTION_LOCK (signal_instance->connection);
4200 : 11068 : has_subscription = FALSE;
4201 : 11068 : if (g_hash_table_lookup (signal_instance->connection->map_id_to_signal_data,
4202 : 11068 : GUINT_TO_POINTER (signal_instance->subscriber->id)) != NULL)
4203 : 10733 : has_subscription = TRUE;
4204 : 11068 : CONNECTION_UNLOCK (signal_instance->connection);
4205 : :
4206 : 11068 : if (has_subscription)
4207 : 10733 : 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 : 10733 : signal_instance->subscriber->user_data);
4214 : :
4215 : 11068 : g_variant_unref (parameters);
4216 : :
4217 : 11068 : return FALSE;
4218 : : }
4219 : :
4220 : : static void
4221 : 11068 : signal_instance_free (SignalInstance *signal_instance)
4222 : : {
4223 : 11068 : g_clear_object (&signal_instance->message);
4224 : 11068 : g_object_unref (signal_instance->connection);
4225 : 11068 : signal_subscriber_unref (signal_instance->subscriber);
4226 : 11068 : g_free (signal_instance);
4227 : 11068 : }
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 : 21749 : 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 : 21749 : interface = NULL;
4283 : 21749 : member = NULL;
4284 : 21749 : path = NULL;
4285 : 21749 : arg0 = NULL;
4286 : 21749 : arg0_path = NULL;
4287 : :
4288 : 21749 : interface = g_dbus_message_get_interface (message);
4289 : 21749 : member = g_dbus_message_get_member (message);
4290 : 21749 : path = g_dbus_message_get_path (message);
4291 : 21749 : arg0 = g_dbus_message_get_arg0 (message);
4292 : 21749 : arg0_path = g_dbus_message_get_arg0_path (message);
4293 : :
4294 : : /* These two are mutually exclusive through the type system. */
4295 : 21749 : 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 : 43902 : for (n = 0; n < signal_data_array->len; n++)
4315 : : {
4316 : 22153 : SignalData *signal_data = signal_data_array->pdata[n];
4317 : :
4318 : 22153 : if (signal_data->interface_name != NULL && g_strcmp0 (signal_data->interface_name, interface) != 0)
4319 : 10669 : continue;
4320 : :
4321 : 11484 : if (signal_data->member != NULL && g_strcmp0 (signal_data->member, member) != 0)
4322 : 5336 : continue;
4323 : :
4324 : 6148 : if (signal_data->object_path != NULL && g_strcmp0 (signal_data->object_path, path) != 0)
4325 : 8 : continue;
4326 : :
4327 : 6140 : 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 : 97 : 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 : 97 : g_assert (!g_dbus_is_unique_name (signal_data->sender));
4342 : 97 : g_assert (g_strcmp0 (signal_data->sender, DBUS_SERVICE_DBUS) != 0);
4343 : :
4344 : 97 : watched_name = signal_data->shared_name_watcher->watched_name;
4345 : 97 : g_assert (watched_name != NULL);
4346 : 97 : current_owner = watched_name->owner;
4347 : :
4348 : : /* Skip the signal if the actual sender is not known to own
4349 : : * the required name */
4350 : 97 : if (current_owner == NULL || g_strcmp0 (current_owner, sender) != 0)
4351 : 9 : continue;
4352 : : }
4353 : 6043 : else if (signal_data->sender != NULL)
4354 : : {
4355 : : /* We want signals from a unique name or o.fd.DBus... */
4356 : 5629 : 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 : 5629 : g_assert (g_strcmp0 (signal_data->sender, sender) == 0);
4364 : : }
4365 : : /* else the sender is unspecified and we will accept anything */
4366 : :
4367 : 6131 : if (signal_data->arg0 != NULL)
4368 : : {
4369 : 5405 : 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 : 5400 : 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 : 5388 : else if (arg0 == NULL || !g_str_equal (signal_data->arg0, arg0))
4381 : 32 : continue;
4382 : : }
4383 : :
4384 : 6091 : if (signal_data->watched_name != NULL)
4385 : : {
4386 : : /* Invariant: SignalData should only have a watched_name if it
4387 : : * represents the NameOwnerChanged signal */
4388 : 5213 : g_assert (g_strcmp0 (sender, DBUS_SERVICE_DBUS) == 0);
4389 : 5213 : g_assert (g_strcmp0 (interface, DBUS_INTERFACE_DBUS) == 0);
4390 : 5213 : g_assert (g_strcmp0 (path, DBUS_PATH_DBUS) == 0);
4391 : 5213 : g_assert (g_strcmp0 (member, "NameOwnerChanged") == 0);
4392 : 5213 : name_watcher_deliver_name_owner_changed_unlocked (signal_data, message);
4393 : : }
4394 : :
4395 : 17276 : for (m = 0; m < signal_data->subscribers->len; m++)
4396 : : {
4397 : 11185 : SignalSubscriber *subscriber = signal_data->subscribers->pdata[m];
4398 : : GSource *idle_source;
4399 : : SignalInstance *signal_instance;
4400 : :
4401 : 11185 : signal_instance = g_new0 (SignalInstance, 1);
4402 : 11185 : signal_instance->subscriber = signal_subscriber_ref (subscriber);
4403 : 11185 : signal_instance->message = g_object_ref (message);
4404 : 11185 : signal_instance->connection = g_object_ref (connection);
4405 : 11185 : signal_instance->sender = sender;
4406 : 11185 : signal_instance->path = path;
4407 : 11185 : signal_instance->interface = interface;
4408 : 11185 : signal_instance->member = member;
4409 : :
4410 : 11185 : idle_source = g_idle_source_new ();
4411 : 11185 : g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
4412 : 11185 : g_source_set_callback (idle_source,
4413 : : emit_signal_instance_in_idle_cb,
4414 : : signal_instance,
4415 : : (GDestroyNotify) signal_instance_free);
4416 : 11185 : g_source_set_static_name (idle_source, "[gio] emit_signal_instance_in_idle_cb");
4417 : 11185 : g_source_attach (idle_source, subscriber->context);
4418 : 11185 : g_source_unref (idle_source);
4419 : : }
4420 : : }
4421 : 21749 : }
4422 : :
4423 : : /* called in GDBusWorker thread with lock held */
4424 : : static void
4425 : 13452 : distribute_signals (GDBusConnection *connection,
4426 : : GDBusMessage *message)
4427 : : {
4428 : : GPtrArray *signal_data_array;
4429 : : const gchar *sender, *interface, *member, *path;
4430 : :
4431 : 13452 : g_assert (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_SIGNAL);
4432 : :
4433 : 13452 : 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 : 13452 : interface = g_dbus_message_get_interface (message);
4438 : 13452 : member = g_dbus_message_get_member (message);
4439 : 13452 : path = g_dbus_message_get_path (message);
4440 : :
4441 : 13452 : g_assert (interface != NULL);
4442 : 13452 : g_assert (member != NULL);
4443 : 13452 : g_assert (path != NULL);
4444 : :
4445 : 13452 : 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 : 13452 : if (sender != NULL)
4460 : : {
4461 : 13277 : signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, sender);
4462 : 13277 : if (signal_data_array != NULL)
4463 : 10803 : schedule_callbacks (connection, signal_data_array, message, sender);
4464 : : }
4465 : :
4466 : : /* collect subscribers not matching on sender, or matching a well-known name */
4467 : 13452 : signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, "");
4468 : 13452 : if (signal_data_array != NULL)
4469 : 10946 : schedule_callbacks (connection, signal_data_array, message, sender);
4470 : 13452 : }
4471 : :
4472 : : /* ---------------------------------------------------------------------------------------------------- */
4473 : :
4474 : : /* only called from finalize(), removes all subscriptions */
4475 : : static void
4476 : 2613 : purge_all_signal_subscriptions (GDBusConnection *connection)
4477 : : {
4478 : : GHashTableIter iter;
4479 : : gpointer key;
4480 : : GArray *ids;
4481 : : guint n;
4482 : :
4483 : 2613 : ids = g_array_new (FALSE, FALSE, sizeof (guint));
4484 : 2613 : g_hash_table_iter_init (&iter, connection->map_id_to_signal_data);
4485 : 2614 : 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 : 2614 : 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 : 2613 : g_array_free (ids, TRUE);
4497 : 2613 : }
4498 : :
4499 : : /* ---------------------------------------------------------------------------------------------------- */
4500 : :
4501 : : static GDBusInterfaceVTable *
4502 : 200620 : _g_dbus_interface_vtable_copy (const GDBusInterfaceVTable *vtable)
4503 : : {
4504 : : /* Don't waste memory by copying padding - remember to update this
4505 : : * when changing struct _GDBusInterfaceVTable in gdbusconnection.h
4506 : : */
4507 : 200620 : return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer));
4508 : : }
4509 : :
4510 : : static void
4511 : 200611 : _g_dbus_interface_vtable_free (GDBusInterfaceVTable *vtable)
4512 : : {
4513 : 200611 : g_free (vtable);
4514 : 200611 : }
4515 : :
4516 : : /* ---------------------------------------------------------------------------------------------------- */
4517 : :
4518 : : static GDBusSubtreeVTable *
4519 : 1003 : _g_dbus_subtree_vtable_copy (const GDBusSubtreeVTable *vtable)
4520 : : {
4521 : : /* Don't waste memory by copying padding - remember to update this
4522 : : * when changing struct _GDBusSubtreeVTable in gdbusconnection.h
4523 : : */
4524 : 1003 : return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer));
4525 : : }
4526 : :
4527 : : static void
4528 : 1003 : _g_dbus_subtree_vtable_free (GDBusSubtreeVTable *vtable)
4529 : : {
4530 : 1003 : g_free (vtable);
4531 : 1003 : }
4532 : :
4533 : : /* ---------------------------------------------------------------------------------------------------- */
4534 : :
4535 : : struct ExportedObject
4536 : : {
4537 : : gchar *object_path;
4538 : : GDBusConnection *connection;
4539 : :
4540 : : /* maps gchar* -> ExportedInterface* */
4541 : : GHashTable *map_if_name_to_ei;
4542 : : };
4543 : :
4544 : : /* only called with lock held */
4545 : : static void
4546 : 200520 : exported_object_free (ExportedObject *eo)
4547 : : {
4548 : 200520 : g_free (eo->object_path);
4549 : 200520 : g_hash_table_unref (eo->map_if_name_to_ei);
4550 : 200520 : g_free (eo);
4551 : 200520 : }
4552 : :
4553 : : typedef struct
4554 : : {
4555 : : ExportedObject *eo;
4556 : :
4557 : : gint refcount; /* (atomic) */
4558 : :
4559 : : guint id;
4560 : : gchar *interface_name; /* (owned) */
4561 : : GDBusInterfaceVTable *vtable; /* (owned) */
4562 : : GDBusInterfaceInfo *interface_info; /* (owned) */
4563 : :
4564 : : GMainContext *context; /* (owned) */
4565 : : gpointer user_data;
4566 : : GDestroyNotify user_data_free_func;
4567 : : } ExportedInterface;
4568 : :
4569 : : static ExportedInterface *
4570 : 742 : exported_interface_ref (ExportedInterface *ei)
4571 : : {
4572 : 742 : g_atomic_int_inc (&ei->refcount);
4573 : :
4574 : 742 : return ei;
4575 : : }
4576 : :
4577 : : /* May be called with lock held */
4578 : : static void
4579 : 201353 : exported_interface_unref (ExportedInterface *ei)
4580 : : {
4581 : 201353 : if (!g_atomic_int_dec_and_test (&ei->refcount))
4582 : 742 : return;
4583 : :
4584 : 200611 : g_dbus_interface_info_cache_release (ei->interface_info);
4585 : 200611 : g_dbus_interface_info_unref ((GDBusInterfaceInfo *) ei->interface_info);
4586 : :
4587 : : /* All uses of ei->vtable from callbacks scheduled in idle functions must
4588 : : * have completed by this call_destroy_notify() call, as language bindings
4589 : : * may destroy function closures in this callback. */
4590 : 200611 : call_destroy_notify (ei->context,
4591 : : ei->user_data_free_func,
4592 : : ei->user_data);
4593 : :
4594 : 200611 : g_main_context_unref (ei->context);
4595 : :
4596 : 200611 : g_free (ei->interface_name);
4597 : 200611 : _g_dbus_interface_vtable_free (ei->vtable);
4598 : 200611 : g_free (ei);
4599 : : }
4600 : :
4601 : : struct ExportedSubtree
4602 : : {
4603 : : gint refcount; /* (atomic) */
4604 : :
4605 : : guint id;
4606 : : gchar *object_path; /* (owned) */
4607 : : GDBusConnection *connection; /* (unowned) */
4608 : : GDBusSubtreeVTable *vtable; /* (owned) */
4609 : : GDBusSubtreeFlags flags;
4610 : :
4611 : : GMainContext *context; /* (owned) */
4612 : : gpointer user_data;
4613 : : GDestroyNotify user_data_free_func;
4614 : : };
4615 : :
4616 : : static ExportedSubtree *
4617 : 383 : exported_subtree_ref (ExportedSubtree *es)
4618 : : {
4619 : 383 : g_atomic_int_inc (&es->refcount);
4620 : :
4621 : 383 : return es;
4622 : : }
4623 : :
4624 : : /* May be called with lock held */
4625 : : static void
4626 : 1386 : exported_subtree_unref (ExportedSubtree *es)
4627 : : {
4628 : 1386 : if (!g_atomic_int_dec_and_test (&es->refcount))
4629 : 383 : return;
4630 : :
4631 : : /* All uses of es->vtable from callbacks scheduled in idle functions must
4632 : : * have completed by this call_destroy_notify() call, as language bindings
4633 : : * may destroy function closures in this callback. */
4634 : 1003 : call_destroy_notify (es->context,
4635 : : es->user_data_free_func,
4636 : : es->user_data);
4637 : :
4638 : 1003 : g_main_context_unref (es->context);
4639 : :
4640 : 1003 : _g_dbus_subtree_vtable_free (es->vtable);
4641 : 1003 : g_free (es->object_path);
4642 : 1003 : g_free (es);
4643 : : }
4644 : :
4645 : : /* ---------------------------------------------------------------------------------------------------- */
4646 : :
4647 : : /* Convenience function to check if @registration_id (if not zero) or
4648 : : * @subtree_registration_id (if not zero) has been unregistered. If
4649 : : * so, returns %TRUE.
4650 : : *
4651 : : * If not, sets @out_ei and/or @out_es to a strong reference to the relevant
4652 : : * #ExportedInterface/#ExportedSubtree and returns %FALSE.
4653 : : *
4654 : : * May be called by any thread. Caller must *not* hold lock.
4655 : : */
4656 : : static gboolean
4657 : 1075 : has_object_been_unregistered (GDBusConnection *connection,
4658 : : guint registration_id,
4659 : : ExportedInterface **out_ei,
4660 : : guint subtree_registration_id,
4661 : : ExportedSubtree **out_es)
4662 : : {
4663 : : gboolean ret;
4664 : 1075 : ExportedInterface *ei = NULL;
4665 : 1075 : gpointer es = NULL;
4666 : :
4667 : 1075 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
4668 : :
4669 : 1075 : ret = FALSE;
4670 : :
4671 : 1075 : CONNECTION_LOCK (connection);
4672 : :
4673 : 1075 : if (registration_id != 0)
4674 : : {
4675 : 803 : ei = g_hash_table_lookup (connection->map_id_to_ei, GUINT_TO_POINTER (registration_id));
4676 : 803 : if (ei == NULL)
4677 : 61 : ret = TRUE;
4678 : 742 : else if (out_ei != NULL)
4679 : 742 : *out_ei = exported_interface_ref (ei);
4680 : : }
4681 : 1075 : if (subtree_registration_id != 0)
4682 : : {
4683 : 272 : es = g_hash_table_lookup (connection->map_id_to_es, GUINT_TO_POINTER (subtree_registration_id));
4684 : 272 : if (es == NULL)
4685 : 189 : ret = TRUE;
4686 : 83 : else if (out_es != NULL)
4687 : 83 : *out_es = exported_subtree_ref (es);
4688 : : }
4689 : :
4690 : 1075 : CONNECTION_UNLOCK (connection);
4691 : :
4692 : 1075 : return ret;
4693 : : }
4694 : :
4695 : : /* ---------------------------------------------------------------------------------------------------- */
4696 : :
4697 : : typedef struct
4698 : : {
4699 : : GDBusConnection *connection;
4700 : : GDBusMessage *message; /* (owned) */
4701 : : gpointer user_data;
4702 : : const gchar *property_name;
4703 : : const GDBusInterfaceVTable *vtable;
4704 : : GDBusInterfaceInfo *interface_info;
4705 : : const GDBusPropertyInfo *property_info;
4706 : : guint registration_id;
4707 : : guint subtree_registration_id;
4708 : : } PropertyData;
4709 : :
4710 : : static void
4711 : 48 : property_data_free (PropertyData *data)
4712 : : {
4713 : 48 : g_object_unref (data->connection);
4714 : 48 : g_clear_object (&data->message);
4715 : 48 : g_free (data);
4716 : 48 : }
4717 : :
4718 : : /* called in thread where object was registered - no locks held */
4719 : : static gboolean
4720 : 5 : invoke_get_property_in_idle_cb (gpointer _data)
4721 : : {
4722 : 5 : PropertyData *data = _data;
4723 : : GVariant *value;
4724 : : GError *error;
4725 : : GDBusMessage *reply;
4726 : 5 : ExportedInterface *ei = NULL;
4727 : 5 : ExportedSubtree *es = NULL;
4728 : :
4729 : 5 : if (has_object_been_unregistered (data->connection,
4730 : : data->registration_id,
4731 : : &ei,
4732 : : data->subtree_registration_id,
4733 : : &es))
4734 : : {
4735 : 0 : reply = g_dbus_message_new_method_error (data->message,
4736 : : DBUS_ERROR_UNKNOWN_METHOD,
4737 : : /* Translators: The first placeholder is a D-Bus interface,
4738 : : * the second is the path of an object. */
4739 : : _("No such interface “%s” on object at path %s"),
4740 : : DBUS_INTERFACE_PROPERTIES,
4741 : : g_dbus_message_get_path (data->message));
4742 : 0 : g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4743 : 0 : g_object_unref (reply);
4744 : 0 : goto out;
4745 : : }
4746 : :
4747 : 5 : error = NULL;
4748 : 5 : value = data->vtable->get_property (data->connection,
4749 : : g_dbus_message_get_sender (data->message),
4750 : : g_dbus_message_get_path (data->message),
4751 : 5 : data->interface_info->name,
4752 : : data->property_name,
4753 : : &error,
4754 : : data->user_data);
4755 : :
4756 : :
4757 : 5 : if (value != NULL)
4758 : : {
4759 : 5 : g_assert (error == NULL);
4760 : :
4761 : 5 : g_variant_take_ref (value);
4762 : 5 : reply = g_dbus_message_new_method_reply (data->message);
4763 : 5 : g_dbus_message_set_body (reply, g_variant_new ("(v)", value));
4764 : 5 : g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4765 : 5 : g_variant_unref (value);
4766 : 5 : g_object_unref (reply);
4767 : : }
4768 : : else
4769 : : {
4770 : : gchar *dbus_error_name;
4771 : 0 : g_assert (error != NULL);
4772 : 0 : dbus_error_name = g_dbus_error_encode_gerror (error);
4773 : 0 : reply = g_dbus_message_new_method_error_literal (data->message,
4774 : : dbus_error_name,
4775 : 0 : error->message);
4776 : 0 : g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4777 : 0 : g_free (dbus_error_name);
4778 : 0 : g_error_free (error);
4779 : 0 : g_object_unref (reply);
4780 : : }
4781 : :
4782 : 5 : out:
4783 : 5 : g_clear_pointer (&ei, exported_interface_unref);
4784 : 5 : g_clear_pointer (&es, exported_subtree_unref);
4785 : :
4786 : 5 : return FALSE;
4787 : : }
4788 : :
4789 : : /* called in thread where object was registered - no locks held */
4790 : : static gboolean
4791 : 43 : invoke_set_property_in_idle_cb (gpointer _data)
4792 : : {
4793 : 43 : PropertyData *data = _data;
4794 : : GError *error;
4795 : : GDBusMessage *reply;
4796 : : GVariant *value;
4797 : :
4798 : 43 : error = NULL;
4799 : 43 : value = NULL;
4800 : :
4801 : 43 : g_variant_get (g_dbus_message_get_body (data->message),
4802 : : "(ssv)",
4803 : : NULL,
4804 : : NULL,
4805 : : &value);
4806 : :
4807 : 43 : if (!data->vtable->set_property (data->connection,
4808 : : g_dbus_message_get_sender (data->message),
4809 : : g_dbus_message_get_path (data->message),
4810 : 43 : data->interface_info->name,
4811 : : data->property_name,
4812 : : value,
4813 : : &error,
4814 : : data->user_data))
4815 : : {
4816 : : gchar *dbus_error_name;
4817 : 4 : g_assert (error != NULL);
4818 : 4 : dbus_error_name = g_dbus_error_encode_gerror (error);
4819 : 4 : reply = g_dbus_message_new_method_error_literal (data->message,
4820 : : dbus_error_name,
4821 : 4 : error->message);
4822 : 4 : g_free (dbus_error_name);
4823 : 4 : g_error_free (error);
4824 : : }
4825 : : else
4826 : : {
4827 : 39 : reply = g_dbus_message_new_method_reply (data->message);
4828 : : }
4829 : :
4830 : 43 : g_assert (reply != NULL);
4831 : 43 : g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4832 : 43 : g_object_unref (reply);
4833 : 43 : g_variant_unref (value);
4834 : :
4835 : 43 : return FALSE;
4836 : : }
4837 : :
4838 : : /* called in any thread with connection's lock held */
4839 : : static gboolean
4840 : 79 : validate_and_maybe_schedule_property_getset (GDBusConnection *connection,
4841 : : GDBusMessage *message,
4842 : : guint registration_id,
4843 : : guint subtree_registration_id,
4844 : : gboolean is_get,
4845 : : GDBusInterfaceInfo *interface_info,
4846 : : const GDBusInterfaceVTable *vtable,
4847 : : GMainContext *main_context,
4848 : : gpointer user_data)
4849 : : {
4850 : : gboolean handled;
4851 : : const char *interface_name;
4852 : : const char *property_name;
4853 : : const GDBusPropertyInfo *property_info;
4854 : : GSource *idle_source;
4855 : : PropertyData *property_data;
4856 : : GDBusMessage *reply;
4857 : :
4858 : 79 : handled = FALSE;
4859 : :
4860 : 79 : if (is_get)
4861 : 24 : g_variant_get (g_dbus_message_get_body (message),
4862 : : "(&s&s)",
4863 : : &interface_name,
4864 : : &property_name);
4865 : : else
4866 : 55 : g_variant_get (g_dbus_message_get_body (message),
4867 : : "(&s&sv)",
4868 : : &interface_name,
4869 : : &property_name,
4870 : : NULL);
4871 : :
4872 : 79 : if (vtable == NULL)
4873 : 0 : goto out;
4874 : :
4875 : : /* Check that the property exists - if not fail with DBUS_ERROR_INVALID_ARGS
4876 : : */
4877 : 79 : property_info = NULL;
4878 : :
4879 : : /* TODO: the cost of this is O(n) - it might be worth caching the result */
4880 : 79 : property_info = g_dbus_interface_info_lookup_property (interface_info, property_name);
4881 : 79 : if (property_info == NULL)
4882 : : {
4883 : 8 : reply = g_dbus_message_new_method_error (message,
4884 : : DBUS_ERROR_INVALID_ARGS,
4885 : : _("No such property “%s”"),
4886 : : property_name);
4887 : 8 : g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4888 : 8 : g_object_unref (reply);
4889 : 8 : handled = TRUE;
4890 : 8 : goto out;
4891 : : }
4892 : :
4893 : 71 : if (is_get && !(property_info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE))
4894 : : {
4895 : 5 : reply = g_dbus_message_new_method_error (message,
4896 : : DBUS_ERROR_INVALID_ARGS,
4897 : : _("Property “%s” is not readable"),
4898 : : property_name);
4899 : 5 : g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4900 : 5 : g_object_unref (reply);
4901 : 5 : handled = TRUE;
4902 : 5 : goto out;
4903 : : }
4904 : 66 : else if (!is_get && !(property_info->flags & G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE))
4905 : : {
4906 : 5 : reply = g_dbus_message_new_method_error (message,
4907 : : DBUS_ERROR_INVALID_ARGS,
4908 : : _("Property “%s” is not writable"),
4909 : : property_name);
4910 : 5 : g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4911 : 5 : g_object_unref (reply);
4912 : 5 : handled = TRUE;
4913 : 5 : goto out;
4914 : : }
4915 : :
4916 : 61 : if (!is_get)
4917 : : {
4918 : : GVariant *value;
4919 : :
4920 : : /* Fail with DBUS_ERROR_INVALID_ARGS if the type
4921 : : * of the given value is wrong
4922 : : */
4923 : 48 : g_variant_get_child (g_dbus_message_get_body (message), 2, "v", &value);
4924 : 48 : if (g_strcmp0 (g_variant_get_type_string (value), property_info->signature) != 0)
4925 : : {
4926 : 2 : reply = g_dbus_message_new_method_error (message,
4927 : : DBUS_ERROR_INVALID_ARGS,
4928 : : _("Error setting property “%s”: Expected type “%s” but got “%s”"),
4929 : 1 : property_name, property_info->signature,
4930 : : g_variant_get_type_string (value));
4931 : 1 : g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
4932 : 1 : g_variant_unref (value);
4933 : 1 : g_object_unref (reply);
4934 : 1 : handled = TRUE;
4935 : 1 : goto out;
4936 : : }
4937 : :
4938 : 47 : g_variant_unref (value);
4939 : : }
4940 : :
4941 : : /* If the vtable pointer for get_property() resp. set_property() is
4942 : : * NULL then dispatch the call via the method_call() handler.
4943 : : */
4944 : 60 : if (is_get)
4945 : : {
4946 : 13 : if (vtable->get_property == NULL)
4947 : : {
4948 : 8 : schedule_method_call (connection, message, registration_id, subtree_registration_id,
4949 : : interface_info, NULL, property_info, g_dbus_message_get_body (message),
4950 : : vtable, main_context, user_data);
4951 : 8 : handled = TRUE;
4952 : 8 : goto out;
4953 : : }
4954 : : }
4955 : : else
4956 : : {
4957 : 47 : if (vtable->set_property == NULL)
4958 : : {
4959 : 4 : schedule_method_call (connection, message, registration_id, subtree_registration_id,
4960 : : interface_info, NULL, property_info, g_dbus_message_get_body (message),
4961 : : vtable, main_context, user_data);
4962 : 4 : handled = TRUE;
4963 : 4 : goto out;
4964 : : }
4965 : : }
4966 : :
4967 : : /* ok, got the property info - call user code in an idle handler */
4968 : 48 : property_data = g_new0 (PropertyData, 1);
4969 : 48 : property_data->connection = g_object_ref (connection);
4970 : 48 : property_data->message = g_object_ref (message);
4971 : 48 : property_data->user_data = user_data;
4972 : 48 : property_data->property_name = property_name;
4973 : 48 : property_data->vtable = vtable;
4974 : 48 : property_data->interface_info = interface_info;
4975 : 48 : property_data->property_info = property_info;
4976 : 48 : property_data->registration_id = registration_id;
4977 : 48 : property_data->subtree_registration_id = subtree_registration_id;
4978 : :
4979 : 48 : idle_source = g_idle_source_new ();
4980 : 48 : g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
4981 : 48 : g_source_set_callback (idle_source,
4982 : : is_get ? invoke_get_property_in_idle_cb : invoke_set_property_in_idle_cb,
4983 : : property_data,
4984 : : (GDestroyNotify) property_data_free);
4985 : 48 : if (is_get)
4986 : 5 : g_source_set_static_name (idle_source, "[gio] invoke_get_property_in_idle_cb");
4987 : : else
4988 : 43 : g_source_set_static_name (idle_source, "[gio] invoke_set_property_in_idle_cb");
4989 : 48 : g_source_attach (idle_source, main_context);
4990 : 48 : g_source_unref (idle_source);
4991 : :
4992 : 48 : handled = TRUE;
4993 : :
4994 : 79 : out:
4995 : 79 : return handled;
4996 : : }
4997 : :
4998 : : /* called in GDBusWorker thread with connection's lock held */
4999 : : static gboolean
5000 : 76 : handle_getset_property (GDBusConnection *connection,
5001 : : ExportedObject *eo,
5002 : : GDBusMessage *message,
5003 : : gboolean is_get)
5004 : : {
5005 : : ExportedInterface *ei;
5006 : : gboolean handled;
5007 : : const char *interface_name;
5008 : : const char *property_name;
5009 : :
5010 : 76 : handled = FALSE;
5011 : :
5012 : 76 : if (is_get)
5013 : 22 : g_variant_get (g_dbus_message_get_body (message),
5014 : : "(&s&s)",
5015 : : &interface_name,
5016 : : &property_name);
5017 : : else
5018 : 54 : g_variant_get (g_dbus_message_get_body (message),
5019 : : "(&s&sv)",
5020 : : &interface_name,
5021 : : &property_name,
5022 : : NULL);
5023 : :
5024 : : /* Fail with DBUS_ERROR_INVALID_ARGS if there is
5025 : : * no such interface registered
5026 : : */
5027 : 76 : ei = g_hash_table_lookup (eo->map_if_name_to_ei, interface_name);
5028 : 76 : if (ei == NULL)
5029 : : {
5030 : : GDBusMessage *reply;
5031 : 2 : reply = g_dbus_message_new_method_error (message,
5032 : : DBUS_ERROR_INVALID_ARGS,
5033 : : _("No such interface “%s”"),
5034 : : interface_name);
5035 : 2 : g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
5036 : 2 : g_object_unref (reply);
5037 : 2 : handled = TRUE;
5038 : 2 : goto out;
5039 : : }
5040 : :
5041 : 74 : handled = validate_and_maybe_schedule_property_getset (eo->connection,
5042 : : message,
5043 : : ei->id,
5044 : : 0,
5045 : : is_get,
5046 : : ei->interface_info,
5047 : 74 : ei->vtable,
5048 : : ei->context,
5049 : : ei->user_data);
5050 : 76 : out:
5051 : 76 : return handled;
5052 : : }
5053 : :
5054 : : /* ---------------------------------------------------------------------------------------------------- */
5055 : :
5056 : : typedef struct
5057 : : {
5058 : : GDBusConnection *connection;
5059 : : GDBusMessage *message; /* (owned) */
5060 : : gpointer user_data;
5061 : : const GDBusInterfaceVTable *vtable;
5062 : : GDBusInterfaceInfo *interface_info;
5063 : : guint registration_id;
5064 : : guint subtree_registration_id;
5065 : : } PropertyGetAllData;
5066 : :
5067 : : static void
5068 : 43 : property_get_all_data_free (PropertyGetAllData *data)
5069 : : {
5070 : 43 : g_object_unref (data->connection);
5071 : 43 : g_clear_object (&data->message);
5072 : 43 : g_free (data);
5073 : 43 : }
5074 : :
5075 : : /* called in thread where object was registered - no locks held */
5076 : : static gboolean
5077 : 43 : invoke_get_all_properties_in_idle_cb (gpointer _data)
5078 : : {
5079 : 43 : PropertyGetAllData *data = _data;
5080 : : GVariantBuilder builder;
5081 : : GDBusMessage *reply;
5082 : : guint n;
5083 : 43 : ExportedInterface *ei = NULL;
5084 : 43 : ExportedSubtree *es = NULL;
5085 : :
5086 : 43 : if (has_object_been_unregistered (data->connection,
5087 : : data->registration_id,
5088 : : &ei,
5089 : : data->subtree_registration_id,
5090 : : &es))
5091 : : {
5092 : 0 : reply = g_dbus_message_new_method_error (data->message,
5093 : : DBUS_ERROR_UNKNOWN_METHOD,
5094 : : _("No such interface “%s” on object at path %s"),
5095 : : DBUS_INTERFACE_PROPERTIES,
5096 : : g_dbus_message_get_path (data->message));
5097 : 0 : g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
5098 : 0 : g_object_unref (reply);
5099 : 0 : goto out;
5100 : : }
5101 : :
5102 : : /* TODO: Right now we never fail this call - we just omit values if
5103 : : * a get_property() call is failing.
5104 : : *
5105 : : * We could fail the whole call if just a single get_property() call
5106 : : * returns an error. We need clarification in the D-Bus spec about this.
5107 : : */
5108 : 43 : g_variant_builder_init_static (&builder, G_VARIANT_TYPE ("(a{sv})"));
5109 : 43 : g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
5110 : 508 : for (n = 0; data->interface_info->properties != NULL && data->interface_info->properties[n] != NULL; n++)
5111 : : {
5112 : 465 : const GDBusPropertyInfo *property_info = data->interface_info->properties[n];
5113 : : GVariant *value;
5114 : :
5115 : 465 : if (!(property_info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE))
5116 : 7 : continue;
5117 : :
5118 : 458 : value = data->vtable->get_property (data->connection,
5119 : : g_dbus_message_get_sender (data->message),
5120 : : g_dbus_message_get_path (data->message),
5121 : 458 : data->interface_info->name,
5122 : 458 : property_info->name,
5123 : : NULL,
5124 : : data->user_data);
5125 : :
5126 : 458 : if (value == NULL)
5127 : 0 : continue;
5128 : :
5129 : 458 : g_variant_take_ref (value);
5130 : 458 : g_variant_builder_add (&builder,
5131 : : "{sv}",
5132 : 458 : property_info->name,
5133 : : value);
5134 : 458 : g_variant_unref (value);
5135 : : }
5136 : 43 : g_variant_builder_close (&builder);
5137 : :
5138 : 43 : reply = g_dbus_message_new_method_reply (data->message);
5139 : 43 : g_dbus_message_set_body (reply, g_variant_builder_end (&builder));
5140 : 43 : g_dbus_connection_send_message (data->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
5141 : 43 : g_object_unref (reply);
5142 : :
5143 : 43 : out:
5144 : 43 : g_clear_pointer (&ei, exported_interface_unref);
5145 : 43 : g_clear_pointer (&es, exported_subtree_unref);
5146 : :
5147 : 43 : return FALSE;
5148 : : }
5149 : :
5150 : : static gboolean
5151 : 5 : interface_has_readable_properties (GDBusInterfaceInfo *interface_info)
5152 : : {
5153 : : gint i;
5154 : :
5155 : 5 : if (!interface_info->properties)
5156 : 1 : return FALSE;
5157 : :
5158 : 4 : for (i = 0; interface_info->properties[i]; i++)
5159 : 3 : if (interface_info->properties[i]->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
5160 : 3 : return TRUE;
5161 : :
5162 : 1 : return FALSE;
5163 : : }
5164 : :
5165 : : /* called in any thread with connection's lock held */
5166 : : static gboolean
5167 : 46 : validate_and_maybe_schedule_property_get_all (GDBusConnection *connection,
5168 : : GDBusMessage *message,
5169 : : guint registration_id,
5170 : : guint subtree_registration_id,
5171 : : GDBusInterfaceInfo *interface_info,
5172 : : const GDBusInterfaceVTable *vtable,
5173 : : GMainContext *main_context,
5174 : : gpointer user_data)
5175 : : {
5176 : : gboolean handled;
5177 : : GSource *idle_source;
5178 : : PropertyGetAllData *property_get_all_data;
5179 : :
5180 : 46 : handled = FALSE;
5181 : :
5182 : 46 : if (vtable == NULL)
5183 : 0 : goto out;
5184 : :
5185 : : /* If the vtable pointer for get_property() is NULL but we have a
5186 : : * non-zero number of readable properties, then dispatch the call via
5187 : : * the method_call() handler.
5188 : : */
5189 : 46 : if (vtable->get_property == NULL && interface_has_readable_properties (interface_info))
5190 : : {
5191 : 3 : schedule_method_call (connection, message, registration_id, subtree_registration_id,
5192 : : interface_info, NULL, NULL, g_dbus_message_get_body (message),
5193 : : vtable, main_context, user_data);
5194 : 3 : handled = TRUE;
5195 : 3 : goto out;
5196 : : }
5197 : :
5198 : : /* ok, got the property info - call user in an idle handler */
5199 : 43 : property_get_all_data = g_new0 (PropertyGetAllData, 1);
5200 : 43 : property_get_all_data->connection = g_object_ref (connection);
5201 : 43 : property_get_all_data->message = g_object_ref (message);
5202 : 43 : property_get_all_data->user_data = user_data;
5203 : 43 : property_get_all_data->vtable = vtable;
5204 : 43 : property_get_all_data->interface_info = interface_info;
5205 : 43 : property_get_all_data->registration_id = registration_id;
5206 : 43 : property_get_all_data->subtree_registration_id = subtree_registration_id;
5207 : :
5208 : 43 : idle_source = g_idle_source_new ();
5209 : 43 : g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
5210 : 43 : g_source_set_callback (idle_source,
5211 : : invoke_get_all_properties_in_idle_cb,
5212 : : property_get_all_data,
5213 : : (GDestroyNotify) property_get_all_data_free);
5214 : 43 : g_source_set_static_name (idle_source, "[gio] invoke_get_all_properties_in_idle_cb");
5215 : 43 : g_source_attach (idle_source, main_context);
5216 : 43 : g_source_unref (idle_source);
5217 : :
5218 : 43 : handled = TRUE;
5219 : :
5220 : 46 : out:
5221 : 46 : return handled;
5222 : : }
5223 : :
5224 : : /* called in GDBusWorker thread with connection's lock held */
5225 : : static gboolean
5226 : 46 : handle_get_all_properties (GDBusConnection *connection,
5227 : : ExportedObject *eo,
5228 : : GDBusMessage *message)
5229 : : {
5230 : : ExportedInterface *ei;
5231 : : gboolean handled;
5232 : : const char *interface_name;
5233 : :
5234 : 46 : handled = FALSE;
5235 : :
5236 : 46 : g_variant_get (g_dbus_message_get_body (message),
5237 : : "(&s)",
5238 : : &interface_name);
5239 : :
5240 : : /* Fail with DBUS_ERROR_INVALID_ARGS if there is
5241 : : * no such interface registered
5242 : : */
5243 : 46 : ei = g_hash_table_lookup (eo->map_if_name_to_ei, interface_name);
5244 : 46 : if (ei == NULL)
5245 : : {
5246 : : GDBusMessage *reply;
5247 : 1 : reply = g_dbus_message_new_method_error (message,
5248 : : DBUS_ERROR_INVALID_ARGS,
5249 : : _("No such interface “%s”"),
5250 : : interface_name);
5251 : 1 : g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
5252 : 1 : g_object_unref (reply);
5253 : 1 : handled = TRUE;
5254 : 1 : goto out;
5255 : : }
5256 : :
5257 : 45 : handled = validate_and_maybe_schedule_property_get_all (eo->connection,
5258 : : message,
5259 : : ei->id,
5260 : : 0,
5261 : : ei->interface_info,
5262 : 45 : ei->vtable,
5263 : : ei->context,
5264 : : ei->user_data);
5265 : 46 : out:
5266 : 46 : return handled;
5267 : : }
5268 : :
5269 : : /* ---------------------------------------------------------------------------------------------------- */
5270 : :
5271 : : static const gchar introspect_header[] =
5272 : : "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
5273 : : " \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
5274 : : "<!-- GDBus " PACKAGE_VERSION " -->\n"
5275 : : "<node>\n";
5276 : :
5277 : : static const gchar introspect_tail[] =
5278 : : "</node>\n";
5279 : :
5280 : : static const gchar introspect_properties_interface[] =
5281 : : " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n"
5282 : : " <method name=\"Get\">\n"
5283 : : " <arg type=\"s\" name=\"interface_name\" direction=\"in\"/>\n"
5284 : : " <arg type=\"s\" name=\"property_name\" direction=\"in\"/>\n"
5285 : : " <arg type=\"v\" name=\"value\" direction=\"out\"/>\n"
5286 : : " </method>\n"
5287 : : " <method name=\"GetAll\">\n"
5288 : : " <arg type=\"s\" name=\"interface_name\" direction=\"in\"/>\n"
5289 : : " <arg type=\"a{sv}\" name=\"properties\" direction=\"out\"/>\n"
5290 : : " </method>\n"
5291 : : " <method name=\"Set\">\n"
5292 : : " <arg type=\"s\" name=\"interface_name\" direction=\"in\"/>\n"
5293 : : " <arg type=\"s\" name=\"property_name\" direction=\"in\"/>\n"
5294 : : " <arg type=\"v\" name=\"value\" direction=\"in\"/>\n"
5295 : : " </method>\n"
5296 : : " <signal name=\"PropertiesChanged\">\n"
5297 : : " <arg type=\"s\" name=\"interface_name\"/>\n"
5298 : : " <arg type=\"a{sv}\" name=\"changed_properties\"/>\n"
5299 : : " <arg type=\"as\" name=\"invalidated_properties\"/>\n"
5300 : : " </signal>\n"
5301 : : " </interface>\n";
5302 : :
5303 : : static const gchar introspect_introspectable_interface[] =
5304 : : " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n"
5305 : : " <method name=\"Introspect\">\n"
5306 : : " <arg type=\"s\" name=\"xml_data\" direction=\"out\"/>\n"
5307 : : " </method>\n"
5308 : : " </interface>\n"
5309 : : " <interface name=\"" DBUS_INTERFACE_PEER "\">\n"
5310 : : " <method name=\"Ping\"/>\n"
5311 : : " <method name=\"GetMachineId\">\n"
5312 : : " <arg type=\"s\" name=\"machine_uuid\" direction=\"out\"/>\n"
5313 : : " </method>\n"
5314 : : " </interface>\n";
5315 : :
5316 : : static void
5317 : 68 : introspect_append_header (GString *s)
5318 : : {
5319 : : g_string_append (s, introspect_header);
5320 : 68 : }
5321 : :
5322 : : static void
5323 : 583 : maybe_add_path (const gchar *path, gsize path_len, const gchar *object_path, GHashTable *set)
5324 : : {
5325 : 583 : if (g_str_has_prefix (object_path, path) && strlen (object_path) > path_len && object_path[path_len-1] == '/')
5326 : : {
5327 : : const gchar *begin;
5328 : : const gchar *end;
5329 : : gchar *s;
5330 : :
5331 : 77 : begin = object_path + path_len;
5332 : 77 : end = strchr (begin, '/');
5333 : 77 : if (end != NULL)
5334 : 52 : s = g_strndup (begin, end - begin);
5335 : : else
5336 : 25 : s = g_strdup (begin);
5337 : :
5338 : 77 : if (!g_hash_table_contains (set, s))
5339 : 31 : g_hash_table_add (set, s);
5340 : : else
5341 : 46 : g_free (s);
5342 : : }
5343 : 583 : }
5344 : :
5345 : : /* TODO: we want a nicer public interface for this */
5346 : : /* called in any thread with connection's lock held */
5347 : : static gchar **
5348 : 68 : g_dbus_connection_list_registered_unlocked (GDBusConnection *connection,
5349 : : const gchar *path)
5350 : : {
5351 : : GPtrArray *p;
5352 : : gchar **ret;
5353 : : GHashTableIter hash_iter;
5354 : : const gchar *object_path;
5355 : : gsize path_len;
5356 : : GHashTable *set;
5357 : :
5358 : 68 : CONNECTION_ENSURE_LOCK (connection);
5359 : :
5360 : 68 : path_len = strlen (path);
5361 : 68 : if (path_len > 1)
5362 : 66 : path_len++;
5363 : :
5364 : 68 : set = g_hash_table_new (g_str_hash, g_str_equal);
5365 : :
5366 : 68 : g_hash_table_iter_init (&hash_iter, connection->map_object_path_to_eo);
5367 : 586 : while (g_hash_table_iter_next (&hash_iter, (gpointer) &object_path, NULL))
5368 : 518 : maybe_add_path (path, path_len, object_path, set);
5369 : :
5370 : 68 : g_hash_table_iter_init (&hash_iter, connection->map_object_path_to_es);
5371 : 133 : while (g_hash_table_iter_next (&hash_iter, (gpointer) &object_path, NULL))
5372 : 65 : maybe_add_path (path, path_len, object_path, set);
5373 : :
5374 : 68 : p = g_hash_table_steal_all_keys (set);
5375 : 68 : g_hash_table_unref (set);
5376 : :
5377 : 68 : g_ptr_array_add (p, NULL);
5378 : 68 : ret = (gchar **) g_ptr_array_free (p, FALSE);
5379 : 68 : return ret;
5380 : : }
5381 : :
5382 : : /* called in any thread with connection's lock not held */
5383 : : static gchar **
5384 : 20 : g_dbus_connection_list_registered (GDBusConnection *connection,
5385 : : const gchar *path)
5386 : : {
5387 : : gchar **ret;
5388 : 20 : CONNECTION_LOCK (connection);
5389 : 20 : ret = g_dbus_connection_list_registered_unlocked (connection, path);
5390 : 20 : CONNECTION_UNLOCK (connection);
5391 : 20 : return ret;
5392 : : }
5393 : :
5394 : : /* called in GDBusWorker thread with connection's lock held */
5395 : : static gboolean
5396 : 34 : handle_introspect (GDBusConnection *connection,
5397 : : ExportedObject *eo,
5398 : : GDBusMessage *message)
5399 : : {
5400 : : guint n;
5401 : : GString *s;
5402 : : GDBusMessage *reply;
5403 : : GHashTableIter hash_iter;
5404 : : ExportedInterface *ei;
5405 : : gchar **registered;
5406 : :
5407 : : /* first the header with the standard interfaces */
5408 : 34 : s = g_string_sized_new (sizeof (introspect_header) +
5409 : : sizeof (introspect_properties_interface) +
5410 : : sizeof (introspect_introspectable_interface) +
5411 : : sizeof (introspect_tail));
5412 : 34 : introspect_append_header (s);
5413 : 34 : if (!g_hash_table_lookup (eo->map_if_name_to_ei,
5414 : : DBUS_INTERFACE_PROPERTIES))
5415 : : g_string_append (s, introspect_properties_interface);
5416 : :
5417 : 34 : if (!g_hash_table_lookup (eo->map_if_name_to_ei,
5418 : : DBUS_INTERFACE_INTROSPECTABLE))
5419 : : g_string_append (s, introspect_introspectable_interface);
5420 : :
5421 : : /* then include the registered interfaces */
5422 : 34 : g_hash_table_iter_init (&hash_iter, eo->map_if_name_to_ei);
5423 : 79 : while (g_hash_table_iter_next (&hash_iter, NULL, (gpointer) &ei))
5424 : 45 : g_dbus_interface_info_generate_xml (ei->interface_info, 2, s);
5425 : :
5426 : : /* finally include nodes registered below us */
5427 : 34 : registered = g_dbus_connection_list_registered_unlocked (connection, eo->object_path);
5428 : 54 : for (n = 0; registered != NULL && registered[n] != NULL; n++)
5429 : 20 : g_string_append_printf (s, " <node name=\"%s\"/>\n", registered[n]);
5430 : 34 : g_strfreev (registered);
5431 : : g_string_append (s, introspect_tail);
5432 : :
5433 : 34 : reply = g_dbus_message_new_method_reply (message);
5434 : 34 : g_dbus_message_set_body (reply, g_variant_new ("(s)", s->str));
5435 : 34 : g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
5436 : 34 : g_object_unref (reply);
5437 : 34 : g_string_free (s, TRUE);
5438 : :
5439 : 34 : return TRUE;
5440 : : }
5441 : :
5442 : : /* called in thread where object was registered - no locks held */
5443 : : static gboolean
5444 : 1027 : call_in_idle_cb (gpointer user_data)
5445 : : {
5446 : 1027 : GDBusMethodInvocation *invocation = G_DBUS_METHOD_INVOCATION (user_data);
5447 : : GDBusInterfaceVTable *vtable;
5448 : : guint registration_id;
5449 : : guint subtree_registration_id;
5450 : 1027 : ExportedInterface *ei = NULL;
5451 : 1027 : ExportedSubtree *es = NULL;
5452 : :
5453 : 1027 : registration_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (invocation), "g-dbus-registration-id"));
5454 : 1027 : subtree_registration_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (invocation), "g-dbus-subtree-registration-id"));
5455 : :
5456 : 1027 : if (has_object_been_unregistered (g_dbus_method_invocation_get_connection (invocation),
5457 : : registration_id,
5458 : : &ei,
5459 : : subtree_registration_id,
5460 : : &es))
5461 : : {
5462 : : GDBusMessage *reply;
5463 : 250 : reply = g_dbus_message_new_method_error (g_dbus_method_invocation_get_message (invocation),
5464 : : DBUS_ERROR_UNKNOWN_METHOD,
5465 : : _("No such interface “%s” on object at path %s"),
5466 : : g_dbus_method_invocation_get_interface_name (invocation),
5467 : : g_dbus_method_invocation_get_object_path (invocation));
5468 : 250 : g_dbus_connection_send_message (g_dbus_method_invocation_get_connection (invocation), reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
5469 : 250 : g_object_unref (reply);
5470 : 250 : goto out;
5471 : : }
5472 : :
5473 : 777 : vtable = g_object_get_data (G_OBJECT (invocation), "g-dbus-interface-vtable");
5474 : 777 : g_assert (vtable != NULL && vtable->method_call != NULL);
5475 : :
5476 : 1554 : vtable->method_call (g_dbus_method_invocation_get_connection (invocation),
5477 : : g_dbus_method_invocation_get_sender (invocation),
5478 : : g_dbus_method_invocation_get_object_path (invocation),
5479 : : g_dbus_method_invocation_get_interface_name (invocation),
5480 : : g_dbus_method_invocation_get_method_name (invocation),
5481 : : g_dbus_method_invocation_get_parameters (invocation),
5482 : 777 : g_object_ref (invocation),
5483 : : g_dbus_method_invocation_get_user_data (invocation));
5484 : :
5485 : 1027 : out:
5486 : 1027 : g_clear_pointer (&ei, exported_interface_unref);
5487 : 1027 : g_clear_pointer (&es, exported_subtree_unref);
5488 : :
5489 : 1027 : return FALSE;
5490 : : }
5491 : :
5492 : : /* called in GDBusWorker thread with connection's lock held */
5493 : : static void
5494 : 1027 : schedule_method_call (GDBusConnection *connection,
5495 : : GDBusMessage *message,
5496 : : guint registration_id,
5497 : : guint subtree_registration_id,
5498 : : const GDBusInterfaceInfo *interface_info,
5499 : : const GDBusMethodInfo *method_info,
5500 : : const GDBusPropertyInfo *property_info,
5501 : : GVariant *parameters,
5502 : : const GDBusInterfaceVTable *vtable,
5503 : : GMainContext *main_context,
5504 : : gpointer user_data)
5505 : : {
5506 : : GDBusMethodInvocation *invocation;
5507 : : GSource *idle_source;
5508 : :
5509 : 1027 : invocation = _g_dbus_method_invocation_new (g_dbus_message_get_sender (message),
5510 : : g_dbus_message_get_path (message),
5511 : : g_dbus_message_get_interface (message),
5512 : : g_dbus_message_get_member (message),
5513 : : method_info,
5514 : : property_info,
5515 : : connection,
5516 : : message,
5517 : : parameters,
5518 : : user_data);
5519 : :
5520 : : /* TODO: would be nicer with a real MethodData like we already
5521 : : * have PropertyData and PropertyGetAllData... */
5522 : 1027 : g_object_set_data (G_OBJECT (invocation), "g-dbus-interface-vtable", (gpointer) vtable);
5523 : 1027 : g_object_set_data (G_OBJECT (invocation), "g-dbus-registration-id", GUINT_TO_POINTER (registration_id));
5524 : 1027 : g_object_set_data (G_OBJECT (invocation), "g-dbus-subtree-registration-id", GUINT_TO_POINTER (subtree_registration_id));
5525 : :
5526 : 1027 : idle_source = g_idle_source_new ();
5527 : 1027 : g_source_set_priority (idle_source, G_PRIORITY_DEFAULT);
5528 : 1027 : g_source_set_callback (idle_source,
5529 : : call_in_idle_cb,
5530 : : g_steal_pointer (&invocation),
5531 : : g_object_unref);
5532 : 1027 : g_source_set_static_name (idle_source, "[gio, " __FILE__ "] call_in_idle_cb");
5533 : 1027 : g_source_attach (idle_source, main_context);
5534 : 1027 : g_source_unref (idle_source);
5535 : 1027 : }
5536 : :
5537 : : /* called in GDBusWorker thread with connection's lock held */
5538 : : static gboolean
5539 : 1020 : validate_and_maybe_schedule_method_call (GDBusConnection *connection,
5540 : : GDBusMessage *message,
5541 : : guint registration_id,
5542 : : guint subtree_registration_id,
5543 : : GDBusInterfaceInfo *interface_info,
5544 : : const GDBusInterfaceVTable *vtable,
5545 : : GMainContext *main_context,
5546 : : gpointer user_data)
5547 : : {
5548 : : GDBusMethodInfo *method_info;
5549 : : GDBusMessage *reply;
5550 : : GVariant *parameters;
5551 : : gboolean handled;
5552 : : GVariantType *in_type;
5553 : :
5554 : 1020 : handled = FALSE;
5555 : :
5556 : : /* TODO: the cost of this is O(n) - it might be worth caching the result */
5557 : 1020 : method_info = g_dbus_interface_info_lookup_method (interface_info, g_dbus_message_get_member (message));
5558 : :
5559 : : /* if the method doesn't exist, return the DBUS_ERROR_UNKNOWN_METHOD
5560 : : * error to the caller
5561 : : */
5562 : 1020 : if (method_info == NULL)
5563 : : {
5564 : 4 : reply = g_dbus_message_new_method_error (message,
5565 : : DBUS_ERROR_UNKNOWN_METHOD,
5566 : : _("No such method “%s”"),
5567 : : g_dbus_message_get_member (message));
5568 : 4 : g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
5569 : 4 : g_object_unref (reply);
5570 : 4 : handled = TRUE;
5571 : 4 : goto out;
5572 : : }
5573 : :
5574 : 1016 : parameters = g_dbus_message_get_body (message);
5575 : 1016 : if (parameters == NULL)
5576 : : {
5577 : 80 : parameters = g_variant_new ("()");
5578 : 80 : g_variant_ref_sink (parameters);
5579 : : }
5580 : : else
5581 : : {
5582 : 936 : g_variant_ref (parameters);
5583 : : }
5584 : :
5585 : : /* Check that the incoming args are of the right type - if they are not, return
5586 : : * the DBUS_ERROR_INVALID_ARGS error to the caller
5587 : : */
5588 : 1016 : in_type = _g_dbus_compute_complete_signature (method_info->in_args);
5589 : 1016 : if (!g_variant_is_of_type (parameters, in_type))
5590 : : {
5591 : : gchar *type_string;
5592 : :
5593 : 4 : type_string = g_variant_type_dup_string (in_type);
5594 : :
5595 : 4 : reply = g_dbus_message_new_method_error (message,
5596 : : DBUS_ERROR_INVALID_ARGS,
5597 : : _("Type of message, “%s”, does not match expected type “%s”"),
5598 : : g_variant_get_type_string (parameters),
5599 : : type_string);
5600 : 4 : g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
5601 : 4 : g_variant_type_free (in_type);
5602 : 4 : g_variant_unref (parameters);
5603 : 4 : g_object_unref (reply);
5604 : 4 : g_free (type_string);
5605 : 4 : handled = TRUE;
5606 : 4 : goto out;
5607 : : }
5608 : 1012 : g_variant_type_free (in_type);
5609 : :
5610 : : /* schedule the call in idle */
5611 : 1012 : schedule_method_call (connection, message, registration_id, subtree_registration_id,
5612 : : interface_info, method_info, NULL, parameters,
5613 : : vtable, main_context, user_data);
5614 : 1012 : g_variant_unref (parameters);
5615 : 1012 : handled = TRUE;
5616 : :
5617 : 1020 : out:
5618 : 1020 : return handled;
5619 : : }
5620 : :
5621 : : /* ---------------------------------------------------------------------------------------------------- */
5622 : :
5623 : : /* called in GDBusWorker thread with connection's lock held */
5624 : : static gboolean
5625 : 917 : obj_message_func (GDBusConnection *connection,
5626 : : ExportedObject *eo,
5627 : : GDBusMessage *message,
5628 : : gboolean *object_found)
5629 : : {
5630 : : const gchar *interface_name;
5631 : : const gchar *member;
5632 : : const gchar *signature;
5633 : : gboolean handled;
5634 : :
5635 : 917 : handled = FALSE;
5636 : :
5637 : 917 : interface_name = g_dbus_message_get_interface (message);
5638 : 917 : member = g_dbus_message_get_member (message);
5639 : 917 : signature = g_dbus_message_get_signature (message);
5640 : :
5641 : : /* see if we have an interface for handling this call */
5642 : 917 : if (interface_name != NULL)
5643 : : {
5644 : : ExportedInterface *ei;
5645 : 917 : ei = g_hash_table_lookup (eo->map_if_name_to_ei, interface_name);
5646 : 917 : if (ei != NULL)
5647 : : {
5648 : : /* we do - invoke the handler in idle in the right thread */
5649 : :
5650 : : /* handle no vtable or handler being present */
5651 : 748 : if (ei->vtable == NULL || ei->vtable->method_call == NULL)
5652 : 0 : goto out;
5653 : :
5654 : 748 : handled = validate_and_maybe_schedule_method_call (connection,
5655 : : message,
5656 : : ei->id,
5657 : : 0,
5658 : : ei->interface_info,
5659 : 748 : ei->vtable,
5660 : : ei->context,
5661 : : ei->user_data);
5662 : 748 : goto out;
5663 : : }
5664 : : else
5665 : : {
5666 : 169 : *object_found = TRUE;
5667 : : }
5668 : : }
5669 : :
5670 : 203 : if (g_strcmp0 (interface_name, DBUS_INTERFACE_INTROSPECTABLE) == 0 &&
5671 : 68 : g_strcmp0 (member, "Introspect") == 0 &&
5672 : 34 : g_strcmp0 (signature, "") == 0)
5673 : : {
5674 : 34 : handled = handle_introspect (connection, eo, message);
5675 : 34 : goto out;
5676 : : }
5677 : 261 : else if (g_strcmp0 (interface_name, DBUS_INTERFACE_PROPERTIES) == 0 &&
5678 : 149 : g_strcmp0 (member, "Get") == 0 &&
5679 : 23 : g_strcmp0 (signature, "ss") == 0)
5680 : : {
5681 : 22 : handled = handle_getset_property (connection, eo, message, TRUE);
5682 : 22 : goto out;
5683 : : }
5684 : 217 : else if (g_strcmp0 (interface_name, DBUS_INTERFACE_PROPERTIES) == 0 &&
5685 : 159 : g_strcmp0 (member, "Set") == 0 &&
5686 : 55 : g_strcmp0 (signature, "ssv") == 0)
5687 : : {
5688 : 54 : handled = handle_getset_property (connection, eo, message, FALSE);
5689 : 54 : goto out;
5690 : : }
5691 : 109 : else if (g_strcmp0 (interface_name, DBUS_INTERFACE_PROPERTIES) == 0 &&
5692 : 97 : g_strcmp0 (member, "GetAll") == 0 &&
5693 : 47 : g_strcmp0 (signature, "s") == 0)
5694 : : {
5695 : 46 : handled = handle_get_all_properties (connection, eo, message);
5696 : 46 : goto out;
5697 : : }
5698 : :
5699 : 13 : out:
5700 : 917 : return handled;
5701 : : }
5702 : :
5703 : : /**
5704 : : * g_dbus_connection_register_object:
5705 : : * @connection: a #GDBusConnection
5706 : : * @object_path: the object path to register at
5707 : : * @interface_info: introspection data for the interface
5708 : : * @vtable: (nullable): a #GDBusInterfaceVTable to call into or %NULL
5709 : : * @user_data: (nullable): data to pass to functions in @vtable
5710 : : * @user_data_free_func: function to call when the object path is unregistered
5711 : : * @error: return location for error or %NULL
5712 : : *
5713 : : * Registers callbacks for exported objects at @object_path with the
5714 : : * D-Bus interface that is described in @interface_info.
5715 : : *
5716 : : * Calls to functions in @vtable (and @user_data_free_func) will happen
5717 : : * in the thread-default main context
5718 : : * (see [method@GLib.MainContext.push_thread_default])
5719 : : * of the thread you are calling this method from.
5720 : : *
5721 : : * Note that all #GVariant values passed to functions in @vtable will match
5722 : : * the signature given in @interface_info - if a remote caller passes
5723 : : * incorrect values, the `org.freedesktop.DBus.Error.InvalidArgs`
5724 : : * is returned to the remote caller.
5725 : : *
5726 : : * Additionally, if the remote caller attempts to invoke methods or
5727 : : * access properties not mentioned in @interface_info the
5728 : : * `org.freedesktop.DBus.Error.UnknownMethod` resp.
5729 : : * `org.freedesktop.DBus.Error.InvalidArgs` errors
5730 : : * are returned to the caller.
5731 : : *
5732 : : * It is considered a programming error if the
5733 : : * #GDBusInterfaceGetPropertyFunc function in @vtable returns a
5734 : : * #GVariant of incorrect type.
5735 : : *
5736 : : * If an existing callback is already registered at @object_path and
5737 : : * @interface_name, then @error is set to %G_IO_ERROR_EXISTS.
5738 : : *
5739 : : * GDBus automatically implements the standard D-Bus interfaces
5740 : : * org.freedesktop.DBus.Properties, org.freedesktop.DBus.Introspectable
5741 : : * and org.freedesktop.Peer, so you don't have to implement those for the
5742 : : * objects you export. You can implement org.freedesktop.DBus.Properties
5743 : : * yourself, e.g. to handle getting and setting of properties asynchronously.
5744 : : *
5745 : : * Note that the reference count on @interface_info will be
5746 : : * incremented by 1 (unless allocated statically, e.g. if the
5747 : : * reference count is -1, see g_dbus_interface_info_ref()) for as long
5748 : : * as the object is exported. Also note that @vtable will be copied.
5749 : : *
5750 : : * See this [server][class@Gio.DBusConnection#an-example-d-bus-server]
5751 : : * for an example of how to use this method.
5752 : : *
5753 : : * Returns: 0 if @error is set, otherwise a registration id (never 0)
5754 : : * that can be used with g_dbus_connection_unregister_object()
5755 : : *
5756 : : * Since: 2.26
5757 : : */
5758 : : guint
5759 : 200624 : g_dbus_connection_register_object (GDBusConnection *connection,
5760 : : const gchar *object_path,
5761 : : GDBusInterfaceInfo *interface_info,
5762 : : const GDBusInterfaceVTable *vtable,
5763 : : gpointer user_data,
5764 : : GDestroyNotify user_data_free_func,
5765 : : GError **error)
5766 : : {
5767 : : ExportedObject *eo;
5768 : : ExportedInterface *ei;
5769 : : guint ret;
5770 : :
5771 : 200624 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
5772 : 200624 : g_return_val_if_fail (object_path != NULL && g_variant_is_object_path (object_path), 0);
5773 : 200624 : g_return_val_if_fail (interface_info != NULL, 0);
5774 : 200624 : g_return_val_if_fail (g_dbus_is_interface_name (interface_info->name), 0);
5775 : 200624 : g_return_val_if_fail (error == NULL || *error == NULL, 0);
5776 : 200624 : g_return_val_if_fail (check_initialized (connection), 0);
5777 : :
5778 : 200624 : ret = 0;
5779 : :
5780 : 200624 : CONNECTION_LOCK (connection);
5781 : :
5782 : 200624 : eo = g_hash_table_lookup (connection->map_object_path_to_eo, object_path);
5783 : 200624 : if (eo == NULL)
5784 : : {
5785 : 200529 : eo = g_new0 (ExportedObject, 1);
5786 : 200529 : eo->object_path = g_strdup (object_path);
5787 : 200529 : eo->connection = connection;
5788 : 200529 : eo->map_if_name_to_ei = g_hash_table_new_full (g_str_hash,
5789 : : g_str_equal,
5790 : : NULL,
5791 : : (GDestroyNotify) exported_interface_unref);
5792 : 200529 : g_hash_table_insert (connection->map_object_path_to_eo, eo->object_path, eo);
5793 : : }
5794 : :
5795 : 200624 : ei = g_hash_table_lookup (eo->map_if_name_to_ei, interface_info->name);
5796 : 200624 : if (ei != NULL)
5797 : : {
5798 : 4 : g_set_error (error,
5799 : : G_IO_ERROR,
5800 : : G_IO_ERROR_EXISTS,
5801 : : _("An object is already exported for the interface %s at %s"),
5802 : : interface_info->name,
5803 : : object_path);
5804 : 4 : goto out;
5805 : : }
5806 : :
5807 : 200620 : ei = g_new0 (ExportedInterface, 1);
5808 : 200620 : ei->refcount = 1;
5809 : 200620 : ei->id = (guint) g_atomic_int_add (&_global_registration_id, 1); /* TODO: overflow etc. */
5810 : 200620 : ei->eo = eo;
5811 : 200620 : ei->user_data = user_data;
5812 : 200620 : ei->user_data_free_func = user_data_free_func;
5813 : 200620 : ei->vtable = _g_dbus_interface_vtable_copy (vtable);
5814 : 200620 : ei->interface_info = g_dbus_interface_info_ref (interface_info);
5815 : 200620 : g_dbus_interface_info_cache_build (ei->interface_info);
5816 : 200620 : ei->interface_name = g_strdup (interface_info->name);
5817 : 200620 : ei->context = g_main_context_ref_thread_default ();
5818 : :
5819 : 200620 : g_hash_table_insert (eo->map_if_name_to_ei,
5820 : 200620 : (gpointer) ei->interface_name,
5821 : : ei);
5822 : 200620 : g_hash_table_insert (connection->map_id_to_ei,
5823 : 200620 : GUINT_TO_POINTER (ei->id),
5824 : : ei);
5825 : :
5826 : 200620 : ret = ei->id;
5827 : :
5828 : 200624 : out:
5829 : 200624 : CONNECTION_UNLOCK (connection);
5830 : :
5831 : 200624 : if (ret == 0 && user_data_free_func != NULL)
5832 : 3 : user_data_free_func (user_data);
5833 : :
5834 : 200624 : return ret;
5835 : : }
5836 : :
5837 : : /**
5838 : : * g_dbus_connection_unregister_object:
5839 : : * @connection: a #GDBusConnection
5840 : : * @registration_id: a registration id obtained from
5841 : : * g_dbus_connection_register_object()
5842 : : *
5843 : : * Unregisters an object.
5844 : : *
5845 : : * Returns: %TRUE if the object was unregistered, %FALSE otherwise
5846 : : *
5847 : : * Since: 2.26
5848 : : */
5849 : : gboolean
5850 : 200601 : g_dbus_connection_unregister_object (GDBusConnection *connection,
5851 : : guint registration_id)
5852 : : {
5853 : : ExportedInterface *ei;
5854 : : ExportedObject *eo;
5855 : : gboolean ret;
5856 : :
5857 : 200601 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
5858 : 200601 : g_return_val_if_fail (check_initialized (connection), FALSE);
5859 : :
5860 : 200601 : ret = FALSE;
5861 : :
5862 : 200601 : CONNECTION_LOCK (connection);
5863 : :
5864 : 200601 : ei = g_hash_table_lookup (connection->map_id_to_ei,
5865 : 200601 : GUINT_TO_POINTER (registration_id));
5866 : 200601 : if (ei == NULL)
5867 : 0 : goto out;
5868 : :
5869 : 200601 : eo = ei->eo;
5870 : :
5871 : 200601 : g_warn_if_fail (g_hash_table_remove (connection->map_id_to_ei, GUINT_TO_POINTER (ei->id)));
5872 : 200601 : g_warn_if_fail (g_hash_table_remove (eo->map_if_name_to_ei, ei->interface_name));
5873 : : /* unregister object path if we have no more exported interfaces */
5874 : 200601 : if (g_hash_table_size (eo->map_if_name_to_ei) == 0)
5875 : 200510 : g_warn_if_fail (g_hash_table_remove (connection->map_object_path_to_eo,
5876 : : eo->object_path));
5877 : :
5878 : 200601 : ret = TRUE;
5879 : :
5880 : 200601 : out:
5881 : 200601 : CONNECTION_UNLOCK (connection);
5882 : :
5883 : 200601 : return ret;
5884 : : }
5885 : :
5886 : : typedef struct {
5887 : : GClosure *method_call_closure;
5888 : : GClosure *get_property_closure;
5889 : : GClosure *set_property_closure;
5890 : : } RegisterObjectData;
5891 : :
5892 : : static RegisterObjectData *
5893 : 2 : register_object_data_new (GClosure *method_call_closure,
5894 : : GClosure *get_property_closure,
5895 : : GClosure *set_property_closure)
5896 : : {
5897 : : RegisterObjectData *data;
5898 : :
5899 : 2 : data = g_new0 (RegisterObjectData, 1);
5900 : :
5901 : 2 : if (method_call_closure != NULL)
5902 : : {
5903 : 2 : data->method_call_closure = g_closure_ref (method_call_closure);
5904 : 2 : g_closure_sink (method_call_closure);
5905 : 2 : if (G_CLOSURE_NEEDS_MARSHAL (method_call_closure))
5906 : 2 : g_closure_set_marshal (method_call_closure, g_cclosure_marshal_generic);
5907 : : }
5908 : :
5909 : 2 : if (get_property_closure != NULL)
5910 : : {
5911 : 2 : data->get_property_closure = g_closure_ref (get_property_closure);
5912 : 2 : g_closure_sink (get_property_closure);
5913 : 2 : if (G_CLOSURE_NEEDS_MARSHAL (get_property_closure))
5914 : 2 : g_closure_set_marshal (get_property_closure, g_cclosure_marshal_generic);
5915 : : }
5916 : :
5917 : 2 : if (set_property_closure != NULL)
5918 : : {
5919 : 2 : data->set_property_closure = g_closure_ref (set_property_closure);
5920 : 2 : g_closure_sink (set_property_closure);
5921 : 2 : if (G_CLOSURE_NEEDS_MARSHAL (set_property_closure))
5922 : 2 : g_closure_set_marshal (set_property_closure, g_cclosure_marshal_generic);
5923 : : }
5924 : :
5925 : 2 : return data;
5926 : : }
5927 : :
5928 : : static void
5929 : 2 : register_object_free_func (gpointer user_data)
5930 : : {
5931 : 2 : RegisterObjectData *data = user_data;
5932 : :
5933 : 2 : g_clear_pointer (&data->method_call_closure, g_closure_unref);
5934 : 2 : g_clear_pointer (&data->get_property_closure, g_closure_unref);
5935 : 2 : g_clear_pointer (&data->set_property_closure, g_closure_unref);
5936 : :
5937 : 2 : g_free (data);
5938 : 2 : }
5939 : :
5940 : : static void
5941 : 2 : register_with_closures_on_method_call (GDBusConnection *connection,
5942 : : const gchar *sender,
5943 : : const gchar *object_path,
5944 : : const gchar *interface_name,
5945 : : const gchar *method_name,
5946 : : GVariant *parameters,
5947 : : GDBusMethodInvocation *invocation,
5948 : : gpointer user_data)
5949 : : {
5950 : 2 : RegisterObjectData *data = user_data;
5951 : 2 : GValue params[] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
5952 : :
5953 : 2 : g_value_init (¶ms[0], G_TYPE_DBUS_CONNECTION);
5954 : 2 : g_value_set_object (¶ms[0], connection);
5955 : :
5956 : 2 : g_value_init (¶ms[1], G_TYPE_STRING);
5957 : 2 : g_value_set_string (¶ms[1], sender);
5958 : :
5959 : 2 : g_value_init (¶ms[2], G_TYPE_STRING);
5960 : 2 : g_value_set_string (¶ms[2], object_path);
5961 : :
5962 : 2 : g_value_init (¶ms[3], G_TYPE_STRING);
5963 : 2 : g_value_set_string (¶ms[3], interface_name);
5964 : :
5965 : 2 : g_value_init (¶ms[4], G_TYPE_STRING);
5966 : 2 : g_value_set_string (¶ms[4], method_name);
5967 : :
5968 : 2 : g_value_init (¶ms[5], G_TYPE_VARIANT);
5969 : 2 : g_value_set_variant (¶ms[5], parameters);
5970 : :
5971 : 2 : g_value_init (¶ms[6], G_TYPE_DBUS_METHOD_INVOCATION);
5972 : : /* NOTE: This is deliberately *not* g_value_take_object(). A reference to
5973 : : * `invocation` is transferred in to this function, and it needs to be
5974 : : * transferred onwards to the `g_dbus_method_invocation_return_*()` method
5975 : : * call which must eventually happen (either in the closure function, or in
5976 : : * a delayed consequence from it). Changing this will break API. */
5977 : 2 : g_value_set_object (¶ms[6], invocation);
5978 : :
5979 : 2 : g_closure_invoke (data->method_call_closure, NULL, G_N_ELEMENTS (params), params, NULL);
5980 : :
5981 : 2 : g_value_unset (params + 0);
5982 : 2 : g_value_unset (params + 1);
5983 : 2 : g_value_unset (params + 2);
5984 : 2 : g_value_unset (params + 3);
5985 : 2 : g_value_unset (params + 4);
5986 : 2 : g_value_unset (params + 5);
5987 : 2 : g_value_unset (params + 6);
5988 : 2 : }
5989 : :
5990 : : static GVariant *
5991 : 6 : register_with_closures_on_get_property (GDBusConnection *connection,
5992 : : const gchar *sender,
5993 : : const gchar *object_path,
5994 : : const gchar *interface_name,
5995 : : const gchar *property_name,
5996 : : GError **error,
5997 : : gpointer user_data)
5998 : : {
5999 : 6 : RegisterObjectData *data = user_data;
6000 : 6 : GValue params[] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
6001 : 6 : GValue result_value = G_VALUE_INIT;
6002 : : GVariant *result;
6003 : :
6004 : 6 : g_value_init (¶ms[0], G_TYPE_DBUS_CONNECTION);
6005 : 6 : g_value_set_object (¶ms[0], connection);
6006 : :
6007 : 6 : g_value_init (¶ms[1], G_TYPE_STRING);
6008 : 6 : g_value_set_string (¶ms[1], sender);
6009 : :
6010 : 6 : g_value_init (¶ms[2], G_TYPE_STRING);
6011 : 6 : g_value_set_string (¶ms[2], object_path);
6012 : :
6013 : 6 : g_value_init (¶ms[3], G_TYPE_STRING);
6014 : 6 : g_value_set_string (¶ms[3], interface_name);
6015 : :
6016 : 6 : g_value_init (¶ms[4], G_TYPE_STRING);
6017 : 6 : g_value_set_string (¶ms[4], property_name);
6018 : :
6019 : 6 : g_value_init (&result_value, G_TYPE_VARIANT);
6020 : :
6021 : 6 : g_closure_invoke (data->get_property_closure, &result_value, G_N_ELEMENTS (params), params, NULL);
6022 : :
6023 : 6 : result = g_value_get_variant (&result_value);
6024 : 6 : if (result)
6025 : 6 : g_variant_ref (result);
6026 : :
6027 : 6 : g_value_unset (params + 0);
6028 : 6 : g_value_unset (params + 1);
6029 : 6 : g_value_unset (params + 2);
6030 : 6 : g_value_unset (params + 3);
6031 : 6 : g_value_unset (params + 4);
6032 : 6 : g_value_unset (&result_value);
6033 : :
6034 : 6 : if (!result)
6035 : 0 : g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
6036 : : _("Unable to retrieve property %s.%s"),
6037 : : interface_name, property_name);
6038 : :
6039 : 6 : return result;
6040 : : }
6041 : :
6042 : : static gboolean
6043 : 2 : register_with_closures_on_set_property (GDBusConnection *connection,
6044 : : const gchar *sender,
6045 : : const gchar *object_path,
6046 : : const gchar *interface_name,
6047 : : const gchar *property_name,
6048 : : GVariant *value,
6049 : : GError **error,
6050 : : gpointer user_data)
6051 : : {
6052 : 2 : RegisterObjectData *data = user_data;
6053 : 2 : GValue params[] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
6054 : 2 : GValue result_value = G_VALUE_INIT;
6055 : : gboolean result;
6056 : :
6057 : 2 : g_value_init (¶ms[0], G_TYPE_DBUS_CONNECTION);
6058 : 2 : g_value_set_object (¶ms[0], connection);
6059 : :
6060 : 2 : g_value_init (¶ms[1], G_TYPE_STRING);
6061 : 2 : g_value_set_string (¶ms[1], sender);
6062 : :
6063 : 2 : g_value_init (¶ms[2], G_TYPE_STRING);
6064 : 2 : g_value_set_string (¶ms[2], object_path);
6065 : :
6066 : 2 : g_value_init (¶ms[3], G_TYPE_STRING);
6067 : 2 : g_value_set_string (¶ms[3], interface_name);
6068 : :
6069 : 2 : g_value_init (¶ms[4], G_TYPE_STRING);
6070 : 2 : g_value_set_string (¶ms[4], property_name);
6071 : :
6072 : 2 : g_value_init (¶ms[5], G_TYPE_VARIANT);
6073 : 2 : g_value_set_variant (¶ms[5], value);
6074 : :
6075 : 2 : g_value_init (&result_value, G_TYPE_BOOLEAN);
6076 : :
6077 : 2 : g_closure_invoke (data->set_property_closure, &result_value, G_N_ELEMENTS (params), params, NULL);
6078 : :
6079 : 2 : result = g_value_get_boolean (&result_value);
6080 : :
6081 : 2 : g_value_unset (params + 0);
6082 : 2 : g_value_unset (params + 1);
6083 : 2 : g_value_unset (params + 2);
6084 : 2 : g_value_unset (params + 3);
6085 : 2 : g_value_unset (params + 4);
6086 : 2 : g_value_unset (params + 5);
6087 : 2 : g_value_unset (&result_value);
6088 : :
6089 : 2 : if (!result)
6090 : 2 : g_set_error (error,
6091 : : G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
6092 : : _("Unable to set property %s.%s"),
6093 : : interface_name, property_name);
6094 : :
6095 : 2 : return result;
6096 : : }
6097 : :
6098 : : /**
6099 : : * g_dbus_connection_register_object_with_closures: (rename-to g_dbus_connection_register_object)
6100 : : * @connection: A #GDBusConnection.
6101 : : * @object_path: The object path to register at.
6102 : : * @interface_info: Introspection data for the interface.
6103 : : * @method_call_closure: (nullable): #GClosure for handling incoming method calls.
6104 : : * @get_property_closure: (nullable): #GClosure for getting a property.
6105 : : * @set_property_closure: (nullable): #GClosure for setting a property.
6106 : : * @error: Return location for error or %NULL.
6107 : : *
6108 : : * Version of g_dbus_connection_register_object() using closures instead of a
6109 : : * #GDBusInterfaceVTable for easier binding in other languages.
6110 : : *
6111 : : * Note that the reference counting semantics of the function wrapped by
6112 : : * @method_call_closure are the same as those of
6113 : : * [callback@Gio.DBusInterfaceMethodCallFunc]: ownership of a reference to the
6114 : : * [class@Gio.DBusMethodInvocation] is transferred to the function.
6115 : : *
6116 : : * Returns: 0 if @error is set, otherwise a registration ID (never 0)
6117 : : * that can be used with g_dbus_connection_unregister_object() .
6118 : : *
6119 : : * Since: 2.46
6120 : : * Deprecated: 2.84: Deprecated in favour of
6121 : : * [method@Gio.DBusConnection.register_object_with_closures2], which has more
6122 : : * binding-friendly reference counting semantics.
6123 : : */
6124 : : guint
6125 : 1 : g_dbus_connection_register_object_with_closures (GDBusConnection *connection,
6126 : : const gchar *object_path,
6127 : : GDBusInterfaceInfo *interface_info,
6128 : : GClosure *method_call_closure,
6129 : : GClosure *get_property_closure,
6130 : : GClosure *set_property_closure,
6131 : : GError **error)
6132 : : {
6133 : : RegisterObjectData *data;
6134 : 4 : GDBusInterfaceVTable vtable =
6135 : : {
6136 : 1 : method_call_closure != NULL ? register_with_closures_on_method_call : NULL,
6137 : 1 : get_property_closure != NULL ? register_with_closures_on_get_property : NULL,
6138 : 1 : set_property_closure != NULL ? register_with_closures_on_set_property : NULL,
6139 : : { 0 }
6140 : : };
6141 : :
6142 : 1 : data = register_object_data_new (method_call_closure, get_property_closure, set_property_closure);
6143 : :
6144 : 1 : return g_dbus_connection_register_object (connection,
6145 : : object_path,
6146 : : interface_info,
6147 : : &vtable,
6148 : : g_steal_pointer (&data),
6149 : : register_object_free_func,
6150 : : error);
6151 : : }
6152 : :
6153 : : static void
6154 : 2 : register_with_closures_on_method_call2 (GDBusConnection *connection,
6155 : : const gchar *sender,
6156 : : const gchar *object_path,
6157 : : const gchar *interface_name,
6158 : : const gchar *method_name,
6159 : : GVariant *parameters,
6160 : : GDBusMethodInvocation *invocation,
6161 : : gpointer user_data)
6162 : : {
6163 : 2 : RegisterObjectData *data = user_data;
6164 : 2 : GValue params[] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
6165 : :
6166 : 2 : g_value_init (¶ms[0], G_TYPE_DBUS_CONNECTION);
6167 : 2 : g_value_set_object (¶ms[0], connection);
6168 : :
6169 : 2 : g_value_init (¶ms[1], G_TYPE_STRING);
6170 : 2 : g_value_set_string (¶ms[1], sender);
6171 : :
6172 : 2 : g_value_init (¶ms[2], G_TYPE_STRING);
6173 : 2 : g_value_set_string (¶ms[2], object_path);
6174 : :
6175 : 2 : g_value_init (¶ms[3], G_TYPE_STRING);
6176 : 2 : g_value_set_string (¶ms[3], interface_name);
6177 : :
6178 : 2 : g_value_init (¶ms[4], G_TYPE_STRING);
6179 : 2 : g_value_set_string (¶ms[4], method_name);
6180 : :
6181 : 2 : g_value_init (¶ms[5], G_TYPE_VARIANT);
6182 : 2 : g_value_set_variant (¶ms[5], parameters);
6183 : :
6184 : 2 : g_value_init (¶ms[6], G_TYPE_DBUS_METHOD_INVOCATION);
6185 : : /* NOTE: This is deliberately *not* g_value_set_object(), in contrast with the
6186 : : * deprecated implementation in register_with_closures_on_method_call().
6187 : : *
6188 : : * A reference to `invocation` is transferred in to this function, but
6189 : : * bindings don’t expect a `GClosure` to provide any (transfer full)
6190 : : * arguments, so consume the reference here. Bindings need to add an
6191 : : * additional reference to the `GDBusMethodInvocation` before calling any
6192 : : * `g_dbus_method_invocation_return_*()` methods on it. They can do this
6193 : : * automatically based on the introspection annotations for those methods. */
6194 : 2 : g_value_take_object (¶ms[6], invocation);
6195 : :
6196 : 2 : g_closure_invoke (data->method_call_closure, NULL, G_N_ELEMENTS (params), params, NULL);
6197 : :
6198 : 2 : g_value_unset (params + 0);
6199 : 2 : g_value_unset (params + 1);
6200 : 2 : g_value_unset (params + 2);
6201 : 2 : g_value_unset (params + 3);
6202 : 2 : g_value_unset (params + 4);
6203 : 2 : g_value_unset (params + 5);
6204 : 2 : g_value_unset (params + 6);
6205 : 2 : }
6206 : :
6207 : : /**
6208 : : * g_dbus_connection_register_object_with_closures2:
6209 : : * @connection: A [class@Gio.DBusConnection].
6210 : : * @object_path: The object path to register at.
6211 : : * @interface_info: Introspection data for the interface.
6212 : : * @method_call_closure: (nullable): [type@GObject.Closure] for handling incoming method calls.
6213 : : * @get_property_closure: (nullable): [type@GObject.Closure] for getting a property.
6214 : : * @set_property_closure: (nullable): [type@GObject.Closure] for setting a property.
6215 : : * @error: Return location for error or `NULL`.
6216 : : *
6217 : : * Version of [method@Gio.DBusConnection.register_object] using closures instead
6218 : : * of a [type@Gio.DBusInterfaceVTable] for easier binding in other languages.
6219 : : *
6220 : : * In contrast to [method@Gio.DBusConnection.register_object] and
6221 : : * [method@Gio.DBusConnection.register_object_with_closures], the reference
6222 : : * counting semantics of the function wrapped by @method_call_closure are *not*
6223 : : * the same as those of [callback@Gio.DBusInterfaceMethodCallFunc]. Ownership of
6224 : : * a reference to the [class@Gio.DBusMethodInvocation] is *not* transferred to
6225 : : * the function. Bindings must ensure that they add a reference to the
6226 : : * [class@Gio.DBusMethodInvocation] before calling any
6227 : : * `g_dbus_method_invocation_return_*()` methods on it. This should be automatic
6228 : : * as a result of the introspection annotations on those methods.
6229 : : *
6230 : : * Returns: `0` if @error is set, otherwise a registration ID (never `0`)
6231 : : * that can be used with [method@Gio.DBusConnection.unregister_object].
6232 : : *
6233 : : * Since: 2.84
6234 : : */
6235 : : guint
6236 : 1 : g_dbus_connection_register_object_with_closures2 (GDBusConnection *connection,
6237 : : const gchar *object_path,
6238 : : GDBusInterfaceInfo *interface_info,
6239 : : GClosure *method_call_closure,
6240 : : GClosure *get_property_closure,
6241 : : GClosure *set_property_closure,
6242 : : GError **error)
6243 : : {
6244 : : RegisterObjectData *data;
6245 : 4 : GDBusInterfaceVTable vtable =
6246 : : {
6247 : 1 : method_call_closure != NULL ? register_with_closures_on_method_call2 : NULL,
6248 : 1 : get_property_closure != NULL ? register_with_closures_on_get_property : NULL,
6249 : 1 : set_property_closure != NULL ? register_with_closures_on_set_property : NULL,
6250 : : { 0 }
6251 : : };
6252 : :
6253 : 1 : data = register_object_data_new (method_call_closure, get_property_closure, set_property_closure);
6254 : :
6255 : 1 : return g_dbus_connection_register_object (connection,
6256 : : object_path,
6257 : : interface_info,
6258 : : &vtable,
6259 : : g_steal_pointer (&data),
6260 : : register_object_free_func,
6261 : : error);
6262 : : }
6263 : :
6264 : : /* ---------------------------------------------------------------------------------------------------- */
6265 : :
6266 : : /**
6267 : : * g_dbus_connection_emit_signal:
6268 : : * @connection: a #GDBusConnection
6269 : : * @destination_bus_name: (nullable): the unique bus name for the destination
6270 : : * for the signal or %NULL to emit to all listeners
6271 : : * @object_path: path of remote object
6272 : : * @interface_name: D-Bus interface to emit a signal on
6273 : : * @signal_name: the name of the signal to emit
6274 : : * @parameters: (nullable): a #GVariant tuple with parameters for the signal
6275 : : * or %NULL if not passing parameters
6276 : : * @error: Return location for error or %NULL
6277 : : *
6278 : : * Emits a signal.
6279 : : *
6280 : : * If the parameters GVariant is floating, it is consumed.
6281 : : *
6282 : : * This can only fail if @parameters is not compatible with the D-Bus protocol
6283 : : * (%G_IO_ERROR_INVALID_ARGUMENT), or if @connection has been closed
6284 : : * (%G_IO_ERROR_CLOSED).
6285 : : *
6286 : : * Returns: %TRUE unless @error is set
6287 : : *
6288 : : * Since: 2.26
6289 : : */
6290 : : gboolean
6291 : 709 : g_dbus_connection_emit_signal (GDBusConnection *connection,
6292 : : const gchar *destination_bus_name,
6293 : : const gchar *object_path,
6294 : : const gchar *interface_name,
6295 : : const gchar *signal_name,
6296 : : GVariant *parameters,
6297 : : GError **error)
6298 : : {
6299 : : GDBusMessage *message;
6300 : : gboolean ret;
6301 : :
6302 : 709 : message = NULL;
6303 : 709 : ret = FALSE;
6304 : :
6305 : 709 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
6306 : 709 : g_return_val_if_fail (destination_bus_name == NULL || g_dbus_is_name (destination_bus_name), FALSE);
6307 : 709 : g_return_val_if_fail (object_path != NULL && g_variant_is_object_path (object_path), FALSE);
6308 : 709 : g_return_val_if_fail (interface_name != NULL && g_dbus_is_interface_name (interface_name), FALSE);
6309 : 709 : g_return_val_if_fail (signal_name != NULL && g_dbus_is_member_name (signal_name), FALSE);
6310 : 709 : g_return_val_if_fail (parameters == NULL || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), FALSE);
6311 : 709 : g_return_val_if_fail (check_initialized (connection), FALSE);
6312 : :
6313 : 709 : if (G_UNLIKELY (_g_dbus_debug_emission ()))
6314 : : {
6315 : 0 : _g_dbus_debug_print_lock ();
6316 : 0 : g_print ("========================================================================\n"
6317 : : "GDBus-debug:Emission:\n"
6318 : : " >>>> SIGNAL EMISSION %s.%s()\n"
6319 : : " on object %s\n"
6320 : : " destination %s\n",
6321 : : interface_name, signal_name,
6322 : : object_path,
6323 : : destination_bus_name != NULL ? destination_bus_name : "(none)");
6324 : 0 : _g_dbus_debug_print_unlock ();
6325 : : }
6326 : :
6327 : 709 : message = g_dbus_message_new_signal (object_path,
6328 : : interface_name,
6329 : : signal_name);
6330 : :
6331 : 709 : if (destination_bus_name != NULL)
6332 : 27 : g_dbus_message_set_header (message,
6333 : : G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION,
6334 : : g_variant_new_string (destination_bus_name));
6335 : :
6336 : 709 : if (parameters != NULL)
6337 : 555 : g_dbus_message_set_body (message, parameters);
6338 : :
6339 : 709 : ret = g_dbus_connection_send_message (connection, message, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, error);
6340 : 709 : g_object_unref (message);
6341 : :
6342 : 709 : return ret;
6343 : : }
6344 : :
6345 : : static void
6346 : 12397 : add_call_flags (GDBusMessage *message,
6347 : : GDBusCallFlags flags)
6348 : : {
6349 : 12397 : GDBusMessageFlags msg_flags = 0;
6350 : :
6351 : 12397 : if (flags & G_DBUS_CALL_FLAGS_NO_AUTO_START)
6352 : 113 : msg_flags |= G_DBUS_MESSAGE_FLAGS_NO_AUTO_START;
6353 : 12397 : if (flags & G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION)
6354 : 0 : msg_flags |= G_DBUS_MESSAGE_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION;
6355 : 12397 : if (msg_flags)
6356 : 113 : g_dbus_message_set_flags (message, msg_flags);
6357 : 12397 : }
6358 : :
6359 : : static GVariant *
6360 : 7036 : decode_method_reply (GDBusMessage *reply,
6361 : : const gchar *method_name,
6362 : : const GVariantType *reply_type,
6363 : : GUnixFDList **out_fd_list,
6364 : : GError **error)
6365 : : {
6366 : : GVariant *result;
6367 : :
6368 : 7036 : result = NULL;
6369 : 7036 : switch (g_dbus_message_get_message_type (reply))
6370 : : {
6371 : 5473 : case G_DBUS_MESSAGE_TYPE_METHOD_RETURN:
6372 : 5473 : result = g_dbus_message_get_body (reply);
6373 : 5473 : if (result == NULL)
6374 : : {
6375 : 183 : result = g_variant_new ("()");
6376 : 183 : g_variant_ref_sink (result);
6377 : : }
6378 : : else
6379 : : {
6380 : 5290 : g_variant_ref (result);
6381 : : }
6382 : :
6383 : 5473 : if (!g_variant_is_of_type (result, reply_type))
6384 : : {
6385 : 3 : gchar *type_string = g_variant_type_dup_string (reply_type);
6386 : :
6387 : 3 : g_set_error (error,
6388 : : G_IO_ERROR,
6389 : : G_IO_ERROR_INVALID_ARGUMENT,
6390 : : _("Method “%s” returned type “%s”, but expected “%s”"),
6391 : : method_name, g_variant_get_type_string (result), type_string);
6392 : :
6393 : 3 : g_variant_unref (result);
6394 : 3 : g_free (type_string);
6395 : 3 : result = NULL;
6396 : : }
6397 : :
6398 : : #ifdef G_OS_UNIX
6399 : 5473 : if (result != NULL)
6400 : : {
6401 : 5470 : if (out_fd_list != NULL)
6402 : : {
6403 : 908 : *out_fd_list = g_dbus_message_get_unix_fd_list (reply);
6404 : 908 : if (*out_fd_list != NULL)
6405 : 3 : g_object_ref (*out_fd_list);
6406 : : }
6407 : : }
6408 : : #endif
6409 : 5473 : break;
6410 : :
6411 : 1563 : case G_DBUS_MESSAGE_TYPE_ERROR:
6412 : 1563 : g_dbus_message_to_gerror (reply, error);
6413 : 1563 : break;
6414 : :
6415 : 0 : default:
6416 : : g_assert_not_reached ();
6417 : : break;
6418 : : }
6419 : :
6420 : 7036 : return result;
6421 : : }
6422 : :
6423 : :
6424 : : typedef struct
6425 : : {
6426 : : GVariantType *reply_type;
6427 : : gchar *method_name; /* for error message */
6428 : :
6429 : : GUnixFDList *fd_list;
6430 : : } CallState;
6431 : :
6432 : : static void
6433 : 2304 : call_state_free (CallState *state)
6434 : : {
6435 : 2304 : g_variant_type_free (state->reply_type);
6436 : 2304 : g_free (state->method_name);
6437 : :
6438 : 2304 : if (state->fd_list != NULL)
6439 : 0 : g_object_unref (state->fd_list);
6440 : 2304 : g_slice_free (CallState, state);
6441 : 2304 : }
6442 : :
6443 : : /* called in any thread, with the connection's lock not held */
6444 : : static void
6445 : 2304 : g_dbus_connection_call_done (GObject *source,
6446 : : GAsyncResult *result,
6447 : : gpointer user_data)
6448 : : {
6449 : 2304 : GDBusConnection *connection = G_DBUS_CONNECTION (source);
6450 : 2304 : GTask *task = user_data;
6451 : 2304 : CallState *state = g_task_get_task_data (task);
6452 : 2304 : GError *error = NULL;
6453 : : GDBusMessage *reply;
6454 : 2304 : GVariant *value = NULL;
6455 : :
6456 : 2304 : reply = g_dbus_connection_send_message_with_reply_finish (connection,
6457 : : result,
6458 : : &error);
6459 : :
6460 : 2304 : if (G_UNLIKELY (_g_dbus_debug_call ()))
6461 : : {
6462 : 0 : _g_dbus_debug_print_lock ();
6463 : 0 : g_print ("========================================================================\n"
6464 : : "GDBus-debug:Call:\n"
6465 : : " <<<< ASYNC COMPLETE %s()",
6466 : : state->method_name);
6467 : :
6468 : 0 : if (reply != NULL)
6469 : : {
6470 : 0 : g_print (" (serial %d)\n"
6471 : : " SUCCESS\n",
6472 : : g_dbus_message_get_reply_serial (reply));
6473 : : }
6474 : : else
6475 : : {
6476 : 0 : g_print ("\n"
6477 : : " FAILED: %s\n",
6478 : 0 : error->message);
6479 : : }
6480 : 0 : _g_dbus_debug_print_unlock ();
6481 : : }
6482 : :
6483 : 2304 : if (reply != NULL)
6484 : 2287 : value = decode_method_reply (reply, state->method_name, state->reply_type, &state->fd_list, &error);
6485 : :
6486 : 2304 : if (error != NULL)
6487 : 1399 : g_task_return_error (task, error);
6488 : : else
6489 : 905 : g_task_return_pointer (task, value, (GDestroyNotify) g_variant_unref);
6490 : :
6491 : 2304 : g_clear_object (&reply);
6492 : 2304 : g_object_unref (task);
6493 : 2304 : }
6494 : :
6495 : : /* called in any thread, with the connection's lock not held */
6496 : : static void
6497 : 7636 : g_dbus_connection_call_internal (GDBusConnection *connection,
6498 : : const gchar *bus_name,
6499 : : const gchar *object_path,
6500 : : const gchar *interface_name,
6501 : : const gchar *method_name,
6502 : : GVariant *parameters,
6503 : : const GVariantType *reply_type,
6504 : : GDBusCallFlags flags,
6505 : : gint timeout_msec,
6506 : : GUnixFDList *fd_list,
6507 : : GCancellable *cancellable,
6508 : : GAsyncReadyCallback callback,
6509 : : gpointer user_data)
6510 : : {
6511 : : GDBusMessage *message;
6512 : : guint32 serial;
6513 : :
6514 : 7636 : g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
6515 : 7636 : g_return_if_fail (bus_name == NULL || g_dbus_is_name (bus_name));
6516 : 7636 : g_return_if_fail (object_path != NULL && g_variant_is_object_path (object_path));
6517 : 7636 : g_return_if_fail (interface_name != NULL && g_dbus_is_interface_name (interface_name));
6518 : 7636 : g_return_if_fail (method_name != NULL && g_dbus_is_member_name (method_name));
6519 : 7636 : g_return_if_fail (timeout_msec >= 0 || timeout_msec == -1);
6520 : 7636 : g_return_if_fail ((parameters == NULL) || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE));
6521 : 7636 : g_return_if_fail (check_initialized (connection));
6522 : : #ifdef G_OS_UNIX
6523 : 7636 : g_return_if_fail (fd_list == NULL || G_IS_UNIX_FD_LIST (fd_list));
6524 : : #else
6525 : : g_return_if_fail (fd_list == NULL);
6526 : : #endif
6527 : :
6528 : 7636 : message = g_dbus_message_new_method_call (bus_name,
6529 : : object_path,
6530 : : interface_name,
6531 : : method_name);
6532 : 7636 : add_call_flags (message, flags);
6533 : 7636 : if (parameters != NULL)
6534 : 7525 : g_dbus_message_set_body (message, parameters);
6535 : :
6536 : : #ifdef G_OS_UNIX
6537 : 7636 : if (fd_list != NULL)
6538 : 1 : g_dbus_message_set_unix_fd_list (message, fd_list);
6539 : : #endif
6540 : :
6541 : : /* If the user has no callback then we can just send the message with
6542 : : * the G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED flag set and skip all
6543 : : * the logic for processing the reply. If the service sends the reply
6544 : : * anyway then it will just be ignored.
6545 : : */
6546 : 7636 : if (callback != NULL)
6547 : : {
6548 : : CallState *state;
6549 : : GTask *task;
6550 : :
6551 : 2305 : state = g_slice_new0 (CallState);
6552 : 2305 : state->method_name = g_strjoin (".", interface_name, method_name, NULL);
6553 : :
6554 : 2305 : if (reply_type == NULL)
6555 : 1548 : reply_type = G_VARIANT_TYPE_ANY;
6556 : :
6557 : 2305 : state->reply_type = g_variant_type_copy (reply_type);
6558 : :
6559 : 2305 : task = g_task_new (connection, cancellable, callback, user_data);
6560 : 2305 : g_task_set_source_tag (task, g_dbus_connection_call_internal);
6561 : 2305 : g_task_set_task_data (task, state, (GDestroyNotify) call_state_free);
6562 : :
6563 : 2305 : g_dbus_connection_send_message_with_reply (connection,
6564 : : message,
6565 : : G_DBUS_SEND_MESSAGE_FLAGS_NONE,
6566 : : timeout_msec,
6567 : : &serial,
6568 : : cancellable,
6569 : : g_dbus_connection_call_done,
6570 : : task);
6571 : : }
6572 : : else
6573 : : {
6574 : : GDBusMessageFlags msg_flags;
6575 : :
6576 : 5331 : msg_flags = g_dbus_message_get_flags (message);
6577 : 5331 : msg_flags |= G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED;
6578 : 5331 : g_dbus_message_set_flags (message, msg_flags);
6579 : :
6580 : 5331 : g_dbus_connection_send_message (connection,
6581 : : message,
6582 : : G_DBUS_SEND_MESSAGE_FLAGS_NONE,
6583 : : &serial, NULL);
6584 : : }
6585 : :
6586 : 7636 : if (G_UNLIKELY (_g_dbus_debug_call ()))
6587 : : {
6588 : 0 : _g_dbus_debug_print_lock ();
6589 : 0 : g_print ("========================================================================\n"
6590 : : "GDBus-debug:Call:\n"
6591 : : " >>>> ASYNC %s.%s()\n"
6592 : : " on object %s\n"
6593 : : " owned by name %s (serial %d)\n",
6594 : : interface_name,
6595 : : method_name,
6596 : : object_path,
6597 : : bus_name != NULL ? bus_name : "(none)",
6598 : : serial);
6599 : 0 : _g_dbus_debug_print_unlock ();
6600 : : }
6601 : :
6602 : 7636 : if (message != NULL)
6603 : 7636 : g_object_unref (message);
6604 : : }
6605 : :
6606 : : /* called in any thread, with the connection's lock not held */
6607 : : static GVariant *
6608 : 2304 : g_dbus_connection_call_finish_internal (GDBusConnection *connection,
6609 : : GUnixFDList **out_fd_list,
6610 : : GAsyncResult *res,
6611 : : GError **error)
6612 : : {
6613 : : GTask *task;
6614 : : CallState *state;
6615 : : GVariant *ret;
6616 : :
6617 : 2304 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
6618 : 2304 : g_return_val_if_fail (g_task_is_valid (res, connection), NULL);
6619 : 2304 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
6620 : :
6621 : 2304 : task = G_TASK (res);
6622 : 2304 : state = g_task_get_task_data (task);
6623 : :
6624 : 2304 : ret = g_task_propagate_pointer (task, error);
6625 : 2304 : if (!ret)
6626 : 1399 : return NULL;
6627 : :
6628 : 905 : if (out_fd_list != NULL)
6629 : 119 : *out_fd_list = state->fd_list != NULL ? g_object_ref (state->fd_list) : NULL;
6630 : 905 : return ret;
6631 : : }
6632 : :
6633 : : /* called in any user thread, with the connection's lock not held */
6634 : : static GVariant *
6635 : 4761 : g_dbus_connection_call_sync_internal (GDBusConnection *connection,
6636 : : const gchar *bus_name,
6637 : : const gchar *object_path,
6638 : : const gchar *interface_name,
6639 : : const gchar *method_name,
6640 : : GVariant *parameters,
6641 : : const GVariantType *reply_type,
6642 : : GDBusCallFlags flags,
6643 : : gint timeout_msec,
6644 : : GUnixFDList *fd_list,
6645 : : GUnixFDList **out_fd_list,
6646 : : GCancellable *cancellable,
6647 : : GError **error)
6648 : : {
6649 : : GDBusMessage *message;
6650 : : GDBusMessage *reply;
6651 : : GVariant *result;
6652 : : GError *local_error;
6653 : : GDBusSendMessageFlags send_flags;
6654 : :
6655 : 4761 : message = NULL;
6656 : 4761 : reply = NULL;
6657 : 4761 : result = NULL;
6658 : :
6659 : 4761 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
6660 : 4761 : g_return_val_if_fail (bus_name == NULL || g_dbus_is_name (bus_name), NULL);
6661 : 4761 : g_return_val_if_fail (object_path != NULL && g_variant_is_object_path (object_path), NULL);
6662 : 4761 : g_return_val_if_fail (interface_name != NULL && g_dbus_is_interface_name (interface_name), NULL);
6663 : 4761 : g_return_val_if_fail (method_name != NULL && g_dbus_is_member_name (method_name), NULL);
6664 : 4761 : g_return_val_if_fail (timeout_msec >= 0 || timeout_msec == -1, NULL);
6665 : 4761 : g_return_val_if_fail ((parameters == NULL) || g_variant_is_of_type (parameters, G_VARIANT_TYPE_TUPLE), NULL);
6666 : : #ifdef G_OS_UNIX
6667 : 4761 : g_return_val_if_fail (fd_list == NULL || G_IS_UNIX_FD_LIST (fd_list), NULL);
6668 : : #else
6669 : : g_return_val_if_fail (fd_list == NULL, NULL);
6670 : : #endif
6671 : 4761 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
6672 : :
6673 : 4761 : if (!(flags & CALL_FLAGS_INITIALIZING))
6674 : 2571 : g_return_val_if_fail (check_initialized (connection), FALSE);
6675 : :
6676 : 4761 : if (reply_type == NULL)
6677 : 2377 : reply_type = G_VARIANT_TYPE_ANY;
6678 : :
6679 : 4761 : message = g_dbus_message_new_method_call (bus_name,
6680 : : object_path,
6681 : : interface_name,
6682 : : method_name);
6683 : 4761 : add_call_flags (message, flags);
6684 : 4761 : if (parameters != NULL)
6685 : 305 : g_dbus_message_set_body (message, parameters);
6686 : :
6687 : : #ifdef G_OS_UNIX
6688 : 4761 : if (fd_list != NULL)
6689 : 12 : g_dbus_message_set_unix_fd_list (message, fd_list);
6690 : : #endif
6691 : :
6692 : 4761 : if (G_UNLIKELY (_g_dbus_debug_call ()))
6693 : : {
6694 : 0 : _g_dbus_debug_print_lock ();
6695 : 0 : g_print ("========================================================================\n"
6696 : : "GDBus-debug:Call:\n"
6697 : : " >>>> SYNC %s.%s()\n"
6698 : : " on object %s\n"
6699 : : " owned by name %s\n",
6700 : : interface_name,
6701 : : method_name,
6702 : : object_path,
6703 : : bus_name != NULL ? bus_name : "(none)");
6704 : 0 : _g_dbus_debug_print_unlock ();
6705 : : }
6706 : :
6707 : 4761 : local_error = NULL;
6708 : :
6709 : 4761 : send_flags = G_DBUS_SEND_MESSAGE_FLAGS_NONE;
6710 : :
6711 : : /* translate from one flavour of flags to another... */
6712 : 4761 : if (flags & CALL_FLAGS_INITIALIZING)
6713 : 2190 : send_flags |= SEND_MESSAGE_FLAGS_INITIALIZING;
6714 : :
6715 : 4761 : reply = g_dbus_connection_send_message_with_reply_sync (connection,
6716 : : message,
6717 : : send_flags,
6718 : : timeout_msec,
6719 : : NULL, /* guint32 *out_serial */
6720 : : cancellable,
6721 : : &local_error);
6722 : :
6723 : 4761 : if (G_UNLIKELY (_g_dbus_debug_call ()))
6724 : : {
6725 : 0 : _g_dbus_debug_print_lock ();
6726 : 0 : g_print ("========================================================================\n"
6727 : : "GDBus-debug:Call:\n"
6728 : : " <<<< SYNC COMPLETE %s.%s()\n"
6729 : : " ",
6730 : : interface_name,
6731 : : method_name);
6732 : 0 : if (reply != NULL)
6733 : : {
6734 : 0 : g_print ("SUCCESS\n");
6735 : : }
6736 : : else
6737 : : {
6738 : 0 : g_print ("FAILED: %s\n",
6739 : 0 : local_error->message);
6740 : : }
6741 : 0 : _g_dbus_debug_print_unlock ();
6742 : : }
6743 : :
6744 : 4761 : if (reply == NULL)
6745 : : {
6746 : 12 : if (error != NULL)
6747 : 12 : *error = local_error;
6748 : : else
6749 : 0 : g_error_free (local_error);
6750 : 12 : goto out;
6751 : : }
6752 : :
6753 : 4749 : result = decode_method_reply (reply, method_name, reply_type, out_fd_list, error);
6754 : :
6755 : 4761 : out:
6756 : 4761 : if (message != NULL)
6757 : 4761 : g_object_unref (message);
6758 : 4761 : if (reply != NULL)
6759 : 4749 : g_object_unref (reply);
6760 : :
6761 : 4761 : return result;
6762 : : }
6763 : :
6764 : : /* ---------------------------------------------------------------------------------------------------- */
6765 : :
6766 : : /**
6767 : : * g_dbus_connection_call:
6768 : : * @connection: a #GDBusConnection
6769 : : * @bus_name: (nullable): a unique or well-known bus name or %NULL if
6770 : : * @connection is not a message bus connection
6771 : : * @object_path: path of remote object
6772 : : * @interface_name: D-Bus interface to invoke method on
6773 : : * @method_name: the name of the method to invoke
6774 : : * @parameters: (nullable): a #GVariant tuple with parameters for the method
6775 : : * or %NULL if not passing parameters
6776 : : * @reply_type: (nullable): the expected type of the reply (which will be a
6777 : : * tuple), or %NULL
6778 : : * @flags: flags from the #GDBusCallFlags enumeration
6779 : : * @timeout_msec: the timeout in milliseconds, -1 to use the default
6780 : : * timeout or %G_MAXINT for no timeout
6781 : : * @cancellable: (nullable): a #GCancellable or %NULL
6782 : : * @callback: (nullable): a #GAsyncReadyCallback to call when the request
6783 : : * is satisfied or %NULL if you don't care about the result of the
6784 : : * method invocation
6785 : : * @user_data: the data to pass to @callback
6786 : : *
6787 : : * Asynchronously invokes the @method_name method on the
6788 : : * @interface_name D-Bus interface on the remote object at
6789 : : * @object_path owned by @bus_name.
6790 : : *
6791 : : * If @connection is closed then the operation will fail with
6792 : : * %G_IO_ERROR_CLOSED. If @cancellable is canceled, the operation will
6793 : : * fail with %G_IO_ERROR_CANCELLED. If @parameters contains a value
6794 : : * not compatible with the D-Bus protocol, the operation fails with
6795 : : * %G_IO_ERROR_INVALID_ARGUMENT.
6796 : : *
6797 : : * If @reply_type is non-%NULL then the reply will be checked for having this type and an
6798 : : * error will be raised if it does not match. Said another way, if you give a @reply_type
6799 : : * then any non-%NULL return value will be of this type. Unless it’s
6800 : : * %G_VARIANT_TYPE_UNIT, the @reply_type will be a tuple containing one or more
6801 : : * values.
6802 : : *
6803 : : * If the @parameters #GVariant is floating, it is consumed. This allows
6804 : : * convenient 'inline' use of g_variant_new(), e.g.:
6805 : : * |[<!-- language="C" -->
6806 : : * g_dbus_connection_call (connection,
6807 : : * "org.freedesktop.StringThings",
6808 : : * "/org/freedesktop/StringThings",
6809 : : * "org.freedesktop.StringThings",
6810 : : * "TwoStrings",
6811 : : * g_variant_new ("(ss)",
6812 : : * "Thing One",
6813 : : * "Thing Two"),
6814 : : * NULL,
6815 : : * G_DBUS_CALL_FLAGS_NONE,
6816 : : * -1,
6817 : : * NULL,
6818 : : * (GAsyncReadyCallback) two_strings_done,
6819 : : * NULL);
6820 : : * ]|
6821 : : *
6822 : : * This is an asynchronous method. When the operation is finished,
6823 : : * @callback will be invoked in the thread-default main context
6824 : : * (see [method@GLib.MainContext.push_thread_default])
6825 : : * of the thread you are calling this method from. You can then call
6826 : : * g_dbus_connection_call_finish() to get the result of the operation.
6827 : : * See g_dbus_connection_call_sync() for the synchronous version of this
6828 : : * function.
6829 : : *
6830 : : * If @callback is %NULL then the D-Bus method call message will be sent with
6831 : : * the %G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED flag set.
6832 : : *
6833 : : * Since: 2.26
6834 : : */
6835 : : void
6836 : 7510 : g_dbus_connection_call (GDBusConnection *connection,
6837 : : const gchar *bus_name,
6838 : : const gchar *object_path,
6839 : : const gchar *interface_name,
6840 : : const gchar *method_name,
6841 : : GVariant *parameters,
6842 : : const GVariantType *reply_type,
6843 : : GDBusCallFlags flags,
6844 : : gint timeout_msec,
6845 : : GCancellable *cancellable,
6846 : : GAsyncReadyCallback callback,
6847 : : gpointer user_data)
6848 : : {
6849 : 7510 : 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);
6850 : 7510 : }
6851 : :
6852 : : /**
6853 : : * g_dbus_connection_call_finish:
6854 : : * @connection: a #GDBusConnection
6855 : : * @res: a #GAsyncResult obtained from the #GAsyncReadyCallback passed to g_dbus_connection_call()
6856 : : * @error: return location for error or %NULL
6857 : : *
6858 : : * Finishes an operation started with g_dbus_connection_call().
6859 : : *
6860 : : * Returns: (transfer full): %NULL if @error is set. Otherwise a non-floating
6861 : : * #GVariant tuple with return values. Free with g_variant_unref().
6862 : : *
6863 : : * Since: 2.26
6864 : : */
6865 : : GVariant *
6866 : 2184 : g_dbus_connection_call_finish (GDBusConnection *connection,
6867 : : GAsyncResult *res,
6868 : : GError **error)
6869 : : {
6870 : 2184 : return g_dbus_connection_call_finish_internal (connection, NULL, res, error);
6871 : : }
6872 : :
6873 : : /**
6874 : : * g_dbus_connection_call_sync:
6875 : : * @connection: a #GDBusConnection
6876 : : * @bus_name: (nullable): a unique or well-known bus name or %NULL if
6877 : : * @connection is not a message bus connection
6878 : : * @object_path: path of remote object
6879 : : * @interface_name: D-Bus interface to invoke method on
6880 : : * @method_name: the name of the method to invoke
6881 : : * @parameters: (nullable): a #GVariant tuple with parameters for the method
6882 : : * or %NULL if not passing parameters
6883 : : * @reply_type: (nullable): the expected type of the reply, or %NULL
6884 : : * @flags: flags from the #GDBusCallFlags enumeration
6885 : : * @timeout_msec: the timeout in milliseconds, -1 to use the default
6886 : : * timeout or %G_MAXINT for no timeout
6887 : : * @cancellable: (nullable): a #GCancellable or %NULL
6888 : : * @error: return location for error or %NULL
6889 : : *
6890 : : * Synchronously invokes the @method_name method on the
6891 : : * @interface_name D-Bus interface on the remote object at
6892 : : * @object_path owned by @bus_name.
6893 : : *
6894 : : * If @connection is closed then the operation will fail with
6895 : : * %G_IO_ERROR_CLOSED. If @cancellable is canceled, the
6896 : : * operation will fail with %G_IO_ERROR_CANCELLED. If @parameters
6897 : : * contains a value not compatible with the D-Bus protocol, the operation
6898 : : * fails with %G_IO_ERROR_INVALID_ARGUMENT.
6899 : : *
6900 : : * If @reply_type is non-%NULL then the reply will be checked for having
6901 : : * this type and an error will be raised if it does not match. Said
6902 : : * another way, if you give a @reply_type then any non-%NULL return
6903 : : * value will be of this type.
6904 : : *
6905 : : * If the @parameters #GVariant is floating, it is consumed.
6906 : : * This allows convenient 'inline' use of g_variant_new(), e.g.:
6907 : : * |[<!-- language="C" -->
6908 : : * g_dbus_connection_call_sync (connection,
6909 : : * "org.freedesktop.StringThings",
6910 : : * "/org/freedesktop/StringThings",
6911 : : * "org.freedesktop.StringThings",
6912 : : * "TwoStrings",
6913 : : * g_variant_new ("(ss)",
6914 : : * "Thing One",
6915 : : * "Thing Two"),
6916 : : * NULL,
6917 : : * G_DBUS_CALL_FLAGS_NONE,
6918 : : * -1,
6919 : : * NULL,
6920 : : * &error);
6921 : : * ]|
6922 : : *
6923 : : * The calling thread is blocked until a reply is received. See
6924 : : * g_dbus_connection_call() for the asynchronous version of
6925 : : * this method.
6926 : : *
6927 : : * Returns: (transfer full): %NULL if @error is set. Otherwise a non-floating
6928 : : * #GVariant tuple with return values. Free with g_variant_unref().
6929 : : *
6930 : : * Since: 2.26
6931 : : */
6932 : : GVariant *
6933 : 4434 : g_dbus_connection_call_sync (GDBusConnection *connection,
6934 : : const gchar *bus_name,
6935 : : const gchar *object_path,
6936 : : const gchar *interface_name,
6937 : : const gchar *method_name,
6938 : : GVariant *parameters,
6939 : : const GVariantType *reply_type,
6940 : : GDBusCallFlags flags,
6941 : : gint timeout_msec,
6942 : : GCancellable *cancellable,
6943 : : GError **error)
6944 : : {
6945 : 4434 : 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);
6946 : : }
6947 : :
6948 : : /* ---------------------------------------------------------------------------------------------------- */
6949 : :
6950 : : #ifdef G_OS_UNIX
6951 : :
6952 : : /**
6953 : : * g_dbus_connection_call_with_unix_fd_list:
6954 : : * @connection: a #GDBusConnection
6955 : : * @bus_name: (nullable): a unique or well-known bus name or %NULL if
6956 : : * @connection is not a message bus connection
6957 : : * @object_path: path of remote object
6958 : : * @interface_name: D-Bus interface to invoke method on
6959 : : * @method_name: the name of the method to invoke
6960 : : * @parameters: (nullable): a #GVariant tuple with parameters for the method
6961 : : * or %NULL if not passing parameters
6962 : : * @reply_type: (nullable): the expected type of the reply, or %NULL
6963 : : * @flags: flags from the #GDBusCallFlags enumeration
6964 : : * @timeout_msec: the timeout in milliseconds, -1 to use the default
6965 : : * timeout or %G_MAXINT for no timeout
6966 : : * @fd_list: (nullable): a #GUnixFDList or %NULL
6967 : : * @cancellable: (nullable): a #GCancellable or %NULL
6968 : : * @callback: (nullable): a #GAsyncReadyCallback to call when the request is
6969 : : * satisfied or %NULL if you don't * care about the result of the
6970 : : * method invocation
6971 : : * @user_data: The data to pass to @callback.
6972 : : *
6973 : : * Like g_dbus_connection_call() but also takes a #GUnixFDList object.
6974 : : *
6975 : : * The file descriptors normally correspond to %G_VARIANT_TYPE_HANDLE
6976 : : * values in the body of the message. For example, if a message contains
6977 : : * two file descriptors, @fd_list would have length 2, and
6978 : : * `g_variant_new_handle (0)` and `g_variant_new_handle (1)` would appear
6979 : : * somewhere in the body of the message (not necessarily in that order!)
6980 : : * to represent the file descriptors at indexes 0 and 1 respectively.
6981 : : *
6982 : : * When designing D-Bus APIs that are intended to be interoperable,
6983 : : * please note that non-GDBus implementations of D-Bus can usually only
6984 : : * access file descriptors if they are referenced in this way by a
6985 : : * value of type %G_VARIANT_TYPE_HANDLE in the body of the message.
6986 : : *
6987 : : * This method is only available on UNIX.
6988 : : *
6989 : : * Since: 2.30
6990 : : */
6991 : : void
6992 : 126 : g_dbus_connection_call_with_unix_fd_list (GDBusConnection *connection,
6993 : : const gchar *bus_name,
6994 : : const gchar *object_path,
6995 : : const gchar *interface_name,
6996 : : const gchar *method_name,
6997 : : GVariant *parameters,
6998 : : const GVariantType *reply_type,
6999 : : GDBusCallFlags flags,
7000 : : gint timeout_msec,
7001 : : GUnixFDList *fd_list,
7002 : : GCancellable *cancellable,
7003 : : GAsyncReadyCallback callback,
7004 : : gpointer user_data)
7005 : : {
7006 : 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);
7007 : 126 : }
7008 : :
7009 : : /**
7010 : : * g_dbus_connection_call_with_unix_fd_list_finish:
7011 : : * @connection: a #GDBusConnection
7012 : : * @out_fd_list: (out) (optional) (nullable): return location for a #GUnixFDList or %NULL
7013 : : * @res: a #GAsyncResult obtained from the #GAsyncReadyCallback passed to
7014 : : * g_dbus_connection_call_with_unix_fd_list()
7015 : : * @error: return location for error or %NULL
7016 : : *
7017 : : * Finishes an operation started with g_dbus_connection_call_with_unix_fd_list().
7018 : : *
7019 : : * The file descriptors normally correspond to %G_VARIANT_TYPE_HANDLE
7020 : : * values in the body of the message. For example,
7021 : : * if g_variant_get_handle() returns 5, that is intended to be a reference
7022 : : * to the file descriptor that can be accessed by
7023 : : * `g_unix_fd_list_get (*out_fd_list, 5, ...)`.
7024 : : *
7025 : : * When designing D-Bus APIs that are intended to be interoperable,
7026 : : * please note that non-GDBus implementations of D-Bus can usually only
7027 : : * access file descriptors if they are referenced in this way by a
7028 : : * value of type %G_VARIANT_TYPE_HANDLE in the body of the message.
7029 : : *
7030 : : * Returns: (transfer full): %NULL if @error is set. Otherwise a non-floating
7031 : : * #GVariant tuple with return values. Free with g_variant_unref().
7032 : : *
7033 : : * Since: 2.30
7034 : : */
7035 : : GVariant *
7036 : 120 : g_dbus_connection_call_with_unix_fd_list_finish (GDBusConnection *connection,
7037 : : GUnixFDList **out_fd_list,
7038 : : GAsyncResult *res,
7039 : : GError **error)
7040 : : {
7041 : 120 : return g_dbus_connection_call_finish_internal (connection, out_fd_list, res, error);
7042 : : }
7043 : :
7044 : : /**
7045 : : * g_dbus_connection_call_with_unix_fd_list_sync:
7046 : : * @connection: a #GDBusConnection
7047 : : * @bus_name: (nullable): a unique or well-known bus name or %NULL
7048 : : * if @connection is not a message bus connection
7049 : : * @object_path: path of remote object
7050 : : * @interface_name: D-Bus interface to invoke method on
7051 : : * @method_name: the name of the method to invoke
7052 : : * @parameters: (nullable): a #GVariant tuple with parameters for
7053 : : * the method or %NULL if not passing parameters
7054 : : * @reply_type: (nullable): the expected type of the reply, or %NULL
7055 : : * @flags: flags from the #GDBusCallFlags enumeration
7056 : : * @timeout_msec: the timeout in milliseconds, -1 to use the default
7057 : : * timeout or %G_MAXINT for no timeout
7058 : : * @fd_list: (nullable): a #GUnixFDList or %NULL
7059 : : * @out_fd_list: (out) (optional) (nullable): return location for a #GUnixFDList or %NULL
7060 : : * @cancellable: (nullable): a #GCancellable or %NULL
7061 : : * @error: return location for error or %NULL
7062 : : *
7063 : : * Like g_dbus_connection_call_sync() but also takes and returns #GUnixFDList objects.
7064 : : * See g_dbus_connection_call_with_unix_fd_list() and
7065 : : * g_dbus_connection_call_with_unix_fd_list_finish() for more details.
7066 : : *
7067 : : * This method is only available on UNIX.
7068 : : *
7069 : : * Returns: (transfer full): %NULL if @error is set. Otherwise a non-floating
7070 : : * #GVariant tuple with return values. Free with g_variant_unref().
7071 : : *
7072 : : * Since: 2.30
7073 : : */
7074 : : GVariant *
7075 : 327 : g_dbus_connection_call_with_unix_fd_list_sync (GDBusConnection *connection,
7076 : : const gchar *bus_name,
7077 : : const gchar *object_path,
7078 : : const gchar *interface_name,
7079 : : const gchar *method_name,
7080 : : GVariant *parameters,
7081 : : const GVariantType *reply_type,
7082 : : GDBusCallFlags flags,
7083 : : gint timeout_msec,
7084 : : GUnixFDList *fd_list,
7085 : : GUnixFDList **out_fd_list,
7086 : : GCancellable *cancellable,
7087 : : GError **error)
7088 : : {
7089 : 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);
7090 : : }
7091 : :
7092 : : #endif /* G_OS_UNIX */
7093 : :
7094 : : /* ---------------------------------------------------------------------------------------------------- */
7095 : :
7096 : : /* called without lock held in the thread where the caller registered
7097 : : * the subtree
7098 : : */
7099 : : static gboolean
7100 : 20 : handle_subtree_introspect (GDBusConnection *connection,
7101 : : ExportedSubtree *es,
7102 : : GDBusMessage *message)
7103 : : {
7104 : : GString *s;
7105 : : gboolean handled;
7106 : : GDBusMessage *reply;
7107 : : gchar **children;
7108 : : gboolean is_root;
7109 : : const gchar *sender;
7110 : : const gchar *requested_object_path;
7111 : : const gchar *requested_node;
7112 : : GDBusInterfaceInfo **interfaces;
7113 : : guint n;
7114 : : gchar **subnode_paths;
7115 : : gboolean has_properties_interface;
7116 : : gboolean has_introspectable_interface;
7117 : :
7118 : 20 : handled = FALSE;
7119 : :
7120 : 20 : requested_object_path = g_dbus_message_get_path (message);
7121 : 20 : sender = g_dbus_message_get_sender (message);
7122 : 20 : is_root = (g_strcmp0 (requested_object_path, es->object_path) == 0);
7123 : :
7124 : 20 : s = g_string_new (NULL);
7125 : 20 : introspect_append_header (s);
7126 : :
7127 : : /* Strictly we don't need the children in dynamic mode, but we avoid the
7128 : : * conditionals to preserve code clarity
7129 : : */
7130 : 20 : children = es->vtable->enumerate (es->connection,
7131 : : sender,
7132 : 20 : es->object_path,
7133 : : es->user_data);
7134 : :
7135 : 20 : if (!is_root)
7136 : : {
7137 : 12 : requested_node = strrchr (requested_object_path, '/') + 1;
7138 : :
7139 : : /* Assert existence of object if we are not dynamic */
7140 : 20 : if (!(es->flags & G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES) &&
7141 : 8 : !g_strv_contains ((const gchar * const *) children, requested_node))
7142 : 0 : goto out;
7143 : : }
7144 : : else
7145 : : {
7146 : 8 : requested_node = NULL;
7147 : : }
7148 : :
7149 : 20 : interfaces = es->vtable->introspect (es->connection,
7150 : : sender,
7151 : 20 : es->object_path,
7152 : : requested_node,
7153 : : es->user_data);
7154 : 20 : if (interfaces != NULL)
7155 : : {
7156 : 16 : has_properties_interface = FALSE;
7157 : 16 : has_introspectable_interface = FALSE;
7158 : :
7159 : 32 : for (n = 0; interfaces[n] != NULL; n++)
7160 : : {
7161 : 16 : if (strcmp (interfaces[n]->name, DBUS_INTERFACE_PROPERTIES) == 0)
7162 : 0 : has_properties_interface = TRUE;
7163 : 16 : else if (strcmp (interfaces[n]->name, DBUS_INTERFACE_INTROSPECTABLE) == 0)
7164 : 0 : has_introspectable_interface = TRUE;
7165 : : }
7166 : 16 : if (!has_properties_interface)
7167 : : g_string_append (s, introspect_properties_interface);
7168 : 16 : if (!has_introspectable_interface)
7169 : : g_string_append (s, introspect_introspectable_interface);
7170 : :
7171 : 32 : for (n = 0; interfaces[n] != NULL; n++)
7172 : : {
7173 : 16 : g_dbus_interface_info_generate_xml (interfaces[n], 2, s);
7174 : 16 : g_dbus_interface_info_unref (interfaces[n]);
7175 : : }
7176 : 16 : g_free (interfaces);
7177 : : }
7178 : :
7179 : : /* then include <node> entries from the Subtree for the root */
7180 : 20 : if (is_root)
7181 : : {
7182 : 25 : for (n = 0; children != NULL && children[n] != NULL; n++)
7183 : 17 : g_string_append_printf (s, " <node name=\"%s\"/>\n", children[n]);
7184 : : }
7185 : :
7186 : : /* finally include nodes registered below us */
7187 : 20 : subnode_paths = g_dbus_connection_list_registered (es->connection, requested_object_path);
7188 : 24 : for (n = 0; subnode_paths != NULL && subnode_paths[n] != NULL; n++)
7189 : 4 : g_string_append_printf (s, " <node name=\"%s\"/>\n", subnode_paths[n]);
7190 : 20 : g_strfreev (subnode_paths);
7191 : :
7192 : 20 : g_string_append (s, "</node>\n");
7193 : :
7194 : 20 : reply = g_dbus_message_new_method_reply (message);
7195 : 20 : g_dbus_message_set_body (reply, g_variant_new ("(s)", s->str));
7196 : 20 : g_dbus_connection_send_message (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
7197 : 20 : g_object_unref (reply);
7198 : :
7199 : 20 : handled = TRUE;
7200 : :
7201 : 20 : out:
7202 : 20 : g_string_free (s, TRUE);
7203 : 20 : g_strfreev (children);
7204 : 20 : return handled;
7205 : : }
7206 : :
7207 : : /* called without lock held in the thread where the caller registered
7208 : : * the subtree
7209 : : */
7210 : : static gboolean
7211 : 280 : handle_subtree_method_invocation (GDBusConnection *connection,
7212 : : ExportedSubtree *es,
7213 : : GDBusMessage *message)
7214 : : {
7215 : : gboolean handled;
7216 : : const gchar *sender;
7217 : : const gchar *interface_name;
7218 : : const gchar *member;
7219 : : const gchar *signature;
7220 : : const gchar *requested_object_path;
7221 : : const gchar *requested_node;
7222 : : gboolean is_root;
7223 : : GDBusInterfaceInfo *interface_info;
7224 : : const GDBusInterfaceVTable *interface_vtable;
7225 : : gpointer interface_user_data;
7226 : : guint n;
7227 : : GDBusInterfaceInfo **interfaces;
7228 : : gboolean is_property_get;
7229 : : gboolean is_property_set;
7230 : : gboolean is_property_get_all;
7231 : :
7232 : 280 : handled = FALSE;
7233 : 280 : interfaces = NULL;
7234 : :
7235 : 280 : requested_object_path = g_dbus_message_get_path (message);
7236 : 280 : sender = g_dbus_message_get_sender (message);
7237 : 280 : interface_name = g_dbus_message_get_interface (message);
7238 : 280 : member = g_dbus_message_get_member (message);
7239 : 280 : signature = g_dbus_message_get_signature (message);
7240 : 280 : is_root = (g_strcmp0 (requested_object_path, es->object_path) == 0);
7241 : :
7242 : 280 : is_property_get = FALSE;
7243 : 280 : is_property_set = FALSE;
7244 : 280 : is_property_get_all = FALSE;
7245 : 280 : if (g_strcmp0 (interface_name, DBUS_INTERFACE_PROPERTIES) == 0)
7246 : : {
7247 : 6 : if (g_strcmp0 (member, "Get") == 0 && g_strcmp0 (signature, "ss") == 0)
7248 : 3 : is_property_get = TRUE;
7249 : 3 : else if (g_strcmp0 (member, "Set") == 0 && g_strcmp0 (signature, "ssv") == 0)
7250 : 2 : is_property_set = TRUE;
7251 : 1 : else if (g_strcmp0 (member, "GetAll") == 0 && g_strcmp0 (signature, "s") == 0)
7252 : 1 : is_property_get_all = TRUE;
7253 : : }
7254 : :
7255 : 280 : if (!is_root)
7256 : : {
7257 : 280 : requested_node = strrchr (requested_object_path, '/') + 1;
7258 : :
7259 : 280 : if (~es->flags & G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES)
7260 : : {
7261 : : /* We don't want to dispatch to unenumerated
7262 : : * nodes, so ensure that the child exists.
7263 : : */
7264 : : gchar **children;
7265 : : gboolean exists;
7266 : :
7267 : 279 : children = es->vtable->enumerate (es->connection,
7268 : : sender,
7269 : 279 : es->object_path,
7270 : : es->user_data);
7271 : :
7272 : 279 : exists = g_strv_contains ((const gchar * const *) children, requested_node);
7273 : 279 : g_strfreev (children);
7274 : :
7275 : 279 : if (!exists)
7276 : 0 : goto out;
7277 : : }
7278 : : }
7279 : : else
7280 : : {
7281 : 0 : requested_node = NULL;
7282 : : }
7283 : :
7284 : : /* get introspection data for the node */
7285 : 280 : interfaces = es->vtable->introspect (es->connection,
7286 : : sender,
7287 : : requested_object_path,
7288 : : requested_node,
7289 : : es->user_data);
7290 : :
7291 : 280 : if (interfaces == NULL)
7292 : 0 : goto out;
7293 : :
7294 : 280 : interface_info = NULL;
7295 : 560 : for (n = 0; interfaces[n] != NULL; n++)
7296 : : {
7297 : 280 : if (g_strcmp0 (interfaces[n]->name, interface_name) == 0)
7298 : 272 : interface_info = interfaces[n];
7299 : : }
7300 : :
7301 : : /* dispatch the call if the user wants to handle it */
7302 : 280 : if (interface_info != NULL)
7303 : : {
7304 : : /* figure out where to dispatch the method call */
7305 : 272 : interface_user_data = NULL;
7306 : 272 : interface_vtable = es->vtable->dispatch (es->connection,
7307 : : sender,
7308 : 272 : es->object_path,
7309 : : interface_name,
7310 : : requested_node,
7311 : : &interface_user_data,
7312 : : es->user_data);
7313 : 272 : if (interface_vtable == NULL)
7314 : 0 : goto out;
7315 : :
7316 : 272 : CONNECTION_LOCK (connection);
7317 : 272 : handled = validate_and_maybe_schedule_method_call (es->connection,
7318 : : message,
7319 : : 0,
7320 : : es->id,
7321 : : interface_info,
7322 : : interface_vtable,
7323 : : es->context,
7324 : : interface_user_data);
7325 : 272 : CONNECTION_UNLOCK (connection);
7326 : : }
7327 : : /* handle DBUS_INTERFACE_PROPERTIES if not explicitly handled */
7328 : 8 : else if (is_property_get || is_property_set || is_property_get_all)
7329 : : {
7330 : 6 : if (is_property_get)
7331 : 3 : g_variant_get (g_dbus_message_get_body (message), "(&s&s)", &interface_name, NULL);
7332 : 3 : else if (is_property_set)
7333 : 2 : g_variant_get (g_dbus_message_get_body (message), "(&s&sv)", &interface_name, NULL, NULL);
7334 : 1 : else if (is_property_get_all)
7335 : 1 : g_variant_get (g_dbus_message_get_body (message), "(&s)", &interface_name, NULL, NULL);
7336 : : else
7337 : : g_assert_not_reached ();
7338 : :
7339 : : /* see if the object supports this interface at all */
7340 : 12 : for (n = 0; interfaces[n] != NULL; n++)
7341 : : {
7342 : 6 : if (g_strcmp0 (interfaces[n]->name, interface_name) == 0)
7343 : 6 : interface_info = interfaces[n];
7344 : : }
7345 : :
7346 : : /* Fail with DBUS_ERROR_INVALID_ARGS if the user-code
7347 : : * claims it won't support the interface
7348 : : */
7349 : 6 : if (interface_info == NULL)
7350 : : {
7351 : : GDBusMessage *reply;
7352 : 0 : reply = g_dbus_message_new_method_error (message,
7353 : : DBUS_ERROR_INVALID_ARGS,
7354 : : _("No such interface “%s”"),
7355 : : interface_name);
7356 : 0 : g_dbus_connection_send_message (es->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
7357 : 0 : g_object_unref (reply);
7358 : 0 : handled = TRUE;
7359 : 0 : goto out;
7360 : : }
7361 : :
7362 : : /* figure out where to dispatch the property get/set/getall calls */
7363 : 6 : interface_user_data = NULL;
7364 : 6 : interface_vtable = es->vtable->dispatch (es->connection,
7365 : : sender,
7366 : 6 : es->object_path,
7367 : : interface_name,
7368 : : requested_node,
7369 : : &interface_user_data,
7370 : : es->user_data);
7371 : 6 : if (interface_vtable == NULL)
7372 : : {
7373 : 0 : g_warning ("The subtree introspection function indicates that '%s' "
7374 : : "is a valid interface name, but calling the dispatch "
7375 : : "function on that interface gave us NULL", interface_name);
7376 : 0 : goto out;
7377 : : }
7378 : :
7379 : 6 : if (is_property_get || is_property_set)
7380 : : {
7381 : 5 : CONNECTION_LOCK (connection);
7382 : 5 : handled = validate_and_maybe_schedule_property_getset (es->connection,
7383 : : message,
7384 : : 0,
7385 : : es->id,
7386 : : is_property_get,
7387 : : interface_info,
7388 : : interface_vtable,
7389 : : es->context,
7390 : : interface_user_data);
7391 : 5 : CONNECTION_UNLOCK (connection);
7392 : : }
7393 : 1 : else if (is_property_get_all)
7394 : : {
7395 : 1 : CONNECTION_LOCK (connection);
7396 : 1 : handled = validate_and_maybe_schedule_property_get_all (es->connection,
7397 : : message,
7398 : : 0,
7399 : : es->id,
7400 : : interface_info,
7401 : : interface_vtable,
7402 : : es->context,
7403 : : interface_user_data);
7404 : 1 : CONNECTION_UNLOCK (connection);
7405 : : }
7406 : : }
7407 : :
7408 : 2 : out:
7409 : 280 : if (interfaces != NULL)
7410 : : {
7411 : 560 : for (n = 0; interfaces[n] != NULL; n++)
7412 : 280 : g_dbus_interface_info_unref (interfaces[n]);
7413 : 280 : g_free (interfaces);
7414 : : }
7415 : :
7416 : 280 : return handled;
7417 : : }
7418 : :
7419 : : typedef struct
7420 : : {
7421 : : GDBusMessage *message; /* (owned) */
7422 : : ExportedSubtree *es; /* (owned) */
7423 : : } SubtreeDeferredData;
7424 : :
7425 : : static void
7426 : 300 : subtree_deferred_data_free (SubtreeDeferredData *data)
7427 : : {
7428 : 300 : g_clear_object (&data->message);
7429 : 300 : exported_subtree_unref (data->es);
7430 : 300 : g_free (data);
7431 : 300 : }
7432 : :
7433 : : /* called without lock held in the thread where the caller registered the subtree */
7434 : : static gboolean
7435 : 300 : process_subtree_vtable_message_in_idle_cb (gpointer _data)
7436 : : {
7437 : 300 : SubtreeDeferredData *data = _data;
7438 : : gboolean handled;
7439 : :
7440 : 300 : handled = FALSE;
7441 : :
7442 : 320 : if (g_strcmp0 (g_dbus_message_get_interface (data->message), DBUS_INTERFACE_INTROSPECTABLE) == 0 &&
7443 : 40 : g_strcmp0 (g_dbus_message_get_member (data->message), "Introspect") == 0 &&
7444 : 20 : g_strcmp0 (g_dbus_message_get_signature (data->message), "") == 0)
7445 : 20 : handled = handle_subtree_introspect (data->es->connection,
7446 : : data->es,
7447 : : data->message);
7448 : : else
7449 : 280 : handled = handle_subtree_method_invocation (data->es->connection,
7450 : : data->es,
7451 : : data->message);
7452 : :
7453 : 300 : if (!handled)
7454 : : {
7455 : 2 : CONNECTION_LOCK (data->es->connection);
7456 : 2 : handled = handle_generic_unlocked (data->es->connection, data->message);
7457 : 2 : CONNECTION_UNLOCK (data->es->connection);
7458 : : }
7459 : :
7460 : : /* if we couldn't handle the request, just bail with the UnknownMethod error */
7461 : 300 : if (!handled)
7462 : : {
7463 : : GDBusMessage *reply;
7464 : 1 : reply = g_dbus_message_new_method_error (data->message,
7465 : : DBUS_ERROR_UNKNOWN_METHOD,
7466 : : _("Method “%s” on interface “%s” with signature “%s” does not exist"),
7467 : : g_dbus_message_get_member (data->message),
7468 : : g_dbus_message_get_interface (data->message),
7469 : : g_dbus_message_get_signature (data->message));
7470 : 1 : g_dbus_connection_send_message (data->es->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
7471 : 1 : g_object_unref (reply);
7472 : : }
7473 : :
7474 : 300 : return FALSE;
7475 : : }
7476 : :
7477 : : /* called in GDBusWorker thread with connection's lock held */
7478 : : static gboolean
7479 : 300 : subtree_message_func (GDBusConnection *connection,
7480 : : ExportedSubtree *es,
7481 : : GDBusMessage *message)
7482 : : {
7483 : : GSource *idle_source;
7484 : : SubtreeDeferredData *data;
7485 : :
7486 : 300 : data = g_new0 (SubtreeDeferredData, 1);
7487 : 300 : data->message = g_object_ref (message);
7488 : 300 : data->es = exported_subtree_ref (es);
7489 : :
7490 : : /* defer this call to an idle handler in the right thread */
7491 : 300 : idle_source = g_idle_source_new ();
7492 : 300 : g_source_set_priority (idle_source, G_PRIORITY_HIGH);
7493 : 300 : g_source_set_callback (idle_source,
7494 : : process_subtree_vtable_message_in_idle_cb,
7495 : : data,
7496 : : (GDestroyNotify) subtree_deferred_data_free);
7497 : 300 : g_source_set_static_name (idle_source, "[gio] process_subtree_vtable_message_in_idle_cb");
7498 : 300 : g_source_attach (idle_source, es->context);
7499 : 300 : g_source_unref (idle_source);
7500 : :
7501 : : /* since we own the entire subtree, handlers for objects not in the subtree have been
7502 : : * tried already by libdbus-1 - so we just need to ensure that we're always going
7503 : : * to reply to the message
7504 : : */
7505 : 300 : return TRUE;
7506 : : }
7507 : :
7508 : : /**
7509 : : * g_dbus_connection_register_subtree:
7510 : : * @connection: a #GDBusConnection
7511 : : * @object_path: the object path to register the subtree at
7512 : : * @vtable: a #GDBusSubtreeVTable to enumerate, introspect and
7513 : : * dispatch nodes in the subtree
7514 : : * @flags: flags used to fine tune the behavior of the subtree
7515 : : * @user_data: data to pass to functions in @vtable
7516 : : * @user_data_free_func: function to call when the subtree is unregistered
7517 : : * @error: return location for error or %NULL
7518 : : *
7519 : : * Registers a whole subtree of dynamic objects.
7520 : : *
7521 : : * The @enumerate and @introspection functions in @vtable are used to
7522 : : * convey, to remote callers, what nodes exist in the subtree rooted
7523 : : * by @object_path.
7524 : : *
7525 : : * When handling remote calls into any node in the subtree, first the
7526 : : * @enumerate function is used to check if the node exists. If the node exists
7527 : : * or the %G_DBUS_SUBTREE_FLAGS_DISPATCH_TO_UNENUMERATED_NODES flag is set
7528 : : * the @introspection function is used to check if the node supports the
7529 : : * requested method. If so, the @dispatch function is used to determine
7530 : : * where to dispatch the call. The collected #GDBusInterfaceVTable and
7531 : : * #gpointer will be used to call into the interface vtable for processing
7532 : : * the request.
7533 : : *
7534 : : * All calls into user-provided code will be invoked in the thread-default
7535 : : * main context (see [method@GLib.MainContext.push_thread_default])
7536 : : * of the thread you are calling this method from.
7537 : : *
7538 : : * If an existing subtree is already registered at @object_path or
7539 : : * then @error is set to %G_IO_ERROR_EXISTS.
7540 : : *
7541 : : * Note that it is valid to register regular objects (using
7542 : : * g_dbus_connection_register_object()) in a subtree registered with
7543 : : * g_dbus_connection_register_subtree() - if so, the subtree handler
7544 : : * is tried as the last resort. One way to think about a subtree
7545 : : * handler is to consider it a fallback handler for object paths not
7546 : : * registered via g_dbus_connection_register_object() or other bindings.
7547 : : *
7548 : : * Note that @vtable will be copied so you cannot change it after
7549 : : * registration.
7550 : : *
7551 : : * See this [server][class@Gio.DBusConnection#an-example-for-exporting-a-subtree]
7552 : : * for an example of how to use this method.
7553 : : *
7554 : : * Returns: 0 if @error is set, otherwise a subtree registration ID (never 0)
7555 : : * that can be used with g_dbus_connection_unregister_subtree()
7556 : : *
7557 : : * Since: 2.26
7558 : : */
7559 : : guint
7560 : 1004 : g_dbus_connection_register_subtree (GDBusConnection *connection,
7561 : : const gchar *object_path,
7562 : : const GDBusSubtreeVTable *vtable,
7563 : : GDBusSubtreeFlags flags,
7564 : : gpointer user_data,
7565 : : GDestroyNotify user_data_free_func,
7566 : : GError **error)
7567 : : {
7568 : : guint ret;
7569 : : ExportedSubtree *es;
7570 : :
7571 : 1004 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
7572 : 1004 : g_return_val_if_fail (object_path != NULL && g_variant_is_object_path (object_path), 0);
7573 : 1004 : g_return_val_if_fail (vtable != NULL, 0);
7574 : 1004 : g_return_val_if_fail (error == NULL || *error == NULL, 0);
7575 : 1004 : g_return_val_if_fail (check_initialized (connection), 0);
7576 : :
7577 : 1004 : ret = 0;
7578 : :
7579 : 1004 : CONNECTION_LOCK (connection);
7580 : :
7581 : 1004 : es = g_hash_table_lookup (connection->map_object_path_to_es, object_path);
7582 : 1004 : if (es != NULL)
7583 : : {
7584 : 1 : g_set_error (error,
7585 : : G_IO_ERROR,
7586 : : G_IO_ERROR_EXISTS,
7587 : : _("A subtree is already exported for %s"),
7588 : : object_path);
7589 : 1 : goto out;
7590 : : }
7591 : :
7592 : 1003 : es = g_new0 (ExportedSubtree, 1);
7593 : 1003 : es->refcount = 1;
7594 : 1003 : es->object_path = g_strdup (object_path);
7595 : 1003 : es->connection = connection;
7596 : :
7597 : 1003 : es->vtable = _g_dbus_subtree_vtable_copy (vtable);
7598 : 1003 : es->flags = flags;
7599 : 1003 : es->id = (guint) g_atomic_int_add (&_global_subtree_registration_id, 1); /* TODO: overflow etc. */
7600 : 1003 : es->user_data = user_data;
7601 : 1003 : es->user_data_free_func = user_data_free_func;
7602 : 1003 : es->context = g_main_context_ref_thread_default ();
7603 : :
7604 : 1003 : g_hash_table_insert (connection->map_object_path_to_es, es->object_path, es);
7605 : 1003 : g_hash_table_insert (connection->map_id_to_es,
7606 : 1003 : GUINT_TO_POINTER (es->id),
7607 : : es);
7608 : :
7609 : 1003 : ret = es->id;
7610 : :
7611 : 1004 : out:
7612 : 1004 : CONNECTION_UNLOCK (connection);
7613 : :
7614 : 1004 : if (ret == 0 && user_data_free_func != NULL)
7615 : 1 : user_data_free_func (user_data);
7616 : :
7617 : 1004 : return ret;
7618 : : }
7619 : :
7620 : : /* ---------------------------------------------------------------------------------------------------- */
7621 : :
7622 : : /**
7623 : : * g_dbus_connection_unregister_subtree:
7624 : : * @connection: a #GDBusConnection
7625 : : * @registration_id: a subtree registration id obtained from
7626 : : * g_dbus_connection_register_subtree()
7627 : : *
7628 : : * Unregisters a subtree.
7629 : : *
7630 : : * Returns: %TRUE if the subtree was unregistered, %FALSE otherwise
7631 : : *
7632 : : * Since: 2.26
7633 : : */
7634 : : gboolean
7635 : 1002 : g_dbus_connection_unregister_subtree (GDBusConnection *connection,
7636 : : guint registration_id)
7637 : : {
7638 : : ExportedSubtree *es;
7639 : : gboolean ret;
7640 : :
7641 : 1002 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
7642 : 1002 : g_return_val_if_fail (check_initialized (connection), FALSE);
7643 : :
7644 : 1002 : ret = FALSE;
7645 : :
7646 : 1002 : CONNECTION_LOCK (connection);
7647 : :
7648 : 1002 : es = g_hash_table_lookup (connection->map_id_to_es,
7649 : 1002 : GUINT_TO_POINTER (registration_id));
7650 : 1002 : if (es == NULL)
7651 : 0 : goto out;
7652 : :
7653 : 1002 : g_warn_if_fail (g_hash_table_remove (connection->map_id_to_es, GUINT_TO_POINTER (es->id)));
7654 : 1002 : g_warn_if_fail (g_hash_table_remove (connection->map_object_path_to_es, es->object_path));
7655 : :
7656 : 1002 : ret = TRUE;
7657 : :
7658 : 1002 : out:
7659 : 1002 : CONNECTION_UNLOCK (connection);
7660 : :
7661 : 1002 : return ret;
7662 : : }
7663 : :
7664 : : /* ---------------------------------------------------------------------------------------------------- */
7665 : :
7666 : : /* may be called in any thread, with connection's lock held */
7667 : : static void
7668 : 6 : handle_generic_ping_unlocked (GDBusConnection *connection,
7669 : : const gchar *object_path,
7670 : : GDBusMessage *message)
7671 : : {
7672 : : GDBusMessage *reply;
7673 : 6 : reply = g_dbus_message_new_method_reply (message);
7674 : 6 : g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
7675 : 6 : g_object_unref (reply);
7676 : 6 : }
7677 : :
7678 : : /* may be called in any thread, with connection's lock held */
7679 : : static void
7680 : 1 : handle_generic_get_machine_id_unlocked (GDBusConnection *connection,
7681 : : const gchar *object_path,
7682 : : GDBusMessage *message)
7683 : : {
7684 : : GDBusMessage *reply;
7685 : :
7686 : 1 : reply = NULL;
7687 : 1 : if (connection->machine_id == NULL)
7688 : : {
7689 : : GError *error;
7690 : :
7691 : 1 : error = NULL;
7692 : 1 : connection->machine_id = _g_dbus_get_machine_id (&error);
7693 : 1 : if (connection->machine_id == NULL)
7694 : : {
7695 : 0 : reply = g_dbus_message_new_method_error_literal (message,
7696 : : DBUS_ERROR_FAILED,
7697 : 0 : error->message);
7698 : 0 : g_error_free (error);
7699 : : }
7700 : : }
7701 : :
7702 : 1 : if (reply == NULL)
7703 : : {
7704 : 1 : reply = g_dbus_message_new_method_reply (message);
7705 : 1 : g_dbus_message_set_body (reply, g_variant_new ("(s)", connection->machine_id));
7706 : : }
7707 : 1 : g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
7708 : 1 : g_object_unref (reply);
7709 : 1 : }
7710 : :
7711 : : /* may be called in any thread, with connection's lock held */
7712 : : static void
7713 : 14 : handle_generic_introspect_unlocked (GDBusConnection *connection,
7714 : : const gchar *object_path,
7715 : : GDBusMessage *message)
7716 : : {
7717 : : guint n;
7718 : : GString *s;
7719 : : gchar **registered;
7720 : : GDBusMessage *reply;
7721 : :
7722 : : /* first the header */
7723 : 14 : s = g_string_new (NULL);
7724 : 14 : introspect_append_header (s);
7725 : :
7726 : 14 : registered = g_dbus_connection_list_registered_unlocked (connection, object_path);
7727 : 21 : for (n = 0; registered != NULL && registered[n] != NULL; n++)
7728 : 7 : g_string_append_printf (s, " <node name=\"%s\"/>\n", registered[n]);
7729 : 14 : g_strfreev (registered);
7730 : 14 : g_string_append (s, "</node>\n");
7731 : :
7732 : 14 : reply = g_dbus_message_new_method_reply (message);
7733 : 14 : g_dbus_message_set_body (reply, g_variant_new ("(s)", s->str));
7734 : 14 : g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
7735 : 14 : g_object_unref (reply);
7736 : 14 : g_string_free (s, TRUE);
7737 : 14 : }
7738 : :
7739 : : /* may be called in any thread, with connection's lock held */
7740 : : static gboolean
7741 : 1091 : handle_generic_unlocked (GDBusConnection *connection,
7742 : : GDBusMessage *message)
7743 : : {
7744 : : gboolean handled;
7745 : : const gchar *interface_name;
7746 : : const gchar *member;
7747 : : const gchar *signature;
7748 : : const gchar *path;
7749 : :
7750 : 1091 : CONNECTION_ENSURE_LOCK (connection);
7751 : :
7752 : 1091 : handled = FALSE;
7753 : :
7754 : 1091 : interface_name = g_dbus_message_get_interface (message);
7755 : 1091 : member = g_dbus_message_get_member (message);
7756 : 1091 : signature = g_dbus_message_get_signature (message);
7757 : 1091 : path = g_dbus_message_get_path (message);
7758 : :
7759 : 1105 : if (g_strcmp0 (interface_name, DBUS_INTERFACE_INTROSPECTABLE) == 0 &&
7760 : 28 : g_strcmp0 (member, "Introspect") == 0 &&
7761 : 14 : g_strcmp0 (signature, "") == 0)
7762 : : {
7763 : 14 : handle_generic_introspect_unlocked (connection, path, message);
7764 : 14 : handled = TRUE;
7765 : : }
7766 : 1084 : else if (g_strcmp0 (interface_name, DBUS_INTERFACE_PEER) == 0 &&
7767 : 13 : g_strcmp0 (member, "Ping") == 0 &&
7768 : 6 : g_strcmp0 (signature, "") == 0)
7769 : : {
7770 : 6 : handle_generic_ping_unlocked (connection, path, message);
7771 : 6 : handled = TRUE;
7772 : : }
7773 : 1072 : else if (g_strcmp0 (interface_name, DBUS_INTERFACE_PEER) == 0 &&
7774 : 2 : g_strcmp0 (member, "GetMachineId") == 0 &&
7775 : 1 : g_strcmp0 (signature, "") == 0)
7776 : : {
7777 : 1 : handle_generic_get_machine_id_unlocked (connection, path, message);
7778 : 1 : handled = TRUE;
7779 : : }
7780 : :
7781 : 1091 : return handled;
7782 : : }
7783 : :
7784 : : /* ---------------------------------------------------------------------------------------------------- */
7785 : :
7786 : : /* called in GDBusWorker thread with connection's lock held */
7787 : : static void
7788 : 2293 : distribute_method_call (GDBusConnection *connection,
7789 : : GDBusMessage *message)
7790 : : {
7791 : : GDBusMessage *reply;
7792 : : ExportedObject *eo;
7793 : : ExportedSubtree *es;
7794 : : const gchar *path;
7795 : : const gchar *interface_name;
7796 : : const gchar *member;
7797 : : gchar *subtree_path;
7798 : : gchar *needle;
7799 : 2293 : gboolean object_found = FALSE;
7800 : :
7801 : 2293 : g_assert (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL);
7802 : :
7803 : : /* these are required, and should have been validated by validate_headers()
7804 : : * in gdbusmessage.c already */
7805 : 2293 : member = g_dbus_message_get_member (message);
7806 : 2293 : path = g_dbus_message_get_path (message);
7807 : :
7808 : 2293 : g_assert (member != NULL);
7809 : 2293 : g_assert (path != NULL);
7810 : :
7811 : : /* this is optional */
7812 : 2293 : interface_name = g_dbus_message_get_interface (message);
7813 : :
7814 : 2293 : subtree_path = g_strdup (path);
7815 : 2293 : needle = strrchr (subtree_path, '/');
7816 : 2293 : if (needle != NULL && needle != subtree_path)
7817 : : {
7818 : 1788 : *needle = '\0';
7819 : : }
7820 : : else
7821 : : {
7822 : 505 : g_free (subtree_path);
7823 : 505 : subtree_path = NULL;
7824 : : }
7825 : :
7826 : 2293 : if (G_UNLIKELY (_g_dbus_debug_incoming ()))
7827 : : {
7828 : 0 : _g_dbus_debug_print_lock ();
7829 : 0 : g_print ("========================================================================\n"
7830 : : "GDBus-debug:Incoming:\n"
7831 : : " <<<< METHOD INVOCATION %s.%s()\n"
7832 : : " on object %s\n"
7833 : : " invoked by name %s\n"
7834 : : " serial %d\n",
7835 : : interface_name, member,
7836 : : path,
7837 : 0 : g_dbus_message_get_sender (message) != NULL ? g_dbus_message_get_sender (message) : "(none)",
7838 : : g_dbus_message_get_serial (message));
7839 : 0 : _g_dbus_debug_print_unlock ();
7840 : : }
7841 : :
7842 : 2293 : eo = g_hash_table_lookup (connection->map_object_path_to_eo, path);
7843 : 2293 : if (eo != NULL)
7844 : : {
7845 : 917 : if (obj_message_func (connection, eo, message, &object_found))
7846 : 904 : goto out;
7847 : : }
7848 : :
7849 : 1389 : es = g_hash_table_lookup (connection->map_object_path_to_es, path);
7850 : 1389 : if (es != NULL)
7851 : : {
7852 : 8 : if (subtree_message_func (connection, es, message))
7853 : 8 : goto out;
7854 : : }
7855 : :
7856 : 1381 : if (subtree_path != NULL)
7857 : : {
7858 : 1362 : es = g_hash_table_lookup (connection->map_object_path_to_es, subtree_path);
7859 : 1362 : if (es != NULL)
7860 : : {
7861 : 292 : if (subtree_message_func (connection, es, message))
7862 : 292 : goto out;
7863 : : }
7864 : : }
7865 : :
7866 : 1089 : if (handle_generic_unlocked (connection, message))
7867 : 20 : goto out;
7868 : :
7869 : : /* if we end up here, the message has not been not handled - so return an error saying this */
7870 : 1069 : if (object_found == TRUE)
7871 : : {
7872 : 7 : reply = g_dbus_message_new_method_error (message,
7873 : : DBUS_ERROR_UNKNOWN_METHOD,
7874 : : _("No such interface “%s” on object at path %s"),
7875 : : interface_name,
7876 : : path);
7877 : : }
7878 : : else
7879 : : {
7880 : 1062 : reply = g_dbus_message_new_method_error (message,
7881 : : DBUS_ERROR_UNKNOWN_METHOD,
7882 : : _("Object does not exist at path “%s”"),
7883 : : path);
7884 : : }
7885 : :
7886 : 1069 : g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
7887 : 1069 : g_object_unref (reply);
7888 : :
7889 : 2293 : out:
7890 : 2293 : g_free (subtree_path);
7891 : 2293 : }
7892 : :
7893 : : /* ---------------------------------------------------------------------------------------------------- */
7894 : :
7895 : : /* Called in any user thread, with the message_bus_lock held. */
7896 : : static GWeakRef *
7897 : 2918 : message_bus_get_singleton (GBusType bus_type,
7898 : : GError **error)
7899 : : {
7900 : : GWeakRef *ret;
7901 : : const gchar *starter_bus;
7902 : :
7903 : 2918 : ret = NULL;
7904 : :
7905 : 2918 : switch (bus_type)
7906 : : {
7907 : 2894 : case G_BUS_TYPE_SESSION:
7908 : 2894 : ret = &the_session_bus;
7909 : 2894 : break;
7910 : :
7911 : 24 : case G_BUS_TYPE_SYSTEM:
7912 : 24 : ret = &the_system_bus;
7913 : 24 : break;
7914 : :
7915 : 0 : case G_BUS_TYPE_STARTER:
7916 : 0 : starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
7917 : 0 : if (g_strcmp0 (starter_bus, "session") == 0)
7918 : : {
7919 : 0 : ret = message_bus_get_singleton (G_BUS_TYPE_SESSION, error);
7920 : 0 : goto out;
7921 : : }
7922 : 0 : else if (g_strcmp0 (starter_bus, "system") == 0)
7923 : : {
7924 : 0 : ret = message_bus_get_singleton (G_BUS_TYPE_SYSTEM, error);
7925 : 0 : goto out;
7926 : : }
7927 : : else
7928 : : {
7929 : 0 : if (starter_bus != NULL)
7930 : : {
7931 : 0 : g_set_error (error,
7932 : : G_IO_ERROR,
7933 : : G_IO_ERROR_INVALID_ARGUMENT,
7934 : : _("Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable"
7935 : : " — unknown value “%s”"),
7936 : : starter_bus);
7937 : : }
7938 : : else
7939 : : {
7940 : 0 : g_set_error_literal (error,
7941 : : G_IO_ERROR,
7942 : : G_IO_ERROR_INVALID_ARGUMENT,
7943 : : _("Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment "
7944 : : "variable is not set"));
7945 : : }
7946 : : }
7947 : 0 : break;
7948 : :
7949 : 0 : default:
7950 : : g_assert_not_reached ();
7951 : : break;
7952 : : }
7953 : :
7954 : 2918 : out:
7955 : 2918 : return ret;
7956 : : }
7957 : :
7958 : : /* Called in any user thread, without holding locks. */
7959 : : static GDBusConnection *
7960 : 2748 : get_uninitialized_connection (GBusType bus_type,
7961 : : GCancellable *cancellable,
7962 : : GError **error)
7963 : : {
7964 : : GWeakRef *singleton;
7965 : : GDBusConnection *ret;
7966 : :
7967 : 2748 : ret = NULL;
7968 : :
7969 : 2748 : G_LOCK (message_bus_lock);
7970 : 2748 : singleton = message_bus_get_singleton (bus_type, error);
7971 : 2748 : if (singleton == NULL)
7972 : 0 : goto out;
7973 : :
7974 : 2748 : ret = g_weak_ref_get (singleton);
7975 : :
7976 : 2748 : if (ret == NULL)
7977 : : {
7978 : : gchar *address;
7979 : 2160 : address = g_dbus_address_get_for_bus_sync (bus_type, cancellable, error);
7980 : 2160 : if (address == NULL)
7981 : 66 : goto out;
7982 : 2094 : ret = g_object_new (G_TYPE_DBUS_CONNECTION,
7983 : : "address", address,
7984 : : "flags", G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT |
7985 : : #ifdef __linux__
7986 : : G_DBUS_CONNECTION_FLAGS_CROSS_NAMESPACE |
7987 : : #endif
7988 : : G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION,
7989 : : "exit-on-close", TRUE,
7990 : : NULL);
7991 : :
7992 : 2094 : g_weak_ref_set (singleton, ret);
7993 : 2094 : g_free (address);
7994 : : }
7995 : :
7996 : 2682 : g_assert (ret != NULL);
7997 : :
7998 : 2748 : out:
7999 : 2748 : G_UNLOCK (message_bus_lock);
8000 : 2748 : return ret;
8001 : : }
8002 : :
8003 : : /* May be called from any thread. Must not hold message_bus_lock. */
8004 : : GDBusConnection *
8005 : 85 : _g_bus_get_singleton_if_exists (GBusType bus_type)
8006 : : {
8007 : : GWeakRef *singleton;
8008 : 85 : GDBusConnection *ret = NULL;
8009 : :
8010 : 85 : G_LOCK (message_bus_lock);
8011 : 85 : singleton = message_bus_get_singleton (bus_type, NULL);
8012 : 85 : if (singleton == NULL)
8013 : 0 : goto out;
8014 : :
8015 : 85 : ret = g_weak_ref_get (singleton);
8016 : :
8017 : 85 : out:
8018 : 85 : G_UNLOCK (message_bus_lock);
8019 : 85 : return ret;
8020 : : }
8021 : :
8022 : : /* May be called from any thread. Must not hold message_bus_lock. */
8023 : : void
8024 : 85 : _g_bus_forget_singleton (GBusType bus_type)
8025 : : {
8026 : : GWeakRef *singleton;
8027 : :
8028 : 85 : G_LOCK (message_bus_lock);
8029 : :
8030 : 85 : singleton = message_bus_get_singleton (bus_type, NULL);
8031 : :
8032 : 85 : if (singleton != NULL)
8033 : 85 : g_weak_ref_set (singleton, NULL);
8034 : :
8035 : 85 : G_UNLOCK (message_bus_lock);
8036 : 85 : }
8037 : :
8038 : : /**
8039 : : * g_bus_get_sync:
8040 : : * @bus_type: a #GBusType
8041 : : * @cancellable: (nullable): a #GCancellable or %NULL
8042 : : * @error: return location for error or %NULL
8043 : : *
8044 : : * Synchronously connects to the message bus specified by @bus_type.
8045 : : * Note that the returned object may shared with other callers,
8046 : : * e.g. if two separate parts of a process calls this function with
8047 : : * the same @bus_type, they will share the same object.
8048 : : *
8049 : : * This is a synchronous failable function. See g_bus_get() and
8050 : : * g_bus_get_finish() for the asynchronous version.
8051 : : *
8052 : : * The returned object is a singleton, that is, shared with other
8053 : : * callers of g_bus_get() and g_bus_get_sync() for @bus_type. In the
8054 : : * event that you need a private message bus connection, use
8055 : : * g_dbus_address_get_for_bus_sync() and
8056 : : * g_dbus_connection_new_for_address() with
8057 : : * G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT and
8058 : : * G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION flags.
8059 : : *
8060 : : * Note that the returned #GDBusConnection object will (usually) have
8061 : : * the #GDBusConnection:exit-on-close property set to %TRUE.
8062 : : *
8063 : : * Returns: (transfer full): a #GDBusConnection or %NULL if @error is set.
8064 : : * Free with g_object_unref().
8065 : : *
8066 : : * Since: 2.26
8067 : : */
8068 : : GDBusConnection *
8069 : 2698 : g_bus_get_sync (GBusType bus_type,
8070 : : GCancellable *cancellable,
8071 : : GError **error)
8072 : : {
8073 : : GDBusConnection *connection;
8074 : :
8075 : 2698 : _g_dbus_initialize ();
8076 : :
8077 : 2698 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
8078 : :
8079 : 2698 : connection = get_uninitialized_connection (bus_type, cancellable, error);
8080 : 2698 : if (connection == NULL)
8081 : 59 : goto out;
8082 : :
8083 : 2639 : if (!g_initable_init (G_INITABLE (connection), cancellable, error))
8084 : : {
8085 : 22 : g_object_unref (connection);
8086 : 22 : connection = NULL;
8087 : : }
8088 : :
8089 : 2617 : out:
8090 : 2698 : return connection;
8091 : : }
8092 : :
8093 : : static void
8094 : 41 : bus_get_async_initable_cb (GObject *source_object,
8095 : : GAsyncResult *res,
8096 : : gpointer user_data)
8097 : : {
8098 : 41 : GTask *task = user_data;
8099 : 41 : GError *error = NULL;
8100 : :
8101 : 41 : if (!g_async_initable_init_finish (G_ASYNC_INITABLE (source_object),
8102 : : res,
8103 : : &error))
8104 : : {
8105 : 1 : g_assert (error != NULL);
8106 : 1 : g_task_return_error (task, error);
8107 : 1 : g_object_unref (source_object);
8108 : : }
8109 : : else
8110 : : {
8111 : 40 : g_task_return_pointer (task, source_object, g_object_unref);
8112 : : }
8113 : 41 : g_object_unref (task);
8114 : 41 : }
8115 : :
8116 : : /**
8117 : : * g_bus_get:
8118 : : * @bus_type: a #GBusType
8119 : : * @cancellable: (nullable): a #GCancellable or %NULL
8120 : : * @callback: a #GAsyncReadyCallback to call when the request is satisfied
8121 : : * @user_data: the data to pass to @callback
8122 : : *
8123 : : * Asynchronously connects to the message bus specified by @bus_type.
8124 : : *
8125 : : * When the operation is finished, @callback will be invoked. You can
8126 : : * then call g_bus_get_finish() to get the result of the operation.
8127 : : *
8128 : : * This is an asynchronous failable function. See g_bus_get_sync() for
8129 : : * the synchronous version.
8130 : : *
8131 : : * Since: 2.26
8132 : : */
8133 : : void
8134 : 50 : g_bus_get (GBusType bus_type,
8135 : : GCancellable *cancellable,
8136 : : GAsyncReadyCallback callback,
8137 : : gpointer user_data)
8138 : : {
8139 : : GDBusConnection *connection;
8140 : : GTask *task;
8141 : 50 : GError *error = NULL;
8142 : :
8143 : 50 : _g_dbus_initialize ();
8144 : :
8145 : 50 : task = g_task_new (NULL, cancellable, callback, user_data);
8146 : 50 : g_task_set_source_tag (task, g_bus_get);
8147 : :
8148 : 50 : connection = get_uninitialized_connection (bus_type, cancellable, &error);
8149 : 50 : if (connection == NULL)
8150 : : {
8151 : 7 : g_assert (error != NULL);
8152 : 7 : g_task_return_error (task, error);
8153 : 7 : g_object_unref (task);
8154 : : }
8155 : : else
8156 : : {
8157 : 43 : g_async_initable_init_async (G_ASYNC_INITABLE (connection),
8158 : : G_PRIORITY_DEFAULT,
8159 : : cancellable,
8160 : : bus_get_async_initable_cb,
8161 : : task);
8162 : : }
8163 : 50 : }
8164 : :
8165 : : /**
8166 : : * g_bus_get_finish:
8167 : : * @res: a #GAsyncResult obtained from the #GAsyncReadyCallback passed
8168 : : * to g_bus_get()
8169 : : * @error: return location for error or %NULL
8170 : : *
8171 : : * Finishes an operation started with g_bus_get().
8172 : : *
8173 : : * The returned object is a singleton, that is, shared with other
8174 : : * callers of g_bus_get() and g_bus_get_sync() for @bus_type. In the
8175 : : * event that you need a private message bus connection, use
8176 : : * g_dbus_address_get_for_bus_sync() and
8177 : : * g_dbus_connection_new_for_address() with
8178 : : * G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT and
8179 : : * G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION flags.
8180 : : *
8181 : : * Note that the returned #GDBusConnection object will (usually) have
8182 : : * the #GDBusConnection:exit-on-close property set to %TRUE.
8183 : : *
8184 : : * Returns: (transfer full): a #GDBusConnection or %NULL if @error is set.
8185 : : * Free with g_object_unref().
8186 : : *
8187 : : * Since: 2.26
8188 : : */
8189 : : GDBusConnection *
8190 : 46 : g_bus_get_finish (GAsyncResult *res,
8191 : : GError **error)
8192 : : {
8193 : 46 : g_return_val_if_fail (g_task_is_valid (res, NULL), NULL);
8194 : 46 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
8195 : :
8196 : 46 : return g_task_propagate_pointer (G_TASK (res), error);
8197 : : }
8198 : :
8199 : : /* ---------------------------------------------------------------------------------------------------- */
|