📄 btsocket.c
字号:
#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <errno.h>#include <fcntl.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <sys/stat.h>#include "btdefines.h"#include "btsocket.h"#include "btutils.h"#define SETTIMEOUT(timeout, tv, ptv) \ if (timeout < 0) { \ ptv = NULL; \ } else { \ if (timeout < 1000000) { \ tv.tv_sec = 0; \ tv.tv_usec = timeout; \ } else { \ tv.tv_sec = timeout / 1000000; \ tv.tv_usec = timeout % 1000000; \ } \ ptv = &tv; \ }int BTSocketCompare(cBTSocket sk, const char* bdaddr, int chan, int *res){ bdaddr_t addr; if (!sk || !bdaddr) return BT_ERR_ARGUMENT; str2ba(bdaddr, &addr); if (!bacmp(&addr, &sk->bdaddr) && sk->chan == chan) *res = BT_TRUE; else *res = BT_FALSE; return BT_ERR_NONE;}int BTSocketCreate(BTSocket* sk, const char* bdaddr, int chan){ BTSocket s; if (!bdaddr || chan < 0 || chan > 30) return BT_ERR_ARGUMENT; s = (BTSocket)malloc(sizeof(struct sBTSocket)); if (!s) return BT_ERR_NOMEMORY; str2ba(bdaddr, &s->bdaddr); s->chan = chan; s->sock = -1; s->accsock = -1; sprintf(s->tty, "%s", ""); *sk = s; return BT_ERR_NONE;}int BTSocketDestroy(BTSocket sk){ if (!sk) return BT_ERR_ARGUMENT; if (sk->sock > 0) close(sk->sock); if (sk->accsock > 0) close(sk->accsock); if (strlen(sk->tty)) BTSocketReleaseTTY(sk); free(sk); return BT_ERR_NONE;}int BTSocketListen(BTSocket sk, int chan){ bdaddr_t local; struct sockaddr_rc addr; int s; if (!sk) return BT_ERR_ARGUMENT; if (sk->sock > 0 || sk->accsock > 0) return BT_ERR_INUSE; if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) { DEBUG_LOG1("creating socket: %s", strerror(errno)); return BT_ERR_FAILED; } if (fcntl(s, F_SETFD, FD_CLOEXEC) < 0) { DEBUG_LOG1("setting FD_CLOEXEC failed: %s", strerror(errno)); close(s); return BT_ERR_FAILED; } memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; hci_devba(0, &local); bacpy(&addr.rc_bdaddr, &local); addr.rc_channel = chan; if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { DEBUG_LOG1("binding socket: %s", strerror(errno)); close(s); return BT_ERR_FAILED; } if (listen(s, 1) < 0) { DEBUG_LOG1("listening socket: %s", strerror(errno)); close(s); return BT_ERR_FAILED; } sk->accsock = s; return BT_ERR_NONE;}int BTSocketStopListen(BTSocket sk){ if (!sk) return BT_ERR_ARGUMENT; if (sk->accsock > 0) close(sk->accsock); sk->accsock = -1; return BT_ERR_NONE;}int BTSocketAccept(BTSocket sk, int timeout){ fd_set rset; struct timeval *ptv; struct timeval tv, tvstart, tvstop, tvreq; socklen_t socklen; struct sockaddr_rc addr; int res; if (!sk) return BT_ERR_ARGUMENT; if (sk->accsock < 0) return BT_ERR_ARGUMENT; if (sk->sock > 0) return BT_ERR_INUSE; SETTIMEOUT(timeout, tv, ptv); tvreq = tv;retry: FD_ZERO(&rset); FD_SET(sk->accsock, &rset); if (ptv) gettimeofday(&tvstart, NULL); res = select(sk->accsock + 1, &rset, NULL, NULL, ptv); if (res < 0 || res > 1) { if (res < 0) { DEBUG_LOG1("select failed with %s", strerror(errno)); } else { DEBUG_LOG1("select failed %d events pending", res); } return BT_ERR_FAILED; } else if (res == 0) return BT_ERR_TIMEOUT; memset(&addr, 0, sizeof(addr)); socklen = sizeof(addr); res = accept(sk->accsock, (struct sockaddr *) &addr, &socklen); if (res < 0) { DEBUG_LOG1("accept failed with %s", strerror(errno)); return BT_ERR_FAILED; } /* check if the connect is coming from the right bt device */ if (bacmp(&sk->bdaddr, &addr.rc_bdaddr)) { DEBUG_LOG("connected to a wrong device"); close(res); /* calculate remained timeout */ if (!ptv) goto retry; gettimeofday(&tvstop, NULL); tv.tv_sec = tvstop.tv_sec - tvstart.tv_sec; if (tvstop.tv_usec > tvstart.tv_usec) tv.tv_usec = tvstop.tv_usec - tvstart.tv_usec; else tv.tv_usec = tvstart.tv_usec - tvstop.tv_usec; if (tv.tv_sec < tvreq.tv_sec || (tv.tv_sec == tvreq.tv_sec && tv.tv_usec < tvreq.tv_usec)) { tv.tv_sec = tvreq.tv_sec - tv.tv_sec; tv.tv_usec = (tv.tv_usec < tvreq.tv_usec) ? tvreq.tv_usec - tv.tv_usec : tv.tv_usec - tvreq.tv_usec; tvreq = tv; goto retry; } return BT_ERR_TIMEOUT; } sk->sock = res; close(sk->accsock); sk->accsock = -1; return BT_ERR_NONE;}int BTSocketReceive(cBTSocket sk, char *buf, int len, int* received, int timeout){ fd_set rset; struct timeval *ptv; struct timeval tv; int res, nr; if (!sk) return BT_ERR_ARGUMENT; if (sk->sock < 0 || !buf || len < 0 || !received) return BT_ERR_ARGUMENT; SETTIMEOUT(timeout, tv, ptv); FD_ZERO(&rset); FD_SET(sk->sock, &rset); res = select(sk->sock + 1, &rset, NULL, NULL, ptv); if (res < 0 || res > 1) { DEBUG_LOG1("select() failed: %s", strerror(errno)); return BT_ERR_FAILED; } else if (res == 0) return BT_ERR_TIMEOUT; nr = recv(sk->sock, buf, len, MSG_NOSIGNAL); if (nr < 0) { DEBUG_LOG1("recv() failed: %s", strerror(errno)); return BT_ERR_FAILED; } *received = nr; return BT_ERR_NONE;}int BTSocketConnect(BTSocket sk, int timeout){ struct sockaddr_rc addr; int s, res; if (!sk) return BT_ERR_ARGUMENT; if (sk->sock > 0 || sk->accsock > 0) return BT_ERR_INUSE; if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) { DEBUG_LOG1("creating socket: %s", strerror(errno)); return BT_ERR_FAILED; } res = fcntl(s, F_GETFL, 0); if (res < 0 || fcntl(s, F_SETFL, res | O_NONBLOCK) < 0) { DEBUG_LOG1("setting non-blocking: %s", strerror(errno)); close(s); return BT_ERR_FAILED; } if (fcntl(s, F_SETFD, FD_CLOEXEC) < 0) { DEBUG_LOG1("setting FD_CLOEXEC failed: %s", strerror(errno)); close(s); return BT_ERR_FAILED; } memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, &sk->bdaddr); addr.rc_channel = sk->chan; if (!connect(s, (struct sockaddr *)&addr, sizeof(addr))) { sk->sock = s; return BT_ERR_NONE; } if (errno != EAGAIN) { DEBUG_LOG1("connect failed: %s", strerror(errno)); close(s); return BT_ERR_FAILED; } sk->sock = s; res = BTSocketIsConnected(sk, timeout); if (res == BT_ERR_FAILED) { close(sk->sock); sk->sock = -1; } return res;}int BTSocketIsConnected(cBTSocket sk, int timeout){ fd_set wset; struct timeval *ptv; struct timeval tv; int res, err, optlen; if (!sk) return BT_ERR_ARGUMENT; if (sk->sock < 0) return BT_ERR_ARGUMENT; SETTIMEOUT(timeout, tv, ptv); FD_ZERO(&wset); FD_SET(sk->sock, &wset); res = select(sk->sock + 1, NULL, &wset, NULL, ptv); if (res < 0 || res > 1) { DEBUG_LOG1("select failed %s", strerror(errno)); return BT_ERR_FAILED; } if (res == 0) return BT_ERR_TIMEOUT; optlen = sizeof(err); res = getsockopt(sk->sock, SOL_SOCKET, SO_ERROR, (void*)&err, &optlen); if (res < 0) { DEBUG_LOG1("getsockopt failed: %s", strerror(errno)); return BT_ERR_FAILED; } if (err != 0) { DEBUG_LOG1("connect failed %s", strerror(err)); return BT_ERR_FAILED; } return BT_ERR_NONE;}int BTSocketSend(cBTSocket sk, const char* buf, int len, int *sent, int timeout){ fd_set wset; struct timeval *ptv; struct timeval tv; int res; ssize_t ns; if (!sk) return BT_ERR_ARGUMENT; if (sk->sock < 0 || !buf || len < 0 || !sent) return BT_ERR_ARGUMENT; FD_ZERO(&wset); FD_SET(sk->sock, &wset); SETTIMEOUT(timeout, tv, ptv); res = select(sk->sock + 1, NULL, &wset, NULL, ptv); if (res < 0 || res > 1) { DEBUG_LOG1("select failed %s", strerror(errno)); return BT_ERR_FAILED; } else if (res == 0) return BT_ERR_TIMEOUT; ns = send(sk->sock, buf, len, MSG_NOSIGNAL); if (ns < 0) { DEBUG_LOG1("send failed %s", strerror(errno)); return BT_ERR_FAILED; } *sent = ns; return BT_ERR_NONE;}int BTSocketClose(BTSocket sk){ if (!sk) return BT_ERR_ARGUMENT; close(sk->sock); sk->sock = -1; close(sk->accsock); sk->accsock = -1; return BT_ERR_NONE;}int BTSocketCreateTTY(BTSocket sk){ int ctl; struct rfcomm_dev_req req; char bdstr[BT_BDADDR_LEN]; if (!sk) return BT_ERR_ARGUMENT; ba2str(&sk->bdaddr, bdstr); if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM)) < 0) { DEBUG_LOG1("creating control socket: %s", strerror(errno)); return BT_ERR_FAILED; } memset(&req, 0, sizeof(req)); req.dev_id = BTS_TTY_ID; bacpy(&req.src, BDADDR_ANY); bacpy(&req.dst, &sk->bdaddr); req.channel = sk->chan; if (ioctl(ctl, RFCOMMCREATEDEV, &req) < 0) { DEBUG_LOG1("ioctl: %s", strerror(errno)); close(ctl); return BT_ERR_FAILED; } close(ctl); sprintf(sk->tty, BTS_TTY); return BT_ERR_NONE;}int BTSocketIsTTYReady(cBTSocket sk, int *ready){ struct stat st; if (!sk) return BT_ERR_ARGUMENT; if (stat(BTS_TTY1, &st) < 0) { if (stat(BTS_TTY2, &st) < 0) *ready = BT_FALSE; else *ready = BT_TRUE; } else *ready = BT_TRUE; return BT_ERR_NONE;}int BTSocketReleaseTTY(BTSocket sk){ int ctl; struct rfcomm_dev_req req; if (!sk) return BT_ERR_ARGUMENT; memset(&req, 0, sizeof(req)); req.dev_id = BTS_TTY_ID; if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM)) < 0) { DEBUG_LOG1("creating control socket: %s", strerror(errno)); return BT_ERR_FAILED; } if (ioctl(ctl, RFCOMMRELEASEDEV, &req) < 0) { DEBUG_LOG1("ioctl: %s", strerror(errno)); close( ctl ); return BT_ERR_FAILED; } close(ctl); sprintf(sk->tty, "%s", ""); return BT_ERR_NONE;}int BTSocketGetTTYName(cBTSocket sk, char* ttyname){ if (!sk) return BT_ERR_ARGUMENT; strcpy(ttyname, BTS_TTY); return BT_ERR_NONE;}int BTSocketGetAddress(cBTSocket sk, char *addr){ if (!sk) return BT_ERR_ARGUMENT; ba2str(&sk->bdaddr, addr); return BT_ERR_NONE;}int BTSocketGetChannel(cBTSocket sk, int *chan){ if (!sk) return BT_ERR_ARGUMENT; *chan = sk->chan; return BT_ERR_NONE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -