diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2009-09-04 18:50:56 +0300 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@nokia.com> | 2009-09-04 18:50:56 +0300 |
commit | 88d7897d4c6e129c52d7f84a670d49e712e27fd1 (patch) | |
tree | 60b5c66b9f06a0caf34db4e2af4b83cdd5aa8286 | |
parent | 966ccc91a4a879574531c1af1ef024b29ff0e77b (diff) | |
download | bluez-88d7897d4c6e129c52d7f84a670d49e712e27fd1.tar.gz |
Fix audio connection authorization handling with timeouts
When manager.c (HFP/HSP), avdtp.c (A2DP) or control.c wants to cancel an
authorization request it shouldnd't affect the requests of the other
modules. So btd_cancel_authorization cannot be used. This patch adds a new
cancellation function to device.c which will remove the specific callback
from the list and only if the list is empty call btd_cancel_authorization.
-rw-r--r-- | audio/avdtp.c | 16 | ||||
-rw-r--r-- | audio/control.c | 13 | ||||
-rw-r--r-- | audio/device.c | 32 | ||||
-rw-r--r-- | audio/device.h | 5 | ||||
-rw-r--r-- | audio/manager.c | 25 |
5 files changed, 87 insertions, 4 deletions
diff --git a/audio/avdtp.c b/audio/avdtp.c index 0ee81c04a..0fd4b9490 100644 --- a/audio/avdtp.c +++ b/audio/avdtp.c @@ -423,6 +423,7 @@ static void connection_lost(struct avdtp *session, int err); static void avdtp_sep_set_state(struct avdtp *session, struct avdtp_local_sep *sep, avdtp_state_t state); +static void auth_cb(DBusError *derr, void *user_data); static struct avdtp_server *find_server(GSList *list, const bdaddr_t *src) { @@ -974,12 +975,16 @@ static void release_stream(struct avdtp_stream *stream, struct avdtp *session) static void connection_lost(struct avdtp *session, int err) { char address[18]; + struct audio_device *dev; ba2str(&session->dst, address); debug("Disconnected from %s", address); - if (session->state == AVDTP_SESSION_STATE_CONNECTING && err != EACCES) - btd_cancel_authorization(&session->server->src, &session->dst); + dev = manager_get_device(&session->server->src, &session->dst, FALSE); + + if (dev != NULL && session->state == AVDTP_SESSION_STATE_CONNECTING && + err != EACCES) + audio_device_cancel_authorization(dev, auth_cb, session); session->free_lock = 1; @@ -1028,8 +1033,11 @@ void avdtp_unref(struct avdtp *session) if (session->ref == 1) { if (session->state == AVDTP_SESSION_STATE_CONNECTING && session->io) { - btd_cancel_authorization(&session->server->src, - &session->dst); + struct audio_device *dev; + dev = manager_get_device(&session->server->src, + &session->dst, FALSE); + audio_device_cancel_authorization(dev, auth_cb, + session); g_io_channel_shutdown(session->io, TRUE, NULL); g_io_channel_unref(session->io); session->io = NULL; diff --git a/audio/control.c b/audio/control.c index d7161c08a..efaf719d6 100644 --- a/audio/control.c +++ b/audio/control.c @@ -195,6 +195,8 @@ static struct { static GSList *avctp_callbacks = NULL; +static void auth_cb(DBusError *derr, void *user_data); + static sdp_record_t *avrcp_ct_record() { sdp_list_t *svclass_id, *pfseq, *apseq, *root; @@ -389,6 +391,10 @@ static void avctp_disconnected(struct audio_device *dev) if (control->io_id) { g_source_remove(control->io_id); control->io_id = 0; + + if (control->state == AVCTP_STATE_CONNECTING) + audio_device_cancel_authorization(dev, auth_cb, + control); } if (control->uinput >= 0) { @@ -654,6 +660,11 @@ static void auth_cb(DBusError *derr, void *user_data) struct control *control = user_data; GError *err = NULL; + if (control->io_id) { + g_source_remove(control->io_id); + control->io_id = 0; + } + if (derr && dbus_error_is_set(derr)) { error("Access denied: %s", derr->message); avctp_set_state(control, AVCTP_STATE_DISCONNECTED); @@ -714,6 +725,8 @@ static void avctp_confirm_cb(GIOChannel *chan, gpointer data) auth_cb, dev->control) < 0) goto drop; + control->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL, + control_cb, control); return; drop: diff --git a/audio/device.c b/audio/device.c index 27d2bdb27..3535257d5 100644 --- a/audio/device.c +++ b/audio/device.c @@ -651,6 +651,11 @@ void audio_device_unregister(struct audio_device *device) { unix_device_removed(device); + if (device->hs_preauth_id) { + g_source_remove(device->hs_preauth_id); + device->hs_preauth_id = 0; + } + if (device->headset) headset_unregister(device); @@ -752,3 +757,30 @@ int audio_device_request_authorization(struct audio_device *dev, return err; } + +int audio_device_cancel_authorization(struct audio_device *dev, + authorization_cb cb, void *user_data) +{ + struct dev_priv *priv = dev->priv; + GSList *l, *next; + + for (l = priv->auths; l != NULL; l = next) { + struct service_auth *auth = priv->auths->data; + + next = g_slist_next(l); + + if (cb && auth->cb != cb) + continue; + + if (user_data && auth->user_data != user_data) + continue; + + priv->auths = g_slist_remove(priv->auths, auth); + g_free(auth); + } + + if (g_slist_length(priv->auths) == 0) + btd_cancel_authorization(&dev->src, &dev->dst); + + return 0; +} diff --git a/audio/device.h b/audio/device.h index 061c3da4f..45c54e80a 100644 --- a/audio/device.h +++ b/audio/device.h @@ -67,6 +67,8 @@ struct audio_device { struct control *control; struct target *target; + guint hs_preauth_id; + struct dev_priv *priv; }; @@ -82,6 +84,9 @@ gboolean audio_device_is_active(struct audio_device *dev, typedef void (*authorization_cb) (DBusError *derr, void *user_data); +int audio_device_cancel_authorization(struct audio_device *dev, + authorization_cb cb, void *user_data); + int audio_device_request_authorization(struct audio_device *dev, const char *uuid, authorization_cb cb, void *user_data); diff --git a/audio/manager.c b/audio/manager.c index b807f77f4..489d7bc1f 100644 --- a/audio/manager.c +++ b/audio/manager.c @@ -411,6 +411,11 @@ static void headset_auth_cb(DBusError *derr, void *user_data) GError *err = NULL; GIOChannel *io; + if (device->hs_preauth_id) { + g_source_remove(device->hs_preauth_id); + device->hs_preauth_id = 0; + } + if (derr && dbus_error_is_set(derr)) { error("Access denied: %s", derr->message); headset_set_state(device, HEADSET_STATE_DISCONNECTED); @@ -427,6 +432,22 @@ static void headset_auth_cb(DBusError *derr, void *user_data) } } +static gboolean hs_preauth_cb(GIOChannel *chan, GIOCondition cond, + gpointer user_data) +{ + struct audio_device *device = user_data; + + debug("Headset disconnected during authorization"); + + audio_device_cancel_authorization(device, headset_auth_cb, device); + + headset_set_state(device, HEADSET_STATE_DISCONNECTED); + + device->hs_preauth_id = 0; + + return FALSE; +} + static void ag_confirm(GIOChannel *chan, gpointer data) { const char *server_uuid, *remote_uuid; @@ -495,6 +516,10 @@ static void ag_confirm(GIOChannel *chan, gpointer data) return; } + device->hs_preauth_id = g_io_add_watch(chan, + G_IO_NVAL | G_IO_HUP | G_IO_ERR, + hs_preauth_cb, device); + device->auto_connect = auto_connect; return; |