Trivial: fix a typo
[platform/upstream/glib.git] / gio / gdbusinterfaceskeleton.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 "gdbusinterface.h"
26 #include "gdbusinterfaceskeleton.h"
27 #include "gdbusobjectskeleton.h"
28 #include "gio-marshal.h"
29 #include "gioenumtypes.h"
30 #include "gdbusprivate.h"
31 #include "gdbusmethodinvocation.h"
32 #include "gdbusconnection.h"
33 #include "gioscheduler.h"
34 #include "gioerror.h"
35
36 #include "glibintl.h"
37
38 /**
39  * SECTION:gdbusinterfaceskeleton
40  * @short_description: Service-side D-Bus interface
41  * @include: gio/gio.h
42  *
43  * Abstract base class for D-Bus interfaces on the service side.
44  */
45
46 struct _GDBusInterfaceSkeletonPrivate
47 {
48   GDBusObject *object;
49   GDBusInterfaceSkeletonFlags flags;
50   guint registration_id;
51
52   GDBusConnection *connection;
53   gchar *object_path;
54   GDBusInterfaceVTable *hooked_vtable;
55 };
56
57 enum
58 {
59   G_AUTHORIZE_METHOD_SIGNAL,
60   LAST_SIGNAL
61 };
62
63 enum
64 {
65   PROP_0,
66   PROP_G_FLAGS
67 };
68
69 static guint signals[LAST_SIGNAL] = {0};
70
71 static void dbus_interface_interface_init (GDBusInterfaceIface *iface);
72
73 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GDBusInterfaceSkeleton, g_dbus_interface_skeleton, G_TYPE_OBJECT,
74                                   G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_INTERFACE, dbus_interface_interface_init));
75
76 static void
77 g_dbus_interface_skeleton_finalize (GObject *object)
78 {
79   GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (object);
80   /* unexport if already exported */
81   if (interface->priv->registration_id > 0)
82     g_dbus_interface_skeleton_unexport (interface);
83
84   g_assert (interface->priv->connection == NULL);
85   g_assert (interface->priv->object_path == NULL);
86   g_assert (interface->priv->hooked_vtable == NULL);
87
88   if (interface->priv->object != NULL)
89     g_object_remove_weak_pointer (G_OBJECT (interface->priv->object), (gpointer *) &interface->priv->object);
90   G_OBJECT_CLASS (g_dbus_interface_skeleton_parent_class)->finalize (object);
91 }
92
93 static void
94 g_dbus_interface_skeleton_get_property (GObject      *object,
95                                         guint         prop_id,
96                                         GValue       *value,
97                                         GParamSpec   *pspec)
98 {
99   GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (object);
100
101   switch (prop_id)
102     {
103     case PROP_G_FLAGS:
104       g_value_set_flags (value, g_dbus_interface_skeleton_get_flags (interface));
105       break;
106
107     default:
108       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
109       break;
110     }
111 }
112
113 static void
114 g_dbus_interface_skeleton_set_property (GObject      *object,
115                                         guint         prop_id,
116                                         const GValue *value,
117                                         GParamSpec   *pspec)
118 {
119   GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (object);
120
121   switch (prop_id)
122     {
123     case PROP_G_FLAGS:
124       g_dbus_interface_skeleton_set_flags (interface, g_value_get_flags (value));
125       break;
126
127     default:
128       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
129       break;
130     }
131 }
132
133 static gboolean
134 g_dbus_interface_skeleton_g_authorize_method_default (GDBusInterfaceSkeleton    *interface,
135                                                       GDBusMethodInvocation *invocation)
136 {
137   return TRUE;
138 }
139
140 static void
141 g_dbus_interface_skeleton_class_init (GDBusInterfaceSkeletonClass *klass)
142 {
143   GObjectClass *gobject_class;
144
145   gobject_class = G_OBJECT_CLASS (klass);
146   gobject_class->finalize     = g_dbus_interface_skeleton_finalize;
147   gobject_class->set_property = g_dbus_interface_skeleton_set_property;
148   gobject_class->get_property = g_dbus_interface_skeleton_get_property;
149
150   klass->g_authorize_method = g_dbus_interface_skeleton_g_authorize_method_default;
151
152   /**
153    * GDBusInterfaceSkeleton:g-flags:
154    *
155    * Flags from the #GDBusInterfaceSkeletonFlags enumeration.
156    *
157    * Since: 2.30
158    */
159   g_object_class_install_property (gobject_class,
160                                    PROP_G_FLAGS,
161                                    g_param_spec_flags ("g-flags",
162                                                        "g-flags",
163                                                        "Flags for the interface skeleton",
164                                                        G_TYPE_DBUS_INTERFACE_SKELETON_FLAGS,
165                                                        G_DBUS_INTERFACE_SKELETON_FLAGS_NONE,
166                                                        G_PARAM_READABLE |
167                                                        G_PARAM_WRITABLE |
168                                                        G_PARAM_STATIC_STRINGS));
169
170   /**
171    * GDBusInterfaceSkeleton::g-authorize-method:
172    * @interface: The #GDBusInterfaceSkeleton emitting the signal.
173    * @invocation: A #GDBusMethodInvocation.
174    *
175    * Emitted when a method is invoked by a remote caller and used to
176    * determine if the method call is authorized.
177    *
178    * Note that this signal is emitted in a thread dedicated to
179    * handling the method call so handlers are allowed to perform
180    * blocking IO. This means that it is appropriate to call
181    * e.g. <ulink
182    * url="http://hal.freedesktop.org/docs/polkit/PolkitAuthority.html#polkit-authority-check-authorization-sync">polkit_authority_check_authorization_sync()</ulink>
183    * with the <ulink
184    * url="http://hal.freedesktop.org/docs/polkit/PolkitAuthority.html#POLKIT-CHECK-AUTHORIZATION-FLAGS-ALLOW-USER-INTERACTION:CAPS">POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION</ulink> flag set.
185    *
186    * If %FALSE is returned then no further handlers are run and the
187    * signal handler must take a reference to @invocation and finish
188    * handling the call (e.g. return an error via
189    * g_dbus_method_invocation_return_error()).
190    *
191    * Otherwise, if %TRUE is returned, signal emission continues. If no
192    * handlers return %FALSE, then the method is dispatched. If
193    * @interface has an enclosing #GDBusObjectSkeleton, then the
194    * #GDBusObjectSkeleton::authorize-method signal handlers run before
195    * the handlers for this signal.
196    *
197    * The default class handler just returns %TRUE.
198    *
199    * Please note that the common case is optimized: if no signals
200    * handlers are connected and the default class handler isn't
201    * overridden (for both @interface and the enclosing
202    * #GDBusObjectSkeleton, if any) and #GDBusInterfaceSkeleton:g-flags does
203    * not have the
204    * %G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD
205    * flags set, no dedicated thread is ever used and the call will be
206    * handled in the same thread as the object that @interface belongs
207    * to was exported in.
208    *
209    * Returns: %TRUE if the call is authorized, %FALSE otherwise.
210    *
211    * Since: 2.30
212    */
213   signals[G_AUTHORIZE_METHOD_SIGNAL] =
214     g_signal_new ("g-authorize-method",
215                   G_TYPE_DBUS_INTERFACE_SKELETON,
216                   G_SIGNAL_RUN_LAST,
217                   G_STRUCT_OFFSET (GDBusInterfaceSkeletonClass, g_authorize_method),
218                   _g_signal_accumulator_false_handled,
219                   NULL,
220                   _gio_marshal_BOOLEAN__OBJECT,
221                   G_TYPE_BOOLEAN,
222                   1,
223                   G_TYPE_DBUS_METHOD_INVOCATION);
224
225   g_type_class_add_private (klass, sizeof (GDBusInterfaceSkeletonPrivate));
226 }
227
228 static void
229 g_dbus_interface_skeleton_init (GDBusInterfaceSkeleton *interface)
230 {
231   interface->priv = G_TYPE_INSTANCE_GET_PRIVATE (interface, G_TYPE_DBUS_INTERFACE_SKELETON, GDBusInterfaceSkeletonPrivate);
232 }
233
234 /* ---------------------------------------------------------------------------------------------------- */
235
236 /**
237  * g_dbus_interface_skeleton_get_flags:
238  * @interface_: A #GDBusInterfaceSkeleton.
239  *
240  * Gets the #GDBusInterfaceSkeletonFlags that describes what the behavior
241  * of @interface_
242  *
243  * Returns: One or more flags from the #GDBusInterfaceSkeletonFlags enumeration.
244  *
245  * Since: 2.30
246  */
247 GDBusInterfaceSkeletonFlags
248 g_dbus_interface_skeleton_get_flags (GDBusInterfaceSkeleton  *interface_)
249 {
250   g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), G_DBUS_INTERFACE_SKELETON_FLAGS_NONE);
251   return interface_->priv->flags;
252 }
253
254 /**
255  * g_dbus_interface_skeleton_set_flags:
256  * @interface_: A #GDBusInterfaceSkeleton.
257  * @flags: Flags from the #GDBusInterfaceSkeletonFlags enumeration.
258  *
259  * Sets flags describing what the behavior of @skeleton should be.
260  *
261  * Since: 2.30
262  */
263 void
264 g_dbus_interface_skeleton_set_flags (GDBusInterfaceSkeleton      *interface_,
265                                      GDBusInterfaceSkeletonFlags  flags)
266 {
267   g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
268   if (interface_->priv->flags != flags)
269     {
270       interface_->priv->flags = flags;
271       g_object_notify (G_OBJECT (interface_), "g-flags");
272     }
273 }
274
275 /**
276  * g_dbus_interface_skeleton_get_info:
277  * @interface_: A #GDBusInterfaceSkeleton.
278  *
279  * Gets D-Bus introspection information for the D-Bus interface
280  * implemented by @interface_.
281  *
282  * Returns: (transfer none): A #GDBusInterfaceInfo (never %NULL). Do not free.
283  *
284  * Since: 2.30
285  */
286 GDBusInterfaceInfo *
287 g_dbus_interface_skeleton_get_info (GDBusInterfaceSkeleton *interface_)
288 {
289   GDBusInterfaceInfo *ret;
290   g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
291   ret = G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface_)->get_info (interface_);
292   g_warn_if_fail (ret != NULL);
293   return ret;
294 }
295
296 /**
297  * g_dbus_interface_skeleton_get_vtable: (skip)
298  * @interface_: A #GDBusInterfaceSkeleton.
299  *
300  * Gets the interface vtable for the D-Bus interface implemented by
301  * @interface_. The returned function pointers should expect @interface_
302  * itself to be passed as @user_data.
303  *
304  * Returns: A #GDBusInterfaceVTable (never %NULL).
305  *
306  * Since: 2.30
307  */
308 GDBusInterfaceVTable *
309 g_dbus_interface_skeleton_get_vtable (GDBusInterfaceSkeleton *interface_)
310 {
311   GDBusInterfaceVTable *ret;
312   g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
313   ret = G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface_)->get_vtable (interface_);
314   g_warn_if_fail (ret != NULL);
315   return ret;
316 }
317
318 /**
319  * g_dbus_interface_skeleton_get_properties:
320  * @interface_: A #GDBusInterfaceSkeleton.
321  *
322  * Gets all D-Bus properties for @interface_.
323  *
324  * Returns: A new, floating, #GVariant of type <link linkend="G-VARIANT-TYPE-VARDICT:CAPS">'a{sv}'</link>. Free with g_variant_unref().
325  *
326  * Since: 2.30
327  */
328 GVariant *
329 g_dbus_interface_skeleton_get_properties (GDBusInterfaceSkeleton *interface_)
330 {
331   GVariant *ret;
332   g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
333   ret = G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface_)->get_properties (interface_);
334   g_warn_if_fail (g_variant_is_floating (ret));
335   return ret;
336 }
337
338 /**
339  * g_dbus_interface_skeleton_flush:
340  * @interface_: A #GDBusInterfaceSkeleton.
341  *
342  * If @interface_ has outstanding changes, request for these changes to be
343  * emitted immediately.
344  *
345  * For example, an exported D-Bus interface may queue up property
346  * changes and emit the
347  * <literal>org.freedesktop.DBus.Properties::PropertiesChanged</literal>
348  * signal later (e.g. in an idle handler). This technique is useful
349  * for collapsing multiple property changes into one.
350  *
351  * Since: 2.30
352  */
353 void
354 g_dbus_interface_skeleton_flush (GDBusInterfaceSkeleton *interface_)
355 {
356   g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
357   G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface_)->flush (interface_);
358 }
359
360 /* ---------------------------------------------------------------------------------------------------- */
361
362 static GDBusInterfaceInfo *
363 _g_dbus_interface_skeleton_get_info (GDBusInterface *interface_)
364 {
365   GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (interface_);
366   return g_dbus_interface_skeleton_get_info (interface);
367 }
368
369 static GDBusObject *
370 g_dbus_interface_skeleton_get_object (GDBusInterface *interface_)
371 {
372   GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (interface_);
373   return interface->priv->object;
374 }
375
376 static void
377 g_dbus_interface_skeleton_set_object (GDBusInterface *interface_,
378                                       GDBusObject    *object)
379 {
380   GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (interface_);
381   if (interface->priv->object != NULL)
382     g_object_remove_weak_pointer (G_OBJECT (interface->priv->object), (gpointer *) &interface->priv->object);
383   interface->priv->object = object;
384   if (object != NULL)
385     g_object_add_weak_pointer (G_OBJECT (interface->priv->object), (gpointer *) &interface->priv->object);
386 }
387
388 static void
389 dbus_interface_interface_init (GDBusInterfaceIface *iface)
390 {
391   iface->get_info    = _g_dbus_interface_skeleton_get_info;
392   iface->get_object  = g_dbus_interface_skeleton_get_object;
393   iface->set_object  = g_dbus_interface_skeleton_set_object;
394 }
395
396 /* ---------------------------------------------------------------------------------------------------- */
397
398 typedef struct
399 {
400   volatile gint ref_count;
401   GDBusInterfaceSkeleton       *interface;
402   GDBusInterfaceMethodCallFunc  method_call_func;
403   GDBusMethodInvocation        *invocation;
404   GMainContext                 *context;
405 } DispatchData;
406
407 static void
408 dispatch_data_unref (DispatchData *data)
409 {
410   if (g_atomic_int_dec_and_test (&data->ref_count))
411     {
412       if (data->context != NULL)
413         g_main_context_unref (data->context);
414       g_free (data);
415     }
416 }
417
418 static DispatchData *
419 dispatch_data_ref (DispatchData *data)
420 {
421   g_atomic_int_inc (&data->ref_count);
422   return data;
423 }
424
425 static gboolean
426 dispatch_invoke_in_context_func (gpointer user_data)
427 {
428   DispatchData *data = user_data;
429   data->method_call_func (g_dbus_method_invocation_get_connection (data->invocation),
430                           g_dbus_method_invocation_get_sender (data->invocation),
431                           g_dbus_method_invocation_get_object_path (data->invocation),
432                           g_dbus_method_invocation_get_interface_name (data->invocation),
433                           g_dbus_method_invocation_get_method_name (data->invocation),
434                           g_dbus_method_invocation_get_parameters (data->invocation),
435                           data->invocation,
436                           g_dbus_method_invocation_get_user_data (data->invocation));
437   return FALSE;
438 }
439
440 static gboolean
441 dispatch_in_thread_func (GIOSchedulerJob *job,
442                          GCancellable    *cancellable,
443                          gpointer         user_data)
444 {
445   DispatchData *data = user_data;
446   gboolean authorized;
447
448   /* first check on the enclosing object (if any), then the interface */
449   authorized = TRUE;
450   if (data->interface->priv->object != NULL)
451     {
452       g_signal_emit_by_name (data->interface->priv->object,
453                              "authorize-method",
454                              data->interface,
455                              data->invocation,
456                              &authorized);
457     }
458   if (authorized)
459     {
460       g_signal_emit (data->interface,
461                      signals[G_AUTHORIZE_METHOD_SIGNAL],
462                      0,
463                      data->invocation,
464                      &authorized);
465     }
466
467   if (authorized)
468     {
469       gboolean run_in_thread;
470       run_in_thread = (data->interface->priv->flags & G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
471       if (run_in_thread)
472         {
473           /* might as well just re-use the existing thread */
474           data->method_call_func (g_dbus_method_invocation_get_connection (data->invocation),
475                                   g_dbus_method_invocation_get_sender (data->invocation),
476                                   g_dbus_method_invocation_get_object_path (data->invocation),
477                                   g_dbus_method_invocation_get_interface_name (data->invocation),
478                                   g_dbus_method_invocation_get_method_name (data->invocation),
479                                   g_dbus_method_invocation_get_parameters (data->invocation),
480                                   data->invocation,
481                                   g_dbus_method_invocation_get_user_data (data->invocation));
482         }
483       else
484         {
485           /* bah, back to original context */
486           g_main_context_invoke_full (data->context,
487                                       G_PRIORITY_DEFAULT,
488                                       dispatch_invoke_in_context_func,
489                                       dispatch_data_ref (data),
490                                       (GDestroyNotify) dispatch_data_unref);
491         }
492     }
493   else
494     {
495       /* do nothing */
496     }
497
498   return FALSE;
499 }
500
501 static void
502 g_dbus_interface_method_dispatch_helper (GDBusInterfaceSkeleton       *interface,
503                                          GDBusInterfaceMethodCallFunc  method_call_func,
504                                          GDBusMethodInvocation        *invocation)
505 {
506   gboolean has_handlers;
507   gboolean has_default_class_handler;
508   gboolean emit_authorized_signal;
509   gboolean run_in_thread;
510
511   g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface));
512   g_return_if_fail (method_call_func != NULL);
513   g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation));
514
515   /* optimization for the common case where
516    *
517    *  a) no handler is connected and class handler is not overridden (both interface and object); and
518    *  b) method calls are not dispatched in a thread
519    */
520   has_handlers = g_signal_has_handler_pending (interface,
521                                                signals[G_AUTHORIZE_METHOD_SIGNAL],
522                                                0,
523                                                TRUE);
524   has_default_class_handler = (G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface)->g_authorize_method ==
525                                g_dbus_interface_skeleton_g_authorize_method_default);
526
527   emit_authorized_signal = (has_handlers || !has_default_class_handler);
528   if (!emit_authorized_signal)
529     {
530       if (interface->priv->object != NULL)
531         emit_authorized_signal = _g_dbus_object_skeleton_has_authorize_method_handlers (G_DBUS_OBJECT_SKELETON (interface->priv->object));
532     }
533
534   run_in_thread = (interface->priv->flags & G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
535   if (!emit_authorized_signal && !run_in_thread)
536     {
537       method_call_func (g_dbus_method_invocation_get_connection (invocation),
538                         g_dbus_method_invocation_get_sender (invocation),
539                         g_dbus_method_invocation_get_object_path (invocation),
540                         g_dbus_method_invocation_get_interface_name (invocation),
541                         g_dbus_method_invocation_get_method_name (invocation),
542                         g_dbus_method_invocation_get_parameters (invocation),
543                         invocation,
544                         g_dbus_method_invocation_get_user_data (invocation));
545     }
546   else
547     {
548       DispatchData *data;
549       data = g_new0 (DispatchData, 1);
550       data->interface = interface;
551       data->method_call_func = method_call_func;
552       data->invocation = invocation;
553       data->context = g_main_context_get_thread_default ();
554       data->ref_count = 1;
555       if (data->context != NULL)
556         g_main_context_ref (data->context);
557       g_io_scheduler_push_job (dispatch_in_thread_func,
558                                data,
559                                (GDestroyNotify) dispatch_data_unref,
560                                G_PRIORITY_DEFAULT,
561                                NULL); /* GCancellable* */
562     }
563 }
564
565 static void
566 skeleton_intercept_handle_method_call (GDBusConnection       *connection,
567                                        const gchar           *sender,
568                                        const gchar           *object_path,
569                                        const gchar           *interface_name,
570                                        const gchar           *method_name,
571                                        GVariant              *parameters,
572                                        GDBusMethodInvocation *invocation,
573                                        gpointer               user_data)
574 {
575   GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (user_data);
576   g_dbus_interface_method_dispatch_helper (interface,
577                                            g_dbus_interface_skeleton_get_vtable (interface)->method_call,
578                                            invocation);
579 }
580
581 /* ---------------------------------------------------------------------------------------------------- */
582
583 /**
584  * g_dbus_interface_skeleton_get_connection:
585  * @interface_: A #GDBusInterfaceSkeleton.
586  *
587  * Gets the connection that @interface_ is exported on, if any.
588  *
589  * Returns: (transfer none): A #GDBusConnection or %NULL if @interface_ is
590  * not exported anywhere. Do not free, the object belongs to @interface_.
591  *
592  * Since: 2.30
593  */
594 GDBusConnection *
595 g_dbus_interface_skeleton_get_connection (GDBusInterfaceSkeleton *interface_)
596 {
597   g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
598   return interface_->priv->connection;
599 }
600
601 /**
602  * g_dbus_interface_skeleton_get_object_path:
603  * @interface_: A #GDBusInterfaceSkeleton.
604  *
605  * Gets the object path that @interface_ is exported on, if any.
606  *
607  * Returns: A string owned by @interface_ or %NULL if @interface_ is not exported
608  * anywhere. Do not free, the string belongs to @interface_.
609  *
610  * Since: 2.30
611  */
612 const gchar *
613 g_dbus_interface_skeleton_get_object_path (GDBusInterfaceSkeleton *interface_)
614 {
615   g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
616   return interface_->priv->object_path;
617 }
618
619 /**
620  * g_dbus_interface_skeleton_export:
621  * @interface_: The D-Bus interface to export.
622  * @connection: A #GDBusConnection to export @interface_ on.
623  * @object_path: The path to export the interface at.
624  * @error: Return location for error or %NULL.
625  *
626  * Exports @interface_ at @object_path on @connection.
627  *
628  * Use g_dbus_interface_skeleton_unexport() to unexport the object.
629  *
630  * Returns: %TRUE if the interface was exported, other %FALSE with
631  * @error set.
632  *
633  * Since: 2.30
634  */
635 gboolean
636 g_dbus_interface_skeleton_export (GDBusInterfaceSkeleton  *interface_,
637                                   GDBusConnection         *connection,
638                                   const gchar             *object_path,
639                                   GError                 **error)
640 {
641   gboolean ret;
642
643   g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), 0);
644   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
645   g_return_val_if_fail (g_variant_is_object_path (object_path), 0);
646   g_return_val_if_fail (error == NULL || *error == NULL, 0);
647
648   ret = FALSE;
649   if (interface_->priv->registration_id > 0)
650     {
651       g_set_error_literal (error,
652                            G_IO_ERROR,
653                            G_IO_ERROR_FAILED, /* TODO: new error code */
654                            "The object is already exported");
655       goto out;
656     }
657
658   g_assert (interface_->priv->connection == NULL);
659   g_assert (interface_->priv->object_path == NULL);
660   g_assert (interface_->priv->hooked_vtable == NULL);
661
662   /* Hook the vtable since we need to intercept method calls for
663    * ::g-authorize-method and for dispatching in thread vs
664    * context
665    */
666   interface_->priv->hooked_vtable = g_memdup (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable));
667   interface_->priv->hooked_vtable->method_call = skeleton_intercept_handle_method_call;
668
669   interface_->priv->connection = g_object_ref (connection);
670   interface_->priv->object_path = g_strdup (object_path);
671   interface_->priv->registration_id = g_dbus_connection_register_object (connection,
672                                                                          object_path,
673                                                                          g_dbus_interface_skeleton_get_info (interface_),
674                                                                          interface_->priv->hooked_vtable,
675                                                                          interface_,
676                                                                          NULL, /* user_data_free_func */
677                                                                          error);
678   if (interface_->priv->registration_id == 0)
679     goto out;
680
681   ret = TRUE;
682
683  out:
684   return ret;
685 }
686
687 /**
688  * g_dbus_interface_skeleton_unexport:
689  * @interface_: A #GDBusInterfaceSkeleton.
690  *
691  * Stops exporting an interface previously exported with
692  * g_dbus_interface_skeleton_export().
693  *
694  * Since: 2.30
695  */
696 void
697 g_dbus_interface_skeleton_unexport (GDBusInterfaceSkeleton *interface_)
698 {
699   g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
700   g_return_if_fail (interface_->priv->registration_id > 0);
701
702   g_assert (interface_->priv->connection != NULL);
703   g_assert (interface_->priv->object_path != NULL);
704   g_assert (interface_->priv->hooked_vtable != NULL);
705
706   g_warn_if_fail (g_dbus_connection_unregister_object (interface_->priv->connection,
707                                                        interface_->priv->registration_id));
708
709   g_object_unref (interface_->priv->connection);
710   g_free (interface_->priv->object_path);
711   interface_->priv->connection = NULL;
712   interface_->priv->object_path = NULL;
713   interface_->priv->hooked_vtable = NULL;
714   interface_->priv->registration_id = 0;
715 }
716
717 /* ---------------------------------------------------------------------------------------------------- */