Skip to content

Commit

Permalink
Implement user defined exception class with additional exception data
Browse files Browse the repository at this point in the history
  • Loading branch information
Martin Haefner committed Jul 28, 2021
1 parent a25f598 commit 54cb18e
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 23 deletions.
22 changes: 20 additions & 2 deletions include/simppl/detail/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
#include "simppl/types.h"
#include "simppl/string.h"

#include "util.h"

#include <cxxabi.h>


namespace simppl
{
Expand All @@ -16,14 +20,28 @@ namespace detail
{


// FIXME get rid of redefinion
struct FreeDeleter {
template<typename T>
void operator()(T* o) {
::free(o);
}
};


template<typename ExceptionT>
struct ErrorFactory
{
/// server side
static
message_ptr_t reply(DBusMessage& msg, const Error& e)
{
message_ptr_t rmsg = e.make_reply_for(msg);
std::unique_ptr<char, FreeDeleter> name;

if (!e.name())
name.reset(make_error_name(abi::__cxa_demangle(typeid(ExceptionT).name(), nullptr, 0, nullptr)));

message_ptr_t rmsg = e.make_reply_for(msg, name.get());

// encode arguments
DBusMessageIter iter;
Expand Down Expand Up @@ -51,7 +69,7 @@ struct ErrorFactory
err.set_members(dbus_message_get_error_name(&msg), text.c_str(), dbus_message_get_reply_serial(&msg));

// any other unexpected dbus error, e.g. exception during method body
if (dbus_message_iter_has_next(&iter))
if (dbus_message_iter_get_arg_type(&iter) != 0)
{
// and now the rest
decode(iter, err);
Expand Down
4 changes: 4 additions & 0 deletions include/simppl/detail/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ std::string make_interface_name(const char* begin, const char* end);
*/
const char* find_next_interface(const char* template_args);

/**
* Make dbus compatible name from Exception type.
*/
char* make_error_name(char*);


} // namespace detail
Expand Down
2 changes: 1 addition & 1 deletion include/simppl/error.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ struct Error : public std::exception

protected:

message_ptr_t make_reply_for(DBusMessage& req) const;
message_ptr_t make_reply_for(DBusMessage& req, const char* classname = nullptr) const;

void set_members(const char* name, const char* msg, uint32_t serial);

Expand Down
8 changes: 1 addition & 7 deletions include/simppl/objectpath.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,7 @@ struct ObjectPath
{
return !(lhs < rhs);
}

inline
bool operator!=(const ObjectPath& rhs) const
{
return path != rhs.path;
}


std::string path;
};

Expand Down
7 changes: 3 additions & 4 deletions src/error.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ namespace simppl
namespace dbus
{


Error::Error(const char* name, const char* msg, uint32_t serial)
: name_and_message_(nullptr)
, message_(nullptr)
Expand Down Expand Up @@ -81,9 +80,9 @@ void Error::set_members(const char* name, const char* msg, uint32_t serial)
}


message_ptr_t Error::make_reply_for(DBusMessage& req) const
message_ptr_t Error::make_reply_for(DBusMessage& req, const char* class_name) const
{
return make_message(dbus_message_new_error(&req, name(), message()));
return make_message(dbus_message_new_error(&req, class_name ? class_name : name(), message()));
}


Expand All @@ -101,7 +100,7 @@ const char* Error::name() const

const char* Error::message() const
{
return message_;
return message_ ? message_ : "";
}


Expand Down
7 changes: 0 additions & 7 deletions src/skeletonbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,6 @@ namespace dbus
namespace detail
{

struct FreeDeleter {
template<typename T>
void operator()(T* o) {
::free(o);
}
};

using DemangledNamePtr = std::unique_ptr<char, FreeDeleter>;

} // namespace detail
Expand Down
23 changes: 23 additions & 0 deletions src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,29 @@ const char* find_next_interface(const char* s) {
}
}


char* make_error_name(char* str)
{
char* to = str;
char* from = str;

while(*from)
{
if (*from == ':')
{
*to++ = '.';
from += 2;
}
else
*to++ = *from++;
}

*to = '\0';

return str;
}


} // namespace detail

} // namespace dbus
Expand Down
44 changes: 42 additions & 2 deletions tests/errors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,20 @@ namespace test
* is it not possible to use the make_serializer here.
*
* But with boost::fusion everything works ok.
*
* @note that if mixing simppl code with raw DBus calls you must make sure
* that when using the exceptions feature, the dbus message must contain
* a message in addition to the error name, otherwise deserialization would
* yield an error.
*/
struct MyException : simppl::dbus::Error
{
/// class needs a default constructor
/// class needs a default constructor which is used during deserialization.
/// If such an exception instance is returned on the server, the name
/// will be set via C++ RTTI.
MyException() = default;

/// This is the instance that can be thrown in user code.
MyException(int return_code)
: simppl::dbus::Error("My.Exception")
, rc(return_code)
Expand All @@ -50,6 +58,7 @@ INTERFACE(Errors)
#if SIMPPL_HAVE_BOOST_FUSION
Method<_throw<MyException>> hello2;
Method<_throw<MyException>> hello3;
Method<_throw<MyException>> hello4;
#endif

inline
Expand All @@ -60,6 +69,7 @@ INTERFACE(Errors)
#if SIMPPL_HAVE_BOOST_FUSION
, INIT(hello2)
, INIT(hello3)
, INIT(hello4)
#endif
{
// NOOP
Expand Down Expand Up @@ -141,12 +151,16 @@ struct Server : simppl::dbus::Skeleton<Errors>

#if SIMPPL_HAVE_BOOST_FUSION
hello2 >> [this](){
respond_with(MyException());
respond_with(MyException(42));
};

hello3 >> [this](){
throw std::runtime_error("Ooops");
};

hello4 >> [this](){
respond_with(MyException()); // will produce an DBus error test.MyException
};
#endif
}
};
Expand Down Expand Up @@ -261,6 +275,32 @@ TEST(Errors, blocking)
{
ASSERT_FALSE(true);
}

try
{
stub.hello4();

// never reach
ASSERT_FALSE(true);
}
catch(const test::MyException& e)
{
EXPECT_STREQ(e.name(), "test.MyException");
EXPECT_EQ(0, e.rc);
}
catch(const simppl::dbus::RuntimeError& e)
{
ASSERT_FALSE(true);
}
catch(const simppl::dbus::Error& e)
{
// does not reach the default exception handler
ASSERT_FALSE(true);
}
catch(...)
{
ASSERT_FALSE(true);
}
#endif

stub.stop();
Expand Down

0 comments on commit 54cb18e

Please sign in to comment.