1/* GDBus - GLib D-Bus Library
2 *
3 * Copyright (C) 2008-2010 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: David Zeuthen <davidz@redhat.com>
19 */
20
21#include "config.h"
22
23#include <stdlib.h>
24
25#include "gdbusutils.h"
26#include "gdbusnameowning.h"
27#include "gdbuserror.h"
28#include "gdbusprivate.h"
29#include "gdbusconnection.h"
30
31#include "glibintl.h"
32
33/**
34 * SECTION:gdbusnameowning
35 * @title: Owning Bus Names
36 * @short_description: Simple API for owning bus names
37 * @include: gio/gio.h
38 *
39 * Convenience API for owning bus names.
40 *
41 * A simple example for owning a name can be found in
42 * [gdbus-example-own-name.c](https://git.gnome.org/browse/glib/tree/gio/tests/gdbus-example-own-name.c)
43 */
44
45G_LOCK_DEFINE_STATIC (lock);
46
47/* ---------------------------------------------------------------------------------------------------- */
48
49typedef enum
50{
51 PREVIOUS_CALL_NONE = 0,
52 PREVIOUS_CALL_ACQUIRED,
53 PREVIOUS_CALL_LOST,
54} PreviousCall;
55
56typedef struct
57{
58 gint ref_count; /* (atomic) */
59 guint id;
60 GBusNameOwnerFlags flags;
61 gchar *name;
62 GBusAcquiredCallback bus_acquired_handler;
63 GBusNameAcquiredCallback name_acquired_handler;
64 GBusNameLostCallback name_lost_handler;
65 gpointer user_data;
66 GDestroyNotify user_data_free_func;
67 GMainContext *main_context;
68
69 PreviousCall previous_call;
70
71 GDBusConnection *connection;
72 gulong disconnected_signal_handler_id;
73 guint name_acquired_subscription_id;
74 guint name_lost_subscription_id;
75
76 gboolean cancelled; /* must hold lock when reading or modifying */
77
78 gboolean needs_release;
79} Client;
80
81static guint next_global_id = 1;
82static GHashTable *map_id_to_client = NULL;
83
84
85static Client *
86client_ref (Client *client)
87{
88 g_atomic_int_inc (&client->ref_count);
89 return client;
90}
91
92static void
93client_unref (Client *client)
94{
95 if (g_atomic_int_dec_and_test (&client->ref_count))
96 {
97 if (client->connection != NULL)
98 {
99 if (client->disconnected_signal_handler_id > 0)
100 g_signal_handler_disconnect (instance: client->connection, handler_id: client->disconnected_signal_handler_id);
101 if (client->name_acquired_subscription_id > 0)
102 g_dbus_connection_signal_unsubscribe (connection: client->connection, subscription_id: client->name_acquired_subscription_id);
103 if (client->name_lost_subscription_id > 0)
104 g_dbus_connection_signal_unsubscribe (connection: client->connection, subscription_id: client->name_lost_subscription_id);
105 g_object_unref (object: client->connection);
106 }
107 g_main_context_unref (context: client->main_context);
108 g_free (mem: client->name);
109 if (client->user_data_free_func != NULL)
110 client->user_data_free_func (client->user_data);
111 g_free (mem: client);
112 }
113}
114
115/* ---------------------------------------------------------------------------------------------------- */
116
117
118typedef enum
119{
120 CALL_TYPE_NAME_ACQUIRED,
121 CALL_TYPE_NAME_LOST
122} CallType;
123
124typedef struct
125{
126 Client *client;
127
128 /* keep this separate because client->connection may
129 * be set to NULL after scheduling the call
130 */
131 GDBusConnection *connection;
132
133 /* set to TRUE to call acquired */
134 CallType call_type;
135} CallHandlerData;
136
137static void
138call_handler_data_free (CallHandlerData *data)
139{
140 if (data->connection != NULL)
141 g_object_unref (object: data->connection);
142 client_unref (client: data->client);
143 g_free (mem: data);
144}
145
146static void
147actually_do_call (Client *client, GDBusConnection *connection, CallType call_type)
148{
149 switch (call_type)
150 {
151 case CALL_TYPE_NAME_ACQUIRED:
152 if (client->name_acquired_handler != NULL)
153 {
154 client->name_acquired_handler (connection,
155 client->name,
156 client->user_data);
157 }
158 break;
159
160 case CALL_TYPE_NAME_LOST:
161 if (client->name_lost_handler != NULL)
162 {
163 client->name_lost_handler (connection,
164 client->name,
165 client->user_data);
166 }
167 break;
168
169 default:
170 g_assert_not_reached ();
171 break;
172 }
173}
174
175static gboolean
176call_in_idle_cb (gpointer _data)
177{
178 CallHandlerData *data = _data;
179 actually_do_call (client: data->client, connection: data->connection, call_type: data->call_type);
180 return FALSE;
181}
182
183static void
184schedule_call_in_idle (Client *client, CallType call_type)
185{
186 CallHandlerData *data;
187 GSource *idle_source;
188
189 data = g_new0 (CallHandlerData, 1);
190 data->client = client_ref (client);
191 data->connection = client->connection != NULL ? g_object_ref (client->connection) : NULL;
192 data->call_type = call_type;
193
194 idle_source = g_idle_source_new ();
195 g_source_set_priority (source: idle_source, G_PRIORITY_HIGH);
196 g_source_set_callback (source: idle_source,
197 func: call_in_idle_cb,
198 data,
199 notify: (GDestroyNotify) call_handler_data_free);
200 g_source_set_name (source: idle_source, name: "[gio, gdbusnameowning.c] call_in_idle_cb");
201 g_source_attach (source: idle_source, context: client->main_context);
202 g_source_unref (source: idle_source);
203}
204
205static void
206do_call (Client *client, CallType call_type)
207{
208 GMainContext *current_context;
209
210 /* only schedule in idle if we're not in the right thread */
211 current_context = g_main_context_ref_thread_default ();
212 if (current_context != client->main_context)
213 schedule_call_in_idle (client, call_type);
214 else
215 actually_do_call (client, connection: client->connection, call_type);
216 g_main_context_unref (context: current_context);
217}
218
219static void
220call_acquired_handler (Client *client)
221{
222 G_LOCK (lock);
223 if (client->previous_call != PREVIOUS_CALL_ACQUIRED)
224 {
225 client->previous_call = PREVIOUS_CALL_ACQUIRED;
226 if (!client->cancelled)
227 {
228 G_UNLOCK (lock);
229 do_call (client, call_type: CALL_TYPE_NAME_ACQUIRED);
230 goto out;
231 }
232 }
233 G_UNLOCK (lock);
234 out:
235 ;
236}
237
238static void
239call_lost_handler (Client *client)
240{
241 G_LOCK (lock);
242 if (client->previous_call != PREVIOUS_CALL_LOST)
243 {
244 client->previous_call = PREVIOUS_CALL_LOST;
245 if (!client->cancelled)
246 {
247 G_UNLOCK (lock);
248 do_call (client, call_type: CALL_TYPE_NAME_LOST);
249 goto out;
250 }
251 }
252 G_UNLOCK (lock);
253 out:
254 ;
255}
256
257/* ---------------------------------------------------------------------------------------------------- */
258
259static void
260on_name_lost_or_acquired (GDBusConnection *connection,
261 const gchar *sender_name,
262 const gchar *object_path,
263 const gchar *interface_name,
264 const gchar *signal_name,
265 GVariant *parameters,
266 gpointer user_data)
267{
268 Client *client = user_data;
269 const gchar *name;
270
271 if (g_strcmp0 (str1: object_path, str2: "/org/freedesktop/DBus") != 0 ||
272 g_strcmp0 (str1: interface_name, str2: "org.freedesktop.DBus") != 0 ||
273 g_strcmp0 (str1: sender_name, str2: "org.freedesktop.DBus") != 0)
274 goto out;
275
276 if (!g_variant_is_of_type (value: parameters, G_VARIANT_TYPE ("(s)")))
277 {
278 g_warning ("%s signal had unexpected signature %s", signal_name,
279 g_variant_get_type_string (parameters));
280 goto out;
281 }
282
283 if (g_strcmp0 (str1: signal_name, str2: "NameLost") == 0)
284 {
285 g_variant_get (value: parameters, format_string: "(&s)", &name);
286 if (g_strcmp0 (str1: name, str2: client->name) == 0)
287 {
288 call_lost_handler (client);
289 }
290 }
291 else if (g_strcmp0 (str1: signal_name, str2: "NameAcquired") == 0)
292 {
293 g_variant_get (value: parameters, format_string: "(&s)", &name);
294 if (g_strcmp0 (str1: name, str2: client->name) == 0)
295 {
296 call_acquired_handler (client);
297 }
298 }
299 out:
300 ;
301}
302
303/* ---------------------------------------------------------------------------------------------------- */
304
305static void
306request_name_cb (GObject *source_object,
307 GAsyncResult *res,
308 gpointer user_data)
309{
310 Client *client = user_data;
311 GVariant *result;
312 guint32 request_name_reply;
313 gboolean unsubscribe;
314
315 request_name_reply = 0;
316 result = NULL;
317
318 /* don't use client->connection - it may be NULL already */
319 result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
320 res,
321 NULL);
322 if (result != NULL)
323 {
324 g_variant_get (value: result, format_string: "(u)", &request_name_reply);
325 g_variant_unref (value: result);
326 }
327
328 unsubscribe = FALSE;
329
330 switch (request_name_reply)
331 {
332 case 1: /* DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER */
333 /* We got the name - now listen for NameLost and NameAcquired */
334 call_acquired_handler (client);
335 break;
336
337 case 2: /* DBUS_REQUEST_NAME_REPLY_IN_QUEUE */
338 /* Waiting in line - listen for NameLost and NameAcquired */
339 call_lost_handler (client);
340 break;
341
342 default:
343 /* assume we couldn't get the name - explicit fallthrough */
344 case 3: /* DBUS_REQUEST_NAME_REPLY_EXISTS */
345 case 4: /* DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER */
346 /* Some other part of the process is already owning the name */
347 call_lost_handler (client);
348 unsubscribe = TRUE;
349 client->needs_release = FALSE;
350 break;
351 }
352
353 /* If we’re not the owner and not in the queue, there’s no point in continuing
354 * to listen to NameAcquired or NameLost. */
355 if (unsubscribe)
356 {
357 GDBusConnection *connection = NULL;
358
359 /* make sure we use a known good Connection object since it may be set to
360 * NULL at any point after being cancelled
361 */
362 G_LOCK (lock);
363 if (!client->cancelled)
364 connection = g_object_ref (client->connection);
365 G_UNLOCK (lock);
366
367 if (connection != NULL)
368 {
369 if (client->name_acquired_subscription_id > 0)
370 g_dbus_connection_signal_unsubscribe (connection: client->connection, subscription_id: client->name_acquired_subscription_id);
371 if (client->name_lost_subscription_id > 0)
372 g_dbus_connection_signal_unsubscribe (connection: client->connection, subscription_id: client->name_lost_subscription_id);
373 client->name_acquired_subscription_id = 0;
374 client->name_lost_subscription_id = 0;
375
376 g_object_unref (object: connection);
377 }
378 }
379
380 client_unref (client);
381}
382
383/* ---------------------------------------------------------------------------------------------------- */
384
385static void
386on_connection_disconnected (GDBusConnection *connection,
387 gboolean remote_peer_vanished,
388 GError *error,
389 gpointer user_data)
390{
391 Client *client = user_data;
392
393 if (client->disconnected_signal_handler_id > 0)
394 g_signal_handler_disconnect (instance: client->connection, handler_id: client->disconnected_signal_handler_id);
395 if (client->name_acquired_subscription_id > 0)
396 g_dbus_connection_signal_unsubscribe (connection: client->connection, subscription_id: client->name_acquired_subscription_id);
397 if (client->name_lost_subscription_id > 0)
398 g_dbus_connection_signal_unsubscribe (connection: client->connection, subscription_id: client->name_lost_subscription_id);
399 g_object_unref (object: client->connection);
400 client->disconnected_signal_handler_id = 0;
401 client->name_acquired_subscription_id = 0;
402 client->name_lost_subscription_id = 0;
403 client->connection = NULL;
404
405 call_lost_handler (client);
406}
407
408/* ---------------------------------------------------------------------------------------------------- */
409
410static void
411has_connection (Client *client)
412{
413 /* listen for disconnection */
414 client->disconnected_signal_handler_id = g_signal_connect (client->connection,
415 "closed",
416 G_CALLBACK (on_connection_disconnected),
417 client);
418
419 /* Start listening to NameLost and NameAcquired messages. We hold
420 * references to the Client in the signal closures, since it’s possible
421 * for a signal to be in-flight after unsubscribing the signal handler.
422 * This creates a reference count cycle, but that’s explicitly broken by
423 * disconnecting the signal handlers before calling client_unref() in
424 * g_bus_unown_name().
425 *
426 * Subscribe to NameLost and NameAcquired before calling RequestName() to
427 * avoid the potential race of losing the name between receiving a reply to
428 * RequestName() and subscribing to NameLost. The #PreviousCall state will
429 * ensure that the user callbacks get called an appropriate number of times. */
430 client->name_lost_subscription_id =
431 g_dbus_connection_signal_subscribe (connection: client->connection,
432 sender: "org.freedesktop.DBus",
433 interface_name: "org.freedesktop.DBus",
434 member: "NameLost",
435 object_path: "/org/freedesktop/DBus",
436 arg0: client->name,
437 flags: G_DBUS_SIGNAL_FLAGS_NONE,
438 callback: on_name_lost_or_acquired,
439 user_data: client_ref (client),
440 user_data_free_func: (GDestroyNotify) client_unref);
441 client->name_acquired_subscription_id =
442 g_dbus_connection_signal_subscribe (connection: client->connection,
443 sender: "org.freedesktop.DBus",
444 interface_name: "org.freedesktop.DBus",
445 member: "NameAcquired",
446 object_path: "/org/freedesktop/DBus",
447 arg0: client->name,
448 flags: G_DBUS_SIGNAL_FLAGS_NONE,
449 callback: on_name_lost_or_acquired,
450 user_data: client_ref (client),
451 user_data_free_func: (GDestroyNotify) client_unref);
452
453 /* attempt to acquire the name */
454 client->needs_release = TRUE;
455 g_dbus_connection_call (connection: client->connection,
456 bus_name: "org.freedesktop.DBus", /* bus name */
457 object_path: "/org/freedesktop/DBus", /* object path */
458 interface_name: "org.freedesktop.DBus", /* interface name */
459 method_name: "RequestName", /* method name */
460 parameters: g_variant_new (format_string: "(su)",
461 client->name,
462 client->flags),
463 G_VARIANT_TYPE ("(u)"),
464 flags: G_DBUS_CALL_FLAGS_NONE,
465 timeout_msec: -1,
466 NULL,
467 callback: (GAsyncReadyCallback) request_name_cb,
468 user_data: client_ref (client));
469}
470
471
472static void
473connection_get_cb (GObject *source_object,
474 GAsyncResult *res,
475 gpointer user_data)
476{
477 Client *client = user_data;
478
479 /* must not do anything if already cancelled */
480 G_LOCK (lock);
481 if (client->cancelled)
482 {
483 G_UNLOCK (lock);
484 goto out;
485 }
486 G_UNLOCK (lock);
487
488 client->connection = g_bus_get_finish (res, NULL);
489 if (client->connection == NULL)
490 {
491 call_lost_handler (client);
492 goto out;
493 }
494
495 /* No need to schedule this in idle as we're already in the thread
496 * that the user called g_bus_own_name() from. This is because
497 * g_bus_get() guarantees that.
498 *
499 * Also, we need to ensure that the handler is invoked *before*
500 * we call RequestName(). Otherwise there is a race.
501 */
502 if (client->bus_acquired_handler != NULL)
503 {
504 client->bus_acquired_handler (client->connection,
505 client->name,
506 client->user_data);
507 }
508
509 has_connection (client);
510
511 out:
512 client_unref (client);
513}
514
515/* ---------------------------------------------------------------------------------------------------- */
516
517/**
518 * g_bus_own_name_on_connection:
519 * @connection: a #GDBusConnection
520 * @name: the well-known name to own
521 * @flags: a set of flags from the #GBusNameOwnerFlags enumeration
522 * @name_acquired_handler: (nullable): handler to invoke when @name is acquired or %NULL
523 * @name_lost_handler: (nullable): handler to invoke when @name is lost or %NULL
524 * @user_data: user data to pass to handlers
525 * @user_data_free_func: (nullable): function for freeing @user_data or %NULL
526 *
527 * Like g_bus_own_name() but takes a #GDBusConnection instead of a
528 * #GBusType.
529 *
530 * Returns: an identifier (never 0) that can be used with
531 * g_bus_unown_name() to stop owning the name
532 *
533 * Since: 2.26
534 */
535guint
536g_bus_own_name_on_connection (GDBusConnection *connection,
537 const gchar *name,
538 GBusNameOwnerFlags flags,
539 GBusNameAcquiredCallback name_acquired_handler,
540 GBusNameLostCallback name_lost_handler,
541 gpointer user_data,
542 GDestroyNotify user_data_free_func)
543{
544 Client *client;
545
546 g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
547 g_return_val_if_fail (g_dbus_is_name (name) && !g_dbus_is_unique_name (name), 0);
548
549 G_LOCK (lock);
550
551 client = g_new0 (Client, 1);
552 client->ref_count = 1;
553 client->id = next_global_id++; /* TODO: uh oh, handle overflow */
554 client->name = g_strdup (str: name);
555 client->flags = flags;
556 client->name_acquired_handler = name_acquired_handler;
557 client->name_lost_handler = name_lost_handler;
558 client->user_data = user_data;
559 client->user_data_free_func = user_data_free_func;
560 client->main_context = g_main_context_ref_thread_default ();
561
562 client->connection = g_object_ref (connection);
563
564 if (map_id_to_client == NULL)
565 {
566 map_id_to_client = g_hash_table_new (hash_func: g_direct_hash, key_equal_func: g_direct_equal);
567 }
568 g_hash_table_insert (hash_table: map_id_to_client,
569 GUINT_TO_POINTER (client->id),
570 value: client);
571
572 G_UNLOCK (lock);
573
574 has_connection (client);
575
576 return client->id;
577}
578
579/**
580 * g_bus_own_name:
581 * @bus_type: the type of bus to own a name on
582 * @name: the well-known name to own
583 * @flags: a set of flags from the #GBusNameOwnerFlags enumeration
584 * @bus_acquired_handler: (nullable): handler to invoke when connected to the bus of type @bus_type or %NULL
585 * @name_acquired_handler: (nullable): handler to invoke when @name is acquired or %NULL
586 * @name_lost_handler: (nullable): handler to invoke when @name is lost or %NULL
587 * @user_data: user data to pass to handlers
588 * @user_data_free_func: (nullable): function for freeing @user_data or %NULL
589 *
590 * Starts acquiring @name on the bus specified by @bus_type and calls
591 * @name_acquired_handler and @name_lost_handler when the name is
592 * acquired respectively lost. Callbacks will be invoked in the
593 * [thread-default main context][g-main-context-push-thread-default]
594 * of the thread you are calling this function from.
595 *
596 * You are guaranteed that one of the @name_acquired_handler and @name_lost_handler
597 * callbacks will be invoked after calling this function - there are three
598 * possible cases:
599 *
600 * - @name_lost_handler with a %NULL connection (if a connection to the bus
601 * can't be made).
602 *
603 * - @bus_acquired_handler then @name_lost_handler (if the name can't be
604 * obtained)
605 *
606 * - @bus_acquired_handler then @name_acquired_handler (if the name was
607 * obtained).
608 *
609 * When you are done owning the name, just call g_bus_unown_name()
610 * with the owner id this function returns.
611 *
612 * If the name is acquired or lost (for example another application
613 * could acquire the name if you allow replacement or the application
614 * currently owning the name exits), the handlers are also invoked.
615 * If the #GDBusConnection that is used for attempting to own the name
616 * closes, then @name_lost_handler is invoked since it is no longer
617 * possible for other processes to access the process.
618 *
619 * You cannot use g_bus_own_name() several times for the same name (unless
620 * interleaved with calls to g_bus_unown_name()) - only the first call
621 * will work.
622 *
623 * Another guarantee is that invocations of @name_acquired_handler
624 * and @name_lost_handler are guaranteed to alternate; that
625 * is, if @name_acquired_handler is invoked then you are
626 * guaranteed that the next time one of the handlers is invoked, it
627 * will be @name_lost_handler. The reverse is also true.
628 *
629 * If you plan on exporting objects (using e.g.
630 * g_dbus_connection_register_object()), note that it is generally too late
631 * to export the objects in @name_acquired_handler. Instead, you can do this
632 * in @bus_acquired_handler since you are guaranteed that this will run
633 * before @name is requested from the bus.
634 *
635 * This behavior makes it very simple to write applications that wants
636 * to [own names][gdbus-owning-names] and export objects.
637 * Simply register objects to be exported in @bus_acquired_handler and
638 * unregister the objects (if any) in @name_lost_handler.
639 *
640 * Returns: an identifier (never 0) that can be used with
641 * g_bus_unown_name() to stop owning the name.
642 *
643 * Since: 2.26
644 */
645guint
646g_bus_own_name (GBusType bus_type,
647 const gchar *name,
648 GBusNameOwnerFlags flags,
649 GBusAcquiredCallback bus_acquired_handler,
650 GBusNameAcquiredCallback name_acquired_handler,
651 GBusNameLostCallback name_lost_handler,
652 gpointer user_data,
653 GDestroyNotify user_data_free_func)
654{
655 Client *client;
656
657 g_return_val_if_fail (g_dbus_is_name (name) && !g_dbus_is_unique_name (name), 0);
658
659 G_LOCK (lock);
660
661 client = g_new0 (Client, 1);
662 client->ref_count = 1;
663 client->id = next_global_id++; /* TODO: uh oh, handle overflow */
664 client->name = g_strdup (str: name);
665 client->flags = flags;
666 client->bus_acquired_handler = bus_acquired_handler;
667 client->name_acquired_handler = name_acquired_handler;
668 client->name_lost_handler = name_lost_handler;
669 client->user_data = user_data;
670 client->user_data_free_func = user_data_free_func;
671 client->main_context = g_main_context_ref_thread_default ();
672
673 if (map_id_to_client == NULL)
674 {
675 map_id_to_client = g_hash_table_new (hash_func: g_direct_hash, key_equal_func: g_direct_equal);
676 }
677 g_hash_table_insert (hash_table: map_id_to_client,
678 GUINT_TO_POINTER (client->id),
679 value: client);
680
681 g_bus_get (bus_type,
682 NULL,
683 callback: connection_get_cb,
684 user_data: client_ref (client));
685
686 G_UNLOCK (lock);
687
688 return client->id;
689}
690
691typedef struct {
692 GClosure *bus_acquired_closure;
693 GClosure *name_acquired_closure;
694 GClosure *name_lost_closure;
695} OwnNameData;
696
697static OwnNameData *
698own_name_data_new (GClosure *bus_acquired_closure,
699 GClosure *name_acquired_closure,
700 GClosure *name_lost_closure)
701{
702 OwnNameData *data;
703
704 data = g_new0 (OwnNameData, 1);
705
706 if (bus_acquired_closure != NULL)
707 {
708 data->bus_acquired_closure = g_closure_ref (closure: bus_acquired_closure);
709 g_closure_sink (closure: bus_acquired_closure);
710 if (G_CLOSURE_NEEDS_MARSHAL (bus_acquired_closure))
711 g_closure_set_marshal (closure: bus_acquired_closure, marshal: g_cclosure_marshal_generic);
712 }
713
714 if (name_acquired_closure != NULL)
715 {
716 data->name_acquired_closure = g_closure_ref (closure: name_acquired_closure);
717 g_closure_sink (closure: name_acquired_closure);
718 if (G_CLOSURE_NEEDS_MARSHAL (name_acquired_closure))
719 g_closure_set_marshal (closure: name_acquired_closure, marshal: g_cclosure_marshal_generic);
720 }
721
722 if (name_lost_closure != NULL)
723 {
724 data->name_lost_closure = g_closure_ref (closure: name_lost_closure);
725 g_closure_sink (closure: name_lost_closure);
726 if (G_CLOSURE_NEEDS_MARSHAL (name_lost_closure))
727 g_closure_set_marshal (closure: name_lost_closure, marshal: g_cclosure_marshal_generic);
728 }
729
730 return data;
731}
732
733static void
734own_with_closures_on_bus_acquired (GDBusConnection *connection,
735 const gchar *name,
736 gpointer user_data)
737{
738 OwnNameData *data = user_data;
739 GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
740
741 g_value_init (value: &params[0], G_TYPE_DBUS_CONNECTION);
742 g_value_set_object (value: &params[0], v_object: connection);
743
744 g_value_init (value: &params[1], G_TYPE_STRING);
745 g_value_set_string (value: &params[1], v_string: name);
746
747 g_closure_invoke (closure: data->bus_acquired_closure, NULL, n_param_values: 2, param_values: params, NULL);
748
749 g_value_unset (value: params + 0);
750 g_value_unset (value: params + 1);
751}
752
753static void
754own_with_closures_on_name_acquired (GDBusConnection *connection,
755 const gchar *name,
756 gpointer user_data)
757{
758 OwnNameData *data = user_data;
759 GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
760
761 g_value_init (value: &params[0], G_TYPE_DBUS_CONNECTION);
762 g_value_set_object (value: &params[0], v_object: connection);
763
764 g_value_init (value: &params[1], G_TYPE_STRING);
765 g_value_set_string (value: &params[1], v_string: name);
766
767 g_closure_invoke (closure: data->name_acquired_closure, NULL, n_param_values: 2, param_values: params, NULL);
768
769 g_value_unset (value: params + 0);
770 g_value_unset (value: params + 1);
771}
772
773static void
774own_with_closures_on_name_lost (GDBusConnection *connection,
775 const gchar *name,
776 gpointer user_data)
777{
778 OwnNameData *data = user_data;
779 GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
780
781 g_value_init (value: &params[0], G_TYPE_DBUS_CONNECTION);
782 g_value_set_object (value: &params[0], v_object: connection);
783
784 g_value_init (value: &params[1], G_TYPE_STRING);
785 g_value_set_string (value: &params[1], v_string: name);
786
787 g_closure_invoke (closure: data->name_lost_closure, NULL, n_param_values: 2, param_values: params, NULL);
788
789 g_value_unset (value: params + 0);
790 g_value_unset (value: params + 1);
791}
792
793static void
794bus_own_name_free_func (gpointer user_data)
795{
796 OwnNameData *data = user_data;
797
798 if (data->bus_acquired_closure != NULL)
799 g_closure_unref (closure: data->bus_acquired_closure);
800
801 if (data->name_acquired_closure != NULL)
802 g_closure_unref (closure: data->name_acquired_closure);
803
804 if (data->name_lost_closure != NULL)
805 g_closure_unref (closure: data->name_lost_closure);
806
807 g_free (mem: data);
808}
809
810/**
811 * g_bus_own_name_with_closures: (rename-to g_bus_own_name)
812 * @bus_type: the type of bus to own a name on
813 * @name: the well-known name to own
814 * @flags: a set of flags from the #GBusNameOwnerFlags enumeration
815 * @bus_acquired_closure: (nullable): #GClosure to invoke when connected to
816 * the bus of type @bus_type or %NULL
817 * @name_acquired_closure: (nullable): #GClosure to invoke when @name is
818 * acquired or %NULL
819 * @name_lost_closure: (nullable): #GClosure to invoke when @name is lost or
820 * %NULL
821 *
822 * Version of g_bus_own_name() using closures instead of callbacks for
823 * easier binding in other languages.
824 *
825 * Returns: an identifier (never 0) that can be used with
826 * g_bus_unown_name() to stop owning the name.
827 *
828 * Since: 2.26
829 */
830guint
831g_bus_own_name_with_closures (GBusType bus_type,
832 const gchar *name,
833 GBusNameOwnerFlags flags,
834 GClosure *bus_acquired_closure,
835 GClosure *name_acquired_closure,
836 GClosure *name_lost_closure)
837{
838 return g_bus_own_name (bus_type,
839 name,
840 flags,
841 bus_acquired_handler: bus_acquired_closure != NULL ? own_with_closures_on_bus_acquired : NULL,
842 name_acquired_handler: name_acquired_closure != NULL ? own_with_closures_on_name_acquired : NULL,
843 name_lost_handler: name_lost_closure != NULL ? own_with_closures_on_name_lost : NULL,
844 user_data: own_name_data_new (bus_acquired_closure,
845 name_acquired_closure,
846 name_lost_closure),
847 user_data_free_func: bus_own_name_free_func);
848}
849
850/**
851 * g_bus_own_name_on_connection_with_closures: (rename-to g_bus_own_name_on_connection)
852 * @connection: a #GDBusConnection
853 * @name: the well-known name to own
854 * @flags: a set of flags from the #GBusNameOwnerFlags enumeration
855 * @name_acquired_closure: (nullable): #GClosure to invoke when @name is
856 * acquired or %NULL
857 * @name_lost_closure: (nullable): #GClosure to invoke when @name is lost
858 * or %NULL
859 *
860 * Version of g_bus_own_name_on_connection() using closures instead of
861 * callbacks for easier binding in other languages.
862 *
863 * Returns: an identifier (never 0) that can be used with
864 * g_bus_unown_name() to stop owning the name.
865 *
866 * Since: 2.26
867 */
868guint
869g_bus_own_name_on_connection_with_closures (GDBusConnection *connection,
870 const gchar *name,
871 GBusNameOwnerFlags flags,
872 GClosure *name_acquired_closure,
873 GClosure *name_lost_closure)
874{
875 return g_bus_own_name_on_connection (connection,
876 name,
877 flags,
878 name_acquired_handler: name_acquired_closure != NULL ? own_with_closures_on_name_acquired : NULL,
879 name_lost_handler: name_lost_closure != NULL ? own_with_closures_on_name_lost : NULL,
880 user_data: own_name_data_new (NULL,
881 name_acquired_closure,
882 name_lost_closure),
883 user_data_free_func: bus_own_name_free_func);
884}
885
886/**
887 * g_bus_unown_name:
888 * @owner_id: an identifier obtained from g_bus_own_name()
889 *
890 * Stops owning a name.
891 *
892 * Note that there may still be D-Bus traffic to process (relating to owning
893 * and unowning the name) in the current thread-default #GMainContext after
894 * this function has returned. You should continue to iterate the #GMainContext
895 * until the #GDestroyNotify function passed to g_bus_own_name() is called, in
896 * order to avoid memory leaks through callbacks queued on the #GMainContext
897 * after it’s stopped being iterated.
898 *
899 * Since: 2.26
900 */
901void
902g_bus_unown_name (guint owner_id)
903{
904 Client *client;
905
906 g_return_if_fail (owner_id > 0);
907
908 client = NULL;
909
910 G_LOCK (lock);
911 if (owner_id == 0 || map_id_to_client == NULL ||
912 (client = g_hash_table_lookup (hash_table: map_id_to_client, GUINT_TO_POINTER (owner_id))) == NULL)
913 {
914 g_warning ("Invalid id %d passed to g_bus_unown_name()", owner_id);
915 goto out;
916 }
917
918 client->cancelled = TRUE;
919 g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (owner_id)));
920
921 out:
922 G_UNLOCK (lock);
923
924 /* do callback without holding lock */
925 if (client != NULL)
926 {
927 /* Release the name if needed */
928 if (client->needs_release &&
929 client->connection != NULL &&
930 !g_dbus_connection_is_closed (connection: client->connection))
931 {
932 GVariant *result;
933 GError *error;
934 guint32 release_name_reply;
935
936 /* TODO: it kinda sucks having to do a sync call to release the name - but if
937 * we don't, then a subsequent grab of the name will make the bus daemon return
938 * IN_QUEUE which will trigger name_lost().
939 *
940 * I believe this is a bug in the bus daemon.
941 */
942 error = NULL;
943 result = g_dbus_connection_call_sync (connection: client->connection,
944 bus_name: "org.freedesktop.DBus", /* bus name */
945 object_path: "/org/freedesktop/DBus", /* object path */
946 interface_name: "org.freedesktop.DBus", /* interface name */
947 method_name: "ReleaseName", /* method name */
948 parameters: g_variant_new (format_string: "(s)", client->name),
949 G_VARIANT_TYPE ("(u)"),
950 flags: G_DBUS_CALL_FLAGS_NONE,
951 timeout_msec: -1,
952 NULL,
953 error: &error);
954 if (result == NULL)
955 {
956 g_warning ("Error releasing name %s: %s", client->name, error->message);
957 g_error_free (error);
958 }
959 else
960 {
961 g_variant_get (value: result, format_string: "(u)", &release_name_reply);
962 if (release_name_reply != 1 /* DBUS_RELEASE_NAME_REPLY_RELEASED */)
963 {
964 g_warning ("Unexpected reply %d when releasing name %s", release_name_reply, client->name);
965 }
966 else
967 {
968 client->needs_release = FALSE;
969 }
970 g_variant_unref (value: result);
971 }
972 }
973
974 if (client->disconnected_signal_handler_id > 0)
975 g_signal_handler_disconnect (instance: client->connection, handler_id: client->disconnected_signal_handler_id);
976 if (client->name_acquired_subscription_id > 0)
977 g_dbus_connection_signal_unsubscribe (connection: client->connection, subscription_id: client->name_acquired_subscription_id);
978 if (client->name_lost_subscription_id > 0)
979 g_dbus_connection_signal_unsubscribe (connection: client->connection, subscription_id: client->name_lost_subscription_id);
980 client->disconnected_signal_handler_id = 0;
981 client->name_acquired_subscription_id = 0;
982 client->name_lost_subscription_id = 0;
983 if (client->connection != NULL)
984 {
985 g_object_unref (object: client->connection);
986 client->connection = NULL;
987 }
988
989 client_unref (client);
990 }
991}
992

source code of gtk/subprojects/glib/gio/gdbusnameowning.c