commit 7163c020a6964fdcfc4f1b6da2bfdb623e8da92d
Author: Tristan Van Berkom <tristan.van.berkom@gmail.com>
Date:   Tue Oct 25 18:07:17 2011 -0400

    Allow GDBusInterfaceSkeleton to export itself on multiple connections
    
    Deprecated:
      o g_dbus_interface_skeleton_export
      o g_dbus_interface_skeleton_unexport
      o g_dbus_interface_skeleton_get_connection
    
    Added
      o g_dbus_interface_skeleton_set_object_path
         (and 'g-object-path' property)
      o g_dbus_interface_skeleton_add_connection
      o g_dbus_interface_skeleton_remove_connection
      o g_dbus_interface_skeleton_has_connection
      o g_dbus_interface_skeleton_get_connections
      o g_dbus_interface_skeleton_exported
    
    Code Generator updated to handle multiple connections
    in generated objects skeletons.
    
    GDBusObjectManager code updated to use new and updated apis.
    
    There is also an added example to try:
      gio/tests/gdbus-example-codegen-peer.c

diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 49ac6b1..4497702 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -3286,13 +3286,19 @@ g_dbus_interface_skeleton_flush
 g_dbus_interface_skeleton_get_info
 g_dbus_interface_skeleton_get_vtable
 g_dbus_interface_skeleton_get_properties
-g_dbus_interface_skeleton_export
-g_dbus_interface_skeleton_unexport
-g_dbus_interface_skeleton_get_connection
+g_dbus_interface_skeleton_set_object_path
 g_dbus_interface_skeleton_get_object_path
 GDBusInterfaceSkeletonFlags
 g_dbus_interface_skeleton_get_flags
 g_dbus_interface_skeleton_set_flags
+g_dbus_interface_skeleton_add_connection
+g_dbus_interface_skeleton_remove_connection
+g_dbus_interface_skeleton_get_connections
+g_dbus_interface_skeleton_has_connection
+g_dbus_interface_skeleton_exported
+g_dbus_interface_skeleton_export
+g_dbus_interface_skeleton_unexport
+g_dbus_interface_skeleton_get_connection
 <SUBSECTION Standard>
 G_DBUS_INTERFACE_SKELETON
 G_IS_DBUS_INTERFACE_SKELETON
diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py
index 8d34bdd..9abe2a6 100644
--- a/gio/gdbus-2.0/codegen/codegen.py
+++ b/gio/gdbus-2.0/codegen/codegen.py
@@ -2244,6 +2244,7 @@ class CodeGenerator:
                      '{\n'
                      '  %sSkeleton *skeleton = %s%s_SKELETON (_skeleton);\n'
                      %(i.name_lower, i.camel_name, i.ns_upper, i.name_upper))
+
         self.c.write('\n'
                      '  GVariantBuilder builder;\n'
                      '  guint n;\n'
@@ -2256,7 +2257,7 @@ class CodeGenerator:
                      '      if (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE)\n'
                      '        {\n'
                      '          GVariant *value;\n'
-                     '          value = _%s_skeleton_handle_get_property (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)), NULL, g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (skeleton)), "%s", info->name, NULL, skeleton);\n'
+                     '          value = _%s_skeleton_handle_get_property (NULL, NULL, g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (skeleton)), "%s", info->name, NULL, skeleton);\n'
                      '          if (value != NULL)\n'
                      '            {\n'
                      '              g_variant_take_ref (value);\n'
@@ -2307,21 +2308,26 @@ class CodeGenerator:
                 self.c.write(',\n    %sarg_%s'%(a.ctype_in, a.name))
             self.c.write(')\n'
                          '{\n'
-                         '  %sSkeleton *skeleton = %s%s_SKELETON (object);\n'
-                         '  GDBusConnection *connection = g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton));\n'
+                         '  %sSkeleton *skeleton = %s%s_SKELETON (object);\n\n'
+                         '  GSList     *connections, *l;\n'
+                         '  connections = g_dbus_interface_skeleton_get_connections (G_DBUS_INTERFACE_SKELETON (skeleton));\n'
+                         '  for (l = connections; l; l = l->next)\n'
+                         '    {\n'
+                         '      GDBusConnection *connection = l->data;\n'
                          %(i.camel_name, i.ns_upper, i.name_upper))
-            self.c.write('  if (connection == NULL)\n'
-                         '    return;\n'
-                         '  g_dbus_connection_emit_signal (connection,\n'
-                         '    NULL, g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (skeleton)), "%s", "%s",\n'
-                         '    g_variant_new ("('
+            self.c.write('      g_dbus_connection_emit_signal (connection,\n'
+                         '        NULL, g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (skeleton)), "%s", "%s",\n'
+                         '        g_variant_new ("('
                          %(i.name, s.name))
+
             for a in s.args:
                 self.c.write('%s'%(a.format_in))
             self.c.write(')"')
             for a in s.args:
                 self.c.write(',\n                   arg_%s'%(a.name))
             self.c.write('), NULL);\n')
+            self.c.write('    }\n')
+            self.c.write('  g_slist_free (connections);\n')
             self.c.write('}\n'
                          '\n')
 
@@ -2386,47 +2392,56 @@ class CodeGenerator:
                          '  GVariantBuilder builder;\n'
                          '  GVariantBuilder invalidated_builder;\n'
                          '  guint num_changes;\n'
+                         '  GSList *connections, *list;\n'
                          '\n'
                          '  g_mutex_lock (&skeleton->priv->lock);\n'
-                         '  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));\n'
-                         '  g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));\n'
-                         '  for (l = skeleton->priv->changed_properties, num_changes = 0; l != NULL; l = l->next)\n'
+                         '\n'
+                         '  connections = g_dbus_interface_skeleton_get_connections (G_DBUS_INTERFACE_SKELETON (skeleton));\n'
+                         '  for (list = connections; list; list = list->next)\n'
                          '    {\n'
-                         '      ChangedProperty *cp = l->data;\n'
-                         '      GVariant *variant;\n'
-                         '      const GValue *cur_value;\n'
+                         '      GDBusConnection *connection = list->data;\n'
                          '\n'
-                         '      cur_value = &skeleton->priv->properties->values[cp->prop_id - 1];\n'
-                         '      if (!_g_value_equal (cur_value, &cp->orig_value))\n'
+                         '      g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));\n'
+                         '      g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));\n'
+                         '      for (l = skeleton->priv->changed_properties, num_changes = 0; l != NULL; l = l->next)\n'
                          '        {\n'
-                         '          variant = g_dbus_gvalue_to_gvariant (cur_value, G_VARIANT_TYPE (cp->info->parent_struct.signature));\n'
-                         '          g_variant_builder_add (&builder, "{sv}", cp->info->parent_struct.name, variant);\n'
-                         '          g_variant_unref (variant);\n'
-                         '          num_changes++;\n'
+                         '          ChangedProperty *cp = l->data;\n'
+                         '          GVariant *variant;\n'
+                         '          const GValue *cur_value;\n'
+                         '\n'
+                         '          cur_value = &skeleton->priv->properties->values[cp->prop_id - 1];\n'
+                         '          if (!_g_value_equal (cur_value, &cp->orig_value))\n'
+                         '            {\n'
+                         '              variant = g_dbus_gvalue_to_gvariant (cur_value, G_VARIANT_TYPE (cp->info->parent_struct.signature));\n'
+                         '              g_variant_builder_add (&builder, "{sv}", cp->info->parent_struct.name, variant);\n'
+                         '              num_changes++;\n'
+                         '            }\n'
+                         '        }\n'
+                         '      if (num_changes > 0)\n'
+                         '        {\n'
+                         '          g_dbus_connection_emit_signal (connection,\n'
+                         '                                         NULL, g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (skeleton)),\n'
+                         '                                         "org.freedesktop.DBus.Properties",\n'
+                         '                                         "PropertiesChanged",\n'
+                         '                                         g_variant_new ("(sa{sv}as)",\n'
+                         '                                                        "%s",\n'
+                         '                                                        &builder, &invalidated_builder),\n'
+                         '                                         NULL);\n'
+                         '        }\n'
+                         '      else\n'
+                         '        {\n'
+                         '          g_variant_builder_clear (&builder);\n'
+                         '          g_variant_builder_clear (&invalidated_builder);\n'
                          '        }\n'
-                         '    }\n'
-                         '  if (num_changes > 0)\n'
-                         '    {\n'
-                         '      g_dbus_connection_emit_signal (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)),\n'
-                         '                                     NULL, g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (skeleton)),\n'
-                         '                                     "org.freedesktop.DBus.Properties",\n'
-                         '                                     "PropertiesChanged",\n'
-                         '                                     g_variant_new ("(sa{sv}as)",\n'
-                         '                                                    "%s",\n'
-                         '                                                    &builder, &invalidated_builder),\n'
-                         '                                     NULL);\n'
-                         '    }\n'
-                         '  else\n'
-                         '    {\n'
-                         '      g_variant_builder_clear (&builder);\n'
-                         '      g_variant_builder_clear (&invalidated_builder);\n'
                          '    }\n'
                          %(i.name))
             self.c.write('  g_list_foreach (skeleton->priv->changed_properties, (GFunc) _changed_property_free, NULL);\n')
             self.c.write('  g_list_free (skeleton->priv->changed_properties);\n')
             self.c.write('  skeleton->priv->changed_properties = NULL;\n')
             self.c.write('  skeleton->priv->changed_properties_idle_source = NULL;\n')
+            self.c.write('  g_slist_free (connections);\n')
             self.c.write('  g_mutex_unlock (&skeleton->priv->lock);\n')
+                         
             self.c.write('  return FALSE;\n'
                          '}\n'
                          '\n')
@@ -2496,7 +2511,7 @@ class CodeGenerator:
                          '  g_object_freeze_notify (object);\n'
                          '  if (!_g_value_equal (value, &skeleton->priv->properties->values[prop_id - 1]))\n'
                          '    {\n'
-                         '      if (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)) != NULL)\n'
+                         '      if (g_dbus_interface_skeleton_exported (G_DBUS_INTERFACE_SKELETON (skeleton)))\n'
                          '        _%s_schedule_emit_changed (skeleton, _%s_property_info_pointers[prop_id - 1], prop_id, &skeleton->priv->properties->values[prop_id - 1]);\n'
                          '      g_value_copy (value, &skeleton->priv->properties->values[prop_id - 1]);\n'
                          '      g_object_notify_by_pspec (object, pspec);\n'
diff --git a/gio/gdbusinterfaceskeleton.c b/gio/gdbusinterfaceskeleton.c
index 0cd5d6f..e573ce3 100644
--- a/gio/gdbusinterfaceskeleton.c
+++ b/gio/gdbusinterfaceskeleton.c
@@ -44,17 +44,21 @@
 
 struct _GDBusInterfaceSkeletonPrivate
 {
-  GMutex lock;
+  GMutex                      lock;
 
-  GDBusObject *object;
+  GDBusObject                *object;
   GDBusInterfaceSkeletonFlags flags;
-  guint registration_id;
 
-  GDBusConnection *connection;
-  gchar *object_path;
-  GDBusInterfaceVTable *hooked_vtable;
+  GSList                     *connections;   /* List of ConnectionData */
+  gchar                      *object_path;   /* The object path for this skeleton */
+  GDBusInterfaceVTable       *hooked_vtable;
 };
 
+typedef struct {
+  GDBusConnection *connection;
+  guint            registration_id;
+} ConnectionData;
+
 enum
 {
   G_AUTHORIZE_METHOD_SIGNAL,
@@ -64,12 +68,27 @@ enum
 enum
 {
   PROP_0,
-  PROP_G_FLAGS
+  PROP_G_FLAGS,
+  PROP_G_OBJECT_PATH
 };
 
 static guint signals[LAST_SIGNAL] = {0};
 
-static void dbus_interface_interface_init (GDBusInterfaceIface *iface);
+static void     dbus_interface_interface_init                      (GDBusInterfaceIface    *iface);
+
+static gboolean g_dbus_interface_skeleton_set_object_path_locked   (GDBusInterfaceSkeleton *interface_,
+								    const gchar            *object_path);
+static void     g_dbus_interface_skeleton_remove_connection_locked (GDBusInterfaceSkeleton *interface_,
+								    GDBusConnection        *connection);
+static void     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);
+
 
 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GDBusInterfaceSkeleton, g_dbus_interface_skeleton, G_TYPE_OBJECT,
                                   G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_INTERFACE, dbus_interface_interface_init));
@@ -78,16 +97,28 @@ static void
 g_dbus_interface_skeleton_finalize (GObject *object)
 {
   GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (object);
-  /* unexport if already exported */
-  if (interface->priv->registration_id > 0)
-    g_dbus_interface_skeleton_unexport (interface);
 
-  g_assert (interface->priv->connection == NULL);
-  g_assert (interface->priv->object_path == NULL);
-  g_assert (interface->priv->hooked_vtable == NULL);
+  /* Do we need to hold the lock here ?? */
+  g_mutex_lock (&interface->priv->lock);
+
+  /* unexport from all connections if we're exported anywhere */
+  while (interface->priv->connections)
+    {
+      ConnectionData *data = interface->priv->connections->data;
+
+      g_dbus_interface_skeleton_remove_connection_locked (interface, data->connection);
+    }
+
+  g_dbus_interface_skeleton_set_object_path_locked (interface, NULL);
+
+  g_mutex_unlock (&interface->priv->lock);
+
+
+  g_free (interface->priv->hooked_vtable);
 
   if (interface->priv->object != NULL)
-    g_object_remove_weak_pointer (G_OBJECT (interface->priv->object), (gpointer *) &interface->priv->object);
+    g_object_remove_weak_pointer (G_OBJECT (interface->priv->object),
+				  (gpointer *) &interface->priv->object);
 
   g_mutex_clear (&interface->priv->lock);
 
@@ -108,6 +139,10 @@ g_dbus_interface_skeleton_get_property (GObject      *object,
       g_value_set_flags (value, g_dbus_interface_skeleton_get_flags (interface));
       break;
 
+    case PROP_G_OBJECT_PATH:
+      g_value_set_string (value, g_dbus_interface_skeleton_get_object_path (interface));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -128,6 +163,10 @@ g_dbus_interface_skeleton_set_property (GObject      *object,
       g_dbus_interface_skeleton_set_flags (interface, g_value_get_flags (value));
       break;
 
+    case PROP_G_OBJECT_PATH:
+      g_dbus_interface_skeleton_set_object_path (interface, g_value_get_string (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -172,6 +211,23 @@ g_dbus_interface_skeleton_class_init (GDBusInterfaceSkeletonClass *klass)
                                                        G_PARAM_STATIC_STRINGS));
 
   /**
+   * GDBusInterfaceSkeleton:g-object-path:
+   *
+   * The object path where the interface is exported.
+   *
+   * Since: 2.32
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_G_OBJECT_PATH,
+                                   g_param_spec_string ("g-object-path",
+                                                        "Object Path",
+                                                        "The object path where the interface is exported",
+                                                        NULL,
+                                                        G_PARAM_READABLE |
+                                                        G_PARAM_WRITABLE |
+                                                        G_PARAM_STATIC_STRINGS));
+
+  /**
    * GDBusInterfaceSkeleton::g-authorize-method:
    * @interface: The #GDBusInterfaceSkeleton emitting the signal.
    * @invocation: A #GDBusMethodInvocation.
@@ -232,7 +288,11 @@ g_dbus_interface_skeleton_class_init (GDBusInterfaceSkeletonClass *klass)
 static void
 g_dbus_interface_skeleton_init (GDBusInterfaceSkeleton *interface)
 {
-  interface->priv = G_TYPE_INSTANCE_GET_PRIVATE (interface, G_TYPE_DBUS_INTERFACE_SKELETON, GDBusInterfaceSkeletonPrivate);
+  interface->priv = 
+    G_TYPE_INSTANCE_GET_PRIVATE (interface,
+				 G_TYPE_DBUS_INTERFACE_SKELETON,
+				 GDBusInterfaceSkeletonPrivate);
+
   g_mutex_init (&interface->priv->lock);
 }
 
@@ -617,6 +677,29 @@ skeleton_intercept_handle_method_call (GDBusConnection       *connection,
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+ConnectionData *
+new_connection (GDBusConnection *connection,
+		guint            registration_id)
+{
+  ConnectionData *data;
+
+  data = g_slice_new0 (ConnectionData);
+  data->connection      = g_object_ref (connection);
+  data->registration_id = registration_id;
+
+  return data;
+}
+
+void
+free_connection (ConnectionData *data)
+{
+  if (data)
+    {
+      g_object_unref (data->connection);
+      g_slice_free (ConnectionData, data);
+    }
+}
+
 /**
  * g_dbus_interface_skeleton_get_connection:
  * @interface_: A #GDBusInterfaceSkeleton.
@@ -626,24 +709,81 @@ skeleton_intercept_handle_method_call (GDBusConnection       *connection,
  * Returns: (transfer none): A #GDBusConnection or %NULL if @interface_ is
  * not exported anywhere. Do not free, the object belongs to @interface_.
  *
- * Since: 2.30
+ * Deprecated: 2.32: g_dbus_interface_skeleton_get_connections() instead.
  */
 GDBusConnection *
 g_dbus_interface_skeleton_get_connection (GDBusInterfaceSkeleton *interface_)
 {
-  GDBusConnection *ret;
+  ConnectionData  *data;
+  GDBusConnection *connection;
+
   g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
+
   g_mutex_lock (&interface_->priv->lock);
-  ret = interface_->priv->connection;
+
+  /* To support the old api we just return the first connection
+   * in the list, we can pretty much assume it will be the only
+   * one in any case if the older api is used. */
+  data = interface_->priv->connections->data;
+  if (data)
+    connection = data->connection;
+  else
+    connection = NULL;
+
   g_mutex_unlock (&interface_->priv->lock);
-  return ret;
+
+  return connection;
+}
+
+static gboolean
+g_dbus_interface_skeleton_set_object_path_locked (GDBusInterfaceSkeleton *interface_,
+						  const gchar            *object_path)
+{
+  if (g_strcmp0 (interface_->priv->object_path, object_path) != 0)
+    {
+      g_free (interface_->priv->object_path);
+      interface_->priv->object_path = g_strdup (object_path);
+
+      return TRUE;
+    }
+  return FALSE;
+}
+
+/**
+ * g_dbus_interface_skeleton_set_object_path:
+ * @interface_: A #GDBusInterfaceSkeleton.
+ * @object_path: The object path to set
+ *
+ * Sets the object path that @interface_ exports itself on.
+ *
+ * You must call this function while @interface_ is not yet
+ * exported on any connections. Otherwise it will fire a 
+ * warning message and do nothing.
+ *
+ * Since: 2.32
+ */
+void
+g_dbus_interface_skeleton_set_object_path (GDBusInterfaceSkeleton *interface_,
+					   const gchar            *object_path)
+{
+  gboolean changed;
+
+  g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
+  g_return_if_fail (object_path && object_path[0]);
+
+  g_mutex_lock (&interface_->priv->lock);
+  changed = g_dbus_interface_skeleton_set_object_path_locked (interface_, object_path);
+  g_mutex_unlock (&interface_->priv->lock);
+
+  if (changed)
+    g_object_notify (G_OBJECT (interface_), "g-object-path");
 }
 
 /**
  * g_dbus_interface_skeleton_get_object_path:
  * @interface_: A #GDBusInterfaceSkeleton.
  *
- * Gets the object path that @interface_ is exported on, if any.
+ * Gets the object path that @interface_ is configured to export itself on.
  *
  * Returns: A string owned by @interface_ or %NULL if @interface_ is not exported
  * anywhere. Do not free, the string belongs to @interface_.
@@ -661,6 +801,236 @@ g_dbus_interface_skeleton_get_object_path (GDBusInterfaceSkeleton *interface_)
   return ret;
 }
 
+static gboolean
+g_dbus_interface_skeleton_add_connection_locked (GDBusInterfaceSkeleton *interface_,
+						 GDBusConnection        *connection,
+						 GError                **error)
+{
+
+  GDBusInterfaceSkeletonPrivate *priv = interface_->priv;
+  ConnectionData                *data;
+  guint                          registration_id;
+
+  if (!priv->hooked_vtable)
+    {
+      /* Hook the vtable since we need to intercept method calls for
+       * ::g-authorize-method and for dispatching in thread vs
+       * context
+       */
+      priv->hooked_vtable =
+	g_memdup (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable));
+      priv->hooked_vtable->method_call = skeleton_intercept_handle_method_call;
+    }
+
+  registration_id =
+    g_dbus_connection_register_object (connection,
+				       priv->object_path,
+				       g_dbus_interface_skeleton_get_info (interface_),
+				       priv->hooked_vtable,
+				       interface_,
+				       NULL, /* user_data_free_func */
+				       error);
+
+  if (registration_id > 0)
+    {
+      data = new_connection (connection, registration_id);
+
+      priv->connections =
+	g_slist_prepend (priv->connections, data);
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * g_dbus_interface_skeleton_add_connection:
+ * @interface_: The D-Bus interface to export.
+ * @connection: A #GDBusConnection to export @interface_ on.
+ * @error:      Return location for error or %NULL.
+ *
+ * Adds @connection to the list of connections which
+ * @interface_ is exported on.
+ *
+ * Use g_dbus_interface_skeleton_remove_connection() to remove this
+ * connection from the list.
+ *
+ * Returns: %TRUE if the interface was exported, other %FALSE with
+ * @error set.
+ *
+ * Since: 2.32
+ */
+gboolean
+g_dbus_interface_skeleton_add_connection (GDBusInterfaceSkeleton *interface_,
+					  GDBusConnection        *connection,
+					  GError                **error)
+{
+  gboolean ret;
+
+  g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), 0);
+  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
+
+  /* The object path must already be defined for this skeleton */
+  g_return_val_if_fail (g_variant_is_object_path (interface_->priv->object_path), 0);
+
+  g_mutex_lock (&interface_->priv->lock);
+  ret = g_dbus_interface_skeleton_add_connection_locked (interface_, connection, error);
+  g_mutex_unlock (&interface_->priv->lock);
+
+  return ret;
+}
+
+static void
+g_dbus_interface_skeleton_remove_connection_locked (GDBusInterfaceSkeleton *interface_,
+						    GDBusConnection        *connection)
+{
+
+  GDBusInterfaceSkeletonPrivate *priv;
+  ConnectionData                *data;
+  GSList                        *list;
+
+  priv = interface_->priv;
+
+  /* Get the connection in the list and unregister ... */
+  for (list = priv->connections; list; list = list->next)
+    {
+      data = list->data;
+
+      if (data->connection == connection)
+	{
+	  g_warn_if_fail
+	    (g_dbus_connection_unregister_object (data->connection, data->registration_id));
+
+	  free_connection (data);
+
+	  priv->connections =
+	    g_slist_delete_link (priv->connections, list);
+	}
+    }
+}
+
+/**
+ * g_dbus_interface_skeleton_remove_connection:
+ * @interface_: The D-Bus interface to export.
+ * @connection: The #GDBusConnection which should be removed.
+ *
+ * Removes @connection from the list of connections which
+ * @interface_ is exported on.
+ *
+ * Since: 2.32
+ */
+void
+g_dbus_interface_skeleton_remove_connection (GDBusInterfaceSkeleton *interface_,
+					     GDBusConnection        *connection)
+{
+  g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
+  g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
+
+  g_mutex_lock (&interface_->priv->lock);
+  g_dbus_interface_skeleton_remove_connection_locked (interface_, connection);
+  g_mutex_unlock (&interface_->priv->lock);
+}
+
+/**
+ * g_dbus_interface_skeleton_get_connections:
+ * @interface_: The D-Bus interface.
+ *
+ * Reports all the connections that @interface_ is exported
+ * on via g_dbus_interface_skeleton_add_connection().
+ *
+ * Returns: (element-type GDBusConnection) (transfer container):
+ *   A newly allocated #GSList of #GDBusConnections owned by @interface_
+ *   which should be freed with g_slist_free().
+ *
+ * Since: 2.32
+ */
+GSList *
+g_dbus_interface_skeleton_get_connections (GDBusInterfaceSkeleton *interface_)
+{
+  GSList          *list, *connections;
+  ConnectionData  *data;
+
+  g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
+
+  g_mutex_lock (&interface_->priv->lock);
+  connections = NULL;
+
+  /* This form of loop should be safe for modifying
+   * the connection list from the foreach callback.
+   *
+   * It will not be safe if more than one thread
+   * tries to add/remove connections from the same
+   * skeleton
+   */
+    for (list = interface_->priv->connections; list; list = list->next)
+    {
+      data        = list->data;
+      connections = g_slist_prepend (connections, data->connection);
+    }
+
+  g_mutex_unlock (&interface_->priv->lock);
+
+  return connections;
+}
+
+
+/**
+ * g_dbus_interface_skeleton_has_connection:
+ * @interface_: The D-Bus interface.
+ * @connection: The #GDBusConnection to check
+ *
+ * Checks if @connection is one of the connections @interface_ has
+ * been exported onto with g_dbus_interface_skeleton_add_connection().
+ *
+ * Returns: whether @interface is exported on @connection
+ *
+ * Since: 2.32
+ */
+gboolean
+g_dbus_interface_skeleton_has_connection (GDBusInterfaceSkeleton     *interface_,
+					  GDBusConnection            *connection)
+{
+  GSList *list;
+  gboolean ret;
+  g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), FALSE);
+  g_mutex_lock (&interface_->priv->lock);
+
+  for (ret = FALSE, list = interface_->priv->connections;
+       ret == FALSE && list != NULL;
+       list = list->next)
+    {
+      ConnectionData *data = list->data;
+
+      ret = (data->connection == connection);
+    }
+
+  g_mutex_unlock (&interface_->priv->lock);
+  return ret;
+}
+
+/**
+ * g_dbus_interface_skeleton_exported:
+ * @interface_: The D-Bus interface to export.
+ * 
+ * A quick check to see if @interface_ is exported on
+ * any #GDBusConnections.
+ *
+ * Returns: %TRUE if @interface_ is exported on at least one connection.
+ *
+ * Since: 2.32
+ */
+gboolean
+g_dbus_interface_skeleton_exported (GDBusInterfaceSkeleton *interface_)
+{
+  gboolean ret;
+  g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), FALSE);
+  g_mutex_lock (&interface_->priv->lock);
+  ret = interface_->priv->connections != NULL;
+  g_mutex_unlock (&interface_->priv->lock);
+  return ret;
+}
+
 /**
  * g_dbus_interface_skeleton_export:
  * @interface_: The D-Bus interface to export.
@@ -675,7 +1045,7 @@ g_dbus_interface_skeleton_get_object_path (GDBusInterfaceSkeleton *interface_)
  * Returns: %TRUE if the interface was exported, other %FALSE with
  * @error set.
  *
- * Since: 2.30
+ * Deprecated: 2.32: Use g_dbus_interface_skeleton_add_connection() instead.
  */
 gboolean
 g_dbus_interface_skeleton_export (GDBusInterfaceSkeleton  *interface_,
@@ -691,44 +1061,24 @@ g_dbus_interface_skeleton_export (GDBusInterfaceSkeleton  *interface_,
   g_return_val_if_fail (error == NULL || *error == NULL, 0);
 
   g_mutex_lock (&interface_->priv->lock);
-
   ret = FALSE;
-  if (interface_->priv->registration_id > 0)
-    {
-      g_set_error_literal (error,
-                           G_IO_ERROR,
-                           G_IO_ERROR_FAILED, /* TODO: new error code */
-                           "The object is already exported");
-      goto out;
-    }
 
-  g_assert (interface_->priv->connection == NULL);
+  /* This deprecated function modifies the object_path, it can
+   * only be called when there is no object path and no connections are added */
   g_assert (interface_->priv->object_path == NULL);
-  g_assert (interface_->priv->hooked_vtable == NULL);
+  g_assert (interface_->priv->connections == NULL);
+
+  /* Set the object path */
+  g_dbus_interface_skeleton_set_object_path_locked (interface_, object_path);
+
+  /* Add the connection */
+  ret = g_dbus_interface_skeleton_add_connection_locked (interface_, connection, error);
 
-  /* Hook the vtable since we need to intercept method calls for
-   * ::g-authorize-method and for dispatching in thread vs
-   * context
-   */
-  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;
-
-  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,
-                                                                         g_dbus_interface_skeleton_get_info (interface_),
-                                                                         interface_->priv->hooked_vtable,
-                                                                         interface_,
-                                                                         NULL, /* user_data_free_func */
-                                                                         error);
-  if (interface_->priv->registration_id == 0)
-    goto out;
-
-  ret = TRUE;
-
- out:
   g_mutex_unlock (&interface_->priv->lock);
+
+  /* Notify the object path changed outside of the lock */
+  g_object_notify (G_OBJECT (interface_), "g-object-path");
+
   return ret;
 }
 
@@ -739,31 +1089,33 @@ g_dbus_interface_skeleton_export (GDBusInterfaceSkeleton  *interface_,
  * Stops exporting an interface previously exported with
  * g_dbus_interface_skeleton_export().
  *
- * Since: 2.30
+ * Deprecated: 2.32: Use g_dbus_interface_skeleton_remove_connection() instead.
  */
 void
 g_dbus_interface_skeleton_unexport (GDBusInterfaceSkeleton *interface_)
 {
+  ConnectionData  *data;
+  GDBusConnection *connection;
+
   g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
-  g_return_if_fail (interface_->priv->registration_id > 0);
+  g_return_if_fail (g_slist_length (interface_->priv->connections) == 1);
 
   g_mutex_lock (&interface_->priv->lock);
 
-  g_assert (interface_->priv->connection != NULL);
-  g_assert (interface_->priv->object_path != NULL);
-  g_assert (interface_->priv->hooked_vtable != NULL);
+  data = interface_->priv->connections->data;
+  connection = data->connection;
 
-  g_warn_if_fail (g_dbus_connection_unregister_object (interface_->priv->connection,
-                                                       interface_->priv->registration_id));
+  /* Remove the connection */
+  g_dbus_interface_skeleton_remove_connection_locked (interface_, data->connection);
 
-  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;
+  /* The old api requires the object path to be unset for
+   * consecutive calls to g_dbus_interface_skeleton_export() */
+  g_dbus_interface_skeleton_set_object_path_locked (interface_, NULL);
 
   g_mutex_unlock (&interface_->priv->lock);
+
+  /* Notify the object path changed outside of the lock */
+  g_object_notify (G_OBJECT (interface_), "g-object-path");
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
diff --git a/gio/gdbusinterfaceskeleton.h b/gio/gdbusinterfaceskeleton.h
index 69dcc2f..08830b0 100644
--- a/gio/gdbusinterfaceskeleton.h
+++ b/gio/gdbusinterfaceskeleton.h
@@ -91,18 +91,35 @@ GType                        g_dbus_interface_skeleton_get_type        (void) G_
 GDBusInterfaceSkeletonFlags  g_dbus_interface_skeleton_get_flags       (GDBusInterfaceSkeleton      *interface_);
 void                         g_dbus_interface_skeleton_set_flags       (GDBusInterfaceSkeleton      *interface_,
                                                                         GDBusInterfaceSkeletonFlags  flags);
+void                         g_dbus_interface_skeleton_set_object_path (GDBusInterfaceSkeleton      *interface_,
+									const gchar                 *object_path);
+const gchar                 *g_dbus_interface_skeleton_get_object_path (GDBusInterfaceSkeleton      *interface_);
 GDBusInterfaceInfo          *g_dbus_interface_skeleton_get_info        (GDBusInterfaceSkeleton      *interface_);
 GDBusInterfaceVTable        *g_dbus_interface_skeleton_get_vtable      (GDBusInterfaceSkeleton      *interface_);
 GVariant                    *g_dbus_interface_skeleton_get_properties  (GDBusInterfaceSkeleton      *interface_);
 void                         g_dbus_interface_skeleton_flush           (GDBusInterfaceSkeleton      *interface_);
 
-gboolean                     g_dbus_interface_skeleton_export          (GDBusInterfaceSkeleton      *interface_,
-                                                                        GDBusConnection             *connection,
-                                                                        const gchar                 *object_path,
-                                                                        GError                     **error);
-void                         g_dbus_interface_skeleton_unexport        (GDBusInterfaceSkeleton      *interface_);
-GDBusConnection             *g_dbus_interface_skeleton_get_connection  (GDBusInterfaceSkeleton      *interface_);
-const gchar                 *g_dbus_interface_skeleton_get_object_path (GDBusInterfaceSkeleton      *interface_);
+
+gboolean                     g_dbus_interface_skeleton_add_connection  (GDBusInterfaceSkeleton     *interface_,
+									GDBusConnection            *connection,
+									GError                     **error);
+void                         g_dbus_interface_skeleton_remove_connection(GDBusInterfaceSkeleton    *interface_,
+									 GDBusConnection           *connection);
+GSList                      *g_dbus_interface_skeleton_get_connections (GDBusInterfaceSkeleton     *interface_);
+gboolean                     g_dbus_interface_skeleton_has_connection  (GDBusInterfaceSkeleton     *interface_,
+									GDBusConnection            *connection);
+gboolean                     g_dbus_interface_skeleton_exported        (GDBusInterfaceSkeleton     *interface_);
+
+GLIB_DEPRECATED
+gboolean                     g_dbus_interface_skeleton_export          (GDBusInterfaceSkeleton     *interface_,
+                                                                        GDBusConnection            *connection,
+                                                                        const gchar                *object_path,
+                                                                        GError                    **error);
+GLIB_DEPRECATED
+void                         g_dbus_interface_skeleton_unexport        (GDBusInterfaceSkeleton     *interface_);
+
+GLIB_DEPRECATED
+GDBusConnection             *g_dbus_interface_skeleton_get_connection  (GDBusInterfaceSkeleton     *interface_);
 
 G_END_DECLS
 
diff --git a/gio/gdbusobjectmanagerserver.c b/gio/gdbusobjectmanagerserver.c
index c9a2673..124c03e 100644
--- a/gio/gdbusobjectmanagerserver.c
+++ b/gio/gdbusobjectmanagerserver.c
@@ -340,10 +340,11 @@ registration_data_export_interface (RegistrationData        *data,
   error = NULL;
   if (data->manager->priv->connection != NULL)
     {
-      if (!g_dbus_interface_skeleton_export (interface_skeleton,
-                                             data->manager->priv->connection,
-                                             object_path,
-                                             &error))
+      g_dbus_interface_skeleton_set_object_path (interface_skeleton, object_path);
+
+      if (!g_dbus_interface_skeleton_add_connection (interface_skeleton,
+						     data->manager->priv->connection,
+						     &error))
         {
           g_warning ("%s: Error registering object at %s with interface %s: %s",
                      G_STRLOC,
@@ -382,7 +383,7 @@ registration_data_unexport_interface (RegistrationData       *data,
   g_assert (iface != NULL);
 
   if (data->manager->priv->connection != NULL)
-    g_dbus_interface_skeleton_unexport (iface);
+    g_dbus_interface_skeleton_remove_connection (iface, data->manager->priv->connection);
 
   g_warn_if_fail (g_hash_table_remove (data->map_iface_name_to_iface, info->name));
 
@@ -438,7 +439,7 @@ registration_data_free (RegistrationData *data)
   while (g_hash_table_iter_next (&iter, NULL, (gpointer) &iface))
     {
       if (data->manager->priv->connection != NULL)
-        g_dbus_interface_skeleton_unexport (iface);
+        g_dbus_interface_skeleton_remove_connection (iface, data->manager->priv->connection);
     }
 
   g_signal_handlers_disconnect_by_func (data->object, G_CALLBACK (on_interface_added), data);
@@ -1056,12 +1057,14 @@ export_all (GDBusObjectManagerServer *manager)
       g_hash_table_iter_init (&iface_iter, data->map_iface_name_to_iface);
       while (g_hash_table_iter_next (&iface_iter, NULL, (gpointer) &iface))
         {
-          g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) == NULL);
+          g_warn_if_fail (g_dbus_interface_skeleton_exported (iface) == FALSE);
           error = NULL;
-          if (!g_dbus_interface_skeleton_export (iface,
-                                                 manager->priv->connection,
-                                                 object_path,
-                                                 &error))
+
+	  g_dbus_interface_skeleton_set_object_path (iface, object_path);
+
+	  if (!g_dbus_interface_skeleton_add_connection (iface,
+							 manager->priv->connection,
+							 &error))
             {
               g_warning ("%s: Error registering object at %s with interface %s: %s",
                          G_STRLOC,
@@ -1100,8 +1103,12 @@ unexport_all (GDBusObjectManagerServer *manager, gboolean only_manager)
       g_hash_table_iter_init (&iface_iter, data->map_iface_name_to_iface);
       while (g_hash_table_iter_next (&iface_iter, NULL, (gpointer) &iface))
         {
-          g_warn_if_fail (g_dbus_interface_skeleton_get_connection (iface) != NULL);
-          g_dbus_interface_skeleton_unexport (iface);
+	  GSList *connections = g_dbus_interface_skeleton_get_connections (iface);
+
+	  g_warn_if_fail (g_slist_length (connections) == 1);
+
+          g_dbus_interface_skeleton_remove_connection (iface, connections->data);
+	  g_slist_free (connections);
         }
     }
  out:
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 2091366..cf462a4 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -124,6 +124,7 @@ SAMPLE_PROGS +=					\
 	gdbus-example-unix-fd-client 		\
 	gdbus-example-objectmanager-server 	\
 	gdbus-example-objectmanager-client 	\
+	gdbus-example-codegen-peer		\
 	$(NULL)
 endif
 
@@ -502,6 +503,11 @@ gdbus_example_objectmanager_server_LDADD    = $(top_builddir)/gio/tests/gdbus-ob
 gdbus_example_objectmanager_client_SOURCES  = gdbus-example-objectmanager-client.c
 gdbus_example_objectmanager_client_CFLAGS   = -I$(top_builddir)/gio/tests/gdbus-object-manager-example
 gdbus_example_objectmanager_client_LDADD    = $(top_builddir)/gio/tests/gdbus-object-manager-example/libgdbus-example-objectmanager.la $(progs_ldadd)
+
+gdbus_example_codegen_peer_SOURCES = gdbus-example-codegen-peer.c
+gdbus_example_codegen_peer_CFLAGS  = -I$(top_builddir)/gio/tests/gdbus-object-manager-example
+gdbus_example_codegen_peer_LDADD   = $(top_builddir)/gio/tests/gdbus-object-manager-example/libgdbus-example-objectmanager.la $(progs_ldadd)
+
 endif OS_UNIX
 
 # -----------------------------------------------------------------------------
diff --git a/gio/tests/gdbus-example-codegen-peer.c b/gio/tests/gdbus-example-codegen-peer.c
new file mode 100644
index 0000000..bff936c
--- /dev/null
+++ b/gio/tests/gdbus-example-codegen-peer.c
@@ -0,0 +1,313 @@
+/*
+ * This example was based on gdbus-example-peer.c,
+ * gdbus-example-objectmanager-server.c and
+ * gdbus-example-objectmanager-client.c.
+ *
+ * Compile and run with --help to see the options.
+ *
+ * Note that with this example, many clients
+ * can connect to the same server instance
+ * and the server uses a single GDBusInterfaceSkeleton.
+ */
+
+#include "gdbus-example-objectmanager-generated.h"
+
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+on_animal_poke (ExampleAnimal          *animal,
+                GDBusMethodInvocation  *invocation,
+                gboolean                make_sad,
+                gboolean                make_happy,
+                gpointer                user_data)
+{
+  g_print ("Poke method invoked on ExampleAnimal with make_happy: %s and make_sad: %s\n",
+	   make_happy ? "true" : "false",
+	   make_sad ? "true" : "false");
+
+  if ((make_sad && make_happy) || (!make_sad && !make_happy))
+    {
+      g_dbus_method_invocation_return_dbus_error (invocation,
+                                                  "org.gtk.GDBus.Examples.ObjectManager.Error.Failed",
+                                                  "Exactly one of make_sad or make_happy must be TRUE");
+      goto out;
+    }
+
+  if (make_sad)
+    {
+      if (g_strcmp0 (example_animal_get_mood (animal), "Sad") == 0)
+        {
+          g_dbus_method_invocation_return_dbus_error (invocation,
+                                                      "org.gtk.GDBus.Examples.ObjectManager.Error.SadAnimalIsSad",
+                                                      "Sad animal is already sad");
+          goto out;
+        }
+
+      example_animal_set_mood (animal, "Sad");
+      example_animal_complete_poke (animal, invocation);
+      goto out;
+    }
+
+  if (make_happy)
+    {
+      if (g_strcmp0 (example_animal_get_mood (animal), "Happy") == 0)
+        {
+          g_dbus_method_invocation_return_dbus_error (invocation,
+                                                      "org.gtk.GDBus.Examples.ObjectManager.Error.HappyAnimalIsHappy",
+                                                      "Happy animal is already happy");
+          goto out;
+        }
+
+      example_animal_set_mood (animal, "Happy");
+      example_animal_complete_poke (animal, invocation);
+      goto out;
+    }
+
+  g_assert_not_reached ();
+
+ out:
+  return TRUE; /* to indicate that the method was handled */
+}
+
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_connection_lost (GDBusConnection *connection,
+		    gboolean         remote_peer_vanished,
+		    GError          *error,
+		    ExampleAnimal   *animal)
+{
+  if (remote_peer_vanished)
+    g_print ("A client closed the connection: %s\n", error->message);
+  else
+    g_print ("A client was killed\n");
+
+  /* Remove the connection from the interface(s) which are exported on it, this
+   * will release our reference to the connection.
+   */
+  if (g_dbus_interface_skeleton_has_connection (G_DBUS_INTERFACE_SKELETON (animal), connection))
+    g_dbus_interface_skeleton_remove_connection (G_DBUS_INTERFACE_SKELETON (animal), connection);
+}
+
+static gboolean
+on_new_connection (GDBusServer *server,
+                   GDBusConnection *connection,
+                   gpointer user_data)
+{
+  GCredentials  *credentials;
+  ExampleAnimal *animal = (ExampleAnimal *)user_data;
+  GError        *error = NULL;
+  gchar *s;
+
+  credentials = g_dbus_connection_get_peer_credentials (connection);
+  if (credentials == NULL)
+    s = g_strdup ("(no credentials received)");
+  else
+    s = g_credentials_to_string (credentials);
+
+  g_print ("Client connected.\n"
+           "Peer credentials: %s\n"
+           "Negotiated capabilities: unix-fd-passing=%d\n",
+           s,
+           g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
+
+  /* Export our ExampleAnimal on the new connection, this will hold
+   * a reference to the connection 
+   */
+  if (g_dbus_interface_skeleton_add_connection (G_DBUS_INTERFACE_SKELETON (animal),
+						connection,
+						&error))
+    {
+      /* Listen for lost connections */
+      g_signal_connect (connection, "closed",
+			G_CALLBACK (on_connection_lost), animal);
+    }
+  else
+    g_warning ("Unable to export ExampleAnimal interface on the new connection: '%s'",
+	       error->message);
+
+  return TRUE;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+int
+main (int argc, char *argv[])
+{
+  gint ret;
+  gboolean opt_server;
+  gchar *opt_address;
+  GOptionContext *opt_context;
+  gboolean opt_allow_anonymous = FALSE;
+  gboolean opt_make_happy = FALSE;
+  gboolean opt_make_sad = FALSE;
+  gboolean opt_stay_alive = FALSE;
+  GError *error = NULL;
+  GMainLoop *loop;
+  ExampleAnimal *animal;
+  GOptionEntry opt_entries[] =
+    {
+      { "server", 's', 0, G_OPTION_ARG_NONE, &opt_server, "Start a server instead of a client", NULL },
+      { "address", 'a', 0, G_OPTION_ARG_STRING, &opt_address, "D-Bus address to use", NULL },
+      { "allow-anonymous", 'n', 0, G_OPTION_ARG_NONE, &opt_allow_anonymous, "Allow anonymous authentication", NULL },
+      { "make-happy", 'H', 0, G_OPTION_ARG_NONE, &opt_make_happy, "Make the animal happy (for the client)", NULL },
+      { "make-sad", 'H', 0, G_OPTION_ARG_NONE, &opt_make_sad, "Make the animal sad (for the client)", NULL },
+      { "stay-alive", 'H', 0, G_OPTION_ARG_NONE, &opt_stay_alive, "Dont exit but sit in a mainloop (for the client)", NULL },
+
+      { NULL}
+    };
+
+  ret = 1;
+
+  g_type_init ();
+
+  opt_address = NULL;
+  opt_server = FALSE;
+  opt_allow_anonymous = FALSE;
+
+  opt_context = g_option_context_new ("peer-to-peer example");
+  g_option_context_add_main_entries (opt_context, opt_entries, NULL);
+  if (!g_option_context_parse (opt_context, &argc, &argv, &error))
+    {
+      g_printerr ("Error parsing options: %s\n", error->message);
+      g_error_free (error);
+      goto out;
+    }
+  if (opt_address == NULL)
+    {
+      g_printerr ("Must provode a gdbus server address\n\n%s\n", 
+		  g_option_context_get_help (opt_context, TRUE, NULL));
+      goto out;
+    }
+  if (!opt_server && opt_allow_anonymous)
+    {
+      g_printerr ("The --allow-anonymous option only makes sense when used with --server.\n");
+      goto out;
+    }
+
+  if (opt_server)
+    {
+      GDBusServer *server;
+      gchar *guid;
+      GDBusServerFlags server_flags;
+
+      guid = g_dbus_generate_guid ();
+
+      server_flags = G_DBUS_SERVER_FLAGS_NONE;
+      if (opt_allow_anonymous)
+        server_flags |= G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS;
+
+      server = g_dbus_server_new_sync (opt_address,
+                                       server_flags,
+                                       guid,
+                                       NULL, /* GDBusAuthObserver */
+                                       NULL, /* GCancellable */
+                                       &error);
+
+      if (server == NULL)
+        {
+          g_printerr ("Error creating server at address %s: %s\n", opt_address, error->message);
+          g_error_free (error);
+          goto out;
+        }
+
+      g_dbus_server_start (server);
+      g_free (guid);
+
+      g_print ("Server is listening at: %s\n", g_dbus_server_get_client_address (server));
+
+      /* Create a skeleton for the interface
+       * org.gtk.GDBus.Example.ObjectManager.Animal and
+       * give it the object path "/Example/Animals/000"
+       */
+      animal = example_animal_skeleton_new ();
+      g_dbus_interface_skeleton_set_object_path (G_DBUS_INTERFACE_SKELETON (animal),
+						 "/Example/Animals/000");
+
+      /* Handle Poke() D-Bus method invocations on the .Animal interface */
+      g_signal_connect (animal,
+                        "handle-poke",
+                        G_CALLBACK (on_animal_poke),
+                        NULL); /* user_data */
+
+      /* Handle incomming connections with our ExampleAnimal skeleton
+       *
+       * Note that you can apply as many interfaces to the handled
+       * connections as you like.
+       */
+      g_signal_connect (server,
+                        "new-connection",
+                        G_CALLBACK (on_new_connection),
+                        animal);
+
+      loop = g_main_loop_new (NULL, FALSE);
+      g_main_loop_run (loop);
+
+      g_object_unref (animal);
+      g_object_unref (server);
+      g_main_loop_unref (loop);
+    }
+  else
+    {
+      GDBusConnection *connection;
+
+      connection = g_dbus_connection_new_for_address_sync (opt_address,
+                                                           G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+                                                           NULL, /* GDBusAuthObserver */
+                                                           NULL, /* GCancellable */
+                                                           &error);
+      if (connection == NULL)
+        {
+          g_printerr ("Error connecting to D-Bus address %s: %s\n", opt_address, error->message);
+          g_error_free (error);
+          goto out;
+        }
+
+      g_print ("Connected.\n"
+               "Negotiated capabilities: unix-fd-passing=%d\n",
+               g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
+
+      animal = example_animal_proxy_new_sync (connection,
+					      0,    /* GDBusProxyFlags */
+					      NULL, /* Bus name, in this case always NULL */
+					      "/Example/Animals/000",
+					      NULL, &error);
+
+      if (!animal)
+	{
+          g_printerr ("Failed to create a proxy for our ExampleAnimal interface: %s\n", error->message);
+          g_error_free (error);
+          goto out;
+	}
+
+      g_print ("Obtained a proxy for our ExampleAnimal with mood '%s'\n",
+	       example_animal_get_mood (animal));
+
+      if (!example_animal_call_poke_sync (animal,
+					  opt_make_sad,
+					  opt_make_happy,
+					  NULL, &error))
+	{
+          g_printerr ("Failed Poke method failed on our ExampleAnimal proxy: %s\n", error->message);
+          g_error_free (error);
+          goto out;
+	}
+
+      if (opt_stay_alive)
+	{
+	  loop = g_main_loop_new (NULL, FALSE);
+	  g_main_loop_run (loop);
+	}
+
+      g_object_unref (animal);
+      g_object_unref (connection);
+    }
+
+  ret = 0;
+
+ out:
+  return ret;
+}
