summaryrefslogtreecommitdiffstats
path: root/xbmc/platform/linux/DBusUtil.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/platform/linux/DBusUtil.cpp')
-rw-r--r--xbmc/platform/linux/DBusUtil.cpp296
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);
+}