blob: ecc31e336dad70b1412af1cfe1d7655afc5d0e82 [file] [log] [blame]
#include <hardware/bluetooth.h>
#include <hardware/bt_sock.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <pthread.h>
#include <fcntl.h>
#include <errno.h>
#include <poll.h>
#include <stdlib.h>
#include <string.h>
#include "aapiSocket.h"
#include "rfcomm.h"
#include "config.h"
#include "aapi.h"
#include "hci.h"
#include "sdp.h"
#include "log.h"
#include "sg.h"
#include "mt.h"
struct aapiSock {
struct aapiSock *prev;
struct aapiSock *next;
btsock_type_t type;
int fd, java_fd;
struct bt_addr peer;
union {
struct {
union { /* listening sockets have no rfc_conn_t */
rfc_conn_t conn;
uint32_t sdpHandle;
};
uint8_t state;
uint8_t chNum;
sg bufRx;
sg bufTx;
} rfc;
};
};
struct appiSockListener {
struct appiSockListener *next;
uint32_t sdpHandle;
uint8_t uuid[16];
};
#define RFC_SOCK_STATE_LISTENING 1
#define RFC_SOCK_STATE_AUTOACCEPTING 2 /* we allocated an instance but it is not yet openened by rfcomm */
#define RFC_SOCK_STATE_ESTABLISHED 3 /* it is open */
#define RFC_SOCK_STATE_AAPI_CLOSED 4 /* aapi closed, waiting for RFCOMM confirmation */
#define RFC_SOCK_STATE_RFC_CLOSED 5 /* rfc closed, waiting for aapi confirmation */
#define RFC_SOCK_STATE_RFC_STOP_LISTEN 6 /* someone else stopped listening for us */
#define WORKER_MSG_SOCK_ADD 0
#define WORKER_MSG_FD_CAN_RX 1 /* our user may now RX data */
#define WORKER_MSG_FD_CAN_TX 2 /* our user may now TX data */
#define WORKER_MSG_FD_CANNOT_RX 3
#define WORKER_MSG_FD_CANNOT_TX 4
#define WORKER_MSG_SOCK_DEL 5 /* delete this socket */
#define WORKER_MSG_QUIT 6 /* TODO: currently unused */
/* our state */
static struct aapiSock *mSocks = NULL;
static pthread_mutex_t mSocksLock = PTHREAD_MUTEX_INITIALIZER;
static pthread_t mWorker;
static int mWorkerPipe = -1;
static bool mSocksUp;
static bool mSocksWantUp;
static struct appiSockListener *mListeners = NULL;
/* fwd decls */
static void aapiSockFree(struct aapiSock* sock);
static void aapiSockWorkerMsgSend(uint8_t msg, void *aux);
/*
* FUNCTION: aapiWorker
* USE: The worker thread for aapi.sock
* PARAMS: pipe - actually an int - the pipe we listen to to wake up
* RETURN: NONE
* NOTES:
*/
static void *aapiSockWorker(void *pipe)
{
uint32_t i, arrSz = 16/* a nice starting number */, arrNum = 1;
struct aapiSock **socks = NULL;
struct pollfd *fds = NULL;
bool quit = false;
uint8_t rdbuf[4096]; /* we read from java using this */
fds = malloc(sizeof(struct pollfd) * arrSz);
if (!fds) {
loge("Failed to alloc fds\n");
return NULL;
}
socks = malloc(sizeof(struct aapiSock*) * arrSz);
if (!socks) {
loge("Failed to alloc socks\n");
free(fds);
return NULL;
}
fds[0].fd = (int)(uintptr_t)pipe;
fds[0].events = POLLIN;
while (!quit) {
int ret;
for (i = 0; i < arrNum; i++)
fds[i].revents = 0;
do {
ret = poll(fds, arrNum, -1);
} while (ret == -1 && errno == EINTR);
if (fds[0].revents & POLLIN) {
uint8_t msg;
struct aapiSock *sock;
r_read(fds[0].fd, &msg, sizeof(msg));
r_read(fds[0].fd, &sock, sizeof(sock));
switch (msg) {
case WORKER_MSG_SOCK_ADD:
if (arrNum == arrSz) {
uint32_t newArrSz = arrSz + 16; /* we grow 16 at a time */
struct pollfd *newFds = realloc(fds, sizeof(struct pollfd) * newArrSz);
struct aapiSock **newSocks = realloc(socks, sizeof(struct aapiSock*) * newArrSz);
if (newFds)
fds = newFds;
if (newSocks)
socks = newSocks;
if (!newFds || !newSocks) {
logw("Failed to resize structs to add new sock\n");
break;
}
arrSz = newArrSz;
}
socks[arrNum] = sock;
fds[arrNum].fd = sock->fd;
fds[arrNum].events = POLLERR | POLLNVAL | POLLHUP;
fds[arrNum].revents = 0;
arrNum++;
break;
case WORKER_MSG_FD_CAN_RX:
case WORKER_MSG_FD_CAN_TX:
case WORKER_MSG_FD_CANNOT_RX:
case WORKER_MSG_FD_CANNOT_TX:
case WORKER_MSG_SOCK_DEL:
for (i = 0; i < arrNum && socks[i] != sock; i++);
if (i == arrNum) {
logw("worker(%u) called with unknown sock\n", msg);
break;
}
if (msg == WORKER_MSG_FD_CAN_RX)
fds[i].events |= POLLOUT;
else if (msg == WORKER_MSG_FD_CAN_TX)
fds[i].events |= POLLIN;
else if (msg == WORKER_MSG_FD_CANNOT_RX)
fds[i].events &=~ POLLOUT;
else if (msg == WORKER_MSG_FD_CANNOT_TX)
fds[i].events &=~ POLLIN;
else {
memcpy(fds + i, fds + arrNum - 1, sizeof(struct pollfd));
socks[i] = socks[arrNum - 1];
arrNum--;
pthread_mutex_lock(&mSocksLock);
aapiSockFree(sock);
pthread_mutex_unlock(&mSocksLock);
}
break;
case WORKER_MSG_QUIT:
quit = true;
logd("AAPI.sock worker exiting\n");
break;
default:
loge("Unknown AAPI.worker command %u\n", msg);
break;
}
}
for (i = 1; i < arrNum; i++) {
uint32_t done;
void *iter;
if (fds[i].revents & (POLLERR | POLLNVAL | POLLHUP)) {
logd("fd %d (sock %d) in state %u failed with error %d -> deleting\n", fds[i].fd, i, socks[i]->rfc.state, fds[i].revents);
aapiSockWorkerMsgSend(WORKER_MSG_SOCK_DEL, socks[i]);
continue;
}
if (!(fds[i].events & fds[i].revents))
continue;
if (fds[i].revents & POLLIN) { /* java has sent us data */
int32_t txRet;
while(1) {
ssize_t now;
if (sgLength(socks[i]->rfc.bufTx) >= AAPI_RFC_MAX_BUF) {
fds[i].events &=~ POLLIN; /* no buffer space - stop reading */
logd("TX throttled in socks api\n");
break;
}
now = read(fds[i].fd, rdbuf, sizeof(rdbuf));
if (now <= 0)
break;
if (!sgConcatBackCopy(socks[i]->rfc.bufTx, rdbuf, now))
loge("Failed to concat read data. TX data will be lost\n");
if (now != sizeof(rdbuf))
break;
}
txRet = rfcTx(socks[i]->rfc.conn, socks[i]->rfc.bufTx);
if (txRet == RFC_TX_RET_ENTIRE_SENT) {
socks[i]->rfc.bufTx = sgNew();
if (!socks[i]->rfc.bufTx) {
loge("Failed to alloc new TX sg for conn. Closing\n");
aapiSockWorkerMsgSend(WORKER_MSG_SOCK_DEL, socks[i]);
}
} else if (txRet == RFC_TX_RET_STOP_SENDING) {
fds[i].events &=~ POLLIN; /* no buffer space - stop reading */
logd("TX throttled in rfc\n");
} else if (txRet == RFC_TX_RET_NO_SUCH_CONN || txRet == RFC_TX_RET_ERROR) {
loge("Rfc sock error %d. Closing\n", txRet);
aapiSockWorkerMsgSend(WORKER_MSG_SOCK_DEL, socks[i]);
}
}
if (fds[i].revents & POLLOUT) { /* java is ready for data */
pthread_mutex_lock(&mSocksLock);
for (done = 0, iter = sgIterStart(socks[i]->rfc.bufRx); iter; iter = sgIterAdvance(iter)) {
ssize_t now = write(fds[i].fd, sgIterCurData(iter), sgIterCurLen(iter));
if (now <= 0)
break;
done += now;
if ((unsigned)now < sgIterCurLen(iter))
break;
}
sgTruncFront(socks[i]->rfc.bufRx, done);
if (sgLength(socks[i]->rfc.bufRx) < AAPI_RFC_MAX_BUF)
rfcFlow(socks[i]->rfc.conn, false);
if (!sgLength(socks[i]->rfc.bufRx))
fds[i].events &=~ POLLOUT; /* if we have no more to give, do not bother caring if java can read */
pthread_mutex_unlock(&mSocksLock);
}
}
}
pthread_mutex_lock(&mSocksLock);
for (i = 1; i < arrNum; i++)
aapiSockFree(socks[i]);
pthread_mutex_unlock(&mSocksLock);
close((int)(uintptr_t)pipe);
free(fds);
free(socks);
return NULL;
}
/*
* FUNCTION: aapiSockDoInit
* USE: Init aapi.sock worker thread & pipes
* PARAMS: NONE
* RETURN: NONE
* NOTES:
*/
static void aapiSockDoInit(void)
{
int pipes[2];
if (pipe(pipes))
return;
if (pthread_create(&mWorker, NULL, aapiSockWorker, (void*)(uintptr_t)pipes[0])) {
close(pipes[0]);
close(pipes[1]);
return;
}
mWorkerPipe = pipes[1];
mSocksUp = true;
mSocksWantUp = false;
}
/*
* FUNCTION: aapiSockWorkerMsgSend
* USE: Wake up aapi.sock worker with a message
* PARAMS: msg - the message
* aux - additional data for said message
* RETURN: NONE
* NOTES:
*/
static void aapiSockWorkerMsgSend(uint8_t msg, void *aux)
{
uint8_t t = msg;
r_write(mWorkerPipe, &t, 1);
r_write(mWorkerPipe, &aux, sizeof(void*));
}
/*
* FUNCTION: aapiSockAlloc
* USE: Create a sock struct and link it into the list
* PARAMS: type - socket type (as per bt iface)
* sockType - local socket type (for linux kernel, SOCK_STREAM/SOCK_DGRAM)
* RETURN: sock struct or NULL on error
* NOTES: call with mSocksLock held
*/
static struct aapiSock* aapiSockAlloc(btsock_type_t type, int sockType)
{
struct aapiSock *sock = calloc(1, sizeof(struct aapiSock));
int socks[2], ret;
if (!sock)
return NULL;
ret = socketpair(AF_LOCAL, sockType, 0, socks);
if (ret) {
free(sock);
return NULL;
}
fcntl(socks[0], F_SETFL, O_NONBLOCK | fcntl(socks[0], F_GETFL));
sock->type = type;
sock->fd = socks[0];
sock->java_fd = socks[1];
sock->next = mSocks;
if (mSocks)
mSocks->prev = sock;
mSocks = sock;
return sock;
}
/*
* FUNCTION: aapiSockAllocRfc
* USE: Create an RFC sock struct and link it into the list
* PARAMS: chNum - the chNum to save in the sock
* state - the state to put it into
* RETURN: sock struct or NULL on error
* NOTES: call with mSocksLock held
*/
static struct aapiSock* aapiSockAllocRfc(uint8_t chNum, uint8_t state)
{
struct aapiSock *sock = NULL;
sg bufTx = sgNew();
sg bufRx = sgNew();
if (!bufTx && ! bufRx) {
if (bufTx)
sgFree(bufTx);
if (bufRx)
sgFree(bufRx);
return NULL;
}
sock = aapiSockAlloc(BTSOCK_RFCOMM, SOCK_STREAM);
if (sock) {
sock->rfc.chNum = chNum;
sock->rfc.state = state;
sock->rfc.bufTx = bufTx;
sock->rfc.bufRx = bufRx;
} else {
sgFree(bufTx);
sgFree(bufRx);
}
return sock;
}
/*
* FUNCTION: aapiSockFree
* USE: Free a socket struct
* PARAMS: sock - the socket struct
* RETURN: NONE
* NOTES: call with mSocksLock held
*/
static void aapiSockFree(struct aapiSock* sock)
{
shutdown(sock->fd, SHUT_RDWR);
close(sock->fd);
if (sock->java_fd != -1)
close(sock->java_fd);
if (sock->prev)
sock->prev->next = sock->next;
else
mSocks = sock->next;
if (sock->next)
sock->next->prev = sock->prev;
switch (sock->type) {
case BTSOCK_RFCOMM:
if (sock->rfc.bufTx)
sgFree(sock->rfc.bufTx);
sock->rfc.bufTx = NULL;
if (sock->rfc.bufRx)
sgFree(sock->rfc.bufRx);
sock->rfc.bufTx = NULL;
if (sock->rfc.state == RFC_SOCK_STATE_LISTENING) {
struct appiSockListener *sl, *p = NULL;
for (sl = mListeners; sl && sl->sdpHandle != sock->rfc.sdpHandle; p = sl, sl = sl->next);
if (!sl)
logw("Failed to find listener object for closed listening socket\n");
else {
if (p)
p->next = sl->next;
else
mListeners = sl->next;
free(sl);
}
rfcStopListen(sock->rfc.chNum);
sdpServiceDescriptorDel(sock->rfc.sdpHandle);
} else if (sock->rfc.state == RFC_SOCK_STATE_RFC_STOP_LISTEN) {
/* nothing to do here */
} else if (sock->rfc.conn)
rfcClose(sock->rfc.conn);
if (sock->rfc.state == RFC_SOCK_STATE_RFC_CLOSED || sock->rfc.state == RFC_SOCK_STATE_RFC_STOP_LISTEN || sock->rfc.state == RFC_SOCK_STATE_LISTENING)
free(sock);
else
sock->rfc.state = RFC_SOCK_STATE_AAPI_CLOSED;
break;
default:
logw("Unknown socket type %u on close\n", sock->type);
break;
}
}
static bool aapiSockNotifyOfConnReq(struct aapiSock *srvSock, struct aapiSock *newSock)
{
sock_connect_signal_t sig = {.size = sizeof(sock_connect_signal_t), .channel = srvSock->rfc.chNum, .status = 0, };
uint8_t *sigBuf = (uint8_t*)&sig;
char cmsgBuf[CMSG_SPACE(1)] = {0,};
int ret, len = sizeof(sig);
struct cmsghdr *cmsg;
struct msghdr msg = {0,};
memcpy(sig.bd_addr.address, newSock->peer.addr, sizeof(sig.bd_addr.address));
msg.msg_control = cmsgBuf;
msg.msg_controllen = sizeof(cmsgBuf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(newSock->java_fd));
memcpy(CMSG_DATA(cmsg), &newSock->java_fd, sizeof(newSock->java_fd));
while (len) {
struct iovec ovec = {0,};
ovec.iov_base = sigBuf;
ovec.iov_len = len;
msg.msg_iov = &ovec;
msg.msg_iovlen = 1;
do {
ret = sendmsg(srvSock->fd, &msg, MSG_NOSIGNAL);
} while (ret < 0 && errno == EINTR);
if (ret == -1) {
logd("sendmsg err: %d\n", errno);
return false;
}
sigBuf += ret;
len -= ret;
memset(&msg, 0, sizeof(msg));
}
close(newSock->java_fd);
newSock->java_fd = -1;
return true;
}
/*
* FUNCTION: aapiSockRfcListenAlloc
* USE: Called when a remote device tries to connect to our listening RFC socket
* PARAMS: userData - our socket
* peerAddr - the peer address
* chNum - the chNum
* RETURN: bt_status_t
* NOTES:
*/
static void* aapiSockRfcListenAlloc(void *userData, const struct bt_addr *peerAddr, uint8_t chNum)
{
/* we have no way to ask user to accept or not, so we accept for the user, and sort it out later */
struct aapiSock *srvSock = (struct aapiSock*)userData;
struct aapiSock *newSock;
logd("Connection to "ADDRFMT"[%u] alloc\n", ADDRCONV(*peerAddr), chNum);
pthread_mutex_lock(&mSocksLock);
newSock = aapiSockAllocRfc(chNum, RFC_SOCK_STATE_AUTOACCEPTING);
if (!newSock)
goto out;
logd("aapi sock alloc ch %u\n", chNum);
srvSock->rfc.chNum = chNum; /* in case we get here before aapiSockListen() finishes */
memcpy(&newSock->peer, peerAddr, sizeof(newSock->peer));
if (!aapiSockNotifyOfConnReq(srvSock, newSock)) {
loge("Failed to notify of new connection - closing server socket too\n");
aapiSockFree(newSock);
aapiSockWorkerMsgSend(WORKER_MSG_SOCK_DEL, srvSock);
newSock = NULL;
}
out:
pthread_mutex_unlock(&mSocksLock);
return newSock;
}
/*
* FUNCTION: aapiSockRfcListenEvt
* USE: Called when an even arises on an RFC connection
* PARAMS: userData - unused
* instance - our socket
* evt - what happened
* s - the data
* RETURN: NONE
* NOTES:
*/
static void aapiSockRfcListenEvt(void *userData, void *instance, uint8_t evt, sg s)
{
struct aapiSock *sock = (struct aapiSock*)instance;
logd("aapi sock evt %u ch %u\n", evt, sock->rfc.chNum);
pthread_mutex_lock(&mSocksLock);
switch (evt) {
case RFC_EVT_OPEN:
logd("Connection to "ADDRFMT"[%u] open\n", ADDRCONV(sock->peer), sock->rfc.chNum);
if (sock->rfc.state != RFC_SOCK_STATE_AUTOACCEPTING)
logw("Weird socket state %u on rfc open\n", sock->rfc.state);
sock->rfc.state = RFC_SOCK_STATE_ESTABLISHED;
sgSerialize(s, 0, sizeof(sock->rfc.conn), &sock->rfc.conn);
sgFree(s);
aapiSockWorkerMsgSend(WORKER_MSG_SOCK_ADD, sock);
aapiSockWorkerMsgSend(WORKER_MSG_FD_CAN_TX, sock);
break;
case RFC_EVT_RX:
if (sock->rfc.state != RFC_SOCK_STATE_ESTABLISHED) {
logw("Dropping data for non-established socket in state %u\n", sock->rfc.state);
sgFree(s);
} else {
sgConcat(sock->rfc.bufRx, s);
if (sgLength(sock->rfc.bufRx) >= AAPI_RFC_MAX_BUF)
rfcFlow(sock->rfc.conn, true);
aapiSockWorkerMsgSend(WORKER_MSG_FD_CAN_RX, sock);
}
break;
case RFC_EVT_MAY_SEND:
logd("TX unthrottled in rfc\n");
aapiSockWorkerMsgSend(WORKER_MSG_FD_CAN_TX, sock);
break;
case RFC_EVT_CLOSE:
logd("Connection to "ADDRFMT"[%u] closed\n", ADDRCONV(sock->peer), sock->rfc.chNum);
sock->rfc.conn = 0;
if (sock->rfc.state == RFC_SOCK_STATE_AAPI_CLOSED)
free(sock);
else {
sock->rfc.state = RFC_SOCK_STATE_RFC_CLOSED;
aapiSockWorkerMsgSend(WORKER_MSG_SOCK_DEL, sock);
}
}
pthread_mutex_unlock(&mSocksLock);
}
/*
* FUNCTION: aapiSockListen
* USE: Listen for connections from a peer on a socket
* PARAMS: type - socket type
* serviceName - service name to advertise
* serviceUuid - service uuid to advertise
* channel - channel number
* sockFdP - store socket's FD here
* flags - other relevant flags
* RETURN: bt_status_t
* NOTES:
*/
static bt_status_t aapiSockListen(btsock_type_t type, const char* serviceName, const uint8_t* serviceUuid, int channel, int* sockFdP, int flags)
{
bt_status_t ret = BT_STATUS_FAIL;
struct appiSockListener *sl = NULL, *p;
struct aapiSock* sock;
bool linkIn = true;
uint8_t ch;
pthread_mutex_lock(&mSocksLock);
if (!mSocksUp) {
logw("Refusing sock listen when socks not up\n");
goto out;
}
for (p = NULL, sl = mListeners; sl && memcmp(sl->uuid, serviceUuid, sizeof(sl->uuid)); p = sl, sl = sl->next);
if (sl) {
logw("Sock listen when identical listener exists -> deleting old\n");
for (sock = mSocks; sock; sock = sock->next) {
if (sock->rfc.state != RFC_SOCK_STATE_LISTENING)
continue;
if (sock->rfc.sdpHandle == sl->sdpHandle)
break;
}
if (sock) {
logd("Previous identical socket found\n");
sock->rfc.state = RFC_SOCK_STATE_RFC_STOP_LISTEN;
rfcStopListen(sock->rfc.chNum);
sock->rfc.chNum = 0;
sdpServiceDescriptorDel(sl->sdpHandle);
sock->rfc.sdpHandle = 0;
aapiSockWorkerMsgSend(WORKER_MSG_SOCK_DEL, sock);
} else {
logw("Failed to find previous listening socket. SDP likely to be leaked->auto-freeing\n");
sdpServiceDescriptorDel(sl->sdpHandle);
}
linkIn = false;
} else
sl = malloc(sizeof(struct appiSockListener));
if (sl)
memcpy(sl->uuid, serviceUuid, sizeof(sl->uuid));
else {
loge("Failed to alloc a listener record\n");
goto out;
}
logd("AAPI.sock: listen(%u,'%s',%d,%u)\n", type, serviceName, channel, flags);
if (type != BTSOCK_RFCOMM) {
logw("Refusing non-RFCOMM sockets for now\n");
goto out;
}
if (channel == -1) /* magic number! */
ch = RFC_CHNUM_REQ_ANY;
else if (channel < RFC_FIRST_CHAN || channel >= RFC_NUM_CHANS + RFC_FIRST_CHAN) {
logw("Refusing RFCOMM listen on invalid channel %d\n", channel);
goto out;
} else ch = channel;
sock = aapiSockAllocRfc(ch, RFC_SOCK_STATE_LISTENING); /* yes, "ch" might be RFC_CHNUM_REQ_ANY here. this is actually ok */
if (!sock)
goto out;
ch = rfcListen(ch, aapiSockRfcListenAlloc, aapiSockRfcListenEvt, sock);
if (!ch) {
logw("Failed to RFC listen\n");
goto out_sockfree;
}
sock->rfc.chNum = ch;
logd("RFC ch %u opened for listening with name '%s'\n", ch, serviceName);
/* XXX: this makes me feel dirty all over, but sadly andriod api demands this be sent as an int and in native byte order... */
channel = ch; /* send the channel ID to java */
if (!sgConcatBackCopy(sock->rfc.bufRx, &channel ,sizeof(channel))) {
loge("Failed to enqueue channel number for java\n");
goto out_stoplisten;
}
sock->rfc.sdpHandle = rfcAddSdpRecord(serviceUuid, ch, serviceName);
logd("sock %p has atate %u and fd %u with sdp handle 0x%08x\n", sock, sock->rfc.state, sock->fd, sock->rfc.sdpHandle);
if (!sock->rfc.sdpHandle) {
loge("Failed to add SDP record\n");
goto out_stoplisten;
}
sl->sdpHandle = sock->rfc.sdpHandle;
if (linkIn) {
sl->next = mListeners;
mListeners = sl;
}
*sockFdP = sock->java_fd;
sock->java_fd = -1;
aapiSockWorkerMsgSend(WORKER_MSG_SOCK_ADD, sock);
aapiSockWorkerMsgSend(WORKER_MSG_FD_CAN_RX, sock);
ret = BT_STATUS_SUCCESS;
goto out;
out_stoplisten:
rfcStopListen(ch);
out_sockfree:
aapiSockFree(sock);
out:
pthread_mutex_unlock(&mSocksLock);
return ret;
}
/*
* FUNCTION: aapiSockConnect
* USE: Try to connect to a peer's matching listening socket
* PARAMS: bd_addr - peer address
* type - socket type
* uuid - service uuid
* channel - channel number
* sockFdP - store socket's FD here
* flags - other relevant flags
* RETURN: bt_status_t
* NOTES:
*/
static bt_status_t aapiSockConnect(const bt_bdaddr_t *bd_addr, btsock_type_t type, const uint8_t* uuid, int channel, int* sockFdP, int flags)
{
bt_status_t ret = BT_STATUS_FAIL;
logd("AAPI.sock: connect(%02X:%02X:%02X:%02X:%02X:%02X,%u,%d,%u)\n",
bd_addr->address[5], bd_addr->address[4], bd_addr->address[3], bd_addr->address[2], bd_addr->address[1], bd_addr->address[0],
type, channel, flags);
pthread_mutex_lock(&mSocksLock);
if (!mSocksUp) {
pthread_mutex_unlock(&mSocksLock);
logw("Refusing sock connect when socks not up\n");
goto out;
}
pthread_mutex_unlock(&mSocksLock);
if (type != BTSOCK_RFCOMM) {
logw("Refusing non-RFCOMM sockets for now\n");
goto out;
}
if (channel != -1 && (channel < RFC_FIRST_CHAN || channel >= RFC_NUM_CHANS + RFC_FIRST_CHAN)) {
logw("Refusing RFCOMM connect on invalid channel %d\n", channel);
goto out;
}
//TODO
out:
return ret;
}
/*
* FUNCTION: aapiGetProfileIfaceSockets
* USE: Try to connect to a peer's matching listening socket
* PARAMS: bd_addr - peer address
* type - socket type
* uuid - service uuid
* channel - channel number
* sockFdP - store socket's FD here
* flags - other relevant flags
* RETURN: bt_status_t
* NOTES:
*/
const void* aapiGetProfileIfaceSockets(void)
{
static const btsock_interface_t sockIface = {
.size = sizeof(btsock_interface_t),
.listen = aapiSockListen,
.connect = aapiSockConnect,
};
pthread_mutex_lock(&mSocksLock);
if (mSocksUp)
logd("socks up again\n");
else if (!aapiIsStackUp())
mSocksWantUp = true;
else
aapiSockDoInit();
pthread_mutex_unlock(&mSocksLock);
return &sockIface;
}
/*
* FUNCTION: aapiSocketNotifStackState
* USE: Stack uses this to tell us of stack up/down state changes
* PARAMS: up - true if stack is now up, false else
* RETURN: NONE
* NOTES:
*/
void aapiSocketNotifStackState(bool up)
{
pthread_mutex_lock(&mSocksLock);
if (up && !mSocksUp && mSocksWantUp) {
logd("socks coming up now\n");
aapiSockDoInit();
pthread_mutex_unlock(&mSocksLock);
} else if (!up) {
mSocksWantUp = false;
while (mListeners) {
struct appiSockListener *sl = mListeners;
mListeners = mListeners->next;
free(sl);
}
pthread_mutex_unlock(&mSocksLock);
if(mSocksUp) {
aapiSockWorkerMsgSend(WORKER_MSG_QUIT, NULL);
pthread_join(mWorker, NULL);
close(mWorkerPipe);
}
mSocksUp = false;
}
}