diff options
author | Philipp Kerling <pkerling@casix.org> | 2017-06-27 13:05:38 +0200 |
---|---|---|
committer | Philipp Kerling <pkerling@casix.org> | 2017-08-16 16:12:01 +0200 |
commit | 24ca9b302ebb15bb8f6fe47468f49c7f900103c9 (patch) | |
tree | 28beca3005229e1bd0a1a1fd97d133143c81bf15 | |
parent | 7895b41e7d85fa8daad0f0759bc66f36f75d647c (diff) |
Add DBusMessage method for retrieving simple reply arguments
-rw-r--r-- | xbmc/linux/DBusMessage.cpp | 27 | ||||
-rw-r--r-- | xbmc/linux/DBusMessage.h | 54 |
2 files changed, 81 insertions, 0 deletions
diff --git a/xbmc/linux/DBusMessage.cpp b/xbmc/linux/DBusMessage.cpp index c674b11274..e5c4f1fd2f 100644 --- a/xbmc/linux/DBusMessage.cpp +++ b/xbmc/linux/DBusMessage.cpp @@ -169,3 +169,30 @@ void CDBusMessage::PrepareArgument() m_haveArgs = true; } + +bool CDBusMessage::InitializeReplyIter(DBusMessageIter* iter) +{ + if (!m_reply) + { + throw std::logic_error("Cannot get reply arguments of message that does not have reply"); + } + if (!dbus_message_iter_init(m_reply.get(), iter)) + { + CLog::Log(LOGWARNING, "Tried to obtain reply arguments from message that has zero arguments"); + return false; + } + return true; +} + +bool CDBusMessage::CheckTypeAndGetValue(DBusMessageIter* iter, int expectType, void* dest) +{ + const int haveType = dbus_message_iter_get_arg_type(iter); + if (haveType != expectType) + { + CLog::Log(LOGDEBUG, "DBus argument type mismatch: expected %d, got %d", expectType, haveType); + return false; + } + + dbus_message_iter_get_basic(iter, dest); + return true; +} diff --git a/xbmc/linux/DBusMessage.h b/xbmc/linux/DBusMessage.h index 510e1514ff..f3d65530ee 100644 --- a/xbmc/linux/DBusMessage.h +++ b/xbmc/linux/DBusMessage.h @@ -23,6 +23,7 @@ #include <cstdint> #include <memory> #include <string> +#include <type_traits> #include <dbus/dbus.h> @@ -42,6 +43,9 @@ template<> struct ToDBusType<std::int64_t> { static constexpr int TYPE = DBUS_TY template<> struct ToDBusType<std::uint64_t> { static constexpr int TYPE = DBUS_TYPE_UINT64; }; template<> struct ToDBusType<double> { static constexpr int TYPE = DBUS_TYPE_DOUBLE; }; +template<typename T> +using ToDBusTypeFromPointer = ToDBusType<typename std::remove_pointer<T>::type>; + struct DBusMessageDeleter { void operator()(DBusMessage* message) const; @@ -76,6 +80,35 @@ public: AppendArguments(args...); } + /** + * Retrieve simple arguments from DBus reply message + * + * You MUST use the correct fixed-width integer typedefs (e.g. std::uint16_t) + * corresponding to the DBus types for the variables or you will get potentially + * differing behavior between architectures since the DBus argument type detection + * is based on the width of the type. + * + * Complex arguments (arrays, structs) are not supported. + * + * Returned pointers for strings are only valid until the instance of this class + * is deleted. + * + * \throw std::logic_error if the message has no reply + * \return whether all arguments could be retrieved (false on argument type + * mismatch or when more arguments were to be retrieved than there are + * in the message) + */ + template<typename... TArgs> + bool GetReplyArguments(TArgs*... args) + { + DBusMessageIter iter; + if (!InitializeReplyIter(&iter)) + { + return false; + } + return GetReplyArgumentsWithIter(&iter, args...); + } + DBusMessage *SendSystem(); DBusMessage *SendSession(); DBusMessage *SendSystem(CDBusError& error); @@ -93,6 +126,27 @@ private: void PrepareArgument(); + bool InitializeReplyIter(DBusMessageIter* iter); + bool CheckTypeAndGetValue(DBusMessageIter* iter, int expectType, void* dest); + template<typename TFirst> + bool GetReplyArgumentsWithIter(DBusMessageIter* iter, TFirst* first) + { + // Recursion end + return CheckTypeAndGetValue(iter, ToDBusTypeFromPointer<TFirst>::TYPE, first); + } + template<typename TFirst, typename... TArgs> + bool GetReplyArgumentsWithIter(DBusMessageIter* iter, TFirst* first, TArgs*... args) + { + if (!CheckTypeAndGetValue(iter, ToDBusTypeFromPointer<TFirst>::TYPE, first)) + { + return false; + } + // Ignore return value, if we try to read past the end of the message this + // will be catched by the type check (past-end type is DBUS_TYPE_INVALID) + dbus_message_iter_next(iter); + return GetReplyArgumentsWithIter(iter, args...); + } + DBusMessagePtr m_message; DBusMessagePtr m_reply; DBusMessageIter m_args; |