diff options
-rw-r--r-- | include/sdp_lib.h | 2 | ||||
-rw-r--r-- | src/sdp.c | 158 |
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); @@ -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) |