diff options
Diffstat (limited to '')
-rw-r--r-- | xbmc/platform/linux/DBusMessage.h | 149 |
1 files changed, 149 insertions, 0 deletions
diff --git a/xbmc/platform/linux/DBusMessage.h b/xbmc/platform/linux/DBusMessage.h new file mode 100644 index 0000000..80c7cd6 --- /dev/null +++ b/xbmc/platform/linux/DBusMessage.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include <cstdint> +#include <memory> +#include <string> +#include <type_traits> + +#include <dbus/dbus.h> + +class CDBusError; + +template<typename T> +struct ToDBusType; +template<> struct ToDBusType<bool> { static constexpr int TYPE = DBUS_TYPE_BOOLEAN; }; +template<> struct ToDBusType<char*> { static constexpr int TYPE = DBUS_TYPE_STRING; }; +template<> struct ToDBusType<const char*> { static constexpr int TYPE = DBUS_TYPE_STRING; }; +template<> struct ToDBusType<std::uint8_t> { static constexpr int TYPE = DBUS_TYPE_BYTE; }; +template<> struct ToDBusType<std::int16_t> { static constexpr int TYPE = DBUS_TYPE_INT16; }; +template<> struct ToDBusType<std::uint16_t> { static constexpr int TYPE = DBUS_TYPE_UINT16; }; +template<> struct ToDBusType<std::int32_t> { static constexpr int TYPE = DBUS_TYPE_INT32; }; +template<> struct ToDBusType<std::uint32_t> { static constexpr int TYPE = DBUS_TYPE_UINT32; }; +template<> struct ToDBusType<std::int64_t> { static constexpr int TYPE = DBUS_TYPE_INT64; }; +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; +}; +using DBusMessagePtr = std::unique_ptr<DBusMessage, DBusMessageDeleter>; + +class CDBusMessage +{ +public: + CDBusMessage(const char *destination, const char *object, const char *interface, const char *method); + CDBusMessage(std::string const& destination, std::string const& object, std::string const& interface, std::string const& method); + + void AppendObjectPath(const char *object); + + template<typename T> + void AppendArgument(const T arg) + { + AppendWithType(ToDBusType<T>::TYPE, &arg); + } + void AppendArgument(const char **arrayString, unsigned int length); + + template<typename TFirst> + void AppendArguments(const TFirst first) + { + AppendArgument(first); + // Recursion end + } + template<typename TFirst, typename... TArgs> + void AppendArguments(const TFirst first, const TArgs... args) + { + AppendArgument(first); + AppendArguments(args...); + } + + DBusMessageIter * GetArgumentIter(); + + /** + * 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); + DBusMessage *SendSession(CDBusError& error); + + bool SendAsyncSystem(); + bool SendAsyncSession(); + + DBusMessage *Send(DBusBusType type); + DBusMessage *Send(DBusBusType type, CDBusError& error); + DBusMessage *Send(DBusConnection *con, CDBusError& error); +private: + void AppendWithType(int type, const void* value); + bool SendAsync(DBusBusType type); + + 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 = nullptr; + DBusMessageIter m_args; + bool m_haveArgs; +}; + +template<> +void CDBusMessage::AppendArgument<bool>(const bool arg); +template<> +void CDBusMessage::AppendArgument<std::string>(const std::string arg); |