martinhaefner / simppl

simppl::dbus - an easy-to-use C++ D-Bus wrapper
MIT License
68 stars 25 forks source link

Empty simppl::dbus::Any Broken #36

Closed COM8 closed 1 year ago

COM8 commented 1 year ago

Think of the following unit test:

// ...
Method<out<simppl::dbus::Any>> getVecEmpty;
Method<in<simppl::dbus::Any>, out<simppl::dbus::Any>> setGet;
// ...
setGet >> [this](const simppl::dbus::Any& a){
    respond_with(get(a));
};

getVecEmpty >> [this](){
    std::vector<std::string> vec;
    simppl::dbus::Any a(vec);
    respond_with(getVecEmpty(a));
 };
// ...

TEST(Any, empty)
{
    simppl::dbus::Dispatcher d("bus:session");

    std::thread t([](){
        simppl::dbus::Dispatcher d("bus:session");
        Server s(d);
        d.run();
    });

    simppl::dbus::Stub<test::any::AServer> stub(d, "role");

    // wait for server to get ready
    std::this_thread::sleep_for(200ms);

    simppl::dbus::Any a = stub.getVecEmpty();
    EXPECT_TRUE(a.is<std::vector<std::string>>());
    for (size_t i = 0; i < 10; i++)
    {
        a = stub.setGet(a);
        EXPECT_TRUE(a.is<std::vector<std::string>>());   
    }

    stub.stop();   // stop server
    t.join();
}

Then the code will fail in the following line:

https://github.com/martinhaefner/simppl/blob/f9ce6223cb8601150aa79d0a3081dfbb48aceac1/include/simppl/any.h#L141

The problem is the serialisation of an "empty" simppl::dbus::Any is not really defined.

martinhaefner commented 1 year ago

Hi, I have looked into the problem and found out, that the problem is in the fact that you try to send a received any once again via a D-Bus interface. The Any variable in this case does not store a pointer to the data, but just a pointer to the received D-Bus stream. That's why you end up in the given line of code resulting in the assertion since this is not a valid use-case (at least for now). You need to extract the any from the received object and create a new Any object like in the in_the_middle method implementation of the Any test. Maybe this could be changed by re-inserting the native D-Bus stream data from the previous call, but for now it is forbidden. Sorry for the missing documentation, I will at least fix this.

COM8 commented 1 year ago

Thanks for looking into this and making it clear!

My use case is, that I access settings from the network manager, where I get something like this as a response:

({
    "connection": {
        "id": <"WIFIonICE">,
        "interface-name": <"wlp2s0">,
        "permissions": <@as []>,
        "timestamp": <uint64 1692885673>,
        "type": <"802-11-wireless">,
        "uuid": <"b297b5b6-365f-4dff-a434-d6faf66124d0">
    },
    "802-11-wireless": {
        "mac-address-blacklist": <@as []>,
        "mode": <"infrastructure">,
        "seen-bssids": <[
            "00:0E:8E:6E:1E:88",
            "F8:A7:3A:22:11:A0",
            "04:F0:21:9E:69:6A",
            "F8:A7:3A:21:D4:00",
            "38:0E:4D:82:52:00"
        ]>,
        "ssid": <[byte 0x57,
            0x49,
            0x46,
            0x49,
            0x6f,
            0x6e,
            0x49,
            0x43,
            0x45
        ]>
    },
    "ipv4": {
        "address-data": <@aa{sv
        } []>,
        "addresses": <@aau []>,
        "dns-search": <@as []>,
        "method": <"auto">,
        "route-data": <@aa{sv
        } []>,
        "routes": <@aau []>
    },
    "ipv6": {
        "address-data": <@aa{sv
        } []>,
        "addresses": <@a(ayuay) []>,
        "dns-search": <@as []>,
        "method": <"auto">,
        "route-data": <@aa{sv
        } []>,
        "routes": <@a(ayuayu) []>
    },
    "proxy": {}
},)

In this case I get per definition a{sa{sv}}. Then I change some parameters and I want to write those settings back. This fails and I can not know what all types there exist.

I'm currently working on a fix for it.