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