summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/glib-helper.c141
-rw-r--r--common/glib-helper.h6
-rw-r--r--hcid/adapter.c60
-rw-r--r--hcid/adapter.h6
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 <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;
}
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);