Я сомневаюсь, что этот ответ будет по-прежнему актуален для автора этого вопроса,
но для любого, кто наткнулся на это, как я сделал:
Ситуация сейчас лучше, чем все эти годы назад, если вы не хотите включать GTK / QT в свой проект для доступа к dbus.
В Embedded Linux Library от Intel есть API-интерфейс dbus (странно, я помню, что он открыт, может быть, он только для зарегистрированных пользователей?)
и библиотека systemd sd-bus теперь предлагает публичный API. Вы, вероятно, в любом случае запустите systemd, если у вас действительно ограниченная встроенная система.
Я работал с GDbus, dbus-cpp и sd-bus, и хотя мне нужна библиотека C ++,
Я нашел sd-bus самым простым и наименее проблемным опытом.
Я не пробовал его привязки C ++, но они также хорошо выглядят
#include <stdio.h>
#include <systemd/sd-bus.h>
#include <stdlib.h>
const char* wpa_service = "fi.w1.wpa_supplicant1";
const char* wpa_root_obj_path = "/fi/w1/wpa_supplicant1";
const char* wpa_root_iface = "fi.w1.wpa_supplicant1";
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus* system_bus = NULL;
sd_event* loop = NULL;
sd_bus_message* reply = NULL;
void cleanup() {
sd_event_unref(loop);
sd_bus_unref(system_bus);
sd_bus_message_unref(reply);
sd_bus_error_free(&error);
}
void print_error(const char* msg, int code) {
fprintf(stderr, "%s %s\n", msg, strerror(-code));
exit(EXIT_FAILURE);
}
const char* get_interface(const char* iface) {
int res = sd_bus_call_method(system_bus,
wpa_service,
wpa_root_obj_path,
wpa_root_iface,
"GetInterface",
&error,
&reply,
"s",
"Ifname", "s", iface,
"Driver", "s", "nl80211");
if (res < 0) {
fprintf(stderr, "(get) error response: %s\n", error.message);
return NULL;
}
const char* iface_path;
/*
* an object path was returned in reply
* this works like an iterator, if a method returns (osu), you could call message_read_basic in succession
* with arguments SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_STRING, SD_BUS_TYPE_UINT32 or you could
* call sd_bus_message_read() and provides the signature + arguments in one call
* */
res = sd_bus_message_read_basic(reply, SD_BUS_TYPE_OBJECT_PATH, &iface_path);
if (res < 0) {
print_error("getIface: ", res);
return NULL;
}
return iface_path;
}
const char* create_interface(const char* iface) {
int res = sd_bus_call_method(system_bus,
wpa_service,
wpa_root_obj_path,
wpa_root_iface,
"CreateInterface",
&error,
&reply,
"a{sv}", 2, //pass array of str:variant (dbus dictionary) with 2
//entries to CreateInterface
"Ifname", "s", iface, // "s" variant parameter contains string, then pass the value
"Driver", "s", "nl80211");
if (res < 0) {
fprintf(stderr, "(create) error response: %s\n", error.message);
return NULL;
}
const char* iface_path;
res = sd_bus_message_read_basic(reply, SD_BUS_TYPE_OBJECT_PATH, &iface_path);
if (res < 0) {
print_error("createIface: ", res);
}
return iface_path;
}
int main() {
int res;
const char* iface_path;
//open connection to system bus - default either opens or reuses existing connection as necessary
res = sd_bus_default_system(&system_bus);
if (res < 0) {
print_error("open: ", res);
}
//associate connection with event loop, again default either creates or reuses existing
res = sd_event_default(&loop);
if (res < 0) {
print_error("event: ", res);
}
// get obj. path to the wireless interface on dbus so you can call methods on it
// this is a wireless interface (e.g. your wifi dongle) NOT the dbus interface
// if you don't know the interface name in advance, you will have to read the Interfaces property of
// wpa_supplicants root interface — call Get method on org.freedesktop.DBus properties interface,
// while some libraries expose some kind of get_property convenience function sd-bus does not
const char* ifaceName = "wlp32s0f3u2";
if (!(iface_path = get_interface(ifaceName))) { //substitute your wireless iface here
// sometimes the HW is present and listed in "ip l" but dbus does not reflect that, this fixes it
if (!(iface_path = create_interface(ifaceName))) {
fprintf(stderr, "can't create iface: %s" , ifaceName);
cleanup();
return EXIT_FAILURE;
}
}
/*
call methods with obj. path iface_path and dbus interface of your choice
this will likely be "fi.w1.wpa_supplicant1.Interface", register for signals etc...
you will need the following to receive those signals
*/
int runForUsec = 1000000; //usec, not msec!
sd_event_run(loop, runForUsec); //or sd_event_loop(loop) if you want to loop forever
cleanup();
printf("Finished OK\n");
return 0;
}
Прошу прощения, если приведенный выше пример не работает идеально. Это отрывок из старого проекта, который я переписал на C с C ++ (я думаю, что это C (-ish), компилятор не протестует, а вы спросили C), но я не могу проверить его, так как все мои ключи отказываются работать с моим рабочий стол прямо сейчас. Это должно дать вам общее представление.
Обратите внимание, что вы, вероятно, столкнетесь с несколькими магическими или полумагическими проблемами.
Для обеспечения бесперебойной разработки / тестирования сделайте следующее:
- убедитесь, что другие приложения управления сетью отключены (networkmanager, connman ...)
- перезапустить службу wpa_supplicant
- убедитесь, что беспроводной интерфейс включен в
ip link
Кроме того, потому что сейчас это не очень хорошо документировано:
Вы можете получить доступ к массивам и значениям внутренних вариантов с помощью sd_bus_message_enter_container
и _выходить коллегу. sd_bus_message_peek_type
может пригодиться при этом.
Или sd_bus_message_read_array
для однородного массива.