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