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 }
};