btsocket: Implement listen and accept This CL adds a function to deal with incoming BLE connection, which is needed by GATT test server. BUG=chromium:449666 TEST=cros deploy $HOST dev-python/btsocket manually run function on tester, run BlueZ btgatt-client on DUT verify that returned socket is able to receive and send messages Change-Id: Ia29ff6073108bc0e9c3474703165e87972f6adf0
diff --git a/btsocket/btsocket.py b/btsocket/btsocket.py index 37889d2..1cec234 100644 --- a/btsocket/btsocket.py +++ b/btsocket/btsocket.py
@@ -85,3 +85,26 @@ """ return _btsocket.recvmsg(self, buffers, ancbufsize, flags) + +def create_le_gatt_server_socket(): + """Create a socket for incoming BLE connection. + + The function creates an LE socket, then does bind, listen and accept. + The accept call blocks until it receives an incoming connection. + + Note, that resulting socket will be standard Python socket, + not BluetoothSocket. It is already connected, ready for recv() and + send() calls, and there is no need for further setup. + + Before calling this function, the machine must be set up (with appropriate + HCI commands) to be advertising, be powered, and have LE turned on. + + @return tuple of (sock, source_address), + @sock is standard Python socket object, which is able to receive and send. + @source_address is string containing BDADDR of the connected remote. + + """ + file_descriptor, source_address = _btsocket.listen_and_accept() + sock = socket.fromfd(file_descriptor, constants.AF_BLUETOOTH, + socket.SOCK_SEQPACKET, constants.BTPROTO_L2CAP) + return sock, source_address
diff --git a/src/bluetooth.h b/src/bluetooth.h index 48323f0..695885a 100644 --- a/src/bluetooth.h +++ b/src/bluetooth.h
@@ -42,6 +42,8 @@ #define PF_BLUETOOTH AF_BLUETOOTH #endif +#define ATT_CID 4 + #define BTPROTO_L2CAP 0 #define BTPROTO_HCI 1 #define BTPROTO_SCO 2
diff --git a/src/btsocket.c b/src/btsocket.c index 7b3c579..791eeda 100644 --- a/src/btsocket.c +++ b/src/btsocket.c
@@ -404,6 +404,74 @@ return retval; } +static PyObject *_btsocket_listen_and_accept() { + int sk, nsk, result; + struct sockaddr_l2 srcaddr, addr; + socklen_t optlen; + struct bt_security btsec; + bdaddr_t *ba; + char str[18]; + + Py_BEGIN_ALLOW_THREADS; + sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); + Py_END_ALLOW_THREADS; + if (sk < 0) + goto fail; + + /* Set up source address */ + memset(&srcaddr, 0, sizeof(srcaddr)); + srcaddr.l2_family = AF_BLUETOOTH; + srcaddr.l2_cid = htobs(ATT_CID); + srcaddr.l2_bdaddr_type = BDADDR_LE_PUBLIC; + + Py_BEGIN_ALLOW_THREADS; + result = bind(sk, (struct sockaddr *) &srcaddr, sizeof(srcaddr)); + Py_END_ALLOW_THREADS; + + if (result < 0) + goto fail; + + /* Set the security level */ + memset(&btsec, 0, sizeof(btsec)); + btsec.level = BT_SECURITY_LOW; + + Py_BEGIN_ALLOW_THREADS; + result = setsockopt(sk, SOL_BLUETOOTH, BT_SECURITY, &btsec, sizeof(btsec)); + Py_END_ALLOW_THREADS; + + if (result != 0) + goto fail; + + Py_BEGIN_ALLOW_THREADS; + result = listen(sk, 10); + Py_END_ALLOW_THREADS; + + if (result < 0) + goto fail; + + memset(&addr, 0, sizeof(addr)); + optlen = sizeof(addr); + + Py_BEGIN_ALLOW_THREADS; + nsk = accept(sk, (struct sockaddr *) &addr, &optlen); + Py_END_ALLOW_THREADS; + + if (nsk < 0) + goto fail; + + ba = &addr.l2_bdaddr; + sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", + ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]); + + close(sk); + return Py_BuildValue("(i,s)", nsk, str); + +fail: + if (sk >= 0) + close(sk); + + return PyErr_SetFromErrno(_btsocket_error); +} static PyMethodDef _btsocket_methods[] = { { "bind", _btsocket_bind, METH_VARARGS, @@ -412,6 +480,8 @@ "Connect a Bluetooth socket to a remote address" }, { "recvmsg", _btsocket_recvmsg, METH_VARARGS, "Receive normal and ancillary data from a Bluetooth socket" }, + { "listen_and_accept", _btsocket_listen_and_accept, METH_NOARGS, + "Create a socket for incoming BLE connection" }, { NULL, NULL, 0, NULL } };