summaryrefslogtreecommitdiff
path: root/gio/tests/gdbus-example-server.c
diff options
context:
space:
mode:
Diffstat (limited to 'gio/tests/gdbus-example-server.c')
-rw-r--r--gio/tests/gdbus-example-server.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/gio/tests/gdbus-example-server.c b/gio/tests/gdbus-example-server.c
new file mode 100644
index 000000000..fe667c040
--- /dev/null
+++ b/gio/tests/gdbus-example-server.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright © 2010 Red Hat, Inc.
+ *
+ * This program 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 licence or (at
+ * your option) any later version.
+ *
+ * See the included COPYING file for more information.
+ *
+ * Author: David Zeuthen <davidz@redhat.com>
+ */
+
+#include <gio/gio.h>
+#include <stdlib.h>
+
+#ifdef G_OS_UNIX
+/* For STDOUT_FILENO */
+#include <unistd.h>
+#endif
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static GDBusNodeInfo *introspection_data = NULL;
+
+/* Introspection data for the service we are exporting */
+static const gchar introspection_xml[] =
+ "<node>"
+ " <interface name='org.gtk.GDBus.TestInterface'>"
+ " <method name='HelloWorld'>"
+ " <arg type='s' name='greeting' direction='in'/>"
+ " <arg type='s' name='response' direction='out'/>"
+ " </method>"
+ " <method name='EmitSignal'>"
+ " <arg type='d' name='speed_in_mph' direction='in'/>"
+ " </method>"
+ " <method name='GimmeStdout'/>"
+ " <signal name='VelocityChanged'>"
+ " <arg type='d' name='speed_in_mph'/>"
+ " <arg type='s' name='speed_as_string'/>"
+ " </signal>"
+ " <property type='s' name='FluxCapicitorName' access='read'/>"
+ " <property type='s' name='Title' access='readwrite'/>"
+ " <property type='s' name='ReadingAlwaysThrowsError' access='read'/>"
+ " <property type='s' name='WritingAlwaysThrowsError' access='readwrite'/>"
+ " <property type='s' name='OnlyWritable' access='write'/>"
+ " <property type='s' name='Foo' access='read'/>"
+ " <property type='s' name='Bar' access='read'/>"
+ " </interface>"
+ "</node>";
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+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)
+{
+ if (g_strcmp0 (method_name, "HelloWorld") == 0)
+ {
+ const gchar *greeting;
+
+ g_variant_get (parameters, "(s)", &greeting);
+
+ if (g_strcmp0 (greeting, "Return Unregistered") == 0)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED_HANDLED,
+ "As requested, here's a GError not registered (G_IO_ERROR_FAILED_HANDLED)");
+ }
+ else if (g_strcmp0 (greeting, "Return Registered") == 0)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
+ "As requested, here's a GError that is registered (G_DBUS_ERROR_MATCH_RULE_NOT_FOUND)");
+ }
+ else if (g_strcmp0 (greeting, "Return Raw") == 0)
+ {
+ g_dbus_method_invocation_return_dbus_error (invocation,
+ "org.gtk.GDBus.SomeErrorName",
+ "As requested, here's a raw D-Bus error");
+ }
+ else
+ {
+ gchar *response;
+ response = g_strdup_printf ("You greeted me with '%s'. Thanks!", greeting);
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(s)", response));
+ g_free (response);
+ }
+ }
+ else if (g_strcmp0 (method_name, "EmitSignal") == 0)
+ {
+ GError *local_error;
+ gdouble speed_in_mph;
+ gchar *speed_as_string;
+
+ g_variant_get (parameters, "(d)", &speed_in_mph);
+ speed_as_string = g_strdup_printf ("%g mph!", speed_in_mph);
+
+ local_error = NULL;
+ g_dbus_connection_emit_signal (connection,
+ NULL,
+ object_path,
+ interface_name,
+ "VelocityChanged",
+ g_variant_new ("(ds)",
+ speed_in_mph,
+ speed_as_string),
+ &local_error);
+ g_assert_no_error (local_error);
+ g_free (speed_as_string);
+
+ g_dbus_method_invocation_return_value (invocation, NULL);
+ }
+ else if (g_strcmp0 (method_name, "GimmeStdout") == 0)
+ {
+#ifdef G_OS_UNIX
+ if (g_dbus_connection_get_capabilities (connection) & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING)
+ {
+ GDBusMessage *reply;
+ GUnixFDList *fd_list;
+ GError *error;
+
+ fd_list = g_unix_fd_list_new ();
+ error = NULL;
+ g_unix_fd_list_append (fd_list, STDOUT_FILENO, &error);
+ g_assert_no_error (error);
+
+ reply = g_dbus_message_new_method_reply (g_dbus_method_invocation_get_message (invocation));
+ g_dbus_message_set_unix_fd_list (reply, fd_list);
+
+ error = NULL;
+ g_dbus_connection_send_message (connection,
+ reply,
+ NULL, /* out_serial */
+ &error);
+ g_assert_no_error (error);
+
+ g_object_unref (invocation);
+ g_object_unref (fd_list);
+ g_object_unref (reply);
+ }
+ else
+ {
+ g_dbus_method_invocation_return_dbus_error (invocation,
+ "org.gtk.GDBus.Failed",
+ "Your message bus daemon does not support file descriptor passing (need D-Bus >= 1.3.0)");
+ }
+#else
+ g_dbus_method_invocation_return_dbus_error (invocation,
+ "org.gtk.GDBus.NotOnUnix",
+ "Your OS does not support file descriptor passing");
+#endif
+ }
+}
+
+static gchar *_global_title = NULL;
+
+static gboolean swap_a_and_b = FALSE;
+
+static GVariant *
+handle_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ GVariant *ret;
+
+ ret = NULL;
+ if (g_strcmp0 (property_name, "FluxCapicitorName") == 0)
+ {
+ ret = g_variant_new_string ("DeLorean");
+ }
+ else if (g_strcmp0 (property_name, "Title") == 0)
+ {
+ if (_global_title == NULL)
+ _global_title = g_strdup ("Back To C!");
+ ret = g_variant_new_string (_global_title);
+ }
+ else if (g_strcmp0 (property_name, "ReadingAlwaysThrowsError") == 0)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Hello %s. I thought I said reading this property "
+ "always results in an error. kthxbye",
+ sender);
+ }
+ else if (g_strcmp0 (property_name, "WritingAlwaysThrowsError") == 0)
+ {
+ ret = g_variant_new_string ("There's no home like home");
+ }
+ else if (g_strcmp0 (property_name, "Foo") == 0)
+ {
+ ret = g_variant_new_string (swap_a_and_b ? "Tock" : "Tick");
+ }
+ else if (g_strcmp0 (property_name, "Bar") == 0)
+ {
+ ret = g_variant_new_string (swap_a_and_b ? "Tick" : "Tock");
+ }
+
+ return ret;
+}
+
+static gboolean
+handle_set_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GVariant *value,
+ GError **error,
+ gpointer user_data)
+{
+ if (g_strcmp0 (property_name, "Title") == 0)
+ {
+ if (g_strcmp0 (_global_title, g_variant_get_string (value, NULL)) != 0)
+ {
+ GVariantBuilder *builder;
+ GError *local_error;
+
+ g_free (_global_title);
+ _global_title = g_variant_dup_string (value, NULL);
+
+ local_error = NULL;
+ builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add (builder,
+ "{sv}",
+ "Title",
+ g_variant_new_string (_global_title));
+ g_dbus_connection_emit_signal (connection,
+ NULL,
+ object_path,
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ g_variant_new ("(sa{sv})",
+ interface_name,
+ builder),
+ &local_error);
+ g_assert_no_error (local_error);
+ }
+ }
+ else if (g_strcmp0 (property_name, "ReadingAlwaysThrowsError") == 0)
+ {
+ /* do nothing - they can't read it after all! */
+ }
+ else if (g_strcmp0 (property_name, "WritingAlwaysThrowsError") == 0)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ "Hello AGAIN %s. I thought I said writing this property "
+ "always results in an error. kthxbye",
+ sender);
+ }
+
+ return *error == NULL;
+}
+
+
+/* for now */
+static const GDBusInterfaceVTable interface_vtable =
+{
+ handle_method_call,
+ handle_get_property,
+ handle_set_property
+};
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+on_timeout_cb (gpointer user_data)
+{
+ GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
+ GVariantBuilder *builder;
+ GError *error;
+
+ swap_a_and_b = !swap_a_and_b;
+
+ error = NULL;
+ builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+ g_variant_builder_add (builder,
+ "{sv}",
+ "Foo",
+ g_variant_new_string (swap_a_and_b ? "Tock" : "Tick"));
+ g_variant_builder_add (builder,
+ "{sv}",
+ "Bar",
+ g_variant_new_string (swap_a_and_b ? "Tick" : "Tock"));
+ g_dbus_connection_emit_signal (connection,
+ NULL,
+ "/org/gtk/GDBus/TestObject",
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ g_variant_new ("(sa{sv})",
+ "org.gtk.GDBus.TestInterface",
+ builder),
+ &error);
+ g_assert_no_error (error);
+
+
+ return TRUE;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_bus_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ guint registration_id;
+
+ registration_id = g_dbus_connection_register_object (connection,
+ "/org/gtk/GDBus/TestObject",
+ "org.gtk.GDBus.TestInterface",
+ introspection_data->interfaces[0],
+ &interface_vtable,
+ NULL, /* user_data */
+ NULL, /* user_data_free_func */
+ NULL); /* GError** */
+ g_assert (registration_id > 0);
+
+ /* swap value of properties Foo and Bar every two seconds */
+ g_timeout_add_seconds (2,
+ on_timeout_cb,
+ connection);
+}
+
+static void
+on_name_acquired (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+}
+
+static void
+on_name_lost (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ exit (1);
+}
+
+int
+main (int argc, char *argv[])
+{
+ guint owner_id;
+ GMainLoop *loop;
+
+ g_type_init ();
+
+ /* We are lazy here - we don't want to manually provide
+ * the introspection data structures - so we just build
+ * them from XML.
+ */
+ introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL);
+ g_assert (introspection_data != NULL);
+
+ owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+ "org.gtk.GDBus.TestServer",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ on_bus_acquired,
+ on_name_acquired,
+ on_name_lost,
+ NULL,
+ NULL);
+
+ loop = g_main_loop_new (NULL, FALSE);
+ g_main_loop_run (loop);
+
+ g_bus_unown_name (owner_id);
+
+ g_dbus_node_info_unref (introspection_data);
+
+ return 0;
+}