Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/using-sdbus-c++.md
Original file line number Diff line number Diff line change
Expand Up @@ -611,10 +611,10 @@ We recommend that sdbus-c++ users prefer the convenience API to the lower level,

> **_Note_:** By default, signal callback handlers are not invoked (i.e., the signal is silently dropped) if there is a signal signature mismatch. If you want to be informed of such situations, you can add `std::optional<sdbus::Error>` parameter to the beginning of your signal callback handler's parameter list. When sdbus-c++ invokes the handler, it will set this argument either to be empty (in normal cases), or to carry a corresponding `sdbus::Error` object (in case of deserialization failures, like type mismatches). An example of a handler with the signature (`int`) different from the real signal contents (`string`):
> ```c++
> void onConcatenated(std::optional<sdbus::Error> e, int wrongParameter)
> void onConcatenated(std::optional<sdbus::Error> err, int wrongParameter)
> {
> assert(e.has_value());
> assert(e->getMessage() == "Failed to deserialize a int32 value");
> assert(err.has_value());
> assert(err->getMessage() == "Failed to deserialize a int32 value");
> }
> ```
> Signature mismatch in signal handlers is probably the most common reason why signals are not received in the client, while we can see them on the bus with `dbus-monitor`. Use `std::optional<sdbus::Error>`-based callback variant and inspect the error to check if that's the cause of your problems.
Expand Down
10 changes: 5 additions & 5 deletions include/sdbus-c++/ConvenienceApiClasses.inl
Original file line number Diff line number Diff line change
Expand Up @@ -317,11 +317,11 @@ namespace sdbus {
{
reply >> args;
}
catch (const Error& e)
catch (const Error& err)
{
// Pass message deserialization exceptions to the client via callback error parameter,
// instead of propagating them up the message loop call stack.
sdbus::apply(callback, e, args);
sdbus::apply(callback, err, args);
return;
}
}
Expand Down Expand Up @@ -453,16 +453,16 @@ namespace sdbus {
{
signal >> signalArgs;
}
catch (const Error& e)
catch (const Error& err)
{
// Pass message deserialization exceptions to the client via callback error parameter,
// instead of propagating them up the message loop call stack.
sdbus::apply(callback, e, signalArgs);
sdbus::apply(callback, err, signalArgs);
return;
}

// Invoke callback with no error and input arguments from the tuple.
sdbus::apply(callback, {}, signalArgs);
sdbus::apply(callback, std::nullopt, signalArgs);
}
else
{
Expand Down
8 changes: 8 additions & 0 deletions tests/integrationtests/DBusSignalsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,14 @@ TYPED_TEST(SdbusTestObject, EmitsSignalWithoutRegistrationSuccessfully)
ASSERT_THAT(this->m_proxy->m_signatureFromSignal["platform"], Eq(sdbus::Signature{"av"}));
}

TYPED_TEST(SdbusTestObject, EmitsSignalWithErrorAndTypeMismatchSuccessfully)
{
this->m_adaptor->emitSignalWithErrorAndTypeMismatch();

ASSERT_TRUE(waitUntil(this->m_proxy->m_gotSignalWithTypeMismatch));
ASSERT_TRUE(this->m_proxy->m_errorFromSignal.has_value());
}

TYPED_TEST(SdbusTestObject, CanAccessAssociatedSignalMessageInSignalHandler)
{
this->m_adaptor->emitSimpleSignal();
Expand Down
5 changes: 5 additions & 0 deletions tests/integrationtests/TestAdaptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,11 @@ void TestAdaptor::emitSignalWithoutRegistration(const sdbus::Struct<std::string,
getObject().emitSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).withArguments(strct);
}

void TestAdaptor::emitSignalWithErrorAndTypeMismatch()
{
getObject().emitSignal("signalWithErrorAndTypeMismatch").onInterface(sdbus::test::INTERFACE_NAME);
}

std::string TestAdaptor::getExpectedXmlApiDescription()
{
return
Expand Down
1 change: 1 addition & 0 deletions tests/integrationtests/TestAdaptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ class TestAdaptor final : public sdbus::AdaptorInterfaces< org::sdbuscpp::integr

public:
void emitSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& strct);
void emitSignalWithErrorAndTypeMismatch();
static std::string getExpectedXmlApiDescription() ;

private:
Expand Down
8 changes: 8 additions & 0 deletions tests/integrationtests/TestProxy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ TestProxy::TestProxy(ServiceName destination, ObjectPath objectPath)
: ProxyInterfaces(std::move(destination), std::move(objectPath))
{
getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& strct){ this->onSignalWithoutRegistration(strct); });
getProxy().uponSignal("signalWithErrorAndTypeMismatch").onInterface(sdbus::test::INTERFACE_NAME).call([this](std::optional<sdbus::Error> err, int wrongParameter){ this->onSignalWithErrorAndTypeMismatch(std::move(err), wrongParameter); });

registerProxy();
}
Expand All @@ -60,6 +61,7 @@ TestProxy::TestProxy(sdbus::IConnection& connection, ServiceName destination, Ob
: ProxyInterfaces(connection, std::move(destination), std::move(objectPath))
{
getProxy().uponSignal("signalWithoutRegistration").onInterface(sdbus::test::INTERFACE_NAME).call([this](const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& strct){ this->onSignalWithoutRegistration(strct); });
getProxy().uponSignal("signalWithErrorAndTypeMismatch").onInterface(sdbus::test::INTERFACE_NAME).call([this](std::optional<sdbus::Error> err, int wrongParameter){ this->onSignalWithErrorAndTypeMismatch(std::move(err), wrongParameter); });

registerProxy();
}
Expand Down Expand Up @@ -96,6 +98,12 @@ void TestProxy::onSignalWithoutRegistration(const sdbus::Struct<std::string, sdb
m_gotSignalWithSignature = true;
}

void TestProxy::onSignalWithErrorAndTypeMismatch(std::optional<sdbus::Error> err, [[maybe_unused]] int wrongParameter)
{
m_errorFromSignal = std::move(err);
m_gotSignalWithTypeMismatch = true;
}

void TestProxy::onDoOperationReply(uint32_t returnValue, std::optional<sdbus::Error> error) const
{
if (m_DoOperationClientSideAsyncReplyHandler)
Expand Down
3 changes: 3 additions & 0 deletions tests/integrationtests/TestProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ class TestProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::integratio
void onSignalWithVariant(const sdbus::Variant& aVariant) override;

void onSignalWithoutRegistration(const sdbus::Struct<std::string, sdbus::Struct<sdbus::Signature>>& strct);
void onSignalWithErrorAndTypeMismatch(std::optional<sdbus::Error> err, int wrongParameter);
void onDoOperationReply(uint32_t returnValue, std::optional<sdbus::Error> error) const;

// Signals of standard D-Bus interfaces
Expand Down Expand Up @@ -130,6 +131,8 @@ class TestProxy final : public sdbus::ProxyInterfaces< org::sdbuscpp::integratio
double m_variantFromSignal{};
std::atomic<bool> m_gotSignalWithSignature{false};
std::map<std::string, Signature> m_signatureFromSignal;
std::atomic<bool> m_gotSignalWithTypeMismatch{false};
std::optional<sdbus::Error> m_errorFromSignal;

std::function<void(uint32_t res, std::optional<sdbus::Error> err)> m_DoOperationClientSideAsyncReplyHandler;
std::function<void(const sdbus::InterfaceName&, const std::map<PropertyName, sdbus::Variant>&, const std::vector<PropertyName>&)> m_onPropertiesChangedHandler;
Expand Down
Loading