| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* GATE PROJECT LICENSE: | ||
| 2 | +----------------------------------------------------------------------------+ | ||
| 3 | | Copyright(c) 2018-2026, Stefan Meislinger | | ||
| 4 | | All rights reserved. | | ||
| 5 | | | | ||
| 6 | | Redistribution and use in source and binary forms, with or without | | ||
| 7 | | modification, are permitted provided that the following conditions are met:| | ||
| 8 | | | | ||
| 9 | | 1. Redistributions of source code must retain the above copyright notice, | | ||
| 10 | | this list of conditions and the following disclaimer. | | ||
| 11 | | 2. Redistributions in binary form must reproduce the above copyright | | ||
| 12 | | notice, this list of conditions and the following disclaimer in the | | ||
| 13 | | documentation and/or other materials provided with the distribution. | | ||
| 14 | | | | ||
| 15 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| | ||
| 16 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | ||
| 17 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | ||
| 18 | | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | | ||
| 19 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | | ||
| 20 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | | ||
| 21 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | | ||
| 22 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | | ||
| 23 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | | ||
| 24 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | | ||
| 25 | | THE POSSIBILITY OF SUCH DAMAGE. | | ||
| 26 | +----------------------------------------------------------------------------+ | ||
| 27 | */ | ||
| 28 | |||
| 29 | #ifndef GATE_SYSTEM_PLATFORM_LINUX_DBUS_API_H_INCLUDED | ||
| 30 | #define GATE_SYSTEM_PLATFORM_LINUX_DBUS_API_H_INCLUDED | ||
| 31 | |||
| 32 | #include <dbus/dbus.h> | ||
| 33 | #include "gate/libraries.h" | ||
| 34 | #include "gate/results.h" | ||
| 35 | #include "gate/values.h" | ||
| 36 | |||
| 37 | typedef struct gate_libdbus_class | ||
| 38 | { | ||
| 39 | void (*error_init)(DBusError* ptr_error); | ||
| 40 | dbus_bool_t (*error_is_set)(DBusError* ptr_error); | ||
| 41 | void (*error_free)(DBusError* ptr_error); | ||
| 42 | |||
| 43 | DBusConnection* (*bus_get)(DBusBusType type, DBusError* ptr_error); | ||
| 44 | |||
| 45 | DBusConnection* (*connection_open)(const char* address, DBusError* error); | ||
| 46 | DBusConnection* (*connection_ref)(DBusConnection* connection); | ||
| 47 | void (*connection_unref)(DBusConnection* connection); | ||
| 48 | void (*connection_close)(DBusConnection* connection); | ||
| 49 | DBusMessage* (*connection_send_with_reply_and_block)(DBusConnection* connection, DBusMessage* message, int timeout_milliseconds, DBusError* error); | ||
| 50 | |||
| 51 | DBusMessage* (*message_ref)(DBusMessage* message); | ||
| 52 | void (*message_unref)(DBusMessage* message); | ||
| 53 | DBusMessage* (*message_copy)(const DBusMessage* message); | ||
| 54 | DBusMessage* (*message_new_method_call)(const char* bus_name, const char* path, const char* iface, const char* method); | ||
| 55 | dbus_bool_t (*message_append_args)(DBusMessage* message, int first_arg_type, ...); | ||
| 56 | |||
| 57 | dbus_bool_t (*message_iter_init) (DBusMessage* message, DBusMessageIter* iter); | ||
| 58 | int (*message_iter_get_arg_type)(DBusMessageIter* iter); | ||
| 59 | void (*message_iter_recurse) (DBusMessageIter* iter, DBusMessageIter* sub); | ||
| 60 | void (*message_iter_get_basic) (DBusMessageIter* iter, void* value); | ||
| 61 | dbus_bool_t (*message_iter_next) (DBusMessageIter* iter); | ||
| 62 | void (*message_iter_init_append) (DBusMessage* message, DBusMessageIter *iter); | ||
| 63 | dbus_bool_t (*message_iter_append_basic) (DBusMessageIter* iter, int type, const void* value); | ||
| 64 | dbus_bool_t (*message_iter_open_container) (DBusMessageIter* iter, int type, const char* contained_signature, DBusMessageIter* sub); | ||
| 65 | dbus_bool_t (*message_iter_close_container) (DBusMessageIter* iter, DBusMessageIter* sub); | ||
| 66 | } gate_libdbus_t; | ||
| 67 | |||
| 68 | |||
| 69 | #if defined(GATE_SYSTEM_LIBDBUS_STATIC) | ||
| 70 | |||
| 71 | static gate_result_t load_libdbus_lib(void) | ||
| 72 | { | ||
| 73 | return GATE_RESULT_OK; | ||
| 74 | } | ||
| 75 | |||
| 76 | # define LOAD_DBUS_FUNC(funcptr, funcname) do { funcptr = funcname; } while(0) | ||
| 77 | |||
| 78 | #else | ||
| 79 | |||
| 80 | static gate_library_t global_libdbus_lib = NULL; | ||
| 81 | |||
| 82 | ✗ | static gate_result_t load_libdbus_lib(void) | |
| 83 | { | ||
| 84 | static gate_string_t const libdbus_libname = GATE_STRING_INIT_STATIC("libdbus-1.so"); | ||
| 85 | gate_result_t ret; | ||
| 86 | |||
| 87 | ✗ | if (global_libdbus_lib == NULL) | |
| 88 | { | ||
| 89 | ✗ | ret = gate_library_open(&libdbus_libname, &global_libdbus_lib, 0); | |
| 90 | ✗ | if (GATE_FAILED(ret)) | |
| 91 | { | ||
| 92 | ✗ | global_libdbus_lib = NULL; | |
| 93 | } | ||
| 94 | } | ||
| 95 | else | ||
| 96 | { | ||
| 97 | ✗ | ret = GATE_RESULT_OK; | |
| 98 | } | ||
| 99 | ✗ | return ret; | |
| 100 | } | ||
| 101 | |||
| 102 | ✗ | static gate_result_t load_libdbus_function(void* ptr_funcptr, char const* funcname) | |
| 103 | { | ||
| 104 | ✗ | return gate_library_get_function_name(global_libdbus_lib, funcname, ptr_funcptr); | |
| 105 | } | ||
| 106 | |||
| 107 | # define LOAD_DBUS_FUNC(funcptr, funcname) \ | ||
| 108 | do { \ | ||
| 109 | gate_result_t result = load_libdbus_function(&funcptr, #funcname); \ | ||
| 110 | if(GATE_FAILED(result)) { return result; } \ | ||
| 111 | } while(0) | ||
| 112 | |||
| 113 | #endif | ||
| 114 | |||
| 115 | |||
| 116 | ✗ | static gate_result_t load_libdbus(gate_libdbus_t* dbus) | |
| 117 | { | ||
| 118 | ✗ | gate_result_t result = load_libdbus_lib(); | |
| 119 | ✗ | if (GATE_FAILED(result)) | |
| 120 | { | ||
| 121 | ✗ | return result; | |
| 122 | } | ||
| 123 | |||
| 124 | ✗ | LOAD_DBUS_FUNC(dbus->error_init, dbus_error_init); | |
| 125 | ✗ | LOAD_DBUS_FUNC(dbus->error_is_set, dbus_error_is_set); | |
| 126 | ✗ | LOAD_DBUS_FUNC(dbus->error_free, dbus_error_free); | |
| 127 | |||
| 128 | ✗ | LOAD_DBUS_FUNC(dbus->bus_get, dbus_bus_get); | |
| 129 | |||
| 130 | ✗ | LOAD_DBUS_FUNC(dbus->connection_open, dbus_connection_open); | |
| 131 | ✗ | LOAD_DBUS_FUNC(dbus->connection_ref, dbus_connection_ref); | |
| 132 | ✗ | LOAD_DBUS_FUNC(dbus->connection_unref, dbus_connection_unref); | |
| 133 | ✗ | LOAD_DBUS_FUNC(dbus->connection_close, dbus_connection_close); | |
| 134 | ✗ | LOAD_DBUS_FUNC(dbus->connection_send_with_reply_and_block, dbus_connection_send_with_reply_and_block); | |
| 135 | |||
| 136 | ✗ | LOAD_DBUS_FUNC(dbus->message_ref, dbus_message_ref); | |
| 137 | ✗ | LOAD_DBUS_FUNC(dbus->message_unref, dbus_message_unref); | |
| 138 | ✗ | LOAD_DBUS_FUNC(dbus->message_copy, dbus_message_copy); | |
| 139 | ✗ | LOAD_DBUS_FUNC(dbus->message_new_method_call, dbus_message_new_method_call); | |
| 140 | ✗ | LOAD_DBUS_FUNC(dbus->message_append_args, dbus_message_append_args); | |
| 141 | |||
| 142 | ✗ | LOAD_DBUS_FUNC(dbus->message_iter_init, dbus_message_iter_init); | |
| 143 | ✗ | LOAD_DBUS_FUNC(dbus->message_iter_get_arg_type, dbus_message_iter_get_arg_type); | |
| 144 | ✗ | LOAD_DBUS_FUNC(dbus->message_iter_recurse, dbus_message_iter_recurse); | |
| 145 | ✗ | LOAD_DBUS_FUNC(dbus->message_iter_get_basic, dbus_message_iter_get_basic); | |
| 146 | ✗ | LOAD_DBUS_FUNC(dbus->message_iter_next, dbus_message_iter_next); | |
| 147 | |||
| 148 | ✗ | LOAD_DBUS_FUNC(dbus->message_iter_init_append, dbus_message_iter_init_append); | |
| 149 | ✗ | LOAD_DBUS_FUNC(dbus->message_iter_append_basic, dbus_message_iter_append_basic); | |
| 150 | ✗ | LOAD_DBUS_FUNC(dbus->message_iter_open_container, dbus_message_iter_open_container); | |
| 151 | ✗ | LOAD_DBUS_FUNC(dbus->message_iter_close_container, dbus_message_iter_close_container); | |
| 152 | |||
| 153 | ✗ | return GATE_RESULT_OK; | |
| 154 | } | ||
| 155 | |||
| 156 | |||
| 157 | ✗ | static gate_libdbus_t* gate_load_libdbus(void) | |
| 158 | { | ||
| 159 | static gate_libdbus_t dbus; | ||
| 160 | static gate_bool_t dbus_loaded = false; | ||
| 161 | |||
| 162 | ✗ | if (!dbus_loaded) | |
| 163 | { | ||
| 164 | ✗ | gate_result_t result = load_libdbus(&dbus); | |
| 165 | ✗ | if (GATE_FAILED(result)) | |
| 166 | { | ||
| 167 | ✗ | return NULL; | |
| 168 | } | ||
| 169 | ✗ | dbus_loaded = true; | |
| 170 | } | ||
| 171 | ✗ | return &dbus; | |
| 172 | } | ||
| 173 | |||
| 174 | |||
| 175 | ✗ | static gate_result_t gate_dbus_open_system_connection(gate_libdbus_t** ptr_dbus, DBusConnection** ptr_conn) | |
| 176 | { | ||
| 177 | ✗ | gate_libdbus_t* dbus = gate_load_libdbus(); | |
| 178 | ✗ | if (dbus == NULL) | |
| 179 | { | ||
| 180 | ✗ | GATE_DEBUG_TRACE("FAILED to load libdbus"); | |
| 181 | ✗ | return GATE_RESULT_NOTAVAILABLE; | |
| 182 | } | ||
| 183 | else | ||
| 184 | { | ||
| 185 | ✗ | DBusConnection* conn = NULL; | |
| 186 | DBusError err; | ||
| 187 | ✗ | dbus->error_init(&err); | |
| 188 | ✗ | conn = dbus->bus_get(DBUS_BUS_SYSTEM, &err); | |
| 189 | ✗ | dbus->error_free(&err); | |
| 190 | ✗ | if (conn == NULL) | |
| 191 | { | ||
| 192 | ✗ | GATE_DEBUG_TRACE("FAILED to access DBUS system bus"); | |
| 193 | ✗ | *ptr_dbus = NULL; | |
| 194 | ✗ | *ptr_conn = NULL; | |
| 195 | ✗ | return GATE_RESULT_NOTAVAILABLE; | |
| 196 | } | ||
| 197 | else | ||
| 198 | { | ||
| 199 | ✗ | *ptr_dbus = dbus; | |
| 200 | ✗ | *ptr_conn = conn; | |
| 201 | ✗ | return GATE_RESULT_OK; | |
| 202 | } | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | |||
| 207 | ✗ | static gate_result_t gate_dbus_property_get(gate_libdbus_t* dbus, DBusConnection* conn, | |
| 208 | char const* bus_name, char const* path, char const* iface, char const* prop_name, gate_value_t* ptr_out_value) | ||
| 209 | { | ||
| 210 | static char const* const DBUS_INTERFACE_PROP = "org.freedesktop.DBus.Properties"; | ||
| 211 | static char const* const DBUS_METHOD_GET = "Get"; | ||
| 212 | ✗ | gate_result_t ret = GATE_RESULT_FAILED; | |
| 213 | DBusError err; | ||
| 214 | ✗ | DBusMessage* msg = NULL; | |
| 215 | ✗ | DBusMessage* reply = NULL;; | |
| 216 | DBusMessageIter args_iter, value_iter; | ||
| 217 | |||
| 218 | ✗ | dbus->error_init(&err); | |
| 219 | do | ||
| 220 | { | ||
| 221 | dbus_bool_t succeeded; | ||
| 222 | |||
| 223 | ✗ | msg = dbus->message_new_method_call(bus_name, path, DBUS_INTERFACE_PROP, DBUS_METHOD_GET); | |
| 224 | ✗ | if (NULL == msg) | |
| 225 | { | ||
| 226 | ✗ | GATE_DEBUG_TRACE("dbus_message_new_method_call() FAILED"); | |
| 227 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
| 228 | ✗ | break; | |
| 229 | } | ||
| 230 | |||
| 231 | ✗ | succeeded = dbus->message_append_args(msg, | |
| 232 | DBUS_TYPE_STRING, &iface, | ||
| 233 | DBUS_TYPE_STRING, &prop_name, | ||
| 234 | DBUS_TYPE_INVALID); | ||
| 235 | ✗ | if (!succeeded) | |
| 236 | { | ||
| 237 | ✗ | GATE_DEBUG_TRACE("dbus_message_append_args() FAILED"); | |
| 238 | ✗ | ret = GATE_RESULT_PREPARATIONFAILED; | |
| 239 | ✗ | break; | |
| 240 | } | ||
| 241 | |||
| 242 | ✗ | reply = dbus->connection_send_with_reply_and_block(conn, msg, -1, &err); | |
| 243 | ✗ | if (reply == NULL) | |
| 244 | { | ||
| 245 | ✗ | GATE_DEBUG_TRACE("dbus_connection_send_with_reply_and_block() FAILED"); | |
| 246 | ✗ | GATE_DEBUG_TRACE(err.message); | |
| 247 | ✗ | ret = GATE_RESULT_FAILED; | |
| 248 | ✗ | break; | |
| 249 | } | ||
| 250 | else | ||
| 251 | { | ||
| 252 | /* reply received */ | ||
| 253 | int value_type; | ||
| 254 | DBusBasicValue basic_value; | ||
| 255 | gate_value_t* ptr_value; | ||
| 256 | |||
| 257 | ✗ | if(!dbus->message_iter_init(reply, &args_iter)) | |
| 258 | { | ||
| 259 | ✗ | ret = GATE_RESULT_NOTAVAILABLE; | |
| 260 | ✗ | break; | |
| 261 | } | ||
| 262 | ✗ | dbus->message_iter_recurse(&args_iter, &value_iter); | |
| 263 | |||
| 264 | ✗ | value_type = dbus->message_iter_get_arg_type(&value_iter); | |
| 265 | ✗ | dbus->message_iter_get_basic(&value_iter, &basic_value); | |
| 266 | |||
| 267 | ✗ | ret = GATE_RESULT_OK; /* expect success as default */ | |
| 268 | ✗ | ptr_value = NULL; /* default output value is NULL */ | |
| 269 | ✗ | switch(value_type) /* map dbus value to gate value */ | |
| 270 | { | ||
| 271 | ✗ | case DBUS_TYPE_BYTE: | |
| 272 | { | ||
| 273 | ✗ | const gate_uint8_t b = basic_value.byt; | |
| 274 | ✗ | ptr_value = gate_value_create(GATE_TYPE_UI8, &b, ptr_out_value); | |
| 275 | ✗ | break; | |
| 276 | } | ||
| 277 | ✗ | case DBUS_TYPE_BOOLEAN: | |
| 278 | { | ||
| 279 | ✗ | const gate_bool_t b = basic_value.bool_val; | |
| 280 | ✗ | ptr_value = gate_value_create(GATE_TYPE_BOOL, &b, ptr_out_value); | |
| 281 | ✗ | break; | |
| 282 | } | ||
| 283 | ✗ | case DBUS_TYPE_INT16: | |
| 284 | { | ||
| 285 | ✗ | const gate_int16_t v = basic_value.i16; | |
| 286 | ✗ | ptr_value = gate_value_create(GATE_TYPE_I16, &v, ptr_out_value); | |
| 287 | ✗ | break; | |
| 288 | } | ||
| 289 | ✗ | case DBUS_TYPE_UINT16: | |
| 290 | { | ||
| 291 | ✗ | const gate_uint16_t v = basic_value.u16; | |
| 292 | ✗ | ptr_value = gate_value_create(GATE_TYPE_UI16, &v, ptr_out_value); | |
| 293 | ✗ | break; | |
| 294 | } | ||
| 295 | ✗ | case DBUS_TYPE_INT32: | |
| 296 | { | ||
| 297 | ✗ | const gate_int32_t v = basic_value.i32; | |
| 298 | ✗ | ptr_value = gate_value_create(GATE_TYPE_I32, &v, ptr_out_value); | |
| 299 | ✗ | break; | |
| 300 | } | ||
| 301 | ✗ | case DBUS_TYPE_UINT32: | |
| 302 | { | ||
| 303 | ✗ | const gate_uint32_t v = basic_value.u32; | |
| 304 | ✗ | ptr_value = gate_value_create(GATE_TYPE_UI32, &v, ptr_out_value); | |
| 305 | ✗ | break; | |
| 306 | } | ||
| 307 | ✗ | case DBUS_TYPE_INT64: | |
| 308 | { | ||
| 309 | ✗ | const gate_int64_t v = basic_value.i64; | |
| 310 | ✗ | ptr_value = gate_value_create(GATE_TYPE_UI64, &v, ptr_out_value); | |
| 311 | ✗ | break; | |
| 312 | } | ||
| 313 | ✗ | case DBUS_TYPE_UINT64: | |
| 314 | { | ||
| 315 | ✗ | const gate_uint64_t v = basic_value.i64; | |
| 316 | ✗ | ptr_value = gate_value_create(GATE_TYPE_UI64, &v, ptr_out_value); | |
| 317 | ✗ | break; | |
| 318 | } | ||
| 319 | ✗ | case DBUS_TYPE_DOUBLE: | |
| 320 | { | ||
| 321 | ✗ | const gate_real64_t v = basic_value.dbl; | |
| 322 | ✗ | ptr_value = gate_value_create(GATE_TYPE_R64, &v, ptr_out_value); | |
| 323 | ✗ | break; | |
| 324 | } | ||
| 325 | ✗ | case DBUS_TYPE_STRING: | |
| 326 | case DBUS_TYPE_OBJECT_PATH: | ||
| 327 | case DBUS_TYPE_SIGNATURE: | ||
| 328 | { | ||
| 329 | gate_string_t str; | ||
| 330 | ✗ | if (NULL != gate_string_create(&str, basic_value.str, gate_str_length(basic_value.str))) | |
| 331 | { | ||
| 332 | ✗ | ptr_value = gate_value_create(GATE_TYPE_STRING, &str, ptr_out_value); | |
| 333 | ✗ | gate_string_release(&str); | |
| 334 | } | ||
| 335 | ✗ | break; | |
| 336 | } | ||
| 337 | ✗ | case DBUS_TYPE_UNIX_FD: | |
| 338 | { | ||
| 339 | ✗ | const gate_uintptr_t v = (gate_uintptr_t)(gate_intptr_t)basic_value.fd; | |
| 340 | ✗ | ptr_value = gate_value_create(GATE_TYPE_ADDRESS, &v, ptr_out_value); | |
| 341 | ✗ | break; | |
| 342 | } | ||
| 343 | ✗ | default: | |
| 344 | { | ||
| 345 | ✗ | ret = GATE_RESULT_NOTSUPPORTED; | |
| 346 | ✗ | break; | |
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | ✗ | if (GATE_SUCCEEDED(ret)) | |
| 351 | { | ||
| 352 | ✗ | if (ptr_value == NULL) | |
| 353 | { | ||
| 354 | /* failed to create gate_value_t */ | ||
| 355 | ✗ | ret = GATE_RESULT_OUTOFMEMORY; | |
| 356 | } | ||
| 357 | } | ||
| 358 | } | ||
| 359 | } while (0); | ||
| 360 | |||
| 361 | ✗ | if (reply) dbus->message_unref(reply); | |
| 362 | ✗ | if (msg) dbus->message_unref(msg); | |
| 363 | ✗ | dbus->error_free(&err); | |
| 364 | |||
| 365 | ✗ | return ret; | |
| 366 | } | ||
| 367 | |||
| 368 | |||
| 369 | #endif | ||
| 370 |