From: Andreas Sandberg Date: Mon, 24 Feb 2020 22:46:35 +0000 (+0000) Subject: bt/bt_bluez: Implement retry if rfcomm sockets are busy X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=4704f64551dd917c2616b4162e7e816fb57113da;p=libsigrok.git bt/bt_bluez: Implement retry if rfcomm sockets are busy There are cases where the connect() call returns EBUSY when trying to connect to a device. This has been observed when sampling an RDTech UM24C. In this case, scanning the device works fine. However, when sampling the device, Sigrok first scans the device, then closes the connection and re-opens it to sample the device. If the close/open calls happen in close successions, the Bluetooth stack sometimes returns EBUSY. Work around this issue by retrying if the connect() returns EBUSY. Signed-off-by: Andreas Sandberg --- diff --git a/src/bt/bt_bluez.c b/src/bt/bt_bluez.c index f64ba59d..52567f9e 100644 --- a/src/bt/bt_bluez.c +++ b/src/bt/bt_bluez.c @@ -93,6 +93,9 @@ #define STORE_MAC_REVERSE 1 #define ACCEPT_NONSEP_MAC 1 +#define CONNECT_RFCOMM_TRIES 3 +#define CONNECT_RFCOMM_RETRY_MS 100 + /* Silence warning about (currently) unused routine. */ #define WITH_WRITE_TYPE_HANDLE 0 @@ -795,7 +798,7 @@ SR_PRIV int sr_bt_connect_ble(struct sr_bt_desc *desc) SR_PRIV int sr_bt_connect_rfcomm(struct sr_bt_desc *desc) { struct sockaddr_rc addr; - int fd, rc; + int i, fd, rc; if (!desc) return -1; @@ -807,25 +810,40 @@ SR_PRIV int sr_bt_connect_rfcomm(struct sr_bt_desc *desc) if (!desc->rfcomm_channel) desc->rfcomm_channel = 1; - fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); - if (fd < 0) { - perror("socket"); - return -1; - } - desc->fd = fd; - memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; str2ba(desc->remote_addr, &addr.rc_bdaddr); addr.rc_channel = desc->rfcomm_channel; - rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); - if (rc < 0) { - perror("connect"); - return -2; + + /* + * There are cases where connect returns EBUSY if we are re-connecting + * to a device. Try multiple times to work around this issue. + */ + for (i = 0; i < CONNECT_RFCOMM_TRIES; i++) { + fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); + if (fd < 0) { + perror("socket"); + return -1; + } + + rc = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); + if (rc >= 0) { + sr_spew("connected"); + desc->fd = fd; + return 0; + } else if (rc < 0 && errno == EBUSY) { + close(fd); + g_usleep(CONNECT_RFCOMM_RETRY_MS * 1000); + } else { + close(fd); + perror("connect"); + return -2; + } } - sr_spew("connected"); - return 0; + sr_err("Connect failed, device busy."); + + return -2; } SR_PRIV void sr_bt_disconnect(struct sr_bt_desc *desc)