https://github.com/python/cpython/commit/d321b6ec826b0767d15d73e6f8ebd38e3600b7f8
commit: d321b6ec826b0767d15d73e6f8ebd38e3600b7f8
branch: 3.13
author: Serhiy Storchaka <storch...@gmail.com>
committer: serhiy-storchaka <storch...@gmail.com>
date: 2025-04-14T19:36:04+03:00
summary:

[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 1fc1df8dcc7a853b0649bc8df37cd07cbd2b6230)

files:
M Doc/library/socket.rst
M Lib/test/test_socket.py
M Modules/socketmodule.c

diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
index 52b993bd81e96b..0757ffd57d8232 100644
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -147,9 +147,8 @@ created.  Socket addresses are represented as follows:
 
     - On Linux it accepts a tuple ``(device_id,)`` where ``device_id``
       is an integer specifying the number of the Bluetooth device.
-    - On FreeBSD, NetBSD and DragonFly BSD it accepts ``bdaddr`` where 
``bdaddr``
-      is a :class:`bytes` object containing the Bluetooth address in a
-      string format. (ex. ``b'12:23:34:45:56:67'``)
+    - On FreeBSD, NetBSD and DragonFly BSD it accepts ``bdaddr``
+      where ``bdaddr`` is the Bluetooth address as a string.
 
     .. versionchanged:: 3.2
        NetBSD and DragonFlyBSD support added.
@@ -157,10 +156,10 @@ created.  Socket addresses are represented as follows:
     .. versionchanged:: 3.13.3
        FreeBSD support added.
 
-  - :const:`BTPROTO_SCO` accepts ``bdaddr`` where ``bdaddr`` is a
-    :class:`bytes` object containing the Bluetooth address in a
-    string format. (ex. ``b'12:23:34:45:56:67'``) This protocol is not
-    supported under FreeBSD.
+  - :const:`BTPROTO_SCO` accepts ``bdaddr`` where ``bdaddr`` is
+    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'``)
+    This protocol is not supported under FreeBSD.
 
 - :const:`AF_ALG` is a Linux-only socket based interface to Kernel
   cryptography. An algorithm socket is configured with a tuple of two to four
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 02413c6056aa76..d33cc052d1cd4f 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -2656,6 +2656,8 @@ def testBadL2capAddr(self):
                 f.bind(socket.BDADDR_ANY)
             with self.assertRaises(OSError):
                 f.bind((socket.BDADDR_ANY.encode(), 0x1001))
+            with self.assertRaises(OSError):
+                f.bind(('\ud812', 0x1001))
 
     def testBindRfcommSocket(self):
         with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, 
socket.BTPROTO_RFCOMM) as s:
@@ -2687,6 +2689,8 @@ def testBadRfcommAddr(self):
                 s.bind((socket.BDADDR_ANY, channel, 0))
             with self.assertRaises(OSError):
                 s.bind((socket.BDADDR_ANY + '\0', channel))
+            with self.assertRaises(OSError):
+                s.bind('\ud812')
             with self.assertRaises(OSError):
                 s.bind(('invalid', channel))
 
@@ -2694,7 +2698,7 @@ def testBadRfcommAddr(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')):
-                s.bind(socket.BDADDR_ANY.encode())
+                s.bind(socket.BDADDR_ANY)
                 addr = s.getsockname()
                 self.assertEqual(addr, socket.BDADDR_ANY)
             else:
@@ -2713,14 +2717,17 @@ def testBadHciAddr(self):
         with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, 
socket.BTPROTO_HCI) as s:
             if sys.platform.startswith(('netbsd', 'dragonfly', 'freebsd')):
                 with self.assertRaises(OSError):
-                    s.bind(socket.BDADDR_ANY)
+                    s.bind(socket.BDADDR_ANY.encode())
                 with self.assertRaises(OSError):
-                    s.bind((socket.BDADDR_ANY.encode(),))
-                if sys.platform.startswith('freebsd'):
-                    with self.assertRaises(ValueError):
-                        s.bind(socket.BDADDR_ANY.encode() + b'\0')
-                    with self.assertRaises(ValueError):
-                        s.bind(socket.BDADDR_ANY.encode() + b' '*100)
+                    s.bind((socket.BDADDR_ANY,))
+                with self.assertRaises(OSError):
+                    s.bind(socket.BDADDR_ANY + '\0')
+                with self.assertRaises((ValueError, OSError)):
+                    s.bind(socket.BDADDR_ANY + ' '*100)
+                with self.assertRaises(OSError):
+                    s.bind('\ud812')
+                with self.assertRaises(OSError):
+                    s.bind('invalid')
                 with self.assertRaises(OSError):
                     s.bind(b'invalid')
             else:
@@ -2731,11 +2738,18 @@ def testBadHciAddr(self):
                     s.bind((dev, 0))
                 with self.assertRaises(OSError):
                     s.bind(dev)
+                with self.assertRaises(OSError):
+                    s.bind(socket.BDADDR_ANY)
                 with self.assertRaises(OSError):
                     s.bind(socket.BDADDR_ANY.encode())
 
     @unittest.skipUnless(hasattr(socket, 'BTPROTO_SCO'), 'Bluetooth SCO 
sockets required for this test')
     def testBindScoSocket(self):
+        with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, 
socket.BTPROTO_SCO) as s:
+            s.bind(socket.BDADDR_ANY)
+            addr = s.getsockname()
+            self.assertEqual(addr, socket.BDADDR_ANY)
+
         with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, 
socket.BTPROTO_SCO) as s:
             s.bind(socket.BDADDR_ANY.encode())
             addr = s.getsockname()
@@ -2745,9 +2759,17 @@ def testBindScoSocket(self):
     def testBadScoAddr(self):
         with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, 
socket.BTPROTO_SCO) as s:
             with self.assertRaises(OSError):
-                s.bind(socket.BDADDR_ANY)
+                s.bind((socket.BDADDR_ANY,))
             with self.assertRaises(OSError):
                 s.bind((socket.BDADDR_ANY.encode(),))
+            with self.assertRaises(ValueError):
+                s.bind(socket.BDADDR_ANY + '\0')
+            with self.assertRaises(ValueError):
+                s.bind(socket.BDADDR_ANY.encode() + b'\0')
+            with self.assertRaises(UnicodeEncodeError):
+                s.bind('\ud812')
+            with self.assertRaises(OSError):
+                s.bind('invalid')
             with self.assertRaises(OSError):
                 s.bind(b'invalid')
 
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 0f480086ccda55..dbc9e4ed3919b0 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -1495,7 +1495,7 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, 
size_t addrlen, int proto)
 #elif defined(__FreeBSD__)
             const char *node = _BT_HCI_MEMB(a, node);
             size_t len = strnlen(node, sizeof(_BT_HCI_MEMB(a, node)));
-            return PyBytes_FromStringAndSize(node, (Py_ssize_t)len);
+            return PyUnicode_FromStringAndSize(node, (Py_ssize_t)len);
 #else
             return makebdaddr(&_BT_HCI_MEMB(a, bdaddr));
 #endif
@@ -2075,36 +2075,25 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
                 return 0;
             }
             _BT_HCI_MEMB(addr, dev) = dev;
-#elif defined(__FreeBSD__)
-            if (!PyBytes_Check(args)) {
+#else
+            const char *straddr;
+            if (!PyArg_Parse(args, "s", &straddr)) {
                 PyErr_Format(PyExc_OSError, "%s: "
-                             "wrong node format", caller);
-                return 0;
-            }
-            const char *straddr = PyBytes_AS_STRING(args);
-            size_t len = PyBytes_GET_SIZE(args);
-            if (strlen(straddr) != len) {
-                PyErr_Format(PyExc_ValueError, "%s: "
-                             "node contains embedded null character", caller);
+                             "wrong format", caller);
                 return 0;
             }
-            if (len > sizeof(_BT_HCI_MEMB(addr, node))) {
+# if defined(__FreeBSD__)
+            if (strlen(straddr) > sizeof(_BT_HCI_MEMB(addr, node))) {
                 PyErr_Format(PyExc_ValueError, "%s: "
                              "node too long", caller);
                 return 0;
             }
             strncpy(_BT_HCI_MEMB(addr, node), straddr,
                     sizeof(_BT_HCI_MEMB(addr, node)));
-#else
-            const char *straddr;
-            if (!PyBytes_Check(args)) {
-                PyErr_Format(PyExc_OSError, "%s: "
-                             "wrong format", caller);
-                return 0;
-            }
-            straddr = PyBytes_AS_STRING(args);
+# else
             if (setbdaddr(straddr, &_BT_HCI_MEMB(addr, bdaddr)) < 0)
                 return 0;
+# endif
 #endif
             *len_ret = sizeof *addr;
             return 1;
@@ -2117,12 +2106,22 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
             struct sockaddr_sco *addr = &addrbuf->bt_sco;
             memset(addr, 0, sizeof(struct sockaddr_sco));
             _BT_SCO_MEMB(addr, family) = AF_BLUETOOTH;
-            if (!PyBytes_Check(args)) {
+
+            if (PyBytes_Check(args)) {
+                if (!PyArg_Parse(args, "y", &straddr)) {
+                    return 0;
+                }
+            }
+            else if (PyUnicode_Check(args)) {
+                if (!PyArg_Parse(args, "s", &straddr)) {
+                    return 0;
+                }
+            }
+            else {
                 PyErr_Format(PyExc_OSError,
                              "%s(): wrong format", caller);
                 return 0;
             }
-            straddr = PyBytes_AS_STRING(args);
             if (setbdaddr(straddr, &_BT_SCO_MEMB(addr, bdaddr)) < 0)
                 return 0;
 

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to