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