diff options
| -rw-r--r-- | common/glib-helper.c | 141 | ||||
| -rw-r--r-- | common/glib-helper.h | 6 | ||||
| -rw-r--r-- | hcid/adapter.c | 60 | ||||
| -rw-r--r-- | 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 <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); | 
