gh-70145: Add support for channels in Bluetooth HCI protocol (GH-132481)
This commit is contained in:
parent
d22604a6d1
commit
61638418a7
@ -156,8 +156,10 @@ created. Socket addresses are represented as follows:
|
|||||||
|
|
||||||
- :const:`BTPROTO_HCI` accepts a format that depends on your OS.
|
- :const:`BTPROTO_HCI` accepts a format that depends on your OS.
|
||||||
|
|
||||||
- On Linux it accepts a tuple ``(device_id,)`` where ``device_id``
|
- On Linux it accepts a tuple ``(device_id, [channel])`` where ``device_id``
|
||||||
is an integer specifying the number of the Bluetooth device.
|
is an integer specifying the number of the Bluetooth device,
|
||||||
|
and ``channel`` is an optional integer specifying the HCI channel
|
||||||
|
(:const:`HCI_CHANNEL_RAW` by default).
|
||||||
- On FreeBSD, NetBSD and DragonFly BSD it accepts ``bdaddr``
|
- On FreeBSD, NetBSD and DragonFly BSD it accepts ``bdaddr``
|
||||||
where ``bdaddr`` is the Bluetooth address as a string.
|
where ``bdaddr`` is the Bluetooth address as a string.
|
||||||
|
|
||||||
@ -167,6 +169,9 @@ created. Socket addresses are represented as follows:
|
|||||||
.. versionchanged:: 3.13.3
|
.. versionchanged:: 3.13.3
|
||||||
FreeBSD support added.
|
FreeBSD support added.
|
||||||
|
|
||||||
|
.. versionchanged:: next
|
||||||
|
Added ``channel`` field.
|
||||||
|
|
||||||
- :const:`BTPROTO_SCO` accepts ``bdaddr`` where ``bdaddr`` is
|
- :const:`BTPROTO_SCO` accepts ``bdaddr`` where ``bdaddr`` is
|
||||||
the Bluetooth address as a string or a :class:`bytes` object.
|
the Bluetooth address as a string or a :class:`bytes` object.
|
||||||
(ex. ``'12:23:34:45:56:67'`` or ``b'12:23:34:45:56:67'``)
|
(ex. ``'12:23:34:45:56:67'`` or ``b'12:23:34:45:56:67'``)
|
||||||
@ -677,6 +682,18 @@ Constants
|
|||||||
available on Linux and FreeBSD. :const:`!HCI_TIME_STAMP` and
|
available on Linux and FreeBSD. :const:`!HCI_TIME_STAMP` and
|
||||||
:const:`!HCI_DATA_DIR` are only available on Linux.
|
:const:`!HCI_DATA_DIR` are only available on Linux.
|
||||||
|
|
||||||
|
.. data:: HCI_CHANNEL_RAW
|
||||||
|
HCI_CHANNEL_USER
|
||||||
|
HCI_CHANNEL_MONITOR
|
||||||
|
HCI_CHANNEL_CONTROL
|
||||||
|
HCI_CHANNEL_LOGGING
|
||||||
|
|
||||||
|
Possible values for ``channel`` field in the :const:`BTPROTO_HCI` address.
|
||||||
|
|
||||||
|
.. availability:: Linux
|
||||||
|
|
||||||
|
.. versionadded:: next
|
||||||
|
|
||||||
.. data:: AF_QIPCRTR
|
.. data:: AF_QIPCRTR
|
||||||
|
|
||||||
Constant for Qualcomm's IPC router protocol, used to communicate with
|
Constant for Qualcomm's IPC router protocol, used to communicate with
|
||||||
|
@ -2622,6 +2622,13 @@ class BasicBluetoothTest(unittest.TestCase):
|
|||||||
socket.BTPROTO_L2CAP
|
socket.BTPROTO_L2CAP
|
||||||
socket.BTPROTO_SCO
|
socket.BTPROTO_SCO
|
||||||
|
|
||||||
|
if sys.platform == "linux":
|
||||||
|
socket.HCI_CHANNEL_RAW
|
||||||
|
socket.HCI_CHANNEL_USER
|
||||||
|
socket.HCI_CHANNEL_MONITOR
|
||||||
|
socket.HCI_CHANNEL_CONTROL
|
||||||
|
socket.HCI_CHANNEL_LOGGING
|
||||||
|
|
||||||
def testCreateRfcommSocket(self):
|
def testCreateRfcommSocket(self):
|
||||||
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM) as s:
|
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM) as s:
|
||||||
pass
|
pass
|
||||||
@ -2721,13 +2728,14 @@ class BasicBluetoothTest(unittest.TestCase):
|
|||||||
|
|
||||||
@unittest.skipUnless(hasattr(socket, 'BTPROTO_HCI'), 'Bluetooth HCI sockets required for this test')
|
@unittest.skipUnless(hasattr(socket, 'BTPROTO_HCI'), 'Bluetooth HCI sockets required for this test')
|
||||||
def testBindHciSocket(self):
|
def testBindHciSocket(self):
|
||||||
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) as s:
|
|
||||||
if sys.platform.startswith(('netbsd', 'dragonfly', 'freebsd')):
|
if sys.platform.startswith(('netbsd', 'dragonfly', 'freebsd')):
|
||||||
|
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) as s:
|
||||||
s.bind(socket.BDADDR_ANY)
|
s.bind(socket.BDADDR_ANY)
|
||||||
addr = s.getsockname()
|
addr = s.getsockname()
|
||||||
self.assertEqual(addr, socket.BDADDR_ANY)
|
self.assertEqual(addr, socket.BDADDR_ANY)
|
||||||
else:
|
else:
|
||||||
dev = 0
|
dev = 0
|
||||||
|
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) as s:
|
||||||
try:
|
try:
|
||||||
s.bind((dev,))
|
s.bind((dev,))
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
@ -2737,6 +2745,26 @@ class BasicBluetoothTest(unittest.TestCase):
|
|||||||
addr = s.getsockname()
|
addr = s.getsockname()
|
||||||
self.assertEqual(addr, dev)
|
self.assertEqual(addr, dev)
|
||||||
|
|
||||||
|
with (self.subTest('channel=HCI_CHANNEL_RAW'),
|
||||||
|
socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) as s):
|
||||||
|
channel = socket.HCI_CHANNEL_RAW
|
||||||
|
s.bind((dev, channel))
|
||||||
|
addr = s.getsockname()
|
||||||
|
self.assertEqual(addr, dev)
|
||||||
|
|
||||||
|
with (self.subTest('channel=HCI_CHANNEL_USER'),
|
||||||
|
socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) as s):
|
||||||
|
channel = socket.HCI_CHANNEL_USER
|
||||||
|
try:
|
||||||
|
s.bind((dev, channel))
|
||||||
|
except OSError as err:
|
||||||
|
# Needs special permissions.
|
||||||
|
if err.errno in (errno.EPERM, errno.EBUSY, errno.ERFKILL):
|
||||||
|
self.skipTest(str(err))
|
||||||
|
raise
|
||||||
|
addr = s.getsockname()
|
||||||
|
self.assertEqual(addr, (dev, channel))
|
||||||
|
|
||||||
@unittest.skipUnless(hasattr(socket, 'BTPROTO_HCI'), 'Bluetooth HCI sockets required for this test')
|
@unittest.skipUnless(hasattr(socket, 'BTPROTO_HCI'), 'Bluetooth HCI sockets required for this test')
|
||||||
def testBadHciAddr(self):
|
def testBadHciAddr(self):
|
||||||
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) as s:
|
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) as s:
|
||||||
@ -2760,7 +2788,7 @@ class BasicBluetoothTest(unittest.TestCase):
|
|||||||
with self.assertRaises(OSError):
|
with self.assertRaises(OSError):
|
||||||
s.bind(())
|
s.bind(())
|
||||||
with self.assertRaises(OSError):
|
with self.assertRaises(OSError):
|
||||||
s.bind((dev, 0))
|
s.bind((dev, socket.HCI_CHANNEL_RAW, 0, 0))
|
||||||
with self.assertRaises(OSError):
|
with self.assertRaises(OSError):
|
||||||
s.bind(dev)
|
s.bind(dev)
|
||||||
with self.assertRaises(OSError):
|
with self.assertRaises(OSError):
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
Add support for channels in Bluetooth HCI protocol
|
||||||
|
(:const:`~socket.BTPROTO_HCI`).
|
@ -1541,7 +1541,14 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
|
|||||||
struct sockaddr_hci *a = (struct sockaddr_hci *) addr;
|
struct sockaddr_hci *a = (struct sockaddr_hci *) addr;
|
||||||
#if defined(HAVE_BLUETOOTH_BLUETOOTH_H)
|
#if defined(HAVE_BLUETOOTH_BLUETOOTH_H)
|
||||||
PyObject *ret = NULL;
|
PyObject *ret = NULL;
|
||||||
ret = Py_BuildValue("i", _BT_HCI_MEMB(a, dev));
|
if (_BT_HCI_MEMB(a, channel) == HCI_CHANNEL_RAW) {
|
||||||
|
return Py_BuildValue("i", _BT_HCI_MEMB(a, dev));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return Py_BuildValue("ii",
|
||||||
|
_BT_HCI_MEMB(a, dev),
|
||||||
|
_BT_HCI_MEMB(a, channel));
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
#elif defined(__FreeBSD__)
|
#elif defined(__FreeBSD__)
|
||||||
const char *node = _BT_HCI_MEMB(a, node);
|
const char *node = _BT_HCI_MEMB(a, node);
|
||||||
@ -2138,13 +2145,15 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
|
|||||||
memset(addr, 0, sizeof(struct sockaddr_hci));
|
memset(addr, 0, sizeof(struct sockaddr_hci));
|
||||||
_BT_HCI_MEMB(addr, family) = AF_BLUETOOTH;
|
_BT_HCI_MEMB(addr, family) = AF_BLUETOOTH;
|
||||||
#if defined(HAVE_BLUETOOTH_BLUETOOTH_H)
|
#if defined(HAVE_BLUETOOTH_BLUETOOTH_H)
|
||||||
unsigned short dev = _BT_HCI_MEMB(addr, dev);
|
unsigned short dev;
|
||||||
if (!PyArg_ParseTuple(args, "H", &dev)) {
|
unsigned short channel = HCI_CHANNEL_RAW;
|
||||||
|
if (!PyArg_ParseTuple(args, "H|H", &dev, &channel)) {
|
||||||
PyErr_Format(PyExc_OSError,
|
PyErr_Format(PyExc_OSError,
|
||||||
"%s(): wrong format", caller);
|
"%s(): wrong format", caller);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_BT_HCI_MEMB(addr, dev) = dev;
|
_BT_HCI_MEMB(addr, dev) = dev;
|
||||||
|
_BT_HCI_MEMB(addr, channel) = channel;
|
||||||
#else
|
#else
|
||||||
const char *straddr;
|
const char *straddr;
|
||||||
if (!PyArg_Parse(args, "s", &straddr)) {
|
if (!PyArg_Parse(args, "s", &straddr)) {
|
||||||
@ -7874,6 +7883,13 @@ socket_exec(PyObject *m)
|
|||||||
#ifdef BTPROTO_HCI
|
#ifdef BTPROTO_HCI
|
||||||
ADD_INT_MACRO(m, BTPROTO_HCI);
|
ADD_INT_MACRO(m, BTPROTO_HCI);
|
||||||
ADD_INT_MACRO(m, SOL_HCI);
|
ADD_INT_MACRO(m, SOL_HCI);
|
||||||
|
#if defined(HCI_CHANNEL_RAW)
|
||||||
|
ADD_INT_MACRO(m, HCI_CHANNEL_RAW);
|
||||||
|
ADD_INT_MACRO(m, HCI_CHANNEL_USER);
|
||||||
|
ADD_INT_MACRO(m, HCI_CHANNEL_MONITOR);
|
||||||
|
ADD_INT_MACRO(m, HCI_CHANNEL_CONTROL);
|
||||||
|
ADD_INT_MACRO(m, HCI_CHANNEL_LOGGING);
|
||||||
|
#endif
|
||||||
#if defined(HCI_FILTER)
|
#if defined(HCI_FILTER)
|
||||||
ADD_INT_MACRO(m, HCI_FILTER);
|
ADD_INT_MACRO(m, HCI_FILTER);
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user