Распечатайте ответ вызова метода Dbus на C

Проблема, с которой я столкнулся, заключается в том, чтобы распечатать ответ на вызов метода dbus в C с использованием API низкого уровня. Я новичок в libdbus C, но проделал некоторую работу в python-dbus.

  • Я знаю, как писать методы и вызовы методов dbus в Python, а также CLI
  • Я могу найти в Интернете код для вызова методов dbus, но они не возвращают и не распечатывают ответ
  • Я смотрю на libdbus doxygen api, но не могу определить, как вытащить ответ.

Как я настроил свой код, демон python dbus работает с методами, которые я хочу вызвать. Некоторые из них возвращают строку. Я хочу, чтобы программа на C подключалась к сеансовой шине, вызывала метод, распечатывала ответ и выходила.

Вот что у меня сейчас:

#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;
}

Может быть синхронным или асинхронным.

1 ответ

Вы можете использовать метод, упомянутый в http://www.matthew.ath.cx/misc/dbus чтобы получить ответное сообщение метода.

Получив сообщение dbus, вы можете использовать следующий метод для извлечения данных. Для разбора сообщения dbus необходим итератор аргументов. Инициализируйте его, чтобы прочитать содержимое входящего сообщения.

DBusMessageIter MsgIter;
dbus_message_iter_init(msg, &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);//this function is used to read basic dbus types like int, string etc. 
}

Для сложных типов, таких как структуры, массивы, варианты и записи dict, необходимо создать соответствующие дочерние итераторы для анализа содержимого каждого сложного элемента. Скажем, для сигнатуры dbuss(i{ii}i)u извлечение выполняется, как показано ниже

//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
    }
}

В приведенном выше коде я использовал проверку аргумента за аргументом. Вместо этого вы можете выполнить однократную проверку с использованием dbus_message_iter_get_signature. Обратитесь к libdbus api для получения дополнительной информации.
#
Из вашего ответа я понимаю, что у вас есть проблемы с настройкой соединения, вот полный пример, где вызов метода вызывается на сервере, и результат выводится, если первый аргумент является строкой.
#

#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;
}
Другие вопросы по тегам