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