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
66 typedef struct
67 {
68 GDBusObjectSkeleton *object;
69 GDBusObjectManagerServer *manager;
70 GHashTable *map_iface_name_to_iface;
71 gboolean exported;
72 } RegistrationData;
73
74 static void registration_data_free (RegistrationData *data);
75
76 static void export_all (GDBusObjectManagerServer *manager);
77 static void unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager);
78
79 static 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
84 static void g_dbus_object_manager_server_emit_interfaces_removed (GDBusObjectManagerServer *manager,
85 RegistrationData *data,
86 const gchar *const *interfaces);
87
88 static gboolean g_dbus_object_manager_server_unexport_unlocked (GDBusObjectManagerServer *manager,
89 const gchar *object_path);
90
91 struct _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
101 enum
102 {
103 PROP_0,
104 PROP_CONNECTION,
105 PROP_OBJECT_PATH
106 };
107
108 static void dbus_object_manager_interface_init (GDBusObjectManagerIface *iface);
109
110 G_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
114 static void g_dbus_object_manager_server_constructed (GObject *object);
115
116 static void
g_dbus_object_manager_server_finalize(GObject * object)117 g_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 (manager->priv->connection);
125 }
126 g_hash_table_unref (manager->priv->map_object_path_to_data);
127 g_free (manager->priv->object_path);
128 g_free (manager->priv->object_path_ending_in_slash);
129
130 g_mutex_clear (&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
136 static void
g_dbus_object_manager_server_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)137 g_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 (&manager->priv->lock);
148 g_value_set_object (value, manager->priv->connection);
149 g_mutex_unlock (&manager->priv->lock);
150 break;
151
152 case PROP_OBJECT_PATH:
153 g_value_set_string (value, 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
162 static void
g_dbus_object_manager_server_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)163 g_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, 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 (manager->priv->object_path, "/"))
181 manager->priv->object_path_ending_in_slash = g_strdup (manager->priv->object_path);
182 else
183 manager->priv->object_path_ending_in_slash = g_strdup_printf ("%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
192 static void
g_dbus_object_manager_server_class_init(GDBusObjectManagerServerClass * klass)193 g_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 (gobject_class,
210 PROP_CONNECTION,
211 g_param_spec_object ("connection",
212 "Connection",
213 "The connection to export objects on",
214 G_TYPE_DBUS_CONNECTION,
215 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 (gobject_class,
227 PROP_OBJECT_PATH,
228 g_param_spec_string ("object-path",
229 "Object Path",
230 "The object path to register the manager object at",
231 NULL,
232 G_PARAM_READABLE |
233 G_PARAM_WRITABLE |
234 G_PARAM_CONSTRUCT_ONLY |
235 G_PARAM_STATIC_STRINGS));
236 }
237
238 static void
g_dbus_object_manager_server_init(GDBusObjectManagerServer * manager)239 g_dbus_object_manager_server_init (GDBusObjectManagerServer *manager)
240 {
241 manager->priv = g_dbus_object_manager_server_get_instance_private (manager);
242 g_mutex_init (&manager->priv->lock);
243 manager->priv->map_object_path_to_data = g_hash_table_new_full (g_str_hash,
244 g_str_equal,
245 g_free,
246 (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 */
265 GDBusObjectManagerServer *
g_dbus_object_manager_server_new(const gchar * object_path)266 g_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 */
282 void
g_dbus_object_manager_server_set_connection(GDBusObjectManagerServer * manager,GDBusConnection * connection)283 g_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 (&manager->priv->lock);
290
291 if (manager->priv->connection == connection)
292 {
293 g_mutex_unlock (&manager->priv->lock);
294 goto out;
295 }
296
297 if (manager->priv->connection != NULL)
298 {
299 unexport_all (manager, FALSE);
300 g_object_unref (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 (&manager->priv->lock);
309
310 g_object_notify (G_OBJECT (manager), "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 */
327 GDBusConnection *
g_dbus_object_manager_server_get_connection(GDBusObjectManagerServer * manager)328 g_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 (&manager->priv->lock);
333 ret = manager->priv->connection != NULL ? g_object_ref (manager->priv->connection) : NULL;
334 g_mutex_unlock (&manager->priv->lock);
335 return ret;
336 }
337
338 /* ---------------------------------------------------------------------------------------------------- */
339
340 static void
registration_data_export_interface(RegistrationData * data,GDBusInterfaceSkeleton * interface_skeleton,const gchar * object_path)341 registration_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_skeleton);
349 error = NULL;
350 if (data->manager->priv->connection != NULL)
351 {
352 if (!g_dbus_interface_skeleton_export (interface_skeleton,
353 data->manager->priv->connection,
354 object_path,
355 &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 (data->map_iface_name_to_iface,
368 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 (data->manager, data, interfaces, object_path);
379 }
380 }
381
382 static void
registration_data_unexport_interface(RegistrationData * data,GDBusInterfaceSkeleton * interface_skeleton)383 registration_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_skeleton);
390 iface = g_hash_table_lookup (data->map_iface_name_to_iface, info->name);
391 g_assert (iface != NULL);
392
393 if (data->manager->priv->connection != NULL)
394 g_dbus_interface_skeleton_unexport (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 (data->manager, data, interfaces);
406 }
407 }
408
409 /* ---------------------------------------------------------------------------------------------------- */
410
411 static void
on_interface_added(GDBusObject * object,GDBusInterface * interface,gpointer user_data)412 on_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 (&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 (&data->manager->priv->lock);
422 }
423
424 static void
on_interface_removed(GDBusObject * object,GDBusInterface * interface,gpointer user_data)425 on_interface_removed (GDBusObject *object,
426 GDBusInterface *interface,
427 gpointer user_data)
428 {
429 RegistrationData *data = user_data;
430 g_mutex_lock (&data->manager->priv->lock);
431 registration_data_unexport_interface (data, G_DBUS_INTERFACE_SKELETON (interface));
432 g_mutex_unlock (&data->manager->priv->lock);
433 }
434
435 /* ---------------------------------------------------------------------------------------------------- */
436
437
438 static void
registration_data_free(RegistrationData * data)439 registration_data_free (RegistrationData *data)
440 {
441 GHashTableIter iter;
442 GDBusInterfaceSkeleton *iface;
443
444 data->exported = FALSE;
445
446 g_hash_table_iter_init (&iter, data->map_iface_name_to_iface);
447 while (g_hash_table_iter_next (&iter, NULL, (gpointer) &iface))
448 {
449 if (data->manager->priv->connection != NULL)
450 g_dbus_interface_skeleton_unexport (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 (data->object);
456 g_hash_table_destroy (data->map_iface_name_to_iface);
457 g_free (data);
458 }
459
460 /* ---------------------------------------------------------------------------------------------------- */
461
462 static void
g_dbus_object_manager_server_export_unlocked(GDBusObjectManagerServer * manager,GDBusObjectSkeleton * object,const gchar * object_path)463 g_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 (manager->priv->map_object_path_to_data, 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 (g_str_hash,
486 g_str_equal,
487 NULL,
488 (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 (interface_names, g_dbus_interface_skeleton_get_info (interface_skeleton)->name);
508 }
509 g_list_free_full (existing_interfaces, g_object_unref);
510 g_ptr_array_add (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, (const gchar *const *) interface_names->pdata, object_path);
516 g_ptr_array_unref (interface_names);
517
518 g_hash_table_insert (manager->priv->map_object_path_to_data,
519 g_strdup (object_path),
520 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 */
541 void
g_dbus_object_manager_server_export(GDBusObjectManagerServer * manager,GDBusObjectSkeleton * object)542 g_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 (&manager->priv->lock);
547 g_dbus_object_manager_server_export_unlocked (manager, object,
548 g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
549 g_mutex_unlock (&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 */
564 void
g_dbus_object_manager_server_export_uniquely(GDBusObjectManagerServer * manager,GDBusObjectSkeleton * object)565 g_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 (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 (&manager->priv->lock);
580
581 object_path = g_strdup (orig_object_path);
582 count = 1;
583 modified = FALSE;
584 while (TRUE)
585 {
586 RegistrationData *data;
587 data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
588 if (data == NULL)
589 {
590 break;
591 }
592 g_free (object_path);
593 object_path = g_strdup_printf ("%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 (&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 (object_path);
605 g_free (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 **/
620 gboolean
g_dbus_object_manager_server_is_exported(GDBusObjectManagerServer * manager,GDBusObjectSkeleton * object)621 g_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 (&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 (manager->priv->map_object_path_to_data, object_path);
636 object_is_exported = (data != NULL);
637
638 g_mutex_unlock (&manager->priv->lock);
639
640 return object_is_exported;
641 }
642
643 /* ---------------------------------------------------------------------------------------------------- */
644
645 static gboolean
g_dbus_object_manager_server_unexport_unlocked(GDBusObjectManagerServer * manager,const gchar * object_path)646 g_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 (manager->priv->map_object_path_to_data, 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, data->map_iface_name_to_iface);
667 while (g_hash_table_iter_next (&iter, (gpointer) &iface_name, NULL))
668 g_ptr_array_add (interface_names, (gpointer) iface_name);
669 g_ptr_array_add (interface_names, NULL);
670 /* now emit InterfacesRemoved() for all the interfaces */
671 g_dbus_object_manager_server_emit_interfaces_removed (manager, data, (const gchar *const *) interface_names->pdata);
672 g_ptr_array_unref (interface_names);
673
674 g_hash_table_remove (manager->priv->map_object_path_to_data, 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 */
696 gboolean
g_dbus_object_manager_server_unexport(GDBusObjectManagerServer * manager,const gchar * object_path)697 g_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 (&manager->priv->lock);
703 ret = g_dbus_object_manager_server_unexport_unlocked (manager, object_path);
704 g_mutex_unlock (&manager->priv->lock);
705 return ret;
706 }
707
708
709 /* ---------------------------------------------------------------------------------------------------- */
710
711 static const GDBusArgInfo manager_interfaces_added_signal_info_arg0 =
712 {
713 -1,
714 "object_path",
715 "o",
716 (GDBusAnnotationInfo**) NULL,
717 };
718
719 static const GDBusArgInfo manager_interfaces_added_signal_info_arg1 =
720 {
721 -1,
722 "interfaces_and_properties",
723 "a{sa{sv}}",
724 (GDBusAnnotationInfo**) NULL,
725 };
726
727 static 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
734 static 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
744 static const GDBusArgInfo manager_interfaces_removed_signal_info_arg0 =
745 {
746 -1,
747 "object_path",
748 "o",
749 (GDBusAnnotationInfo**) NULL,
750 };
751
752 static const GDBusArgInfo manager_interfaces_removed_signal_info_arg1 =
753 {
754 -1,
755 "interfaces",
756 "as",
757 (GDBusAnnotationInfo**) NULL,
758 };
759
760 static 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
767 static 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
777 static 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
786 static 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
794 static const GDBusArgInfo * const manager_get_all_method_info_out_arg_pointers[] =
795 {
796 &manager_get_all_method_info_out_arg0,
797 NULL
798 };
799
800 static 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
809 static const GDBusMethodInfo * const manager_method_info_pointers[] =
810 {
811 &manager_get_all_method_info,
812 NULL
813 };
814
815 /* ---------- */
816
817 static 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
827 static void
manager_method_call(GDBusConnection * connection,const gchar * sender,const gchar * object_path,const gchar * interface_name,const gchar * method_name,GVariant * parameters,GDBusMethodInvocation * invocation,gpointer user_data)828 manager_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 (&manager->priv->lock);
843
844 if (g_strcmp0 (method_name, "GetManagedObjects") == 0)
845 {
846 g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{oa{sa{sv}}}"));
847 g_hash_table_iter_init (&object_iter, manager->priv->map_object_path_to_data);
848 while (g_hash_table_iter_next (&object_iter, NULL, (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 (&interfaces_builder, G_VARIANT_TYPE ("a{sa{sv}}"));
856 g_hash_table_iter_init (&interface_iter, data->map_iface_name_to_iface);
857 while (g_hash_table_iter_next (&interface_iter, NULL, (gpointer) &iface))
858 {
859 GVariant *properties = g_dbus_interface_skeleton_get_properties (iface);
860 g_variant_builder_add (&interfaces_builder, "{s@a{sv}}",
861 g_dbus_interface_skeleton_get_info (iface)->name,
862 properties);
863 g_variant_unref (properties);
864 }
865 iter_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (data->object));
866 g_variant_builder_add (&array_builder,
867 "{oa{sa{sv}}}",
868 iter_object_path,
869 &interfaces_builder);
870 }
871
872 g_dbus_method_invocation_return_value (invocation,
873 g_variant_new ("(a{oa{sa{sv}}})",
874 &array_builder));
875 }
876 else
877 {
878 g_dbus_method_invocation_return_error (invocation,
879 G_DBUS_ERROR,
880 G_DBUS_ERROR_UNKNOWN_METHOD,
881 "Unknown method %s - only GetManagedObjects() is supported",
882 method_name);
883 }
884 g_mutex_unlock (&manager->priv->lock);
885 }
886
887 static 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
897 static void
g_dbus_object_manager_server_constructed(GObject * object)898 g_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
909 static void
g_dbus_object_manager_server_emit_interfaces_added(GDBusObjectManagerServer * manager,RegistrationData * data,const gchar * const * interfaces,const gchar * object_path)910 g_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 (&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 (data->map_iface_name_to_iface, interfaces[n]);
929 g_assert (iface != NULL);
930 properties = g_dbus_interface_skeleton_get_properties (iface);
931 g_variant_builder_add (&array_builder, "{s@a{sv}}", interfaces[n], properties);
932 g_variant_unref (properties);
933 }
934
935 error = NULL;
936 g_dbus_connection_emit_signal (data->manager->priv->connection,
937 NULL, /* destination_bus_name */
938 manager->priv->object_path,
939 manager_interface_info.name,
940 "InterfacesAdded",
941 g_variant_new ("(oa{sa{sv}})",
942 object_path,
943 &array_builder),
944 &error);
945 if (error)
946 {
947 if (!g_error_matches (error, G_IO_ERROR, 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
955 static void
g_dbus_object_manager_server_emit_interfaces_removed(GDBusObjectManagerServer * manager,RegistrationData * data,const gchar * const * interfaces)956 g_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 (&array_builder, G_VARIANT_TYPE ("as"));
969 for (n = 0; interfaces[n] != NULL; n++)
970 g_variant_builder_add (&array_builder, "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 (data->manager->priv->connection,
975 NULL, /* destination_bus_name */
976 manager->priv->object_path,
977 manager_interface_info.name,
978 "InterfacesRemoved",
979 g_variant_new ("(oas)",
980 object_path,
981 &array_builder),
982 &error);
983 if (error)
984 {
985 if (!g_error_matches (error, G_IO_ERROR, 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
995 static GList *
g_dbus_object_manager_server_get_objects(GDBusObjectManager * _manager)996 g_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 (&manager->priv->lock);
1004
1005 ret = NULL;
1006 g_hash_table_iter_init (&iter, manager->priv->map_object_path_to_data);
1007 while (g_hash_table_iter_next (&iter, NULL, (gpointer) &data))
1008 {
1009 ret = g_list_prepend (ret, g_object_ref (data->object));
1010 }
1011
1012 g_mutex_unlock (&manager->priv->lock);
1013
1014 return ret;
1015 }
1016
1017 static const gchar *
g_dbus_object_manager_server_get_object_path(GDBusObjectManager * _manager)1018 g_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
1024 static GDBusObject *
g_dbus_object_manager_server_get_object(GDBusObjectManager * _manager,const gchar * object_path)1025 g_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 (&manager->priv->lock);
1035 data = g_hash_table_lookup (manager->priv->map_object_path_to_data, object_path);
1036 if (data != NULL)
1037 ret = g_object_ref (G_DBUS_OBJECT (data->object));
1038 g_mutex_unlock (&manager->priv->lock);
1039
1040 return ret;
1041 }
1042
1043 static GDBusInterface *
g_dbus_object_manager_server_get_interface(GDBusObjectManager * _manager,const gchar * object_path,const gchar * interface_name)1044 g_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, 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
1064 static void
dbus_object_manager_interface_init(GDBusObjectManagerIface * iface)1065 dbus_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
1075 static void
export_all(GDBusObjectManagerServer * manager)1076 export_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 (manager->priv->connection,
1090 manager->priv->object_path,
1091 (GDBusInterfaceInfo *) &manager_interface_info,
1092 &manager_interface_vtable,
1093 manager,
1094 NULL, /* user_data_free_func */
1095 &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, manager->priv->map_object_path_to_data);
1106 while (g_hash_table_iter_next (&iter, (gpointer) &object_path, (gpointer) &data))
1107 {
1108 g_hash_table_iter_init (&iface_iter, data->map_iface_name_to_iface);
1109 while (g_hash_table_iter_next (&iface_iter, NULL, (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 (iface,
1114 manager->priv->connection,
1115 object_path,
1116 &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
1129 static void
unexport_all(GDBusObjectManagerServer * manager,gboolean only_manager)1130 unexport_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, manager->priv->map_object_path_to_data);
1150 while (g_hash_table_iter_next (&iter, NULL, (gpointer) &data))
1151 {
1152 g_hash_table_iter_init (&iface_iter, data->map_iface_name_to_iface);
1153 while (g_hash_table_iter_next (&iface_iter, NULL, (gpointer) &iface))
1154 {
1155 g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) != NULL);
1156 g_dbus_interface_skeleton_unexport (iface);
1157 }
1158 }
1159 out:
1160 ;
1161 }
1162
1163 /* ---------------------------------------------------------------------------------------------------- */
1164