aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilipp Kerling <pkerling@casix.org>2017-06-27 13:05:38 +0200
committerPhilipp Kerling <pkerling@casix.org>2017-08-16 16:12:01 +0200
commit24ca9b302ebb15bb8f6fe47468f49c7f900103c9 (patch)
tree28beca3005229e1bd0a1a1fd97d133143c81bf15
parent7895b41e7d85fa8daad0f0759bc66f36f75d647c (diff)
Add DBusMessage method for retrieving simple reply arguments
-rw-r--r--xbmc/linux/DBusMessage.cpp27
-rw-r--r--xbmc/linux/DBusMessage.h54
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;