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

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

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

Как я настроил свой код, демон dbus python работает с методами, которые я хочу вызвать. Некоторые из них возвращают строку. Я хочу, чтобы программа 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;
}

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


person NuclearPeon    schedule 26.06.2013    source источник
comment
Вы смотрели эти примеры из руководства?   -  person user4815162342    schedule 27.06.2013
comment
Спасибо за ответ, но этот пример основан на Glib, чего я стараюсь избегать, поскольку пишу для системы без возможностей X.   -  person NuclearPeon    schedule 27.06.2013
comment
Я просмотрел следующий сайт: matthew.ath.cx/misc/dbus. .. в котором есть полезный код, но он по-прежнему не выводит ответ после запуска раздела «Вызов метода». Сам код не имеет переменной param, поэтому он не работает, если вы скопируете/вставите его в файл c и скомпилируете. Даже с переменной он ничего не печатает.   -  person NuclearPeon    schedule 27.06.2013
comment
у вас есть что-то на другом конце, что будет реагировать на сигнал /org/example/foo/bar/org.example.foo.bar? Кроме того, вы посылаете сигнал, который должен быть односторонним. В то время как на уровне протокола можно ответить на сигнал (вы можете отправить обратно сообщение с параметром replySerial, установленным на серийный номер сигнала), это не очень распространено, если вообще используется.   -  person Andrey Sidorov    schedule 27.06.2013


Ответы (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. 
}

Для сложных типов, таких как структуры, массивы, варианты и записи словаря, вы должны создать соответствующие дочерние итераторы для анализа содержимого каждого сложного элемента. Скажем, для сигнатуры dbus s(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;
}
person Ranjit Katuri    schedule 15.07.2013
comment
Спасибо за пост, но я не думаю, что он касается моего вопроса. Во-первых, вы ссылаетесь на ту же ссылку, которую я упоминал в своих комментариях к @user4815162342, которые я безуспешно просматривал. Распечатка ответа - это то, что мне нужно. Я просмотрю и проверю то, что вы написали, когда у меня будет время, но я не вижу никаких печатных сообщений в вашем ответе, поэтому я не думаю, что он отвечает на мой вопрос. Вы также инициализируете char str, но это не указано в вашем коде. - person NuclearPeon; 19.07.2013