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