Qt DBUS NetworkManager get Address from IP4Config interface

626 views Asked by At

I have been using QtDBus and NetworkManager for a while but have run into a problem. I need to access the Wi-Fi devices IP address and the way to obtain it is to get the Wi-Fi device object, get its IP4Config property (a QDbusObjectPath object) and then to get the AddressData. The problem is that as soon as I try to obtain the AddressData using the interfaces property method, my application crashes.

I believe I need to register a meta type (I have done this for other types) but can't seem to figure out how to unpack the aa{sv} data returned from the property. Using qdbusviewer I can see the data for the IP address.

How can I get this information from the property?

Here is a snippet of the code which is encountering the problem. It seems I can get the QString property of Gateway but as soon as I try to get the AddressData my process crashes (as shown below).

    cout << wifi_args.size() << endl;
    cout << wifi_args[0].path().toStdString() << endl;
    if (wifi_args.size() > 0) {

        QDBusInterface wifi_device(NM_DBUS_SERVICE, wifi_args[0].path(),
                                   NM_DBUS_INTERFACE_DEVICE,
                                   QDBusConnection::systemBus());

        const auto wifiInterface = wifi_device.property("Interface").toString();
        // auto wifiIPv4 = wifi_device.property("Ip4Address").toInt();
        auto ip4_config_path =
            qdbus_cast<QDBusObjectPath>(wifi_device.property("Ip4Config"));

        cout << "config path = " << ip4_config_path.path().toStdString()
             << endl;

        QDBusInterface wifi_ip4_if(NM_DBUS_SERVICE, ip4_config_path.path(),
                                   NM_DBUS_INTERFACE_IP4_CONFIG,
                                   QDBusConnection::systemBus());

        auto gateway = wifi_ip4_if.property("Gateway").toString();
        auto ipv4 = wifi_ip4_if.property("AddressData");

        // for (auto item : wifiIPv4) {
        //     cout << "Item";
        // }

        cout << "Interface = " << wifiInterface.toStdString() << endl;
        cout << "Gateway   = " << gateway.toStdString() << endl;
        // cout << "Address   = " << int_to_ipv4(wifiIPv4) << endl;
    } else {
        cerr << "ERROR: Multiple wifi devices found!" << endl;
    }

Here is the output from the run:

michael_uman@ThinkPad-X1-Carbon-7th ~/gitroot/UXHUB-development (development)$ ./build-host/app/kylixctl/kylixctl list wifi
1
/org/freedesktop/NetworkManager/Devices/3
config path = /org/freedesktop/NetworkManager/IP4Config/8
Cannot construct placeholder type QDBusRawType
Aborted (core dumped)
1

There are 1 answers

0
David Lockhart On

You can safely get the property in question by using org.freedesktop.DBus.Properties.Get and then manually demarshall the response, similar to Fatal error when trying to get a DBus property with custom type

// Required operator for demarshalling aa{sv} signature
const QDBusArgument &operator>>(const QDBusArgument &argument, QList<QVariantMap> &varMapList)
{
    argument.beginArray();
    varMapList.clear();

    while(!argument.atEnd()) {
        QVariantMap map;
        argument >> map;
        varMapList.append(map);
    }

    argument.endArray();
    return argument;
}
// Use generic property interface.
QDBusInterface getter(NM_DBUS_SERVICE, wifi_args[0].path(), "org.freedesktop.DBus.Properties", QDBusConnection::systemBus());
// Use the Get function to manually access the AddressData property.
auto reply = getter.call("Get", NM_DBUS_INTERFACE_IP4_CONFIG, "AddressData");
// Extract the needed argument from the reply.
auto arg = reply.arguments().first();
// Demarshall the argument into Qt's aa{sv} equivalent.
QList<QVariantMap> list;
arg.value<QDBusVariant>().variant().value<QDBusArgument>() >> list;
// Access the address data.
cout << "Address   = " << list.first()["address"].toString().toStdString();

This should be sufficient to get the required data without crashing Qt.