summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@nokia.com>2009-09-04 18:50:56 +0300
committerJohan Hedberg <johan.hedberg@nokia.com>2009-09-04 18:50:56 +0300
commit88d7897d4c6e129c52d7f84a670d49e712e27fd1 (patch)
tree60b5c66b9f06a0caf34db4e2af4b83cdd5aa8286
parent966ccc91a4a879574531c1af1ef024b29ff0e77b (diff)
downloadbluez-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.c16
-rw-r--r--audio/control.c13
-rw-r--r--audio/device.c32
-rw-r--r--audio/device.h5
-rw-r--r--audio/manager.c25
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;