From 2d041e37d04e869241a88d4e8bebea3633728632 Mon Sep 17 00:00:00 2001 From: Olivier Martin Date: Thu, 15 Feb 2024 21:44:34 +0100 Subject: [PATCH] error: Introduce error module to catch DBUS error details --- bluez/gattlib_discover.c | 8 +++--- dbus/gattlib.c | 44 ++++++++++++++++++++++++--------- dbus/gattlib_adapter.c | 33 ++++++++++++++----------- dbus/gattlib_char.c | 33 +++++++++++++++++++------ dbus/gattlib_internal.h | 2 +- dbus/gattlib_notification.c | 4 ++- dbus/gattlib_stream.c | 7 ++++-- gattlib-py/gattlib/exception.py | 24 +++++++++++++----- include/gattlib.h | 27 ++++++++++++-------- 9 files changed, 124 insertions(+), 58 deletions(-) diff --git a/bluez/gattlib_discover.c b/bluez/gattlib_discover.c index 9c7cfcd0..7075220b 100644 --- a/bluez/gattlib_discover.c +++ b/bluez/gattlib_discover.c @@ -85,7 +85,7 @@ int gattlib_discover_primary(gatt_connection_t* connection, gattlib_primary_serv ret = gatt_discover_primary(conn_context->attrib, NULL, primary_all_cb, &user_data); if (ret == 0) { GATTLIB_LOG(GATTLIB_ERROR, "Fail to discover primary services."); - return GATTLIB_ERROR_BLUEZ; + return GATTLIB_ERROR_BLUEZ_WITH_ERROR(ret); } // Wait for completion @@ -157,11 +157,11 @@ int gattlib_discover_char_range(gatt_connection_t* connection, int start, int en ret = gatt_discover_char(conn_context->attrib, start, end, NULL, characteristic_cb, &user_data); if (ret == 0) { GATTLIB_LOG(GATTLIB_ERROR, "Fail to discover characteristics."); - return GATTLIB_ERROR_BLUEZ; + return GATTLIB_ERROR_BLUEZ_WITH_ERROR(ret); } // Wait for completion - while(user_data.discovered == FALSE) { + while(user_data.discovered == FALSE) { g_main_context_iteration(g_gattlib_thread.loop_context, FALSE); } *characteristics = user_data.characteristics; @@ -278,7 +278,7 @@ int gattlib_discover_desc_range(gatt_connection_t* connection, int start, int en #endif if (ret == 0) { fprintf(stderr, "Fail to discover descriptors.\n"); - return GATTLIB_ERROR_BLUEZ; + return GATTLIB_ERROR_BLUEZ_WITH_ERROR(ret); } // Wait for completion diff --git a/dbus/gattlib.c b/dbus/gattlib.c index 6261054f..c5f76a6b 100644 --- a/dbus/gattlib.c +++ b/dbus/gattlib.c @@ -24,6 +24,7 @@ static void* glib_event_thread(void* main_loop_p) { static void _on_device_connect(gatt_connection_t* connection) { gattlib_context_t* conn_context = connection->context; GDBusObjectManager *device_manager; + GError *error = NULL; // Stop the timeout for connection if (conn_context->connection_timeout) { @@ -32,10 +33,14 @@ static void _on_device_connect(gatt_connection_t* connection) { } // Get list of objects belonging to Device Manager - device_manager = get_device_manager_from_adapter(conn_context->adapter); + device_manager = get_device_manager_from_adapter(conn_context->adapter, &error); if (device_manager == NULL) { - GATTLIB_LOG(GATTLIB_DEBUG, "gattlib_connect: Failed to get device manager from adapter"); - + if (error != NULL) { + GATTLIB_LOG(GATTLIB_ERROR, "gattlib_connect: Failed to get device manager from adapter (%d, %d).", error->domain, error->code); + g_error_free(error); + } else { + GATTLIB_LOG(GATTLIB_ERROR, "gattlib_connect: Failed to get device manager from adapter"); + } //TODO: Free device return; } @@ -423,17 +428,24 @@ int gattlib_discover_primary(gatt_connection_t* connection, gattlib_primary_serv } gattlib_context_t* conn_context = connection->context; - GDBusObjectManager *device_manager = get_device_manager_from_adapter(conn_context->adapter); + GError *error = NULL; + GDBusObjectManager *device_manager = get_device_manager_from_adapter(conn_context->adapter, &error); OrgBluezDevice1* device = conn_context->device; const gchar* const* service_str; - GError *error = NULL; int ret = GATTLIB_SUCCESS; const gchar* const* service_strs = org_bluez_device1_get_uuids(device); if (device_manager == NULL) { - GATTLIB_LOG(GATTLIB_ERROR, "Gattlib context not initialized."); - return GATTLIB_INVALID_PARAMETER; + if (error != NULL) { + ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error); + GATTLIB_LOG(GATTLIB_ERROR, "Gattlib Context not initialized (%d, %d).", error->domain, error->code); + g_error_free(error); + } else { + ret = GATTLIB_ERROR_DBUS; + GATTLIB_LOG(GATTLIB_ERROR, "Gattlib Context not initialized."); + } + return ret; } if (service_strs == NULL) { @@ -808,13 +820,21 @@ static void add_characteristics_from_service(gattlib_context_t* conn_context, GD int gattlib_discover_char_range(gatt_connection_t* connection, int start, int end, gattlib_characteristic_t** characteristics, int* characteristics_count) { gattlib_context_t* conn_context = connection->context; - GDBusObjectManager *device_manager = get_device_manager_from_adapter(conn_context->adapter); GError *error = NULL; + GDBusObjectManager *device_manager = get_device_manager_from_adapter(conn_context->adapter, &error); GList *l; + int ret; if (device_manager == NULL) { - GATTLIB_LOG(GATTLIB_ERROR, "Gattlib context not initialized."); - return GATTLIB_INVALID_PARAMETER; + if (error != NULL) { + ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error); + GATTLIB_LOG(GATTLIB_ERROR, "Gattlib Context not initialized (%d, %d).", error->domain, error->code); + g_error_free(error); + } else { + ret = GATTLIB_ERROR_DBUS; + GATTLIB_LOG(GATTLIB_ERROR, "Gattlib Context not initialized."); + } + return ret; } // Count the maximum number of characteristic to allocate the array (we count all the characterstic for all devices) @@ -923,6 +943,7 @@ int get_bluez_device_from_mac(struct gattlib_adapter *adapter, const char *mac_a { GError *error = NULL; char object_path[100]; + int ret; if (adapter != NULL) { get_device_path_from_mac_with_adapter(adapter->adapter_proxy, mac_address, object_path, sizeof(object_path)); @@ -938,9 +959,10 @@ int get_bluez_device_from_mac(struct gattlib_adapter *adapter, const char *mac_a NULL, &error); if (error) { + ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error); GATTLIB_LOG(GATTLIB_ERROR, "Failed to connection to new DBus Bluez Device: %s", error->message); g_error_free(error); - return GATTLIB_ERROR_DBUS; + return ret; } return GATTLIB_SUCCESS; diff --git a/dbus/gattlib_adapter.c b/dbus/gattlib_adapter.c index 54e21a57..5ed0626b 100644 --- a/dbus/gattlib_adapter.c +++ b/dbus/gattlib_adapter.c @@ -29,13 +29,15 @@ int gattlib_adapter_open(const char* adapter_name, void** adapter) { object_path, NULL, &error); if (adapter_proxy == NULL) { + int ret = GATTLIB_ERROR_DBUS; if (error) { GATTLIB_LOG(GATTLIB_ERROR, "Failed to get adapter %s: %s", object_path, error->message); + ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error); g_error_free(error); } else { GATTLIB_LOG(GATTLIB_ERROR, "Failed to get adapter %s", object_path); } - return GATTLIB_ERROR_DBUS; + return ret; } // Ensure the adapter is powered on @@ -71,9 +73,7 @@ struct gattlib_adapter *init_default_adapter(void) { } } -GDBusObjectManager *get_device_manager_from_adapter(struct gattlib_adapter *gattlib_adapter) { - GError *error = NULL; - +GDBusObjectManager *get_device_manager_from_adapter(struct gattlib_adapter *gattlib_adapter, GError **error) { if (gattlib_adapter->device_manager) { return gattlib_adapter->device_manager; } @@ -89,14 +89,8 @@ GDBusObjectManager *get_device_manager_from_adapter(struct gattlib_adapter *gatt "org.bluez", "/", NULL, NULL, NULL, NULL, - &error); + error); if (gattlib_adapter->device_manager == NULL) { - if (error) { - GATTLIB_LOG(GATTLIB_ERROR, "Failed to get Bluez Device Manager: %s", error->message); - g_error_free(error); - } else { - GATTLIB_LOG(GATTLIB_ERROR, "Failed to get Bluez Device Manager."); - } return NULL; } @@ -266,6 +260,7 @@ static int _gattlib_adapter_scan_enable_with_filter(void *adapter, uuid_t **uuid GError *error = NULL; GVariantBuilder arg_properties_builder; GVariant *rssi_variant = NULL; + int ret; g_variant_builder_init(&arg_properties_builder, G_VARIANT_TYPE("a{sv}")); @@ -296,10 +291,11 @@ static int _gattlib_adapter_scan_enable_with_filter(void *adapter, uuid_t **uuid } if (error) { + ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error); GATTLIB_LOG(GATTLIB_ERROR, "Failed to set discovery filter: %s (%d.%d)", error->message, error->domain, error->code); g_error_free(error); - return GATTLIB_ERROR_DBUS; + return ret; } // @@ -307,9 +303,15 @@ static int _gattlib_adapter_scan_enable_with_filter(void *adapter, uuid_t **uuid // We should get notified when the connection is lost with the target to allow // us to advertise us again // - device_manager = get_device_manager_from_adapter(gattlib_adapter); + device_manager = get_device_manager_from_adapter(gattlib_adapter, &error); if (device_manager == NULL) { - return GATTLIB_ERROR_DBUS; + if (error != NULL) { + ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error); + g_error_free(error); + } else { + ret = GATTLIB_ERROR_DBUS; + } + return ret; } // Clear BLE scan structure @@ -333,9 +335,10 @@ static int _gattlib_adapter_scan_enable_with_filter(void *adapter, uuid_t **uuid // Now, start BLE discovery org_bluez_adapter1_call_start_discovery_sync(gattlib_adapter->adapter_proxy, NULL, &error); if (error) { + ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error); GATTLIB_LOG(GATTLIB_ERROR, "Failed to start discovery: %s", error->message); g_error_free(error); - return GATTLIB_ERROR_DBUS; + return ret; } return GATTLIB_SUCCESS; diff --git a/dbus/gattlib_char.c b/dbus/gattlib_char.c index 670ecd23..5fcc6172 100644 --- a/dbus/gattlib_char.c +++ b/dbus/gattlib_char.c @@ -103,8 +103,8 @@ static bool handle_dbus_battery_from_uuid(gattlib_context_t* conn_context, const struct dbus_characteristic get_characteristic_from_uuid(gatt_connection_t* connection, const uuid_t* uuid) { gattlib_context_t* conn_context = connection->context; - GDBusObjectManager *device_manager = get_device_manager_from_adapter(conn_context->adapter); GError *error = NULL; + GDBusObjectManager *device_manager = get_device_manager_from_adapter(conn_context->adapter, &error); bool is_battery_level_uuid = false; struct dbus_characteristic dbus_characteristic = { @@ -112,7 +112,12 @@ struct dbus_characteristic get_characteristic_from_uuid(gatt_connection_t* conne }; if (device_manager == NULL) { - GATTLIB_LOG(GATTLIB_ERROR, "Gattlib Context not initialized."); + if (error != NULL) { + GATTLIB_LOG(GATTLIB_ERROR, "Gattlib Context not initialized (%d, %d).", error->domain, error->code); + g_error_free(error); + } else { + GATTLIB_LOG(GATTLIB_ERROR, "Gattlib Context not initialized."); + } return dbus_characteristic; // Return characteristic of type TYPE_NONE } @@ -163,8 +168,8 @@ struct dbus_characteristic get_characteristic_from_uuid(gatt_connection_t* conne static struct dbus_characteristic get_characteristic_from_handle(gatt_connection_t* connection, int handle) { gattlib_context_t* conn_context = connection->context; - GDBusObjectManager *device_manager = get_device_manager_from_adapter(conn_context->adapter); GError *error = NULL; + GDBusObjectManager *device_manager = get_device_manager_from_adapter(conn_context->adapter, &error); int char_handle; struct dbus_characteristic dbus_characteristic = { @@ -172,7 +177,12 @@ static struct dbus_characteristic get_characteristic_from_handle(gatt_connection }; if (device_manager == NULL) { - GATTLIB_LOG(GATTLIB_ERROR, "Gattlib context not initialized."); + if (error != NULL) { + GATTLIB_LOG(GATTLIB_ERROR, "Gattlib Context not initialized (%d, %d).", error->domain, error->code); + g_error_free(error); + } else { + GATTLIB_LOG(GATTLIB_ERROR, "Gattlib Context not initialized."); + } return dbus_characteristic; } @@ -219,9 +229,10 @@ static int read_gatt_characteristic(struct dbus_characteristic *dbus_characteris g_variant_builder_unref(options); #endif if (error != NULL) { + ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error); GATTLIB_LOG(GATTLIB_ERROR, "Failed to read DBus GATT characteristic: %s", error->message); g_error_free(error); - return GATTLIB_ERROR_DBUS; + return ret; } gsize n_elements = 0; @@ -320,9 +331,9 @@ int gattlib_read_char_by_uuid_async(gatt_connection_t* connection, uuid_t* uuid, g_variant_builder_unref(options); #endif if (error != NULL) { + ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error); GATTLIB_LOG(GATTLIB_ERROR, "Failed to read DBus GATT characteristic: %s", error->message); g_error_free(error); - ret = GATTLIB_ERROR_DBUS; goto EXIT; } @@ -359,9 +370,15 @@ static int write_char(struct dbus_characteristic *dbus_characteristic, const voi #endif if (error != NULL) { - GATTLIB_LOG(GATTLIB_ERROR, "Failed to write DBus GATT characteristic: %s", error->message); + if ((error->domain == 238) && (error->code == 36)) { + ret = GATTLIB_DEVICE_NOT_CONNECTED; + } else { + GATTLIB_LOG(GATTLIB_ERROR, "Failed to write DBus GATT characteristic: %s (%d,%d)", + error->message, error->domain, error->code); + ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error); + } g_error_free(error); - return GATTLIB_ERROR_DBUS; + return ret; } // diff --git a/dbus/gattlib_internal.h b/dbus/gattlib_internal.h index 2bca3ff0..772f3723 100644 --- a/dbus/gattlib_internal.h +++ b/dbus/gattlib_internal.h @@ -103,7 +103,7 @@ struct dbus_characteristic { extern const uuid_t m_battery_level_uuid; struct gattlib_adapter *init_default_adapter(void); -GDBusObjectManager *get_device_manager_from_adapter(struct gattlib_adapter *gattlib_adapter); +GDBusObjectManager *get_device_manager_from_adapter(struct gattlib_adapter *gattlib_adapter, GError **error); void get_device_path_from_mac_with_adapter(OrgBluezAdapter1* adapter, const char *mac_address, char *object_path, size_t object_path_len); void get_device_path_from_mac(const char *adapter_name, const char *mac_address, char *object_path, size_t object_path_len); diff --git a/dbus/gattlib_notification.c b/dbus/gattlib_notification.c index 818bf6bd..df32c8f6 100644 --- a/dbus/gattlib_notification.c +++ b/dbus/gattlib_notification.c @@ -148,6 +148,7 @@ static gboolean on_handle_characteristic_indication( static int connect_signal_to_characteristic_uuid(gatt_connection_t* connection, const uuid_t* uuid, void *callback) { gattlib_context_t* conn_context = connection->context; + int ret; assert(callback != NULL); @@ -197,9 +198,10 @@ static int connect_signal_to_characteristic_uuid(gatt_connection_t* connection, GError *error = NULL; org_bluez_gatt_characteristic1_call_start_notify_sync(dbus_characteristic.gatt, NULL, &error); if (error) { + ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error); GATTLIB_LOG(GATTLIB_ERROR, "Failed to start DBus GATT notification: %s", error->message); g_error_free(error); - return GATTLIB_ERROR_DBUS; + return ret; } else { return GATTLIB_SUCCESS; } diff --git a/dbus/gattlib_stream.c b/dbus/gattlib_stream.c index c31dbeda..23677427 100644 --- a/dbus/gattlib_stream.c +++ b/dbus/gattlib_stream.c @@ -33,6 +33,7 @@ int gattlib_write_char_by_uuid_stream_open(gatt_connection_t* connection, uuid_t GError *error = NULL; GUnixFDList *fd_list; GVariant *out_fd; + int ret; int fd; GVariantBuilder *variant_options = g_variant_builder_new(G_VARIANT_TYPE("a{sv}")); @@ -48,17 +49,19 @@ int gattlib_write_char_by_uuid_stream_open(gatt_connection_t* connection, uuid_t g_variant_builder_unref(variant_options); if (error != NULL) { + ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error); GATTLIB_LOG(GATTLIB_ERROR, "Failed to acquired write DBus GATT characteristic: %s", error->message); g_error_free(error); - return GATTLIB_ERROR_DBUS; + return ret; } error = NULL; fd = g_unix_fd_list_get(fd_list, g_variant_get_handle(out_fd), &error); if (error != NULL) { + ret = GATTLIB_ERROR_DBUS_WITH_ERROR(error); GATTLIB_LOG(GATTLIB_ERROR, "Failed to retrieve Unix File Descriptor: %s", error->message); g_error_free(error); - return GATTLIB_ERROR_DBUS; + return ret; } // We abuse the pointer 'stream' to pass the 'File Descriptor' diff --git a/gattlib-py/gattlib/exception.py b/gattlib-py/gattlib/exception.py index 7054567b..4fb34ec3 100644 --- a/gattlib-py/gattlib/exception.py +++ b/gattlib-py/gattlib/exception.py @@ -11,9 +11,12 @@ GATTLIB_OUT_OF_MEMORY = 4 GATTLIB_NOT_SUPPORTED = 5 GATTLIB_DEVICE_ERROR = 6 -GATTLIB_ERROR_DBUS = 7 -GATTLIB_ERROR_BLUEZ = 8 -GATTLIB_ERROR_INTERNAL = 9 +GATTLIB_DEVICE_NOT_CONNECTED = 7 + +GATTLIB_ERROR_MODULE_MASK = 0xF0000000 +GATTLIB_ERROR_DBUS = 0x10000000 +GATTLIB_ERROR_BLUEZ = 0x20000000 +GATTLIB_ERROR_INTERNAL = 0x80000000 class GattlibException(Exception): @@ -39,6 +42,8 @@ class OutOfMemory(GattlibException): class NotSupported(GattlibException): pass +class NotConnected(GattlibException): + pass class DeviceError(GattlibException): def __init__(self, adapter: str = None, mac_address: str = None) -> None: @@ -49,7 +54,12 @@ def __str__(self) -> str: return f"Error with device {self.mac_address} on adapter {self.adapter}" class DBusError(GattlibException): - pass + def __init__(self, domain: int, code: int) -> None: + self.domain = domain + self.code = code + + def __str__(self) -> str: + return f"DBus Error domain={self.domain},code={self.code}" def handle_return(ret): @@ -65,8 +75,10 @@ def handle_return(ret): raise NotSupported() elif ret == GATTLIB_DEVICE_ERROR: raise DeviceError() - elif ret == GATTLIB_ERROR_DBUS: - raise DBusError() + elif ret == GATTLIB_DEVICE_NOT_CONNECTED: + raise NotConnected() + elif (ret & GATTLIB_ERROR_MODULE_MASK) == GATTLIB_ERROR_DBUS: + raise DBusError((ret >> 8) & 0xFFF, ret & 0xFFFF) elif ret == -22: # From '-EINVAL' raise ValueError("Gattlib value error") elif ret != 0: diff --git a/include/gattlib.h b/include/gattlib.h index 4df3c3ea..cfa52445 100644 --- a/include/gattlib.h +++ b/include/gattlib.h @@ -35,16 +35,23 @@ extern "C" { * @name Gattlib errors */ //@{ -#define GATTLIB_SUCCESS 0 -#define GATTLIB_INVALID_PARAMETER 1 -#define GATTLIB_NOT_FOUND 2 -#define GATTLIB_ERROR_TIMEOUT 3 -#define GATTLIB_OUT_OF_MEMORY 4 -#define GATTLIB_NOT_SUPPORTED 5 -#define GATTLIB_DEVICE_ERROR 6 -#define GATTLIB_ERROR_DBUS 7 -#define GATTLIB_ERROR_BLUEZ 8 -#define GATTLIB_ERROR_INTERNAL 9 +#define GATTLIB_SUCCESS 0 +#define GATTLIB_INVALID_PARAMETER 1 +#define GATTLIB_NOT_FOUND 2 +#define GATTLIB_ERROR_TIMEOUT 3 +#define GATTLIB_OUT_OF_MEMORY 4 +#define GATTLIB_NOT_SUPPORTED 5 +#define GATTLIB_DEVICE_ERROR 6 +#define GATTLIB_DEVICE_NOT_CONNECTED 7 +#define GATTLIB_ERROR_MODULE_MASK 0xF0000000 +#define GATTLIB_ERROR_DBUS 0x10000000 +#define GATTLIB_ERROR_BLUEZ 0x20000000 +#define GATTLIB_ERROR_INTERNAL 0x80000000 + +#define GATTLIB_ERROR_DBUS_WITH_ERROR(error) \ + (GATTLIB_ERROR_DBUS | (error->domain << 8) | (error->code)) +#define GATTLIB_ERROR_BLUEZ_WITH_ERROR(ret) \ + (GATTLIB_ERROR_BLUEZ | (ret)) //@} /**