mor*_*ndg 17 linux embedded dbus
我正在尝试编写一些代码来使用DBUS与wpa_supplicant进行通信.当我在嵌入式系统(ARM)中工作时,我想避免使用Python或GLib.我想知道我是不是很愚蠢,因为我真的觉得没有关于D-Bus的清晰文档.即使使用官方文档,我发现文档的级别太高,或者显示的示例都使用了Glib!我看过的文档:http://www.freedesktop.org/wiki/Software/dbus
我发现了一篇关于在C中使用D-Bus的好文章:http://www.matthew.ath.cx/articles/dbus
但是,这篇文章已经很老了,还不够完整!我也找到了c ++ - dbus API,但在这里,我找不到任何文档!我一直在深入研究wpa_supplicant和NetworkManager源代码,但这真是一场噩梦!我一直在研究"低级D-Bus API",但这并没有告诉我如何从D-Bus消息中提取字符串参数!http://dbus.freedesktop.org/doc/api/html/index.html
下面是我编写的一些代码来测试,但我真的很难提取字符串值.很抱歉有很长的源代码,但如果有人想尝试...我的D-Bus配置似乎很好,因为它"已经"从wpa_supplicant捕获"StateChanged"信号,但无法打印状态:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <dbus/dbus.h>
//#include "wpa_supp_dbus.h"
/* Content of wpa_supp_dbus.h */
#define WPAS_DBUS_SERVICE   "fi.epitest.hostap.WPASupplicant"
#define WPAS_DBUS_PATH      "/fi/epitest/hostap/WPASupplicant"
#define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicant"
#define WPAS_DBUS_PATH_INTERFACES   WPAS_DBUS_PATH "/Interfaces"
#define WPAS_DBUS_IFACE_INTERFACE   WPAS_DBUS_INTERFACE ".Interface"
#define WPAS_DBUS_NETWORKS_PART "Networks"
#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network"
#define WPAS_DBUS_BSSIDS_PART   "BSSIDs"
#define WPAS_DBUS_IFACE_BSSID   WPAS_DBUS_INTERFACE ".BSSID"
int running = 1;
void stopLoop(int sig)
{
    running = 0;
}
void sendScan()
{
  // TODO !
}
void loop(DBusConnection* conn)
{
    DBusMessage* msg;
    DBusMessageIter args;
    DBusMessageIter subArgs;
    int argType;
    int i;
    int buffSize = 1024;
    char strValue[buffSize];
    const char* member = 0;
    sendScan();
    while (running)
    {
        // non blocking read of the next available message
        dbus_connection_read_write(conn, 0);
        msg = dbus_connection_pop_message(conn);
        // loop again if we haven't read a message
        if (!msg)
        {
            printf("No message received, waiting a little ...\n");
            sleep(1);
            continue;
        }
        else printf("Got a message, will analyze it ...\n");
        // Print the message member
        printf("Got message for interface %s\n",
                dbus_message_get_interface(msg));
        member = dbus_message_get_member(msg);
        if(member) printf("Got message member %s\n", member);
        // Check has argument
        if (!dbus_message_iter_init(msg, &args))
        {
            printf("Message has no argument\n");
            continue;
        }
        else
        {
            // Go through arguments
            while(1)
            {
                argType = dbus_message_iter_get_arg_type(&args);
                if (argType == DBUS_TYPE_STRING)
                {
                    printf("Got string argument, extracting ...\n");
                    /* FIXME : got weird characters
                    dbus_message_iter_get_basic(&args, &strValue);
                    */
                    /* FIXME : segmentation fault !
                    dbus_message_iter_get_fixed_array(
                            &args, &strValue, buffSize);
                    */
                    /* FIXME : segmentation fault !
                    dbus_message_iter_recurse(&args, &subArgs);
                    */
                    /* FIXME : deprecated!
                    if(dbus_message_iter_get_array_len(&args) > buffSize)
                        printf("message content to big for local buffer!");
                    */
                    //printf("String value was %s\n", strValue);
                }
                else
                    printf("Arg type not implemented yet !\n");
                if(dbus_message_iter_has_next(&args))
                    dbus_message_iter_next(&args);
                else break;
            }
            printf("No more arguments!\n");
        }
        // free the message
        dbus_message_unref(msg);
    }
}
int main(int argc, char* argv[])
{
    DBusError err;
    DBusConnection* conn;
    int ret;
    char signalDesc[1024];     // Signal description as string
    // Signal handling
    signal(SIGKILL, stopLoop);
    signal(SIGTERM, stopLoop);
    // Initialize err struct
    dbus_error_init(&err);
    // connect to the bus
    conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
    if (dbus_error_is_set(&err))
    {
        fprintf(stderr, "Connection Error (%s)\n", err.message);
        dbus_error_free(&err);
    }
    if (!conn)
    {
        exit(1);
    }
    // request a name on the bus
    ret = dbus_bus_request_name(conn, WPAS_DBUS_SERVICE, 0, &err);
    if (dbus_error_is_set(&err))
    {
        fprintf(stderr, "Name Error (%s)\n", err.message);
        dbus_error_free(&err);
    }
    /* Connect to signal */
    // Interface signal ..
    sprintf(signalDesc, "type='signal',interface='%s'",
            WPAS_DBUS_IFACE_INTERFACE);
    dbus_bus_add_match(conn, signalDesc, &err);
    dbus_connection_flush(conn);
    if (dbus_error_is_set(&err))
    {
        fprintf(stderr, "Match Error (%s)\n", err.message);
        exit(1);
    }
    // Network signal ..
    sprintf(signalDesc, "type='signal',interface='%s'",
            WPAS_DBUS_IFACE_NETWORK);
    dbus_bus_add_match(conn, signalDesc, &err);
    dbus_connection_flush(conn);
    if (dbus_error_is_set(&err))
    {
        fprintf(stderr, "Match Error (%s)\n", err.message);
        exit(1);
    }
    // Bssid signal ..
    sprintf(signalDesc, "type='signal',interface='%s'",
            WPAS_DBUS_IFACE_BSSID);
    dbus_bus_add_match(conn, signalDesc, &err);
    dbus_connection_flush(conn);
    if (dbus_error_is_set(&err))
    {
        fprintf(stderr, "Match Error (%s)\n", err.message);
        exit(1);
    }
    // Do main loop
    loop(conn);
    // Main loop exited
    printf("Main loop stopped, exiting ...\n");
    dbus_connection_close(conn);
    return 0;
}
任何指向任何漂亮,完整,低级C教程的指针都非常感谢!我也打算做一些远程方法调用,所以如果教程涵盖了这个主题,那就太棒了!说我不是很聪明,因为我没有用官方教程得到它也很感激:-p!
或者是否有另一种与wpa_supplicant通信的方式(除了使用wpa_cli)?
编辑1:
使用'qdbusviewer'和内省功能,这有助于我发现wpa_supplicant使用dbus的工作原理和方式.跳这个会帮助别人!
编辑2:
当我找到一种在D-Bus上读取字符串值的方法时,可能会来!
您已经放弃了可以帮助您更轻松地学习 D-Bus 的工具,而正在使用低级别的 libdbus 实现,所以也许您应该感到痛苦。顺便说一句,您是在谈论 ARM,就像手机 ARM 一样吗?可能有 500 Mhz 和 256 MB RAM?在这种情况下,处理器非常适合使用 glib、Qt 甚至 python。当您编写异步事件驱动代码时,D-Bus 最有用,例如来自 glib 的集成主循环,即使您使用低级 libdbus(它具有连接到 glib 主循环的功能,例如)。
由于您使用的是低级库,因此文档就是您已经拥有的:
http://dbus.freedesktop.org/doc/api/html/index.html
此外,libdbus 源代码也是文档的一部分:
http://dbus.freedesktop.org/doc/api/html/files.html
文档的主要入口点是模块页面(特别是公共 API 部分):
http://dbus.freedesktop.org/doc/api/html/modules.html
对于消息处理,DBusMessage 部分是相关的: DBusMessage
那里有解析项目值的函数的文档。在您的情况下,您从 dbus_message_iter_get_basic 开始。如文档中所述,检索字符串需要一个 const char ** 变量,因为返回的值将指向接收到的消息中预先分配的字符串:
因此,对于 int32,它应该是“dbus_int32_t*”,而对于字符串,它应该是“const char**”。返回值是通过引用,不应被释放。
所以你不能定义一个数组,因为 libdbus 不会将文本复制到你的数组中。如果需要保存字符串,先获取常量字符串引用,然后strcpy到自己的数组。
然后您尝试在不移动迭代器的情况下获得固定数组。您需要在基本字符串和固定数组之间调用下一个迭代器 (dbus_message_iter_next)。在递归到子迭代器之前相同。
最后,您不调用 get_array_len 来获取数组上的元素数。从文档中,它只返回字节数。相反,您使用 iter_next 循环遍历子迭代器,就像您应该使用主迭代器一样。遍历数组末尾后,dbus_message_iter_get_arg_type 将返回 DBUS_TYPE_INVALID。
有关更多信息,请阅读参考手册,不要寻找教程。或者只是使用合理的 d-bus 实现:
https://developer.gnome.org/gio/2.36/gdbus-codegen.html
GIO 的 GDBus 会自动为您的 d-bus 调用创建包装器。
http://qt-project.org/doc/qt-4.8/intro-to-dbus.html
http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html
等等。
如果您只需要编写一个 C 程序来与 wpa_supplicant 通信,则不需要使用/理解 dbus 的工作原理。我对 wpa_cli 的源代码进行了逆向工程。完成了它的实现并使用了 wpa_ctrl.h/c 中提供的函数。这个实现会处理所有事情。您可以使用/修改任何您想要的内容,构建可执行文件,然后就完成了!
这是 wpa_supplicant 的 ctrl_interface 的官方链接: http://hostap.epitest.fi/wpa_supplicant/devel/ctrl_iface_page.html