869007e4d069b0e69965136e353040440d50ae2a
[platform/upstream/glib.git] / gio / gdbusobjectskeleton.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 "gdbusobject.h"
26 #include "gdbusobjectskeleton.h"
27 #include "gdbusinterfaceskeleton.h"
28 #include "gdbusprivate.h"
29 #include "gdbusmethodinvocation.h"
30 #include "gdbusintrospection.h"
31 #include "gdbusinterface.h"
32 #include "gdbusutils.h"
33
34 #include "glibintl.h"
35
36 /**
37  * SECTION:gdbusobjectskeleton
38  * @short_description: Service-side D-Bus object
39  * @include: gio/gio.h
40  *
41  * A #GDBusObjectSkeleton instance is essentially a group of D-Bus
42  * interfaces. The set of exported interfaces on the object may be
43  * dynamic and change at runtime.
44  *
45  * This type is intended to be used with #GDBusObjectManager.
46  */
47
48 struct _GDBusObjectSkeletonPrivate
49 {
50   gchar *object_path;
51   GHashTable *map_name_to_iface;
52 };
53
54 enum
55 {
56   PROP_0,
57   PROP_OBJECT_PATH
58 };
59
60 enum
61 {
62   AUTHORIZE_METHOD_SIGNAL,
63   LAST_SIGNAL,
64 };
65
66 static guint signals[LAST_SIGNAL] = {0};
67
68 static void dbus_object_interface_init (GDBusObjectIface *iface);
69
70 G_DEFINE_TYPE_WITH_CODE (GDBusObjectSkeleton, g_dbus_object_skeleton, G_TYPE_OBJECT,
71                          G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT, dbus_object_interface_init));
72
73
74 static void
75 g_dbus_object_skeleton_finalize (GObject *_object)
76 {
77   GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
78
79   g_free (object->priv->object_path);
80   g_hash_table_unref (object->priv->map_name_to_iface);
81
82   if (G_OBJECT_CLASS (g_dbus_object_skeleton_parent_class)->finalize != NULL)
83     G_OBJECT_CLASS (g_dbus_object_skeleton_parent_class)->finalize (_object);
84 }
85
86 static void
87 g_dbus_object_skeleton_get_property (GObject    *_object,
88                                      guint       prop_id,
89                                      GValue     *value,
90                                      GParamSpec *pspec)
91 {
92   GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
93
94   switch (prop_id)
95     {
96     case PROP_OBJECT_PATH:
97       g_value_take_string (value, object->priv->object_path);
98       break;
99
100     default:
101       G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
102       break;
103     }
104 }
105
106 static void
107 g_dbus_object_skeleton_set_property (GObject       *_object,
108                                      guint          prop_id,
109                                      const GValue  *value,
110                                      GParamSpec    *pspec)
111 {
112   GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
113
114   switch (prop_id)
115     {
116     case PROP_OBJECT_PATH:
117       g_dbus_object_skeleton_set_object_path (object, g_value_get_string (value));
118       break;
119
120     default:
121       G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
122       break;
123     }
124 }
125
126 static gboolean
127 g_dbus_object_skeleton_authorize_method_default (GDBusObjectSkeleton    *object,
128                                                  GDBusInterfaceSkeleton *interface,
129                                                  GDBusMethodInvocation  *invocation)
130 {
131   return TRUE;
132 }
133
134 static void
135 g_dbus_object_skeleton_class_init (GDBusObjectSkeletonClass *klass)
136 {
137   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
138
139   gobject_class->finalize     = g_dbus_object_skeleton_finalize;
140   gobject_class->set_property = g_dbus_object_skeleton_set_property;
141   gobject_class->get_property = g_dbus_object_skeleton_get_property;
142
143   klass->authorize_method = g_dbus_object_skeleton_authorize_method_default;
144
145   /**
146    * GDBusObjectSkeleton:object-path:
147    *
148    * The object path where the object is exported.
149    *
150    * Since: 2.30
151    */
152   g_object_class_install_property (gobject_class,
153                                    PROP_OBJECT_PATH,
154                                    g_param_spec_string ("object-path",
155                                                         "Object Path",
156                                                         "The object path where the object is exported",
157                                                         NULL,
158                                                         G_PARAM_READABLE |
159                                                         G_PARAM_WRITABLE |
160                                                         G_PARAM_CONSTRUCT |
161                                                         G_PARAM_STATIC_STRINGS));
162
163   /**
164    * GDBusObjectSkeleton::authorize-method:
165    * @object: The #GDBusObjectSkeleton emitting the signal.
166    * @interface: The #GDBusInterfaceSkeleton that @invocation is for.
167    * @invocation: A #GDBusMethodInvocation.
168    *
169    * Emitted when a method is invoked by a remote caller and used to
170    * determine if the method call is authorized.
171    *
172    * This signal is like #GDBusInterfaceSkeleton<!-- -->'s
173    * #GDBusInterfaceSkeleton::g-authorize-method signal, except that it is
174    * for the enclosing object.
175    *
176    * The default class handler just returns %TRUE.
177    *
178    * Returns: %TRUE if the call is authorized, %FALSE otherwise.
179    *
180    * Since: 2.30
181    */
182   signals[AUTHORIZE_METHOD_SIGNAL] =
183     g_signal_new ("authorize-method",
184                   G_TYPE_DBUS_OBJECT_SKELETON,
185                   G_SIGNAL_RUN_LAST,
186                   G_STRUCT_OFFSET (GDBusObjectSkeletonClass, authorize_method),
187                   _g_signal_accumulator_false_handled,
188                   NULL,
189                   NULL,
190                   G_TYPE_BOOLEAN,
191                   2,
192                   G_TYPE_DBUS_INTERFACE_SKELETON,
193                   G_TYPE_DBUS_METHOD_INVOCATION);
194
195   g_type_class_add_private (klass, sizeof (GDBusObjectSkeletonPrivate));
196 }
197
198 static void
199 g_dbus_object_skeleton_init (GDBusObjectSkeleton *object)
200 {
201   object->priv = G_TYPE_INSTANCE_GET_PRIVATE (object, G_TYPE_DBUS_OBJECT_SKELETON, GDBusObjectSkeletonPrivate);
202   object->priv->map_name_to_iface = g_hash_table_new_full (g_str_hash,
203                                                            g_str_equal,
204                                                            g_free,
205                                                            (GDestroyNotify) g_object_unref);
206 }
207
208 /**
209  * g_dbus_object_skeleton_new:
210  * @object_path: An object path.
211  *
212  * Creates a new #GDBusObjectSkeleton.
213  *
214  * Returns: A #GDBusObjectSkeleton. Free with g_object_unref().
215  *
216  * Since: 2.30
217  */
218 GDBusObjectSkeleton *
219 g_dbus_object_skeleton_new (const gchar *object_path)
220 {
221   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
222   return G_DBUS_OBJECT_SKELETON (g_object_new (G_TYPE_DBUS_OBJECT_SKELETON,
223                                                "object-path", object_path,
224                                                NULL));
225 }
226
227 /**
228  * g_dbus_object_skeleton_set_object_path:
229  * @object: A #GDBusObjectSkeleton.
230  * @object_path: A valid D-Bus object path.
231  *
232  * Sets the object path for @object.
233  *
234  * Since: 2.30
235  */
236 void
237 g_dbus_object_skeleton_set_object_path (GDBusObjectSkeleton *object,
238                                         const gchar     *object_path)
239 {
240   g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
241   g_return_if_fail (object_path == NULL || g_variant_is_object_path (object_path));
242   /* TODO: fail if object is currently exported */
243   if (g_strcmp0 (object->priv->object_path, object_path) != 0)
244     {
245       g_free (object->priv->object_path);
246       object->priv->object_path = g_strdup (object_path);
247       g_object_notify (G_OBJECT (object), "object-path");
248     }
249 }
250
251 static const gchar *
252 g_dbus_object_skeleton_get_object_path (GDBusObject *_object)
253 {
254   GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
255   return object->priv->object_path;
256 }
257
258 /**
259  * g_dbus_object_skeleton_add_interface:
260  * @object: A #GDBusObjectSkeleton.
261  * @interface_: A #GDBusInterfaceSkeleton.
262  *
263  * Adds @interface_ to @object.
264  *
265  * If @object already contains a #GDBusInterfaceSkeleton with the same
266  * interface name, it is removed before @interface_ is added.
267  *
268  * Note that @object takes its own reference on @interface_ and holds
269  * it until removed.
270  *
271  * Since: 2.30
272  */
273 void
274 g_dbus_object_skeleton_add_interface (GDBusObjectSkeleton     *object,
275                                       GDBusInterfaceSkeleton  *interface_)
276 {
277   GDBusInterfaceInfo *info;
278
279   g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
280   g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
281
282   info = g_dbus_interface_skeleton_get_info (interface_);
283   g_object_ref (interface_);
284   g_dbus_object_skeleton_remove_interface_by_name (object, info->name);
285   g_hash_table_insert (object->priv->map_name_to_iface,
286                        g_strdup (info->name),
287                        interface_);
288   g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_), G_DBUS_OBJECT (object));
289   g_signal_emit_by_name (object,
290                          "interface-added",
291                          interface_);
292 }
293
294 /**
295  * g_dbus_object_skeleton_remove_interface:
296  * @object: A #GDBusObjectSkeleton.
297  * @interface_: A #GDBusInterfaceSkeleton.
298  *
299  * Removes @interface_ from @object.
300  *
301  * Since: 2.30
302  */
303 void
304 g_dbus_object_skeleton_remove_interface  (GDBusObjectSkeleton    *object,
305                                           GDBusInterfaceSkeleton *interface_)
306 {
307   GDBusInterfaceSkeleton *other_interface;
308   GDBusInterfaceInfo *info;
309
310   g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
311   g_return_if_fail (G_IS_DBUS_INTERFACE (interface_));
312
313   info = g_dbus_interface_skeleton_get_info (interface_);
314
315   other_interface = g_hash_table_lookup (object->priv->map_name_to_iface, info->name);
316   if (other_interface == NULL)
317     {
318       g_warning ("Tried to remove interface with name %s from object "
319                  "at path %s but no such interface exists",
320                  info->name,
321                  object->priv->object_path);
322     }
323   else if (other_interface != interface_)
324     {
325       g_warning ("Tried to remove interface %p with name %s from object "
326                  "at path %s but the object has the interface %p",
327                  interface_,
328                  info->name,
329                  object->priv->object_path,
330                  other_interface);
331     }
332   else
333     {
334       g_object_ref (interface_);
335       g_warn_if_fail (g_hash_table_remove (object->priv->map_name_to_iface, info->name));
336       g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_), NULL);
337       g_signal_emit_by_name (object,
338                              "interface-removed",
339                              interface_);
340       g_object_unref (interface_);
341     }
342 }
343
344
345 /**
346  * g_dbus_object_skeleton_remove_interface_by_name:
347  * @object: A #GDBusObjectSkeleton.
348  * @interface_name: A D-Bus interface name.
349  *
350  * Removes the #GDBusInterface with @interface_name from @object.
351  *
352  * If no D-Bus interface of the given interface exists, this function
353  * does nothing.
354  *
355  * Since: 2.30
356  */
357 void
358 g_dbus_object_skeleton_remove_interface_by_name (GDBusObjectSkeleton *object,
359                                                  const gchar         *interface_name)
360 {
361   GDBusInterface *interface;
362
363   g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
364   g_return_if_fail (g_dbus_is_interface_name (interface_name));
365
366   interface = g_hash_table_lookup (object->priv->map_name_to_iface, interface_name);
367   if (interface != NULL)
368     {
369       g_object_ref (interface);
370       g_warn_if_fail (g_hash_table_remove (object->priv->map_name_to_iface, interface_name));
371       g_dbus_interface_set_object (interface, NULL);
372       g_signal_emit_by_name (object,
373                              "interface-removed",
374                              interface);
375       g_object_unref (interface);
376     }
377 }
378
379 static GDBusInterface *
380 g_dbus_object_skeleton_get_interface (GDBusObject  *_object,
381                                       const gchar  *interface_name)
382 {
383   GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
384   GDBusInterface *ret;
385
386   g_return_val_if_fail (G_IS_DBUS_OBJECT_SKELETON (object), NULL);
387   g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
388
389   ret = g_hash_table_lookup (object->priv->map_name_to_iface, interface_name);
390   if (ret != NULL)
391     g_object_ref (ret);
392   return ret;
393 }
394
395 static GList *
396 g_dbus_object_skeleton_get_interfaces (GDBusObject *_object)
397 {
398   GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
399   GList *ret;
400   GHashTableIter iter;
401   GDBusInterface *interface;
402
403   g_return_val_if_fail (G_IS_DBUS_OBJECT_SKELETON (object), NULL);
404
405   ret = NULL;
406
407   g_hash_table_iter_init (&iter, object->priv->map_name_to_iface);
408   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &interface))
409     ret = g_list_prepend (ret, g_object_ref (interface));
410
411   return ret;
412 }
413
414 /**
415  * g_dbus_object_skeleton_flush:
416  * @object: A #GDBusObjectSkeleton.
417  *
418  * This method simply calls g_dbus_interface_skeleton_flush() on all
419  * interfaces belonging to @object. See that method for when flushing
420  * is useful.
421  *
422  * Since: 2.30
423  */
424 void
425 g_dbus_object_skeleton_flush (GDBusObjectSkeleton *object)
426 {
427   GHashTableIter iter;
428   GDBusInterfaceSkeleton *interface_skeleton;
429
430   g_hash_table_iter_init (&iter, object->priv->map_name_to_iface);
431   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &interface_skeleton))
432     {
433       g_dbus_interface_skeleton_flush (interface_skeleton);
434     }
435 }
436
437 static void
438 dbus_object_interface_init (GDBusObjectIface *iface)
439 {
440   iface->get_object_path = g_dbus_object_skeleton_get_object_path;
441   iface->get_interfaces  = g_dbus_object_skeleton_get_interfaces;
442   iface->get_interface  = g_dbus_object_skeleton_get_interface;
443 }
444
445 gboolean
446 _g_dbus_object_skeleton_has_authorize_method_handlers (GDBusObjectSkeleton *object)
447 {
448   gboolean has_handlers;
449   gboolean has_default_class_handler;
450
451   has_handlers = g_signal_has_handler_pending (object,
452                                                signals[AUTHORIZE_METHOD_SIGNAL],
453                                                0,
454                                                TRUE);
455   has_default_class_handler = (G_DBUS_OBJECT_SKELETON_GET_CLASS (object)->authorize_method ==
456                                g_dbus_object_skeleton_authorize_method_default);
457
458   return has_handlers || !has_default_class_handler;
459 }