diff options
author | Johan Hedberg <johan.hedberg@nokia.com> | 2007-08-21 06:48:14 +0000 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@nokia.com> | 2007-08-21 06:48:14 +0000 |
commit | c92c420f83dda53ebde74ad72cd0a3959d430901 (patch) | |
tree | be6d064f24fd36556d7475b6e5f027435802425b /audio | |
parent | f4f92d015b2bf4b5478d62fb8f4d0e28443f25cf (diff) |
Implement RequestAuthorization support
Diffstat (limited to 'audio')
-rw-r--r-- | audio/a2dp.c | 4 | ||||
-rw-r--r-- | audio/avdtp.c | 89 | ||||
-rw-r--r-- | audio/manager.c | 125 | ||||
-rw-r--r-- | audio/manager.h | 7 | ||||
-rw-r--r-- | audio/sink.c | 4 | ||||
-rw-r--r-- | audio/unix.c | 5 |
6 files changed, 170 insertions, 64 deletions
diff --git a/audio/a2dp.c b/audio/a2dp.c index 1e22e7c8..febc112c 100644 --- a/audio/a2dp.c +++ b/audio/a2dp.c @@ -607,8 +607,8 @@ int a2dp_init(DBusConnection *conn, gboolean enable_sink, gboolean enable_source if (enable_sink) { source.sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE, - AVDTP_MEDIA_TYPE_AUDIO, - &ind, &cfm); + AVDTP_MEDIA_TYPE_AUDIO, + &ind, &cfm); if (source.sep == NULL) return -1; diff --git a/audio/avdtp.c b/audio/avdtp.c index 57de80b9..be2709da 100644 --- a/audio/avdtp.c +++ b/audio/avdtp.c @@ -36,10 +36,13 @@ #include <glib.h> #include <bluetooth/bluetooth.h> +#include <bluetooth/sdp.h> #include "dbus.h" #include "logging.h" +#include "device.h" +#include "manager.h" #include "avdtp.h" #include <bluetooth/l2cap.h> @@ -274,6 +277,8 @@ struct avdtp { struct pending_req *req; guint dc_timer; + + DBusPendingCall *pending_auth; }; struct avdtp_error { @@ -1363,7 +1368,15 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond, return TRUE; failed: + if (session->pending_auth) { + manager_cancel_authorize(&session->dst, ADVANCED_AUDIO_UUID, + session->pending_auth); + dbus_pending_call_unref(session->pending_auth); + session->pending_auth = NULL; + } + connection_lost(session, -EIO); + return FALSE; } @@ -2041,8 +2054,12 @@ static struct avdtp *avdtp_get_internal(bdaddr_t *src, bdaddr_t *dst) assert(dst != NULL); session = find_session(src, dst); - if (session) - return session; + if (session) { + if (session->pending_auth) + return NULL; + else + return session; + } session = g_new0(struct avdtp, 1); @@ -2063,6 +2080,9 @@ struct avdtp *avdtp_get(bdaddr_t *src, bdaddr_t *dst) session = avdtp_get_internal(src, dst); + if (!session) + return NULL; + return avdtp_ref(session); } @@ -2463,6 +2483,51 @@ int avdtp_unregister_sep(struct avdtp_local_sep *sep) return 0; } +static void auth_cb(DBusPendingCall *call, void *data) +{ + GIOChannel *io; + struct avdtp *session = data; + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusError err; + + dbus_pending_call_unref(session->pending_auth); + session->pending_auth = NULL; + + dbus_error_init(&err); + if (dbus_set_error_from_message(&err, reply)) { + error("Access denied: %s", err.message); + + if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) { + debug("Canceling authorization request"); + manager_cancel_authorize(&session->dst, + ADVANCED_AUDIO_UUID, + NULL); + } + + dbus_error_free(&err); + + connection_lost(session, -EACCES); + + dbus_message_unref(reply); + + return; + } + + session->buf = g_malloc0(session->mtu); + + set_disconnect_timer(session); + + session->state = AVDTP_SESSION_STATE_CONNECTED; + + g_source_remove(session->io); + + io = g_io_channel_unix_new(session->sock); + session->io = g_io_add_watch(io, + G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + (GIOFunc) session_cb, session); + g_io_channel_unref(io); +} + static gboolean avdtp_server_cb(GIOChannel *chan, GIOCondition cond, void *data) { int srv_sk, cli_sk; @@ -2471,7 +2536,7 @@ static gboolean avdtp_server_cb(GIOChannel *chan, GIOCondition cond, void *data) struct l2cap_options l2o; bdaddr_t src, dst; struct avdtp *session; - GIOChannel *cli_io; + GIOChannel *io; char address[18]; if (cond & G_IO_NVAL) @@ -2529,19 +2594,19 @@ static gboolean avdtp_server_cb(GIOChannel *chan, GIOCondition cond, void *data) return TRUE; } - if (session->ref == 1) - set_disconnect_timer(session); + if (!manager_authorize(&dst, ADVANCED_AUDIO_UUID, auth_cb, session, + &session->pending_auth)) { + close(cli_sk); + return TRUE; + } session->mtu = l2o.imtu; - session->buf = g_malloc0(session->mtu); session->sock = cli_sk; - session->state = AVDTP_SESSION_STATE_CONNECTED; - cli_io = g_io_channel_unix_new(session->sock); - session->io = g_io_add_watch(cli_io, - G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, - (GIOFunc) session_cb, session); - g_io_channel_unref(cli_io); + io = g_io_channel_unix_new(session->sock); + session->io = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL, + (GIOFunc) session_cb, session); + g_io_channel_unref(io); return TRUE; } diff --git a/audio/manager.c b/audio/manager.c index 6eebce94..4d8d424d 100644 --- a/audio/manager.c +++ b/audio/manager.c @@ -1383,10 +1383,11 @@ int remove_service_record(DBusConnection *conn, uint32_t rec_id) return 0; } -static void send_cancel_auth(struct device *device) +static void auth_cb(DBusPendingCall *call, void *data) { - DBusMessage *cancel; - char addr[18], *address = addr; + struct device *device = data; + DBusMessage *reply = dbus_pending_call_steal_reply(call); + DBusError err; const char *uuid; if (headset_get_type(device) == SVC_HEADSET) @@ -1394,35 +1395,12 @@ static void send_cancel_auth(struct device *device) else uuid = HFP_AG_UUID; - cancel = dbus_message_new_method_call("org.bluez", "/org/bluez", - "org.bluez.Database", - "CancelAuthorizationRequest"); - if (!cancel) { - error("Unable to allocate new method call"); - return; - } - - ba2str(&device->dst, addr); - - dbus_message_append_args(cancel, DBUS_TYPE_STRING, &address, - DBUS_TYPE_STRING, &uuid, - DBUS_TYPE_INVALID); - - send_message_and_unref(connection, cancel); -} - -static void auth_cb(DBusPendingCall *call, void *data) -{ - struct device *device = data; - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusError err; - dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("Access denied: %s", err.message); if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) { debug("Canceling authorization request"); - send_cancel_auth(device); + manager_cancel_authorize(&device->dst, uuid, NULL); } dbus_error_free(&err); @@ -1446,11 +1424,8 @@ static gboolean ag_io_cb(GIOChannel *chan, GIOCondition cond, void *data) int srv_sk, cli_sk; struct sockaddr_rc addr; socklen_t size; - char hs_address[18], *address = hs_address; const char *uuid; struct device *device; - DBusMessage *auth; - DBusPendingCall *pending; headset_type_t type; if (cond & G_IO_NVAL) @@ -1500,28 +1475,9 @@ static gboolean ag_io_cb(GIOChannel *chan, GIOCondition cond, void *data) headset_set_type(device, type); - auth = dbus_message_new_method_call("org.bluez", "/org/bluez", - "org.bluez.Database", - "RequestAuthorization"); - if (!auth) { - error("Unable to allocate RequestAuthorization method call"); + if (!manager_authorize(&device->dst, uuid, auth_cb, device, NULL)) goto failed; - } - ba2str(&device->dst, hs_address); - - dbus_message_append_args(auth, DBUS_TYPE_STRING, &address, - DBUS_TYPE_STRING, &uuid, - DBUS_TYPE_INVALID); - - if (!dbus_connection_send_with_reply(connection, auth, &pending, -1)) { - error("Sending of authorization request failed"); - goto failed; - } - - dbus_pending_call_set_notify(pending, auth_cb, device, NULL); - dbus_pending_call_unref(pending); - dbus_message_unref(auth); headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS); return TRUE; @@ -1734,3 +1690,72 @@ struct device *manager_get_connected_device(void) return NULL; } + +void manager_cancel_authorize(bdaddr_t *dba, const char *uuid, + DBusPendingCall *pending) +{ + DBusMessage *cancel; + char addr[18], *address = addr; + + if (pending) + dbus_pending_call_cancel(pending); + + cancel = dbus_message_new_method_call("org.bluez", "/org/bluez", + "org.bluez.Database", + "CancelAuthorizationRequest"); + if (!cancel) { + error("Unable to allocate new method call"); + return; + } + + ba2str(dba, addr); + + dbus_message_append_args(cancel, DBUS_TYPE_STRING, &address, + DBUS_TYPE_STRING, &uuid, + DBUS_TYPE_INVALID); + + send_message_and_unref(connection, cancel); +} + +gboolean manager_authorize(bdaddr_t *dba, const char *uuid, + DBusPendingCallNotifyFunction cb, + void *user_data, + DBusPendingCall **pending) +{ + DBusMessage *auth; + char address[18], *addr_ptr = address; + DBusPendingCall *p; + + ba2str(dba, address); + + debug("Requesting authorization for device %s, UUID %s", + address, uuid); + + auth = dbus_message_new_method_call("org.bluez", "/org/bluez", + "org.bluez.Database", + "RequestAuthorization"); + if (!auth) { + error("Unable to allocate RequestAuthorization method call"); + return FALSE; + } + + dbus_message_append_args(auth, DBUS_TYPE_STRING, &addr_ptr, + DBUS_TYPE_STRING, &uuid, + DBUS_TYPE_INVALID); + + if (!dbus_connection_send_with_reply(connection, auth, &p, -1)) { + error("Sending of authorization request failed"); + dbus_message_unref(auth); + return FALSE; + } + + dbus_pending_call_set_notify(p, cb, user_data, NULL); + if (pending) + *pending = p; + else + dbus_pending_call_unref(p); + + dbus_message_unref(auth); + + return TRUE; +} diff --git a/audio/manager.h b/audio/manager.h index a18cf4fd..65992040 100644 --- a/audio/manager.h +++ b/audio/manager.h @@ -47,3 +47,10 @@ struct device *manager_device_connected(bdaddr_t *bda, const char *uuid); struct device *manager_default_device(); struct device *manager_get_connected_device(void); + +gboolean manager_authorize(bdaddr_t *dba, const char *uuid, + DBusPendingCallNotifyFunction cb, + void *user_data, + DBusPendingCall **pending); +void manager_cancel_authorize(bdaddr_t *dba, const char *uuid, + DBusPendingCall *pending); diff --git a/audio/sink.c b/audio/sink.c index ab9f401b..c09c019f 100644 --- a/audio/sink.c +++ b/audio/sink.c @@ -160,6 +160,10 @@ static DBusHandlerResult sink_connect(DBusConnection *conn, if (!sink->session) sink->session = avdtp_get(&dev->src, &dev->dst); + if (!sink->session) + return err_connect_failed(conn, msg, + "Unable to get a session"); + if (sink->connect || sink->disconnect) return err_connect_failed(conn, msg, "Connect in progress"); diff --git a/audio/unix.c b/audio/unix.c index 19a140c0..3488fd5f 100644 --- a/audio/unix.c +++ b/audio/unix.c @@ -317,6 +317,11 @@ proceed: if (!a2dp->session) a2dp->session = avdtp_get(&dev->src, &dev->dst); + if (!a2dp->session) { + error("Unable to get a session"); + goto failed; + } + id = a2dp_source_request_stream(a2dp->session, dev, TRUE, a2dp_setup_complete, client); |