Hello community,
here is the log from the commit of package bluez-libs
checked in at Thu Sep 7 01:08:51 CEST 2006.
--------
--- bluez-libs/bluez-libs.changes 2006-08-31 11:56:42.000000000 +0200
+++ bluez-libs/bluez-libs.changes 2006-09-06 19:25:24.000000000 +0200
@@ -1,0 +2,6 @@
+Wed Sep 6 19:25:03 CEST 2006 - seife@suse.de
+
+- update to v3.5:
+ * Add asynchronous API for SDP.
+
+-------------------------------------------------------------------
Old:
----
bluez-libs-3.4.tar.gz
New:
----
bluez-libs-3.5.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ bluez-libs.spec ++++++
--- /var/tmp/diff_new_pack.EkB2ED/_old 2006-09-07 01:07:51.000000000 +0200
+++ /var/tmp/diff_new_pack.EkB2ED/_new 2006-09-07 01:07:51.000000000 +0200
@@ -1,5 +1,5 @@
#
-# spec file for package bluez-libs (Version 3.4)
+# spec file for package bluez-libs (Version 3.5)
#
# Copyright (c) 2006 SUSE LINUX Products GmbH, Nuernberg, Germany.
# This file and all modifications and additions to the pristine
@@ -12,7 +12,7 @@
Name: bluez-libs
URL: http://bluez.sourceforge.net
-Version: 3.4
+Version: 3.5
Release: 1
Summary: Bluetooth Libraries
License: GPL
@@ -64,6 +64,9 @@
%doc AUTHORS COPYING INSTALL ChangeLog NEWS README
%changelog -n bluez-libs
+* Wed Sep 06 2006 - seife@suse.de
+- update to v3.5:
+ * Add asynchronous API for SDP.
* Wed Aug 30 2006 - dgollub@suse.de
- update to v3.4
* Fix UUID128 string lookup handling
++++++ bluez-libs-3.4.tar.gz -> bluez-libs-3.5.tar.gz ++++++
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/bluez-libs-3.4/ChangeLog new/bluez-libs-3.5/ChangeLog
--- old/bluez-libs-3.4/ChangeLog 2006-08-25 03:16:10.000000000 +0200
+++ new/bluez-libs-3.5/ChangeLog 2006-09-06 16:39:41.000000000 +0200
@@ -1,3 +1,6 @@
+ver 3.5:
+ Add asynchronous API for SDP.
+
ver 3.4:
Fix UUID128 string lookup handling.
Fix malloc() versus bt_malloc() usage.
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/bluez-libs-3.4/configure new/bluez-libs-3.5/configure
--- old/bluez-libs-3.4/configure 2006-08-25 03:17:57.000000000 +0200
+++ new/bluez-libs-3.5/configure 2006-09-06 16:44:38.000000000 +0200
@@ -1775,7 +1775,7 @@
# Define the identity of the package.
PACKAGE=bluez-libs
- VERSION=3.4
+ VERSION=3.5
cat >>confdefs.h <<_ACEOF
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/bluez-libs-3.4/configure.in new/bluez-libs-3.5/configure.in
--- old/bluez-libs-3.4/configure.in 2006-08-25 03:16:11.000000000 +0200
+++ new/bluez-libs-3.5/configure.in 2006-09-06 16:39:41.000000000 +0200
@@ -1,7 +1,7 @@
AC_PREREQ(2.50)
AC_INIT()
-AM_INIT_AUTOMAKE(bluez-libs, 3.4)
+AM_INIT_AUTOMAKE(bluez-libs, 3.5)
AM_CONFIG_HEADER(config.h)
AM_MAINTAINER_MODE
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/bluez-libs-3.4/include/sdp_lib.h new/bluez-libs-3.5/include/sdp_lib.h
--- old/bluez-libs-3.4/include/sdp_lib.h 2006-08-22 08:26:05.000000000 +0200
+++ new/bluez-libs-3.5/include/sdp_lib.h 2006-09-06 16:39:42.000000000 +0200
@@ -80,6 +80,7 @@
*/
#define SDP_RETRY_IF_BUSY 0x01
#define SDP_WAIT_ON_CLOSE 0x02
+#define SDP_NON_BLOCKING 0x04
/*
* a session with an SDP server
@@ -93,6 +94,19 @@
void *priv;
} sdp_session_t;
+typedef enum {
+ /*
+ * Attributes are specified as individual elements
+ */
+ SDP_ATTR_REQ_INDIVIDUAL = 1,
+ /*
+ * Attributes are specified as a range
+ */
+ SDP_ATTR_REQ_RANGE
+} sdp_attrreq_type_t;
+
+typedef void sdp_callback_t(uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *udata);
+
/*
* create an L2CAP connection to a Bluetooth device
*
@@ -109,6 +123,17 @@
int sdp_close(sdp_session_t *session);
int sdp_get_socket(const sdp_session_t *session);
+/*
+ * SDP transaction: functions for asynchronous search.
+ */
+sdp_session_t *sdp_create(int sk, uint32_t flags);
+int sdp_process(sdp_session_t *session);
+int sdp_set_notify(sdp_session_t *session, sdp_callback_t *func, void *udata);
+
+int sdp_service_search_async(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num);
+int sdp_service_attr_async(sdp_session_t *session, uint32_t handle, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list);
+int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list);
+
uint16_t sdp_gen_tid(sdp_session_t *session);
/*
@@ -289,7 +314,7 @@
*
* INPUT :
*
- * sdp_list_t *search_list
+ * sdp_list_t *search
* list containing elements of the search
* pattern. Each entry in the list is a UUID
* of the service to be searched
@@ -312,7 +337,7 @@
* non-zero service handles. It is a singly linked list of
* service record handles (uint16_t)
*/
-int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search_list, uint16_t max_rec_num, sdp_list_t **rsp_list);
+int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num, sdp_list_t **rsp_list);
/*
* a service attribute request.
@@ -347,18 +372,6 @@
* -1
* The request completed unsuccessfully due to a timeout
*/
-
-typedef enum {
- /*
- * Attributes are specified as individual elements
- */
- SDP_ATTR_REQ_INDIVIDUAL = 1,
- /*
- * Attributes are specified as a range
- */
- SDP_ATTR_REQ_RANGE
-} sdp_attrreq_type_t;
-
sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list);
/*
@@ -368,7 +381,7 @@
*
* INPUT :
*
- * sdp_list_t *search_list
+ * sdp_list_t *search
* Singly linked list containing elements of the search
* pattern. Each entry in the list is a UUID(DataTypeSDP_UUID16)
* of the service to be searched
@@ -402,7 +415,7 @@
* service(s) found. Each element of this list is of type
* sdp_record_t *.
*/
-int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search_list, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list, sdp_list_t **rsp_list);
+int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list, sdp_list_t **rsp_list);
/*
* Allocate/free a service record and its attributes
@@ -582,11 +595,6 @@
int sdp_send_req_w4_rsp(sdp_session_t *session, uint8_t *req, uint8_t *rsp, uint32_t reqsize, uint32_t *rspsize);
-typedef struct {
- uint8_t length;
- unsigned char data[16];
-} __attribute__ ((packed)) sdp_cstate_t;
-
#ifdef __cplusplus
}
#endif
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/bluez-libs-3.4/src/Makefile.am new/bluez-libs-3.5/src/Makefile.am
--- old/bluez-libs-3.4/src/Makefile.am 2006-08-25 03:16:11.000000000 +0200
+++ new/bluez-libs-3.5/src/Makefile.am 2006-09-06 16:39:42.000000000 +0200
@@ -2,7 +2,7 @@
lib_LTLIBRARIES = libbluetooth.la
libbluetooth_la_SOURCES = bluetooth.c hci.c sdp.c
-libbluetooth_la_LDFLAGS = -version-info 4:1:2
+libbluetooth_la_LDFLAGS = -version-info 5:0:3
INCLUDES = -I$(top_builddir)/include
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/bluez-libs-3.4/src/Makefile.in new/bluez-libs-3.5/src/Makefile.in
--- old/bluez-libs-3.4/src/Makefile.in 2006-08-25 03:17:56.000000000 +0200
+++ new/bluez-libs-3.5/src/Makefile.in 2006-09-06 16:44:37.000000000 +0200
@@ -165,7 +165,7 @@
target_alias = @target_alias@
lib_LTLIBRARIES = libbluetooth.la
libbluetooth_la_SOURCES = bluetooth.c hci.c sdp.c
-libbluetooth_la_LDFLAGS = -version-info 4:1:2
+libbluetooth_la_LDFLAGS = -version-info 5:0:3
INCLUDES = -I$(top_builddir)/include
MAINTAINERCLEANFILES = Makefile.in
all: all-am
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/bluez-libs-3.4/src/bluetooth.c new/bluez-libs-3.5/src/bluetooth.c
--- old/bluez-libs-3.4/src/bluetooth.c 2006-05-30 12:51:54.000000000 +0200
+++ new/bluez-libs-3.5/src/bluetooth.c 2006-09-06 16:39:42.000000000 +0200
@@ -382,6 +382,8 @@
return "CONWISE Technology Corporation Ltd";
case 67:
return "PARROT SA";
+ case 68:
+ return "Socket Communications";
case 65535:
return "internal use";
default:
diff -urN --exclude=CVS --exclude=.cvsignore --exclude=.svn --exclude=.svnignore old/bluez-libs-3.4/src/sdp.c new/bluez-libs-3.5/src/sdp.c
--- old/bluez-libs-3.4/src/sdp.c 2006-08-25 03:16:12.000000000 +0200
+++ new/bluez-libs-3.5/src/sdp.c 2006-09-06 16:39:45.000000000 +0200
@@ -31,6 +31,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -89,9 +90,6 @@
static uint128_t *bluetooth_base_uuid = NULL;
-#define SDP_BASIC_ATTR_PDUFORM_SIZE 32
-#define SDP_SEQ_PDUFORM_SIZE 128
-#define SDP_UUID_SEQ_SIZE 256
#define SDP_MAX_ATTR_LEN 65535
/* Message structure. */
@@ -807,14 +805,15 @@
int sdp_gen_record_pdu(const sdp_record_t *rec, sdp_buf_t *buf)
{
buf->data = malloc(SDP_PDU_CHUNK_SIZE);
- if (buf->data) {
- buf->buf_size = SDP_PDU_CHUNK_SIZE;
- buf->data_size = 0;
- memset(buf->data, 0, buf->buf_size);
- sdp_list_foreach(rec->attrlist, sdp_attr_pdu, buf);
- return 0;
- }
- return -1;
+ if (!buf->data)
+ return -ENOMEM;
+
+ buf->buf_size = SDP_PDU_CHUNK_SIZE;
+ buf->data_size = 0;
+ memset(buf->data, 0, buf->buf_size);
+ sdp_list_foreach(rec->attrlist, sdp_attr_pdu, buf);
+
+ return 0;
}
void sdp_attr_replace(sdp_record_t *rec, uint16_t attr, sdp_data_t *d)
@@ -1148,13 +1147,13 @@
{
sdp_data_t *d = sdp_data_get(rec, SDP_ATTR_SVCNAME_PRIMARY);
if (d)
- printf("Service Name: %s\n", d->val.str);
+ printf("Service Name: %.*s\n", d->unitSize, d->val.str);
d = sdp_data_get(rec, SDP_ATTR_SVCDESC_PRIMARY);
if (d)
- printf("Service Description: %s\n", d->val.str);
+ printf("Service Description: %.*s\n", d->unitSize, d->val.str);
d = sdp_data_get(rec, SDP_ATTR_PROVNAME_PRIMARY);
if (d)
- printf("Service Provider: %s\n", d->val.str);
+ printf("Service Provider: %.*s\n", d->unitSize, d->val.str);
}
#ifdef SDP_DEBUG
@@ -2375,12 +2374,14 @@
void sdp_append_to_pdu(sdp_buf_t *pdu, sdp_data_t *d)
{
- uint8_t buf[SDP_SEQ_PDUFORM_SIZE];
+ uint8_t buf[256];
sdp_buf_t append;
+ memset(&append, 0, sizeof(sdp_buf_t));
append.data = buf;
append.buf_size = sizeof(buf);
append.data_size = 0;
+
sdp_set_attrid(&append, d->attrId);
sdp_gen_pdu(&append, d);
sdp_append_to_buf(pdu, append.data, append.data_size);
@@ -2678,8 +2679,11 @@
SDPDBG("");
memset(&buf, 0, sizeof(sdp_buf_t));
- buf.data = malloc(SDP_UUID_SEQ_SIZE);
- buf.buf_size = SDP_UUID_SEQ_SIZE;
+ buf.data = malloc(256);
+ buf.buf_size = 256;
+
+ if (!buf.data)
+ return -ENOMEM;
SDPDBG("Seq length : %d\n", seqlen);
@@ -2719,6 +2723,11 @@
return gen_dataseq_pdu(dst, seq, dataType);
}
+typedef struct {
+ uint8_t length;
+ unsigned char data[16];
+} __attribute__ ((packed)) sdp_cstate_t;
+
static int copy_cstate(uint8_t *pdata, const sdp_cstate_t *cstate)
{
if (cstate) {
@@ -2735,7 +2744,7 @@
*
* INPUT :
*
- * sdp_list_t *search_list
+ * sdp_list_t *search
* Singly linked list containing elements of the search
* pattern. Each entry in the list is a UUID (DataTypeSDP_UUID16)
* of the service to be searched
@@ -3033,6 +3042,545 @@
}
/*
+ * SDP transaction structure for asynchronous search
+ */
+struct sdp_transaction {
+ sdp_callback_t *cb; /* called when the transaction finishes */
+ void *udata; /* client user data */
+ uint8_t *reqbuf; /* pointer to request PDU */
+ sdp_buf_t rsp_concat_buf;
+ uint32_t reqsize; /* without cstate */
+};
+
+/*
+ * Creates a new sdp session for asynchronous search
+ * INPUT:
+ * int sk
+ * non-blocking L2CAP socket
+ *
+ * RETURN:
+ * sdp_session_t *
+ * NULL - On memory allocation failure
+ */
+sdp_session_t *sdp_create(int sk, uint32_t flags)
+{
+ sdp_session_t *session;
+ struct sdp_transaction *t;
+
+ session = malloc(sizeof(sdp_session_t));
+ if (!session) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ memset(session, 0, sizeof(*session));
+
+ session->flags = flags;
+ session->sock = sk;
+
+ t = malloc(sizeof(struct sdp_transaction));
+ if (!t) {
+ errno = ENOMEM;
+ free(session);
+ return NULL;
+ }
+ memset(t, 0, sizeof(*t));
+
+ session->priv = t;
+
+ return session;
+}
+
+/*
+ * Sets the callback function/user data used to notify the application
+ * that the asynchronous transaction finished. This function must be
+ * called before request an asynchronous search.
+ *
+ * INPUT:
+ * sdp_session_t *session
+ * Current sdp session to be handled
+ * sdp_callback_t *cb
+ * callback to be called when the transaction finishes
+ * void *udata
+ * user data passed to callback
+ * RETURN:
+ * 0 - Success
+ * -1 - Failure
+ */
+int sdp_set_notify(sdp_session_t *session, sdp_callback_t *func, void *udata)
+{
+ struct sdp_transaction *t;
+
+ if (!session || !session->priv)
+ return -1;
+
+ t = session->priv;
+ t->cb = func;
+ t->udata = udata;
+
+ return 0;
+}
+
+/*
+ * This function starts an asynchronous service search request.
+ * The incomming and outgoing data are stored in the transaction structure
+ * buffers. When there is incomming data the sdp_process function must be
+ * called to get the data and handle the continuation state.
+ *
+ * INPUT :
+ * sdp_session_t *session
+ * Current sdp session to be handled
+ *
+ * sdp_list_t *search
+ * Singly linked list containing elements of the search
+ * pattern. Each entry in the list is a UUID (DataTypeSDP_UUID16)
+ * of the service to be searched
+ *
+ * uint16_t max_rec_num
+ * A 16 bit integer which tells the service, the maximum
+ * entries that the client can handle in the response. The
+ * server is obliged not to return > max_rec_num entries
+ *
+ * OUTPUT :
+ *
+ * int return value
+ * 0 - if the request has been sent properly
+ * -1 - On any failure and sets errno
+ */
+
+int sdp_service_search_async(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num)
+{
+ struct sdp_transaction *t;
+ sdp_pdu_hdr_t *reqhdr;
+ uint8_t *pdata;
+ int cstate_len, seqlen = 0;
+
+ if (!session || !session->priv) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ t = session->priv;
+ t->reqbuf = malloc(SDP_REQ_BUFFER_SIZE);
+ if (!t->reqbuf) {
+ errno = ENOMEM;
+ goto end;
+ }
+
+ memset(t->reqbuf, 0, SDP_REQ_BUFFER_SIZE);
+ memset((char *)&t->rsp_concat_buf, 0, sizeof(sdp_buf_t));
+
+ reqhdr = (sdp_pdu_hdr_t *) t->reqbuf;
+ reqhdr->tid = htons(sdp_gen_tid(session));
+ reqhdr->pdu_id = SDP_SVC_SEARCH_REQ;
+
+ // generate PDU
+ pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t);
+ t->reqsize = sizeof(sdp_pdu_hdr_t);
+
+ // add service class IDs for search
+ seqlen = gen_searchseq_pdu(pdata, search);
+
+ SDPDBG("Data seq added : %d\n", seqlen);
+
+ // now set the length and increment the pointer
+ t->reqsize += seqlen;
+ pdata += seqlen;
+
+ bt_put_unaligned(htons(max_rec_num), (uint16_t *) pdata);
+ t->reqsize += sizeof(uint16_t);
+ pdata += sizeof(uint16_t);
+
+
+ // set the request header's param length
+ cstate_len = copy_cstate(pdata, NULL);
+ reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));
+
+ if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) {
+ SDPERR("Error sendind data:%s", strerror(errno));
+ goto end;
+ }
+
+ return 0;
+end:
+
+ if (t) {
+ if (t->reqbuf)
+ free(t->reqbuf);
+ free(t);
+ }
+
+ return -1;
+}
+
+/*
+ * This function starts an asynchronous service attribute request.
+ * The incomming and outgoing data are stored in the transaction structure
+ * buffers. When there is incomming data the sdp_process function must be
+ * called to get the data and handle the continuation state.
+ *
+ * INPUT :
+ * sdp_session_t *session
+ * Current sdp session to be handled
+ *
+ * uint32_t handle
+ * The handle of the service for which the attribute(s) are
+ * requested
+ *
+ * sdp_attrreq_type_t reqtype
+ * Attribute identifiers are 16 bit unsigned integers specified
+ * in one of 2 ways described below :
+ * SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers
+ * They are the actual attribute identifiers in ascending order
+ *
+ * SDP_ATTR_REQ_RANGE - 32bit identifier range
+ * The high-order 16bits is the start of range
+ * the low-order 16bits are the end of range
+ * 0x0000 to 0xFFFF gets all attributes
+ *
+ * sdp_list_t *attrid_list
+ * Singly linked list containing attribute identifiers desired.
+ * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
+ * or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
+ *
+ * OUTPUT :
+ * int return value
+ * 0 - if the request has been sent properly
+ * -1 - On any failure and sets errno
+ */
+
+int sdp_service_attr_async(sdp_session_t *session, uint32_t handle, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list)
+{
+ struct sdp_transaction *t;
+ sdp_pdu_hdr_t *reqhdr;
+ uint8_t *pdata;
+ int cstate_len, seqlen = 0;
+
+ if (!session || !session->priv) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ t = session->priv;
+ t->reqbuf = malloc(SDP_REQ_BUFFER_SIZE);
+ if (!t->reqbuf) {
+ errno = ENOMEM;
+ goto end;
+ }
+
+ memset(t->reqbuf, 0, SDP_REQ_BUFFER_SIZE);
+ memset((char *)&t->rsp_concat_buf, 0, sizeof(sdp_buf_t));
+
+ reqhdr = (sdp_pdu_hdr_t *) t->reqbuf;
+ reqhdr->tid = htons(sdp_gen_tid(session));
+ reqhdr->pdu_id = SDP_SVC_ATTR_REQ;
+
+ // generate PDU
+ pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t);
+ t->reqsize = sizeof(sdp_pdu_hdr_t);
+
+ // add the service record handle
+ bt_put_unaligned(htonl(handle), (uint32_t *) pdata);
+ t->reqsize += sizeof(uint32_t);
+ pdata += sizeof(uint32_t);
+
+ // specify the response limit
+ bt_put_unaligned(htons(65535), (uint16_t *) pdata);
+ t->reqsize += sizeof(uint16_t);
+ pdata += sizeof(uint16_t);
+
+ // get attr seq PDU form
+ seqlen = gen_attridseq_pdu(pdata, attrid_list,
+ reqtype == SDP_ATTR_REQ_INDIVIDUAL? SDP_UINT16 : SDP_UINT32);
+ if (seqlen == -1) {
+ errno = EINVAL;
+ goto end;
+ }
+
+ // now set the length and increment the pointer
+ t->reqsize += seqlen;
+ pdata += seqlen;
+ SDPDBG("Attr list length : %d\n", seqlen);
+
+ // set the request header's param length
+ cstate_len = copy_cstate(pdata, NULL);
+ reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));
+
+ if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) {
+ SDPERR("Error sendind data:%s", strerror(errno));
+ goto end;
+ }
+
+ return 0;
+end:
+
+ if (t) {
+ if (t->reqbuf)
+ free(t->reqbuf);
+ free(t);
+ }
+
+ return -1;
+}
+
+/*
+ * This function starts an asynchronous service search attributes.
+ * It is a service search request combined with attribute request. The incomming
+ * and outgoing data are stored in the transaction structure buffers. When there
+ * is incomming data the sdp_process function must be called to get the data
+ * and handle the continuation state.
+ *
+ * INPUT:
+ * sdp_session_t *session
+ * Current sdp session to be handled
+ *
+ * sdp_list_t *search
+ * Singly linked list containing elements of the search
+ * pattern. Each entry in the list is a UUID(DataTypeSDP_UUID16)
+ * of the service to be searched
+ *
+ * AttributeSpecification attrSpec
+ * Attribute identifiers are 16 bit unsigned integers specified
+ * in one of 2 ways described below :
+ * SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers
+ * They are the actual attribute identifiers in ascending order
+ *
+ * SDP_ATTR_REQ_RANGE - 32bit identifier range
+ * The high-order 16bits is the start of range
+ * the low-order 16bits are the end of range
+ * 0x0000 to 0xFFFF gets all attributes
+ *
+ * sdp_list_t *attrid_list
+ * Singly linked list containing attribute identifiers desired.
+ * Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
+ * or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
+ *
+
+ * RETURN:
+ * 0 - if the request has been sent properly
+ * -1 - On any failure
+ */
+int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list)
+{
+ struct sdp_transaction *t;
+ sdp_pdu_hdr_t *reqhdr;
+ uint8_t *pdata;
+ int cstate_len, seqlen = 0;
+
+ if (!session || !session->priv) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ t = session->priv;
+ t->reqbuf = malloc(SDP_REQ_BUFFER_SIZE);
+ if (!t->reqbuf) {
+ errno = ENOMEM;
+ goto end;
+ }
+
+ memset(t->reqbuf, 0, SDP_REQ_BUFFER_SIZE);
+ memset((char *)&t->rsp_concat_buf, 0, sizeof(sdp_buf_t));
+
+ reqhdr = (sdp_pdu_hdr_t *) t->reqbuf;
+ reqhdr->tid = htons(sdp_gen_tid(session));
+ reqhdr->pdu_id = SDP_SVC_SEARCH_ATTR_REQ;
+
+ // generate PDU
+ pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t);
+ t->reqsize = sizeof(sdp_pdu_hdr_t);
+
+ // add service class IDs for search
+ seqlen = gen_searchseq_pdu(pdata, search);
+
+ SDPDBG("Data seq added : %d\n", seqlen);
+
+ // now set the length and increment the pointer
+ t->reqsize += seqlen;
+ pdata += seqlen;
+
+ bt_put_unaligned(htons(SDP_MAX_ATTR_LEN), (uint16_t *) pdata);
+ t->reqsize += sizeof(uint16_t);
+ pdata += sizeof(uint16_t);
+
+ SDPDBG("Max attr byte count : %d\n", SDP_MAX_ATTR_LEN);
+
+ // get attr seq PDU form
+ seqlen = gen_attridseq_pdu(pdata, attrid_list,
+ reqtype == SDP_ATTR_REQ_INDIVIDUAL ? SDP_UINT16 : SDP_UINT32);
+ if (seqlen == -1) {
+ errno = EINVAL;
+ goto end;
+ }
+
+ pdata += seqlen;
+ SDPDBG("Attr list length : %d\n", seqlen);
+ t->reqsize += seqlen;
+
+ // set the request header's param length
+ cstate_len = copy_cstate(pdata, NULL);
+ reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));
+
+ if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) {
+ SDPERR("Error sendind data:%s", strerror(errno));
+ goto end;
+ }
+
+ return 0;
+end:
+
+ if (t) {
+ if (t->reqbuf)
+ free(t->reqbuf);
+ free(t);
+ }
+
+ return -1;
+}
+
+/*
+ * Receive the incomming SDP PDU. This function must be called when there is data
+ * available to be read. On continuation state, the original request (with a new
+ * transaction ID) and the continuation state data will be appended in the initial PDU.
+ * If an error happens or the transaction finishes the callback function will be called.
+ *
+ * INPUT:
+ * sdp_session_t *session
+ * Current sdp session to be handled
+ * RETURN:
+ * 0 - if the transaction is on continuation state
+ * -1 - On any failure or the transaction finished
+ */
+int sdp_process(sdp_session_t *session)
+{
+ struct sdp_transaction *t = NULL;
+ sdp_pdu_hdr_t *reqhdr = NULL;
+ sdp_pdu_hdr_t *rsphdr = NULL;
+ sdp_cstate_t *pcstate = NULL;
+ uint8_t *pdata = NULL, *rspbuf = NULL, *targetPtr = NULL;
+ int rsp_count = 0, err = -1;
+ size_t size = 0;
+ uint16_t status = 0;
+
+ if (!session || !session->priv) {
+ SDPERR("Invalid session");
+ return -1;
+ }
+
+ rspbuf = malloc(SDP_RSP_BUFFER_SIZE);
+ if (!rspbuf)
+ return -1;
+
+ memset(rspbuf, 0, SDP_RSP_BUFFER_SIZE);
+
+ t = session->priv;
+ reqhdr = (sdp_pdu_hdr_t *)t->reqbuf;
+ rsphdr = (sdp_pdu_hdr_t *)rspbuf;
+
+ if (sdp_read_rsp(session, rspbuf, SDP_RSP_BUFFER_SIZE) <= 0)
+ goto end;
+
+ if (reqhdr->tid != rsphdr->tid)
+ goto end;
+
+ pdata = rspbuf + sizeof(sdp_pdu_hdr_t);
+
+ if (rsphdr->pdu_id == SDP_ERROR_RSP) {
+ status = ntohs(bt_get_unaligned((uint16_t *) pdata));
+ size = rsphdr->plen;
+ goto end;
+ }
+
+ switch (rsphdr->pdu_id) {
+ uint8_t *ssr_pdata;
+ uint16_t tsrc, csrc;
+ case SDP_SVC_SEARCH_RSP:
+ /*
+ * TSRC: Total Service Record Count
+ * CSRC: Current Service Record Count
+ */
+ ssr_pdata = pdata;
+ ssr_pdata += sizeof(tsrc);
+ tsrc = ntohs(bt_get_unaligned((uint16_t *) ssr_pdata));
+ csrc = ntohs(bt_get_unaligned((uint16_t *) ssr_pdata));
+
+ if (t->rsp_concat_buf.data_size == 0) {
+ /* first fragment */
+ rsp_count = sizeof(tsrc) + sizeof(csrc) + csrc * 4;
+ SDPDBG("Total svc count: %d\n", tsrc);
+ SDPDBG("Current svc count: %d\n", csrc);
+ } else {
+ pdata += 2 * sizeof(uint16_t); /* Ignore TSRC and CSRC */
+ rsp_count = csrc * 4;
+ }
+ break;
+ case SDP_SVC_ATTR_RSP:
+ case SDP_SVC_SEARCH_ATTR_RSP:
+ rsp_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
+ SDPDBG("Attrlist byte count : %d\n", rsp_count);
+
+ pdata += sizeof(uint16_t); // points to attribute list
+ break;
+ default:
+ /* FIXME: how handle this situation? */
+ SDPDBG("Illegal PDU ID!");
+ goto end;
+ }
+
+ pcstate = (sdp_cstate_t *) (pdata + rsp_count);
+
+ SDPDBG("Cstate length : %d\n", pcstate->length);
+ /*
+ * This is a split response, need to concatenate intermediate
+ * responses and the last one which will have cstate_len == 0
+ */
+
+ // build concatenated response buffer
+ t->rsp_concat_buf.data = realloc(t->rsp_concat_buf.data, t->rsp_concat_buf.data_size + rsp_count);
+ targetPtr = t->rsp_concat_buf.data + t->rsp_concat_buf.data_size;
+ t->rsp_concat_buf.buf_size = t->rsp_concat_buf.data_size + rsp_count;
+ memcpy(targetPtr, pdata, rsp_count);
+ t->rsp_concat_buf.data_size += rsp_count;
+
+ if (pcstate->length > 0) {
+ int reqsize, cstate_len;
+
+ reqhdr->tid = htons(sdp_gen_tid(session));
+
+ // add continuation state (can be null)
+ cstate_len = copy_cstate(t->reqbuf + t->reqsize, pcstate);
+
+ reqsize = t->reqsize + cstate_len;
+
+ // set the request header's param length
+ reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));
+
+ if (sdp_send_req(session, t->reqbuf, reqsize) < 0) {
+ SDPERR("Error sendind data:%s", strerror(errno));
+ /* FIXME: how handle this error ? */
+ goto end;
+ }
+ err = 0;
+ }
+
+end:
+ if (err) {
+ if (t->rsp_concat_buf.data_size != 0) {
+ pdata = t->rsp_concat_buf.data;
+ size = t->rsp_concat_buf.data_size;
+ }
+
+ if (t->cb)
+ t->cb(rsphdr->pdu_id, status, pdata,
+ size, t->udata);
+ }
+
+ if (rspbuf)
+ free(rspbuf);
+
+ return err;
+}
+
+/*
* This is a service search request combined with the service
* attribute request. First a service class match is done and
* for matching service, requested attributes are extracted
@@ -3256,7 +3804,25 @@
int sdp_close(sdp_session_t *session)
{
- int ret = close(session->sock);
+ struct sdp_transaction *t;
+ int ret;
+
+ if (!session)
+ return -1;
+
+ ret = close(session->sock);
+
+ t = session->priv;
+
+ if (t) {
+ if (t->reqbuf)
+ free(t->reqbuf);
+
+ if (t->rsp_concat_buf.data)
+ free(t->rsp_concat_buf.data);
+
+ free(t);
+ }
free(session);
return ret;
}
@@ -3266,59 +3832,104 @@
return memcmp(device, BDADDR_LOCAL, sizeof(bdaddr_t)) == 0;
}
-sdp_session_t *sdp_connect(const bdaddr_t *src, const bdaddr_t *dst, uint32_t flags)
+static int sdp_connect_local(sdp_session_t *session)
+{
+ struct sockaddr_un sa;
+
+ session->sock = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (session->sock < 0)
+ return -1;
+ session->local = 1;
+
+ sa.sun_family = AF_UNIX;
+ strcpy(sa.sun_path, SDP_UNIX_PATH);
+
+ return connect(session->sock, (struct sockaddr *)&sa, sizeof(sa));
+}
+
+static int sdp_connect_l2cap(const bdaddr_t *src,
+ const bdaddr_t *dst, sdp_session_t *session)
{
+ uint32_t flags = session->flags;
+ struct sockaddr_l2 sa;
+ int sk;
+
+ session->sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+ if (session->sock < 0)
+ return -1;
+ session->local = 0;
+
+ sk = session->sock;
+
+ if (flags & SDP_NON_BLOCKING) {
+ long arg = fcntl(sk, F_GETFL, 0);
+ fcntl(sk, F_SETFL, arg | O_NONBLOCK);
+ }
+
+ sa.l2_family = AF_BLUETOOTH;
+ sa.l2_psm = 0;
+
+ if (bacmp(src, BDADDR_ANY)) {
+ sa.l2_bdaddr = *src;
+ if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0)
+ return -1;
+ }
+
+ if (flags & SDP_WAIT_ON_CLOSE) {
+ struct linger l = { .l_onoff = 1, .l_linger = 1 };
+ setsockopt(sk, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
+ }
+
+ sa.l2_psm = htobs(SDP_PSM);
+ sa.l2_bdaddr = *dst;
+
+ do {
+ int ret = connect(sk, (struct sockaddr *) &sa, sizeof(sa));
+ if (!ret)
+ return 0;
+ if (ret < 0 && (flags & SDP_NON_BLOCKING) &&
+ (errno == EAGAIN || errno == EINPROGRESS))
+ return 0;
+ } while (errno == EBUSY && (flags & SDP_RETRY_IF_BUSY));
+
+ return -1;
+}
+
+sdp_session_t *sdp_connect(const bdaddr_t *src,
+ const bdaddr_t *dst, uint32_t flags)
+{
+ sdp_session_t *session;
int err;
- sdp_session_t *session = malloc(sizeof(sdp_session_t));
+
+ if ((flags & SDP_RETRY_IF_BUSY) && (flags & SDP_NON_BLOCKING)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ session = sdp_create(-1, flags);
if (!session)
- return session;
- memset(session, 0, sizeof(*session));
- session->flags = flags;
- if (sdp_is_local(dst)) {
- struct sockaddr_un sa;
+ return NULL;
- // create local unix connection
- session->sock = socket(PF_UNIX, SOCK_STREAM, 0);
- session->local = 1;
- if (session->sock >= 0) {
- sa.sun_family = AF_UNIX;
- strcpy(sa.sun_path, SDP_UNIX_PATH);
- if (connect(session->sock, (struct sockaddr *)&sa, sizeof(sa)) == 0)
- return session;
- }
+ if (sdp_is_local(dst)) {
+ if (sdp_connect_local(session) < 0)
+ goto fail;
} else {
- struct sockaddr_l2 sa;
-
- // create L2CAP connection
- session->sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
- session->local = 0;
- if (session->sock >= 0) {
- sa.l2_family = AF_BLUETOOTH;
- sa.l2_psm = 0;
- if (bacmp(src, BDADDR_ANY) != 0) {
- sa.l2_bdaddr = *src;
- if (bind(session->sock, (struct sockaddr *) &sa, sizeof(sa)) < 0)
- goto fail;
- }
- if (flags & SDP_WAIT_ON_CLOSE) {
- struct linger l = { .l_onoff = 1, .l_linger = 1 };
- setsockopt(session->sock, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
- }
- sa.l2_psm = htobs(SDP_PSM);
- sa.l2_bdaddr = *dst;
- do
- if (connect(session->sock, (struct sockaddr *) &sa, sizeof(sa)) == 0)
- return session;
- while (errno == EBUSY && (flags & SDP_RETRY_IF_BUSY));
- }
+ if (sdp_connect_l2cap(src, dst, session) < 0)
+ goto fail;
}
+
+ return session;
+
fail:
err = errno;
if (session->sock >= 0)
close(session->sock);
+ if (session->priv)
+ free(session->priv);
free(session);
errno = err;
- return 0;
+
+ return NULL;
}
int sdp_get_socket(const sdp_session_t *session)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Remember to have fun...
---------------------------------------------------------------------
To unsubscribe, e-mail: opensuse-commit+unsubscribe@opensuse.org
For additional commands, e-mail: opensuse-commit+help@opensuse.org