diff options
author | Ulisses Furquim <ulissesf@gmail.com> | 2006-09-04 17:13:33 +0000 |
---|---|---|
committer | Ulisses Furquim <ulissesf@gmail.com> | 2006-09-04 17:13:33 +0000 |
commit | 1be1f79648ba7aafde6349cfe51f9c929e20d018 (patch) | |
tree | d27dd34e43d3e1862e0ef84a89c8e2fc9c02bc40 /src | |
parent | c01b6039f44d9e78acc26cd8482b5e0c7b23fe14 (diff) |
Make sdp_connect() fully async aware
Diffstat (limited to 'src')
-rw-r--r-- | src/sdp.c | 158 |
1 files changed, 100 insertions, 58 deletions
@@ -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) |