Skip to content

Commit d321b6e

Browse files
[3.13] gh-132099: Harmonize Bluetooth address handling (GH-132486) (GH-132497)
Now all protocols always accept the Bluetooth address as string and getsockname() always returns the Bluetooth address as string. * BTPROTO_SCO now accepts not only bytes, but str. * BTPROTO_SCO now checks address for embedded null. * On *BSD, BTPROTO_HCI now accepts str instead of bytes. * On FreeBSD, getsockname() for BTPROTO_HCI now returns str instead of bytes. * On NetBSD and DragonFly BSD, BTPROTO_HCI now checks address for embedded null. (cherry picked from commit 1fc1df8)
1 parent a50aa33 commit d321b6e

File tree

3 files changed

+58
-38
lines changed

3 files changed

+58
-38
lines changed

Diff for: Doc/library/socket.rst

+6-7
Original file line numberDiff line numberDiff line change
@@ -147,20 +147,19 @@ created. Socket addresses are represented as follows:
147147

148148
- On Linux it accepts a tuple ``(device_id,)`` where ``device_id``
149149
is an integer specifying the number of the Bluetooth device.
150-
- On FreeBSD, NetBSD and DragonFly BSD it accepts ``bdaddr`` where ``bdaddr``
151-
is a :class:`bytes` object containing the Bluetooth address in a
152-
string format. (ex. ``b'12:23:34:45:56:67'``)
150+
- On FreeBSD, NetBSD and DragonFly BSD it accepts ``bdaddr``
151+
where ``bdaddr`` is the Bluetooth address as a string.
153152

154153
.. versionchanged:: 3.2
155154
NetBSD and DragonFlyBSD support added.
156155

157156
.. versionchanged:: 3.13.3
158157
FreeBSD support added.
159158

160-
- :const:`BTPROTO_SCO` accepts ``bdaddr`` where ``bdaddr`` is a
161-
:class:`bytes` object containing the Bluetooth address in a
162-
string format. (ex. ``b'12:23:34:45:56:67'``) This protocol is not
163-
supported under FreeBSD.
159+
- :const:`BTPROTO_SCO` accepts ``bdaddr`` where ``bdaddr`` is
160+
the Bluetooth address as a string or a :class:`bytes` object.
161+
(ex. ``'12:23:34:45:56:67'`` or ``b'12:23:34:45:56:67'``)
162+
This protocol is not supported under FreeBSD.
164163

165164
- :const:`AF_ALG` is a Linux-only socket based interface to Kernel
166165
cryptography. An algorithm socket is configured with a tuple of two to four

Diff for: Lib/test/test_socket.py

+31-9
Original file line numberDiff line numberDiff line change
@@ -2656,6 +2656,8 @@ def testBadL2capAddr(self):
26562656
f.bind(socket.BDADDR_ANY)
26572657
with self.assertRaises(OSError):
26582658
f.bind((socket.BDADDR_ANY.encode(), 0x1001))
2659+
with self.assertRaises(OSError):
2660+
f.bind(('\ud812', 0x1001))
26592661

26602662
def testBindRfcommSocket(self):
26612663
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM) as s:
@@ -2687,14 +2689,16 @@ def testBadRfcommAddr(self):
26872689
s.bind((socket.BDADDR_ANY, channel, 0))
26882690
with self.assertRaises(OSError):
26892691
s.bind((socket.BDADDR_ANY + '\0', channel))
2692+
with self.assertRaises(OSError):
2693+
s.bind('\ud812')
26902694
with self.assertRaises(OSError):
26912695
s.bind(('invalid', channel))
26922696

26932697
@unittest.skipUnless(hasattr(socket, 'BTPROTO_HCI'), 'Bluetooth HCI sockets required for this test')
26942698
def testBindHciSocket(self):
26952699
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) as s:
26962700
if sys.platform.startswith(('netbsd', 'dragonfly', 'freebsd')):
2697-
s.bind(socket.BDADDR_ANY.encode())
2701+
s.bind(socket.BDADDR_ANY)
26982702
addr = s.getsockname()
26992703
self.assertEqual(addr, socket.BDADDR_ANY)
27002704
else:
@@ -2713,14 +2717,17 @@ def testBadHciAddr(self):
27132717
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) as s:
27142718
if sys.platform.startswith(('netbsd', 'dragonfly', 'freebsd')):
27152719
with self.assertRaises(OSError):
2716-
s.bind(socket.BDADDR_ANY)
2720+
s.bind(socket.BDADDR_ANY.encode())
27172721
with self.assertRaises(OSError):
2718-
s.bind((socket.BDADDR_ANY.encode(),))
2719-
if sys.platform.startswith('freebsd'):
2720-
with self.assertRaises(ValueError):
2721-
s.bind(socket.BDADDR_ANY.encode() + b'\0')
2722-
with self.assertRaises(ValueError):
2723-
s.bind(socket.BDADDR_ANY.encode() + b' '*100)
2722+
s.bind((socket.BDADDR_ANY,))
2723+
with self.assertRaises(OSError):
2724+
s.bind(socket.BDADDR_ANY + '\0')
2725+
with self.assertRaises((ValueError, OSError)):
2726+
s.bind(socket.BDADDR_ANY + ' '*100)
2727+
with self.assertRaises(OSError):
2728+
s.bind('\ud812')
2729+
with self.assertRaises(OSError):
2730+
s.bind('invalid')
27242731
with self.assertRaises(OSError):
27252732
s.bind(b'invalid')
27262733
else:
@@ -2731,11 +2738,18 @@ def testBadHciAddr(self):
27312738
s.bind((dev, 0))
27322739
with self.assertRaises(OSError):
27332740
s.bind(dev)
2741+
with self.assertRaises(OSError):
2742+
s.bind(socket.BDADDR_ANY)
27342743
with self.assertRaises(OSError):
27352744
s.bind(socket.BDADDR_ANY.encode())
27362745

27372746
@unittest.skipUnless(hasattr(socket, 'BTPROTO_SCO'), 'Bluetooth SCO sockets required for this test')
27382747
def testBindScoSocket(self):
2748+
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_SCO) as s:
2749+
s.bind(socket.BDADDR_ANY)
2750+
addr = s.getsockname()
2751+
self.assertEqual(addr, socket.BDADDR_ANY)
2752+
27392753
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_SCO) as s:
27402754
s.bind(socket.BDADDR_ANY.encode())
27412755
addr = s.getsockname()
@@ -2745,9 +2759,17 @@ def testBindScoSocket(self):
27452759
def testBadScoAddr(self):
27462760
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_SCO) as s:
27472761
with self.assertRaises(OSError):
2748-
s.bind(socket.BDADDR_ANY)
2762+
s.bind((socket.BDADDR_ANY,))
27492763
with self.assertRaises(OSError):
27502764
s.bind((socket.BDADDR_ANY.encode(),))
2765+
with self.assertRaises(ValueError):
2766+
s.bind(socket.BDADDR_ANY + '\0')
2767+
with self.assertRaises(ValueError):
2768+
s.bind(socket.BDADDR_ANY.encode() + b'\0')
2769+
with self.assertRaises(UnicodeEncodeError):
2770+
s.bind('\ud812')
2771+
with self.assertRaises(OSError):
2772+
s.bind('invalid')
27512773
with self.assertRaises(OSError):
27522774
s.bind(b'invalid')
27532775

Diff for: Modules/socketmodule.c

+21-22
Original file line numberDiff line numberDiff line change
@@ -1495,7 +1495,7 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
14951495
#elif defined(__FreeBSD__)
14961496
const char *node = _BT_HCI_MEMB(a, node);
14971497
size_t len = strnlen(node, sizeof(_BT_HCI_MEMB(a, node)));
1498-
return PyBytes_FromStringAndSize(node, (Py_ssize_t)len);
1498+
return PyUnicode_FromStringAndSize(node, (Py_ssize_t)len);
14991499
#else
15001500
return makebdaddr(&_BT_HCI_MEMB(a, bdaddr));
15011501
#endif
@@ -2075,36 +2075,25 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
20752075
return 0;
20762076
}
20772077
_BT_HCI_MEMB(addr, dev) = dev;
2078-
#elif defined(__FreeBSD__)
2079-
if (!PyBytes_Check(args)) {
2078+
#else
2079+
const char *straddr;
2080+
if (!PyArg_Parse(args, "s", &straddr)) {
20802081
PyErr_Format(PyExc_OSError, "%s: "
2081-
"wrong node format", caller);
2082-
return 0;
2083-
}
2084-
const char *straddr = PyBytes_AS_STRING(args);
2085-
size_t len = PyBytes_GET_SIZE(args);
2086-
if (strlen(straddr) != len) {
2087-
PyErr_Format(PyExc_ValueError, "%s: "
2088-
"node contains embedded null character", caller);
2082+
"wrong format", caller);
20892083
return 0;
20902084
}
2091-
if (len > sizeof(_BT_HCI_MEMB(addr, node))) {
2085+
# if defined(__FreeBSD__)
2086+
if (strlen(straddr) > sizeof(_BT_HCI_MEMB(addr, node))) {
20922087
PyErr_Format(PyExc_ValueError, "%s: "
20932088
"node too long", caller);
20942089
return 0;
20952090
}
20962091
strncpy(_BT_HCI_MEMB(addr, node), straddr,
20972092
sizeof(_BT_HCI_MEMB(addr, node)));
2098-
#else
2099-
const char *straddr;
2100-
if (!PyBytes_Check(args)) {
2101-
PyErr_Format(PyExc_OSError, "%s: "
2102-
"wrong format", caller);
2103-
return 0;
2104-
}
2105-
straddr = PyBytes_AS_STRING(args);
2093+
# else
21062094
if (setbdaddr(straddr, &_BT_HCI_MEMB(addr, bdaddr)) < 0)
21072095
return 0;
2096+
# endif
21082097
#endif
21092098
*len_ret = sizeof *addr;
21102099
return 1;
@@ -2117,12 +2106,22 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
21172106
struct sockaddr_sco *addr = &addrbuf->bt_sco;
21182107
memset(addr, 0, sizeof(struct sockaddr_sco));
21192108
_BT_SCO_MEMB(addr, family) = AF_BLUETOOTH;
2120-
if (!PyBytes_Check(args)) {
2109+
2110+
if (PyBytes_Check(args)) {
2111+
if (!PyArg_Parse(args, "y", &straddr)) {
2112+
return 0;
2113+
}
2114+
}
2115+
else if (PyUnicode_Check(args)) {
2116+
if (!PyArg_Parse(args, "s", &straddr)) {
2117+
return 0;
2118+
}
2119+
}
2120+
else {
21212121
PyErr_Format(PyExc_OSError,
21222122
"%s(): wrong format", caller);
21232123
return 0;
21242124
}
2125-
straddr = PyBytes_AS_STRING(args);
21262125
if (setbdaddr(straddr, &_BT_SCO_MEMB(addr, bdaddr)) < 0)
21272126
return 0;
21282127

0 commit comments

Comments
 (0)