• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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