bluez: fix calling of bdaddr added/removed signals in nm-bluez4-adapter

Fix several issues with emitting the BDADDR_ADDED/BDADDR_REMOVED
signals:

 - when removing a device, the handlers were never disconnected from
   the device's notify::usable and initialized signals.
 - ensure that the signals BDADDR_ADDED/BDADDR_REMOVED only get emitted
   in a consistent way (toggeling). Before, there was a bug, that the
   signal BDADDR_REMOVED was emitted for devices that were never added
   and never usable.

Co-Authored-By: Dan Williams <dcbw@redhat.com>
Signed-off-by: Thomas Haller <thaller@redhat.com>
This commit is contained in:
Thomas Haller 2013-10-08 20:43:22 +02:00
parent 28a6f11b2c
commit 4ba86e2cc8

View file

@ -64,6 +64,8 @@ enum {
}; };
static guint signals[LAST_SIGNAL] = { 0 }; static guint signals[LAST_SIGNAL] = { 0 };
static void device_do_remove (NMBluez4Adapter *self, NMBluezDevice *device);
const char * const char *
nm_bluez4_adapter_get_path (NMBluez4Adapter *self) nm_bluez4_adapter_get_path (NMBluez4Adapter *self)
{ {
@ -103,36 +105,54 @@ nm_bluez4_adapter_get_devices (NMBluez4Adapter *self)
return devices; return devices;
} }
static void
emit_device_removed (NMBluez4Adapter *self, NMBluezDevice *device)
{
nm_log_dbg (LOGD_BT, "(%s): bluez device now unusable",
nm_bluez_device_get_path (device));
g_signal_emit (self, signals[DEVICE_REMOVED], 0, device);
}
static void static void
device_usable (NMBluezDevice *device, GParamSpec *pspec, gpointer user_data) device_usable (NMBluezDevice *device, GParamSpec *pspec, gpointer user_data)
{ {
NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data);
gboolean usable = nm_bluez_device_get_usable (device);
nm_log_dbg (LOGD_BT, "(%s): bluez device now %s", if (nm_bluez_device_get_usable (device)) {
nm_bluez_device_get_path (device), nm_log_dbg (LOGD_BT, "(%s): bluez device now usable (device address is %s)",
usable ? "usable" : "unusable"); nm_bluez_device_get_path (device),
nm_bluez_device_get_address (device));
if (usable) {
nm_log_dbg (LOGD_BT, "(%s): bluez device address %s",
nm_bluez_device_get_path (device),
nm_bluez_device_get_address (device));
g_signal_emit (self, signals[DEVICE_ADDED], 0, device); g_signal_emit (self, signals[DEVICE_ADDED], 0, device);
} else } else
g_signal_emit (self, signals[DEVICE_REMOVED], 0, device); emit_device_removed (self, device);
} }
static void static void
device_initialized (NMBluezDevice *device, gboolean success, gpointer user_data) device_initialized (NMBluezDevice *device, gboolean success, gpointer user_data)
{ {
NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data); NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (user_data);
NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self);
nm_log_dbg (LOGD_BT, "(%s): bluez device %s", nm_log_dbg (LOGD_BT, "(%s): bluez device %s",
nm_bluez_device_get_path (device), nm_bluez_device_get_path (device),
success ? "initialized" : "failed to initialize"); success ? "initialized" : "failed to initialize");
if (!success) if (!success)
g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device)); device_do_remove (self, device);
}
static void
device_do_remove (NMBluez4Adapter *self, NMBluezDevice *device)
{
NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self);
if (g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device))) {
g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_initialized), self);
g_signal_handlers_disconnect_by_func (device, G_CALLBACK (device_usable), self);
if (nm_bluez_device_get_usable (device))
emit_device_removed (self, device);
g_object_unref (device);
}
} }
static void static void
@ -160,12 +180,8 @@ device_removed (DBusGProxy *proxy, const char *path, gpointer user_data)
nm_log_dbg (LOGD_BT, "(%s): bluez device removed", path); nm_log_dbg (LOGD_BT, "(%s): bluez device removed", path);
device = g_hash_table_lookup (priv->devices, path); device = g_hash_table_lookup (priv->devices, path);
if (device) { if (device)
g_object_ref (device); device_do_remove (self, device);
g_hash_table_remove (priv->devices, nm_bluez_device_get_path (device));
g_signal_emit (self, signals[DEVICE_REMOVED], 0, device);
g_object_unref (device);
}
} }
@ -268,7 +284,13 @@ nm_bluez4_adapter_init (NMBluez4Adapter *self)
NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self);
priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal, priv->devices = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL, g_object_unref); NULL, NULL);
}
static gboolean
_find_all (gpointer key, gpointer value, gpointer user_data)
{
return TRUE;
} }
static void static void
@ -276,13 +298,10 @@ dispose (GObject *object)
{ {
NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (object); NMBluez4Adapter *self = NM_BLUEZ4_ADAPTER (object);
NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self); NMBluez4AdapterPrivate *priv = NM_BLUEZ4_ADAPTER_GET_PRIVATE (self);
GHashTableIter iter;
NMBluezDevice *device; NMBluezDevice *device;
g_hash_table_iter_init (&iter, priv->devices); while ((device = g_hash_table_find (priv->devices, _find_all, NULL)))
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &device)) device_do_remove (self, device);
g_signal_emit (self, signals[DEVICE_REMOVED], 0, device);
g_hash_table_remove_all (priv->devices);
G_OBJECT_CLASS (nm_bluez4_adapter_parent_class)->dispose (object); G_OBJECT_CLASS (nm_bluez4_adapter_parent_class)->dispose (object);
} }