D-BUS Tips 3.0: Performing asynchronous/synchronous method invocations and dbus-binding-tool
To easy perform a synchronous remote method invocation you have just to use GLib bindings for DBus Proxy API (DBusGProxy), that is our first example. The second example shows how to use generated code by dbus-binding-tool to implement remote calls faster. Examples bellow are implemented accessing org.freedesktop.NetworkManager interface of NetworkManager API.
Example 1
int main() { g_type_init(); GError *error = NULL; DBusGConnection *conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error); if (error != NULL) { g_error("D-BUS Connection error: %s", error->message); g_error_free(error); } if (!conn) { g_error("D-BUS connection cannot be created"); return EXIT_FAILURE; } DBusGProxy *proxy = dbus_g_proxy_new_for_name(conn, "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager"); if (!proxy) { g_error("Cannot create proxy"); return EXIT_FAILURE; } g_message("Calling NetworkManager.sate synchronously"); guint state; GError *error = NULL; if (!dbus_g_proxy_call(proxy, "state", &error, G_TYPE_INVALID, G_TYPE_UINT, &state, G_TYPE_INVALID)) { if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) { g_error("Caught remote method exception %s: %s", dbus_g_error_get_name(error), error->message); } else { g_error("D-BUS: %s", error->message); } } print_network_manager_state(state); g_object_unref(proxy); dbus_g_connection_unref(conn); return EXIT_SUCCESS; }
The code is self explaining. Be careful to use the right type parameters, otherwise the call will not work, at D-Bus tutorial page you can find GLib – DBus type mapping. If you want to use more complex types outside this mapping, GLib may show you the message “No marshaller for signature of …” and you will need to register a custom marshaller to this type, but this is a subject for future posts.
Example 2
A faster way to call a remote method is to generate client stub. First you need to get XML API of object interface, you can use d-feet tool to call DBus Introspectable interface and get that.
Then execute the following command passing network-manager-api.xml file:
dbus-binding-tool --mode=glib-client network-manager-api.xml > network-manager-client-stub.h
And you will simply get the code ready to execute D-BUS calls and they are properly typed according to method signatures. The example show you an asynchronous call using the stub:
#include "network-manager-client-stub.h" void network_state_callback(DBusGProxy *proxy, guint state, GError *error, gpointer userdata) { print_network_manager_state(state); g_main_loop_quit(loop); } static GMainLoop *loop; int main() { loop = g_main_loop_new(NULL, FALSE); g_type_init(); GError *error = NULL; DBusGConnection *conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error); if (error != NULL) { g_error("D-BUS Connection error: %s", error->message); g_error_free(error); } if (!conn) { g_error("D-BUS connection cannot be created"); return EXIT_FAILURE; } DBusGProxy *proxy = dbus_g_proxy_new_for_name(conn, "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager", "org.freedesktop.NetworkManager"); if (!proxy) { g_error("Cannot create proxy"); return EXIT_FAILURE; } g_message("Calling NetworkManager.sate asynchronously"); org_freedesktop_NetworkManager_state_async(proxy, network_state_callback , NULL); g_message("Waiting D-BUS callback"); g_main_loop_run(loop); g_message("Exiting glib mainloop"); g_main_loop_unref(loop); g_object_unref(proxy); dbus_g_connection_unref(conn); return EXIT_SUCCESS; }
See full code example in method-invocation.c at dbus-glib-sample project.