summaryrefslogtreecommitdiffstats
path: root/src/common/impl/dbus.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/impl/dbus.c')
-rw-r--r--src/common/impl/dbus.c334
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