/** * server-b * A simple D-Bus server, intended as an example in a D-Bus * server tutorial. * * Copyright (c) 2013 Samuel A. Rebelsky. All rights reserved. * * This file is part of The Glimmer Guide to Writing a D-Bus Server. * * The Glimmer Guide to Writing a D-Bus Server is free software: you * can redistribute it and/or modify it under the terms of the GNU * General Public License as published by the Free Software Foundation, * either version 3 of the License, or (at your option) any later version. * * The Glimmer Guide to Writing a D-Bus Server 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software. If not, see . */ // +-------+----------------------------------------------------------- // | Notes | // +-------+ // +---------+--------------------------------------------------------- // | Headers | // +---------+ #include #include #include #include // +--------------------------+---------------------------------------- // | Function Predeclarations | // +--------------------------+ // +-----------+------------------------------------------------------- // | CONSTANTS | // +-----------+ /** * The prefix used in reporting messages. */ #define MSG_PREFIX "[server B] " // +---------+--------------------------------------------------------- // | Globals | // +---------+ /** * The service name on the bus. */ static const gchar service[] = "edu.grinnell.glimmer.guide.SampleServerB"; /** * The object we publish on the bus. */ static const gchar object_name[] = "/edu/grinnell/glimmer/guide/SampleObjectB"; /** * Introspection data for the one object, in the internal form. * (This will get filled in later.) */ static GDBusNodeInfo *introspection_data = NULL; /** * Introspection data for the one object in XML form (somewhat human * readable, somewaht computer readable). */ static const gchar introspection_xml[] = "" " " " " " " " " " " " " " " " " " " " " " " " " " " " " ""; // +------------+------------------------------------------------------ // | Properties | // +------------+ /** * A shared 'n'. */ static int property_n = 42; // +------------------+------------------------------------------------ // | Object Callbacks | // +------------------+ /** * Handle a request for a property. (Parameters should be obvious.) */ 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) { // Print an optional log message #ifdef VERBOSE fprintf (stderr, MSG_PREFIX "handle_get_property (%p,\"%s\",\"%s\",\"%s\",\"%s\",(error),%p)\n", connection, sender, object_path, interface_name, property_name, user_data); #endif // Property "n" - a number (integer) if (g_strcmp0 (property_name, "n") == 0) { return g_variant_new_int32 (property_n); } // "n" // Anything else is an error. else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, MSG_PREFIX "Invalid property '%s'", property_name); return NULL; } // unknown property } // handle_get_property /** * Handle a call to a method. (Parameters should be obvious.) */ 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) { #ifdef VERBOSE gchar *paramstr = g_variant_print (parameters, TRUE); fprintf (stderr, MSG_PREFIX "handle_method_call (%p,\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",(invocation),%p)\n", connection, sender, object_path, interface_name, method_name, paramstr, user_data); g_free (paramstr); #endif // Method one: HelloWorld if (g_strcmp0 (method_name, "HelloWorld") == 0) { GVariant *result = g_variant_new ("(s)", "Hello World"); g_dbus_method_invocation_return_value (invocation, result); } // if it's HelloWorld // Method: Multiply else if (g_strcmp0 (method_name, "compute") == 0) { int n1, n2; // Extract the parameters (number1 and number 2) from parameters g_variant_get (parameters, "(ii)", &n1, &n2); // Do our computation // and ackage our result to return GVariant *result = g_variant_new ("(iiii)", n1+n2, n1-n2, n1*n2, n1/n2); // And return the result g_dbus_method_invocation_return_value (invocation, result); } // if it's 'multiply' // Default: No such method else { g_dbus_method_invocation_return_error (invocation, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, MSG_PREFIX "Invalid method: '%s'", method_name); } // if it's an unknown method } // handle_method_call /** * Handle a request to set a property. */ 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) { // Print an optional log message #ifdef VERBOSE gchar *valstr = g_variant_print (value, TRUE); fprintf (stderr, MSG_PREFIX "handle_set_property (%p,\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",(error),%p)\n", connection, sender, object_path, interface_name, property_name, valstr, user_data); g_free (valstr); #endif // Property "n" - a number (integer) if (g_strcmp0 (property_name, "n") == 0) { property_n = g_variant_get_int32 (value); return 1; } // "n" // We've hit an unknown property name. Issue an error else { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, MSG_PREFIX "Invalid property: '%s'", property_name); return 0; } // unknown property } // handle_set_property // +---------------+--------------------------------------------------- // | Bus Callbacks | // +---------------+ /** * What to do when the bus gets acquired. */ static void on_bus_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { static GDBusInterfaceVTable interface_vtable = { handle_method_call, handle_get_property, handle_set_property }; guint registration_id; GError *error = NULL; // A bit of (optional) notification #ifdef VERBOSE fprintf (stderr, MSG_PREFIX "on_bus_acquired (%p, \"%s\", %p)\n", connection, name, user_data); #endif registration_id = g_dbus_connection_register_object (connection, object_name, introspection_data->interfaces[0], &interface_vtable, NULL, // Optional user data NULL, // Func. for freeing user data &error); } // on_bus_acquired static void on_name_acquired (GDBusConnection *connection, const gchar *name, gpointer user_data) { // A bit of (optional) notification #ifdef VERBOSE fprintf (stderr, MSG_PREFIX "on_name_acquired (%p, \"%s\", %p)\n", connection, name, user_data); #endif } // on_name_acquired static void on_name_lost (GDBusConnection *connection, const gchar *name, gpointer user_data) { // A bit of (optional) notification #ifdef VERBOSE fprintf (stderr, MSG_PREFIX "on_name_lost (%p, \"%s\", %p)\n", connection, name, user_data); #endif // Things seem to have gone badly wrong, so give up exit (1); } // on_name_lost // +------+------------------------------------------------------------ // | Main | // +------+ int main (int argc, char *argv[]) { guint owner_id; GMainLoop *loop; // Set up glib. g_type_init (); // Build an internal representation of the interface introspection_data = g_dbus_node_info_new_for_xml (introspection_xml, NULL); // Request the name on the bus owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, service, G_BUS_NAME_OWNER_FLAGS_NONE, on_bus_acquired, on_name_acquired, on_name_lost, NULL, NULL); // Start the main loop loop = g_main_loop_new (NULL, FALSE); g_main_loop_run (loop); // Tell the bus that we're done with the name g_bus_unown_name (owner_id); // Clean up after ourselves g_dbus_node_info_unref (introspection_data); // And we're done return 0; } // main