6

私が抱えている問題は、低レベル API を使用してC で dbus メソッド呼び出しの応答を出力することです。私はCのlibdbusは初めてですが、python-dbusでいくつかの作業を行いました。

  • CLIだけでなくPythonでもdbusメソッドとメソッド呼び出しを書く方法を知っています
  • インターネットで 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;
}

同期または非同期にすることができます。

4

1 に答える 1

11

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 エントリなどの複雑な型の場合、対応する子反復子を作成して、各複雑な要素の内容を解析する必要があります。たとえば、 s(i{ii}i)u のdbus 署名の場合、抽出は次のように行われます

//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 を使用して 1 回限りの検証を行うことができます。詳細については、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;
}
于 2013-07-15T00:40:25.663 に答える