C 中的 D-Bus 教程与 wpa_supplicant 通信 [英] D-Bus tutorial in C to communicate with wpa_supplicant

查看:27
本文介绍了C 中的 D-Bus 教程与 wpa_supplicant 通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一些代码来使用 DBUS 与 wpa_supplicant 进行通信.当我在嵌入式系统 (ARM) 中工作时,我想避免使用 Python 或 GLib.我想知道我是不是很愚蠢,因为我真的觉得没有关于 D-Bus 的漂亮而清晰的文档.即使是官方的,我还是觉得文档太高级了,或者显示的示例使用的是 Glib!我看过的文档:http://www.freedesktop.org/wiki/Software/dbus

I'm trying to write some code to communicate with wpa_supplicant using DBUS. As I'm working in an embedded system (ARM), I'd like to avoid the use of Python or the GLib. I'm wondering if I'm stupid because I really have the feeling that there is no nice and clear documentation about D-Bus. Even with the official one, I either find the documentation too high level, or the examples shown are using Glib! Documentation I've looked at: http://www.freedesktop.org/wiki/Software/dbus

我发现了一篇关于在 C 中使用 D-Bus 的好文章:http://www.matthew.ath.cx/articles/dbus

I found a nice article about using D-Bus in C: 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

However, this article is pretty old and not complete enough! I also found the c++-dbus API but also here, I don't find ANY documentation! I've been digging into wpa_supplicant and NetworkManager source code but it's quite a nightmare! I've been looking into the "low-level D-Bus API" as well but this doesn't tell me how to extract a string parameter from a D-Bus message! http://dbus.freedesktop.org/doc/api/html/index.html

这是我写的一些代码来测试一下,但我真的很难提取字符串值.很抱歉源代码太长,但如果有人想尝试一下……我的 D-Bus 配置看起来不错,因为它已经"从 wpa_supplicant 捕获StateChanged"信号但无法打印状态:

Here is some code I wrote to test a little but I really have trouble to extract string values. Sorry for the long source code but if someone want to try it ... My D-Bus configuration seems fine because it "already" catches "StateChanged" signals from wpa_supplicant but cannot print the state:

#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 ...
");
            sleep(1);
            continue;
        }
        else printf("Got a message, will analyze it ...
");

        // Print the message member
        printf("Got message for interface %s
",
                dbus_message_get_interface(msg));
        member = dbus_message_get_member(msg);
        if(member) printf("Got message member %s
", member);

        // Check has argument
        if (!dbus_message_iter_init(msg, &args))
        {
            printf("Message has no argument
");
            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 ...
");

                    /* 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
", strValue);
                }
                else
                    printf("Arg type not implemented yet !
");

                if(dbus_message_iter_has_next(&args))
                    dbus_message_iter_next(&args);
                else break;
            }
            printf("No more arguments!
");
        }

        // 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)
", 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)
", 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)
", 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)
", 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)
", err.message);
        exit(1);
    }

    // Do main loop
    loop(conn);

    // Main loop exited
    printf("Main loop stopped, exiting ...
");

    dbus_connection_close(conn);

    return 0;
}

非常感谢任何指向任何漂亮、完整、低级 C 教程的指针!我还计划做一些远程方法调用,所以如果教程涵盖了这个主题,那就太好了!说我不是很聪明,因为我没有通过官方教程得到它也很感激:-p!

Any pointer to any nice, complete, low-level C tutorial is strongly appreciated! I'm also planning to do some remote method call, so if the tutorial covers this subject it would be great! Saying I'm not very smart because I don't get it with the official tutorial is also appreciated :-p!

或者是否有其他方式与 wpa_supplicant 通信(使用 wpa_cli 除外)?

Or is there another way to communicate with wpa_supplicant (except using wpa_cli)?

编辑 1:

使用 'qdbusviewer' 和自省功能,这有助于我发现 wpa_supplicant 使用 dbus 的工作原理和方式.希望这对其他人有帮助!

Using 'qdbusviewer' and the introspection capabilty, this helped me a lot discovering what and how wpa_supplicant works using dbus. Hopping that this would help someone else!

编辑 2:

当我找到在 D-Bus 上读取字符串值的方法时可能会出现!

Will probably come when I'll find a way to read string values on D-Bus!

推荐答案

您已经放弃了可以帮助您更轻松地学习 D-Bus 的工具,并且正在使用低级别的 libdbus 实现,所以也许您应该加入疼痛.顺便说一句,您是在谈论 ARM,例如手机 ARM 吗?可能有 500 Mhz 和 256 MB RAM?在这种情况下,处理器非常适合使用 glib、Qt 甚至 python.当您编写异步事件驱动代码时,D-Bus 最有用,具有集成的主循环,例如来自 glib,即使您使用的是低级 libdbus(它具有连接到 glib 主循环的功能,例如).

You have given up the tools that would help you to learn D-Bus more easily and are using the low level libdbus implementation, so maybe you deserve to be in pain. BTW, are you talking about ARM, like a cell phone ARM ? With maybe 500 Mhz and 256 MB RAM ? In this case the processor is well suited to using glib, Qt or even python. And D-Bus is most useful when you're writing asynchronous event driven code, with an integrated main loop, for example from glib, even when you're using the low level libdbus (it has functions to connect to the glib main loop, for example).

由于您使用的是低级库,因此您已经拥有文档:

Since you're using the low level library, then documentation is what you already have:

http://dbus.freedesktop.org/doc/api/html/index.html

另外,libdbus 源代码也是文档的一部分:

Also, libdbus source code is also part of the documentation:

http://dbus.freedesktop.org/doc/api/html/文件.html

文档的主要入口点是模块页面(特别是公共 API 部分):

The main entry point for the documentation is the Modules page (in particular, the public API section):

http://dbus.freedesktop.org/doc/api/html/模块.html

对于消息处理,DBusMessage 部分是相关的:DBusMessage

For message handling, the section DBusMessage is the relevant one: DBusMessage

那里有解析项目值的函数的文档.在您的情况下,您从 dbus_message_iter_get_basic 开始.如文档中所述,检索字符串需要一个 const char ** 变量,因为返回的值将指向接收到的消息中预先分配的字符串:

There you have the documentation for functions that parse item values. In your case, you started with a dbus_message_iter_get_basic. As described in the docs, retrieving the string requires a const char ** variable, since the returned value will point to the pre-allocated string in the received message:

所以对于 int32 应该是dbus_int32_t*",对于字符串应该是const char**".返回值是引用,不应被释放.
So for int32 it should be a "dbus_int32_t*" and for string a "const char**". The returned value is by reference and should not be freed.

所以你不能定义一个数组,因为 libdbus 不会将文本复制到你的数组中.如果需要保存字符串,先获取常量字符串引用,然后strcpy到自己的数组中.

So you can't define an array, because libdbus won't copy the text to your array. If you need to save the string, first get the constant string reference, then strcpy to your own array.

然后您尝试在不移动迭代器的情况下获得一个固定数组.您需要调用基本字符串和固定数组之间的下一个迭代器 (dbus_message_iter_next).在递归到子迭代器之前也是如此.

Then you tried to get a fixed array without moving the iterator. You need a call to the next iterator (dbus_message_iter_next) between the basic string and the fixed array. Same right before recursing into the sub iterator.

最后,您不要调用 get_array_len 来获取数组上的元素数量.从文档中,它只返回字节数.相反,您使用 iter_next 循环子迭代器,就像您应该使用主迭代器一样.在您遍历数组末尾之后,dbus_message_iter_get_arg_type 将返回 DBUS_TYPE_INVALID.

Finally, you don't call get_array_len to get the number of elements on the array. From the docs, it only returns byte counts. Instead you loop over the sub iterator using iter_next the same way you should have done with the main iterator. After you have iterated past the end of the array, dbus_message_iter_get_arg_type will return DBUS_TYPE_INVALID.

有关更多信息,请阅读参考手册,不要寻找教程.或者只是使用合理的 d-bus 实现:

For more info, read the reference manual, don't look for a tutorial. Or just use a reasonable d-bus implementation:

https://developer.gnome.org/gio/2.36/gdbus-codegen.html

GIO 的 GDBus 会自动为您的 d-bus 调用创建包装器.

GIO's GDBus automatically creates wrappers for your d-bus calls.

http://qt-project.org/doc/qt-4.8/intro-to-dbus.html

http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html

等等

这篇关于C 中的 D-Bus 教程与 wpa_supplicant 通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆