diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 18:07:22 +0000 |
commit | c04dcc2e7d834218ef2d4194331e383402495ae1 (patch) | |
tree | 7333e38d10d75386e60f336b80c2443c1166031d /xbmc/platform/linux/DBusUtil.cpp | |
parent | Initial commit. (diff) | |
download | kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.tar.xz kodi-c04dcc2e7d834218ef2d4194331e383402495ae1.zip |
Adding upstream version 2:20.4+dfsg.upstream/2%20.4+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'xbmc/platform/linux/DBusUtil.cpp')
-rw-r--r-- | xbmc/platform/linux/DBusUtil.cpp | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/xbmc/platform/linux/DBusUtil.cpp b/xbmc/platform/linux/DBusUtil.cpp new file mode 100644 index 0000000..2efb75c --- /dev/null +++ b/xbmc/platform/linux/DBusUtil.cpp @@ -0,0 +1,296 @@ +/* + * 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. + */ +#include "DBusUtil.h" + +#include "utils/log.h" + +CVariant CDBusUtil::GetVariant(const char *destination, const char *object, const char *interface, const char *property) +{ +//dbus-send --system --print-reply --dest=destination object org.freedesktop.DBus.Properties.Get string:interface string:property + CDBusMessage message(destination, object, "org.freedesktop.DBus.Properties", "Get"); + CVariant result; + + message.AppendArgument(interface); + message.AppendArgument(property); + DBusMessage *reply = message.SendSystem(); + + if (reply) + { + DBusMessageIter iter; + + if (dbus_message_iter_init(reply, &iter)) + { + if (!dbus_message_has_signature(reply, "v")) + CLog::Log(LOGERROR, "DBus: wrong signature on Get - should be \"v\" but was {}", + dbus_message_iter_get_signature(&iter)); + else + result = ParseVariant(&iter); + } + } + + return result; +} + +CVariant CDBusUtil::GetAll(const char *destination, const char *object, const char *interface) +{ + CDBusMessage message(destination, object, "org.freedesktop.DBus.Properties", "GetAll"); + CVariant properties; + message.AppendArgument(interface); + DBusMessage *reply = message.SendSystem(); + if (reply) + { + DBusMessageIter iter; + if (dbus_message_iter_init(reply, &iter)) + { + if (!dbus_message_has_signature(reply, "a{sv}")) + CLog::Log(LOGERROR, "DBus: wrong signature on GetAll - should be \"a{sv}\" but was {}", + dbus_message_iter_get_signature(&iter)); + else + { + do + { + DBusMessageIter sub; + dbus_message_iter_recurse(&iter, &sub); + do + { + DBusMessageIter dict; + dbus_message_iter_recurse(&sub, &dict); + do + { + const char * key = NULL; + + dbus_message_iter_get_basic(&dict, &key); + if (!dbus_message_iter_next(&dict)) + break; + + CVariant value = ParseVariant(&dict); + + if (!value.isNull()) + properties[key] = value; + + } while (dbus_message_iter_next(&dict)); + + } while (dbus_message_iter_next(&sub)); + + } while (dbus_message_iter_next(&iter)); + } + } + } + + return properties; +} + +CVariant CDBusUtil::ParseVariant(DBusMessageIter *itr) +{ + DBusMessageIter variant; + dbus_message_iter_recurse(itr, &variant); + + return ParseType(&variant); +} + +CVariant CDBusUtil::ParseType(DBusMessageIter *itr) +{ + CVariant value; + const char * string = NULL; + dbus_int32_t int32 = 0; + dbus_uint32_t uint32 = 0; + dbus_int64_t int64 = 0; + dbus_uint64_t uint64 = 0; + dbus_bool_t boolean = false; + double doublev = 0; + + int type = dbus_message_iter_get_arg_type(itr); + switch (type) + { + case DBUS_TYPE_OBJECT_PATH: + case DBUS_TYPE_STRING: + dbus_message_iter_get_basic(itr, &string); + value = string; + break; + case DBUS_TYPE_UINT32: + dbus_message_iter_get_basic(itr, &uint32); + value = (uint64_t)uint32; + break; + case DBUS_TYPE_BYTE: + case DBUS_TYPE_INT32: + dbus_message_iter_get_basic(itr, &int32); + value = (int64_t)int32; + break; + case DBUS_TYPE_UINT64: + dbus_message_iter_get_basic(itr, &uint64); + value = (uint64_t)uint64; + break; + case DBUS_TYPE_INT64: + dbus_message_iter_get_basic(itr, &int64); + value = (int64_t)int64; + break; + case DBUS_TYPE_BOOLEAN: + dbus_message_iter_get_basic(itr, &boolean); + value = (bool)boolean; + break; + case DBUS_TYPE_DOUBLE: + dbus_message_iter_get_basic(itr, &doublev); + value = doublev; + break; + case DBUS_TYPE_ARRAY: + DBusMessageIter array; + dbus_message_iter_recurse(itr, &array); + + value = CVariant::VariantTypeArray; + + do + { + CVariant item = ParseType(&array); + if (!item.isNull()) + value.push_back(item); + } while (dbus_message_iter_next(&array)); + break; + } + + return value; +} + +bool CDBusUtil::TryMethodCall(DBusBusType bus, const char* destination, const char* object, const char* interface, const char* method) +{ + CDBusMessage message(destination, object, interface, method); + CDBusError error; + message.Send(bus, error); + if (error) + { + error.Log(LOGDEBUG, std::string("DBus method call to ") + interface + "." + method + " at " + object + " of " + destination + " failed"); + } + return !error; +} + +bool CDBusUtil::TryMethodCall(DBusBusType bus, std::string const& destination, std::string const& object, std::string const& interface, std::string const& method) +{ + return TryMethodCall(bus, destination.c_str(), object.c_str(), interface.c_str(), method.c_str()); +} + +CDBusConnection::CDBusConnection() = default; + +bool CDBusConnection::Connect(DBusBusType bus, bool openPrivate) +{ + CDBusError error; + Connect(bus, error, openPrivate); + if (error) + { + error.Log(LOGWARNING, "DBus connection failed"); + return false; + } + + return true; +} + +bool CDBusConnection::Connect(DBusBusType bus, CDBusError& error, bool openPrivate) +{ + if (m_connection) + { + throw std::logic_error("Cannot reopen connected DBus connection"); + } + + m_connection.get_deleter().closeBeforeUnref = openPrivate; + + if (openPrivate) + { + m_connection.reset(dbus_bus_get_private(bus, error)); + } + else + { + m_connection.reset(dbus_bus_get(bus, error)); + } + + return !!m_connection; +} + +CDBusConnection::operator DBusConnection*() +{ + return m_connection.get(); +} + +void CDBusConnection::DBusConnectionDeleter::operator()(DBusConnection* connection) const +{ + if (closeBeforeUnref) + { + dbus_connection_close(connection); + } + dbus_connection_unref(connection); +} + +void CDBusConnection::Destroy() +{ + m_connection.reset(); +} + + +CDBusError::CDBusError() +{ + dbus_error_init(&m_error); +} + +CDBusError::~CDBusError() +{ + Reset(); +} + +void CDBusError::Reset() +{ + dbus_error_free(&m_error); +} + +CDBusError::operator DBusError*() +{ + return &m_error; +} + +bool CDBusError::IsSet() const +{ + return dbus_error_is_set(&m_error); +} + +CDBusError::operator bool() +{ + return IsSet(); +} + +CDBusError::operator bool() const +{ + return IsSet(); +} + +std::string CDBusError::Name() const +{ + if (!IsSet()) + { + throw std::logic_error("Cannot retrieve name of unset DBus error"); + } + return m_error.name; +} + +std::string CDBusError::Message() const +{ + if (!IsSet()) + { + throw std::logic_error("Cannot retrieve message of unset DBus error"); + } + return m_error.message; +} + +void CDBusError::Log(std::string const& message) const +{ + Log(LOGERROR, message); +} + +void CDBusError::Log(int level, const std::string& message) const +{ + if (!IsSet()) + { + throw std::logic_error("Cannot log unset DBus error"); + } + CLog::Log(level, "{}: {} - {}", message, m_error.name, m_error.message); +} |