diff options
Diffstat (limited to 'src/common/impl/dbus.c')
| -rw-r--r-- | src/common/impl/dbus.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/src/common/impl/dbus.c b/src/common/impl/dbus.c new file mode 100644 index 0000000..473af2d --- /dev/null +++ b/src/common/impl/dbus.c @@ -0,0 +1,334 @@ +#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 |