From 6eab5e203d793fbeea8a488a315a62ab2e69417e Mon Sep 17 00:00:00 2001 From: Claudio Takahasi Date: Thu, 6 Mar 2008 21:58:13 +0000 Subject: added bt_discover_services function --- common/glib-helper.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++++-- common/glib-helper.h | 6 +++ hcid/adapter.c | 60 +++++++++++++++++----- hcid/adapter.h | 6 +++ 4 files changed, 195 insertions(+), 18 deletions(-) diff --git a/common/glib-helper.c b/common/glib-helper.c index 35261188..b97aa82c 100644 --- a/common/glib-helper.c +++ b/common/glib-helper.c @@ -29,14 +29,147 @@ #include #include +#include +#include #include #include "glib-helper.h" -int bt_discover_services(const bdaddr_t src, const bdaddr_t dst, - void (*callback) (void), void *user_data, - void (*destroy) (void *user_data)) +struct search_context { + bdaddr_t src; + bdaddr_t dst; + sdp_session_t *session; + bt_callback_t cb; + bt_destroy_t destroy; + gpointer user_data; +}; + +static void search_context_cleanup(struct search_context *ctxt) +{ + if (ctxt->destroy) + ctxt->destroy(ctxt->user_data); + sdp_close(ctxt->session); + g_free(ctxt); +} + +static void search_completed_cb(uint8_t type, uint16_t status, + uint8_t *rsp, size_t size, void *user_data) +{ + struct search_context *ctxt = user_data; + sdp_list_t *recs = NULL; + + /* FIXME: Extract the records */ + + ctxt->cb(ctxt->user_data, recs, 0); + + search_context_cleanup(ctxt); +} + +static gboolean search_process_cb(GIOChannel *chan, + GIOCondition cond, void *user_data) +{ + struct search_context *ctxt = user_data; + int err = 0; + + if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) { + err = EIO; + goto failed; + } + + if (sdp_process(ctxt->session) < 0) + goto failed; + + return TRUE; + +failed: + if (err) { + ctxt->cb(ctxt->user_data, NULL, -err); + search_context_cleanup(ctxt); + } + + return FALSE; +} + +static gboolean connect_watch(GIOChannel *chan, GIOCondition cond, gpointer user_data) { - return -EIO; + struct search_context *ctxt = user_data; + sdp_list_t *search, *attrids; + uint32_t range = 0x0000ffff; + uuid_t uuid; + socklen_t len; + int sk, err = 0; + + sk = g_io_channel_unix_get_fd(chan); + + len = sizeof(err); + if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { + err = errno; + goto failed; + } + + if (err != 0) + goto failed; + + if (sdp_set_notify(ctxt->session, search_completed_cb, ctxt) < 0) { + err = EIO; + goto failed; + } + + sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP); + search = sdp_list_append(NULL, &uuid); + attrids = sdp_list_append(NULL, &range); + if (sdp_service_search_attr_async(ctxt->session, + search, SDP_ATTR_REQ_RANGE, attrids) < 0) { + sdp_list_free(attrids, NULL); + sdp_list_free(search, NULL); + err = EIO; + goto failed; + } + + sdp_list_free(attrids, NULL); + sdp_list_free(search, NULL); + + /* Set callback responsible for update the internal SDP transaction */ + g_io_add_watch(chan, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + search_process_cb, ctxt); + return FALSE; + +failed: + ctxt->cb(ctxt->user_data, NULL, -err); + search_context_cleanup(ctxt); + + return FALSE; +} + +int bt_discover_services(const bdaddr_t *src, const bdaddr_t *dst, + bt_callback_t cb, void *user_data, bt_destroy_t destroy) +{ + struct search_context *ctxt; + sdp_session_t *s; + GIOChannel *chan; + + if (!cb) + return -EINVAL; + + s = sdp_connect(src, dst, SDP_NON_BLOCKING); + if (!s) + return -EIO; + + ctxt = g_malloc0(sizeof(struct search_context)); + if (!ctxt) + return -ENOMEM; + + bacpy(&ctxt->src, src); + bacpy(&ctxt->dst, dst); + ctxt->session = s; + ctxt->cb = cb; + ctxt->destroy = destroy; + ctxt->user_data = user_data; + + chan = g_io_channel_unix_new(sdp_get_socket(s)); + g_io_add_watch(chan, G_IO_OUT, connect_watch, ctxt); + g_io_channel_unref(chan); + + return 0; } diff --git a/common/glib-helper.h b/common/glib-helper.h index 71377516..7426a6ad 100644 --- a/common/glib-helper.h +++ b/common/glib-helper.h @@ -20,3 +20,9 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ + +typedef void (*bt_callback_t) (gpointer user_data, sdp_list_t *recs, int err); +typedef void (*bt_destroy_t) (gpointer user_data); + +int bt_discover_services(const bdaddr_t *src, const bdaddr_t *dst, + bt_callback_t cb, void *user_data, bt_destroy_t destroy); diff --git a/hcid/adapter.c b/hcid/adapter.c index 5784b863..e58cb87a 100644 --- a/hcid/adapter.c +++ b/hcid/adapter.c @@ -62,6 +62,8 @@ #include "dbus-sdp.h" #include "dbus-error.h" #include "error.h" +#include "glib-helper.h" +#include "logging.h" #define NUM_ELEMENTS(table) (sizeof(table)/sizeof(const char *)) @@ -3174,17 +3176,44 @@ static DBusHandlerResult list_devices(DBusConnection *conn, return send_message_and_unref(conn, reply); } +static void discover_services_cb(gpointer user_data, sdp_list_t *recs, int err) +{ + struct adapter *adapter = user_data; + DBusMessage *reply; + + if (err < 0) { + error_connection_attempt_failed(adapter->create->conn, + adapter->create->msg, -err); + goto failed; + } + + /* FIXME: Register the device object path */ + + reply = dbus_message_new_method_return(adapter->create->msg); + send_message_and_unref(adapter->create->conn, reply); + +failed: + dbus_connection_unref(adapter->create->conn); + dbus_message_unref(adapter->create->msg); + g_free(adapter->create); + adapter->create = NULL; +} + static DBusHandlerResult create_device(DBusConnection *conn, - DBusMessage *msg, void *data) + DBusMessage *msg, void *data) { struct adapter *adapter = data; - struct device *device; - DBusMessage *reply; - const char *address, *path; + struct create_device_req *create; + const char *address; + bdaddr_t src, dst; + int err; if (!hcid_dbus_use_experimental()) return error_unknown_method(conn, msg); + if (adapter->create) + return error_in_progress(conn, msg, "CreateDevice in progress"); + if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID) == FALSE) return error_invalid_arguments(conn, msg, NULL); @@ -3192,18 +3221,21 @@ static DBusHandlerResult create_device(DBusConnection *conn, if (check_address(address) < 0) return error_invalid_arguments(conn, msg, NULL); - reply = dbus_message_new_method_return(msg); - if (!reply) - return DBUS_HANDLER_RESULT_NEED_MEMORY; - - device = device_create(adapter, address); - - path = device->path; + str2ba(adapter->address, &src); + str2ba(address, &dst); + err = bt_discover_services(&src, &dst, + discover_services_cb, adapter, NULL); + if (err < 0) { + error("Discover services failed!"); + return error_connection_attempt_failed(conn, msg, -err); + } - dbus_message_append_args(reply, DBUS_TYPE_STRING, &path, - DBUS_TYPE_INVALID); + create = g_malloc0(sizeof(struct create_device_req)); + create->conn = dbus_connection_ref(conn); + create->msg = dbus_message_ref(msg); + adapter->create = create; - return send_message_and_unref(conn, reply); + return DBUS_HANDLER_RESULT_HANDLED; } static DBusHandlerResult remove_device(DBusConnection *conn, diff --git a/hcid/adapter.h b/hcid/adapter.h index 0331f29a..b6f30291 100644 --- a/hcid/adapter.h +++ b/hcid/adapter.h @@ -80,6 +80,11 @@ struct pending_dc_info { guint timeout_id; }; +struct create_device_req { + DBusConnection *conn; + DBusMessage *msg; +}; + struct adapter { uint16_t dev_id; int up; @@ -106,6 +111,7 @@ struct adapter { struct bonding_request_info *bonding; GSList *pin_reqs; struct pending_dc_info *pending_dc; + struct create_device_req *create; }; dbus_bool_t adapter_init(DBusConnection *conn, const char *path); -- cgit