staging.inyokaproject.org

[C++] DBUS output ''a(oa{sv})'' entschlüsseln

Status: Gelöst | Ubuntu-Version: Kein Ubuntu
Antworten |

ChickenLipsRfun2eat Team-Icon

Supporter
Avatar von ChickenLipsRfun2eat

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12070

Hallo zusammen!

Ich verzweifle nun schon seit Stunden daran Informationen vom DBUS mundgerecht zu servieren. Hintergrund ist in meinem Fall connman, es geht aber generell um das Vorgehen die DBUS-Methoden zu entschlüsseln.

Um das ganze nicht mit massiv langen Codeblöcken zuzuspammen, versuche ich mal das relevante zusammenzufassen:

  • Introspect des DBUS und das automatische Klassen genererieren mit bspw. qdbusxml2cpp funktioniert so nicht, da die Methoden zu komplex sind (oder ich zu doof das xml aufzubereiten, was wahrscheinlicher ist^^).

  • Die Quelle List of DBus data types entschlüsselt den obigen Aufbau als

    array(
      struct(
        objectPath,
        array(
          dict{string,variant}
        )
      )
    )
  • eine funktionierende Lösung findet sich unter wifi-runner (Python), die ich aber mangels Kenntnisse nicht verstehe, bzw. auf C++ ummünzen kann. (siehe filter mit lambda)

Meine bisherigen Versuche mit diversen Ansätzen, wie bspw:

  • Vector< Pair< DBusObjectPath, Vector< Map< String,Variant > > > >

  • struct { DBusObjectPath, Map<String,Variant> }; innerhalb eines Vector,

  • etc.

sind kläglich gescheitert. Die Fehler-Meldung lautet stets:

Unexpected reply signature: got \"a(oa{sv})\", expected \"\" (MeinVersuchHier)

Nun hoffe ich, einer von euch kann mir sagen, wie ich das Denken muss, um zu einem Ziel zu kommen. Das reine a{sv} lässt sich übrigens mit Map<String, Variant> abbilden. Ein paar Beispielausgaben mit funktionierendem Connman vom Sailfish OS-Device:

Beispiel für a{sv}:

[Argument: a{sv} {
"Name" = [Variant(QString): "WiFi"], 
"Type" = [Variant(QString): "wifi"], 
"Powered" = [Variant(bool): true], 
"Connected" = [Variant(bool): true], 
"Tethering" = [Variant(bool): false], 
"TetheringIdentifier" = [Variant(QString): "Shared"], 
"TetheringPassphrase" = [Variant(QString): "HierStehtEinPasswort"]}]

Beispiel für a(oa{sv}) (Auszug):

[Argument: 
    a(oa{sv}) 
        {
        [Argument: (oa{sv}) 
            [ObjectPath: /net/connman/service/wifi_5056a8016f7e_5363686967676e4f6e416972_managed_psk],
        [Argument: a{sv} 
        {
        "Type" = [Variant(QString): "wifi"],
        "Security" = [Variant(QStringList): {"psk", "wps"}],
        "State" = [Variant(QString): "online"],
        "Strength" = [Variant(uchar): 46],
        "Favorite" = [Variant(bool): true],
        "Immutable" = [Variant(bool): false],
        "AutoConnect" = [Variant(bool): true],
        "Name" = [Variant(QString): "MyHomeWireless"],
        "BSSID" = [Variant(QString): "00:11:55:44:33:cc"],
        "MaxRate" = [Variant(uint): 54000000],
        "Frequency" = [Variant(ushort): 2427],
        "EncryptionMode" = [Variant(QString): "aes"],
        "Ethernet" = [Variant: [Argument: a{sv} {"Method" = [Variant(QString): "auto"], "Interface" = [Variant(QString): "wlan0"], "Address" = [Variant(QString): "00:11:55:44:33:dd"], "MTU" = [Variant(ushort): 1500]}]],
        "Hidden" = [Variant(bool): false],
        "IPv4" = [Variant: [Argument: a{sv} {"Method" = [Variant(QString): "manual"], "Address" = [Variant(QString): "192.168.1.40"], "Netmask" = [Variant(QString): "255.255.255.0"], "Gateway" = [Variant(QString): "192.168.1.1"]}]],
        "IPv4.Configuration" = [Variant: [Argument: a{sv} {"Method" = [Variant(QString): "manual"],
        "Address" = [Variant(QString): "192.168.1.40"],
        "Netmask" = [Variant(QString): "255.255.255.0"],
        "Gateway" = [Variant(QString): "192.168.1.1"]}]],
        "IPv6" = [Variant: [Argument: a{sv} {"Method" = [Variant(QString): "auto"], "Address" = [Variant(QString): "1234:5678:910a:bcde:fghi:jklm:nopq:rstu"], "PrefixLength" = [Variant(uchar): 64], "Privacy" = [Variant(QString): "disabled"]}]],
        "IPv6.Configuration" = [Variant: [Argument: a{sv} {"Method" = [Variant(QString): "auto"], "Privacy" = [Variant(QString): "disabled"]}]], "Nameservers" = [Variant(QStringList): {"127.0.0.1", "192.168.1.1"}],
        "Nameservers.Configuration" = [Variant(QStringList): {"127.0.0.1", "192.168.16.1"}], 
        "Timeservers" = [Variant(QStringList): {"0.pool.ntp.org", "1.pool.ntp.org", "2.pool.ntp.org", "3.pool.ntp.org"}],
        "Timeservers.Configuration" = [Variant(QStringList): {}],
        "Domains" = [Variant(QStringList): {}],
        "Domains.Configuration" = [Variant(QStringList): {}],
        "Proxy" = [Variant: [Argument: a{sv} {"Method" = [Variant(QString): "direct"]}]],
        "Proxy.Configuration" = [Variant: [Argument: a{sv} {}]],
        "Provider" = [Variant: [Argument: a{sv} {}]],
        "Available" = [Variant(bool): true],
        "Saved" = [Variant(bool): true],
        "Access" = [Variant(QString): ""], 
        "DefaultAccess" = [Variant(QString): "sailfish:1;ClearProperty(*)|Connect()|Disconnect()|Remove()|ResetCounters()=deny;group(privileged)=allow"]
        }
        ]
        ],
        [Argument: (oa{sv}) [ObjectPath: /net/connman/service/cellular_262017400417810_context1], [Argument: a{sv} {"Type" = [Variant(QString): "cellular"], "Security" = [Variant(QStringList): {}], "State" = [Variant(QString): "ready"], "Strength" = [Variant(uchar): 45], "Favorite" = [Variant(bool): true], "Immutable" = [Variant(bool): false], "AutoConnect" = [Variant(bool): true], "Name" = [Variant(QString): "Anbieter.de"], "Roaming" = [Variant(bool): false], "Ethernet" = [Variant: [Argument: a{sv} {"Method" = [Variant(QString): "auto"], "Interface" = [Variant(QString): "rmnet0"], "Address" = [Variant(QString): "AB:CD:EF:11:22:33"], "MTU" = [Variant(ushort): 1280]}]], "IPv4" = [Variant: [Argument: a{sv} {"Method" = [Variant(QString): "fixed"], "Address" = [Variant(QString): "12.34.45.789"], "Netmask" = [Variant(QString): "255.0.0.0"], "Gateway" = [Variant(QString): "37.84.96.197"]}]], "IPv4.Configuration" = [Variant: [Argument: a{sv} {"Method" = [Variant(QString): "fixed"], "Address" = [Variant(QString): "12.34.45.789"], "Netmask" = [Variant(QString): "255.0.0.0"], "Gateway" = [Variant(QString): "37.84.96.197"]}]], "IPv6" = [Variant: [Argument: a{sv} {}]], "IPv6.Configuration" = [Variant: [Argument: a{sv} {"Method" = [Variant(QString): "auto"], "Privacy" = [Variant(QString): "disabled"]}]], "Nameservers" = [Variant(QStringList): {"12.34.45.700", "12.34.45.800"}], "Nameservers.Configuration" = [Variant(QStringList): {}], "Timeservers" = [Variant(QStringList): {"0.pool.ntp.org", "1.pool.ntp.org", "2.pool.ntp.org", "3.pool.ntp.org"}], "Timeservers.Configuration" = [Variant(QStringList): {}], "Domains" = [Variant(QStringList): {}], "Domains.Configuration" = [Variant(QStringList): {}], "Proxy" = [Variant: [Argument: a{sv} {"Method" = [Variant(QString): "direct"]}]], "Proxy.Configuration" = [Variant: [Argument: a{sv} {}]], "Provider" = [Variant: [Argument: a{sv} {}]], "Available" = [Variant(bool): true], "Saved" = [Variant(bool): true], "Access" = [Variant(QString): ""], "DefaultAccess" = [Variant(QString): "sailfish:1;ClearProperty(*)|Connect()|Disconnect()|Remove()|ResetCounters()=deny;group(privileged)=allow"]}]],
…

Ich versuche natürlich das ganze in Qt umzusetzen, aber die Implementierung ist gerade zweitrangig. Ich möchte in erster Linie wissen, was ich da falsch verstehe oder wo meine Ansätze haken.

ChickenLipsRfun2eat Team-Icon

Supporter
(Themenstarter)
Avatar von ChickenLipsRfun2eat

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12070

Ein Minimalbeispiel für den funktionierenden Teil:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <QCoreApplication>
#include <QtDBus>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    if (!QDBusConnection::sessionBus().isConnected()) {
        qFatal("Cannot connect to the D-Bus session bus.");
      }
    //qdbus com.canonical.Unity /MainApplication org.qtproject.Qt.QCoreApplication.applicationName
    //here: plasmashell
    QDBusInterface dbus_iface("com.canonical.Unity", "/MainApplication", "org.freedesktop.DBus.Properties", QDBusConnection::sessionBus());
    QDBusReply<QVariantMap> reply = dbus_iface.callWithArgumentList(QDBus::AutoDetect,"GetAll", QVariantList() << "plasmashell");
    if(!reply.isValid())
        qDebug() << "Reply not valid. Reason:" << reply.error().message();

    QVariantMap map = reply.value();
    QVariantMap::Iterator i;
    for (i = map.begin(); i != map.end(); ++i)
      qDebug() << i.key() << ": " << i.value();

    exit(0);
    return a.exec();
}

.pro

QT -= gui
QT += dbus
CONFIG += c++11 console
CONFIG -= app_bundle
SOURCES += main.cpp

ChickenLipsRfun2eat Team-Icon

Supporter
(Themenstarter)
Avatar von ChickenLipsRfun2eat

Anmeldungsdatum:
6. Dezember 2009

Beiträge: 12070

Gelöst!

War ne schwere Geburt, aber letzten Endes hat es nicht die Logik geschafft, sondern die Debug-Ausgaben und die Annäherung^^

Für alle die, die über ein solches Problem stolpern, natürlich auch das obige Beispiel mit funktionierendem DBusReply.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <QCoreApplication>
#include <QtDBus>
#include <QDebug>

typedef QPair<QDBusObjectPath, QVariantMap> myPair;
typedef QList<myPair> ConnmanServices;
Q_DECLARE_METATYPE(myPair)
Q_DECLARE_METATYPE(ConnmanServices)

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    if (!QDBusConnection::systemBus().isConnected()) {
        qFatal("Cannot connect to the D-Bus system bus.");
      }

    QDBusInterface dbus_iface("net.connman", "/net/connman/technology/wifi", "net.connman.Technology", QDBusConnection::systemBus());
    QDBusReply<QVariantMap> reply = dbus_iface.call("GetProperties");
    if(!reply.isValid())
        qDebug() << "Reply not valid. Reason:" << reply.error().message();

    QVariantMap map = reply.value();
    QVariantMap::Iterator i;
    for (i = map.begin(); i != map.end(); ++i)
      qDebug() << i.key() << ": " << i.value();

/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
    qDBusRegisterMetaType<myPair>();
    qDBusRegisterMetaType<ConnmanServices>();

    QDBusInterface iface("net.connman", "/", "net.connman.Manager", QDBusConnection::systemBus());
    QList<QVariant> argumentList;
    QDBusReply<ConnmanServices> rep = iface.callWithArgumentList(QDBus::Block, QStringLiteral("GetServices"), argumentList);
    if(!rep.isValid())
      qDebug() << "Error:" << rep.error().message();

    //continue with data in ConnmanServices
    foreach(myPair mp, rep.value()) {
        qDebug() << "QDBusObjectPath" << mp.first.path();

        for (i = mp.second.begin(); i != mp.second.end(); ++i)
          qDebug() << i.key() << ": " << i.value();
      }
/*---------------------------------------------------------------------------------------------------------------------------------------------------*/
    exit(0);
    return a.exec();
}
Antworten |