(root)/
glib-2.79.0/
gio/
gdbusobjectskeleton.c
       1  /* GDBus - GLib D-Bus Library
       2   *
       3   * Copyright (C) 2008-2010 Red Hat, Inc.
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   *
       7   * This library is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 2.1 of the License, or (at your option) any later version.
      11   *
      12   * This library is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15   * Lesser General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU Lesser General
      18   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      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   * GDBusObjectSkeleton:
      38   *
      39   * A `GDBusObjectSkeleton` instance is essentially a group of D-Bus
      40   * interfaces. The set of exported interfaces on the object may be
      41   * dynamic and change at runtime.
      42   *
      43   * This type is intended to be used with [iface@Gio.DBusObjectManager].
      44   *
      45   * Since: 2.30
      46   */
      47  
      48  struct _GDBusObjectSkeletonPrivate
      49  {
      50    GMutex lock;
      51    gchar *object_path;
      52    GHashTable *map_name_to_iface;
      53  };
      54  
      55  enum
      56  {
      57    PROP_0,
      58    PROP_G_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_ADD_PRIVATE (GDBusObjectSkeleton)
      73                           G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT, dbus_object_interface_init))
      74  
      75  
      76  static void
      77  g_dbus_object_skeleton_finalize (GObject *_object)
      78  {
      79    GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
      80  
      81    g_free (object->priv->object_path);
      82    g_hash_table_unref (object->priv->map_name_to_iface);
      83  
      84    g_mutex_clear (&object->priv->lock);
      85  
      86    if (G_OBJECT_CLASS (g_dbus_object_skeleton_parent_class)->finalize != NULL)
      87      G_OBJECT_CLASS (g_dbus_object_skeleton_parent_class)->finalize (_object);
      88  }
      89  
      90  static void
      91  g_dbus_object_skeleton_get_property (GObject    *_object,
      92                                       guint       prop_id,
      93                                       GValue     *value,
      94                                       GParamSpec *pspec)
      95  {
      96    GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
      97  
      98    switch (prop_id)
      99      {
     100      case PROP_G_OBJECT_PATH:
     101        g_mutex_lock (&object->priv->lock);
     102        g_value_set_string (value, object->priv->object_path);
     103        g_mutex_unlock (&object->priv->lock);
     104        break;
     105  
     106      default:
     107        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     108        break;
     109      }
     110  }
     111  
     112  static void
     113  g_dbus_object_skeleton_set_property (GObject       *_object,
     114                                       guint          prop_id,
     115                                       const GValue  *value,
     116                                       GParamSpec    *pspec)
     117  {
     118    GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
     119  
     120    switch (prop_id)
     121      {
     122      case PROP_G_OBJECT_PATH:
     123        g_dbus_object_skeleton_set_object_path (object, g_value_get_string (value));
     124        break;
     125  
     126      default:
     127        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     128        break;
     129      }
     130  }
     131  
     132  static gboolean
     133  g_dbus_object_skeleton_authorize_method_default (GDBusObjectSkeleton    *object,
     134                                                   GDBusInterfaceSkeleton *interface,
     135                                                   GDBusMethodInvocation  *invocation)
     136  {
     137    return TRUE;
     138  }
     139  
     140  static void
     141  g_dbus_object_skeleton_class_init (GDBusObjectSkeletonClass *klass)
     142  {
     143    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
     144  
     145    gobject_class->finalize     = g_dbus_object_skeleton_finalize;
     146    gobject_class->set_property = g_dbus_object_skeleton_set_property;
     147    gobject_class->get_property = g_dbus_object_skeleton_get_property;
     148  
     149    klass->authorize_method = g_dbus_object_skeleton_authorize_method_default;
     150  
     151    /**
     152     * GDBusObjectSkeleton:g-object-path:
     153     *
     154     * The object path where the object is exported.
     155     *
     156     * Since: 2.30
     157     */
     158    g_object_class_install_property (gobject_class,
     159                                     PROP_G_OBJECT_PATH,
     160                                     g_param_spec_string ("g-object-path", NULL, NULL,
     161                                                          NULL,
     162                                                          G_PARAM_READABLE |
     163                                                          G_PARAM_WRITABLE |
     164                                                          G_PARAM_CONSTRUCT |
     165                                                          G_PARAM_STATIC_STRINGS));
     166  
     167    /**
     168     * GDBusObjectSkeleton::authorize-method:
     169     * @object: The #GDBusObjectSkeleton emitting the signal.
     170     * @interface: The #GDBusInterfaceSkeleton that @invocation is for.
     171     * @invocation: A #GDBusMethodInvocation.
     172     *
     173     * Emitted when a method is invoked by a remote caller and used to
     174     * determine if the method call is authorized.
     175     *
     176     * This signal is like #GDBusInterfaceSkeleton's
     177     * #GDBusInterfaceSkeleton::g-authorize-method signal,
     178     * except that it is for the enclosing object.
     179     *
     180     * The default class handler just returns %TRUE.
     181     *
     182     * Returns: %TRUE if the call is authorized, %FALSE otherwise.
     183     *
     184     * Since: 2.30
     185     */
     186    signals[AUTHORIZE_METHOD_SIGNAL] =
     187      g_signal_new (I_("authorize-method"),
     188                    G_TYPE_DBUS_OBJECT_SKELETON,
     189                    G_SIGNAL_RUN_LAST,
     190                    G_STRUCT_OFFSET (GDBusObjectSkeletonClass, authorize_method),
     191                    _g_signal_accumulator_false_handled,
     192                    NULL,
     193                    NULL,
     194                    G_TYPE_BOOLEAN,
     195                    2,
     196                    G_TYPE_DBUS_INTERFACE_SKELETON,
     197                    G_TYPE_DBUS_METHOD_INVOCATION);
     198  }
     199  
     200  static void
     201  g_dbus_object_skeleton_init (GDBusObjectSkeleton *object)
     202  {
     203    object->priv = g_dbus_object_skeleton_get_instance_private (object);
     204    g_mutex_init (&object->priv->lock);
     205    object->priv->map_name_to_iface = g_hash_table_new_full (g_str_hash,
     206                                                             g_str_equal,
     207                                                             g_free,
     208                                                             (GDestroyNotify) g_object_unref);
     209  }
     210  
     211  /**
     212   * g_dbus_object_skeleton_new:
     213   * @object_path: An object path.
     214   *
     215   * Creates a new #GDBusObjectSkeleton.
     216   *
     217   * Returns: A #GDBusObjectSkeleton. Free with g_object_unref().
     218   *
     219   * Since: 2.30
     220   */
     221  GDBusObjectSkeleton *
     222  g_dbus_object_skeleton_new (const gchar *object_path)
     223  {
     224    g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
     225    return G_DBUS_OBJECT_SKELETON (g_object_new (G_TYPE_DBUS_OBJECT_SKELETON,
     226                                                 "g-object-path", object_path,
     227                                                 NULL));
     228  }
     229  
     230  /**
     231   * g_dbus_object_skeleton_set_object_path:
     232   * @object: A #GDBusObjectSkeleton.
     233   * @object_path: A valid D-Bus object path.
     234   *
     235   * Sets the object path for @object.
     236   *
     237   * Since: 2.30
     238   */
     239  void
     240  g_dbus_object_skeleton_set_object_path (GDBusObjectSkeleton *object,
     241                                          const gchar     *object_path)
     242  {
     243    g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
     244    g_return_if_fail (object_path == NULL || g_variant_is_object_path (object_path));
     245    g_mutex_lock (&object->priv->lock);
     246    /* TODO: fail if object is currently exported */
     247    if (g_strcmp0 (object->priv->object_path, object_path) != 0)
     248      {
     249        g_free (object->priv->object_path);
     250        object->priv->object_path = g_strdup (object_path);
     251        g_mutex_unlock (&object->priv->lock);
     252        g_object_notify (G_OBJECT (object), "g-object-path");
     253      }
     254    else
     255      {
     256        g_mutex_unlock (&object->priv->lock);
     257      }
     258  }
     259  
     260  static const gchar *
     261  g_dbus_object_skeleton_get_object_path (GDBusObject *_object)
     262  {
     263    GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
     264    const gchar *ret;
     265    g_mutex_lock (&object->priv->lock);
     266    ret = object->priv->object_path;
     267    g_mutex_unlock (&object->priv->lock);
     268    return ret;
     269  }
     270  
     271  /**
     272   * g_dbus_object_skeleton_add_interface:
     273   * @object: A #GDBusObjectSkeleton.
     274   * @interface_: A #GDBusInterfaceSkeleton.
     275   *
     276   * Adds @interface_ to @object.
     277   *
     278   * If @object already contains a #GDBusInterfaceSkeleton with the same
     279   * interface name, it is removed before @interface_ is added.
     280   *
     281   * Note that @object takes its own reference on @interface_ and holds
     282   * it until removed.
     283   *
     284   * Since: 2.30
     285   */
     286  void
     287  g_dbus_object_skeleton_add_interface (GDBusObjectSkeleton     *object,
     288                                        GDBusInterfaceSkeleton  *interface_)
     289  {
     290    GDBusInterfaceInfo *info;
     291    GDBusInterface *interface_to_remove;
     292  
     293    g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
     294    g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
     295  
     296    g_mutex_lock (&object->priv->lock);
     297  
     298    info = g_dbus_interface_skeleton_get_info (interface_);
     299    g_object_ref (interface_);
     300  
     301    interface_to_remove = g_hash_table_lookup (object->priv->map_name_to_iface, info->name);
     302    if (interface_to_remove != NULL)
     303      {
     304        g_object_ref (interface_to_remove);
     305        g_warn_if_fail (g_hash_table_remove (object->priv->map_name_to_iface, info->name));
     306      }
     307    g_hash_table_insert (object->priv->map_name_to_iface,
     308                         g_strdup (info->name),
     309                         g_object_ref (interface_));
     310    g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_), G_DBUS_OBJECT (object));
     311  
     312    g_mutex_unlock (&object->priv->lock);
     313  
     314    if (interface_to_remove != NULL)
     315      {
     316        g_dbus_interface_set_object (interface_to_remove, NULL);
     317        g_signal_emit_by_name (object,
     318                               "interface-removed",
     319                               interface_to_remove);
     320        g_object_unref (interface_to_remove);
     321      }
     322  
     323    g_signal_emit_by_name (object,
     324                           "interface-added",
     325                           interface_);
     326    g_object_unref (interface_);
     327  }
     328  
     329  /**
     330   * g_dbus_object_skeleton_remove_interface:
     331   * @object: A #GDBusObjectSkeleton.
     332   * @interface_: A #GDBusInterfaceSkeleton.
     333   *
     334   * Removes @interface_ from @object.
     335   *
     336   * Since: 2.30
     337   */
     338  void
     339  g_dbus_object_skeleton_remove_interface  (GDBusObjectSkeleton    *object,
     340                                            GDBusInterfaceSkeleton *interface_)
     341  {
     342    GDBusInterfaceSkeleton *other_interface;
     343    GDBusInterfaceInfo *info;
     344  
     345    g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
     346    g_return_if_fail (G_IS_DBUS_INTERFACE (interface_));
     347  
     348    g_mutex_lock (&object->priv->lock);
     349  
     350    info = g_dbus_interface_skeleton_get_info (interface_);
     351  
     352    other_interface = g_hash_table_lookup (object->priv->map_name_to_iface, info->name);
     353    if (other_interface == NULL)
     354      {
     355        g_mutex_unlock (&object->priv->lock);
     356        g_warning ("Tried to remove interface with name %s from object "
     357                   "at path %s but no such interface exists",
     358                   info->name,
     359                   object->priv->object_path);
     360      }
     361    else if (other_interface != interface_)
     362      {
     363        g_mutex_unlock (&object->priv->lock);
     364        g_warning ("Tried to remove interface %p with name %s from object "
     365                   "at path %s but the object has the interface %p",
     366                   interface_,
     367                   info->name,
     368                   object->priv->object_path,
     369                   other_interface);
     370      }
     371    else
     372      {
     373        g_object_ref (interface_);
     374        g_warn_if_fail (g_hash_table_remove (object->priv->map_name_to_iface, info->name));
     375        g_mutex_unlock (&object->priv->lock);
     376        g_dbus_interface_set_object (G_DBUS_INTERFACE (interface_), NULL);
     377        g_signal_emit_by_name (object,
     378                               "interface-removed",
     379                               interface_);
     380        g_object_unref (interface_);
     381      }
     382  }
     383  
     384  
     385  /**
     386   * g_dbus_object_skeleton_remove_interface_by_name:
     387   * @object: A #GDBusObjectSkeleton.
     388   * @interface_name: A D-Bus interface name.
     389   *
     390   * Removes the #GDBusInterface with @interface_name from @object.
     391   *
     392   * If no D-Bus interface of the given interface exists, this function
     393   * does nothing.
     394   *
     395   * Since: 2.30
     396   */
     397  void
     398  g_dbus_object_skeleton_remove_interface_by_name (GDBusObjectSkeleton *object,
     399                                                   const gchar         *interface_name)
     400  {
     401    GDBusInterface *interface;
     402  
     403    g_return_if_fail (G_IS_DBUS_OBJECT_SKELETON (object));
     404    g_return_if_fail (g_dbus_is_interface_name (interface_name));
     405  
     406    g_mutex_lock (&object->priv->lock);
     407    interface = g_hash_table_lookup (object->priv->map_name_to_iface, interface_name);
     408    if (interface != NULL)
     409      {
     410        g_object_ref (interface);
     411        g_warn_if_fail (g_hash_table_remove (object->priv->map_name_to_iface, interface_name));
     412        g_mutex_unlock (&object->priv->lock);
     413        g_dbus_interface_set_object (interface, NULL);
     414        g_signal_emit_by_name (object,
     415                               "interface-removed",
     416                               interface);
     417        g_object_unref (interface);
     418      }
     419    else
     420      {
     421        g_mutex_unlock (&object->priv->lock);
     422      }
     423  }
     424  
     425  static GDBusInterface *
     426  g_dbus_object_skeleton_get_interface (GDBusObject  *_object,
     427                                        const gchar  *interface_name)
     428  {
     429    GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
     430    GDBusInterface *ret;
     431  
     432    g_return_val_if_fail (G_IS_DBUS_OBJECT_SKELETON (object), NULL);
     433    g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
     434  
     435    g_mutex_lock (&object->priv->lock);
     436    ret = g_hash_table_lookup (object->priv->map_name_to_iface, interface_name);
     437    if (ret != NULL)
     438      g_object_ref (ret);
     439    g_mutex_unlock (&object->priv->lock);
     440    return ret;
     441  }
     442  
     443  static GList *
     444  g_dbus_object_skeleton_get_interfaces (GDBusObject *_object)
     445  {
     446    GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (_object);
     447    GList *ret;
     448  
     449    g_return_val_if_fail (G_IS_DBUS_OBJECT_SKELETON (object), NULL);
     450  
     451    ret = NULL;
     452  
     453    g_mutex_lock (&object->priv->lock);
     454    ret = g_hash_table_get_values (object->priv->map_name_to_iface);
     455    g_list_foreach (ret, (GFunc) g_object_ref, NULL);
     456    g_mutex_unlock (&object->priv->lock);
     457  
     458    return ret;
     459  }
     460  
     461  /**
     462   * g_dbus_object_skeleton_flush:
     463   * @object: A #GDBusObjectSkeleton.
     464   *
     465   * This method simply calls g_dbus_interface_skeleton_flush() on all
     466   * interfaces belonging to @object. See that method for when flushing
     467   * is useful.
     468   *
     469   * Since: 2.30
     470   */
     471  void
     472  g_dbus_object_skeleton_flush (GDBusObjectSkeleton *object)
     473  {
     474    GPtrArray *to_flush;
     475  
     476    g_mutex_lock (&object->priv->lock);
     477    to_flush = g_hash_table_get_values_as_ptr_array (object->priv->map_name_to_iface);
     478    g_ptr_array_foreach (to_flush, (GFunc) g_object_ref, NULL);
     479    g_ptr_array_set_free_func (to_flush, g_object_unref);
     480    g_mutex_unlock (&object->priv->lock);
     481  
     482    for (guint i = 0; i < to_flush->len; ++i)
     483      {
     484        g_dbus_interface_skeleton_flush (
     485          G_DBUS_INTERFACE_SKELETON (g_ptr_array_index (to_flush, i)));
     486      }
     487  
     488    g_clear_pointer (&to_flush, g_ptr_array_unref);
     489  }
     490  
     491  static void
     492  dbus_object_interface_init (GDBusObjectIface *iface)
     493  {
     494    iface->get_object_path = g_dbus_object_skeleton_get_object_path;
     495    iface->get_interfaces  = g_dbus_object_skeleton_get_interfaces;
     496    iface->get_interface  = g_dbus_object_skeleton_get_interface;
     497  }
     498  
     499  gboolean
     500  _g_dbus_object_skeleton_has_authorize_method_handlers (GDBusObjectSkeleton *object)
     501  {
     502    gboolean has_handlers;
     503    gboolean has_default_class_handler;
     504  
     505    has_handlers = g_signal_has_handler_pending (object,
     506                                                 signals[AUTHORIZE_METHOD_SIGNAL],
     507                                                 0,
     508                                                 TRUE);
     509    has_default_class_handler = (G_DBUS_OBJECT_SKELETON_GET_CLASS (object)->authorize_method ==
     510                                 g_dbus_object_skeleton_authorize_method_default);
     511  
     512    return has_handlers || !has_default_class_handler;
     513  }