diff options
author | Claudio Takahasi <claudio.takahasi@openbossa.org> | 2008-03-06 21:58:13 +0000 |
---|---|---|
committer | Claudio Takahasi <claudio.takahasi@openbossa.org> | 2008-03-06 21:58:13 +0000 |
commit | 6eab5e203d793fbeea8a488a315a62ab2e69417e (patch) | |
tree | 3843d76b14275da37d94acbe49c05a6eb3c29cee /common/glib-helper.c | |
parent | 51a5483169faa3b64b50970891a545192836ee9b (diff) |
added bt_discover_services function
Diffstat (limited to 'common/glib-helper.c')
-rw-r--r-- | common/glib-helper.c | 141 |
1 files changed, 137 insertions, 4 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 <sys/socket.h> #include <bluetooth/bluetooth.h> +#include <bluetooth/sdp.h> +#include <bluetooth/sdp_lib.h> #include <glib.h> #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; } |