C中的D-Bus教程与wpa_supplicant进行通信

我试图写一些代码来使用DBUS与wpa_supplicant进行通信。 当我在embedded式系统(ARM)中工作时,我想避免使用Python或GLib。 我想知道我是否愚蠢,因为我真的有这样的感觉,就是没有关于D-Bus的清晰文档。 即使是官方的,我要么find太高的文档,要么使用Glib! 我看过的文档: http : //www.freedesktop.org/wiki/Software/dbus

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

但是,这篇文章很老,不够完整! 我也find了c ++ – dbus API,但是在这里,我没有find任何文档! 我一直在挖掘wpa_supplicant和NetworkManager源代码,但这真是一场噩梦! 我一直在研究“低级D-Bus API”,但是这并不能告诉我如何从D-Bus消息中提取string参数! http://dbus.freedesktop.org/doc/api/html/index.html

这里有一些我写的testing代码,但我真的很难提取string值。 对不起,长的源代码,但如果有人想尝试它…我的D-Busconfiguration似乎很好,因为它已经从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'和内省function,这帮助我发现了什么以及wpa_supplicant如何使用dbus工作。 跳,这将有助于别人!

编辑2:

当我find一种方法来读取D-Bus上的string值时,可能会出现这种情况!

    你已经放弃了可以帮助你更容易地学习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

    文档的主要入口点是modulees页面(特别是公共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

    等等

    您不需要使用/理解dbus的工作如果您只需要编写一个C程序来与wpa_supplicant进行通信。 我反向设计了wpa_cli的源代码。 通过它的实现和使用wpa_ctrl.h / c中提供的功能。 这个实现关心一切。 你可以使用/修改任何你想要的,建立你的可执行文件,你就完成了!

    这里是wpa_supplicant的ctrl_interface的官方链接: http : //hostap.epitest.fi/wpa_supplicant/devel/ctrl_iface_page.html

    你的意思是这样的: http : //hostap.epitest.fi/gitweb/gitweb.cgi?p=hostap-1.git;a=tree;f=wpa_supplicant;h=5e71ad2d72cef4a59842cb6c91a116ae4997ddd1;hb=HEAD

    下面的代码片段适合我

     if (argType == DBUS_TYPE_STRING) { printf("Got string argument, extracting ...\n"); char* strBuffer = NULL; dbus_message_iter_get_basic(&args, &strBuffer); printf("Received string: \n %s \n",strBuffer); }