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