Print out response of Dbus Method Call in C

偶尔善良 提交于 2019-12-04 11:23:18

You can use the method mentioned in http://www.matthew.ath.cx/misc/dbus to get a method reply message.

Once you have a dbus message you can use following method to extract the data. To parse a dbus message, you need a argument iterator. Initalize it to read contents of the incoming message.

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

You have to validate the signature of the incoming message before reading it. Or you can also go for argument by argument verification. For example, if the argument type is 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, like structures, arrays, variants and dict entries, you have to create corresponding child iterators to parse contents of each complex element. Say, for a dbus signature ofs(i{ii}i)u, the extraction is done 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 above code, I used argument by argument signature check. Instead you can do a one time verfication using dbus_message_iter_get_signature. Refer to libdbus api for more info.
#
From your reply I understand that you have problems with connection setup , here is a full example, where a method call is invoked on a 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;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!