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