ohmu
·
2026-10-15
1#include "common/dbus.h"
2
3#ifdef FF_HAVE_DBUS
4
5 #include "common/debug.h"
6 #include "common/thread.h"
7 #include "common/strutil.h"
8
9static bool loadLibSymbols(FFDBusLibrary* lib) {
10 FF_LIBRARY_LOAD(dbus, false, "libdbus-1" FF_LIBRARY_EXTENSION, 4);
11 FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_bus_get, false)
12 FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_new_method_call, false)
13 FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_append_args, false)
14 FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_init, false)
15 FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_get_arg_type, false)
16 FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_get_basic, false)
17 FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_recurse, false)
18 FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_has_next, false)
19 FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_next, false)
20 FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_unref, false)
21 FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_send_with_reply_and_block, false)
22 FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_unref, false)
23 dbus = nullptr; // don't auto dlclose
24 return true;
25}
26
27static const FFDBusLibrary* loadLib(void) {
28 static FFDBusLibrary lib;
29 static bool loaded = false;
30 static bool loadSuccess = false;
31
32 if (!loaded) {
33 loaded = true;
34 loadSuccess = loadLibSymbols(&lib);
35 }
36
37 return loadSuccess ? &lib : nullptr;
38}
39
40const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data) {
41 data->lib = loadLib();
42 if (data->lib == nullptr) {
43 FF_DEBUG("libdbus-1 could not be loaded");
44 return "Failed to load DBus library";
45 }
46
47 data->connection = data->lib->ffdbus_bus_get(busType, nullptr);
48 if (data->connection == nullptr) {
49 FF_DEBUG("dbus_bus_get(busType=%d) returned no connection", (int) busType);
50 return "Failed to connect to DBus";
51 }
52
53 return nullptr;
54}
55
56void ffDBusDestroyData(FFDBusData* data) {
57 if (data->connection != nullptr) {
58 data->lib->ffdbus_connection_unref(data->connection);
59 data->connection = nullptr;
60 }
61}
62
63bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result) {
64 int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
65
66 if (argType == DBUS_TYPE_STRING || argType == DBUS_TYPE_OBJECT_PATH) {
67 const char* value = nullptr;
68 dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
69
70 if (!ffStrSet(value)) {
71 return false;
72 }
73
74 ffStrbufAppendS(result, value);
75 return true;
76 }
77
78 if (argType == DBUS_TYPE_BYTE) {
79 uint8_t value;
80 dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
81 ffStrbufAppendC(result, (char) value);
82 return true;
83 }
84
85 if (argType != DBUS_TYPE_VARIANT && argType != DBUS_TYPE_ARRAY) {
86 return false;
87 }
88
89 DBusMessageIter subIter;
90 dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
91
92 if (argType == DBUS_TYPE_VARIANT) {
93 return ffDBusGetString(dbus, &subIter, result);
94 }
95
96 // At this point we have an array
97
98 int subArgType = dbus->lib->ffdbus_message_iter_get_arg_type(&subIter);
99 if (subArgType == DBUS_TYPE_INVALID) {
100 return false;
101 }
102
103 if (subArgType == DBUS_TYPE_BYTE) {
104 while (true) {
105 uint8_t value;
106 dbus->lib->ffdbus_message_iter_get_basic(&subIter, &value);
107 ffStrbufAppendC(result, (char) value);
108
109 if (!dbus->lib->ffdbus_message_iter_next(&subIter)) {
110 break;
111 }
112 }
113
114 return true;
115 }
116
117 bool foundAValue = false;
118
119 while (true) {
120 if (ffDBusGetString(dbus, &subIter, result)) {
121 foundAValue = true;
122 ffStrbufAppendS(result, ", ");
123 }
124
125 if (!dbus->lib->ffdbus_message_iter_next(&subIter)) {
126 break;
127 } else {
128 continue;
129 }
130 }
131
132 if (foundAValue) {
133 ffStrbufSubstrBefore(result, result->length - 2);
134 }
135
136 return foundAValue;
137}
138
139bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result) {
140 int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
141
142 if (argType == DBUS_TYPE_BOOLEAN) {
143 dbus_bool_t value = 0;
144 dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
145 *result = value != 0;
146 return true;
147 }
148
149 if (argType != DBUS_TYPE_VARIANT) {
150 return false;
151 }
152
153 DBusMessageIter subIter;
154 dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
155 return ffDBusGetBool(dbus, &subIter, result);
156}
157
158bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint64_t* result) {
159 int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
160
161 if (argType == DBUS_TYPE_BYTE) {
162 uint8_t value = 0;
163 dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
164 *result = value;
165 return true;
166 }
167
168 if (argType == DBUS_TYPE_UINT16) {
169 uint16_t value = 0;
170 dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
171 *result = value;
172 return true;
173 }
174
175 if (argType == DBUS_TYPE_UINT32) {
176 uint32_t value = 0;
177 dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
178 *result = value;
179 return true;
180 }
181
182 if (argType == DBUS_TYPE_UINT64) {
183 dbus->lib->ffdbus_message_iter_get_basic(iter, result);
184 return true;
185 }
186
187 if (argType != DBUS_TYPE_VARIANT) {
188 return false;
189 }
190
191 DBusMessageIter subIter;
192 dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
193 return ffDBusGetUint(dbus, &subIter, result);
194}
195
196bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int64_t* result) {
197 int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
198
199 if (argType == DBUS_TYPE_INT16) {
200 int16_t value = 0;
201 dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
202 *result = value;
203 return true;
204 }
205
206 if (argType == DBUS_TYPE_INT32) {
207 int32_t value = 0;
208 dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
209 *result = value;
210 return true;
211 }
212
213 if (argType == DBUS_TYPE_INT64) {
214 dbus->lib->ffdbus_message_iter_get_basic(iter, result);
215 return true;
216 }
217
218 if (argType == DBUS_TYPE_BYTE) {
219 uint8_t value = 0;
220 dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
221 *result = value;
222 return true;
223 }
224
225 if (argType == DBUS_TYPE_UINT16) {
226 uint16_t value = 0;
227 dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
228 *result = (int32_t) value;
229 return true;
230 }
231
232 if (argType == DBUS_TYPE_UINT32) {
233 uint32_t value = 0;
234 dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
235 *result = (int32_t) value;
236 return true;
237 }
238
239 if (argType == DBUS_TYPE_UINT64) {
240 uint64_t value = 0;
241 dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
242 if (value > INT64_MAX) {
243 return false;
244 }
245 *result = (int64_t) value;
246 return true;
247 }
248
249 if (argType != DBUS_TYPE_VARIANT) {
250 return false;
251 }
252
253 DBusMessageIter subIter;
254 dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
255 return ffDBusGetInt(dbus, &subIter, result);
256}
257
258DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2) {
259 DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, interface, method);
260 if (message == nullptr) {
261 return nullptr;
262 }
263
264 if (arg1) {
265 if (arg2) {
266 dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_STRING, &arg2, DBUS_TYPE_INVALID);
267 } else {
268 dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_INVALID);
269 }
270 }
271
272 DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, nullptr);
273
274 dbus->lib->ffdbus_message_unref(message);
275
276 return reply;
277}
278
279DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property) {
280 DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, "org.freedesktop.DBus.Properties", "Get");
281 if (message == nullptr) {
282 return nullptr;
283 }
284
285 dbus->lib->ffdbus_message_append_args(message,
286 DBUS_TYPE_STRING,
287 &interface,
288 DBUS_TYPE_STRING,
289 &property,
290 DBUS_TYPE_INVALID);
291
292 DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, nullptr);
293
294 dbus->lib->ffdbus_message_unref(message);
295
296 return reply;
297}
298
299bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result) {
300 DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property);
301 if (reply == nullptr) {
302 return false;
303 }
304
305 DBusMessageIter rootIterator;
306 if (!dbus->lib->ffdbus_message_iter_init(reply, &rootIterator)) {
307 dbus->lib->ffdbus_message_unref(reply);
308 return false;
309 }
310
311 bool ret = ffDBusGetString(dbus, &rootIterator, result);
312
313 dbus->lib->ffdbus_message_unref(reply);
314
315 return ret;
316}
317
318bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint64_t* result) {
319 DBusMessage* reply = ffDBusGetProperty(dbus, busName, objectPath, interface, property);
320 if (reply == nullptr) {
321 return false;
322 }
323
324 DBusMessageIter rootIterator;
325 if (!dbus->lib->ffdbus_message_iter_init(reply, &rootIterator)) {
326 dbus->lib->ffdbus_message_unref(reply);
327 return false;
328 }
329
330 bool ret = ffDBusGetUint(dbus, &rootIterator, result);
331
332 dbus->lib->ffdbus_message_unref(reply);
333
334 return ret;
335}
336
337#endif // FF_HAVE_DBUS