From c3958aaa07373d4b77e6d8b753e13f48d624523a Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 1 Jul 2009 02:20:23 +0200 Subject: bluetooth: handle absence of bluez D-Bus service properly --- src/modules/bluetooth/bluetooth-util.c | 77 +++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 11 deletions(-) (limited to 'src/modules/bluetooth') diff --git a/src/modules/bluetooth/bluetooth-util.c b/src/modules/bluetooth/bluetooth-util.c index 5c7681d4..66e1c31e 100644 --- a/src/modules/bluetooth/bluetooth-util.c +++ b/src/modules/bluetooth/bluetooth-util.c @@ -309,6 +309,17 @@ static void run_callback(pa_bluetooth_discovery *y, pa_bluetooth_device *d, pa_b pa_hook_fire(&y->hook, d); } +static void remove_all_devices(pa_bluetooth_discovery *y) { + pa_bluetooth_device *d; + + pa_assert(y); + + while ((d = pa_hashmap_steal_first(y->devices))) { + run_callback(y, d, TRUE); + device_free(d); + } +} + static void get_properties_reply(DBusPendingCall *pending, void *userdata) { DBusMessage *r; DBusMessageIter arg_i, element_i; @@ -332,6 +343,12 @@ static void get_properties_reply(DBusPendingCall *pending, void *userdata) { if (dbus_message_is_method_call(p->message, "org.bluez.Device", "GetProperties")) d->device_info_valid = valid; + if (dbus_message_is_error(r, DBUS_ERROR_SERVICE_UNKNOWN)) { + pa_log_debug("Bluetooth daemon is apparently not available."); + remove_all_devices(y); + goto finish2; + } + if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { if (!dbus_message_is_error(r, DBUS_ERROR_UNKNOWN_METHOD)) @@ -383,6 +400,7 @@ static void get_properties_reply(DBusPendingCall *pending, void *userdata) { finish: run_callback(y, d, FALSE); +finish2: dbus_message_unref(r); PA_LLIST_REMOVE(pa_dbus_pending, y->pending, p); @@ -412,6 +430,9 @@ static void found_device(pa_bluetooth_discovery *y, const char* path) { pa_assert(y); pa_assert(path); + if (pa_hashmap_get(y->devices, path)) + return; + d = device_new(path); pa_hashmap_put(y->devices, d->path, d); @@ -439,9 +460,15 @@ static void list_devices_reply(DBusPendingCall *pending, void *userdata) { pa_assert_se(y = p->context_data); pa_assert_se(r = dbus_pending_call_steal_reply(pending)); + if (dbus_message_is_error(r, DBUS_ERROR_SERVICE_UNKNOWN)) { + pa_log_debug("Bluetooth daemon is apparently not available."); + remove_all_devices(y); + goto finish; + } + if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { pa_log("Error from ListDevices reply: %s", dbus_message_get_error_name(r)); - goto end; + goto finish; } if (!dbus_message_get_args(r, &e, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &paths, &num, DBUS_TYPE_INVALID)) { @@ -454,7 +481,7 @@ static void list_devices_reply(DBusPendingCall *pending, void *userdata) { found_device(y, paths[i]); } -end: +finish: if (paths) dbus_free_string_array (paths); @@ -487,9 +514,15 @@ static void list_adapters_reply(DBusPendingCall *pending, void *userdata) { pa_assert_se(y = p->context_data); pa_assert_se(r = dbus_pending_call_steal_reply(pending)); + if (dbus_message_is_error(r, DBUS_ERROR_SERVICE_UNKNOWN)) { + pa_log_debug("Bluetooth daemon is apparently not available."); + remove_all_devices(y); + goto finish; + } + if (dbus_message_get_type(r) == DBUS_MESSAGE_TYPE_ERROR) { pa_log("Error from ListAdapters reply: %s", dbus_message_get_error_name(r)); - goto end; + goto finish; } if (!dbus_message_get_args(r, &e, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &paths, &num, DBUS_TYPE_INVALID)) { @@ -502,7 +535,7 @@ static void list_adapters_reply(DBusPendingCall *pending, void *userdata) { found_adapter(y, paths[i]); } -end: +finish: if (paths) dbus_free_string_array (paths); @@ -615,6 +648,32 @@ static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *m, void *us run_callback(y, d, FALSE); } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + } else if (dbus_message_is_signal(m, "org.freedesktop.DBus", "NameOwnerChanged")) { + const char *name, *old_owner, *new_owner; + + if (!dbus_message_get_args(m, &err, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &old_owner, + DBUS_TYPE_STRING, &new_owner, + DBUS_TYPE_INVALID)) { + pa_log("Failed to parse org.freedesktop.DBus.NameOwnerChanged: %s", err.message); + goto fail; + } + + if (pa_streq(name, "org.bluez")) { + if (old_owner && *old_owner) { + pa_log_debug("Bluetooth daemon disappeared."); + remove_all_devices(y); + } + + if (new_owner && *new_owner) { + pa_log_debug("Bluetooth daemon appeared."); + list_adapters(y); + } + } + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -699,6 +758,7 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_get(pa_core *c) { if (pa_dbus_add_matches( pa_dbus_connection_get(y->connection), &err, + "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged'", "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterAdded'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceCreated'", @@ -734,8 +794,6 @@ pa_bluetooth_discovery* pa_bluetooth_discovery_ref(pa_bluetooth_discovery *y) { } void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) { - pa_bluetooth_device *d; - pa_assert(y); pa_assert(PA_REFCNT_VALUE(y) > 0); @@ -745,16 +803,13 @@ void pa_bluetooth_discovery_unref(pa_bluetooth_discovery *y) { pa_dbus_free_pending_list(&y->pending); if (y->devices) { - while ((d = pa_hashmap_steal_first(y->devices))) { - run_callback(y, d, TRUE); - device_free(d); - } - + remove_all_devices(y); pa_hashmap_free(y->devices, NULL, NULL); } if (y->connection) { pa_dbus_remove_matches(pa_dbus_connection_get(y->connection), + "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged'", "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterAdded'", "type='signal',sender='org.bluez',interface='org.bluez.Manager',member='AdapterRemoved'", "type='signal',sender='org.bluez',interface='org.bluez.Adapter',member='DeviceRemoved'", -- cgit