1/* GDBus - GLib D-Bus Library
2 *
3 * Copyright (C) 2008-2010 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: David Zeuthen <davidz@redhat.com>
19 */
20
21#include "config.h"
22
23#include "gdbusobjectmanager.h"
24#include "gdbusobjectmanagerserver.h"
25#include "gdbusobject.h"
26#include "gdbusobjectskeleton.h"
27#include "gdbusinterfaceskeleton.h"
28#include "gdbusconnection.h"
29#include "gdbusintrospection.h"
30#include "gdbusmethodinvocation.h"
31#include "gdbuserror.h"
32
33#include "gioerror.h"
34
35#include "glibintl.h"
36
37/**
38 * SECTION:gdbusobjectmanagerserver
39 * @short_description: Service-side object manager
40 * @include: gio/gio.h
41 *
42 * #GDBusObjectManagerServer is used to export #GDBusObject instances using
43 * the standardized
44 * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
45 * interface. For example, remote D-Bus clients can get all objects
46 * and properties in a single call. Additionally, any change in the
47 * object hierarchy is broadcast using signals. This means that D-Bus
48 * clients can keep caches up to date by only listening to D-Bus
49 * signals.
50 *
51 * The recommended path to export an object manager at is the path form of the
52 * well-known name of a D-Bus service, or below. For example, if a D-Bus service
53 * is available at the well-known name `net.example.ExampleService1`, the object
54 * manager should typically be exported at `/net/example/ExampleService1`, or
55 * below (to allow for multiple object managers in a service).
56 *
57 * It is supported, but not recommended, to export an object manager at the root
58 * path, `/`.
59 *
60 * See #GDBusObjectManagerClient for the client-side code that is
61 * intended to be used with #GDBusObjectManagerServer or any D-Bus
62 * object implementing the org.freedesktop.DBus.ObjectManager
63 * interface.
64 */
65
66typedef struct
67{
68 GDBusObjectSkeleton *object;
69 GDBusObjectManagerServer *manager;
70 GHashTable *map_iface_name_to_iface;
71 gboolean exported;
72} RegistrationData;
73
74static void registration_data_free (RegistrationData *data);
75
76static void export_all (GDBusObjectManagerServer *manager);
77static void unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager);
78
79static void g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager,
80 RegistrationData *data,
81 const gchar *const *interfaces,
82 const gchar *object_path);
83
84static void g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
85 RegistrationData *data,
86 const gchar *const *interfaces);
87
88static gboolean g_dbus_object_manager_server_unexport_unlocked (GDBusObjectManagerServer *manager,
89 const gchar *object_path);
90
91struct _GDBusObjectManagerServerPrivate
92{
93 GMutex lock;
94 GDBusConnection *connection;
95 gchar *object_path;
96 gchar *object_path_ending_in_slash;
97 GHashTable *map_object_path_to_data;
98 guint manager_reg_id;
99};
100
101enum
102{
103 PROP_0,
104 PROP_CONNECTION,
105 PROP_OBJECT_PATH
106};
107
108static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
109
110G_DEFINE_TYPE_WITH_CODE (GDBusObjectManagerServer, g_dbus_object_manager_server, G_TYPE_OBJECT,
111 G_ADD_PRIVATE (GDBusObjectManagerServer)
112 G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT_MANAGER, dbus_object_manager_interface_init))
113
114static void g_dbus_object_manager_server_constructed (GObject *object);
115
116static void
117g_dbus_object_manager_server_finalize (GObject *object)
118{
119 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
120
121 if (manager->priv->connection != NULL)
122 {
123 unexport_all (manager, TRUE);
124 g_object_unref (object: manager->priv->connection);
125 }
126 g_hash_table_unref (hash_table: manager->priv->map_object_path_to_data);
127 g_free (mem: manager->priv->object_path);
128 g_free (mem: manager->priv->object_path_ending_in_slash);
129
130 g_mutex_clear (mutex: &manager->priv->lock);
131
132 if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize != NULL)
133 G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->finalize (object);
134}
135
136static void
137g_dbus_object_manager_server_get_property (GObject *object,
138 guint prop_id,
139 GValue *value,
140 GParamSpec *pspec)
141{
142 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
143
144 switch (prop_id)
145 {
146 case PROP_CONNECTION:
147 g_mutex_lock (mutex: &manager->priv->lock);
148 g_value_set_object (value, v_object: manager->priv->connection);
149 g_mutex_unlock (mutex: &manager->priv->lock);
150 break;
151
152 case PROP_OBJECT_PATH:
153 g_value_set_string (value, v_string: g_dbus_object_manager_get_object_path (G_DBUS_OBJECT_MANAGER (manager)));
154 break;
155
156 default:
157 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
158 break;
159 }
160}
161
162static void
163g_dbus_object_manager_server_set_property (GObject *object,
164 guint prop_id,
165 const GValue *value,
166 GParamSpec *pspec)
167{
168 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
169
170 switch (prop_id)
171 {
172 case PROP_CONNECTION:
173 g_dbus_object_manager_server_set_connection (manager, connection: g_value_get_object (value));
174 break;
175
176 case PROP_OBJECT_PATH:
177 g_assert (manager->priv->object_path == NULL);
178 g_assert (g_variant_is_object_path (g_value_get_string (value)));
179 manager->priv->object_path = g_value_dup_string (value);
180 if (g_str_equal (v1: manager->priv->object_path, v2: "/"))
181 manager->priv->object_path_ending_in_slash = g_strdup (str: manager->priv->object_path);
182 else
183 manager->priv->object_path_ending_in_slash = g_strdup_printf (format: "%s/", manager->priv->object_path);
184 break;
185
186 default:
187 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
188 break;
189 }
190}
191
192static void
193g_dbus_object_manager_server_class_init (GDBusObjectManagerServerClass *klass)
194{
195 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
196
197 gobject_class->finalize = g_dbus_object_manager_server_finalize;
198 gobject_class->constructed = g_dbus_object_manager_server_constructed;
199 gobject_class->set_property = g_dbus_object_manager_server_set_property;
200 gobject_class->get_property = g_dbus_object_manager_server_get_property;
201
202 /**
203 * GDBusObjectManagerServer:connection:
204 *
205 * The #GDBusConnection to export objects on.
206 *
207 * Since: 2.30
208 */
209 g_object_class_install_property (oclass: gobject_class,
210 property_id: PROP_CONNECTION,
211 pspec: g_param_spec_object (name: "connection",
212 nick: "Connection",
213 blurb: "The connection to export objects on",
214 G_TYPE_DBUS_CONNECTION,
215 flags: G_PARAM_READABLE |
216 G_PARAM_WRITABLE |
217 G_PARAM_STATIC_STRINGS));
218
219 /**
220 * GDBusObjectManagerServer:object-path:
221 *
222 * The object path to register the manager object at.
223 *
224 * Since: 2.30
225 */
226 g_object_class_install_property (oclass: gobject_class,
227 property_id: PROP_OBJECT_PATH,
228 pspec: g_param_spec_string (name: "object-path",
229 nick: "Object Path",
230 blurb: "The object path to register the manager object at",
231 NULL,
232 flags: G_PARAM_READABLE |
233 G_PARAM_WRITABLE |
234 G_PARAM_CONSTRUCT_ONLY |
235 G_PARAM_STATIC_STRINGS));
236}
237
238static void
239g_dbus_object_manager_server_init (GDBusObjectManagerServer *manager)
240{
241 manager->priv = g_dbus_object_manager_server_get_instance_private (self: manager);
242 g_mutex_init (mutex: &manager->priv->lock);
243 manager->priv->map_object_path_to_data = g_hash_table_new_full (hash_func: g_str_hash,
244 key_equal_func: g_str_equal,
245 key_destroy_func: g_free,
246 value_destroy_func: (GDestroyNotify) registration_data_free);
247}
248
249/**
250 * g_dbus_object_manager_server_new:
251 * @object_path: The object path to export the manager object at.
252 *
253 * Creates a new #GDBusObjectManagerServer object.
254 *
255 * The returned server isn't yet exported on any connection. To do so,
256 * use g_dbus_object_manager_server_set_connection(). Normally you
257 * want to export all of your objects before doing so to avoid
258 * [InterfacesAdded](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager)
259 * signals being emitted.
260 *
261 * Returns: A #GDBusObjectManagerServer object. Free with g_object_unref().
262 *
263 * Since: 2.30
264 */
265GDBusObjectManagerServer *
266g_dbus_object_manager_server_new (const gchar *object_path)
267{
268 g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
269 return G_DBUS_OBJECT_MANAGER_SERVER (g_object_new (G_TYPE_DBUS_OBJECT_MANAGER_SERVER,
270 "object-path", object_path,
271 NULL));
272}
273
274/**
275 * g_dbus_object_manager_server_set_connection:
276 * @manager: A #GDBusObjectManagerServer.
277 * @connection: (nullable): A #GDBusConnection or %NULL.
278 *
279 * Exports all objects managed by @manager on @connection. If
280 * @connection is %NULL, stops exporting objects.
281 */
282void
283g_dbus_object_manager_server_set_connection (GDBusObjectManagerServer *manager,
284 GDBusConnection *connection)
285{
286 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
287 g_return_if_fail (connection == NULL || G_IS_DBUS_CONNECTION (connection));
288
289 g_mutex_lock (mutex: &manager->priv->lock);
290
291 if (manager->priv->connection == connection)
292 {
293 g_mutex_unlock (mutex: &manager->priv->lock);
294 goto out;
295 }
296
297 if (manager->priv->connection != NULL)
298 {
299 unexport_all (manager, FALSE);
300 g_object_unref (object: manager->priv->connection);
301 manager->priv->connection = NULL;
302 }
303
304 manager->priv->connection = connection != NULL ? g_object_ref (connection) : NULL;
305 if (manager->priv->connection != NULL)
306 export_all (manager);
307
308 g_mutex_unlock (mutex: &manager->priv->lock);
309
310 g_object_notify (G_OBJECT (manager), property_name: "connection");
311 out:
312 ;
313}
314
315/**
316 * g_dbus_object_manager_server_get_connection:
317 * @manager: A #GDBusObjectManagerServer
318 *
319 * Gets the #GDBusConnection used by @manager.
320 *
321 * Returns: (transfer full): A #GDBusConnection object or %NULL if
322 * @manager isn't exported on a connection. The returned object should
323 * be freed with g_object_unref().
324 *
325 * Since: 2.30
326 */
327GDBusConnection *
328g_dbus_object_manager_server_get_connection (GDBusObjectManagerServer *manager)
329{
330 GDBusConnection *ret;
331 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), NULL);
332 g_mutex_lock (mutex: &manager->priv->lock);
333 ret = manager->priv->connection != NULL ? g_object_ref (manager->priv->connection) : NULL;
334 g_mutex_unlock (mutex: &manager->priv->lock);
335 return ret;
336}
337
338/* ---------------------------------------------------------------------------------------------------- */
339
340static void
341registration_data_export_interface (RegistrationData *data,
342 GDBusInterfaceSkeleton *interface_skeleton,
343 const gchar *object_path)
344{
345 GDBusInterfaceInfo *info;
346 GError *error;
347
348 info = g_dbus_interface_skeleton_get_info (interface_: interface_skeleton);
349 error = NULL;
350 if (data->manager->priv->connection != NULL)
351 {
352 if (!g_dbus_interface_skeleton_export (interface_: interface_skeleton,
353 connection: data->manager->priv->connection,
354 object_path,
355 error: &error))
356 {
357 g_warning ("%s: Error registering object at %s with interface %s: %s",
358 G_STRLOC,
359 object_path,
360 info->name,
361 error->message);
362 g_error_free (error);
363 }
364 }
365
366 g_assert (g_hash_table_lookup (data->map_iface_name_to_iface, info->name) == NULL);
367 g_hash_table_insert (hash_table: data->map_iface_name_to_iface,
368 key: info->name,
369 g_object_ref (interface_skeleton));
370
371 /* if we are already exported, then... */
372 if (data->exported)
373 {
374 const gchar *interfaces[2];
375 /* emit InterfacesAdded on the ObjectManager object */
376 interfaces[0] = info->name;
377 interfaces[1] = NULL;
378 g_dbus_object_manager_server_emit_interfaces_added (manager: data->manager, data, interfaces, object_path);
379 }
380}
381
382static void
383registration_data_unexport_interface (RegistrationData *data,
384 GDBusInterfaceSkeleton *interface_skeleton)
385{
386 GDBusInterfaceInfo *info;
387 GDBusInterfaceSkeleton *iface;
388
389 info = g_dbus_interface_skeleton_get_info (interface_: interface_skeleton);
390 iface = g_hash_table_lookup (hash_table: data->map_iface_name_to_iface, key: info->name);
391 g_assert (iface != NULL);
392
393 if (data->manager->priv->connection != NULL)
394 g_dbus_interface_skeleton_unexport (interface_: iface);
395
396 g_warn_if_fail (g_hash_table_remove (data->map_iface_name_to_iface, info->name));
397
398 /* if we are already exported, then... */
399 if (data->exported)
400 {
401 const gchar *interfaces[2];
402 /* emit InterfacesRemoved on the ObjectManager object */
403 interfaces[0] = info->name;
404 interfaces[1] = NULL;
405 g_dbus_object_manager_server_emit_interfaces_removed (manager: data->manager, data, interfaces);
406 }
407}
408
409/* ---------------------------------------------------------------------------------------------------- */
410
411static void
412on_interface_added (GDBusObject *object,
413 GDBusInterface *interface,
414 gpointer user_data)
415{
416 RegistrationData *data = user_data;
417 const gchar *object_path;
418 g_mutex_lock (mutex: &data->manager->priv->lock);
419 object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
420 registration_data_export_interface (data, G_DBUS_INTERFACE_SKELETON (interface), object_path);
421 g_mutex_unlock (mutex: &data->manager->priv->lock);
422}
423
424static void
425on_interface_removed (GDBusObject *object,
426 GDBusInterface *interface,
427 gpointer user_data)
428{
429 RegistrationData *data = user_data;
430 g_mutex_lock (mutex: &data->manager->priv->lock);
431 registration_data_unexport_interface (data, G_DBUS_INTERFACE_SKELETON (interface));
432 g_mutex_unlock (mutex: &data->manager->priv->lock);
433}
434
435/* ---------------------------------------------------------------------------------------------------- */
436
437
438static void
439registration_data_free (RegistrationData *data)
440{
441 GHashTableIter iter;
442 GDBusInterfaceSkeleton *iface;
443
444 data->exported = FALSE;
445
446 g_hash_table_iter_init (iter: &iter, hash_table: data->map_iface_name_to_iface);
447 while (g_hash_table_iter_next (iter: &iter, NULL, value: (gpointer) &iface))
448 {
449 if (data->manager->priv->connection != NULL)
450 g_dbus_interface_skeleton_unexport (interface_: iface);
451 }
452
453 g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_added), data);
454 g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_removed), data);
455 g_object_unref (object: data->object);
456 g_hash_table_destroy (hash_table: data->map_iface_name_to_iface);
457 g_free (mem: data);
458}
459
460/* ---------------------------------------------------------------------------------------------------- */
461
462static void
463g_dbus_object_manager_server_export_unlocked (GDBusObjectManagerServer *manager,
464 GDBusObjectSkeleton *object,
465 const gchar *object_path)
466{
467 RegistrationData *data;
468 GList *existing_interfaces;
469 GList *l;
470 GPtrArray *interface_names;
471
472 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
473 g_return_if_fail (G_IS_DBUS_OBJECT (object));
474 g_return_if_fail (g_str_has_prefix (object_path, manager->priv->object_path_ending_in_slash));
475
476 interface_names = g_ptr_array_new ();
477
478 data = g_hash_table_lookup (hash_table: manager->priv->map_object_path_to_data, key: object_path);
479 if (data != NULL)
480 g_dbus_object_manager_server_unexport_unlocked (manager, object_path);
481
482 data = g_new0 (RegistrationData, 1);
483 data->object = g_object_ref (object);
484 data->manager = manager;
485 data->map_iface_name_to_iface = g_hash_table_new_full (hash_func: g_str_hash,
486 key_equal_func: g_str_equal,
487 NULL,
488 value_destroy_func: (GDestroyNotify) g_object_unref);
489
490 g_signal_connect (object,
491 "interface-added",
492 G_CALLBACK (on_interface_added),
493 data);
494 g_signal_connect (object,
495 "interface-removed",
496 G_CALLBACK (on_interface_removed),
497 data);
498
499 /* Register all known interfaces - note that data->exported is FALSE so
500 * we don't emit any InterfacesAdded signals.
501 */
502 existing_interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (object));
503 for (l = existing_interfaces; l != NULL; l = l->next)
504 {
505 GDBusInterfaceSkeleton *interface_skeleton = G_DBUS_INTERFACE_SKELETON (l->data);
506 registration_data_export_interface (data, interface_skeleton, object_path);
507 g_ptr_array_add (array: interface_names, data: g_dbus_interface_skeleton_get_info (interface_: interface_skeleton)->name);
508 }
509 g_list_free_full (list: existing_interfaces, free_func: g_object_unref);
510 g_ptr_array_add (array: interface_names, NULL);
511
512 data->exported = TRUE;
513
514 /* now emit InterfacesAdded() for all the interfaces */
515 g_dbus_object_manager_server_emit_interfaces_added (manager, data, interfaces: (const gchar *const *) interface_names->pdata, object_path);
516 g_ptr_array_unref (array: interface_names);
517
518 g_hash_table_insert (hash_table: manager->priv->map_object_path_to_data,
519 key: g_strdup (str: object_path),
520 value: data);
521}
522
523/**
524 * g_dbus_object_manager_server_export:
525 * @manager: A #GDBusObjectManagerServer.
526 * @object: A #GDBusObjectSkeleton.
527 *
528 * Exports @object on @manager.
529 *
530 * If there is already a #GDBusObject exported at the object path,
531 * then the old object is removed.
532 *
533 * The object path for @object must be in the hierarchy rooted by the
534 * object path for @manager.
535 *
536 * Note that @manager will take a reference on @object for as long as
537 * it is exported.
538 *
539 * Since: 2.30
540 */
541void
542g_dbus_object_manager_server_export (GDBusObjectManagerServer *manager,
543 GDBusObjectSkeleton *object)
544{
545 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
546 g_mutex_lock (mutex: &manager->priv->lock);
547 g_dbus_object_manager_server_export_unlocked (manager, object,
548 object_path: g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
549 g_mutex_unlock (mutex: &manager->priv->lock);
550}
551
552/**
553 * g_dbus_object_manager_server_export_uniquely:
554 * @manager: A #GDBusObjectManagerServer.
555 * @object: An object.
556 *
557 * Like g_dbus_object_manager_server_export() but appends a string of
558 * the form _N (with N being a natural number) to @object's object path
559 * if an object with the given path already exists. As such, the
560 * #GDBusObjectProxy:g-object-path property of @object may be modified.
561 *
562 * Since: 2.30
563 */
564void
565g_dbus_object_manager_server_export_uniquely (GDBusObjectManagerServer *manager,
566 GDBusObjectSkeleton *object)
567{
568 gchar *orig_object_path;
569 gchar *object_path;
570 guint count;
571 gboolean modified;
572
573 orig_object_path = g_strdup (str: g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
574
575 g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager));
576 g_return_if_fail (G_IS_DBUS_OBJECT (object));
577 g_return_if_fail (g_str_has_prefix (orig_object_path, manager->priv->object_path_ending_in_slash));
578
579 g_mutex_lock (mutex: &manager->priv->lock);
580
581 object_path = g_strdup (str: orig_object_path);
582 count = 1;
583 modified = FALSE;
584 while (TRUE)
585 {
586 RegistrationData *data;
587 data = g_hash_table_lookup (hash_table: manager->priv->map_object_path_to_data, key: object_path);
588 if (data == NULL)
589 {
590 break;
591 }
592 g_free (mem: object_path);
593 object_path = g_strdup_printf (format: "%s_%d", orig_object_path, count++);
594 modified = TRUE;
595 }
596
597 g_dbus_object_manager_server_export_unlocked (manager, object, object_path);
598
599 g_mutex_unlock (mutex: &manager->priv->lock);
600
601 if (modified)
602 g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (object), object_path);
603
604 g_free (mem: object_path);
605 g_free (mem: orig_object_path);
606
607}
608
609/**
610 * g_dbus_object_manager_server_is_exported:
611 * @manager: A #GDBusObjectManagerServer.
612 * @object: An object.
613 *
614 * Returns whether @object is currently exported on @manager.
615 *
616 * Returns: %TRUE if @object is exported
617 *
618 * Since: 2.34
619 **/
620gboolean
621g_dbus_object_manager_server_is_exported (GDBusObjectManagerServer *manager,
622 GDBusObjectSkeleton *object)
623{
624 RegistrationData *data = NULL;
625 const gchar *object_path;
626 gboolean object_is_exported;
627
628 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
629 g_return_val_if_fail (G_IS_DBUS_OBJECT (object), FALSE);
630
631 g_mutex_lock (mutex: &manager->priv->lock);
632
633 object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
634 if (object_path != NULL)
635 data = g_hash_table_lookup (hash_table: manager->priv->map_object_path_to_data, key: object_path);
636 object_is_exported = (data != NULL);
637
638 g_mutex_unlock (mutex: &manager->priv->lock);
639
640 return object_is_exported;
641}
642
643/* ---------------------------------------------------------------------------------------------------- */
644
645static gboolean
646g_dbus_object_manager_server_unexport_unlocked (GDBusObjectManagerServer *manager,
647 const gchar *object_path)
648{
649 RegistrationData *data;
650 gboolean ret;
651
652 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
653 g_return_val_if_fail (g_variant_is_object_path (object_path), FALSE);
654 g_return_val_if_fail (g_str_has_prefix (object_path, manager->priv->object_path_ending_in_slash), FALSE);
655
656 ret = FALSE;
657
658 data = g_hash_table_lookup (hash_table: manager->priv->map_object_path_to_data, key: object_path);
659 if (data != NULL)
660 {
661 GPtrArray *interface_names;
662 GHashTableIter iter;
663 const gchar *iface_name;
664
665 interface_names = g_ptr_array_new ();
666 g_hash_table_iter_init (iter: &iter, hash_table: data->map_iface_name_to_iface);
667 while (g_hash_table_iter_next (iter: &iter, key: (gpointer) &iface_name, NULL))
668 g_ptr_array_add (array: interface_names, data: (gpointer) iface_name);
669 g_ptr_array_add (array: interface_names, NULL);
670 /* now emit InterfacesRemoved() for all the interfaces */
671 g_dbus_object_manager_server_emit_interfaces_removed (manager, data, interfaces: (const gchar *const *) interface_names->pdata);
672 g_ptr_array_unref (array: interface_names);
673
674 g_hash_table_remove (hash_table: manager->priv->map_object_path_to_data, key: object_path);
675 ret = TRUE;
676 }
677
678 return ret;
679}
680
681/**
682 * g_dbus_object_manager_server_unexport:
683 * @manager: A #GDBusObjectManagerServer.
684 * @object_path: An object path.
685 *
686 * If @manager has an object at @path, removes the object. Otherwise
687 * does nothing.
688 *
689 * Note that @object_path must be in the hierarchy rooted by the
690 * object path for @manager.
691 *
692 * Returns: %TRUE if object at @object_path was removed, %FALSE otherwise.
693 *
694 * Since: 2.30
695 */
696gboolean
697g_dbus_object_manager_server_unexport (GDBusObjectManagerServer *manager,
698 const gchar *object_path)
699{
700 gboolean ret;
701 g_return_val_if_fail (G_IS_DBUS_OBJECT_MANAGER_SERVER (manager), FALSE);
702 g_mutex_lock (mutex: &manager->priv->lock);
703 ret = g_dbus_object_manager_server_unexport_unlocked (manager, object_path);
704 g_mutex_unlock (mutex: &manager->priv->lock);
705 return ret;
706}
707
708
709/* ---------------------------------------------------------------------------------------------------- */
710
711static const GDBusArgInfo manager_interfaces_added_signal_info_arg0 =
712{
713 -1,
714 "object_path",
715 "o",
716 (GDBusAnnotationInfo**) NULL,
717};
718
719static const GDBusArgInfo manager_interfaces_added_signal_info_arg1 =
720{
721 -1,
722 "interfaces_and_properties",
723 "a{sa{sv}}",
724 (GDBusAnnotationInfo**) NULL,
725};
726
727static const GDBusArgInfo * const manager_interfaces_added_signal_info_arg_pointers[] =
728{
729 &manager_interfaces_added_signal_info_arg0,
730 &manager_interfaces_added_signal_info_arg1,
731 NULL
732};
733
734static const GDBusSignalInfo manager_interfaces_added_signal_info =
735{
736 -1,
737 "InterfacesAdded",
738 (GDBusArgInfo**) &manager_interfaces_added_signal_info_arg_pointers,
739 (GDBusAnnotationInfo**) NULL
740};
741
742/* ---------- */
743
744static const GDBusArgInfo manager_interfaces_removed_signal_info_arg0 =
745{
746 -1,
747 "object_path",
748 "o",
749 (GDBusAnnotationInfo**) NULL,
750};
751
752static const GDBusArgInfo manager_interfaces_removed_signal_info_arg1 =
753{
754 -1,
755 "interfaces",
756 "as",
757 (GDBusAnnotationInfo**) NULL,
758};
759
760static const GDBusArgInfo * const manager_interfaces_removed_signal_info_arg_pointers[] =
761{
762 &manager_interfaces_removed_signal_info_arg0,
763 &manager_interfaces_removed_signal_info_arg1,
764 NULL
765};
766
767static const GDBusSignalInfo manager_interfaces_removed_signal_info =
768{
769 -1,
770 "InterfacesRemoved",
771 (GDBusArgInfo**) &manager_interfaces_removed_signal_info_arg_pointers,
772 (GDBusAnnotationInfo**) NULL
773};
774
775/* ---------- */
776
777static const GDBusSignalInfo * const manager_signal_info_pointers[] =
778{
779 &manager_interfaces_added_signal_info,
780 &manager_interfaces_removed_signal_info,
781 NULL
782};
783
784/* ---------- */
785
786static const GDBusArgInfo manager_get_all_method_info_out_arg0 =
787{
788 -1,
789 "object_paths_interfaces_and_properties",
790 "a{oa{sa{sv}}}",
791 (GDBusAnnotationInfo**) NULL,
792};
793
794static const GDBusArgInfo * const manager_get_all_method_info_out_arg_pointers[] =
795{
796 &manager_get_all_method_info_out_arg0,
797 NULL
798};
799
800static const GDBusMethodInfo manager_get_all_method_info =
801{
802 -1,
803 "GetManagedObjects",
804 (GDBusArgInfo**) NULL,
805 (GDBusArgInfo**) &manager_get_all_method_info_out_arg_pointers,
806 (GDBusAnnotationInfo**) NULL
807};
808
809static const GDBusMethodInfo * const manager_method_info_pointers[] =
810{
811 &manager_get_all_method_info,
812 NULL
813};
814
815/* ---------- */
816
817static const GDBusInterfaceInfo manager_interface_info =
818{
819 -1,
820 "org.freedesktop.DBus.ObjectManager",
821 (GDBusMethodInfo **) manager_method_info_pointers,
822 (GDBusSignalInfo **) manager_signal_info_pointers,
823 (GDBusPropertyInfo **) NULL,
824 (GDBusAnnotationInfo **) NULL
825};
826
827static void
828manager_method_call (GDBusConnection *connection,
829 const gchar *sender,
830 const gchar *object_path,
831 const gchar *interface_name,
832 const gchar *method_name,
833 GVariant *parameters,
834 GDBusMethodInvocation *invocation,
835 gpointer user_data)
836{
837 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (user_data);
838 GVariantBuilder array_builder;
839 GHashTableIter object_iter;
840 RegistrationData *data;
841
842 g_mutex_lock (mutex: &manager->priv->lock);
843
844 if (g_strcmp0 (str1: method_name, str2: "GetManagedObjects") == 0)
845 {
846 g_variant_builder_init (builder: &array_builder, G_VARIANT_TYPE ("a{oa{sa{sv}}}"));
847 g_hash_table_iter_init (iter: &object_iter, hash_table: manager->priv->map_object_path_to_data);
848 while (g_hash_table_iter_next (iter: &object_iter, NULL, value: (gpointer) &data))
849 {
850 GVariantBuilder interfaces_builder;
851 GHashTableIter interface_iter;
852 GDBusInterfaceSkeleton *iface;
853 const gchar *iter_object_path;
854
855 g_variant_builder_init (builder: &interfaces_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
856 g_hash_table_iter_init (iter: &interface_iter, hash_table: data->map_iface_name_to_iface);
857 while (g_hash_table_iter_next (iter: &interface_iter, NULL, value: (gpointer) &iface))
858 {
859 GVariant *properties = g_dbus_interface_skeleton_get_properties (interface_: iface);
860 g_variant_builder_add (builder: &interfaces_builder, format_string: "{s@a{sv}}",
861 g_dbus_interface_skeleton_get_info (interface_: iface)->name,
862 properties);
863 g_variant_unref (value: properties);
864 }
865 iter_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
866 g_variant_builder_add (builder: &array_builder,
867 format_string: "{oa{sa{sv}}}",
868 iter_object_path,
869 &interfaces_builder);
870 }
871
872 g_dbus_method_invocation_return_value (invocation,
873 parameters: g_variant_new (format_string: "(a{oa{sa{sv}}})",
874 &array_builder));
875 }
876 else
877 {
878 g_dbus_method_invocation_return_error (invocation,
879 G_DBUS_ERROR,
880 code: G_DBUS_ERROR_UNKNOWN_METHOD,
881 format: "Unknown method %s - only GetManagedObjects() is supported",
882 method_name);
883 }
884 g_mutex_unlock (mutex: &manager->priv->lock);
885}
886
887static const GDBusInterfaceVTable manager_interface_vtable =
888{
889 manager_method_call, /* handle_method_call */
890 NULL, /* get_property */
891 NULL, /* set_property */
892 { 0 }
893};
894
895/* ---------------------------------------------------------------------------------------------------- */
896
897static void
898g_dbus_object_manager_server_constructed (GObject *object)
899{
900 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (object);
901
902 if (manager->priv->connection != NULL)
903 export_all (manager);
904
905 if (G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed != NULL)
906 G_OBJECT_CLASS (g_dbus_object_manager_server_parent_class)->constructed (object);
907}
908
909static void
910g_dbus_object_manager_server_emit_interfaces_added (GDBusObjectManagerServer *manager,
911 RegistrationData *data,
912 const gchar *const *interfaces,
913 const gchar *object_path)
914{
915 GVariantBuilder array_builder;
916 GError *error;
917 guint n;
918
919 if (data->manager->priv->connection == NULL)
920 goto out;
921
922 g_variant_builder_init (builder: &array_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
923 for (n = 0; interfaces[n] != NULL; n++)
924 {
925 GDBusInterfaceSkeleton *iface;
926 GVariant *properties;
927
928 iface = g_hash_table_lookup (hash_table: data->map_iface_name_to_iface, key: interfaces[n]);
929 g_assert (iface != NULL);
930 properties = g_dbus_interface_skeleton_get_properties (interface_: iface);
931 g_variant_builder_add (builder: &array_builder, format_string: "{s@a{sv}}", interfaces[n], properties);
932 g_variant_unref (value: properties);
933 }
934
935 error = NULL;
936 g_dbus_connection_emit_signal (connection: data->manager->priv->connection,
937 NULL, /* destination_bus_name */
938 object_path: manager->priv->object_path,
939 interface_name: manager_interface_info.name,
940 signal_name: "InterfacesAdded",
941 parameters: g_variant_new (format_string: "(oa{sa{sv}})",
942 object_path,
943 &array_builder),
944 error: &error);
945 if (error)
946 {
947 if (!g_error_matches (error, G_IO_ERROR, code: G_IO_ERROR_CLOSED))
948 g_warning ("Couldn't emit InterfacesAdded signal: %s", error->message);
949 g_error_free (error);
950 }
951 out:
952 ;
953}
954
955static void
956g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
957 RegistrationData *data,
958 const gchar *const *interfaces)
959{
960 GVariantBuilder array_builder;
961 GError *error;
962 guint n;
963 const gchar *object_path;
964
965 if (data->manager->priv->connection == NULL)
966 goto out;
967
968 g_variant_builder_init (builder: &array_builder, G_VARIANT_TYPE ("as"));
969 for (n = 0; interfaces[n] != NULL; n++)
970 g_variant_builder_add (builder: &array_builder, format_string: "s", interfaces[n]);
971
972 error = NULL;
973 object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
974 g_dbus_connection_emit_signal (connection: data->manager->priv->connection,
975 NULL, /* destination_bus_name */
976 object_path: manager->priv->object_path,
977 interface_name: manager_interface_info.name,
978 signal_name: "InterfacesRemoved",
979 parameters: g_variant_new (format_string: "(oas)",
980 object_path,
981 &array_builder),
982 error: &error);
983 if (error)
984 {
985 if (!g_error_matches (error, G_IO_ERROR, code: G_IO_ERROR_CLOSED))
986 g_warning ("Couldn't emit InterfacesRemoved signal: %s", error->message);
987 g_error_free (error);
988 }
989 out:
990 ;
991}
992
993/* ---------------------------------------------------------------------------------------------------- */
994
995static GList *
996g_dbus_object_manager_server_get_objects (GDBusObjectManager *_manager)
997{
998 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
999 GList *ret;
1000 GHashTableIter iter;
1001 RegistrationData *data;
1002
1003 g_mutex_lock (mutex: &manager->priv->lock);
1004
1005 ret = NULL;
1006 g_hash_table_iter_init (iter: &iter, hash_table: manager->priv->map_object_path_to_data);
1007 while (g_hash_table_iter_next (iter: &iter, NULL, value: (gpointer) &data))
1008 {
1009 ret = g_list_prepend (list: ret, g_object_ref (data->object));
1010 }
1011
1012 g_mutex_unlock (mutex: &manager->priv->lock);
1013
1014 return ret;
1015}
1016
1017static const gchar *
1018g_dbus_object_manager_server_get_object_path (GDBusObjectManager *_manager)
1019{
1020 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
1021 return manager->priv->object_path;
1022}
1023
1024static GDBusObject *
1025g_dbus_object_manager_server_get_object (GDBusObjectManager *_manager,
1026 const gchar *object_path)
1027{
1028 GDBusObjectManagerServer *manager = G_DBUS_OBJECT_MANAGER_SERVER (_manager);
1029 GDBusObject *ret;
1030 RegistrationData *data;
1031
1032 ret = NULL;
1033
1034 g_mutex_lock (mutex: &manager->priv->lock);
1035 data = g_hash_table_lookup (hash_table: manager->priv->map_object_path_to_data, key: object_path);
1036 if (data != NULL)
1037 ret = g_object_ref (G_DBUS_OBJECT (data->object));
1038 g_mutex_unlock (mutex: &manager->priv->lock);
1039
1040 return ret;
1041}
1042
1043static GDBusInterface *
1044g_dbus_object_manager_server_get_interface (GDBusObjectManager *_manager,
1045 const gchar *object_path,
1046 const gchar *interface_name)
1047{
1048 GDBusInterface *ret;
1049 GDBusObject *object;
1050
1051 ret = NULL;
1052
1053 object = g_dbus_object_manager_get_object (manager: _manager, object_path);
1054 if (object == NULL)
1055 goto out;
1056
1057 ret = g_dbus_object_get_interface (object, interface_name);
1058 g_object_unref (object);
1059
1060 out:
1061 return ret;
1062}
1063
1064static void
1065dbus_object_manager_interface_init (GDBusObjectManagerIface *iface)
1066{
1067 iface->get_object_path = g_dbus_object_manager_server_get_object_path;
1068 iface->get_objects = g_dbus_object_manager_server_get_objects;
1069 iface->get_object = g_dbus_object_manager_server_get_object;
1070 iface->get_interface = g_dbus_object_manager_server_get_interface;
1071}
1072
1073/* ---------------------------------------------------------------------------------------------------- */
1074
1075static void
1076export_all (GDBusObjectManagerServer *manager)
1077{
1078 GHashTableIter iter;
1079 const gchar *object_path;
1080 RegistrationData *data;
1081 GHashTableIter iface_iter;
1082 GDBusInterfaceSkeleton *iface;
1083 GError *error;
1084
1085 g_return_if_fail (manager->priv->connection != NULL);
1086
1087 error = NULL;
1088 g_warn_if_fail (manager->priv->manager_reg_id == 0);
1089 manager->priv->manager_reg_id = g_dbus_connection_register_object (connection: manager->priv->connection,
1090 object_path: manager->priv->object_path,
1091 interface_info: (GDBusInterfaceInfo *) &manager_interface_info,
1092 vtable: &manager_interface_vtable,
1093 user_data: manager,
1094 NULL, /* user_data_free_func */
1095 error: &error);
1096 if (manager->priv->manager_reg_id == 0)
1097 {
1098 g_warning ("%s: Error registering manager at %s: %s",
1099 G_STRLOC,
1100 manager->priv->object_path,
1101 error->message);
1102 g_error_free (error);
1103 }
1104
1105 g_hash_table_iter_init (iter: &iter, hash_table: manager->priv->map_object_path_to_data);
1106 while (g_hash_table_iter_next (iter: &iter, key: (gpointer) &object_path, value: (gpointer) &data))
1107 {
1108 g_hash_table_iter_init (iter: &iface_iter, hash_table: data->map_iface_name_to_iface);
1109 while (g_hash_table_iter_next (iter: &iface_iter, NULL, value: (gpointer) &iface))
1110 {
1111 g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) == NULL);
1112 error = NULL;
1113 if (!g_dbus_interface_skeleton_export (interface_: iface,
1114 connection: manager->priv->connection,
1115 object_path,
1116 error: &error))
1117 {
1118 g_warning ("%s: Error registering object at %s with interface %s: %s",
1119 G_STRLOC,
1120 object_path,
1121 g_dbus_interface_skeleton_get_info (iface)->name,
1122 error->message);
1123 g_error_free (error);
1124 }
1125 }
1126 }
1127}
1128
1129static void
1130unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager)
1131{
1132 GHashTableIter iter;
1133 RegistrationData *data;
1134 GHashTableIter iface_iter;
1135 GDBusInterfaceSkeleton *iface;
1136
1137 g_return_if_fail (manager->priv->connection != NULL);
1138
1139 g_warn_if_fail (manager->priv->manager_reg_id > 0);
1140 if (manager->priv->manager_reg_id > 0)
1141 {
1142 g_warn_if_fail (g_dbus_connection_unregister_object (manager->priv->connection,
1143 manager->priv->manager_reg_id));
1144 manager->priv->manager_reg_id = 0;
1145 }
1146 if (only_manager)
1147 goto out;
1148
1149 g_hash_table_iter_init (iter: &iter, hash_table: manager->priv->map_object_path_to_data);
1150 while (g_hash_table_iter_next (iter: &iter, NULL, value: (gpointer) &data))
1151 {
1152 g_hash_table_iter_init (iter: &iface_iter, hash_table: data->map_iface_name_to_iface);
1153 while (g_hash_table_iter_next (iter: &iface_iter, NULL, value: (gpointer) &iface))
1154 {
1155 g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) != NULL);
1156 g_dbus_interface_skeleton_unexport (interface_: iface);
1157 }
1158 }
1159 out:
1160 ;
1161}
1162
1163/* ---------------------------------------------------------------------------------------------------- */
1164

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