Coverage Report

Created: 2025-07-01 07:09

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