Coverage Report

Created: 2025-07-18 06:08

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