2013-06-26 3 views
4

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

  • Я знаю, как писать методы Dbus и метод вызывает в питона, а также 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; 
} 

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

+0

Вы смотрели на эти [примеры из учебника] (http://dbus.freedesktop.org/doc/dbus-tutorial.html#glib-more-examples)? – user4815162342

+0

Спасибо за ответ, но этот пример основан на Glib, чего я пытаюсь избежать, поскольку я пишу для системы без X-возможностей. – NuclearPeon

+0

Я просмотрел следующий сайт: http://www.matthew.ath.cx/misc/dbus ... у которого есть полезный код, но он все еще не распечатывает ответ после запуска своего " Вызов метода ".Сам код не имеет переменной param, поэтому он терпит неудачу, если вы скопируете/вставьте его в файл c и скомпилируете его. Даже с переменной она ничего не распечатывает. – NuclearPeon

ответ

6

Вы можете использовать метод, упомянутый в 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 подписи с (I {II} я) у, извлечение делается как показано ниже

//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; 
} 
+0

Спасибо за сообщение, но я не думаю, что это касается моего вопроса. Во-первых, вы ссылаетесь на ту же ссылку, что и в моих комментариях, на @ user4815162342, с которой я закончил без успеха. Распечатка ответа - это то, что мне нужно. Я пройду и испытаю то, что вы написали, когда у меня есть момент, но я не вижу никаких сообщений о печати в вашем ответе, поэтому я не думаю, что это отвечает на мой вопрос. Вы также инициализируете 'char str', но на ваш код не ссылаются. – NuclearPeon

+0

Я считал, что вы столкнулись с проблемами с извлечением аргументов из DBusMessage. Обновленный ответ с тестовым кодом для вашей справки. –