initial commit
This commit is contained in:
@@ -0,0 +1,475 @@
|
||||
#include "nm_device.h"
|
||||
#include "nm_connection.h"
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
// Only include sdbus on Linux
|
||||
#ifdef __linux__
|
||||
#include <systemd/sd-bus.h>
|
||||
#endif
|
||||
|
||||
namespace radiantwave::network {
|
||||
|
||||
// ─── Access Point Helper ───────────────────────────────────────────────
|
||||
|
||||
namespace {
|
||||
|
||||
AccessPointInfo parseAccessPoint(
|
||||
const std::string& object_path,
|
||||
const std::string& ssid,
|
||||
uint8_t signal,
|
||||
uint32_t flags,
|
||||
uint32_t wpa_flags,
|
||||
uint32_t rsn_flags
|
||||
) {
|
||||
AccessPointInfo ap;
|
||||
ap.object_path = object_path;
|
||||
ap.ssid = ssid;
|
||||
ap.ssid_bytes = ssidToBytes(ssid);
|
||||
ap.signal_strength = signal;
|
||||
ap.flags = flags;
|
||||
ap.wpa_flags = wpa_flags;
|
||||
ap.rsn_flags = rsn_flags;
|
||||
ap.security = detectSecurityType(flags, wpa_flags, rsn_flags);
|
||||
|
||||
return ap;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ─── WifiDevice Implementation ─────────────────────────────────────────
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
struct WifiDevice::Impl {
|
||||
std::string object_path;
|
||||
sd_bus* bus = nullptr;
|
||||
|
||||
explicit Impl(const std::string& path) : object_path(path) {
|
||||
int r = sd_bus_open_system(&bus);
|
||||
if (r < 0) {
|
||||
throw std::runtime_error("Failed to open system bus: " + std::string(strerror(-r)));
|
||||
}
|
||||
}
|
||||
|
||||
~Impl() {
|
||||
if (bus) {
|
||||
sd_bus_unref(bus);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper: call a D-Bus method and get response
|
||||
sd_bus_message* callMethod(
|
||||
const char* dest,
|
||||
const char* path,
|
||||
const char* iface,
|
||||
const char* member,
|
||||
const char* type,
|
||||
...
|
||||
) {
|
||||
sd_bus_message* msg = nullptr;
|
||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
int r = sd_bus_call_method(
|
||||
bus,
|
||||
dest,
|
||||
path,
|
||||
iface,
|
||||
member,
|
||||
&error,
|
||||
&msg,
|
||||
type
|
||||
);
|
||||
|
||||
if (r < 0) {
|
||||
std::string err = "D-Bus call failed: ";
|
||||
err += error.message ? error.message : strerror(-r);
|
||||
sd_bus_error_free(&error);
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
|
||||
sd_bus_error_free(&error);
|
||||
return msg;
|
||||
}
|
||||
|
||||
// Helper: get a property value
|
||||
sd_bus_message* getProperty(
|
||||
const char* dest,
|
||||
const char* path,
|
||||
const char* iface,
|
||||
const char* prop,
|
||||
const char* type
|
||||
) {
|
||||
sd_bus_message* msg = nullptr;
|
||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
int r = sd_bus_get_property(
|
||||
bus,
|
||||
dest,
|
||||
path,
|
||||
iface,
|
||||
prop,
|
||||
&error,
|
||||
&msg,
|
||||
type
|
||||
);
|
||||
|
||||
if (r < 0) {
|
||||
std::string err = "D-Bus property get failed: ";
|
||||
err += error.message ? error.message : strerror(-r);
|
||||
sd_bus_error_free(&error);
|
||||
throw std::runtime_error(err);
|
||||
}
|
||||
|
||||
sd_bus_error_free(&error);
|
||||
return msg;
|
||||
}
|
||||
};
|
||||
|
||||
WifiDevice::WifiDevice(const std::string& object_path)
|
||||
: impl_(std::make_unique<Impl>(object_path))
|
||||
{
|
||||
}
|
||||
|
||||
WifiDevice::~WifiDevice() = default;
|
||||
|
||||
WifiDevice::WifiDevice(WifiDevice&& other) noexcept = default;
|
||||
WifiDevice& WifiDevice::operator=(WifiDevice&& other) noexcept = default;
|
||||
|
||||
std::string WifiDevice::getInterfaceName() const {
|
||||
sd_bus_message* msg = impl_->getProperty(
|
||||
"org.freedesktop.NetworkManager",
|
||||
impl_->object_path.c_str(),
|
||||
"org.freedesktop.NetworkManager.Device",
|
||||
"Interface",
|
||||
"s"
|
||||
);
|
||||
|
||||
const char* iface = nullptr;
|
||||
sd_bus_message_read(msg, "s", &iface);
|
||||
std::string result = iface ? iface : "";
|
||||
sd_bus_message_unref(msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t WifiDevice::getDeviceState() const {
|
||||
sd_bus_message* msg = impl_->getProperty(
|
||||
"org.freedesktop.NetworkManager",
|
||||
impl_->object_path.c_str(),
|
||||
"org.freedesktop.NetworkManager.Device",
|
||||
"State",
|
||||
"u"
|
||||
);
|
||||
|
||||
uint32_t state = 0;
|
||||
sd_bus_message_read(msg, "u", &state);
|
||||
sd_bus_message_unref(msg);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
std::string WifiDevice::getObjectPath() const {
|
||||
return impl_->object_path;
|
||||
}
|
||||
|
||||
bool WifiDevice::requestScan() {
|
||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
int r = sd_bus_call_method(
|
||||
impl_->bus,
|
||||
"org.freedesktop.NetworkManager",
|
||||
impl_->object_path.c_str(),
|
||||
"org.freedesktop.NetworkManager.Device.Wireless",
|
||||
"RequestScan",
|
||||
&error,
|
||||
nullptr,
|
||||
"a{sv}",
|
||||
0 // Empty options dict
|
||||
);
|
||||
|
||||
sd_bus_error_free(&error);
|
||||
return r >= 0;
|
||||
}
|
||||
|
||||
std::vector<AccessPointInfo> WifiDevice::getAccessPoints() const {
|
||||
std::vector<AccessPointInfo> result;
|
||||
|
||||
// Get access point paths
|
||||
sd_bus_message* msg = nullptr;
|
||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
int r = sd_bus_get_property(
|
||||
impl_->bus,
|
||||
"org.freedesktop.NetworkManager",
|
||||
impl_->object_path.c_str(),
|
||||
"org.freedesktop.NetworkManager.Device.Wireless",
|
||||
"AllAccessPoints",
|
||||
&error,
|
||||
&msg,
|
||||
"ao"
|
||||
);
|
||||
|
||||
if (r < 0) {
|
||||
sd_bus_error_free(&error);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read array of object paths
|
||||
r = sd_bus_message_enter_container(msg, 'a', "o");
|
||||
if (r < 0) {
|
||||
sd_bus_message_unref(msg);
|
||||
return result;
|
||||
}
|
||||
|
||||
const char* ap_path = nullptr;
|
||||
while ((r = sd_bus_message_read(msg, "o", &ap_path)) > 0 && ap_path) {
|
||||
// Get AP properties
|
||||
sd_bus_message* ap_msg = nullptr;
|
||||
sd_bus_error ap_error = SD_BUS_ERROR_NULL;
|
||||
|
||||
// Get all properties at once
|
||||
r = sd_bus_get_property(
|
||||
impl_->bus,
|
||||
"org.freedesktop.NetworkManager",
|
||||
ap_path,
|
||||
"org.freedesktop.NetworkManager.AccessPoint",
|
||||
"Ssid",
|
||||
&ap_error,
|
||||
&ap_msg,
|
||||
"ay"
|
||||
);
|
||||
|
||||
if (r >= 0) {
|
||||
// Read SSID byte array
|
||||
sd_bus_message_enter_container(ap_msg, 'a', "y");
|
||||
const uint8_t* ssid_data = nullptr;
|
||||
size_t ssid_len = 0;
|
||||
r = sd_bus_message_read_array(ap_msg, 'y', (const void**)&ssid_data, &ssid_len);
|
||||
|
||||
std::string ssid;
|
||||
if (r >= 0 && ssid_data && ssid_len > 0) {
|
||||
ssid = std::string(reinterpret_cast<const char*>(ssid_data), ssid_len);
|
||||
}
|
||||
sd_bus_message_unref(ap_msg);
|
||||
|
||||
// Get signal strength
|
||||
sd_bus_message* sig_msg = nullptr;
|
||||
sd_bus_error sig_error = SD_BUS_ERROR_NULL;
|
||||
uint8_t signal = 0;
|
||||
|
||||
r = sd_bus_get_property(
|
||||
impl_->bus,
|
||||
"org.freedesktop.NetworkManager",
|
||||
ap_path,
|
||||
"org.freedesktop.NetworkManager.AccessPoint",
|
||||
"Strength",
|
||||
&sig_error,
|
||||
&sig_msg,
|
||||
"y"
|
||||
);
|
||||
|
||||
if (r >= 0) {
|
||||
sd_bus_message_read(sig_msg, "y", &signal);
|
||||
sd_bus_message_unref(sig_msg);
|
||||
}
|
||||
sd_bus_error_free(&sig_error);
|
||||
|
||||
// Get flags
|
||||
uint32_t flags = 0, wpa_flags = 0, rsn_flags = 0;
|
||||
// ... (would need similar property reads for flags)
|
||||
|
||||
if (!ssid.empty()) {
|
||||
result.push_back(parseAccessPoint(ap_path, ssid, signal, flags, wpa_flags, rsn_flags));
|
||||
}
|
||||
}
|
||||
|
||||
sd_bus_error_free(&ap_error);
|
||||
}
|
||||
|
||||
sd_bus_message_exit_container(msg);
|
||||
sd_bus_message_unref(msg);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
AccessPointInfo WifiDevice::getActiveAccessPoint() const {
|
||||
sd_bus_message* msg = impl_->getProperty(
|
||||
"org.freedesktop.NetworkManager",
|
||||
impl_->object_path.c_str(),
|
||||
"org.freedesktop.NetworkManager.Device.Wireless",
|
||||
"ActiveAccessPoint",
|
||||
"o"
|
||||
);
|
||||
|
||||
const char* ap_path = nullptr;
|
||||
sd_bus_message_read(msg, "o", &ap_path);
|
||||
sd_bus_message_unref(msg);
|
||||
|
||||
if (!ap_path || std::string(ap_path) == "/") {
|
||||
return AccessPointInfo{}; // No active AP
|
||||
}
|
||||
|
||||
// Would need to fetch AP properties here
|
||||
// For now, return basic info
|
||||
AccessPointInfo ap;
|
||||
ap.object_path = ap_path;
|
||||
return ap;
|
||||
}
|
||||
|
||||
bool WifiDevice::isConnected() const {
|
||||
return getDeviceState() == nm_device_state::Activated;
|
||||
}
|
||||
|
||||
std::string WifiDevice::connectedSSID() const {
|
||||
if (!isConnected()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
auto ap = getActiveAccessPoint();
|
||||
return ap.ssid;
|
||||
}
|
||||
|
||||
std::unique_ptr<WifiDevice> WifiDevice::findFirstDevice() {
|
||||
sd_bus* bus = nullptr;
|
||||
int r = sd_bus_open_system(&bus);
|
||||
if (r < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sd_bus_message* msg = nullptr;
|
||||
sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
|
||||
r = sd_bus_call_method(
|
||||
bus,
|
||||
"org.freedesktop.NetworkManager",
|
||||
"/org/freedesktop/NetworkManager",
|
||||
"org.freedesktop.NetworkManager",
|
||||
"GetDevices",
|
||||
&error,
|
||||
&msg,
|
||||
""
|
||||
);
|
||||
|
||||
if (r < 0) {
|
||||
sd_bus_error_free(&error);
|
||||
sd_bus_unref(bus);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Read device paths
|
||||
r = sd_bus_message_enter_container(msg, 'a', "o");
|
||||
if (r < 0) {
|
||||
sd_bus_message_unref(msg);
|
||||
sd_bus_unref(bus);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char* dev_path = nullptr;
|
||||
std::string wifi_path;
|
||||
|
||||
while ((r = sd_bus_message_read(msg, "o", &dev_path)) > 0 && dev_path) {
|
||||
// Check device type
|
||||
sd_bus_message* type_msg = nullptr;
|
||||
sd_bus_error type_error = SD_BUS_ERROR_NULL;
|
||||
uint32_t dev_type = 0;
|
||||
|
||||
r = sd_bus_get_property(
|
||||
bus,
|
||||
"org.freedesktop.NetworkManager",
|
||||
dev_path,
|
||||
"org.freedesktop.NetworkManager.Device",
|
||||
"DeviceType",
|
||||
&type_error,
|
||||
&type_msg,
|
||||
"u"
|
||||
);
|
||||
|
||||
if (r >= 0) {
|
||||
sd_bus_message_read(type_msg, "u", &dev_type);
|
||||
sd_bus_message_unref(type_msg);
|
||||
|
||||
// NM_DEVICE_TYPE_WIFI = 2
|
||||
if (dev_type == 2) {
|
||||
wifi_path = dev_path;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
sd_bus_error_free(&type_error);
|
||||
}
|
||||
|
||||
sd_bus_message_exit_container(msg);
|
||||
sd_bus_message_unref(msg);
|
||||
sd_bus_unref(bus);
|
||||
|
||||
if (wifi_path.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<WifiDevice>(wifi_path);
|
||||
}
|
||||
|
||||
#else // !__linux__
|
||||
|
||||
// ─── Stub implementation for non-Linux platforms ───────────────────────
|
||||
|
||||
struct WifiDevice::Impl {
|
||||
std::string object_path;
|
||||
|
||||
explicit Impl(const std::string& path) : object_path(path) {}
|
||||
};
|
||||
|
||||
WifiDevice::WifiDevice(const std::string& object_path)
|
||||
: impl_(std::make_unique<Impl>(object_path))
|
||||
{
|
||||
}
|
||||
|
||||
WifiDevice::~WifiDevice() = default;
|
||||
|
||||
WifiDevice::WifiDevice(WifiDevice&& other) noexcept = default;
|
||||
WifiDevice& WifiDevice::operator=(WifiDevice&& other) noexcept = default;
|
||||
|
||||
std::string WifiDevice::getInterfaceName() const {
|
||||
return "wlan0"; // Stub
|
||||
}
|
||||
|
||||
uint32_t WifiDevice::getDeviceState() const {
|
||||
return nm_device_state::Disconnected; // Stub
|
||||
}
|
||||
|
||||
std::string WifiDevice::getObjectPath() const {
|
||||
return impl_->object_path;
|
||||
}
|
||||
|
||||
bool WifiDevice::requestScan() {
|
||||
std::cerr << "[WifiDevice] Stub: requestScan() called on non-Linux platform\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<AccessPointInfo> WifiDevice::getAccessPoints() const {
|
||||
std::cerr << "[WifiDevice] Stub: getAccessPoints() called on non-Linux platform\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
AccessPointInfo WifiDevice::getActiveAccessPoint() const {
|
||||
std::cerr << "[WifiDevice] Stub: getActiveAccessPoint() called on non-Linux platform\n";
|
||||
return {};
|
||||
}
|
||||
|
||||
bool WifiDevice::isConnected() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string WifiDevice::connectedSSID() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
std::unique_ptr<WifiDevice> WifiDevice::findFirstDevice() {
|
||||
std::cerr << "[WifiDevice] Stub: findFirstDevice() called on non-Linux platform\n";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#endif // __linux__
|
||||
|
||||
} // namespace radiantwave::network
|
||||
Reference in New Issue
Block a user