[glib] GDBusInterfaceSkeleton: make it possible to export on multiple connections
- From: David Zeuthen <davidz src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] GDBusInterfaceSkeleton: make it possible to export on multiple connections
- Date: Fri, 2 Dec 2011 16:27:44 +0000 (UTC)
commit a00530ecb0e8576e7a023f37a97528da4d0dfce5
Author: Tristan Van Berkom <tristanvb openismus com>
Date: Fri Dec 2 11:20:21 2011 -0500
GDBusInterfaceSkeleton: make it possible to export on multiple connections
This is useful in peer-to-peer connections.
With minor changes by David Zeuthen <davidz redhat com>.
https://bugzilla.gnome.org/show_bug.cgi?id=662718
Signed-off-by: David Zeuthen <davidz redhat com>
docs/reference/gio/gio-sections.txt | 3 +
gio/gdbus-2.0/codegen/codegen.py | 56 ++++--
gio/gdbusinterfaceskeleton.c | 364 ++++++++++++++++++++++++++++-------
gio/gdbusinterfaceskeleton.h | 6 +
gio/gio.symbols | 3 +
gio/tests/Makefile.am | 8 +-
gio/tests/gdbus-peer.c | 239 +++++++++++++++++++++++
7 files changed, 592 insertions(+), 87 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 895398d..6dfaf9a 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -3344,7 +3344,10 @@ 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_unexport_from_connection
g_dbus_interface_skeleton_get_connection
+g_dbus_interface_skeleton_get_connections
+g_dbus_interface_skeleton_has_connection
g_dbus_interface_skeleton_get_object_path
GDBusInterfaceSkeletonFlags
g_dbus_interface_skeleton_get_flags
diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py
index 8d34bdd..41161b0 100644
--- a/gio/gdbus-2.0/codegen/codegen.py
+++ b/gio/gdbus-2.0/codegen/codegen.py
@@ -2307,21 +2307,31 @@ 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'
+ ' GList *connections, *l;\n'
+ ' GVariant *signal_variant;\n'
+ ' connections = g_dbus_interface_skeleton_get_connections (G_DBUS_INTERFACE_SKELETON (skeleton));\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 ("('
- %(i.name, s.name))
+ self.c.write('\n'
+ ' signal_variant = g_variant_ref_sink (g_variant_new ("(')
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(' for (l = connections; l != NULL; l = l->next)\n'
+ ' {\n'
+ ' GDBusConnection *connection = l->data;\n'
+ ' g_dbus_connection_emit_signal (connection,\n'
+ ' NULL, g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (skeleton)), "%s", "%s",\n'
+ ' signal_variant, NULL);\n'
+ ' }\n'
+ %(i.name, s.name))
+ self.c.write(' g_variant_unref (signal_variant);\n')
+ self.c.write(' g_list_foreach (connections, (GFunc)g_object_unref, NULL);\n')
+ self.c.write(' g_list_free (connections);\n')
self.c.write('}\n'
'\n')
@@ -2407,14 +2417,26 @@ class CodeGenerator:
' }\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'
+ ' GList *connections, *l;\n'
+ ' GVariant *signal_variant;'
+ '\n'
+ ' signal_variant = g_variant_ref_sink (g_variant_new ("(sa{sv}as)", "%s",\n'
+ ' &builder, &invalidated_builder));\n'
+ ' connections = g_dbus_interface_skeleton_get_connections (G_DBUS_INTERFACE_SKELETON (skeleton));\n'
+ ' for (l = connections; l != NULL; l = l->next)\n'
+ ' {\n'
+ ' GDBusConnection *connection = l->data;\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'
+ ' signal_variant,\n'
+ ' NULL);\n'
+ ' }\n'
+ ' g_variant_unref (signal_variant);\n'
+ ' g_list_foreach (connections, (GFunc)g_object_unref, NULL);\n'
+ ' g_list_free (connections);\n'
' }\n'
' else\n'
' {\n'
diff --git a/gio/gdbusinterfaceskeleton.c b/gio/gdbusinterfaceskeleton.c
index 0cd5d6f..e6c0a49 100644
--- a/gio/gdbusinterfaceskeleton.c
+++ b/gio/gdbusinterfaceskeleton.c
@@ -44,17 +44,22 @@
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,
@@ -69,7 +74,21 @@ enum
static guint signals[LAST_SIGNAL] = {0};
-static void dbus_interface_interface_init (GDBusInterfaceIface *iface);
+static void dbus_interface_interface_init (GDBusInterfaceIface *iface);
+
+static void set_object_path_locked (GDBusInterfaceSkeleton *interface_,
+ const gchar *object_path);
+static void 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,13 +97,22 @@ 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);
+ /* Hold the lock just incase any code we call verifies that the lock is held */
+ g_mutex_lock (&interface->priv->lock);
+
+ /* unexport from all connections if we're exported anywhere */
+ while (interface->priv->connections != NULL)
+ {
+ ConnectionData *data = interface->priv->connections->data;
+ remove_connection_locked (interface, data->connection);
+ }
+
+ 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);
@@ -617,11 +645,112 @@ skeleton_intercept_handle_method_call (GDBusConnection *connection,
/* ---------------------------------------------------------------------------------------------------- */
+static 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;
+}
+
+static void
+free_connection (ConnectionData *data)
+{
+ if (data != NULL)
+ {
+ g_object_unref (data->connection);
+ g_slice_free (ConnectionData, data);
+ }
+}
+
+static gboolean
+add_connection_locked (GDBusInterfaceSkeleton *interface_,
+ GDBusConnection *connection,
+ GError **error)
+{
+ ConnectionData *data;
+ guint registration_id;
+ gboolean ret = FALSE;
+
+ if (interface_->priv->hooked_vtable == NULL)
+ {
+ /* Hook the vtable since we need to intercept method calls for
+ * ::g-authorize-method and for dispatching in thread vs
+ * context
+ *
+ * We need to wait until subclasses have had time to initialize
+ * properly before building the hooked_vtable, so we create it
+ * once at the last minute.
+ */
+ 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;
+ }
+
+ registration_id = g_dbus_connection_register_object (connection,
+ interface_->priv->object_path,
+ g_dbus_interface_skeleton_get_info (interface_),
+ interface_->priv->hooked_vtable,
+ interface_,
+ NULL, /* user_data_free_func */
+ error);
+
+ if (registration_id > 0)
+ {
+ data = new_connection (connection, registration_id);
+ interface_->priv->connections = g_slist_append (interface_->priv->connections, data);
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+static void
+remove_connection_locked (GDBusInterfaceSkeleton *interface_,
+ GDBusConnection *connection)
+{
+ ConnectionData *data;
+ GSList *l;
+
+ /* Get the connection in the list and unregister ... */
+ for (l = interface_->priv->connections; l != NULL; l = l->next)
+ {
+ data = l->data;
+ if (data->connection == connection)
+ {
+ g_warn_if_fail (g_dbus_connection_unregister_object (data->connection, data->registration_id));
+ free_connection (data);
+ interface_->priv->connections = g_slist_delete_link (interface_->priv->connections, l);
+ /* we are guaranteed that the connection is only added once, so bail out early */
+ goto out;
+ }
+ }
+ out:
+ ;
+}
+
+static void
+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);
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
/**
* g_dbus_interface_skeleton_get_connection:
* @interface_: A #GDBusInterfaceSkeleton.
*
- * Gets the connection that @interface_ is exported on, if any.
+ * Gets the first connection that @interface_ is exported on, if any.
*
* Returns: (transfer none): A #GDBusConnection or %NULL if @interface_ is
* not exported anywhere. Do not free, the object belongs to @interface_.
@@ -631,10 +760,97 @@ skeleton_intercept_handle_method_call (GDBusConnection *connection,
GDBusConnection *
g_dbus_interface_skeleton_get_connection (GDBusInterfaceSkeleton *interface_)
{
+ ConnectionData *data;
GDBusConnection *ret;
+
g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
g_mutex_lock (&interface_->priv->lock);
- ret = interface_->priv->connection;
+
+ ret = NULL;
+ if (interface_->priv->connections != NULL)
+ {
+ data = interface_->priv->connections->data;
+ if (data != NULL)
+ ret = data->connection;
+ }
+
+ g_mutex_unlock (&interface_->priv->lock);
+
+ return ret;
+}
+
+/**
+ * g_dbus_interface_skeleton_get_connections:
+ * @interface_: A #GDBusInterfaceSkeleton.
+ *
+ * Gets a list of the connections that @interface_ is exported on.
+ *
+ * Returns: (element-type GDBusConnection) (transfer full): A list of
+ * all the connections that @interface_ is exported on. The returned
+ * list should be freed with g_list_free() after each element has
+ * been freed with g_object_unref().
+ *
+ * Since: 2.32
+ */
+GList *
+g_dbus_interface_skeleton_get_connections (GDBusInterfaceSkeleton *interface_)
+{
+ GList *connections;
+ GSList *l;
+ ConnectionData *data;
+
+ g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), NULL);
+
+ g_mutex_lock (&interface_->priv->lock);
+ connections = NULL;
+
+ for (l = interface_->priv->connections; l != NULL; l = l->next)
+ {
+ data = l->data;
+ connections = g_list_prepend (connections,
+ /* Return a reference to each connection */
+ g_object_ref (data->connection));
+ }
+
+ g_mutex_unlock (&interface_->priv->lock);
+
+ return g_list_reverse (connections);
+}
+
+/**
+ * g_dbus_interface_skeleton_has_connection:
+ * @interface_: A #GDBusInterfaceSkeleton.
+ * @connection: A #GDBusConnection.
+ *
+ * Checks if @interface_ is export on @connection.
+ *
+ * Returns: %TRUE if @interface_ is exported on @connection, %FALSE otherwise.
+ *
+ * Since: 2.32
+ */
+gboolean
+g_dbus_interface_skeleton_has_connection (GDBusInterfaceSkeleton *interface_,
+ GDBusConnection *connection)
+{
+ GSList *l;
+ gboolean ret = FALSE;
+
+ g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), FALSE);
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
+
+ g_mutex_lock (&interface_->priv->lock);
+
+ for (l = interface_->priv->connections; l != NULL; l = l->next)
+ {
+ ConnectionData *data = l->data;
+ if (data->connection == connection)
+ {
+ ret = TRUE;
+ goto out;
+ }
+ }
+
+ out:
g_mutex_unlock (&interface_->priv->lock);
return ret;
}
@@ -670,9 +886,13 @@ g_dbus_interface_skeleton_get_object_path (GDBusInterfaceSkeleton *interface_)
*
* Exports @interface_ at @object_path on @connection.
*
+ * This can be called multiple times to export the same @interface_
+ * onto multiple connections however the @object_path provided must be
+ * the same for all connections.
+ *
* Use g_dbus_interface_skeleton_unexport() to unexport the object.
*
- * Returns: %TRUE if the interface was exported, other %FALSE with
+ * Returns: %TRUE if the interface was exported on @connection, otherwise %FALSE with
* @error set.
*
* Since: 2.30
@@ -683,51 +903,25 @@ g_dbus_interface_skeleton_export (GDBusInterfaceSkeleton *interface_,
const gchar *object_path,
GError **error)
{
- gboolean ret;
+ gboolean ret = FALSE;
- g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), 0);
- 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);
+ g_return_val_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_), FALSE);
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (g_variant_is_object_path (object_path), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
- g_mutex_lock (&interface_->priv->lock);
+ /* Assert that the object path is the same for multiple connections here */
+ g_return_val_if_fail (interface_->priv->object_path == NULL ||
+ g_strcmp0 (interface_->priv->object_path, object_path) == 0, FALSE);
- 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_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);
+ /* Set the object path */
+ set_object_path_locked (interface_, object_path);
- /* 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;
+ /* Add the connection */
+ ret = add_connection_locked (interface_, connection, error);
- out:
g_mutex_unlock (&interface_->priv->lock);
return ret;
}
@@ -736,8 +930,10 @@ g_dbus_interface_skeleton_export (GDBusInterfaceSkeleton *interface_,
* g_dbus_interface_skeleton_unexport:
* @interface_: A #GDBusInterfaceSkeleton.
*
- * Stops exporting an interface previously exported with
- * g_dbus_interface_skeleton_export().
+ * Stops exporting @interface_ on all connections it is exported on.
+ *
+ * To unexport @interface_ from only a single connection, use
+ * g_dbus_interface_skeleton_export_from_connection()
*
* Since: 2.30
*/
@@ -745,23 +941,57 @@ void
g_dbus_interface_skeleton_unexport (GDBusInterfaceSkeleton *interface_)
{
g_return_if_fail (G_IS_DBUS_INTERFACE_SKELETON (interface_));
- g_return_if_fail (interface_->priv->registration_id > 0);
+ g_return_if_fail (interface_->priv->connections != NULL);
+
+ g_mutex_lock (&interface_->priv->lock);
+
+ g_assert (interface_->priv->object_path != NULL);
+ g_assert (interface_->priv->hooked_vtable != NULL);
+
+ /* Remove all connections */
+ while (interface_->priv->connections != NULL)
+ {
+ ConnectionData *data = interface_->priv->connections->data;
+ remove_connection_locked (interface_, data->connection);
+ }
+
+ /* Unset the object path since there are no connections left */
+ set_object_path_locked (interface_, NULL);
+
+ g_mutex_unlock (&interface_->priv->lock);
+}
+
+
+/**
+ * g_dbus_interface_skeleton_unexport_from_connection:
+ * @interface_: A #GDBusInterfaceSkeleton.
+ * @connection: A #GDBusConnection.
+ *
+ * Stops exporting @interface_ on @connection.
+ *
+ * To stop exporting on all connections the interface is exported on,
+ * use g_dbus_interface_skeleton_unexport().
+ *
+ * Since: 2.32
+ */
+void
+g_dbus_interface_skeleton_unexport_from_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_return_if_fail (interface_->priv->connections != NULL);
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);
- g_warn_if_fail (g_dbus_connection_unregister_object (interface_->priv->connection,
- interface_->priv->registration_id));
+ remove_connection_locked (interface_, 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;
+ /* Reset the object path if we removed the last connection */
+ if (interface_->priv->connections == NULL)
+ set_object_path_locked (interface_, NULL);
g_mutex_unlock (&interface_->priv->lock);
}
diff --git a/gio/gdbusinterfaceskeleton.h b/gio/gdbusinterfaceskeleton.h
index 69dcc2f..5f1c166 100644
--- a/gio/gdbusinterfaceskeleton.h
+++ b/gio/gdbusinterfaceskeleton.h
@@ -101,7 +101,13 @@ gboolean g_dbus_interface_skeleton_export (GDBusInt
const gchar *object_path,
GError **error);
void g_dbus_interface_skeleton_unexport (GDBusInterfaceSkeleton *interface_);
+void g_dbus_interface_skeleton_unexport_from_connection (GDBusInterfaceSkeleton *interface_,
+ GDBusConnection *connection);
+
GDBusConnection *g_dbus_interface_skeleton_get_connection (GDBusInterfaceSkeleton *interface_);
+GList *g_dbus_interface_skeleton_get_connections (GDBusInterfaceSkeleton *interface_);
+gboolean g_dbus_interface_skeleton_has_connection (GDBusInterfaceSkeleton *interface_,
+ GDBusConnection *connection);
const gchar *g_dbus_interface_skeleton_get_object_path (GDBusInterfaceSkeleton *interface_);
G_END_DECLS
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 791fbeb..cd8d52a 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1535,6 +1535,8 @@ g_dbus_interface_skeleton_export
g_dbus_interface_skeleton_flags_get_type
g_dbus_interface_skeleton_flush
g_dbus_interface_skeleton_get_connection
+g_dbus_interface_skeleton_get_connections
+g_dbus_interface_skeleton_has_connection
g_dbus_interface_skeleton_get_flags
g_dbus_interface_skeleton_get_info
g_dbus_interface_skeleton_get_object_path
@@ -1543,6 +1545,7 @@ g_dbus_interface_skeleton_get_type
g_dbus_interface_skeleton_get_vtable
g_dbus_interface_skeleton_set_flags
g_dbus_interface_skeleton_unexport
+g_dbus_interface_skeleton_unexport_from_connection
g_dbus_object_get_interface
g_dbus_object_get_interfaces
g_dbus_object_get_object_path
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 9724892..b449a38 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -344,9 +344,6 @@ gdbus_export_LDADD = $(progs_ldadd)
gdbus_error_SOURCES = gdbus-error.c gdbus-sessionbus.c gdbus-sessionbus.h gdbus-tests.h gdbus-tests.c
gdbus_error_LDADD = $(progs_ldadd)
-gdbus_peer_SOURCES = gdbus-peer.c gdbus-tests.h gdbus-tests.c
-gdbus_peer_LDADD = $(progs_ldadd)
-
gdbus_non_socket_SOURCES = \
gdbus-non-socket.c \
gdbus-tests.c \
@@ -527,6 +524,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_peer_SOURCES = gdbus-peer.c gdbus-tests.h gdbus-tests.c
+gdbus_peer_CFLAGS = -I$(top_builddir)/gio/tests/gdbus-object-manager-example
+gdbus_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-peer.c b/gio/tests/gdbus-peer.c
index ee2ceb6..7eeb59d 100644
--- a/gio/tests/gdbus-peer.c
+++ b/gio/tests/gdbus-peer.c
@@ -47,6 +47,8 @@
#include "gdbus-tests.h"
+#include "gdbus-example-objectmanager-generated.h"
+
#ifdef G_OS_UNIX
static gboolean is_unix = TRUE;
#else
@@ -601,6 +603,7 @@ test_peer (void)
g_assert (c == NULL);
/* bring up a server - we run the server in a different thread to avoid deadlocks */
+ service_loop = NULL;
service_thread = g_thread_new ("test_peer",
service_thread_func,
&data);
@@ -1534,6 +1537,241 @@ test_tcp_anonymous (void)
/* ---------------------------------------------------------------------------------------------------- */
+static GDBusServer *codegen_server = NULL;
+
+static gboolean
+codegen_on_animal_poke (ExampleAnimal *animal,
+ GDBusMethodInvocation *invocation,
+ gboolean make_sad,
+ gboolean make_happy,
+ gpointer user_data)
+{
+ if ((make_sad && make_happy) || (!make_sad && !make_happy))
+ {
+ g_main_loop_quit (service_loop);
+
+ 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 */
+}
+
+/* Runs in thread we created GDBusServer in (since we didn't pass G_DBUS_SERVER_FLAGS_RUN_IN_THREAD) */
+static gboolean
+codegen_on_new_connection (GDBusServer *server,
+ GDBusConnection *connection,
+ gpointer user_data)
+{
+ ExampleAnimal *animal = user_data;
+ GError *error = NULL;
+
+ /* g_print ("Client connected.\n" */
+ /* "Negotiated capabilities: unix-fd-passing=%d\n", */
+ /* g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING); */
+
+ g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (animal), connection,
+ "/Example/Animals/000", &error);
+ g_assert_no_error (error);
+
+ return TRUE;
+}
+
+static gpointer
+codegen_service_thread_func (gpointer user_data)
+{
+ GMainContext *service_context;
+ ExampleAnimal *animal;
+ GError *error = NULL;
+
+ service_context = g_main_context_new ();
+ g_main_context_push_thread_default (service_context);
+
+ /* Create the animal in the right thread context */
+ animal = example_animal_skeleton_new ();
+
+ /* Handle Poke() D-Bus method invocations on the .Animal interface */
+ g_signal_connect (animal, "handle-poke",
+ G_CALLBACK (codegen_on_animal_poke),
+ NULL); /* user_data */
+
+ codegen_server = g_dbus_server_new_sync (tmp_address,
+ G_DBUS_SERVER_FLAGS_NONE,
+ test_guid,
+ NULL, /* observer */
+ NULL, /* cancellable */
+ &error);
+ g_assert_no_error (error);
+ g_dbus_server_start (codegen_server);
+
+ g_signal_connect (codegen_server, "new-connection",
+ G_CALLBACK (codegen_on_new_connection),
+ animal);
+
+ service_loop = g_main_loop_new (service_context, FALSE);
+ g_main_loop_run (service_loop);
+
+ g_object_unref (animal);
+
+ g_main_context_pop_thread_default (service_context);
+
+ g_main_loop_unref (service_loop);
+ g_main_context_unref (service_context);
+
+ g_dbus_server_stop (codegen_server);
+ g_object_unref (codegen_server);
+ codegen_server = NULL;
+
+ return NULL;
+}
+
+
+gboolean
+codegen_quit_mainloop_timeout (gpointer data)
+{
+ g_main_loop_quit (loop);
+ return FALSE;
+}
+
+static void
+codegen_test_peer (void)
+{
+ GDBusConnection *connection;
+ ExampleAnimal *animal1, *animal2;
+ GThread *service_thread;
+ GError *error = NULL;
+ GVariant *value;
+
+ /* bring up a server - we run the server in a different thread to avoid deadlocks */
+ service_thread = g_thread_new ("codegen_test_peer",
+ codegen_service_thread_func,
+ NULL);
+ service_loop = NULL;
+ while (service_loop == NULL)
+ g_thread_yield ();
+ g_assert (codegen_server != NULL);
+
+ /* Get an animal 1 ... */
+ connection = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (codegen_server),
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+ NULL, /* GDBusAuthObserver */
+ NULL, /* cancellable */
+ &error);
+ g_assert_no_error (error);
+ g_assert (connection != NULL);
+
+ animal1 = example_animal_proxy_new_sync (connection, 0, NULL,
+ "/Example/Animals/000", NULL, &error);
+ g_assert_no_error (error);
+ g_assert (animal1 != NULL);
+ g_object_unref (connection);
+
+ /* Get animal 2 ... */
+ connection = g_dbus_connection_new_for_address_sync (g_dbus_server_get_client_address (codegen_server),
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT,
+ NULL, /* GDBusAuthObserver */
+ NULL, /* cancellable */
+ &error);
+ g_assert_no_error (error);
+ g_assert (connection != NULL);
+
+ animal2 = example_animal_proxy_new_sync (connection, 0, NULL,
+ "/Example/Animals/000", NULL, &error);
+ g_assert_no_error (error);
+ g_assert (animal2 != NULL);
+ g_object_unref (connection);
+
+ /* Make animal sad via animal1 */
+ example_animal_call_poke_sync (animal1, TRUE, FALSE, NULL, &error);
+ g_assert_no_error (error);
+
+ /* Poke server and make sure animal is updated */
+ value = g_dbus_proxy_call_sync (G_DBUS_PROXY (animal1),
+ "org.freedesktop.DBus.Peer.Ping",
+ NULL, G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &error);
+ g_assert_no_error (error);
+ g_assert (value != NULL);
+ g_variant_unref (value);
+
+ /* Give the proxies a chance to refresh in the defaul main loop */
+ g_timeout_add (100, codegen_quit_mainloop_timeout, NULL);
+ g_main_loop_run (loop);
+
+ /* Assert animals are sad */
+ g_assert_cmpstr (example_animal_get_mood (animal1), ==, "Sad");
+ g_assert_cmpstr (example_animal_get_mood (animal2), ==, "Sad");
+
+ /* Make animal happy via animal2 */
+ example_animal_call_poke_sync (animal2, FALSE, TRUE, NULL, &error);
+ g_assert_no_error (error);
+
+ /* Poke server and make sure animal is updated */
+ value = g_dbus_proxy_call_sync (G_DBUS_PROXY (animal2),
+ "org.freedesktop.DBus.Peer.Ping",
+ NULL, G_DBUS_CALL_FLAGS_NONE, -1,
+ NULL, &error);
+ g_assert_no_error (error);
+ g_assert (value != NULL);
+ g_variant_unref (value);
+
+ /* Give the proxies a chance to refresh in the defaul main loop */
+ g_timeout_add (1000, codegen_quit_mainloop_timeout, NULL);
+ g_main_loop_run (loop);
+
+ /* Assert animals are happy */
+ g_assert_cmpstr (example_animal_get_mood (animal1), ==, "Happy");
+ g_assert_cmpstr (example_animal_get_mood (animal2), ==, "Happy");
+
+ /* This final call making the animal happy and sad will cause
+ * the server to quit, when the server quits we dont get property
+ * change notifications anyway because those are done from an idle handler
+ */
+ example_animal_call_poke_sync (animal2, TRUE, TRUE, NULL, &error);
+
+ g_object_unref (animal1);
+ g_object_unref (animal2);
+ g_thread_join (service_thread);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+
int
main (int argc,
char *argv[])
@@ -1575,6 +1813,7 @@ main (int argc,
g_test_add_func ("/gdbus/tcp-anonymous", test_tcp_anonymous);
g_test_add_func ("/gdbus/credentials", test_credentials);
g_test_add_func ("/gdbus/overflow", test_overflow);
+ g_test_add_func ("/gdbus/codegen-peer-to-peer", codegen_test_peer);
ret = g_test_run();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]