From 279e85d6da77c74f04e5fc605dd8074bfe56b5a5 Mon Sep 17 00:00:00 2001 From: Luiz Augusto von Dentz Date: Fri, 25 Apr 2008 20:01:09 +0000 Subject: Make input service to use libbluetooth-glib convenient functions. --- input/device.c | 206 ++++------------------ input/manager.c | 532 ++++++++------------------------------------------------ 2 files changed, 103 insertions(+), 635 deletions(-) diff --git a/input/device.c b/input/device.c index 46214217..08a1c089 100644 --- a/input/device.c +++ b/input/device.c @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -53,6 +54,7 @@ #include "manager.h" #include "storage.h" #include "fakehid.h" +#include "glib-helper.h" #define INPUT_DEVICE_INTERFACE "org.bluez.input.Device" @@ -368,38 +370,18 @@ failed: return FALSE; } -static gboolean rfcomm_connect_cb(GIOChannel *chan, - GIOCondition cond, struct device *idev) +static void rfcomm_connect_cb(GIOChannel *chan, int err, gpointer user_data) { + struct device *idev = user_data; struct fake_input *fake; DBusMessage *reply; const char *path; - socklen_t len; - int ret, err; fake = idev->fake; fake->rfcomm = g_io_channel_unix_get_fd(chan); - if (cond & G_IO_NVAL) - return FALSE; - - if (cond & (G_IO_ERR | G_IO_HUP)) { - err = EIO; - goto failed; - } - - len = sizeof(ret); - if (getsockopt(fake->rfcomm, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - err = errno; - error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); - goto failed; - } - - if (ret != 0) { - err = ret; - error("connect(): %s (%d)", strerror(err), err); + if (err < 0) goto failed; - } /* * FIXME: Some headsets required a sco connection @@ -429,85 +411,27 @@ static gboolean rfcomm_connect_cb(GIOChannel *chan, dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return FALSE; + return; failed: error_connection_attempt_failed(idev->conn, idev->pending_connect, err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - - g_io_channel_close(chan); - - return FALSE; } static int rfcomm_connect(struct device *idev) { - struct sockaddr_rc addr; - GIOChannel *io; - int sk, err; - - sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - if (sk < 0) { - err = errno; - error("socket: %s (%d)", strerror(err), err); - return -err; - } - - memset(&addr, 0, sizeof(addr)); - addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &idev->src); - addr.rc_channel = 0; - - if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - err = errno; - error("bind: %s (%d)", strerror(err), err); - goto failed; - } - - if (set_nonblocking(sk) < 0) { - err = errno; - error("Set non blocking: %s (%d)", strerror(err), err); - goto failed; - } - - memset(&addr, 0, sizeof(addr)); - addr.rc_family = AF_BLUETOOTH; - bacpy(&addr.rc_bdaddr, &idev->dst); - addr.rc_channel = idev->fake->ch; - - io = g_io_channel_unix_new(sk); - g_io_channel_set_close_on_unref(io, FALSE); - - if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - char peer[18]; /* FIXME: debug purpose */ - if (!(errno == EAGAIN || errno == EINPROGRESS)) { - err = errno; - error("connect() failed: %s (%d)", - strerror(err), err); - g_io_channel_unref(io); - goto failed; - } + int err; - ba2str(&idev->dst, peer); - debug("RFCOMM connection in progress: %s channel:%d", peer, idev->fake->ch); - g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - (GIOFunc) rfcomm_connect_cb, idev); - } else { - debug("Connect succeeded with first try"); - rfcomm_connect_cb(io, G_IO_OUT, idev); + err = bt_rfcomm_connect(&idev->src, &idev->dst, idev->fake->ch, + rfcomm_connect_cb, idev); + if (err < 0) { + error("connect() failed: %s (%d)", strerror(-err), -err); + return err; } - g_io_channel_unref(io); - return 0; - -failed: - close(sk); - errno = err; - - return -err; } static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data) @@ -628,41 +552,16 @@ cleanup: return err; } -static gboolean interrupt_connect_cb(GIOChannel *chan, - GIOCondition cond, struct device *idev) +static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) { - int isk, ret, err; - socklen_t len; - - isk = g_io_channel_unix_get_fd(chan); - - if (cond & G_IO_NVAL) { - err = EHOSTDOWN; - isk = -1; - goto failed; - } - - if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EHOSTDOWN; - error("Hangup or error on HIDP interrupt socket"); - goto failed; - - } - - len = sizeof(ret); - if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - err = errno; - error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); - goto failed; - } + struct device *idev = user_data; - if (ret != 0) { - err = ret; - error("connect(): %s (%d)", strerror(ret), ret); + if (err < 0) { + error("connect(): %s (%d)", strerror(-err), -err); goto failed; } - idev->intr_sk = isk; + idev->intr_sk = g_io_channel_unix_get_fd(chan); err = hidp_connadd(&idev->src, &idev->dst, idev->ctrl_sk, idev->intr_sk, idev->name); if (err < 0) @@ -683,78 +582,43 @@ static gboolean interrupt_connect_cb(GIOChannel *chan, goto cleanup; failed: error_connection_attempt_failed(idev->conn, - idev->pending_connect, err); - if (isk > 0) - close(isk); - close(idev->ctrl_sk); + idev->pending_connect, -err); idev->intr_sk = -1; idev->ctrl_sk = -1; cleanup: dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - - return FALSE; } -static gboolean control_connect_cb(GIOChannel *chan, - GIOCondition cond, struct device *idev) +static void control_connect_cb(GIOChannel *chan, int err, gpointer user_data) { - int ret, csk, err; - socklen_t len; + struct device *idev = user_data; - csk = g_io_channel_unix_get_fd(chan); - - if (cond & G_IO_NVAL) { - err = EHOSTDOWN; - csk = -1; - goto failed; - } - - if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EHOSTDOWN; - error("Hangup or error on HIDP control socket"); + if (err < 0) { + error("connect(): %s (%d)", strerror(-err), -err); goto failed; } /* Set HID control channel */ - idev->ctrl_sk = csk; - - len = sizeof(ret); - if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - err = errno; - error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); - goto failed; - } - - if (ret != 0) { - err = ret; - error("connect(): %s (%d)", strerror(ret), ret); - goto failed; - } + idev->ctrl_sk = g_io_channel_unix_get_fd(chan); /* Connect to the HID interrupt channel */ - if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_INTR, - (GIOFunc) interrupt_connect_cb, idev) < 0) { - - err = errno; - error("L2CAP connect failed:%s (%d)", strerror(errno), errno); + err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_INTR, + interrupt_connect_cb, idev); + if (err < 0) { + error("L2CAP connect failed:%s (%d)", strerror(-err), -err); goto failed; } - return FALSE; + return; failed: - if (csk > 0) - close(csk); - idev->ctrl_sk = -1; error_connection_attempt_failed(idev->conn, - idev->pending_connect, err); + idev->pending_connect, -err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - - return FALSE; } static int fake_disconnect(struct device *idev) @@ -874,6 +738,7 @@ static DBusHandlerResult device_connect(DBusConnection *conn, { struct device *idev = data; struct fake_input *fake = idev->fake; + int err; if (idev->pending_connect) return error_in_progress(conn, msg, @@ -900,14 +765,13 @@ static DBusHandlerResult device_connect(DBusConnection *conn, } /* HID devices */ - if (l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, - (GIOFunc) control_connect_cb, idev) < 0) { - int err = errno; - - error("L2CAP connect failed: %s(%d)", strerror(err), err); + err = bt_l2cap_connect(&idev->src, &idev->dst, L2CAP_PSM_HIDP_CTRL, + control_connect_cb, idev); + if (err < 0) { + error("L2CAP connect failed: %s(%d)", strerror(-err), -err); dbus_message_unref(idev->pending_connect); idev->pending_connect = NULL; - return error_connection_attempt_failed(conn, msg, err); + return error_connection_attempt_failed(conn, msg, -err); } return DBUS_HANDLER_RESULT_HANDLED; diff --git a/input/manager.c b/input/manager.c index 2e138c6b..4b25843d 100644 --- a/input/manager.c +++ b/input/manager.c @@ -52,10 +52,7 @@ #include "error.h" #include "manager.h" #include "storage.h" - -static const char *pnp_uuid = "00001200-0000-1000-8000-00805f9b34fb"; -static const char *hid_uuid = "00001124-0000-1000-8000-00805f9b34fb"; -static const char *headset_uuid = "00001108-0000-1000-8000-00805f9b34fb"; +#include "glib-helper.h" struct pending_req { char *adapter_path; /* Local adapter D-Bus path */ @@ -119,70 +116,6 @@ static void pending_req_free(struct pending_req *pr) g_free(pr); } -static int get_record(struct pending_req *pr, uint32_t handle, - DBusPendingCallNotifyFunction cb) -{ - DBusMessage *msg; - DBusPendingCall *pending; - char addr[18]; - const char *paddr = addr; - - msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, - "org.bluez.Adapter", "GetRemoteServiceRecord"); - if (!msg) - return -1; - - ba2str(&pr->dst, addr); - dbus_message_append_args(msg, - DBUS_TYPE_STRING, &paddr, - DBUS_TYPE_UINT32, &handle, - DBUS_TYPE_INVALID); - - if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) { - error("Can't send D-Bus message."); - dbus_message_unref(msg); - return -1; - } - - dbus_pending_call_set_notify(pending, cb, pr, NULL); - dbus_pending_call_unref(pending); - dbus_message_unref(msg); - - return 0; -} - -static int get_handles(struct pending_req *pr, const char *uuid, - DBusPendingCallNotifyFunction cb) -{ - DBusMessage *msg; - DBusPendingCall *pending; - char addr[18]; - const char *paddr = addr; - - msg = dbus_message_new_method_call("org.bluez", pr->adapter_path, - "org.bluez.Adapter", "GetRemoteServiceHandles"); - if (!msg) - return -1; - - ba2str(&pr->dst, addr); - dbus_message_append_args(msg, - DBUS_TYPE_STRING, &paddr, - DBUS_TYPE_STRING, &uuid, - DBUS_TYPE_INVALID); - - if (dbus_connection_send_with_reply(pr->conn, msg, &pending, -1) == FALSE) { - error("Can't send D-Bus message."); - dbus_message_unref(msg); - return -1; - } - - dbus_pending_call_set_notify(pending, cb, pr, NULL); - dbus_pending_call_unref(pending); - dbus_message_unref(msg); - - return 0; -} - static void epox_endian_quirk(unsigned char *data, int size) { /* USAGE_PAGE (Keyboard) 05 07 @@ -279,42 +212,17 @@ static void extract_pnp_record(sdp_record_t *rec, struct hidp_connadd_req *req) req->version = pdlist ? pdlist->val.uint16 : 0x0000; } -static gboolean interrupt_connect_cb(GIOChannel *chan, - GIOCondition cond, struct pending_req *pr) +static void interrupt_connect_cb(GIOChannel *chan, int err, gpointer user_data) { + struct pending_req *pr = user_data; struct hidp_connadd_req hidp; DBusMessage *reply; const char *path; - int isk, ret, err; - socklen_t len; memset(&hidp, 0, sizeof(hidp)); - isk = g_io_channel_unix_get_fd(chan); - - if (cond & G_IO_NVAL) { - err = EHOSTDOWN; - isk = -1; - goto failed; - } - - if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EHOSTDOWN; - error("Hangup or error on HIDP interrupt socket"); - goto failed; - - } - - len = sizeof(ret); - if (getsockopt(isk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - err = errno; - error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); - goto failed; - } - - if (ret != 0) { - err = ret; - error("connect(): %s (%d)", strerror(ret), ret); + if (err < 0) { + error("connect(): %s (%d)", strerror(-err), -err); goto failed; } @@ -351,74 +259,38 @@ failed: error_connection_attempt_failed(pr->conn, pr->msg, err); cleanup: - if (isk >= 0) - close(isk); - close(pr->ctrl_sock); pending_req_free(pr); if (hidp.rd_data) g_free(hidp.rd_data); - - return FALSE; } -static gboolean control_connect_cb(GIOChannel *chan, - GIOCondition cond, struct pending_req *pr) +static void control_connect_cb(GIOChannel *chan, int err, gpointer user_data) { - int ret, csk, err; - socklen_t len; - - csk = g_io_channel_unix_get_fd(chan); - - if (cond & G_IO_NVAL) { - err = EHOSTDOWN; - csk = -1; - goto failed; - } + struct pending_req *pr = user_data; - if (cond & (G_IO_HUP | G_IO_ERR)) { - err = EHOSTDOWN; - error("Hangup or error on HIDP control socket"); + if (err < 0) { + error("connect(): %s (%d)", strerror(-err), -err); goto failed; - } /* Set HID control channel */ - pr->ctrl_sock = csk; - - len = sizeof(ret); - if (getsockopt(csk, SOL_SOCKET, SO_ERROR, &ret, &len) < 0) { - err = errno; - error("getsockopt(SO_ERROR): %s (%d)", strerror(err), err); - goto failed; - } - - if (ret != 0) { - err = ret; - error("connect(): %s (%d)", strerror(ret), ret); - goto failed; - } + pr->ctrl_sock = g_io_channel_unix_get_fd(chan); /* Connect to the HID interrupt channel */ - if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_INTR, - (GIOFunc) interrupt_connect_cb, pr) < 0) { - - err = errno; - error("L2CAP connect failed:%s (%d)", strerror(errno), errno); + err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_INTR, + interrupt_connect_cb, pr); + if (err < 0) { + error("L2CAP connect failed:%s (%d)", strerror(-err), -err); goto failed; } - return FALSE; + return; failed: - if (csk >= 0) - close(csk); - - error_connection_attempt_failed(pr->conn, pr->msg, err); + error_connection_attempt_failed(pr->conn, pr->msg, -err); pending_req_free(pr); - - return FALSE; } static void create_bonding_reply(DBusPendingCall *call, void *data) @@ -426,6 +298,7 @@ static void create_bonding_reply(DBusPendingCall *call, void *data) DBusMessage *reply = dbus_pending_call_steal_reply(call); struct pending_req *pr = data; DBusError derr; + int err; dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { @@ -440,36 +313,15 @@ static void create_bonding_reply(DBusPendingCall *call, void *data) dbus_message_unref(reply); - if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, - (GIOFunc) control_connect_cb, pr) < 0) { - int err = errno; - error_connection_attempt_failed(pr->conn, pr->msg, err); - error("L2CAP connect failed:%s (%d)", strerror(err), err); + err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, + control_connect_cb, pr); + if (err < 0) { + error("L2CAP connect failed:%s (%d)", strerror(-err), -err); + error_connection_attempt_failed(pr->conn, pr->msg, -err); pending_req_free(pr); } } -static void finish_sdp_transaction(bdaddr_t *dba) -{ - char address[18], *addr_ptr = address; - DBusMessage *msg; - - ba2str(dba, address); - - msg = dbus_message_new_method_call("org.bluez", "/org/bluez/hci0", - "org.bluez.Adapter", - "FinishRemoteServiceTransaction"); - if (!msg) { - error("Unable to allocate new method call"); - return; - } - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &addr_ptr, - DBUS_TYPE_INVALID); - - send_message_and_unref(connection, msg); -} - static int create_bonding(struct pending_req *pr) { DBusPendingCall *pending; @@ -496,53 +348,23 @@ static int create_bonding(struct pending_req *pr) return 0; } -static void hid_record_reply(DBusPendingCall *call, void *data) +static void hid_record_cb(sdp_list_t *recs, int err, gpointer user_data) { - DBusMessage *reply = dbus_pending_call_steal_reply(call); - struct pending_req *pr = data; - DBusError derr; - uint8_t *rec_bin; - int len, scanned; + struct pending_req *pr = user_data; - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - /* FIXME : to not try to be clever about - hcid error but forward as is to the user */ - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - error_connection_attempt_failed(pr->conn, - pr->msg, EIO); - else - error_not_supported(pr->conn, pr->msg); - - error("GetRemoteServiceRecord failed: %s(%s)", - derr.name, derr.message); - goto fail; - } - - finish_sdp_transaction(&pr->dst); - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, - DBUS_TYPE_INVALID)) { + if (err < 0) { error_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); + error("SDP search error: %s (%d)", strerror(-err), -err); goto fail; } - if (len == 0) { + if (!recs || !recs->data) { error_not_supported(pr->conn, pr->msg); error("Invalid HID service record length"); goto fail; } - pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned); - if (!pr->hid_rec) { - error_not_supported(pr->conn, pr->msg); - goto fail; - } - - dbus_message_unref(reply); + pr->hid_rec = recs->data; if (strcmp("CreateSecureDevice", dbus_message_get_member(pr->msg)) == 0) { sdp_data_t *d; @@ -564,240 +386,76 @@ static void hid_record_reply(DBusPendingCall *call, void *data) } /* No encryption or link key already exists -- connect control channel */ - if (l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, - (GIOFunc) control_connect_cb, pr) < 0) { - int err = errno; - error("L2CAP connect failed:%s (%d)", strerror(err), err); - error_connection_attempt_failed(pr->conn, pr->msg, err); + err = bt_l2cap_connect(&pr->src, &pr->dst, L2CAP_PSM_HIDP_CTRL, + control_connect_cb, pr); + if (err < 0) { + error("L2CAP connect failed:%s (%d)", strerror(-err), -err); + error_connection_attempt_failed(pr->conn, pr->msg, -err); goto fail; } /* Wait L2CAP connect */ return; -fail: - dbus_error_free(&derr); - pending_req_free(pr); - dbus_message_unref(reply); -} - -static void hid_handle_reply(DBusPendingCall *call, void *data) -{ - DBusMessage *reply = dbus_pending_call_steal_reply(call); - struct pending_req *pr = data; - uint32_t *phandle; - DBusError derr; - int len; - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - /* FIXME : to not try to be clever about - hcid error but forward as is to the user */ - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - error_connection_attempt_failed(pr->conn, - pr->msg, EIO); - else - error_not_supported(pr->conn, pr->msg); - - error("GetRemoteServiceHandles: %s(%s)", - derr.name, derr.message); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, - DBUS_TYPE_INVALID)) { - error_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (len == 0) { - error_not_supported(pr->conn, pr->msg); - error("HID record handle not found"); - goto fail; - } - - if (get_record(pr, *phandle, hid_record_reply) < 0) { - error_not_supported(pr->conn, pr->msg); - error("HID service attribute request failed"); - goto fail; - } else { - /* Wait record reply */ - goto done; - } fail: - dbus_error_free(&derr); pending_req_free(pr); - -done: - dbus_message_unref(reply); } -static void pnp_record_reply(DBusPendingCall *call, void *data) +static void pnp_record_cb(sdp_list_t *recs, int err, gpointer user_data) { - DBusMessage *reply = dbus_pending_call_steal_reply(call); - struct pending_req *pr = data; - DBusError derr; - uint8_t *rec_bin; - int len, scanned; + struct pending_req *pr = user_data; + uuid_t uuid; - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - /* FIXME : to not try to be clever about - hcid error but forward as is to the user */ - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - error_connection_attempt_failed(pr->conn, pr->msg, - EIO); - else - error_not_supported(pr->conn, pr->msg); - - error("GetRemoteServiceRecord: %s(%s)", - derr.name, derr.message); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, - DBUS_TYPE_INVALID)) { + if (err < 0) { error_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); + error("SDP search error: %s (%d)", strerror(-err), -err); goto fail; } - if (len == 0) { + if (!recs || !recs->data) { error_not_supported(pr->conn, pr->msg); error("Invalid PnP service record length"); goto fail; } - pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned); - if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) { + pr->pnp_rec = recs->data; + sdp_uuid16_create(&uuid, HID_SVCLASS_ID); + err = bt_search_service(&pr->src, &pr->dst, &uuid, hid_record_cb, + pr, NULL); + if (err < 0) { error_not_supported(pr->conn, pr->msg); error("HID service search request failed"); goto fail; - } else { - /* Wait handle reply */ - goto done; } -fail: - dbus_error_free(&derr); - pending_req_free(pr); - -done: - dbus_message_unref(reply); -} - -static void pnp_handle_reply(DBusPendingCall *call, void *data) -{ - DBusMessage *reply = dbus_pending_call_steal_reply(call); - struct pending_req *pr = data; - DBusError derr; - uint32_t *phandle; - int len; - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - /* FIXME : to not try to be clever about - hcid error but forward as is to the user */ - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - error_connection_attempt_failed(pr->conn, pr->msg, - EIO); - else - error_not_supported(pr->conn, pr->msg); - - error("GetRemoteServiceHandles: %s(%s)", - derr.name, derr.message); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, - DBUS_TYPE_INVALID)) { - error_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (len == 0) { - /* PnP is optional: Ignore it and request the HID handle */ - if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) { - error_not_supported(pr->conn, pr->msg); - error("HID service search request failed"); - goto fail; - } - } else { - /* Request PnP record */ - if (get_record(pr, *phandle, pnp_record_reply) < 0) { - error_not_supported(pr->conn, pr->msg); - error("PnP service attribute request failed"); - goto fail; - } - } - - /* Wait HID handle reply or PnP record reply */ - goto done; + return; fail: - dbus_error_free(&derr); pending_req_free(pr); - -done: - dbus_message_unref(reply); } -static void headset_record_reply(DBusPendingCall *call, void *data) +static void headset_record_cb(sdp_list_t *recs, int err, gpointer user_data) { - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusMessage *pr_reply; - DBusError derr; - struct pending_req *pr = data; - uint8_t *rec_bin; + struct pending_req *pr = user_data; + DBusMessage *reply; sdp_record_t *rec; sdp_list_t *protos; const char *path; - int len, scanned; uint8_t ch; - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - /* FIXME : to not try to be clever about - hcid error but forward as is to the user */ - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - error_connection_attempt_failed(pr->conn, pr->msg, - EIO); - else - error_not_supported(pr->conn, pr->msg); - - error("GetRemoteServiceRecord: %s(%s)", - derr.name, derr.message); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &rec_bin, &len, - DBUS_TYPE_INVALID)) { + if (err < 0) { error_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); + error("SDP search error: %s (%d)", strerror(-err), -err); goto fail; } - if (len == 0) { + if (!recs || !recs->data) { error_not_supported(pr->conn, pr->msg); error("Invalid headset service record length"); goto fail; } - rec = sdp_extract_pdu(rec_bin, &scanned); - if (!rec) { - error_not_supported(pr->conn, pr->msg); - goto fail; - } + rec = recs->data; if (sdp_get_access_protos(rec, &protos) < 0) { error_not_supported(pr->conn, pr->msg); @@ -830,73 +488,16 @@ static void headset_record_reply(DBusPendingCall *call, void *data) device_paths = g_slist_append(device_paths, g_strdup(path)); - pr_reply = dbus_message_new_method_return(pr->msg); + reply = dbus_message_new_method_return(pr->msg); - dbus_message_append_args(pr_reply, + dbus_message_append_args(reply, DBUS_TYPE_STRING, &path, DBUS_TYPE_INVALID); - send_message_and_unref(pr->conn, pr_reply); - -fail: - dbus_error_free(&derr); - pending_req_free(pr); - dbus_message_unref(reply); -} - -static void headset_handle_reply(DBusPendingCall *call, void *data) -{ - DBusMessage *reply = dbus_pending_call_steal_reply(call); - struct pending_req *pr = data; - DBusError derr; - uint32_t *phandle; - int len; - - dbus_error_init(&derr); - if (dbus_set_error_from_message(&derr, reply)) { - /* FIXME : to not try to be clever about - hcid error but forward as is to the user */ - if (dbus_error_has_name(&derr, - "org.bluez.Error.ConnectionAttemptFailed")) - error_connection_attempt_failed(pr->conn, pr->msg, - EIO); - else - error_not_supported(pr->conn, pr->msg); - - error("GetRemoteServiceHandles: %s(%s)", - derr.name, derr.message); - goto fail; - } - - if (!dbus_message_get_args(reply, &derr, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &phandle, &len, - DBUS_TYPE_INVALID)) { - error_not_supported(pr->conn, pr->msg); - error("%s: %s", derr.name, derr.message); - goto fail; - } - - if (len == 0) { - error_not_supported(pr->conn, pr->msg); - error("Headset record handle not found"); - goto fail; - } - - if (get_record(pr, *phandle, headset_record_reply) < 0) { - error_not_supported(pr->conn, pr->msg); - error("Headset service attribute request failed"); - goto fail; - } else { - /* Wait record reply */ - goto done; - } + send_message_and_unref(pr->conn, reply); fail: - dbus_error_free(&derr); pending_req_free(pr); - -done: - dbus_message_unref(reply); } static DBusHandlerResult create_device(DBusConnection *conn, @@ -907,7 +508,9 @@ static DBusHandlerResult create_device(DBusConnection *conn, const char *addr; bdaddr_t src, dst; uint32_t cls = 0; - int dev_id; + int dev_id, err; + uuid_t uuid; + bt_callback_t cb; dbus_error_init(&derr); if (!dbus_message_get_args(msg, &derr, @@ -946,23 +549,24 @@ static DBusHandlerResult create_device(DBusConnection *conn, switch (cls & 0x1f00) { case 0x0500: /* Peripheral */ case 0x0200: /* Phone */ - if (get_handles(pr, pnp_uuid, pnp_handle_reply) < 0) { - pending_req_free(pr); - return error_not_supported(conn, msg); - } + sdp_uuid16_create(&uuid, PNP_INFO_SVCLASS_ID); + cb = pnp_record_cb; break; case 0x0400: /* Fake input */ - if (get_handles(pr, headset_uuid, - headset_handle_reply) < 0) { - pending_req_free(pr); - return error_not_supported(conn, msg); - } + sdp_uuid16_create(&uuid, HEADSET_SVCLASS_ID); + cb = headset_record_cb; break; default: pending_req_free(pr); return error_not_supported(conn, msg); } + err = bt_search_service(&src, &dst, &uuid, cb, pr, NULL); + if (err < 0) { + pending_req_free(pr); + return error_not_supported(conn, msg); + } + return DBUS_HANDLER_RESULT_HANDLED; } -- cgit