Print Dbus Method Call Answer in C

The problem I encountered is , in particular, printing a response to a dbus method call in C using a low level API. I am new to C libdbus, but have done some work in python-dbus.

  • I know how to write dbus methods and method calls in python as well as CLI
  • I can find code on the Internet to call dbus methods, but they do not return or print the response
  • I am looking at the libdbus doxygen api but cannot determine how to pull the answer.

As I set up my code, the python dbus daemon works with the methods I want to call. Some of them return a string. I want C to connect to the session bus, call the method, print the response, and exit.

This is what I have:

#include <stdio.h> #include <dbus/dbus.h> static void send_dbus_message (DBusConnection *connection, const char *msg) { DBusMessage *message; //initialize the message message = dbus_message_new_signal ("/org/example/foo/bar", "org.example.foo.bar", msg); //send the message dbus_connection_send (connection, message, NULL); //deallocate the message dbus_message_unref (message); } int main (int argc, char **argv) { DBusConnection *connection; DBusError error; //init error message dbus_error_init (&error); connection = dbus_bus_get (DBUS_BUS_SESSION, &error); if (!connection) { printf ("Connection to D-BUS daemon failed: %s", error.message); //deallocate error message dbus_error_free (&error); return 1; } send_dbus_message (connection, "HelloWorld"); return 0; } 

It can be synchronous or asynchronous.

+4
source share
1 answer

You can use the method mentioned at http://www.matthew.ath.cx/misc/dbus to get the method response.

Once you get the dbus message, you can use the following method to retrieve the data. To parse a dbus message, you need an argument iterator. Initialize it to read the contents of the incoming message.

 DBusMessageIter MsgIter; dbus_message_iter_init(msg, &MsgIter);//msg is pointer to dbus message received 

Before reading, you must verify the signature of the incoming message. Or you can also use an argument by checking the arguments. For example, if the argument type is a string

 if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&MsgIter)){ char* str = NULL; dbus_message_iter_get_basic(&MsgIter, &str);//this function is used to read basic dbus types like int, string etc. } 

For complex types, such as structures, arrays, options, and dict entries, you need to create appropriate child iterators to parse the contents of each complex element. Say for a dbus signature s (i {ii} i) u, extraction is performed as below

 //Parsing a signature s(i{ii}i)u DBusMessageIter rootIter; dbus_message_iter_init(msg, &rootIter); if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&rootIter)) { char* str = NULL; dbus_message_iter_get_basic(&rootIter, &str);//this function is used to read basic dbus types like int, string etc. dbus_message_iter_next(&rootIter);//Go to next argument of root iter //Block to enter and read structure if (DBUS_TYPE_STRUCT == dbus_message_iter_get_arg_type(&rootIter)) { DBusMessageIter structIter; dbus_message_iter_recurse(&rootIter, &structIter);//Initialize iterator for struct //Argument 1 is int32 if (DBUS_TYPE_INT32 == dbus_message_iter_get_arg_type(&structIter)) { int a; dbus_message_iter_get_basic(&structIter, &a);//Read integer dbus_message_iter_next(&structIter);//Go to next argument of structiter if (DDBUS_TYPE_DICT_ENTRY == dbus_message_iter_get_arg_type(&structIter)) { DBusMessageIter dictIter; dbus_message_iter_recurse(&structIter, &dictIter);//Initialize iterator for dictentry if (DBUS_TYPE_INT32 == dbus_message_iter_get_arg_type(&dictIter)) { dbus_message_iter_get_basic(&dictIter, &a);//Read integer dbus_message_iter_next(&dictIter);//Go to next argument of dictentry if (DBUS_TYPE_INT32 == dbus_message_iter_get_arg_type(&dictIter)) { dbus_message_iter_get_basic(&dictIter, &a);//Read integer } } } dbus_message_iter_next(&structIter);//Go to next argument of structiter if (DBUS_TYPE_INT32 == dbus_message_iter_get_arg_type(&structIter)) { dbus_message_iter_get_basic(&structIter, &a);//Read integer } } } dbus_message_iter_next(&rootIter);//Go to next argument of root iterator if (DBUS_TYPE_UINT32 == dbus_message_iter_get_arg_type(&rootIter)) { uint32_t b; dbus_message_iter_get_basic(&rootIter, &b);//Read integer } } 

In the above code, I used an argument by checking the signature of the arguments. Instead, you can do a one-time check using dbus_message_iter_get_signature . For more information see the Libdbus api.
#
From your answer, I understand that you have problems setting up the connection, here is a complete example when a method call is called on the server, and the result is printed if the first argument is a string.
#

 #include <stdio.h> #include <stdlib.h> #include <dbus/dbus.h> #include <assert.h> DBusConnection* conn = NULL; //Helper function to setup connection void vsetupconnection(); //Send method call, Returns NULL on failure, else pointer to reply DBusMessage* sendMethodCall(const char* objectpath, \ const char* busname, \ const char* interfacename, \ const char* methodname); #define TEST_BUS_NAME "org.freedesktop.DBus" #define TEST_OBJ_PATH "/org/freedesktop/DBus" #define TEST_INTERFACE_NAME "org.freedesktop.DBus.Introspectable" #define TEST_METHOD_NAME "Introspect" int main (int argc, char **argv) { vsetupconnection(); DBusMessage* reply = sendMethodCall(TEST_OBJ_PATH, TEST_BUS_NAME, TEST_INTERFACE_NAME, TEST_METHOD_NAME); if(reply != NULL) { DBusMessageIter MsgIter; dbus_message_iter_init(reply, &MsgIter);//msg is pointer to dbus message received if (DBUS_TYPE_STRING == dbus_message_iter_get_arg_type(&MsgIter)){ char* str = NULL; dbus_message_iter_get_basic(&MsgIter, &str); printf("Received string: \n %s \n",str); } dbus_message_unref(reply);//unref reply } dbus_connection_close(conn); return 0; } void vsetupconnection() { DBusError err; // initialise the errors dbus_error_init(&err); // connect to session bus conn = dbus_bus_get(DBUS_BUS_SESSION, &err); if (dbus_error_is_set(&err)) { printf("Connection Error (%s)\n", err.message); dbus_error_free(&err); } if (NULL == conn) { exit(1); } else { printf("Connected to session bus\n"); } } DBusMessage* sendMethodCall(const char* objectpath, const char* busname, const char* interfacename, const char* methodname) { assert(objectpath != NULL); assert(busname != NULL); assert(interfacename != NULL); assert(methodname != NULL); assert(conn != NULL); DBusMessage* methodcall = dbus_message_new_method_call(busname,objectpath, interfacename, methodname); if (methodcall == NULL) { printf("Cannot allocate DBus message!\n"); } //Now do a sync call DBusPendingCall* pending; DBusMessage* reply; if (!dbus_connection_send_with_reply(conn, methodcall, &pending, -1))//Send and expect reply using pending call object { printf("failed to send message!\n"); } dbus_connection_flush(conn); dbus_message_unref(methodcall); methodcall = NULL; dbus_pending_call_block(pending);//Now block on the pending call reply = dbus_pending_call_steal_reply(pending);//Get the reply message from the queue dbus_pending_call_unref(pending);//Free pending call handle assert(reply != NULL); if(dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) { printf("Error : %s",dbus_message_get_error_name(reply)); dbus_message_unref(reply); reply = NULL; } return reply; } 
+6
source

Source: https://habr.com/ru/post/1488370/


All Articles