summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sdp_lib.h2
-rw-r--r--src/sdp.c158
2 files changed, 102 insertions, 58 deletions
diff --git a/include/sdp_lib.h b/include/sdp_lib.h
index d61413c3..0e8948f9 100644
--- a/include/sdp_lib.h
+++ b/include/sdp_lib.h
@@ -80,6 +80,7 @@ static inline void sdp_list_foreach(sdp_list_t *list, sdp_list_func_t f, void *u
*/
#define SDP_RETRY_IF_BUSY 0x01
#define SDP_WAIT_ON_CLOSE 0x02
+#define SDP_NON_BLOCKING 0x04
/*
* a session with an SDP server
@@ -125,6 +126,7 @@ typedef enum {
* SDP transaction: functions for asynchronous search.
*/
typedef void sdp_callback_t(uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *udata);
+int sdp_is_connected(sdp_session_t *session);
sdp_session_t *sdp_create(int sk, uint32_t flags);
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);
diff --git a/src/sdp.c b/src/sdp.c
index 1ce5e81b..2a054094 100644
--- a/src/sdp.c
+++ b/src/sdp.c
@@ -31,6 +31,7 @@
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
+#include <fcntl.h>
#include <stdlib.h>
#include <malloc.h>
#include <syslog.h>
@@ -3041,21 +3042,33 @@ struct sdp_transaction {
uint8_t *reqbuf; /* pointer to request PDU */
sdp_buf_t rsp_concat_buf;
uint32_t reqsize; /* without cstate */
+ uint8_t connected;
};
+inline int sdp_is_connected(sdp_session_t *session)
+{
+ struct sdp_transaction *t = session->priv;
+ return t->connected;
+}
+
+static inline void sdp_set_connected(sdp_session_t *session)
+{
+ struct sdp_transaction *t = session->priv;
+ t->connected = 1;
+}
+
/*
* Creates a new sdp session for asynchronous search
* INPUT:
* int sk
- * non-blocking L2CAP socket
- *
+ * 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;
@@ -3064,7 +3077,6 @@ sdp_session_t *sdp_create(int sk, uint32_t flags)
errno = ENOMEM;
return NULL;
}
-
memset(session, 0, sizeof(*session));
session->flags = flags;
@@ -3076,7 +3088,6 @@ sdp_session_t *sdp_create(int sk, uint32_t flags)
free(session);
return NULL;
}
-
memset(t, 0, sizeof(*t));
session->priv = t;
@@ -3826,71 +3837,101 @@ static inline int sdp_is_local(const bdaddr_t *device)
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)
{
- sdp_session_t *session;
- struct sdp_transaction *t;
- int err;
+ struct sockaddr_un sa;
+ int ret;
- session = malloc(sizeof(sdp_session_t));
- if (!session)
- return session;
+ session->sock = socket(PF_UNIX, SOCK_STREAM, 0);
+ if (session->sock < 0)
+ return -1;
+ session->local = 1;
- memset(session, 0, sizeof(*session));
+ sa.sun_family = AF_UNIX;
+ strcpy(sa.sun_path, SDP_UNIX_PATH);
- session->flags = flags;
- session->sock = -1;
+ ret = connect(session->sock, (struct sockaddr *)&sa, sizeof(sa));
+ if (!ret)
+ sdp_set_connected(session);
- t = malloc(sizeof(struct sdp_transaction));
- if (!t) {
- errno = ENOMEM;
- free(session);
- return NULL;
+ return ret;
+}
+
+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);
}
- memset(t, 0, sizeof(*t));
+ sa.l2_family = AF_BLUETOOTH;
+ sa.l2_psm = 0;
- session->priv = t;
+ if (bacmp(src, BDADDR_ANY)) {
+ sa.l2_bdaddr = *src;
+ if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0)
+ return -1;
+ }
- if (sdp_is_local(dst)) {
- struct sockaddr_un sa;
-
- // 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 (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) {
+ sdp_set_connected(session);
+ 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;
+
+ if ((flags & SDP_RETRY_IF_BUSY) && (flags & SDP_NON_BLOCKING)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ session = sdp_create(-1, flags);
+ if (!session)
+ return NULL;
+
+ 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)
@@ -3899,7 +3940,8 @@ fail:
free(session->priv);
free(session);
errno = err;
- return 0;
+
+ return NULL;
}
int sdp_get_socket(const sdp_session_t *session)