(root)/
glib-2.79.0/
gio/
gdbusinterfaceskeleton.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 "gdbusinterface.h"
      26  #include "gdbusinterfaceskeleton.h"
      27  #include "gdbusobjectskeleton.h"
      28  #include "gioenumtypes.h"
      29  #include "gdbusprivate.h"
      30  #include "gdbusmethodinvocation.h"
      31  #include "gdbusconnection.h"
      32  #include "gmarshal-internal.h"
      33  #include "gtask.h"
      34  #include "gioerror.h"
      35  
      36  #include "glibintl.h"
      37  
      38  /**
      39   * GDBusInterfaceSkeleton:
      40   *
      41   * Abstract base class for D-Bus interfaces on the service side.
      42   *
      43   * Since: 2.30
      44   */
      45  
      46  struct _GDBusInterfaceSkeletonPrivate
      47  {
      48    GMutex                      lock;
      49  
      50    GDBusObject                *object;
      51    GDBusInterfaceSkeletonFlags flags;
      52  
      53    GSList                     *connections;   /* List of ConnectionData */
      54    gchar                      *object_path;   /* The object path for this skeleton */
      55    GDBusInterfaceVTable       *hooked_vtable;
      56  };
      57  
      58  typedef struct
      59  {
      60    GDBusConnection *connection;
      61    guint            registration_id;
      62  } ConnectionData;
      63  
      64  enum
      65  {
      66    G_AUTHORIZE_METHOD_SIGNAL,
      67    LAST_SIGNAL
      68  };
      69  
      70  enum
      71  {
      72    PROP_0,
      73    PROP_G_FLAGS
      74  };
      75  
      76  static guint signals[LAST_SIGNAL] = {0};
      77  
      78  static void     dbus_interface_interface_init                      (GDBusInterfaceIface    *iface);
      79  
      80  static void     set_object_path_locked                             (GDBusInterfaceSkeleton *interface_,
      81                                                                      const gchar            *object_path);
      82  static void     remove_connection_locked                           (GDBusInterfaceSkeleton *interface_,
      83                                                                      GDBusConnection        *connection);
      84  static void     skeleton_intercept_handle_method_call              (GDBusConnection        *connection,
      85                                                                      const gchar            *sender,
      86                                                                      const gchar            *object_path,
      87                                                                      const gchar            *interface_name,
      88                                                                      const gchar            *method_name,
      89                                                                      GVariant               *parameters,
      90                                                                      GDBusMethodInvocation  *invocation,
      91                                                                      gpointer                user_data);
      92  
      93  
      94  G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GDBusInterfaceSkeleton, g_dbus_interface_skeleton, G_TYPE_OBJECT,
      95                                    G_ADD_PRIVATE (GDBusInterfaceSkeleton)
      96                                    G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_INTERFACE, dbus_interface_interface_init))
      97  
      98  static void
      99  g_dbus_interface_skeleton_finalize (GObject *object)
     100  {
     101    GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (object);
     102  
     103    /* Hold the lock just in case any code we call verifies that the lock is held */
     104    g_mutex_lock (&interface->priv->lock);
     105  
     106    /* unexport from all connections if we're exported anywhere */
     107    while (interface->priv->connections != NULL)
     108      {
     109        ConnectionData *data = interface->priv->connections->data;
     110        remove_connection_locked (interface, data->connection);
     111      }
     112  
     113    set_object_path_locked (interface, NULL);
     114  
     115    g_mutex_unlock (&interface->priv->lock);
     116  
     117    g_free (interface->priv->hooked_vtable);
     118  
     119    if (interface->priv->object != NULL)
     120      g_object_remove_weak_pointer (G_OBJECT (interface->priv->object), (gpointer *) &interface->priv->object);
     121  
     122    g_mutex_clear (&interface->priv->lock);
     123  
     124    G_OBJECT_CLASS (g_dbus_interface_skeleton_parent_class)->finalize (object);
     125  }
     126  
     127  static void
     128  g_dbus_interface_skeleton_get_property (GObject      *object,
     129                                          guint         prop_id,
     130                                          GValue       *value,
     131                                          GParamSpec   *pspec)
     132  {
     133    GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (object);
     134  
     135    switch (prop_id)
     136      {
     137      case PROP_G_FLAGS:
     138        g_value_set_flags (value, g_dbus_interface_skeleton_get_flags (interface));
     139        break;
     140  
     141      default:
     142        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     143        break;
     144      }
     145  }
     146  
     147  static void
     148  g_dbus_interface_skeleton_set_property (GObject      *object,
     149                                          guint         prop_id,
     150                                          const GValue *value,
     151                                          GParamSpec   *pspec)
     152  {
     153    GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (object);
     154  
     155    switch (prop_id)
     156      {
     157      case PROP_G_FLAGS:
     158        g_dbus_interface_skeleton_set_flags (interface, g_value_get_flags (value));
     159        break;
     160  
     161      default:
     162        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     163        break;
     164      }
     165  }
     166  
     167  static gboolean
     168  g_dbus_interface_skeleton_g_authorize_method_default (GDBusInterfaceSkeleton    *interface,
     169                                                        GDBusMethodInvocation *invocation)
     170  {
     171    return TRUE;
     172  }
     173  
     174  static void
     175  g_dbus_interface_skeleton_class_init (GDBusInterfaceSkeletonClass *klass)
     176  {
     177    GObjectClass *gobject_class;
     178  
     179    gobject_class = G_OBJECT_CLASS (klass);
     180    gobject_class->finalize     = g_dbus_interface_skeleton_finalize;
     181    gobject_class->set_property = g_dbus_interface_skeleton_set_property;
     182    gobject_class->get_property = g_dbus_interface_skeleton_get_property;
     183  
     184    klass->g_authorize_method = g_dbus_interface_skeleton_g_authorize_method_default;
     185  
     186    /**
     187     * GDBusInterfaceSkeleton:g-flags:
     188     *
     189     * Flags from the #GDBusInterfaceSkeletonFlags enumeration.
     190     *
     191     * Since: 2.30
     192     */
     193    g_object_class_install_property (gobject_class,
     194                                     PROP_G_FLAGS,
     195                                     g_param_spec_flags ("g-flags", NULL, NULL,
     196                                                         G_TYPE_DBUS_INTERFACE_SKELETON_FLAGS,
     197                                                         G_DBUS_INTERFACE_SKELETON_FLAGS_NONE,
     198                                                         G_PARAM_READABLE |
     199                                                         G_PARAM_WRITABLE |
     200                                                         G_PARAM_STATIC_STRINGS));
     201  
     202    /**
     203     * GDBusInterfaceSkeleton::g-authorize-method:
     204     * @interface: The #GDBusInterfaceSkeleton emitting the signal.
     205     * @invocation: A #GDBusMethodInvocation.
     206     *
     207     * Emitted when a method is invoked by a remote caller and used to
     208     * determine if the method call is authorized.
     209     *
     210     * Note that this signal is emitted in a thread dedicated to
     211     * handling the method call so handlers are allowed to perform
     212     * blocking IO. This means that it is appropriate to call e.g.
     213     * [polkit_authority_check_authorization_sync()](http://hal.freedesktop.org/docs/polkit/PolkitAuthority.html#polkit-authority-check-authorization-sync)
     214     * with the
     215     * [POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION](http://hal.freedesktop.org/docs/polkit/PolkitAuthority.html#POLKIT-CHECK-AUTHORIZATION-FLAGS-ALLOW-USER-INTERACTION:CAPS)
     216     * flag set.
     217     *
     218     * If %FALSE is returned then no further handlers are run and the
     219     * signal handler must take a reference to @invocation and finish
     220     * handling the call (e.g. return an error via
     221     * g_dbus_method_invocation_return_error()).
     222     *
     223     * Otherwise, if %TRUE is returned, signal emission continues. If no
     224     * handlers return %FALSE, then the method is dispatched. If
     225     * @interface has an enclosing #GDBusObjectSkeleton, then the
     226     * #GDBusObjectSkeleton::authorize-method signal handlers run before
     227     * the handlers for this signal.
     228     *
     229     * The default class handler just returns %TRUE.
     230     *
     231     * Please note that the common case is optimized: if no signals
     232     * handlers are connected and the default class handler isn't
     233     * overridden (for both @interface and the enclosing
     234     * #GDBusObjectSkeleton, if any) and #GDBusInterfaceSkeleton:g-flags does
     235     * not have the
     236     * %G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD
     237     * flags set, no dedicated thread is ever used and the call will be
     238     * handled in the same thread as the object that @interface belongs
     239     * to was exported in.
     240     *
     241     * Returns: %TRUE if the call is authorized, %FALSE otherwise.
     242     *
     243     * Since: 2.30
     244     */
     245    signals[G_AUTHORIZE_METHOD_SIGNAL] =
     246      g_signal_new (I_("g-authorize-method"),
     247                    G_TYPE_DBUS_INTERFACE_SKELETON,
     248                    G_SIGNAL_RUN_LAST,
     249                    G_STRUCT_OFFSET (GDBusInterfaceSkeletonClass, g_authorize_method),
     250                    _g_signal_accumulator_false_handled,
     251                    NULL,
     252                    _g_cclosure_marshal_BOOLEAN__OBJECT,
     253                    G_TYPE_BOOLEAN,
     254                    1,
     255                    G_TYPE_DBUS_METHOD_INVOCATION);
     256    g_signal_set_va_marshaller (signals[G_AUTHORIZE_METHOD_SIGNAL],
     257                                G_TYPE_FROM_CLASS (klass),
     258                                _g_cclosure_marshal_BOOLEAN__OBJECTv);
     259  }
     260  
     261  static void
     262  g_dbus_interface_skeleton_init (GDBusInterfaceSkeleton *interface)
     263  {
     264    interface->priv = g_dbus_interface_skeleton_get_instance_private (interface);
     265    g_mutex_init (&interface->priv->lock);
     266  }
     267  
     268  /* ---------------------------------------------------------------------------------------------------- */
     269  
     270  /**
     271   * g_dbus_interface_skeleton_get_flags:
     272   * @interface_: A #GDBusInterfaceSkeleton.
     273   *
     274   * Gets the #GDBusInterfaceSkeletonFlags that describes what the behavior
     275   * of @interface_
     276   *
     277   * Returns: One or more flags from the #GDBusInterfaceSkeletonFlags enumeration.
     278   *
     279   * Since: 2.30
     280   */
     281  GDBusInterfaceSkeletonFlags
     282  g_dbus_interface_skeleton_get_flags (GDBusInterfaceSkeleton  *interface_)
     283  {
     284    g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), G_DBUS_INTERFACE_SKELETON_FLAGS_NONE);
     285    return interface_->priv->flags;
     286  }
     287  
     288  /**
     289   * g_dbus_interface_skeleton_set_flags:
     290   * @interface_: A #GDBusInterfaceSkeleton.
     291   * @flags: Flags from the #GDBusInterfaceSkeletonFlags enumeration.
     292   *
     293   * Sets flags describing what the behavior of @skeleton should be.
     294   *
     295   * Since: 2.30
     296   */
     297  void
     298  g_dbus_interface_skeleton_set_flags (GDBusInterfaceSkeleton      *interface_,
     299                                       GDBusInterfaceSkeletonFlags  flags)
     300  {
     301    g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
     302    g_mutex_lock (&interface_->priv->lock);
     303    if (interface_->priv->flags != flags)
     304      {
     305        interface_->priv->flags = flags;
     306        g_mutex_unlock (&interface_->priv->lock);
     307        g_object_notify (G_OBJECT (interface_), "g-flags");
     308      }
     309    else
     310      {
     311        g_mutex_unlock (&interface_->priv->lock);
     312      }
     313  }
     314  
     315  /**
     316   * g_dbus_interface_skeleton_get_info:
     317   * @interface_: A #GDBusInterfaceSkeleton.
     318   *
     319   * Gets D-Bus introspection information for the D-Bus interface
     320   * implemented by @interface_.
     321   *
     322   * Returns: (transfer none): A #GDBusInterfaceInfo (never %NULL). Do not free.
     323   *
     324   * Since: 2.30
     325   */
     326  GDBusInterfaceInfo *
     327  g_dbus_interface_skeleton_get_info (GDBusInterfaceSkeleton *interface_)
     328  {
     329    GDBusInterfaceInfo *ret;
     330    g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
     331    ret = G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface_)->get_info (interface_);
     332    g_warn_if_fail (ret != NULL);
     333    return ret;
     334  }
     335  
     336  /**
     337   * g_dbus_interface_skeleton_get_vtable:
     338   * @interface_: A #GDBusInterfaceSkeleton.
     339   *
     340   * Gets the interface vtable for the D-Bus interface implemented by
     341   * @interface_. The returned function pointers should expect @interface_
     342   * itself to be passed as @user_data.
     343   *
     344   * Returns: (not nullable) (transfer none): the vtable of the D-Bus interface implemented by the skeleton
     345   *
     346   * Since: 2.30
     347   */
     348  GDBusInterfaceVTable *
     349  g_dbus_interface_skeleton_get_vtable (GDBusInterfaceSkeleton *interface_)
     350  {
     351    GDBusInterfaceVTable *ret;
     352    g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
     353    ret = G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface_)->get_vtable (interface_);
     354    g_warn_if_fail (ret != NULL);
     355    return ret;
     356  }
     357  
     358  /**
     359   * g_dbus_interface_skeleton_get_properties:
     360   * @interface_: A #GDBusInterfaceSkeleton.
     361   *
     362   * Gets all D-Bus properties for @interface_.
     363   *
     364   * Returns: (transfer full): A #GVariant of type
     365   * ['a{sv}'][G-VARIANT-TYPE-VARDICT:CAPS].
     366   * Free with g_variant_unref().
     367   *
     368   * Since: 2.30
     369   */
     370  GVariant *
     371  g_dbus_interface_skeleton_get_properties (GDBusInterfaceSkeleton *interface_)
     372  {
     373    GVariant *ret;
     374    g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
     375    ret = G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface_)->get_properties (interface_);
     376    return g_variant_take_ref (ret);
     377  }
     378  
     379  /**
     380   * g_dbus_interface_skeleton_flush:
     381   * @interface_: A #GDBusInterfaceSkeleton.
     382   *
     383   * If @interface_ has outstanding changes, request for these changes to be
     384   * emitted immediately.
     385   *
     386   * For example, an exported D-Bus interface may queue up property
     387   * changes and emit the
     388   * `org.freedesktop.DBus.Properties.PropertiesChanged`
     389   * signal later (e.g. in an idle handler). This technique is useful
     390   * for collapsing multiple property changes into one.
     391   *
     392   * Since: 2.30
     393   */
     394  void
     395  g_dbus_interface_skeleton_flush (GDBusInterfaceSkeleton *interface_)
     396  {
     397    g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
     398    G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface_)->flush (interface_);
     399  }
     400  
     401  /* ---------------------------------------------------------------------------------------------------- */
     402  
     403  static GDBusInterfaceInfo *
     404  _g_dbus_interface_skeleton_get_info (GDBusInterface *interface_)
     405  {
     406    GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (interface_);
     407    return g_dbus_interface_skeleton_get_info (interface);
     408  }
     409  
     410  static GDBusObject *
     411  g_dbus_interface_skeleton_get_object (GDBusInterface *interface_)
     412  {
     413    GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (interface_);
     414    GDBusObject *ret;
     415    g_mutex_lock (&interface->priv->lock);
     416    ret = interface->priv->object;
     417    g_mutex_unlock (&interface->priv->lock);
     418    return ret;
     419  }
     420  
     421  static GDBusObject *
     422  g_dbus_interface_skeleton_dup_object (GDBusInterface *interface_)
     423  {
     424    GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (interface_);
     425    GDBusObject *ret;
     426    g_mutex_lock (&interface->priv->lock);
     427    ret = interface->priv->object;
     428    if (ret != NULL)
     429      g_object_ref (ret);
     430    g_mutex_unlock (&interface->priv->lock);
     431    return ret;
     432  }
     433  
     434  static void
     435  g_dbus_interface_skeleton_set_object (GDBusInterface *interface_,
     436                                        GDBusObject    *object)
     437  {
     438    GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (interface_);
     439    g_mutex_lock (&interface->priv->lock);
     440    if (interface->priv->object != NULL)
     441      g_object_remove_weak_pointer (G_OBJECT (interface->priv->object), (gpointer *) &interface->priv->object);
     442    interface->priv->object = object;
     443    if (object != NULL)
     444      g_object_add_weak_pointer (G_OBJECT (interface->priv->object), (gpointer *) &interface->priv->object);
     445    g_mutex_unlock (&interface->priv->lock);
     446  }
     447  
     448  static void
     449  dbus_interface_interface_init (GDBusInterfaceIface *iface)
     450  {
     451    iface->get_info    = _g_dbus_interface_skeleton_get_info;
     452    iface->get_object  = g_dbus_interface_skeleton_get_object;
     453    iface->dup_object  = g_dbus_interface_skeleton_dup_object;
     454    iface->set_object  = g_dbus_interface_skeleton_set_object;
     455  }
     456  
     457  /* ---------------------------------------------------------------------------------------------------- */
     458  
     459  typedef struct
     460  {
     461    gint ref_count;  /* (atomic) */
     462    GDBusInterfaceMethodCallFunc  method_call_func;
     463    GDBusMethodInvocation        *invocation;  /* (owned) */
     464  } DispatchData;
     465  
     466  static void
     467  dispatch_data_unref (DispatchData *data)
     468  {
     469    if (g_atomic_int_dec_and_test (&data->ref_count))
     470      {
     471        g_clear_object (&data->invocation);
     472        g_slice_free (DispatchData, data);
     473      }
     474  }
     475  
     476  static DispatchData *
     477  dispatch_data_ref (DispatchData *data)
     478  {
     479    g_atomic_int_inc (&data->ref_count);
     480    return data;
     481  }
     482  
     483  static gboolean
     484  dispatch_invoke_in_context_func (gpointer user_data)
     485  {
     486    DispatchData *data = user_data;
     487    data->method_call_func (g_dbus_method_invocation_get_connection (data->invocation),
     488                            g_dbus_method_invocation_get_sender (data->invocation),
     489                            g_dbus_method_invocation_get_object_path (data->invocation),
     490                            g_dbus_method_invocation_get_interface_name (data->invocation),
     491                            g_dbus_method_invocation_get_method_name (data->invocation),
     492                            g_dbus_method_invocation_get_parameters (data->invocation),
     493                            data->invocation,
     494                            g_dbus_method_invocation_get_user_data (data->invocation));
     495    return FALSE;
     496  }
     497  
     498  static void
     499  dispatch_in_thread_func (GTask        *task,
     500                           gpointer      source_object,
     501                           gpointer      task_data,
     502                           GCancellable *cancellable)
     503  {
     504    DispatchData *data = task_data;
     505    GDBusInterfaceSkeleton *interface = g_task_get_source_object (task);
     506    GDBusInterfaceSkeletonFlags flags;
     507    GDBusObject *object;
     508    gboolean authorized;
     509  
     510    g_mutex_lock (&interface->priv->lock);
     511    flags = interface->priv->flags;
     512    object = interface->priv->object;
     513    if (object != NULL)
     514      g_object_ref (object);
     515    g_mutex_unlock (&interface->priv->lock);
     516  
     517    /* first check on the enclosing object (if any), then the interface */
     518    authorized = TRUE;
     519    if (object != NULL)
     520      {
     521        g_signal_emit_by_name (object,
     522                               "authorize-method",
     523                               interface,
     524                               data->invocation,
     525                               &authorized);
     526      }
     527    if (authorized)
     528      {
     529        g_signal_emit (interface,
     530                       signals[G_AUTHORIZE_METHOD_SIGNAL],
     531                       0,
     532                       data->invocation,
     533                       &authorized);
     534      }
     535  
     536    if (authorized)
     537      {
     538        gboolean run_in_thread;
     539        run_in_thread = (flags & G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
     540        if (run_in_thread)
     541          {
     542            /* might as well just re-use the existing thread */
     543            data->method_call_func (g_dbus_method_invocation_get_connection (data->invocation),
     544                                    g_dbus_method_invocation_get_sender (data->invocation),
     545                                    g_dbus_method_invocation_get_object_path (data->invocation),
     546                                    g_dbus_method_invocation_get_interface_name (data->invocation),
     547                                    g_dbus_method_invocation_get_method_name (data->invocation),
     548                                    g_dbus_method_invocation_get_parameters (data->invocation),
     549                                    data->invocation,
     550                                    g_dbus_method_invocation_get_user_data (data->invocation));
     551          }
     552        else
     553          {
     554            /* bah, back to original context */
     555            g_main_context_invoke_full (g_task_get_context (task),
     556                                        g_task_get_priority (task),
     557                                        dispatch_invoke_in_context_func,
     558                                        dispatch_data_ref (data),
     559                                        (GDestroyNotify) dispatch_data_unref);
     560          }
     561      }
     562    else
     563      {
     564        /* do nothing */
     565      }
     566  
     567    if (object != NULL)
     568      g_object_unref (object);
     569  
     570    g_task_return_boolean (task, TRUE);
     571  }
     572  
     573  static void
     574  g_dbus_interface_method_dispatch_helper (GDBusInterfaceSkeleton       *interface,
     575                                           GDBusInterfaceMethodCallFunc  method_call_func,
     576                                           GDBusMethodInvocation        *invocation)
     577  {
     578    gboolean has_handlers;
     579    gboolean has_default_class_handler;
     580    gboolean emit_authorized_signal;
     581    gboolean run_in_thread;
     582    GDBusInterfaceSkeletonFlags flags;
     583    GDBusObject *object;
     584  
     585    g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface));
     586    g_return_if_fail (method_call_func != NULL);
     587    g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation));
     588  
     589    g_mutex_lock (&interface->priv->lock);
     590    flags = interface->priv->flags;
     591    object = interface->priv->object;
     592    if (object != NULL)
     593      g_object_ref (object);
     594    g_mutex_unlock (&interface->priv->lock);
     595  
     596    /* optimization for the common case where
     597     *
     598     *  a) no handler is connected and class handler is not overridden (both interface and object); and
     599     *  b) method calls are not dispatched in a thread
     600     */
     601    has_handlers = g_signal_has_handler_pending (interface,
     602                                                 signals[G_AUTHORIZE_METHOD_SIGNAL],
     603                                                 0,
     604                                                 TRUE);
     605    has_default_class_handler = (G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface)->g_authorize_method ==
     606                                 g_dbus_interface_skeleton_g_authorize_method_default);
     607  
     608    emit_authorized_signal = (has_handlers || !has_default_class_handler);
     609    if (!emit_authorized_signal)
     610      {
     611        if (object != NULL)
     612          emit_authorized_signal = _g_dbus_object_skeleton_has_authorize_method_handlers (G_DBUS_OBJECT_SKELETON (object));
     613      }
     614  
     615    run_in_thread = (flags & G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
     616    if (!emit_authorized_signal && !run_in_thread)
     617      {
     618        method_call_func (g_dbus_method_invocation_get_connection (invocation),
     619                          g_dbus_method_invocation_get_sender (invocation),
     620                          g_dbus_method_invocation_get_object_path (invocation),
     621                          g_dbus_method_invocation_get_interface_name (invocation),
     622                          g_dbus_method_invocation_get_method_name (invocation),
     623                          g_dbus_method_invocation_get_parameters (invocation),
     624                          invocation,
     625                          g_dbus_method_invocation_get_user_data (invocation));
     626      }
     627    else
     628      {
     629        GTask *task;
     630        DispatchData *data;
     631  
     632        data = g_slice_new0 (DispatchData);
     633        data->method_call_func = method_call_func;
     634        data->invocation = g_object_ref (invocation);
     635        data->ref_count = 1;
     636  
     637        task = g_task_new (interface, NULL, NULL, NULL);
     638        g_task_set_source_tag (task, g_dbus_interface_method_dispatch_helper);
     639        g_task_set_name (task, "[gio] D-Bus interface method dispatch");
     640        g_task_set_task_data (task, data, (GDestroyNotify) dispatch_data_unref);
     641        g_task_run_in_thread (task, dispatch_in_thread_func);
     642        g_object_unref (task);
     643      }
     644  
     645    if (object != NULL)
     646      g_object_unref (object);
     647  }
     648  
     649  static void
     650  skeleton_intercept_handle_method_call (GDBusConnection       *connection,
     651                                         const gchar           *sender,
     652                                         const gchar           *object_path,
     653                                         const gchar           *interface_name,
     654                                         const gchar           *method_name,
     655                                         GVariant              *parameters,
     656                                         GDBusMethodInvocation *invocation,
     657                                         gpointer               user_data)
     658  {
     659    GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (user_data);
     660    g_dbus_interface_method_dispatch_helper (interface,
     661                                             g_dbus_interface_skeleton_get_vtable (interface)->method_call,
     662                                             invocation);
     663  }
     664  
     665  /* ---------------------------------------------------------------------------------------------------- */
     666  
     667  static ConnectionData *
     668  new_connection (GDBusConnection *connection,
     669                  guint            registration_id)
     670  {
     671    ConnectionData *data;
     672  
     673    data = g_slice_new0 (ConnectionData);
     674    data->connection      = g_object_ref (connection);
     675    data->registration_id = registration_id;
     676  
     677    return data;
     678  }
     679  
     680  static void
     681  free_connection (ConnectionData *data)
     682  {
     683    if (data != NULL)
     684      {
     685        g_object_unref (data->connection);
     686        g_slice_free (ConnectionData, data);
     687      }
     688  }
     689  
     690  static gboolean
     691  add_connection_locked (GDBusInterfaceSkeleton *interface_,
     692                         GDBusConnection        *connection,
     693                         GError                **error)
     694  {
     695    ConnectionData *data;
     696    guint registration_id;
     697    gboolean ret = FALSE;
     698  
     699    if (interface_->priv->hooked_vtable == NULL)
     700      {
     701        /* Hook the vtable since we need to intercept method calls for
     702         * ::g-authorize-method and for dispatching in thread vs
     703         * context
     704         *
     705         * We need to wait until subclasses have had time to initialize
     706         * properly before building the hooked_vtable, so we create it
     707         * once at the last minute.
     708         */
     709        interface_->priv->hooked_vtable = g_memdup2 (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable));
     710        interface_->priv->hooked_vtable->method_call = skeleton_intercept_handle_method_call;
     711      }
     712  
     713    registration_id = g_dbus_connection_register_object (connection,
     714                                                         interface_->priv->object_path,
     715                                                         g_dbus_interface_skeleton_get_info (interface_),
     716                                                         interface_->priv->hooked_vtable,
     717                                                         interface_,
     718                                                         NULL, /* user_data_free_func */
     719                                                         error);
     720  
     721    if (registration_id > 0)
     722      {
     723        data = new_connection (connection, registration_id);
     724        interface_->priv->connections = g_slist_append (interface_->priv->connections, data);
     725        ret = TRUE;
     726      }
     727  
     728    return ret;
     729  }
     730  
     731  static void
     732  remove_connection_locked (GDBusInterfaceSkeleton *interface_,
     733                            GDBusConnection        *connection)
     734  {
     735    ConnectionData *data;
     736    GSList *l;
     737  
     738    /* Get the connection in the list and unregister ... */
     739    for (l = interface_->priv->connections; l != NULL; l = l->next)
     740      {
     741        data = l->data;
     742        if (data->connection == connection)
     743          {
     744            g_warn_if_fail (g_dbus_connection_unregister_object (data->connection, data->registration_id));
     745            free_connection (data);
     746            interface_->priv->connections = g_slist_delete_link (interface_->priv->connections, l);
     747            /* we are guaranteed that the connection is only added once, so bail out early */
     748            goto out;
     749          }
     750      }
     751   out:
     752    ;
     753  }
     754  
     755  static void
     756  set_object_path_locked (GDBusInterfaceSkeleton *interface_,
     757                          const gchar            *object_path)
     758  {
     759    if (g_strcmp0 (interface_->priv->object_path, object_path) != 0)
     760      {
     761        g_free (interface_->priv->object_path);
     762        interface_->priv->object_path = g_strdup (object_path);
     763      }
     764  }
     765  
     766  /* ---------------------------------------------------------------------------------------------------- */
     767  
     768  /**
     769   * g_dbus_interface_skeleton_get_connection:
     770   * @interface_: A #GDBusInterfaceSkeleton.
     771   *
     772   * Gets the first connection that @interface_ is exported on, if any.
     773   *
     774   * Returns: (nullable) (transfer none): A #GDBusConnection or %NULL if @interface_ is
     775   * not exported anywhere. Do not free, the object belongs to @interface_.
     776   *
     777   * Since: 2.30
     778   */
     779  GDBusConnection *
     780  g_dbus_interface_skeleton_get_connection (GDBusInterfaceSkeleton *interface_)
     781  {
     782    ConnectionData  *data;
     783    GDBusConnection *ret;
     784  
     785    g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
     786    g_mutex_lock (&interface_->priv->lock);
     787  
     788    ret = NULL;
     789    if (interface_->priv->connections != NULL)
     790      {
     791        data = interface_->priv->connections->data;
     792        if (data != NULL)
     793          ret = data->connection;
     794      }
     795  
     796    g_mutex_unlock (&interface_->priv->lock);
     797  
     798    return ret;
     799  }
     800  
     801  /**
     802   * g_dbus_interface_skeleton_get_connections:
     803   * @interface_: A #GDBusInterfaceSkeleton.
     804   *
     805   * Gets a list of the connections that @interface_ is exported on.
     806   *
     807   * Returns: (element-type GDBusConnection) (transfer full): A list of
     808   *   all the connections that @interface_ is exported on. The returned
     809   *   list should be freed with g_list_free() after each element has
     810   *   been freed with g_object_unref().
     811   *
     812   * Since: 2.32
     813   */
     814  GList *
     815  g_dbus_interface_skeleton_get_connections (GDBusInterfaceSkeleton *interface_)
     816  {
     817    GList           *connections;
     818    GSList          *l;
     819    ConnectionData  *data;
     820  
     821    g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
     822  
     823    g_mutex_lock (&interface_->priv->lock);
     824    connections = NULL;
     825  
     826    for (l = interface_->priv->connections; l != NULL; l = l->next)
     827      {
     828        data        = l->data;
     829        connections = g_list_prepend (connections,
     830                                      /* Return a reference to each connection */
     831                                      g_object_ref (data->connection));
     832      }
     833  
     834    g_mutex_unlock (&interface_->priv->lock);
     835  
     836    return g_list_reverse (connections);
     837  }
     838  
     839  /**
     840   * g_dbus_interface_skeleton_has_connection:
     841   * @interface_: A #GDBusInterfaceSkeleton.
     842   * @connection: A #GDBusConnection.
     843   *
     844   * Checks if @interface_ is exported on @connection.
     845   *
     846   * Returns: %TRUE if @interface_ is exported on @connection, %FALSE otherwise.
     847   *
     848   * Since: 2.32
     849   */
     850  gboolean
     851  g_dbus_interface_skeleton_has_connection (GDBusInterfaceSkeleton     *interface_,
     852                                            GDBusConnection            *connection)
     853  {
     854    GSList *l;
     855    gboolean ret = FALSE;
     856  
     857    g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), FALSE);
     858    g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
     859  
     860    g_mutex_lock (&interface_->priv->lock);
     861  
     862    for (l = interface_->priv->connections; l != NULL; l = l->next)
     863      {
     864        ConnectionData *data = l->data;
     865        if (data->connection == connection)
     866          {
     867            ret = TRUE;
     868            goto out;
     869          }
     870      }
     871  
     872   out:
     873    g_mutex_unlock (&interface_->priv->lock);
     874    return ret;
     875  }
     876  
     877  /**
     878   * g_dbus_interface_skeleton_get_object_path:
     879   * @interface_: A #GDBusInterfaceSkeleton.
     880   *
     881   * Gets the object path that @interface_ is exported on, if any.
     882   *
     883   * Returns: (nullable): A string owned by @interface_ or %NULL if @interface_ is not exported
     884   * anywhere. Do not free, the string belongs to @interface_.
     885   *
     886   * Since: 2.30
     887   */
     888  const gchar *
     889  g_dbus_interface_skeleton_get_object_path (GDBusInterfaceSkeleton *interface_)
     890  {
     891    const gchar *ret;
     892    g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
     893    g_mutex_lock (&interface_->priv->lock);
     894    ret = interface_->priv->object_path;
     895    g_mutex_unlock (&interface_->priv->lock);
     896    return ret;
     897  }
     898  
     899  /**
     900   * g_dbus_interface_skeleton_export:
     901   * @interface_: The D-Bus interface to export.
     902   * @connection: A #GDBusConnection to export @interface_ on.
     903   * @object_path: The path to export the interface at.
     904   * @error: Return location for error or %NULL.
     905   *
     906   * Exports @interface_ at @object_path on @connection.
     907   *
     908   * This can be called multiple times to export the same @interface_
     909   * onto multiple connections however the @object_path provided must be
     910   * the same for all connections.
     911   *
     912   * Use g_dbus_interface_skeleton_unexport() to unexport the object.
     913   *
     914   * Returns: %TRUE if the interface was exported on @connection, otherwise %FALSE with
     915   * @error set.
     916   *
     917   * Since: 2.30
     918   */
     919  gboolean
     920  g_dbus_interface_skeleton_export (GDBusInterfaceSkeleton  *interface_,
     921                                    GDBusConnection         *connection,
     922                                    const gchar             *object_path,
     923                                    GError                 **error)
     924  {
     925    gboolean ret = FALSE;
     926  
     927    g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), FALSE);
     928    g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
     929    g_return_val_if_fail (g_variant_is_object_path (object_path), FALSE);
     930    g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
     931  
     932    /* Assert that the object path is the same for multiple connections here */
     933    g_return_val_if_fail (interface_->priv->object_path == NULL ||
     934                          g_strcmp0 (interface_->priv->object_path, object_path) == 0, FALSE);
     935  
     936    g_mutex_lock (&interface_->priv->lock);
     937  
     938    /* Set the object path */
     939    set_object_path_locked (interface_, object_path);
     940  
     941    /* Add the connection */
     942    ret = add_connection_locked (interface_, connection, error);
     943  
     944    g_mutex_unlock (&interface_->priv->lock);
     945    return ret;
     946  }
     947  
     948  /**
     949   * g_dbus_interface_skeleton_unexport:
     950   * @interface_: A #GDBusInterfaceSkeleton.
     951   *
     952   * Stops exporting @interface_ on all connections it is exported on.
     953   *
     954   * To unexport @interface_ from only a single connection, use
     955   * g_dbus_interface_skeleton_unexport_from_connection()
     956   *
     957   * Since: 2.30
     958   */
     959  void
     960  g_dbus_interface_skeleton_unexport (GDBusInterfaceSkeleton *interface_)
     961  {
     962    g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
     963    g_return_if_fail (interface_->priv->connections != NULL);
     964  
     965    g_mutex_lock (&interface_->priv->lock);
     966  
     967    g_assert (interface_->priv->object_path != NULL);
     968    g_assert (interface_->priv->hooked_vtable != NULL);
     969  
     970    /* Remove all connections */
     971    while (interface_->priv->connections != NULL)
     972      {
     973        ConnectionData *data = interface_->priv->connections->data;
     974        remove_connection_locked (interface_, data->connection);
     975      }
     976  
     977    /* Unset the object path since there are no connections left */
     978    set_object_path_locked (interface_, NULL);
     979  
     980    g_mutex_unlock (&interface_->priv->lock);
     981  }
     982  
     983  
     984  /**
     985   * g_dbus_interface_skeleton_unexport_from_connection:
     986   * @interface_: A #GDBusInterfaceSkeleton.
     987   * @connection: A #GDBusConnection.
     988   *
     989   * Stops exporting @interface_ on @connection.
     990   *
     991   * To stop exporting on all connections the interface is exported on,
     992   * use g_dbus_interface_skeleton_unexport().
     993   *
     994   * Since: 2.32
     995   */
     996  void
     997  g_dbus_interface_skeleton_unexport_from_connection (GDBusInterfaceSkeleton *interface_,
     998                                                      GDBusConnection        *connection)
     999  {
    1000    g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
    1001    g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
    1002    g_return_if_fail (interface_->priv->connections != NULL);
    1003  
    1004    g_mutex_lock (&interface_->priv->lock);
    1005  
    1006    g_assert (interface_->priv->object_path != NULL);
    1007    g_assert (interface_->priv->hooked_vtable != NULL);
    1008  
    1009    remove_connection_locked (interface_, connection);
    1010  
    1011    /* Reset the object path if we removed the last connection */
    1012    if (interface_->priv->connections == NULL)
    1013      set_object_path_locked (interface_, NULL);
    1014  
    1015    g_mutex_unlock (&interface_->priv->lock);
    1016  }
    1017  
    1018  /* ---------------------------------------------------------------------------------------------------- */