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