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 : :
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 : 145 : client_ref (Client *client)
77 : : {
78 : 145 : g_atomic_int_inc (&client->ref_count);
79 : 145 : return client;
80 : : }
81 : :
82 : : static void
83 : 149 : client_unref (Client *client)
84 : : {
85 : 149 : if (g_atomic_int_dec_and_test (&client->ref_count))
86 : : {
87 : 25 : if (client->connection != NULL)
88 : : {
89 : 0 : if (client->disconnected_signal_handler_id > 0)
90 : 0 : g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id);
91 : 0 : if (client->name_acquired_subscription_id > 0)
92 : 0 : g_dbus_connection_signal_unsubscribe (client->connection, g_steal_handle_id (&client->name_acquired_subscription_id));
93 : 0 : if (client->name_lost_subscription_id > 0)
94 : 0 : g_dbus_connection_signal_unsubscribe (client->connection, g_steal_handle_id (&client->name_lost_subscription_id));
95 : 0 : g_object_unref (client->connection);
96 : : }
97 : 25 : g_main_context_unref (client->main_context);
98 : 25 : g_free (client->name);
99 : 25 : if (client->user_data_free_func != NULL)
100 : 21 : client->user_data_free_func (client->user_data);
101 : 25 : g_free (client);
102 : : }
103 : 149 : }
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 : 0 : call_handler_data_free (CallHandlerData *data)
129 : : {
130 : 0 : if (data->connection != NULL)
131 : 0 : g_object_unref (data->connection);
132 : 0 : client_unref (data->client);
133 : 0 : g_free (data);
134 : 0 : }
135 : :
136 : : static void
137 : 55 : actually_do_call (Client *client, GDBusConnection *connection, CallType call_type)
138 : : {
139 : 55 : switch (call_type)
140 : : {
141 : 36 : case CALL_TYPE_NAME_ACQUIRED:
142 : 36 : if (client->name_acquired_handler != NULL)
143 : : {
144 : 36 : client->name_acquired_handler (connection,
145 : 36 : client->name,
146 : : client->user_data);
147 : : }
148 : 36 : break;
149 : :
150 : 19 : case CALL_TYPE_NAME_LOST:
151 : 19 : if (client->name_lost_handler != NULL)
152 : : {
153 : 19 : client->name_lost_handler (connection,
154 : 19 : client->name,
155 : : client->user_data);
156 : : }
157 : 13 : break;
158 : :
159 : 0 : default:
160 : : g_assert_not_reached ();
161 : : break;
162 : : }
163 : 49 : }
164 : :
165 : : static gboolean
166 : 0 : call_in_idle_cb (gpointer _data)
167 : : {
168 : 0 : CallHandlerData *data = _data;
169 : 0 : actually_do_call (data->client, data->connection, data->call_type);
170 : 0 : return FALSE;
171 : : }
172 : :
173 : : static void
174 : 0 : schedule_call_in_idle (Client *client, CallType call_type)
175 : : {
176 : : CallHandlerData *data;
177 : : GSource *idle_source;
178 : :
179 : 0 : data = g_new0 (CallHandlerData, 1);
180 : 0 : data->client = client_ref (client);
181 : 0 : data->connection = client->connection != NULL ? g_object_ref (client->connection) : NULL;
182 : 0 : data->call_type = call_type;
183 : :
184 : 0 : idle_source = g_idle_source_new ();
185 : 0 : g_source_set_priority (idle_source, G_PRIORITY_HIGH);
186 : 0 : g_source_set_callback (idle_source,
187 : : call_in_idle_cb,
188 : : data,
189 : : (GDestroyNotify) call_handler_data_free);
190 : 0 : g_source_set_static_name (idle_source, "[gio, gdbusnameowning.c] call_in_idle_cb");
191 : 0 : g_source_attach (idle_source, client->main_context);
192 : 0 : g_source_unref (idle_source);
193 : 0 : }
194 : :
195 : : static void
196 : 55 : 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 : 55 : current_context = g_main_context_ref_thread_default ();
202 : 55 : if (current_context != client->main_context)
203 : 0 : schedule_call_in_idle (client, call_type);
204 : : else
205 : 55 : actually_do_call (client, client->connection, call_type);
206 : 49 : g_main_context_unref (current_context);
207 : 49 : }
208 : :
209 : : static void
210 : 71 : call_acquired_handler (Client *client)
211 : : {
212 : 71 : G_LOCK (lock);
213 : 71 : if (client->previous_call != PREVIOUS_CALL_ACQUIRED)
214 : : {
215 : 36 : client->previous_call = PREVIOUS_CALL_ACQUIRED;
216 : 36 : if (!client->cancelled)
217 : : {
218 : 36 : G_UNLOCK (lock);
219 : 36 : do_call (client, CALL_TYPE_NAME_ACQUIRED);
220 : 36 : goto out;
221 : : }
222 : : }
223 : 35 : G_UNLOCK (lock);
224 : 71 : out:
225 : : ;
226 : 71 : }
227 : :
228 : : static void
229 : 19 : call_lost_handler (Client *client)
230 : : {
231 : 19 : G_LOCK (lock);
232 : 19 : if (client->previous_call != PREVIOUS_CALL_LOST)
233 : : {
234 : 19 : client->previous_call = PREVIOUS_CALL_LOST;
235 : 19 : if (!client->cancelled)
236 : : {
237 : 19 : G_UNLOCK (lock);
238 : 19 : do_call (client, CALL_TYPE_NAME_LOST);
239 : 13 : goto out;
240 : : }
241 : : }
242 : 0 : G_UNLOCK (lock);
243 : 13 : out:
244 : : ;
245 : 13 : }
246 : :
247 : : /* ---------------------------------------------------------------------------------------------------- */
248 : :
249 : : static void
250 : 37 : 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 : 37 : Client *client = user_data;
259 : : const gchar *name;
260 : :
261 : 74 : if (g_strcmp0 (object_path, DBUS_PATH_DBUS) != 0 ||
262 : 74 : g_strcmp0 (interface_name, DBUS_INTERFACE_DBUS) != 0 ||
263 : 37 : g_strcmp0 (sender_name, DBUS_SERVICE_DBUS) != 0)
264 : 0 : goto out;
265 : :
266 : 37 : if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(s)")))
267 : : {
268 : 0 : g_warning ("%s signal had unexpected signature %s", signal_name,
269 : : g_variant_get_type_string (parameters));
270 : 0 : goto out;
271 : : }
272 : :
273 : 37 : if (g_strcmp0 (signal_name, "NameLost") == 0)
274 : : {
275 : 1 : g_variant_get (parameters, "(&s)", &name);
276 : 1 : if (g_strcmp0 (name, client->name) == 0)
277 : : {
278 : 1 : call_lost_handler (client);
279 : : }
280 : : }
281 : 36 : else if (g_strcmp0 (signal_name, "NameAcquired") == 0)
282 : : {
283 : 36 : g_variant_get (parameters, "(&s)", &name);
284 : 36 : if (g_strcmp0 (name, client->name) == 0)
285 : : {
286 : 36 : call_acquired_handler (client);
287 : : }
288 : : }
289 : 0 : out:
290 : : ;
291 : 37 : }
292 : :
293 : : /* ---------------------------------------------------------------------------------------------------- */
294 : :
295 : : static void
296 : 39 : request_name_cb (GObject *source_object,
297 : : GAsyncResult *res,
298 : : gpointer user_data)
299 : : {
300 : 39 : Client *client = user_data;
301 : : GVariant *result;
302 : : guint32 request_name_reply;
303 : : gboolean unsubscribe;
304 : :
305 : 39 : request_name_reply = 0;
306 : 39 : result = NULL;
307 : :
308 : : /* don't use client->connection - it may be NULL already */
309 : 39 : result = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object),
310 : : res,
311 : : NULL);
312 : 39 : if (result != NULL)
313 : : {
314 : 39 : g_variant_get (result, "(u)", &request_name_reply);
315 : 39 : g_variant_unref (result);
316 : : }
317 : :
318 : 39 : unsubscribe = FALSE;
319 : :
320 : 39 : switch (request_name_reply)
321 : : {
322 : 35 : case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
323 : : /* We got the name - now listen for NameLost and NameAcquired */
324 : 35 : call_acquired_handler (client);
325 : 35 : break;
326 : :
327 : 3 : case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
328 : : /* Waiting in line - listen for NameLost and NameAcquired */
329 : 3 : call_lost_handler (client);
330 : 3 : break;
331 : :
332 : 1 : default:
333 : : /* assume we couldn't get the name - explicit fallthrough */
334 : : case DBUS_REQUEST_NAME_REPLY_EXISTS:
335 : : case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
336 : : /* Some other part of the process is already owning the name */
337 : 1 : call_lost_handler (client);
338 : 1 : unsubscribe = TRUE;
339 : 1 : client->needs_release = FALSE;
340 : 1 : 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 : 39 : if (unsubscribe)
346 : : {
347 : 1 : 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 : 1 : G_LOCK (lock);
353 : 1 : if (!client->cancelled)
354 : 1 : connection = g_object_ref (client->connection);
355 : 1 : G_UNLOCK (lock);
356 : :
357 : 1 : if (connection != NULL)
358 : : {
359 : 1 : if (client->name_acquired_subscription_id > 0)
360 : 1 : g_dbus_connection_signal_unsubscribe (client->connection, g_steal_handle_id (&client->name_acquired_subscription_id));
361 : 1 : if (client->name_lost_subscription_id > 0)
362 : 1 : g_dbus_connection_signal_unsubscribe (client->connection, g_steal_handle_id (&client->name_lost_subscription_id));
363 : :
364 : 1 : g_object_unref (connection);
365 : : }
366 : : }
367 : :
368 : 39 : client_unref (client);
369 : 39 : }
370 : :
371 : : /* ---------------------------------------------------------------------------------------------------- */
372 : :
373 : : static void
374 : 13 : on_connection_disconnected (GDBusConnection *connection,
375 : : gboolean remote_peer_vanished,
376 : : GError *error,
377 : : gpointer user_data)
378 : : {
379 : 13 : Client *client = user_data;
380 : :
381 : 13 : if (client->disconnected_signal_handler_id > 0)
382 : 13 : g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id);
383 : 13 : if (client->name_acquired_subscription_id > 0)
384 : 13 : g_dbus_connection_signal_unsubscribe (client->connection, g_steal_handle_id (&client->name_acquired_subscription_id));
385 : 13 : if (client->name_lost_subscription_id > 0)
386 : 13 : g_dbus_connection_signal_unsubscribe (client->connection, g_steal_handle_id (&client->name_lost_subscription_id));
387 : 13 : g_object_unref (client->connection);
388 : 13 : client->disconnected_signal_handler_id = 0;
389 : 13 : client->connection = NULL;
390 : :
391 : 13 : call_lost_handler (client);
392 : 7 : }
393 : :
394 : : /* ---------------------------------------------------------------------------------------------------- */
395 : :
396 : : static void
397 : 39 : has_connection (Client *client)
398 : : {
399 : : /* listen for disconnection */
400 : 39 : client->disconnected_signal_handler_id = g_signal_connect (client->connection,
401 : : "closed",
402 : : G_CALLBACK (on_connection_disconnected),
403 : : client);
404 : :
405 : : /* Start listening to NameLost and NameAcquired messages. We hold
406 : : * references to the Client in the signal closures, since it’s possible
407 : : * for a signal to be in-flight after unsubscribing the signal handler.
408 : : * This creates a reference count cycle, but that’s explicitly broken by
409 : : * disconnecting the signal handlers before calling client_unref() in
410 : : * g_bus_unown_name().
411 : : *
412 : : * Subscribe to NameLost and NameAcquired before calling RequestName() to
413 : : * avoid the potential race of losing the name between receiving a reply to
414 : : * RequestName() and subscribing to NameLost. The #PreviousCall state will
415 : : * ensure that the user callbacks get called an appropriate number of times. */
416 : 39 : client->name_lost_subscription_id =
417 : 39 : g_dbus_connection_signal_subscribe (client->connection,
418 : : DBUS_SERVICE_DBUS,
419 : : DBUS_INTERFACE_DBUS,
420 : : "NameLost",
421 : : DBUS_PATH_DBUS,
422 : 39 : client->name,
423 : : G_DBUS_SIGNAL_FLAGS_NONE,
424 : : on_name_lost_or_acquired,
425 : 39 : client_ref (client),
426 : : (GDestroyNotify) client_unref);
427 : 39 : client->name_acquired_subscription_id =
428 : 39 : g_dbus_connection_signal_subscribe (client->connection,
429 : : DBUS_SERVICE_DBUS,
430 : : DBUS_INTERFACE_DBUS,
431 : : "NameAcquired",
432 : : DBUS_PATH_DBUS,
433 : 39 : client->name,
434 : : G_DBUS_SIGNAL_FLAGS_NONE,
435 : : on_name_lost_or_acquired,
436 : 39 : client_ref (client),
437 : : (GDestroyNotify) client_unref);
438 : :
439 : : /* attempt to acquire the name */
440 : 39 : client->needs_release = TRUE;
441 : 78 : g_dbus_connection_call (client->connection,
442 : : DBUS_SERVICE_DBUS,
443 : : DBUS_PATH_DBUS,
444 : : DBUS_INTERFACE_DBUS,
445 : : "RequestName", /* method name */
446 : : g_variant_new ("(su)",
447 : : client->name,
448 : 39 : client->flags),
449 : : G_VARIANT_TYPE ("(u)"),
450 : : G_DBUS_CALL_FLAGS_NONE,
451 : : -1,
452 : : NULL,
453 : : (GAsyncReadyCallback) request_name_cb,
454 : 39 : client_ref (client));
455 : 39 : }
456 : :
457 : :
458 : : static void
459 : 28 : connection_get_cb (GObject *source_object,
460 : : GAsyncResult *res,
461 : : gpointer user_data)
462 : : {
463 : 28 : Client *client = user_data;
464 : :
465 : : /* must not do anything if already cancelled */
466 : 28 : G_LOCK (lock);
467 : 28 : if (client->cancelled)
468 : : {
469 : 1 : G_UNLOCK (lock);
470 : 1 : goto out;
471 : : }
472 : 27 : G_UNLOCK (lock);
473 : :
474 : 27 : client->connection = g_bus_get_finish (res, NULL);
475 : 27 : if (client->connection == NULL)
476 : : {
477 : 1 : call_lost_handler (client);
478 : 1 : goto out;
479 : : }
480 : :
481 : : /* No need to schedule this in idle as we're already in the thread
482 : : * that the user called g_bus_own_name() from. This is because
483 : : * g_bus_get() guarantees that.
484 : : *
485 : : * Also, we need to ensure that the handler is invoked *before*
486 : : * we call RequestName(). Otherwise there is a race.
487 : : */
488 : 26 : if (client->bus_acquired_handler != NULL)
489 : : {
490 : 26 : client->bus_acquired_handler (client->connection,
491 : 26 : client->name,
492 : : client->user_data);
493 : : }
494 : :
495 : 26 : has_connection (client);
496 : :
497 : 28 : out:
498 : 28 : client_unref (client);
499 : 28 : }
500 : :
501 : : /* ---------------------------------------------------------------------------------------------------- */
502 : :
503 : : /**
504 : : * g_bus_own_name_on_connection:
505 : : * @connection: a #GDBusConnection
506 : : * @name: the well-known name to own
507 : : * @flags: a set of flags from the #GBusNameOwnerFlags enumeration
508 : : * @name_acquired_handler: (nullable) (scope notified): handler to invoke when
509 : : * @name is acquired or %NULL
510 : : * @name_lost_handler: (nullable) (scope notified): handler to invoke when @name
511 : : * is lost or %NULL
512 : : * @user_data: user data to pass to handlers
513 : : * @user_data_free_func: (nullable): function for freeing @user_data or %NULL
514 : : *
515 : : * Like g_bus_own_name() but takes a #GDBusConnection instead of a
516 : : * #GBusType.
517 : : *
518 : : * Returns: an identifier (never 0) that can be used with
519 : : * g_bus_unown_name() to stop owning the name
520 : : *
521 : : * Since: 2.26
522 : : */
523 : : guint
524 : 13 : 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 : 13 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
535 : 13 : g_return_val_if_fail (g_dbus_is_name (name) && !g_dbus_is_unique_name (name), 0);
536 : :
537 : 13 : G_LOCK (lock);
538 : :
539 : 13 : client = g_new0 (Client, 1);
540 : 13 : client->ref_count = 1;
541 : 13 : client->id = next_global_id++; /* TODO: uh oh, handle overflow */
542 : 13 : client->name = g_strdup (name);
543 : 13 : client->flags = flags;
544 : 13 : client->name_acquired_handler = name_acquired_handler;
545 : 13 : client->name_lost_handler = name_lost_handler;
546 : 13 : client->user_data = user_data;
547 : 13 : client->user_data_free_func = user_data_free_func;
548 : 13 : client->main_context = g_main_context_ref_thread_default ();
549 : :
550 : 13 : client->connection = g_object_ref (connection);
551 : :
552 : 13 : if (map_id_to_client == NULL)
553 : : {
554 : 2 : map_id_to_client = g_hash_table_new (g_direct_hash, g_direct_equal);
555 : : }
556 : 13 : g_hash_table_insert (map_id_to_client,
557 : 13 : GUINT_TO_POINTER (client->id),
558 : : client);
559 : :
560 : 13 : G_UNLOCK (lock);
561 : :
562 : 13 : has_connection (client);
563 : :
564 : 13 : return client->id;
565 : : }
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 from the #GBusNameOwnerFlags enumeration
572 : : * @bus_acquired_handler: (nullable) (scope notified): handler to invoke when
573 : : * connected to the bus of type @bus_type or %NULL
574 : : * @name_acquired_handler: (nullable) (scope notified): handler to invoke when
575 : : * @name is acquired or %NULL
576 : : * @name_lost_handler: (nullable) (scope notified): handler to invoke when @name
577 : : * is lost or %NULL
578 : : * @user_data: user data to pass to handlers
579 : : * @user_data_free_func: (nullable): function for freeing @user_data or %NULL
580 : : *
581 : : * Starts acquiring @name on the bus specified by @bus_type and calls
582 : : * @name_acquired_handler and @name_lost_handler when the name is
583 : : * acquired respectively lost. Callbacks will be invoked in the
584 : : * [thread-default main context][g-main-context-push-thread-default]
585 : : * of the thread you are calling this function from.
586 : : *
587 : : * You are guaranteed that one of the @name_acquired_handler and @name_lost_handler
588 : : * callbacks will be invoked after calling this function - there are three
589 : : * possible cases:
590 : : *
591 : : * - @name_lost_handler with a %NULL connection (if a connection to the bus
592 : : * can't be made).
593 : : *
594 : : * - @bus_acquired_handler then @name_lost_handler (if the name can't be
595 : : * obtained)
596 : : *
597 : : * - @bus_acquired_handler then @name_acquired_handler (if the name was
598 : : * obtained).
599 : : *
600 : : * When you are done owning the name, just call g_bus_unown_name()
601 : : * with the owner id this function returns.
602 : : *
603 : : * If the name is acquired or lost (for example another application
604 : : * could acquire the name if you allow replacement or the application
605 : : * currently owning the name exits), the handlers are also invoked.
606 : : * If the #GDBusConnection that is used for attempting to own the name
607 : : * closes, then @name_lost_handler is invoked since it is no longer
608 : : * possible for other processes to access the process.
609 : : *
610 : : * You cannot use g_bus_own_name() several times for the same name (unless
611 : : * interleaved with calls to g_bus_unown_name()) - only the first call
612 : : * will work.
613 : : *
614 : : * Another guarantee is that invocations of @name_acquired_handler
615 : : * and @name_lost_handler are guaranteed to alternate; that
616 : : * is, if @name_acquired_handler is invoked then you are
617 : : * guaranteed that the next time one of the handlers is invoked, it
618 : : * will be @name_lost_handler. The reverse is also true.
619 : : *
620 : : * If you plan on exporting objects (using e.g.
621 : : * g_dbus_connection_register_object()), note that it is generally too late
622 : : * to export the objects in @name_acquired_handler. Instead, you can do this
623 : : * in @bus_acquired_handler since you are guaranteed that this will run
624 : : * before @name is requested from the bus.
625 : : *
626 : : * This behavior makes it very simple to write applications that wants
627 : : * to [own names][gdbus-owning-names] and export objects.
628 : : * Simply register objects to be exported in @bus_acquired_handler and
629 : : * unregister the objects (if any) in @name_lost_handler.
630 : : *
631 : : * Returns: an identifier (never 0) that can be used with
632 : : * g_bus_unown_name() to stop owning the name.
633 : : *
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 : : }
668 : 28 : g_hash_table_insert (map_id_to_client,
669 : 28 : GUINT_TO_POINTER (client->id),
670 : : 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 : : }
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 : : }
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 : : }
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 : : }
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 from the #GBusNameOwnerFlags enumeration
806 : : * @bus_acquired_closure: (nullable): #GClosure to invoke when connected to
807 : : * the bus of type @bus_type or %NULL
808 : : * @name_acquired_closure: (nullable): #GClosure to invoke when @name is
809 : : * acquired or %NULL
810 : : * @name_lost_closure: (nullable): #GClosure to invoke when @name is lost or
811 : : * %NULL
812 : : *
813 : : * Version of g_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 : : * g_bus_unown_name() to stop owning the name.
818 : : *
819 : : * Since: 2.26
820 : : */
821 : : guint
822 : 1 : g_bus_own_name_with_closures (GBusType bus_type,
823 : : const gchar *name,
824 : : GBusNameOwnerFlags flags,
825 : : GClosure *bus_acquired_closure,
826 : : GClosure *name_acquired_closure,
827 : : GClosure *name_lost_closure)
828 : : {
829 : 1 : return g_bus_own_name (bus_type,
830 : : name,
831 : : flags,
832 : : bus_acquired_closure != NULL ? own_with_closures_on_bus_acquired : NULL,
833 : : name_acquired_closure != NULL ? own_with_closures_on_name_acquired : NULL,
834 : : name_lost_closure != NULL ? own_with_closures_on_name_lost : NULL,
835 : 1 : own_name_data_new (bus_acquired_closure,
836 : : name_acquired_closure,
837 : : name_lost_closure),
838 : : bus_own_name_free_func);
839 : : }
840 : :
841 : : /**
842 : : * g_bus_own_name_on_connection_with_closures: (rename-to g_bus_own_name_on_connection)
843 : : * @connection: a #GDBusConnection
844 : : * @name: the well-known name to own
845 : : * @flags: a set of flags from the #GBusNameOwnerFlags enumeration
846 : : * @name_acquired_closure: (nullable): #GClosure to invoke when @name is
847 : : * acquired or %NULL
848 : : * @name_lost_closure: (nullable): #GClosure to invoke when @name is lost
849 : : * or %NULL
850 : : *
851 : : * Version of g_bus_own_name_on_connection() using closures instead of
852 : : * callbacks for easier binding in other languages.
853 : : *
854 : : * Returns: an identifier (never 0) that can be used with
855 : : * g_bus_unown_name() to stop owning the name.
856 : : *
857 : : * Since: 2.26
858 : : */
859 : : guint
860 : 0 : g_bus_own_name_on_connection_with_closures (GDBusConnection *connection,
861 : : const gchar *name,
862 : : GBusNameOwnerFlags flags,
863 : : GClosure *name_acquired_closure,
864 : : GClosure *name_lost_closure)
865 : : {
866 : 0 : return g_bus_own_name_on_connection (connection,
867 : : name,
868 : : flags,
869 : : name_acquired_closure != NULL ? own_with_closures_on_name_acquired : NULL,
870 : : name_lost_closure != NULL ? own_with_closures_on_name_lost : NULL,
871 : 0 : own_name_data_new (NULL,
872 : : name_acquired_closure,
873 : : name_lost_closure),
874 : : bus_own_name_free_func);
875 : : }
876 : :
877 : : /**
878 : : * g_bus_unown_name:
879 : : * @owner_id: an identifier obtained from g_bus_own_name()
880 : : *
881 : : * Stops owning a name.
882 : : *
883 : : * Note that there may still be D-Bus traffic to process (relating to owning
884 : : * and unowning the name) in the current thread-default #GMainContext after
885 : : * this function has returned. You should continue to iterate the #GMainContext
886 : : * until the #GDestroyNotify function passed to g_bus_own_name() is called, in
887 : : * order to avoid memory leaks through callbacks queued on the #GMainContext
888 : : * after it’s stopped being iterated.
889 : : *
890 : : * Since: 2.26
891 : : */
892 : : void
893 : 35 : g_bus_unown_name (guint owner_id)
894 : : {
895 : : Client *client;
896 : :
897 : 35 : g_return_if_fail (owner_id > 0);
898 : :
899 : 35 : client = NULL;
900 : :
901 : 35 : G_LOCK (lock);
902 : 70 : if (owner_id == 0 || map_id_to_client == NULL ||
903 : 35 : (client = g_hash_table_lookup (map_id_to_client, GUINT_TO_POINTER (owner_id))) == NULL)
904 : : {
905 : 0 : g_warning ("Invalid id %d passed to g_bus_unown_name()", owner_id);
906 : 0 : goto out;
907 : : }
908 : :
909 : 35 : client->cancelled = TRUE;
910 : 35 : g_warn_if_fail (g_hash_table_remove (map_id_to_client, GUINT_TO_POINTER (owner_id)));
911 : :
912 : 35 : out:
913 : 35 : G_UNLOCK (lock);
914 : :
915 : : /* do callback without holding lock */
916 : 35 : if (client != NULL)
917 : : {
918 : : /* Release the name if needed */
919 : 35 : if (client->needs_release &&
920 : 57 : client->connection != NULL &&
921 : 25 : !g_dbus_connection_is_closed (client->connection))
922 : : {
923 : : GVariant *result;
924 : : GError *error;
925 : : guint32 release_name_reply;
926 : :
927 : : /* TODO: it kinda sucks having to do a sync call to release the name - but if
928 : : * we don't, then a subsequent grab of the name will make the bus daemon return
929 : : * IN_QUEUE which will trigger name_lost().
930 : : *
931 : : * I believe this is a bug in the bus daemon.
932 : : */
933 : 25 : error = NULL;
934 : 25 : result = g_dbus_connection_call_sync (client->connection,
935 : : DBUS_SERVICE_DBUS,
936 : : DBUS_PATH_DBUS,
937 : : DBUS_INTERFACE_DBUS,
938 : : "ReleaseName", /* method name */
939 : : g_variant_new ("(s)", client->name),
940 : : G_VARIANT_TYPE ("(u)"),
941 : : G_DBUS_CALL_FLAGS_NONE,
942 : : -1,
943 : : NULL,
944 : : &error);
945 : 25 : if (result == NULL)
946 : : {
947 : 0 : g_warning ("Error releasing name %s: %s", client->name, error->message);
948 : 0 : g_error_free (error);
949 : : }
950 : : else
951 : : {
952 : 25 : g_variant_get (result, "(u)", &release_name_reply);
953 : 25 : 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 : : }
957 : : else
958 : : {
959 : 25 : client->needs_release = FALSE;
960 : : }
961 : 25 : g_variant_unref (result);
962 : : }
963 : : }
964 : :
965 : 35 : if (client->disconnected_signal_handler_id > 0)
966 : 26 : g_signal_handler_disconnect (client->connection, client->disconnected_signal_handler_id);
967 : 35 : if (client->name_acquired_subscription_id > 0)
968 : 25 : g_dbus_connection_signal_unsubscribe (client->connection, g_steal_handle_id (&client->name_acquired_subscription_id));
969 : 35 : if (client->name_lost_subscription_id > 0)
970 : 25 : g_dbus_connection_signal_unsubscribe (client->connection, g_steal_handle_id (&client->name_lost_subscription_id));
971 : 35 : client->disconnected_signal_handler_id = 0;
972 : 35 : if (client->connection != NULL)
973 : : {
974 : 26 : g_object_unref (client->connection);
975 : 26 : client->connection = NULL;
976 : : }
977 : :
978 : 35 : client_unref (client);
979 : : }
980 : : }
|