commit 082547143c33b228555ef0216dfc4754ce4b8a53 Author: joprietoe Date: Thu Apr 7 10:33:48 2016 -0300 v01 diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..cc7ff0b --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,29 @@ +{ + "version": "0.1.0", + "command": "make", + "isShellCommand": true, + "tasks": [ + { + "taskName": "all", + // Make this the default build command. + "isBuildCommand": true, + // Show the output window only if unrecognized errors occur. + "showOutput": "always", + // No args + "args": [], + // Use the standard less compilation problem matcher. + "problemMatcher": { + "owner": "cpp", + "fileLocation": ["relative", "${workspaceRoot}"], + "pattern": { + "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + } + } + ] +} \ No newline at end of file diff --git a/GPATH b/GPATH new file mode 100644 index 0000000..16aad27 Binary files /dev/null and b/GPATH differ diff --git a/GRTAGS b/GRTAGS new file mode 100644 index 0000000..debcce5 Binary files /dev/null and b/GRTAGS differ diff --git a/GTAGS b/GTAGS new file mode 100644 index 0000000..2d82183 Binary files /dev/null and b/GTAGS differ diff --git a/Makefile b/Makefile new file mode 100755 index 0000000..0b663a8 --- /dev/null +++ b/Makefile @@ -0,0 +1,39 @@ + +CFLAGS_DBUS = $(shell pkg-config --cflags --libs dbus-1) +CFLAGS_DBUS_GLIB = $(shell pkg-config --cflags --libs dbus-glib-1) +CFLAGS_GIO = $(shell pkg-config --cflags --libs gio-2.0) +CFLAGS_GUNIX = $(shell pkg-config --cflags --libs gio-unix-2.0) + +CFLAGS = -g -Wall -Werror + + +all: gdbus-example-server gdbus-example-client + +#dbus-server: dbus-server.c +# gcc $< -o $@ $(CFLAGS) $(CFLAGS_DBUS) $(CFLAGS_DBUS_GLIB) + +#dbus-client: dbus-client.c +# gcc $< -o $@ $(CFLAGS) $(CFLAGS_GIO) + +gdbus-example-server: gdbus-example-server.c + gcc $< -o $@ $(CFLAGS) $(CFLAGS_DBUS) $(CFLAGS_GIO) $(CFLAGS_GUNIX) + +gdbus-example-client: gdbus-example-client.c + gcc $< -o $@ $(CFLAGS) $(CFLAGS_GIO) + +#gdbus-testserver: gdbus-testserver.c +# gcc $< -o $@ $(CFLAGS) $(CFLAGS_GIO) + +#gdbus-example-unix-fd-client: gdbus-example-unix-fd-client.c +# gcc $< -o $@ $(CFLAGS) $(CFLAGS_DBUS) $(CFLAGS_GIO) $(CFLAGS_GUNIX) + +clean: + rm -f dbus-server + rm -f dbus-client + rm -f gdbus-example-server + rm -f gdbus-testserver + rm -f gdbus-example-unix-fd-client + rm -f gdbus-example-client + + +.PHONY: all clean diff --git a/client.c b/client.c new file mode 100755 index 0000000..49fcace --- /dev/null +++ b/client.c @@ -0,0 +1,146 @@ +/* + * Source Code from the DBus Activation Tutorial + * from Raphael Slinckx + * + * This code illustrates how to requrest the dbus daemon + * to automatically start a program that provides a given + * service. For more detailed information refer also to + * http://raphael.slinckx.net/blog/documents/dbus-tutorial + * where all source has taken from. + * + * Provision of all glue code to form compilable application + * by Otto Linnemann + * + * Implementations for Client + */ + +#include "client.h" +#include "client-bindings.h" + +static void client_class_init(ClientClass *klass); +static void client_class_release(ClientClass *klass); + +GType client_get_type(void) +{ + static GType client_type = 0; + + if(!client_type) + { + static const GTypeInfo client_info = { + sizeof(ClientClass), /* class structure size */ + NULL, /* base class initializer */ + NULL, /* base class finalizer */ + (GClassInitFunc)client_class_init, /* class initializer */ + NULL, /* class finalizer */ + NULL, /* class data */ + sizeof(Client), /* instance structure size */ + 1, /* preallocated instances */ + NULL, /* instance initializers */ + NULL + }; + + client_type = g_type_register_static( + G_TYPE_OBJECT, /* parent class */ + "Client", + &client_info, + 0); + } + + return client_type; +} + +static void +client_echo_reply (DBusGProxy *proxy, char *answer, GError *error, gpointer userdata); + +static void client_class_init(ClientClass *klass) +{ + GError *error = NULL; + + /* Init the DBus connection, per-klass */ + klass->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (klass->connection == NULL) + { + g_warning("Unable to connect to dbus: %s", error->message); + g_error_free (error); + return; + } + +/* This won't trigger activation! */ + klass->proxy = dbus_g_proxy_new_for_name (klass->connection, + "org.gnome.ServiceName", + "/org/gnome/ServiceName", + "org.gnome.ServiceName"); + + g_message("ClientClass successfully initialized"); +} + +static void client_send_async(Client *client) +{ + ClientClass *klass = CLIENT_GET_CLASS( client ); + +/* The method call will trigger activation and prints results asynchronously */ + org_gnome_ServiceName_echo_string_async(klass->proxy, + "The async request string we want echo-ed", + client_echo_reply, client); +} + +static void client_send_sync(Client *client) +{ + GError *error = NULL; + ClientClass *klass = CLIENT_GET_CLASS( client ); + gchar *result; + +/* The method call will trigger activation and blocks until result arives */ + if (!org_gnome_ServiceName_echo_string (klass->proxy, + "The sync request string we want echo-ed", + &result, &error)) + { + /* Method failed, the GError is set, let's warn everyone */ + g_warning ("Woops remote method failed: %s", error->message); + g_error_free (error); + return; + } + + g_print ("We got the folowing result from synchronous request: %s\n", result); + +/* Cleanup */ + g_free (result); +} + +static void +client_echo_reply (DBusGProxy *proxy, char *answer, GError *error, gpointer userdata) +{ + Client *client = CLIENT(userdata); + + if (error!= NULL) + { + g_warning ("An error occured while calling echo_string remote method: %s", error->message); + g_error_free (error); + return; + } + + g_print ("We got an echo reply, result: %s\n", answer); +} + + +int main() +{ + Client *client; + GMainLoop *loop; + + g_type_init(); /* initialize type system */ + + if (!g_thread_supported ()) + g_thread_init (NULL); + + dbus_g_thread_init (); + + loop = g_main_loop_new (NULL, FALSE); + client = g_object_new( TYPE_CLIENT, NULL ); + + client_send_async( client ); + client_send_sync( client ); + + g_main_loop_run (loop); + return 0; +} diff --git a/client.h b/client.h new file mode 100755 index 0000000..6a6a7eb --- /dev/null +++ b/client.h @@ -0,0 +1,48 @@ +/* + * Source Code from the DBus Activation Tutorial + * from Raphael Slinckx + * + * This code illustrates how to requrest the dbus daemon + * to automatically start a program that provides a given + * service. For more detailed information refer also to + * http://raphael.slinckx.net/blog/documents/dbus-tutorial + * where all source has taken from. + * + * Provision of all glue code to form compilable application + * by Otto Linnemann + * + * Declarations for Client + */ + +#ifndef CLIENT_H +#define CLIENT_H + +#include + +/* Standard GObject class structures, etc */ + +#define TYPE_CLIENT (client_get_type()) +#define CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_CLIENT, Client)) +#define IS_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_CLIENT)) +#define CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_CLIENT, ClientClass)) +#define IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_CLIENT)) +#define CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_CLIENT, ClientClass)) + +typedef struct +{ + GObjectClass parent_class; + + DBusGConnection *connection; + DBusGProxy *proxy; +} ClientClass; + +typedef struct +{ + GObject parnet_instance; + +} Client; + + +GType client_get_type(void); + +#endif /* #ifndef CLIENT_H */ diff --git a/gdbus-example-client.c b/gdbus-example-client.c new file mode 100644 index 0000000..9c510ad --- /dev/null +++ b/gdbus-example-client.c @@ -0,0 +1,132 @@ +#include +#include + +#include +#include + +#include + +#include +#include + +/* see gdbus-example-server.c for the server implementation */ +static gint +get_server_stdout (GDBusConnection *connection, + const gchar *name_owner, + GError **error) +{ + GDBusMessage *method_call_message; + GDBusMessage *method_reply_message; + GUnixFDList *fd_list; + gint fd; + + fd = -1; + method_call_message = NULL; + method_reply_message = NULL; + + method_call_message = g_dbus_message_new_method_call (name_owner, + "/org/gtk/GDBus/TestObject", + "org.gtk.GDBus.TestInterface", + "GimmeStdout"); + method_reply_message = g_dbus_connection_send_message_with_reply_sync (connection, + method_call_message, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + -1, + NULL, /* out_serial */ + NULL, /* cancellable */ + error); + if (method_reply_message == NULL) + goto out; + + if (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_ERROR) + { + g_dbus_message_to_gerror (method_reply_message, error); + goto out; + } + + fd_list = g_dbus_message_get_unix_fd_list (method_reply_message); + fd = g_unix_fd_list_get (fd_list, 0, error); + + out: + g_object_unref (method_call_message); + g_object_unref (method_reply_message); + + return fd; +} + +static void +on_name_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer user_data) +{ + gint fd; + GError *error; + + error = NULL; + fd = get_server_stdout (connection, name_owner, &error); + if (fd == -1) + { + g_printerr ("Error invoking GimmeStdout(): %s\n", + error->message); + g_error_free (error); + exit (1); + } + else + { + gchar now_buf[256]; + time_t now; + gssize len; + gchar *str; + + now = time (NULL); + strftime (now_buf, + sizeof now_buf, + "%c", + localtime (&now)); + + str = g_strdup_printf ("On %s, gdbus-example-unix-fd-client with pid %d was here!\n", + now_buf, + (gint) getpid ()); + len = strlen (str); + g_warn_if_fail (write (fd, str, len) == len); + close (fd); + + g_print ("Wrote the following on server's stdout:\n%s", str); + + g_free (str); + exit (0); + } +} + +static void +on_name_vanished (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + g_printerr ("Failed to get name owner for %s\n" + "Is ./gdbus-example-server running?\n", + name); + exit (1); +} + +int +main (int argc, char *argv[]) +{ + guint watcher_id; + GMainLoop *loop; + + watcher_id = g_bus_watch_name (G_BUS_TYPE_SESSION, + "org.gtk.GDBus.TestServer", + G_BUS_NAME_WATCHER_FLAGS_NONE, + on_name_appeared, + on_name_vanished, + NULL, + NULL); + + loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (loop); + + g_bus_unwatch_name (watcher_id); + return 0; +} diff --git a/gdbus-example-server.c b/gdbus-example-server.c new file mode 100755 index 0000000..edcfaca --- /dev/null +++ b/gdbus-example-server.c @@ -0,0 +1,391 @@ +#include +#include + +#ifdef G_OS_UNIX +#include +/* For STDOUT_FILENO */ +#include +#endif + +/* ---------------------------------------------------------------------------------------------------- */ + +static GDBusNodeInfo *introspection_data = NULL; + +/* Introspection data for the service we are exporting */ +static const gchar introspection_xml[] = + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +/* ---------------------------------------------------------------------------------------------------- */ + +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, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + 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}as)", + interface_name, + builder, + NULL), + &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; + GVariantBuilder *invalidated_builder; + GError *error; + + swap_a_and_b = !swap_a_and_b; + + error = NULL; + builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY); + invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); + 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}as)", + "org.gtk.GDBus.TestInterface", + builder, + invalidated_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", + 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; + + /* 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; +} + diff --git a/gdbus-example-unix-fd-client.c b/gdbus-example-unix-fd-client.c new file mode 100755 index 0000000..e3ab015 --- /dev/null +++ b/gdbus-example-unix-fd-client.c @@ -0,0 +1,132 @@ +#include +#include + +#include +#include + +#include + +#include +#include + +/* see gdbus-example-server.c for the server implementation */ +static gint +get_server_stdout (GDBusConnection *connection, + const gchar *name_owner, + GError **error) +{ + GDBusMessage *method_call_message; + GDBusMessage *method_reply_message; + GUnixFDList *fd_list; + gint fd; + + fd = -1; + method_call_message = NULL; + method_reply_message = NULL; + + method_call_message = g_dbus_message_new_method_call (name_owner, + "/org/gtk/GDBus/TestObject", + "org.gtk.GDBus.TestInterface", + "GimmeStdout"); + method_reply_message = g_dbus_connection_send_message_with_reply_sync (connection, + method_call_message, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + -1, + NULL, /* out_serial */ + NULL, /* cancellable */ + error); + if (method_reply_message == NULL) + goto out; + + if (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_ERROR) + { + g_dbus_message_to_gerror (method_reply_message, error); + goto out; + } + + fd_list = g_dbus_message_get_unix_fd_list (method_reply_message); + fd = g_unix_fd_list_get (fd_list, 0, error); + + out: + g_object_unref (method_call_message); + g_object_unref (method_reply_message); + + return fd; +} + +static void +on_name_appeared (GDBusConnection *connection, + const gchar *name, + const gchar *name_owner, + gpointer user_data) +{ + gint fd; + GError *error; + + error = NULL; + fd = get_server_stdout (connection, name_owner, &error); + if (fd == -1) + { + g_printerr ("Error invoking GimmeStdout(): %s\n", + error->message); + g_error_free (error); + exit (1); + } + else + { + gchar now_buf[256]; + time_t now; + gssize len; + gchar *str; + + now = time (NULL); + strftime (now_buf, + sizeof now_buf, + "%c", + localtime (&now)); + + str = g_strdup_printf ("On %s, gdbus-example-unix-fd-client with pid %d was here!\n", + now_buf, + (gint) getpid ()); + len = strlen (str); + g_warn_if_fail (write (fd, str, len) == len); + close (fd); + + g_print ("Wrote the following on server's stdout:\n%s", str); + + g_free (str); + exit (0); + } +} + +static void +on_name_vanished (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + g_printerr ("Failed to get name owner for %s\n" + "Is ./gdbus-example-server running?\n", + name); + exit (1); +} + +int +main (int argc, char *argv[]) +{ + guint watcher_id; + GMainLoop *loop; + + watcher_id = g_bus_watch_name (G_BUS_TYPE_SESSION, + "org.gtk.GDBus.TestServer", + G_BUS_NAME_WATCHER_FLAGS_NONE, + on_name_appeared, + on_name_vanished, + NULL, + NULL); + + loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (loop); + + g_bus_unwatch_name (watcher_id); + return 0; +} diff --git a/gdbus-message.c b/gdbus-message.c new file mode 100755 index 0000000..7a88bbf --- /dev/null +++ b/gdbus-message.c @@ -0,0 +1,156 @@ +/* GLib testing framework examples and tests + * + * Copyright (C) 2008-2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + * + * Author: David Zeuthen + */ + +#include +#include + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +on_notify_locked (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + gint *count = user_data; + *count += 1; +} + +static void +message_lock (void) +{ + GDBusMessage *m; + gint count; + + count = 0; + m = g_dbus_message_new (); + g_signal_connect (m, + "notify::locked", + G_CALLBACK (on_notify_locked), + &count); + g_assert (!g_dbus_message_get_locked (m)); + g_dbus_message_lock (m); + g_assert (g_dbus_message_get_locked (m)); + g_assert_cmpint (count, ==, 1); + g_dbus_message_lock (m); + g_assert (g_dbus_message_get_locked (m)); + g_assert_cmpint (count, ==, 1); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Attempted to modify a locked message*"); + g_dbus_message_set_serial (m, 42); + g_test_assert_expected_messages (); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Attempted to modify a locked message*"); + g_dbus_message_set_byte_order (m, G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN); + g_test_assert_expected_messages (); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Attempted to modify a locked message*"); + g_dbus_message_set_message_type (m, G_DBUS_MESSAGE_TYPE_METHOD_CALL); + g_test_assert_expected_messages (); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Attempted to modify a locked message*"); + g_dbus_message_set_flags (m, G_DBUS_MESSAGE_FLAGS_NONE); + g_test_assert_expected_messages (); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Attempted to modify a locked message*"); + g_dbus_message_set_body (m, NULL); + g_test_assert_expected_messages (); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, + "*Attempted to modify a locked message*"); + g_dbus_message_set_header (m, 0, NULL); + g_test_assert_expected_messages (); + + g_object_unref (m); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +message_copy (void) +{ + GDBusMessage *m; + GDBusMessage *copy; + GError *error; + guchar *m_headers; + guchar *copy_headers; + guint n; + + m = g_dbus_message_new_method_call ("org.example.Name", + "/org/example/Object", + "org.example.Interface", + "Method"); + g_dbus_message_set_serial (m, 42); + g_dbus_message_set_byte_order (m, G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN); + + error = NULL; + copy = g_dbus_message_copy (m, &error); + g_assert_no_error (error); + g_assert (G_IS_DBUS_MESSAGE (copy)); + g_assert (m != copy); + g_assert_cmpint (G_OBJECT (m)->ref_count, ==, 1); + g_assert_cmpint (G_OBJECT (copy)->ref_count, ==, 1); + + g_assert_cmpint (g_dbus_message_get_serial (copy), ==, g_dbus_message_get_serial (m)); + g_assert_cmpint (g_dbus_message_get_byte_order (copy), ==, g_dbus_message_get_byte_order (m)); + g_assert_cmpint (g_dbus_message_get_flags (copy), ==, g_dbus_message_get_flags (m)); + g_assert_cmpint (g_dbus_message_get_message_type (copy), ==, g_dbus_message_get_message_type (m)); + m_headers = g_dbus_message_get_header_fields (m); + copy_headers = g_dbus_message_get_header_fields (copy); + g_assert (m_headers != NULL); + g_assert (copy_headers != NULL); + for (n = 0; m_headers[n] != 0; n++) + { + GVariant *m_val; + GVariant *copy_val; + m_val = g_dbus_message_get_header (m, m_headers[n]); + copy_val = g_dbus_message_get_header (m, m_headers[n]); + g_assert (m_val != NULL); + g_assert (copy_val != NULL); + g_assert (g_variant_equal (m_val, copy_val)); + } + g_assert_cmpint (n, >, 0); /* make sure we actually compared headers etc. */ + g_assert_cmpint (copy_headers[n], ==, 0); + g_free (m_headers); + g_free (copy_headers); + + g_object_unref (copy); + g_object_unref (m); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +int +main (int argc, + char *argv[]) +{ + setlocale (LC_ALL, "C"); + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/gdbus/message/lock", message_lock); + g_test_add_func ("/gdbus/message/copy", message_copy); + return g_test_run(); +} + diff --git a/gdbus-tests.c b/gdbus-tests.c new file mode 100755 index 0000000..2770354 --- /dev/null +++ b/gdbus-tests.c @@ -0,0 +1,207 @@ +/* GLib testing framework examples and tests + * + * Copyright (C) 2008-2010 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + * + * Author: David Zeuthen + */ + +#include +#include + +#include "gdbus-tests.h" + +/* ---------------------------------------------------------------------------------------------------- */ + +typedef struct +{ + GMainLoop *loop; + gboolean timed_out; +} PropertyNotifyData; + +static void +on_property_notify (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + PropertyNotifyData *data = user_data; + g_main_loop_quit (data->loop); +} + +static gboolean +on_property_notify_timeout (gpointer user_data) +{ + PropertyNotifyData *data = user_data; + data->timed_out = TRUE; + g_main_loop_quit (data->loop); + return TRUE; +} + +gboolean +_g_assert_property_notify_run (gpointer object, + const gchar *property_name) +{ + gchar *s; + gulong handler_id; + guint timeout_id; + PropertyNotifyData data; + + data.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE); + data.timed_out = FALSE; + s = g_strdup_printf ("notify::%s", property_name); + handler_id = g_signal_connect (object, + s, + G_CALLBACK (on_property_notify), + &data); + g_free (s); + timeout_id = g_timeout_add_seconds (30, + on_property_notify_timeout, + &data); + g_main_loop_run (data.loop); + g_signal_handler_disconnect (object, handler_id); + g_source_remove (timeout_id); + g_main_loop_unref (data.loop); + + return data.timed_out; +} + +static gboolean +_give_up (gpointer data) +{ + g_error ("%s", (const gchar *) data); + g_return_val_if_reached (TRUE); +} + +void +ensure_gdbus_testserver_up (void) +{ + guint id; + gchar *name_owner; + GDBusConnection *connection; + GDBusProxy *proxy; + GError *error = NULL; + + connection = g_bus_get_sync (G_BUS_TYPE_SESSION, + NULL, + &error); + + g_assert_no_error (error); + error = NULL; + + proxy = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_NONE, + NULL, /* GDBusInterfaceInfo */ + "com.example.TestService", /* name */ + "/com/example/TestObject", /* object path */ + "com.example.Frob", /* interface */ + NULL, /* GCancellable */ + &error); + g_assert_no_error (error); + + id = g_timeout_add_seconds (60, _give_up, + "waited more than ~ 60s for gdbus-testserver to take its bus name"); + + while (TRUE) + { + name_owner = g_dbus_proxy_get_name_owner (proxy); + + if (name_owner != NULL) + break; + + g_main_context_iteration (NULL, TRUE); + } + + g_source_remove (id); + g_free (name_owner); + g_object_unref (proxy); + g_object_unref (connection); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +typedef struct +{ + GMainLoop *loop; + gboolean timed_out; +} SignalReceivedData; + +static void +on_signal_received (gpointer user_data) +{ + SignalReceivedData *data = user_data; + g_main_loop_quit (data->loop); +} + +static gboolean +on_signal_received_timeout (gpointer user_data) +{ + SignalReceivedData *data = user_data; + data->timed_out = TRUE; + g_main_loop_quit (data->loop); + return TRUE; +} + +gboolean +_g_assert_signal_received_run (gpointer object, + const gchar *signal_name) +{ + gulong handler_id; + guint timeout_id; + SignalReceivedData data; + + data.loop = g_main_loop_new (g_main_context_get_thread_default (), FALSE); + data.timed_out = FALSE; + handler_id = g_signal_connect_swapped (object, + signal_name, + G_CALLBACK (on_signal_received), + &data); + timeout_id = g_timeout_add_seconds (30, + on_signal_received_timeout, + &data); + g_main_loop_run (data.loop); + g_signal_handler_disconnect (object, handler_id); + g_source_remove (timeout_id); + g_main_loop_unref (data.loop); + + return data.timed_out; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +GDBusConnection * +_g_bus_get_priv (GBusType bus_type, + GCancellable *cancellable, + GError **error) +{ + gchar *address; + GDBusConnection *ret; + + ret = NULL; + + address = g_dbus_address_get_for_bus_sync (bus_type, cancellable, error); + if (address == NULL) + goto out; + + ret = g_dbus_connection_new_for_address_sync (address, + G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | + G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, + NULL, /* GDBusAuthObserver */ + cancellable, + error); + g_free (address); + + out: + return ret; +} \ No newline at end of file diff --git a/gdbus-tests.h b/gdbus-tests.h new file mode 100755 index 0000000..2d7b8a1 --- /dev/null +++ b/gdbus-tests.h @@ -0,0 +1,122 @@ +/* GLib testing framework examples and tests + * + * Copyright (C) 2008-2009 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + * + * Author: David Zeuthen + */ + +#ifndef __TESTS_H__ +#define __TESTS_H__ + +#include +#include "gdbus-sessionbus.h" + +G_BEGIN_DECLS + +/* TODO: clean up and move to gtestutils.c + * + * This is needed because libdbus-1 does not give predictable error messages - e.g. you + * get a different error message on connecting to a bus if the socket file is there vs + * if the socket file is missing. + */ + +#define _g_assert_error_domain(err, dom) do { if (!err || (err)->domain != dom) \ + g_assertion_message_error (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \ + #err, err, dom, -1); } while (0) + +#define _g_assert_property_notify(object, property_name) \ + do \ + { \ + if (!G_IS_OBJECT (object)) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Not a GObject instance"); \ + } \ + if (g_object_class_find_property (G_OBJECT_GET_CLASS (object), \ + property_name) == NULL) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Property " property_name " does not " \ + "exist on object"); \ + } \ + if (_g_assert_property_notify_run (object, property_name)) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Timed out waiting for notification " \ + "on property " property_name); \ + } \ + } \ + while (FALSE) + +#define _g_assert_signal_received(object, signal_name) \ + do \ + { \ + if (!G_IS_OBJECT (object)) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Not a GObject instance"); \ + } \ + if (g_signal_lookup (signal_name, \ + G_TYPE_FROM_INSTANCE (object)) == 0) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Signal '" signal_name "' does not " \ + "exist on object"); \ + } \ + if (_g_assert_signal_received_run (object, signal_name)) \ + { \ + g_assertion_message (G_LOG_DOMAIN, \ + __FILE__, \ + __LINE__, \ + G_STRFUNC, \ + "Timed out waiting for signal '" \ + signal_name "'"); \ + } \ + } \ + while (FALSE) + +gboolean _g_assert_property_notify_run (gpointer object, + const gchar *property_name); + + +gboolean _g_assert_signal_received_run (gpointer object, + const gchar *signal_name); + +GDBusConnection *_g_bus_get_priv (GBusType bus_type, + GCancellable *cancellable, + GError **error); + +void ensure_gdbus_testserver_up (void); + +G_END_DECLS + +#endif /* __TESTS_H__ */ + diff --git a/gdbus-testserver.c b/gdbus-testserver.c new file mode 100755 index 0000000..1ceb638 --- /dev/null +++ b/gdbus-testserver.c @@ -0,0 +1,893 @@ +#include +#include + +static GDBusNodeInfo *introspection_data = NULL; +static GMainLoop *loop = NULL; +static GHashTable *properties = NULL; + +static const gchar introspection_xml[] = + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + +static gboolean +end_sleep (gpointer data) +{ + GDBusMethodInvocation *invocation = data; + + g_dbus_method_invocation_return_value (invocation, NULL); + g_object_unref (invocation); + + return G_SOURCE_REMOVE; +} + +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, "Yo") == 0) + { + g_dbus_method_invocation_return_dbus_error (invocation, + "com.example.TestException", + "Yo is not a proper greeting"); + } + 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, "DoubleHelloWorld") == 0) + { + const gchar *hello1, *hello2; + gchar *reply1, *reply2; + + g_variant_get (parameters, "(&s&s)", &hello1, &hello2); + reply1 = g_strdup_printf ("You greeted me with '%s'. Thanks!", hello1); + reply2 = g_strdup_printf ("Yo dawg, you uttered '%s'. Thanks!", hello2); + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(ss)", reply1, reply2)); + g_free (reply1); + g_free (reply2); + } + else if (g_strcmp0 (method_name, "PairReturn") == 0) + { + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(su)", "foo", 42)); + } + else if (g_strcmp0 (method_name, "TestPrimitiveTypes") == 0) + { + guchar val_byte; + gboolean val_boolean; + gint16 val_int16; + guint16 val_uint16; + gint32 val_int32; + guint32 val_uint32; + gint64 val_int64; + guint64 val_uint64; + gdouble val_double; + const gchar *val_string; + const gchar *val_objpath; + const gchar *val_signature; + gchar *ret_string; + gchar *ret_objpath; + gchar *ret_signature; + + g_variant_get (parameters, "(ybnqiuxtd&s&o&g)", + &val_byte, + &val_boolean, + &val_int16, + &val_uint16, + &val_int32, + &val_uint32, + &val_int64, + &val_uint64, + &val_double, + &val_string, + &val_objpath, + &val_signature); + + ret_string = g_strconcat (val_string, val_string, NULL); + ret_objpath = g_strconcat (val_objpath, "/modified", NULL); + ret_signature = g_strconcat (val_signature, val_signature, NULL); + + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(ybnqiuxtdsog)", + val_byte + 1, + !val_boolean, + val_int16 + 1, + val_uint16 + 1, + val_int32 + 1, + val_uint32 + 1, + val_int64 + 1, + val_uint64 + 1, + - val_double + 0.123, + ret_string, + ret_objpath, + ret_signature)); + + g_free (ret_string); + g_free (ret_objpath); + g_free (ret_signature); + } + else if (g_strcmp0 (method_name, "TestArrayOfPrimitiveTypes") == 0) + { + GVariant *v; + const guchar *bytes; + const gint16 *int16s; + const guint16 *uint16s; + const gint32 *int32s; + const guint32 *uint32s; + const gint64 *int64s; + const guint64 *uint64s; + const gdouble *doubles; + gsize n_elts; + gint i, j; + GVariantBuilder ret; + + g_variant_builder_init (&ret, G_VARIANT_TYPE ("(ayabanaqaiauaxatad)")); + + v = g_variant_get_child_value (parameters, 0); + bytes = g_variant_get_fixed_array (v, &n_elts, 1); + g_variant_builder_open (&ret, G_VARIANT_TYPE ("ay")); + for (j = 0; j < 2; j++) + for (i = 0; i < n_elts; i++) + g_variant_builder_add (&ret, "y", bytes[i]); + g_variant_builder_close (&ret); + g_variant_unref (v); + + v = g_variant_get_child_value (parameters, 1); + bytes = g_variant_get_fixed_array (v, &n_elts, 1); + g_variant_builder_open (&ret, G_VARIANT_TYPE ("ab")); + for (j = 0; j < 2; j++) + for (i = 0; i < n_elts; i++) + g_variant_builder_add (&ret, "b", (gboolean)bytes[i]); + g_variant_builder_close (&ret); + g_variant_unref (v); + + v = g_variant_get_child_value (parameters, 2); + int16s = g_variant_get_fixed_array (v, &n_elts, 2); + g_variant_builder_open (&ret, G_VARIANT_TYPE ("an")); + for (j = 0; j < 2; j++) + for (i = 0; i < n_elts; i++) + g_variant_builder_add (&ret, "n", int16s[i]); + g_variant_builder_close (&ret); + g_variant_unref (v); + + v = g_variant_get_child_value (parameters, 3); + uint16s = g_variant_get_fixed_array (v, &n_elts, 2); + g_variant_builder_open (&ret, G_VARIANT_TYPE ("aq")); + for (j = 0; j < 2; j++) + for (i = 0; i < n_elts; i++) + g_variant_builder_add (&ret, "q", uint16s[i]); + g_variant_builder_close (&ret); + g_variant_unref (v); + + v = g_variant_get_child_value (parameters, 4); + int32s = g_variant_get_fixed_array (v, &n_elts, 4); + g_variant_builder_open (&ret, G_VARIANT_TYPE ("ai")); + for (j = 0; j < 2; j++) + for (i = 0; i < n_elts; i++) + g_variant_builder_add (&ret, "i", int32s[i]); + g_variant_builder_close (&ret); + g_variant_unref (v); + + v = g_variant_get_child_value (parameters, 5); + uint32s = g_variant_get_fixed_array (v, &n_elts, 4); + g_variant_builder_open (&ret, G_VARIANT_TYPE ("au")); + for (j = 0; j < 2; j++) + for (i = 0; i < n_elts; i++) + g_variant_builder_add (&ret, "u", uint32s[i]); + g_variant_builder_close (&ret); + g_variant_unref (v); + + v = g_variant_get_child_value (parameters, 6); + int64s = g_variant_get_fixed_array (v, &n_elts, 8); + g_variant_builder_open (&ret, G_VARIANT_TYPE ("ax")); + for (j = 0; j < 2; j++) + for (i = 0; i < n_elts; i++) + g_variant_builder_add (&ret, "x", int64s[i]); + g_variant_builder_close (&ret); + g_variant_unref (v); + + v = g_variant_get_child_value (parameters, 7); + uint64s = g_variant_get_fixed_array (v, &n_elts, 8); + g_variant_builder_open (&ret, G_VARIANT_TYPE ("at")); + for (j = 0; j < 2; j++) + for (i = 0; i < n_elts; i++) + g_variant_builder_add (&ret, "t", uint64s[i]); + g_variant_builder_close (&ret); + g_variant_unref (v); + + v = g_variant_get_child_value (parameters, 8); + doubles = g_variant_get_fixed_array (v, &n_elts, sizeof (gdouble)); + g_variant_builder_open (&ret, G_VARIANT_TYPE ("ad")); + for (j = 0; j < 2; j++) + for (i = 0; i < n_elts; i++) + g_variant_builder_add (&ret, "d", doubles[i]); + g_variant_builder_close (&ret); + g_variant_unref (v); + + g_dbus_method_invocation_return_value (invocation, + g_variant_builder_end (&ret)); + } + else if (g_strcmp0 (method_name, "TestArrayOfStringTypes") == 0) + { + GVariantIter *iter1; + GVariantIter *iter2; + GVariantIter *iter3; + GVariantIter *iter; + GVariantBuilder ret; + const gchar *s; + gint i; + + g_variant_builder_init (&ret, G_VARIANT_TYPE ("(asaoag)")); + g_variant_get (parameters, "(asaoag)", &iter1, &iter2, &iter3); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("as")); + for (i = 0; i < 2; i++) + { + iter = g_variant_iter_copy (iter1); + while (g_variant_iter_loop (iter, "s", &s)) + g_variant_builder_add (&ret, "s", s); + g_variant_iter_free (iter); + } + g_variant_builder_close (&ret); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("ao")); + for (i = 0; i < 2; i++) + { + iter = g_variant_iter_copy (iter1); + while (g_variant_iter_loop (iter, "o", &s)) + g_variant_builder_add (&ret, "o", s); + g_variant_iter_free (iter); + } + g_variant_builder_close (&ret); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("ag")); + for (i = 0; i < 2; i++) + { + iter = g_variant_iter_copy (iter1); + while (g_variant_iter_loop (iter, "g", &s)) + g_variant_builder_add (&ret, "g", s); + g_variant_iter_free (iter); + } + g_variant_builder_close (&ret); + + g_variant_iter_free (iter1); + g_variant_iter_free (iter2); + g_variant_iter_free (iter3); + + g_dbus_method_invocation_return_value (invocation, + g_variant_builder_end (&ret)); + } + else if (g_strcmp0 (method_name, "TestHashTables") == 0) + { + GVariant *v; + GVariantIter iter; + GVariantBuilder ret; + guint8 y1, y2; + gboolean b1, b2; + gint16 n1, n2; + guint16 q1, q2; + gint i1, i2; + guint u1, u2; + gint64 x1, x2; + guint64 t1, t2; + gdouble d1, d2; + gchar *s1, *s2; + + g_print("Hello\n"); + + g_variant_builder_init (&ret, G_VARIANT_TYPE ("(a{yy}a{bb}a{nn}a{qq}a{ii}a{uu}a{xx}a{tt}a{dd}a{ss}a{oo}a{gg})")); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{yy}")); + v = g_variant_get_child_value (parameters, 0); + g_variant_iter_init (&iter, v); + while (g_variant_iter_loop (&iter, "yy", &y1, &y2)) + g_variant_builder_add (&ret, "{yy}", y1 * 2, (y2 * 3) & 255); + g_variant_unref (v); + g_variant_builder_close (&ret); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{bb}")); + v = g_variant_get_child_value (parameters, 1); + g_variant_iter_init (&iter, v); + while (g_variant_iter_loop (&iter, "bb", &b1, &b2)) + g_variant_builder_add (&ret, "{bb}", b1, TRUE); + g_variant_unref (v); + g_variant_builder_close (&ret); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{nn}")); + v = g_variant_get_child_value (parameters, 2); + g_variant_iter_init (&iter, v); + while (g_variant_iter_loop (&iter, "nn", &n1, &n2)) + g_variant_builder_add (&ret, "{nn}", n1 * 2, n2 * 3); + g_variant_unref (v); + g_variant_builder_close (&ret); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{qq}")); + v = g_variant_get_child_value (parameters, 3); + g_variant_iter_init (&iter, v); + while (g_variant_iter_loop (&iter, "qq", &q1, &q2)) + g_variant_builder_add (&ret, "{qq}", q1 * 2, q2 * 3); + g_variant_unref (v); + g_variant_builder_close (&ret); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{ii}")); + v = g_variant_get_child_value (parameters, 4); + g_variant_iter_init (&iter, v); + while (g_variant_iter_loop (&iter, "ii", &i1, &i2)) + g_variant_builder_add (&ret, "{ii}", i1 * 2, i2 * 3); + g_variant_unref (v); + g_variant_builder_close (&ret); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{uu}")); + v = g_variant_get_child_value (parameters, 5); + g_variant_iter_init (&iter, v); + while (g_variant_iter_loop (&iter, "uu", &u1, &u2)) + g_variant_builder_add (&ret, "{uu}", u1 * 2, u2 * 3); + g_variant_unref (v); + g_variant_builder_close (&ret); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{xx}")); + v = g_variant_get_child_value (parameters, 6); + g_variant_iter_init (&iter, v); + while (g_variant_iter_loop (&iter, "xx", &x1, &x2)) + g_variant_builder_add (&ret, "{xx}", x1 + 2, x2 + 1); + g_variant_unref (v); + g_variant_builder_close (&ret); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{tt}")); + v = g_variant_get_child_value (parameters, 7); + g_variant_iter_init (&iter, v); + while (g_variant_iter_loop (&iter, "tt", &t1, &t2)) + g_variant_builder_add (&ret, "{tt}", t1 + 2, t2 + 1); + g_variant_unref (v); + g_variant_builder_close (&ret); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{dd}")); + v = g_variant_get_child_value (parameters, 8); + g_variant_iter_init (&iter, v); + while (g_variant_iter_loop (&iter, "dd", &d1, &d2)) + g_variant_builder_add (&ret, "{dd}", d1 + 2.5, d2 + 5.0); + g_variant_unref (v); + g_variant_builder_close (&ret); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{ss}")); + v = g_variant_get_child_value (parameters, 9); + g_variant_iter_init (&iter, v); + while (g_variant_iter_loop (&iter, "ss", &s1, &s2)) + { + gchar *tmp1, *tmp2; + tmp1 = g_strconcat (s1, "mod", NULL); + tmp2 = g_strconcat (s2, s2, NULL); + g_variant_builder_add (&ret, "{ss}", tmp1, tmp2); + g_free (tmp1); + g_free (tmp2); + } + g_variant_unref (v); + g_variant_builder_close (&ret); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{oo}")); + v = g_variant_get_child_value (parameters, 10); + g_variant_iter_init (&iter, v); + while (g_variant_iter_loop (&iter, "oo", &s1, &s2)) + { + gchar *tmp1, *tmp2; + tmp1 = g_strconcat (s1, "/mod", NULL); + tmp2 = g_strconcat (s2, "/mod2", NULL); + g_variant_builder_add (&ret, "{oo}", tmp1, tmp2); + g_free (tmp1); + g_free (tmp2); + } + g_variant_unref (v); + g_variant_builder_close (&ret); + + g_variant_builder_open (&ret, G_VARIANT_TYPE ("a{gg}")); + v = g_variant_get_child_value (parameters, 11); + g_variant_iter_init (&iter, v); + while (g_variant_iter_loop (&iter, "gg", &s1, &s2)) + { + gchar *tmp1, *tmp2; + tmp1 = g_strconcat (s1, "assgit", NULL); + tmp2 = g_strconcat (s2, s2, NULL); + g_variant_builder_add (&ret, "{gg}", tmp1, tmp2); + g_free (tmp1); + g_free (tmp2); + } + g_variant_unref (v); + g_variant_builder_close (&ret); + + g_dbus_method_invocation_return_value (invocation, + g_variant_builder_end (&ret)); + } + else if (g_strcmp0 (method_name, "TestStructureTypes") == 0) + { + gint x, y, x1, y1; + const gchar *desc; + GVariantIter *iter1, *iter2; + gchar *desc_ret; + GVariantBuilder ret1, ret2; + GVariantIter *iter; + GVariant *v; + gchar *s1, *s2; + + g_variant_get (parameters, "((ii)(&s(ii)aya{ss}))", + &x, &y, &desc, &x1, &y1, &iter1, &iter2); + + desc_ret = g_strconcat (desc, "... in bed!", NULL); + + g_variant_builder_init (&ret1, G_VARIANT_TYPE ("ay")); + iter = g_variant_iter_copy (iter1); + while (g_variant_iter_loop (iter1, "y", &v)) + g_variant_builder_add (&ret1, "y", v); + while (g_variant_iter_loop (iter, "y", &v)) + g_variant_builder_add (&ret1, "y", v); + g_variant_iter_free (iter); + g_variant_iter_free (iter1); + + g_variant_builder_init (&ret2, G_VARIANT_TYPE ("a{ss}")); + while (g_variant_iter_loop (iter1, "ss", &s1, &s2)) + { + gchar *tmp; + tmp = g_strconcat (s2, " ... in bed!", NULL); + g_variant_builder_add (&ret1, "{ss}", s1, tmp); + g_free (tmp); + } + g_variant_iter_free (iter2); + + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("((ii)(&s(ii)aya{ss}))", + x + 1, y + 1, desc_ret, x1 + 2, y1 + 2, + &ret1, &ret2)); + + g_free (desc_ret); + } + else if (g_strcmp0 (method_name, "TestVariant") == 0) + { + GVariant *v; + gboolean modify; + GVariant *ret; + + g_variant_get (parameters, "(vb)", &v, &modify); + + /* FIXME handle more cases */ + if (modify) + { + if (g_variant_is_of_type (v, G_VARIANT_TYPE_BOOLEAN)) + { + ret = g_variant_new_boolean (FALSE); + } + else if (g_variant_is_of_type (v, G_VARIANT_TYPE_TUPLE)) + { + ret = g_variant_new ("(si)", "other struct", 100); + } + else + g_assert_not_reached (); + } + else + ret = v; + + g_dbus_method_invocation_return_value (invocation, ret); + g_variant_unref (v); + } + else if (g_strcmp0 (method_name, "TestComplexArrays") == 0) + { + /* FIXME */ + g_dbus_method_invocation_return_value (invocation, parameters); + } + else if (g_strcmp0 (method_name, "TestComplexHashTables") == 0) + { + /* FIXME */ + g_dbus_method_invocation_return_value (invocation, parameters); + } + else if (g_strcmp0 (method_name, "FrobSetProperty") == 0) + { + gchar *name; + GVariant *value; + g_variant_get (parameters, "(sv)", &name, &value); + g_hash_table_replace (properties, name, value); + g_dbus_connection_emit_signal (connection, + NULL, + "/com/example/TestObject", + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + g_variant_new_parsed ("('com.example.Frob', [{%s, %v}], @as [])", name, value), + NULL); + g_dbus_method_invocation_return_value (invocation, NULL); + } + else if (g_strcmp0 (method_name, "FrobInvalidateProperty") == 0) + { + const gchar *value; + g_variant_get (parameters, "(&s)", &value); + g_hash_table_replace (properties, g_strdup ("PropertyThatWillBeInvalidated"), g_variant_ref_sink (g_variant_new_string (value))); + + g_dbus_connection_emit_signal (connection, + NULL, + "/com/example/TestObject", + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + g_variant_new_parsed ("('com.example.Frob', @a{sv} [], ['PropertyThatWillBeInvalidated'])"), + NULL); + g_dbus_method_invocation_return_value (invocation, NULL); + } + else if (g_strcmp0 (method_name, "EmitSignal") == 0) + { + const gchar *str; + const gchar *path; + gchar *str_ret; + gchar *path_ret; + g_variant_get (parameters, "(&s&o)", &str, &path); + str_ret = g_strconcat (str, " .. in bed!", NULL); + path_ret = g_strconcat (path, "/in/bed", NULL); + g_dbus_connection_emit_signal (connection, + NULL, + "/com/example/TestObject", + "com.example.Frob", + "TestSignal", + g_variant_new_parsed ("(%s, %o, <'a variant'>)", str_ret, path_ret), + NULL); + g_free (str_ret); + g_free (path_ret); + g_dbus_method_invocation_return_value (invocation, NULL); + } + else if (g_strcmp0 (method_name, "EmitSignal2") == 0) + { + g_dbus_connection_emit_signal (connection, + NULL, + "/com/example/TestObject", + "com.example.Frob", + "TestSignal2", + g_variant_new_parsed ("(42, )"), + NULL); + g_dbus_method_invocation_return_value (invocation, NULL); + } + else if (g_strcmp0 (method_name, "Sleep") == 0) + { + gint msec; + + g_variant_get (parameters, "(i)", &msec); + + g_timeout_add ((guint)msec, end_sleep, g_object_ref (invocation)); + } + else if (g_strcmp0 (method_name, "Quit") == 0) + { + g_dbus_method_invocation_return_value (invocation, NULL); + g_main_loop_quit (loop); + } +} + +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 = g_hash_table_lookup (properties, property_name); + if (ret) + { + g_assert (!g_variant_is_floating (ret)); + g_variant_ref (ret); + } + else + { + g_set_error (error, + G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "no such property: %s", property_name); + } + + 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) +{ + g_set_error (error, + G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "SetProperty not implemented"); + return FALSE; +} + +static const GDBusInterfaceVTable interface_vtable = +{ + handle_method_call, + handle_get_property, + handle_set_property +}; + +static void +on_bus_acquired (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + guint id; + + id = g_dbus_connection_register_object (connection, + "/com/example/TestObject", + introspection_data->interfaces[0], + &interface_vtable, + NULL, + NULL, + NULL); + g_assert (id > 0); +} + +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; + + introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); + properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_variant_unref); + g_hash_table_insert (properties, g_strdup ("y"), g_variant_ref_sink (g_variant_new_byte (1))); + g_hash_table_insert (properties, g_strdup ("b"), g_variant_ref_sink (g_variant_new_boolean (TRUE))); + g_hash_table_insert (properties, g_strdup ("n"), g_variant_ref_sink (g_variant_new_int16 (2))); + g_hash_table_insert (properties, g_strdup ("q"), g_variant_ref_sink (g_variant_new_uint16 (3))); + g_hash_table_insert (properties, g_strdup ("i"), g_variant_ref_sink (g_variant_new_int32 (4))); + g_hash_table_insert (properties, g_strdup ("u"), g_variant_ref_sink (g_variant_new_uint32 (5))); + g_hash_table_insert (properties, g_strdup ("x"), g_variant_ref_sink (g_variant_new_int64 (6))); + g_hash_table_insert (properties, g_strdup ("t"), g_variant_ref_sink (g_variant_new_uint64 (7))); + g_hash_table_insert (properties, g_strdup ("d"), g_variant_ref_sink (g_variant_new_double (7.5))); + g_hash_table_insert (properties, g_strdup ("s"), g_variant_ref_sink (g_variant_new_string ("a string"))); + g_hash_table_insert (properties, g_strdup ("o"), g_variant_ref_sink (g_variant_new_object_path ("/some/path"))); + g_hash_table_insert (properties, g_strdup ("ay"), g_variant_ref_sink (g_variant_new_parsed ("[@y 1, @y 11]"))); + g_hash_table_insert (properties, g_strdup ("ab"), g_variant_ref_sink (g_variant_new_parsed ("[true, false]"))); + g_hash_table_insert (properties, g_strdup ("an"), g_variant_ref_sink (g_variant_new_parsed ("[@n 2, @n 12]"))); + g_hash_table_insert (properties, g_strdup ("aq"), g_variant_ref_sink (g_variant_new_parsed ("[@q 3, @q 13]"))); + g_hash_table_insert (properties, g_strdup ("ai"), g_variant_ref_sink (g_variant_new_parsed ("[@i 4, @i 14]"))); + g_hash_table_insert (properties, g_strdup ("au"), g_variant_ref_sink (g_variant_new_parsed ("[@u 5, @u 15]"))); + g_hash_table_insert (properties, g_strdup ("ax"), g_variant_ref_sink (g_variant_new_parsed ("[@x 6, @x 16]"))); + g_hash_table_insert (properties, g_strdup ("at"), g_variant_ref_sink (g_variant_new_parsed ("[@t 7, @t 17]"))); + g_hash_table_insert (properties, g_strdup ("ad"), g_variant_ref_sink (g_variant_new_parsed ("[7.5, 17.5]"))); + g_hash_table_insert (properties, g_strdup ("as"), g_variant_ref_sink (g_variant_new_parsed ("['a string', 'another string']"))); + g_hash_table_insert (properties, g_strdup ("ao"), g_variant_ref_sink (g_variant_new_parsed ("[@o '/some/path', @o '/another/path']"))); + g_hash_table_insert (properties, g_strdup ("foo"), g_variant_ref_sink (g_variant_new_string ("a frobbed string"))); + g_hash_table_insert (properties, g_strdup ("PropertyThatWillBeInvalidated"), g_variant_ref_sink (g_variant_new_string ("InitialValue"))); + + owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, + "com.example.TestService", + 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; +} + + diff --git a/server.c b/server.c new file mode 100755 index 0000000..e884eed --- /dev/null +++ b/server.c @@ -0,0 +1,145 @@ +/* + * Source Code from the DBus Activation Tutorial + * from Raphael Slinckx + * + * This code illustrates how to requrest the dbus daemon + * to automatically start a program that provides a given + * service. For more detailed information refer also to + * http://raphael.slinckx.net/blog/documents/dbus-tutorial + * where all source has taken from. + * + * Provision of all glue code to form compilable application + * by Otto Linnemann + * + * Implementations for Server + */ + +#include "server.h" +#include "server-bindings.h" + +static void server_class_init(ServerClass *klass); + +GType server_get_type(void) +{ + static GType server_type = 0; + + if(!server_type) + { + static const GTypeInfo server_info = { + sizeof(ServerClass), /* class structure size */ + NULL, /* base class initializer */ + NULL, /* base class finalizer */ + (GClassInitFunc)server_class_init, /* class initializer */ + NULL, /* class finalizer */ + NULL, /* class data */ + sizeof(Server), /* instance structure size */ + 1, /* preallocated instances */ + NULL, /* instance initializers */ + NULL + }; + + server_type = g_type_register_static( + G_TYPE_OBJECT, /* parent class */ + "Server", + &server_info, + 0); + } + + return server_type; +} + +static void server_class_init(ServerClass *klass) +{ + GError *error = NULL; + + /* Init the DBus connection, per-klass */ + klass->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (klass->connection == NULL) + { + g_warning("Unable to connect to dbus: %s", error->message); + g_error_free (error); + return; + } + + /* &dbus_glib__object_info is provided in the server-bindings.h file */ + /* OBJECT_TYPE_SERVER is the GType of your server object */ + dbus_g_object_type_install_info (TYPE_SERVER, &dbus_glib_server_object_object_info); + + g_message("ServerClass successfully initialized"); +} + + +static gint server_init(Server *server) +{ + GError *error = NULL; + DBusGProxy *driver_proxy; + ServerClass *klass = SERVER_GET_CLASS (server); + guint request_ret; + gint retcode = 1; + + /* Register DBUS path */ + dbus_g_connection_register_g_object (klass->connection, + "/org/gnome/ServiceName", + G_OBJECT (server)); + + /* Register the service name, the constant here are defined in dbus-glib-bindings.h */ + driver_proxy = dbus_g_proxy_new_for_name (klass->connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + + if(!org_freedesktop_DBus_request_name (driver_proxy, + "org.gnome.ServiceName", + 0, &request_ret, /* See tutorial for more infos about these */ + &error)) + { + g_warning("Unable to register service: %s", error->message); + g_error_free (error); + retcode = 0; + } + g_object_unref (driver_proxy); + + return( retcode ); +} + + +gboolean server_echo_string (Server *server, gchar *original, gchar **echo, GError **error) +{ + *echo = g_strdup (original); + gboolean problem = FALSE; + + if (problem) + { + /* We have an error, set the gerror */ + g_set_error (error, g_quark_from_static_string ("echo"), + 0xdeadbeef, + "Some random problem occured, you're screwed"); + return FALSE; + } + + return TRUE; +} + +int main() +{ + Server *server; + GMainLoop *loop; + + g_type_init(); /* initialize type system */ + + if (!g_thread_supported ()) + g_thread_init (NULL); + + dbus_g_thread_init (); + + loop = g_main_loop_new (NULL, FALSE); + + server = g_object_new( TYPE_SERVER, NULL ); + + if( server_init( server ) ) + { + g_main_loop_run (loop); + } + + return 0; +} diff --git a/server.h b/server.h new file mode 100755 index 0000000..21266d3 --- /dev/null +++ b/server.h @@ -0,0 +1,48 @@ +/* + * Source Code from the DBus Activation Tutorial + * from Raphael Slinckx + * + * This code illustrates how to requrest the dbus daemon + * to automatically start a program that provides a given + * service. For more detailed information refer also to + * http://raphael.slinckx.net/blog/documents/dbus-tutorial + * where all source has taken from. + * + * Provision of all glue code to form compilable application + * by Otto Linnemann + * + * Declarations for Server + */ + +#ifndef SERVER_H +#define SERVER_H + +#include + +/* Standard GObject class structures, etc */ + +#define TYPE_SERVER (server_get_type()) +#define SERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_SERVER, Server)) +#define IS_SERVER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_SERVER)) +#define SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_SERVER, ServerClass)) +#define IS_SERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_SERVER)) +#define SERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_SERVER, ServerClass)) + +typedef struct +{ + GObjectClass parent_class; + + DBusGConnection *connection; +} ServerClass; + +typedef struct +{ + GObject parnet_instance; + +} Server; + + +GType server_get_type(void); +gboolean server_echo_string(Server *server, gchar *original, gchar **echo, GError **error); + +#endif /* #ifndef SERVER_H */ diff --git a/servicename-infos.xml b/servicename-infos.xml new file mode 100755 index 0000000..119253c --- /dev/null +++ b/servicename-infos.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + +