gdbusinterfaceskeleton.c 25.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/* GDBus - GLib D-Bus Library
 *
 * Copyright (C) 2008-2010 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 * Author: David Zeuthen <davidz@redhat.com>
 */

#include "config.h"

#include "gdbusinterface.h"
26 27
#include "gdbusinterfaceskeleton.h"
#include "gdbusobjectskeleton.h"
28 29 30 31 32 33 34 35 36 37 38
#include "gio-marshal.h"
#include "gioenumtypes.h"
#include "gdbusprivate.h"
#include "gdbusmethodinvocation.h"
#include "gdbusconnection.h"
#include "gioscheduler.h"
#include "gioerror.h"

#include "glibintl.h"

/**
39
 * SECTION:gdbusinterfaceskeleton
40 41 42 43 44 45
 * @short_description: Service-side D-Bus interface
 * @include: gio/gio.h
 *
 * Abstract base class for D-Bus interfaces on the service side.
 */

46
struct _GDBusInterfaceSkeletonPrivate
47 48
{
  GDBusObject *object;
49
  GDBusInterfaceSkeletonFlags flags;
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
  guint registration_id;

  GDBusConnection *connection;
  gchar *object_path;
  GDBusInterfaceVTable *hooked_vtable;
};

enum
{
  G_AUTHORIZE_METHOD_SIGNAL,
  LAST_SIGNAL
};

enum
{
  PROP_0,
  PROP_G_FLAGS
};

static guint signals[LAST_SIGNAL] = {0};

static void dbus_interface_interface_init (GDBusInterfaceIface *iface);

73
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GDBusInterfaceSkeleton, g_dbus_interface_skeleton, G_TYPE_OBJECT,
74 75 76
                                  G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_INTERFACE, dbus_interface_interface_init));

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 85 86
  g_assert (interface->priv->connection == NULL);
  g_assert (interface->priv->object_path == NULL);
  g_assert (interface->priv->hooked_vtable == NULL);
87

88 89
  if (interface->priv->object != NULL)
    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 95 96 97
g_dbus_interface_skeleton_get_property (GObject      *object,
                                        guint         prop_id,
                                        GValue       *value,
                                        GParamSpec   *pspec)
98
{
99
  GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (object);
100 101 102 103

  switch (prop_id)
    {
    case PROP_G_FLAGS:
104
      g_value_set_flags (value, g_dbus_interface_skeleton_get_flags (interface));
105 106 107 108 109 110 111 112 113
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
114 115 116 117
g_dbus_interface_skeleton_set_property (GObject      *object,
                                        guint         prop_id,
                                        const GValue *value,
                                        GParamSpec   *pspec)
118
{
119
  GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (object);
120 121 122 123

  switch (prop_id)
    {
    case PROP_G_FLAGS:
124
      g_dbus_interface_skeleton_set_flags (interface, g_value_get_flags (value));
125 126 127 128 129 130 131 132 133
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static gboolean
134 135
g_dbus_interface_skeleton_g_authorize_method_default (GDBusInterfaceSkeleton    *interface,
                                                      GDBusMethodInvocation *invocation)
136 137 138 139 140
{
  return TRUE;
}

static void
141
g_dbus_interface_skeleton_class_init (GDBusInterfaceSkeletonClass *klass)
142 143 144 145
{
  GObjectClass *gobject_class;

  gobject_class = G_OBJECT_CLASS (klass);
146 147 148
  gobject_class->finalize     = g_dbus_interface_skeleton_finalize;
  gobject_class->set_property = g_dbus_interface_skeleton_set_property;
  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 160 161 162
   */
  g_object_class_install_property (gobject_class,
                                   PROP_G_FLAGS,
                                   g_param_spec_flags ("g-flags",
                                                       "g-flags",
163 164 165
                                                       "Flags for the interface skeleton",
                                                       G_TYPE_DBUS_INTERFACE_SKELETON_FLAGS,
                                                       G_DBUS_INTERFACE_SKELETON_FLAGS_NONE,
166 167 168 169 170
                                                       G_PARAM_READABLE |
                                                       G_PARAM_WRITABLE |
                                                       G_PARAM_STATIC_STRINGS));

  /**
171 172
   * GDBusInterfaceSkeleton::g-authorize-method:
   * @interface: The #GDBusInterfaceSkeleton emitting the signal.
173 174 175 176 177 178 179 180 181 182 183 184 185 186
   * @invocation: A #GDBusMethodInvocation.
   *
   * Emitted when a method is invoked by a remote caller and used to
   * determine if the method call is authorized.
   *
   * Note that this signal is emitted in a thread dedicated to
   * handling the method call so handlers are allowed to perform
   * blocking IO. This means that it is appropriate to call
   * e.g. <ulink
   * url="http://hal.freedesktop.org/docs/polkit/PolkitAuthority.html#polkit-authority-check-authorization-sync">polkit_authority_check_authorization_sync()</ulink>
   * with the <ulink
   * 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.
   *
   * If %FALSE is returned then no further handlers are run and the
187
   * signal handler must take a reference to @invocation and finish
188 189 190 191 192
   * handling the call (e.g. return an error via
   * g_dbus_method_invocation_return_error()).
   *
   * Otherwise, if %TRUE is returned, signal emission continues. If no
   * handlers return %FALSE, then the method is dispatched. If
193 194 195
   * @interface has an enclosing #GDBusObjectSkeleton, then the
   * #GDBusObjectSkeleton::authorize-method signal handlers run before
   * the handlers for this signal.
196 197 198 199 200 201
   *
   * The default class handler just returns %TRUE.
   *
   * Please note that the common case is optimized: if no signals
   * handlers are connected and the default class handler isn't
   * 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 206 207 208 209
   * flags set, no dedicated thread is ever used and the call will be
   * handled in the same thread as the object that @interface belongs
   * to was exported in.
   *
   * Returns: %TRUE if the call is authorized, %FALSE otherwise.
210 211
   *
   * Since: 2.30
212 213 214
   */
  signals[G_AUTHORIZE_METHOD_SIGNAL] =
    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 219 220 221 222 223 224
                  _g_signal_accumulator_false_handled,
                  NULL,
                  _gio_marshal_BOOLEAN__OBJECT,
                  G_TYPE_BOOLEAN,
                  1,
                  G_TYPE_DBUS_METHOD_INVOCATION);

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 238
 * g_dbus_interface_skeleton_get_flags:
 * @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 248
GDBusInterfaceSkeletonFlags
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 256 257
 * g_dbus_interface_skeleton_set_flags:
 * @interface_: A #GDBusInterfaceSkeleton.
 * @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 265
g_dbus_interface_skeleton_set_flags (GDBusInterfaceSkeleton      *interface_,
                                     GDBusInterfaceSkeletonFlags  flags)
266
{
267
  g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
268
  if (interface_->priv->flags != flags)
269
    {
270 271
      interface_->priv->flags = flags;
      g_object_notify (G_OBJECT (interface_), "g-flags");
272 273 274 275
    }
}

/**
276 277
 * g_dbus_interface_skeleton_get_info:
 * @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 291
  g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
  ret = G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface_)->get_info (interface_);
292 293 294 295 296
  g_warn_if_fail (ret != NULL);
  return ret;
}

/**
297 298
 * g_dbus_interface_skeleton_get_vtable:
 * @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 303 304
 * itself to be passed as @user_data.
 *
 * 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 313
  g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
  ret = G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface_)->get_vtable (interface_);
314 315 316 317 318
  g_warn_if_fail (ret != NULL);
  return ret;
}

/**
319 320
 * g_dbus_interface_skeleton_get_properties:
 * @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 333
  g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
  ret = G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface_)->get_properties (interface_);
334 335 336 337 338
  g_warn_if_fail (g_variant_is_floating (ret));
  return ret;
}

/**
339 340
 * g_dbus_interface_skeleton_flush:
 * @interface_: A #GDBusInterfaceSkeleton.
341
 *
342
 * If @interface_ has outstanding changes, request for these changes to be
343 344 345 346 347 348 349
 * emitted immediately.
 *
 * For example, an exported D-Bus interface may queue up property
 * changes and emit the
 * <literal>org.freedesktop.DBus.Properties::PropertiesChanged</literal>
 * signal later (e.g. in an idle handler). This technique is useful
 * 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 357
  g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
  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 366
  GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (interface_);
  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 378
g_dbus_interface_skeleton_set_object (GDBusInterface *interface_,
                                      GDBusObject    *object)
379
{
380
  GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (interface_);
381 382 383
  if (interface->priv->object != NULL)
    g_object_remove_weak_pointer (G_OBJECT (interface->priv->object), (gpointer *) &interface->priv->object);
  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 389 390
}

static void
dbus_interface_interface_init (GDBusInterfaceIface *iface)
{
391 392 393
  iface->get_info    = _g_dbus_interface_skeleton_get_info;
  iface->get_object  = g_dbus_interface_skeleton_get_object;
  iface->set_object  = g_dbus_interface_skeleton_set_object;
394 395 396 397 398 399 400
}

/* ---------------------------------------------------------------------------------------------------- */

typedef struct
{
  volatile gint ref_count;
401
  GDBusInterfaceSkeleton       *interface;
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
  GDBusInterfaceMethodCallFunc  method_call_func;
  GDBusMethodInvocation        *invocation;
  GMainContext                 *context;
} DispatchData;

static void
dispatch_data_unref (DispatchData *data)
{
  if (g_atomic_int_dec_and_test (&data->ref_count))
    {
      if (data->context != NULL)
        g_main_context_unref (data->context);
      g_free (data);
    }
}

static DispatchData *
dispatch_data_ref (DispatchData *data)
{
  g_atomic_int_inc (&data->ref_count);
  return data;
}

static gboolean
dispatch_invoke_in_context_func (gpointer user_data)
{
  DispatchData *data = user_data;
  data->method_call_func (g_dbus_method_invocation_get_connection (data->invocation),
                          g_dbus_method_invocation_get_sender (data->invocation),
                          g_dbus_method_invocation_get_object_path (data->invocation),
                          g_dbus_method_invocation_get_interface_name (data->invocation),
                          g_dbus_method_invocation_get_method_name (data->invocation),
                          g_dbus_method_invocation_get_parameters (data->invocation),
                          data->invocation,
                          g_dbus_method_invocation_get_user_data (data->invocation));
  return FALSE;
}

static gboolean
dispatch_in_thread_func (GIOSchedulerJob *job,
                         GCancellable    *cancellable,
                         gpointer         user_data)
{
  DispatchData *data = user_data;
  gboolean authorized;

  /* first check on the enclosing object (if any), then the interface */
  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 456 457 458 459
                             data->invocation,
                             &authorized);
    }
  if (authorized)
    {
460
      g_signal_emit (data->interface,
461 462 463 464 465 466 467 468 469
                     signals[G_AUTHORIZE_METHOD_SIGNAL],
                     0,
                     data->invocation,
                     &authorized);
    }

  if (authorized)
    {
      gboolean run_in_thread;
470
      run_in_thread = (data->interface->priv->flags & G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
      if (run_in_thread)
        {
          /* might as well just re-use the existing thread */
          data->method_call_func (g_dbus_method_invocation_get_connection (data->invocation),
                                  g_dbus_method_invocation_get_sender (data->invocation),
                                  g_dbus_method_invocation_get_object_path (data->invocation),
                                  g_dbus_method_invocation_get_interface_name (data->invocation),
                                  g_dbus_method_invocation_get_method_name (data->invocation),
                                  g_dbus_method_invocation_get_parameters (data->invocation),
                                  data->invocation,
                                  g_dbus_method_invocation_get_user_data (data->invocation));
        }
      else
        {
          /* bah, back to original context */
          g_main_context_invoke_full (data->context,
                                      G_PRIORITY_DEFAULT,
                                      dispatch_invoke_in_context_func,
                                      dispatch_data_ref (data),
                                      (GDestroyNotify) dispatch_data_unref);
        }
    }
  else
    {
      /* do nothing */
    }

  return FALSE;
}

static void
502
g_dbus_interface_method_dispatch_helper (GDBusInterfaceSkeleton       *interface,
503 504 505 506 507 508 509 510
                                         GDBusInterfaceMethodCallFunc  method_call_func,
                                         GDBusMethodInvocation        *invocation)
{
  gboolean has_handlers;
  gboolean has_default_class_handler;
  gboolean emit_authorized_signal;
  gboolean run_in_thread;

511
  g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface));
512 513 514 515 516 517 518 519
  g_return_if_fail (method_call_func != NULL);
  g_return_if_fail (G_IS_DBUS_METHOD_INVOCATION (invocation));

  /* optimization for the common case where
   *
   *  a) no handler is connected and class handler is not overridden (both interface and object); and
   *  b) method calls are not dispatched in a thread
   */
520
  has_handlers = g_signal_has_handler_pending (interface,
521 522 523
                                               signals[G_AUTHORIZE_METHOD_SIGNAL],
                                               0,
                                               TRUE);
524 525
  has_default_class_handler = (G_DBUS_INTERFACE_SKELETON_GET_CLASS (interface)->g_authorize_method ==
                               g_dbus_interface_skeleton_g_authorize_method_default);
526 527 528 529

  emit_authorized_signal = (has_handlers || !has_default_class_handler);
  if (!emit_authorized_signal)
    {
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 536 537 538 539 540 541 542 543 544 545 546 547 548 549
  if (!emit_authorized_signal && !run_in_thread)
    {
      method_call_func (g_dbus_method_invocation_get_connection (invocation),
                        g_dbus_method_invocation_get_sender (invocation),
                        g_dbus_method_invocation_get_object_path (invocation),
                        g_dbus_method_invocation_get_interface_name (invocation),
                        g_dbus_method_invocation_get_method_name (invocation),
                        g_dbus_method_invocation_get_parameters (invocation),
                        invocation,
                        g_dbus_method_invocation_get_user_data (invocation));
    }
  else
    {
      DispatchData *data;
      data = g_new0 (DispatchData, 1);
550
      data->interface = interface;
551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
      data->method_call_func = method_call_func;
      data->invocation = invocation;
      data->context = g_main_context_get_thread_default ();
      data->ref_count = 1;
      if (data->context != NULL)
        g_main_context_ref (data->context);
      g_io_scheduler_push_job (dispatch_in_thread_func,
                               data,
                               (GDestroyNotify) dispatch_data_unref,
                               G_PRIORITY_DEFAULT,
                               NULL); /* GCancellable* */
    }
}

static void
566 567 568 569 570 571 572 573
skeleton_intercept_handle_method_call (GDBusConnection       *connection,
                                       const gchar           *sender,
                                       const gchar           *object_path,
                                       const gchar           *interface_name,
                                       const gchar           *method_name,
                                       GVariant              *parameters,
                                       GDBusMethodInvocation *invocation,
                                       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 579 580 581 582 583
                                           invocation);
}

/* ---------------------------------------------------------------------------------------------------- */

/**
584 585
 * g_dbus_interface_skeleton_get_connection:
 * @interface_: A #GDBusInterfaceSkeleton.
586
 *
587
 * Gets the connection that @interface_ is exported on, if any.
588
 *
589 590
 * Returns: (transfer none): A #GDBusConnection or %NULL if @interface_ is
 * 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 603
 * g_dbus_interface_skeleton_get_object_path:
 * @interface_: A #GDBusInterfaceSkeleton.
604
 *
605
 * Gets the object path that @interface_ is exported on, if any.
606
 *
607 608
 * Returns: A string owned by @interface_ or %NULL if @interface_ is not exported
 * 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 622
 * @interface_: The D-Bus interface to export.
 * @connection: A #GDBusConnection to export @interface_ on.
623 624 625
 * @object_path: The path to export the interface at.
 * @error: Return location for error or %NULL.
 *
626
 * Exports @interface_ at @object_path on @connection.
627
 *
628
 * Use g_dbus_interface_skeleton_unexport() to unexport the object.
629 630 631
 *
 * Returns: %TRUE if the interface was exported, other %FALSE with
 * @error set.
632 633
 *
 * Since: 2.30
634 635
 */
gboolean
636 637 638 639
g_dbus_interface_skeleton_export (GDBusInterfaceSkeleton  *interface_,
                                  GDBusConnection         *connection,
                                  const gchar             *object_path,
                                  GError                 **error)
640 641 642
{
  gboolean ret;

643
  g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), 0);
644 645 646 647 648
  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
  g_return_val_if_fail (g_variant_is_object_path (object_path), 0);
  g_return_val_if_fail (error == NULL || *error == NULL, 0);

  ret = FALSE;
649
  if (interface_->priv->registration_id > 0)
650 651 652 653 654 655 656 657
    {
      g_set_error_literal (error,
                           G_IO_ERROR,
                           G_IO_ERROR_FAILED, /* TODO: new error code */
                           "The object is already exported");
      goto out;
    }

658 659 660
  g_assert (interface_->priv->connection == NULL);
  g_assert (interface_->priv->object_path == NULL);
  g_assert (interface_->priv->hooked_vtable == NULL);
661 662 663 664 665

  /* Hook the vtable since we need to intercept method calls for
   * ::g-authorize-method and for dispatching in thread vs
   * context
   */
666 667
  interface_->priv->hooked_vtable = g_memdup (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable));
  interface_->priv->hooked_vtable->method_call = skeleton_intercept_handle_method_call;
668 669 670 671 672

  interface_->priv->connection = g_object_ref (connection);
  interface_->priv->object_path = g_strdup (object_path);
  interface_->priv->registration_id = g_dbus_connection_register_object (connection,
                                                                         object_path,
673
                                                                         g_dbus_interface_skeleton_get_info (interface_),
674 675 676 677 678
                                                                         interface_->priv->hooked_vtable,
                                                                         interface_,
                                                                         NULL, /* user_data_free_func */
                                                                         error);
  if (interface_->priv->registration_id == 0)
679 680 681 682 683 684 685 686 687
    goto out;

  ret = TRUE;

 out:
  return ret;
}

/**
688 689
 * g_dbus_interface_skeleton_unexport:
 * @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 701 702 703 704 705 706 707 708 709 710 711 712 713 714
  g_return_if_fail (interface_->priv->registration_id > 0);

  g_assert (interface_->priv->connection != NULL);
  g_assert (interface_->priv->object_path != NULL);
  g_assert (interface_->priv->hooked_vtable != NULL);

  g_warn_if_fail (g_dbus_connection_unregister_object (interface_->priv->connection,
                                                       interface_->priv->registration_id));

  g_object_unref (interface_->priv->connection);
  g_free (interface_->priv->object_path);
  interface_->priv->connection = NULL;
  interface_->priv->object_path = NULL;
  interface_->priv->hooked_vtable = NULL;
  interface_->priv->registration_id = 0;
715 716 717
}

/* ---------------------------------------------------------------------------------------------------- */