diff options
| author | Johan Hedberg <johan.hedberg@nokia.com> | 2006-08-23 14:33:58 +0000 | 
|---|---|---|
| committer | Johan Hedberg <johan.hedberg@nokia.com> | 2006-08-23 14:33:58 +0000 | 
| commit | 684ba3688de17a3b8a6defd3139e1b8bf8971ef5 (patch) | |
| tree | ab10267b189a8d6a26730e2dd5621a0eaa5b233a | |
| parent | d6faebdc8a88ed8338dc68beefbfbae7e303f895 (diff) | |
Add preliminary RFCOMM.Connect and RFCOMM.CancelConnect support
| -rw-r--r-- | hcid/dbus-api.txt | 4 | ||||
| -rw-r--r-- | hcid/dbus-rfcomm.c | 126 | ||||
| -rw-r--r-- | hcid/dbus-sdp.c | 71 | ||||
| -rw-r--r-- | hcid/dbus.h | 4 | 
4 files changed, 199 insertions, 6 deletions
| diff --git a/hcid/dbus-api.txt b/hcid/dbus-api.txt index 35d60264..825314a1 100644 --- a/hcid/dbus-api.txt +++ b/hcid/dbus-api.txt @@ -893,8 +893,8 @@ Object path	/org/bluez/{hci0,hci1,...}  Methods		string Connect(string address, string service)  			This creates a connection to a remote RFCOMM based -			service. The service string can either be a UUID-16, -			a UUID-32, a UUID-128 or a service abbreviation. +			service. The service string can either be a UUID-128, +			a service abbreviation or a record handle.  			The return value will be the path of the newly  			created RFCOMM TTY device (for example /dev/rfcomm0). diff --git a/hcid/dbus-rfcomm.c b/hcid/dbus-rfcomm.c index f4215f92..61a0365f 100644 --- a/hcid/dbus-rfcomm.c +++ b/hcid/dbus-rfcomm.c @@ -33,11 +33,15 @@  #include <fcntl.h>  #include <sys/ioctl.h>  #include <sys/socket.h> +#include <arpa/inet.h>  #include <bluetooth/bluetooth.h>  #include <bluetooth/rfcomm.h>  #include <bluetooth/hci.h>  #include <bluetooth/hci_lib.h> +#include <bluetooth/sdp.h> +#include <bluetooth/sdp_lib.h> +  #include <dbus/dbus.h> @@ -452,18 +456,132 @@ static struct rfcomm_node *rfcomm_bind(bdaddr_t *src, const char *bda, uint8_t c  	return node;  } +static sdp_record_t *get_record_from_string (const char *dst,  +					     const char *string)	 +{ +	uuid_t short_uuid; +	uuid_t *uuid; +	sdp_record_t *rec = NULL;	 +	unsigned int data0, data4; +	unsigned short data1, data2, data3, data5; +	long handle; + +	/* Check if the string is a service name */ +	short_uuid.value.uuid16 = sdp_str2svclass (string); +	 +	if (short_uuid.value.uuid16) { +		short_uuid.type = SDP_UUID16; +		uuid = sdp_uuid_to_uuid128 (&short_uuid); +		rec = find_record_by_uuid (dst, uuid); +	} else if (sscanf (string, "%8x-%4hx-%4hx-%4hx-%8x%4hx", &data0,  +			   &data1, &data2, &data3, &data4, &data5) == 6) { +		data0 = htonl(data0); +		data1 = htons(data1); +		data2 = htons(data2); +		data3 = htons(data3); +		data4 = htonl(data4); +		data5 = htons(data5); +		 +		uuid = malloc (sizeof(uuid_t)); +		uuid->type = SDP_UUID128; +		memcpy (&uuid->value.uuid128.data[0], &data0, 4); +		memcpy (&uuid->value.uuid128.data[4], &data1, 2); +		memcpy (&uuid->value.uuid128.data[6], &data2, 2); +		memcpy (&uuid->value.uuid128.data[8], &data3, 2); +		memcpy (&uuid->value.uuid128.data[10], &data4, 4); +		memcpy (&uuid->value.uuid128.data[14], &data5, 2); + +		rec = find_record_by_uuid (dst, uuid); +	} else if ((handle = strtol (string, (char **)NULL, 0))) { +		rec = find_record_by_handle (dst, handle); +	} +	 +	return rec; +} +  static DBusHandlerResult rfcomm_connect_req(DBusConnection *conn,  						DBusMessage *msg, void *data)  { -	error("RFCOMM.Connect not implemented"); -	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +	int ch = -1; +	const char *dst; +	const char *string; +	sdp_record_t *rec;	 +	sdp_list_t *protos; +	bdaddr_t bdaddr; +	struct hci_dbus_data *dbus_data = data; +	int err; + +	if (!dbus_message_get_args(msg, NULL, +				   DBUS_TYPE_STRING, &dst, +				   DBUS_TYPE_STRING, &string, +				   DBUS_TYPE_INVALID)) +		return error_invalid_arguments(conn, msg); + +	hci_devba(dbus_data->dev_id, &bdaddr); + +	rec = get_record_from_string (dst, string); + +	if (!rec) +		return error_record_does_not_exist (conn, msg); +	 +	if (sdp_get_access_protos(rec, &protos) == 0) +		ch = sdp_get_proto_port (protos, RFCOMM_UUID); + +	if (ch == -1) +		return error_record_does_not_exist (conn, msg); + +	if (find_pending_connect(dst, ch)) +		return error_connect_in_progress(conn, msg); +	 +	if (rfcomm_connect(conn, msg, &bdaddr, dst, NULL, ch, &err) < 0) +		return error_failed(conn, msg, err); +	 +	return DBUS_HANDLER_RESULT_HANDLED;  }  static DBusHandlerResult rfcomm_cancel_connect_req(DBusConnection *conn,  						DBusMessage *msg, void *data)  { -	error("RFCOMM.CancelConnect not implemented"); -	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +	int ch = -1; +	const char *dst; +	const char *string; +	sdp_record_t *rec;	 +	sdp_list_t *protos; +	bdaddr_t bdaddr; +	struct hci_dbus_data *dbus_data = data; +	DBusMessage *reply; +	struct pending_connect *pending; + +	if (!dbus_message_get_args(msg, NULL, +				   DBUS_TYPE_STRING, &dst, +				   DBUS_TYPE_STRING, &string, +				   DBUS_TYPE_INVALID)) +		return error_invalid_arguments(conn, msg); + +	hci_devba(dbus_data->dev_id, &bdaddr); + +	rec = get_record_from_string (dst, string); + +	if (!rec) +		return error_record_does_not_exist (conn, msg); +	 +	if (sdp_get_access_protos(rec, &protos) == 0) +		ch = sdp_get_proto_port (protos, RFCOMM_UUID); + +	if (ch == -1) +		return error_record_does_not_exist (conn, msg); + +	reply = dbus_message_new_method_return (msg); +	if (!reply) +		return DBUS_HANDLER_RESULT_NEED_MEMORY; + +	pending = find_pending_connect(dst, ch); +	if (!pending) +		return error_connect_not_in_progress(conn, msg); + +	pending->canceled = 1; +	 +	return send_reply_and_unref(conn, reply);  }  static DBusHandlerResult rfcomm_connect_by_ch_req(DBusConnection *conn, diff --git a/hcid/dbus-sdp.c b/hcid/dbus-sdp.c index cfc4f4f2..2634a5ea 100644 --- a/hcid/dbus-sdp.c +++ b/hcid/dbus-sdp.c @@ -833,6 +833,77 @@ search_request:  } +static int sdp_uuid_comp_func(const void *key1, const void *key2) +{	 +	const uuid_t *a = (const uuid_t *)key1; +	const uuid_t *b = (const uuid_t *)key2; + +	if (a->type != b->type) +		return 1; +	 +	switch (a->type) { +	case SDP_UUID16:		 +		return !(a->value.uuid16 == b->value.uuid16); +		break; +        case SDP_UUID32: +		return !(a->value.uuid32 == b->value.uuid32); +		break; +        case SDP_UUID128: +		return !memcmp(&a->value.uuid128, &b->value.uuid128,  +			       sizeof(uint128_t)); +		break; +	} +	return 1; +} + +sdp_record_t *find_record_by_uuid(const char *address, uuid_t *uuid) +{ +	struct slist *lp, *lr; +	struct service_provider *p; +	struct service_record *r; +	sdp_list_t *list = 0; +	 + +	for (lp = sdp_cache; lp; lp = lp->next) { +		p = lp->data; +		if (strcmp(p->prov, address)) +			continue; + +		for (lr = p->lrec; lr; lr = lr->next) { +			r = lr->data; +			/* Check whether the record has the correct uuid */ +			if (sdp_get_service_classes(r->record, &list) !=0) +				continue; +			 +			if (sdp_list_find (list, &uuid, sdp_uuid_comp_func)) +				return r->record; +		} +	} + +	return NULL; +}	 + +sdp_record_t *find_record_by_handle(const char *address, int handle) +{ +	struct slist *lp, *lr; +	struct service_provider *p; +	struct service_record *r; + +	for (lp = sdp_cache; lp; lp = lp->next) { +		p = lp->data; +		if (strcmp(p->prov, address)) +			continue; + +		for (lr = p->lrec; lr; lr = lr->next) { +			r = lr->data; +			if (r->record->handle == handle) +				return r->record; +		} +	} + +	return NULL; +} +  static sdp_record_t *find_record(const char *address, int id)  {  	struct slist *lp, *lr; diff --git a/hcid/dbus.h b/hcid/dbus.h index f33ebc3a..0e0e95bb 100644 --- a/hcid/dbus.h +++ b/hcid/dbus.h @@ -219,4 +219,8 @@ int disc_device_req_name(struct hci_dbus_data *dbus_data);  int discoverable_timeout_handler(void *data); +sdp_record_t *find_record_by_uuid(const char *address, uuid_t *uuid); +sdp_record_t *find_record_by_handle(const char *address, int handle); +uint16_t sdp_str2svclass(const char *str); +  #endif /* __H_BLUEZ_DBUS_H__ */ | 
