#include "common/dbus.h" #ifdef FF_HAVE_DBUS #include "common/thread.h" #include "common/strutil.h" static bool loadLibSymbols(FFDBusLibrary* lib) { FF_LIBRARY_LOAD(dbus, false, "libdbus-1" FF_LIBRARY_EXTENSION, 4); FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_bus_get, false) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_new_method_call, false) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_append_args, false) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_init, false) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_get_arg_type, false) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_get_basic, false) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_recurse, false) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_has_next, false) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_next, false) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_unref, false) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_send_with_reply_and_block, false) FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_unref, false) dbus = NULL; // don't auto dlclose return true; } static const FFDBusLibrary* loadLib(void) { static FFDBusLibrary lib; static bool loaded = false; static bool loadSuccess = false; if (!loaded) { loaded = true; loadSuccess = loadLibSymbols(&lib); } return loadSuccess ? &lib : NULL; } const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data) { data->lib = loadLib(); if (data->lib == NULL) { return "Failed to load DBus library"; } data->connection = data->lib->ffdbus_bus_get(busType, NULL); if (data->connection == NULL) { return "Failed to connect to DBus"; } return NULL; } void ffDBusDestroyData(FFDBusData* data) { if (data->connection != NULL) { data->lib->ffdbus_connection_unref(data->connection); data->connection = NULL; } } bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result) { int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter); if (argType == DBUS_TYPE_STRING || argType == DBUS_TYPE_OBJECT_PATH) { const char* value = NULL; dbus->lib->ffdbus_message_iter_get_basic(iter, &value); if (!ffStrSet(value)) { return false; } ffStrbufAppendS(result, value); return true; } if (argType == DBUS_TYPE_BYTE) { uint8_t value; dbus->lib->ffdbus_message_iter_get_basic(iter, &value); ffStrbufAppendC(result, (char) value); return true; } if (argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY) { return false; } DBusMessageIter subIter; dbus->lib->ffdbus_message_iter_recurse(iter, &subIter); if (argType == DBUS_TYPE_VARIANT) { return ffDBusGetString(dbus, &subIter, result); } // At this point we have an array int subArgType = dbus->lib->ffdbus_message_iter_get_arg_type(&subIter); if (subArgType == DBUS_TYPE_INVALID) { return false; } if (subArgType == DBUS_TYPE_BYTE) { while (true) { uint8_t value; dbus->lib->ffdbus_message_iter_get_basic(&subIter, &value); ffStrbufAppendC(result, (char) value); if (!dbus->lib->ffdbus_message_iter_next(&subIter)) { break; } } return true; } bool foundAValue = false; while (true) { if (ffDBusGetString(dbus, &subIter, result)) { foundAValue = true; ffStrbufAppendS(result, ", "); } if (!dbus->lib->ffdbus_message_iter_next(&subIter)) { break; } else { continue; } } if (foundAValue) { ffStrbufSubstrBefore(result, result->length - 2); } return foundAValue; } bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result) { int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter); if (argType == DBUS_TYPE_BOOLEAN) { dbus_bool_t value = 0; dbus->lib->ffdbus_message_iter_get_basic(iter, &value); *result = value != 0; return true; } if (argType != DBUS_TYPE_VARIANT) { return false; } DBusMessageIter subIter; dbus->lib->ffdbus_message_iter_recurse(iter, &subIter); return ffDBusGetBool(dbus, &subIter, result); } bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint64_t* result) { int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter); if (argType == DBUS_TYPE_BYTE) { uint8_t value = 0; dbus->lib->ffdbus_message_iter_get_basic(iter, &value); *result = value; return true; } if (argType == DBUS_TYPE_UINT16) { uint16_t value = 0; dbus->lib->ffdbus_message_iter_get_basic(iter, &value); *result = value; return true; } if (argType == DBUS_TYPE_UINT32) { uint32_t value = 0; dbus->lib->ffdbus_message_iter_get_basic(iter, &value); *result = value; return true; } if (argType == DBUS_TYPE_UINT64) { dbus->lib->ffdbus_message_iter_get_basic(iter, result); return true; } if (argType != DBUS_TYPE_VARIANT) { return false; } DBusMessageIter subIter; dbus->lib->ffdbus_message_iter_recurse(iter, &subIter); return ffDBusGetUint(dbus, &subIter, result); } bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int64_t* result) { int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter); if (argType == DBUS_TYPE_INT16) { int16_t value = 0; dbus->lib->ffdbus_message_iter_get_basic(iter, &value); *result = value; return true; } if (argType == DBUS_TYPE_INT32) { int32_t value = 0; dbus->lib->ffdbus_message_iter_get_basic(iter, &value); *result = value; return true; } if (argType == DBUS_TYPE_INT64) { dbus->lib->ffdbus_message_iter_get_basic(iter, result); return true; } if (argType == DBUS_TYPE_BYTE) { uint8_t value = 0; dbus->lib->ffdbus_message_iter_get_basic(iter, &value); *result = value; return true; } if (argType == DBUS_TYPE_UINT16) { uint16_t value = 0; dbus->lib->ffdbus_message_iter_get_basic(iter, &value); *result = (int32_t) value; return true; } if (argType == DBUS_TYPE_UINT32) { uint32_t value = 0; dbus->lib->ffdbus_message_iter_get_basic(iter, &value); *result = (int32_t) value; return true; } if (argType == DBUS_TYPE_UINT64) { uint64_t value = 0; dbus->lib->ffdbus_message_iter_get_basic(iter, &value); if (value > INT64_MAX) { return false; } *result = (int64_t) value; return true; } if (argType != DBUS_TYPE_VARIANT) { return false; } DBusMessageIter subIter; dbus->lib->ffdbus_message_iter_recurse(iter, &subIter); return ffDBusGetInt(dbus, &subIter, result); } DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2) { DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, interface, method); if (message == NULL) { return NULL; } if (arg1) { if (arg2) { dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_STRING, &arg2, DBUS_TYPE_INVALID); } else { dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_INVALID); } } DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, NULL); dbus->lib->ffdbus_message_unref(message); return reply; } DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property) { DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, "org.freedesktop.DBus.Properties", "Get"); if (message == NULL) { return NULL; } dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID); DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, NULL); dbus->lib->ffdbus_message_unref(message); return reply; } bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result) { DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property); if (reply == NULL) { return false; } DBusMessageIter rootIterator; if (!dbus->lib->ffdbus_message_iter_init(reply, &rootIterator)) { dbus->lib->ffdbus_message_unref(reply); return false; } bool ret = ffDBusGetString(dbus, &rootIterator, result); dbus->lib->ffdbus_message_unref(reply); return ret; } bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint64_t* result) { DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property); if (reply == NULL) { return false; } DBusMessageIter rootIterator; if (!dbus->lib->ffdbus_message_iter_init(reply, &rootIterator)) { dbus->lib->ffdbus_message_unref(reply); return false; } bool ret = ffDBusGetUint(dbus, &rootIterator, result); dbus->lib->ffdbus_message_unref(reply); return ret; } #endif // FF_HAVE_DBUS