https://github.com/python/cpython/commit/f2f86d3f459a89273ea22389bb57eed402908302 commit: f2f86d3f459a89273ea22389bb57eed402908302 branch: main author: Serhiy Storchaka <storch...@gmail.com> committer: serhiy-storchaka <storch...@gmail.com> date: 2025-04-12T23:57:34+03:00 summary:
gh-132429: Fix support of Bluetooth sockets on NetBSD and DragonFly BSD (GH-132431) * Also add support for cid and bdaddr_type in the BTPROTO_L2CAP address on FreeBSD. * Return cid in getsockname() for BTPROTO_L2CAP if it is not zero. * Fix a compiler warning on FreeBSD. files: A Misc/NEWS.d/next/Library/2025-04-12-12-59-51.gh-issue-132429.OEIdlW.rst M Lib/test/test_socket.py M Modules/socketmodule.c M Modules/socketmodule.h diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index cf46acbaab4b9e..fcadcb3fb884aa 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -2643,36 +2643,44 @@ def testCreateScoSocket(self): @unittest.skipUnless(HAVE_SOCKET_BLUETOOTH_L2CAP, 'Bluetooth L2CAP sockets required for this test') def testBindLeAttL2capSocket(self): + BDADDR_LE_PUBLIC = support.get_attribute(socket, 'BDADDR_LE_PUBLIC') with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_L2CAP) as f: # ATT is the only CID allowed in userspace by the Linux kernel CID_ATT = 4 - f.bind((socket.BDADDR_ANY, 0, CID_ATT, socket.BDADDR_LE_PUBLIC)) + f.bind((socket.BDADDR_ANY, 0, CID_ATT, BDADDR_LE_PUBLIC)) addr = f.getsockname() - self.assertEqual(addr, (socket.BDADDR_ANY, 0, CID_ATT, socket.BDADDR_LE_PUBLIC)) + self.assertEqual(addr, (socket.BDADDR_ANY, 0, CID_ATT, BDADDR_LE_PUBLIC)) @unittest.skipUnless(HAVE_SOCKET_BLUETOOTH_L2CAP, 'Bluetooth L2CAP sockets required for this test') def testBindLePsmL2capSocket(self): + BDADDR_LE_RANDOM = support.get_attribute(socket, 'BDADDR_LE_RANDOM') with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_L2CAP) as f: # First user PSM in LE L2CAP psm = 0x80 - f.bind((socket.BDADDR_ANY, psm, 0, socket.BDADDR_LE_RANDOM)) + f.bind((socket.BDADDR_ANY, psm, 0, BDADDR_LE_RANDOM)) addr = f.getsockname() - self.assertEqual(addr, (socket.BDADDR_ANY, psm, 0, socket.BDADDR_LE_RANDOM)) + self.assertEqual(addr, (socket.BDADDR_ANY, psm, 0, BDADDR_LE_RANDOM)) @unittest.skipUnless(HAVE_SOCKET_BLUETOOTH_L2CAP, 'Bluetooth L2CAP sockets required for this test') def testBindBrEdrL2capSocket(self): + # First user PSM in BR/EDR L2CAP + psm = 0x1001 with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_L2CAP) as f: - # First user PSM in BR/EDR L2CAP - psm = 0x1001 f.bind((socket.BDADDR_ANY, psm)) addr = f.getsockname() self.assertEqual(addr, (socket.BDADDR_ANY, psm)) + cid = 1 + with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_L2CAP) as f: + f.bind((socket.BDADDR_ANY, psm, cid)) + addr = f.getsockname() + self.assertEqual(addr, (socket.BDADDR_ANY, psm, cid)) + @unittest.skipUnless(HAVE_SOCKET_BLUETOOTH_L2CAP, 'Bluetooth L2CAP sockets required for this test') def testBadL2capAddr(self): with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_L2CAP) as f: with self.assertRaises(OSError): - f.bind((socket.BDADDR_ANY, 0, 0, socket.BDADDR_BREDR, 0)) + f.bind((socket.BDADDR_ANY, 0, 0, 0, 0)) with self.assertRaises(OSError): f.bind((socket.BDADDR_ANY,)) with self.assertRaises(OSError): diff --git a/Misc/NEWS.d/next/Library/2025-04-12-12-59-51.gh-issue-132429.OEIdlW.rst b/Misc/NEWS.d/next/Library/2025-04-12-12-59-51.gh-issue-132429.OEIdlW.rst new file mode 100644 index 00000000000000..95be9ec922bc93 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-04-12-12-59-51.gh-issue-132429.OEIdlW.rst @@ -0,0 +1,3 @@ +Fix support of Bluetooth sockets on NetBSD and DragonFly BSD. Add support +for *cid* and *bdaddr_type* in the BTPROTO_L2CAP address on FreeBSD. Return +*cid* in ``getsockname()`` for BTPROTO_L2CAP if it is not zero. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 22a3a2effe2962..76e16bc3a2d3ec 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -460,39 +460,44 @@ remove_unusable_flags(PyObject *m) # define SOCKETCLOSE close #endif -#if (defined(HAVE_BLUETOOTH_H) || defined(HAVE_BLUETOOTH_BLUETOOTH_H)) && !defined(__NetBSD__) && !defined(__DragonFly__) -#define USE_BLUETOOTH 1 -#if defined(__FreeBSD__) -#define BTPROTO_L2CAP BLUETOOTH_PROTO_L2CAP -#define BTPROTO_RFCOMM BLUETOOTH_PROTO_RFCOMM -#define BTPROTO_HCI BLUETOOTH_PROTO_HCI -#define BTPROTO_SCO BLUETOOTH_PROTO_SCO -#define SOL_HCI SOL_HCI_RAW -#define HCI_FILTER SO_HCI_RAW_FILTER -#define sockaddr_l2 sockaddr_l2cap -#define sockaddr_rc sockaddr_rfcomm -#define hci_dev hci_node -#define _BT_L2_MEMB(sa, memb) ((sa)->l2cap_##memb) -#define _BT_RC_MEMB(sa, memb) ((sa)->rfcomm_##memb) -#define _BT_HCI_MEMB(sa, memb) ((sa)->hci_##memb) -#define _BT_SCO_MEMB(sa, memb) ((sa)->sco_##memb) -#elif defined(__NetBSD__) || defined(__DragonFly__) -#define sockaddr_l2 sockaddr_bt -#define sockaddr_rc sockaddr_bt -#define sockaddr_hci sockaddr_bt -#define sockaddr_sco sockaddr_bt -#define SOL_HCI BTPROTO_HCI -#define HCI_DATA_DIR SO_HCI_DIRECTION -#define _BT_L2_MEMB(sa, memb) ((sa)->bt_##memb) -#define _BT_RC_MEMB(sa, memb) ((sa)->bt_##memb) -#define _BT_HCI_MEMB(sa, memb) ((sa)->bt_##memb) -#define _BT_SCO_MEMB(sa, memb) ((sa)->bt_##memb) -#else -#define _BT_L2_MEMB(sa, memb) ((sa)->l2_##memb) -#define _BT_RC_MEMB(sa, memb) ((sa)->rc_##memb) -#define _BT_HCI_MEMB(sa, memb) ((sa)->hci_##memb) -#define _BT_SCO_MEMB(sa, memb) ((sa)->sco_##memb) -#endif +#if defined(HAVE_BLUETOOTH_H) || defined(HAVE_BLUETOOTH_BLUETOOTH_H) +# define USE_BLUETOOTH 1 +# if defined(HAVE_BLUETOOTH_BLUETOOTH_H) // Linux +# define _BT_L2_MEMB(sa, memb) ((sa)->l2_##memb) +# define _BT_RC_MEMB(sa, memb) ((sa)->rc_##memb) +# define _BT_HCI_MEMB(sa, memb) ((sa)->hci_##memb) +# define _BT_SCO_MEMB(sa, memb) ((sa)->sco_##memb) +# elif defined(__FreeBSD__) +# define BTPROTO_L2CAP BLUETOOTH_PROTO_L2CAP +# define BTPROTO_RFCOMM BLUETOOTH_PROTO_RFCOMM +# define BTPROTO_HCI BLUETOOTH_PROTO_HCI +# define BTPROTO_SCO BLUETOOTH_PROTO_SCO +# define SOL_HCI SOL_HCI_RAW +# define HCI_FILTER SO_HCI_RAW_FILTER +# define sockaddr_l2 sockaddr_l2cap +# define sockaddr_rc sockaddr_rfcomm +# define hci_dev hci_node +# define _BT_L2_MEMB(sa, memb) ((sa)->l2cap_##memb) +# define _BT_RC_MEMB(sa, memb) ((sa)->rfcomm_##memb) +# define _BT_HCI_MEMB(sa, memb) ((sa)->hci_##memb) +# define _BT_SCO_MEMB(sa, memb) ((sa)->sco_##memb) +# else // NetBSD, DragonFly BSD +# define sockaddr_l2 sockaddr_bt +# define sockaddr_rc sockaddr_bt +# define sockaddr_hci sockaddr_bt +# define sockaddr_sco sockaddr_bt +# define bt_l2 bt +# define bt_rc bt +# define bt_sco bt +# define bt_hci bt +# define bt_cid bt_channel +# define SOL_HCI BTPROTO_HCI +# define HCI_DATA_DIR SO_HCI_DIRECTION +# define _BT_L2_MEMB(sa, memb) ((sa)->bt_##memb) +# define _BT_RC_MEMB(sa, memb) ((sa)->bt_##memb) +# define _BT_HCI_MEMB(sa, memb) ((sa)->bt_##memb) +# define _BT_SCO_MEMB(sa, memb) ((sa)->bt_##memb) +# endif #endif #ifdef MS_WINDOWS_DESKTOP @@ -1487,20 +1492,28 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto) PyObject *addrobj = makebdaddr(&_BT_L2_MEMB(a, bdaddr)); PyObject *ret = NULL; if (addrobj) { - /* Retain old format for non-LE address. - (cid may be set for BR/EDR, but we're discarding it for now) - */ - if (_BT_L2_MEMB(a, bdaddr_type) == BDADDR_BREDR) { - ret = Py_BuildValue("Oi", - addrobj, - _BT_L2_MEMB(a, psm)); - } else { +#if defined(BDADDR_BREDR) // Linux, FreeBSD + if (_BT_L2_MEMB(a, bdaddr_type) != BDADDR_BREDR) { ret = Py_BuildValue("OiiB", addrobj, _BT_L2_MEMB(a, psm), _BT_L2_MEMB(a, cid), _BT_L2_MEMB(a, bdaddr_type)); } + else +#endif + if (_BT_L2_MEMB(a, cid) != 0) { + ret = Py_BuildValue("Oii", + addrobj, + _BT_L2_MEMB(a, psm), + _BT_L2_MEMB(a, cid)); + } + else { + /* Retain old format for non-LE address. */ + ret = Py_BuildValue("Oi", + addrobj, + _BT_L2_MEMB(a, psm)); + } Py_DECREF(addrobj); } return ret; @@ -1526,16 +1539,16 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto) case BTPROTO_HCI: { struct sockaddr_hci *a = (struct sockaddr_hci *) addr; -#if defined(__NetBSD__) || defined(__DragonFly__) - return makebdaddr(&_BT_HCI_MEMB(a, bdaddr)); +#if defined(HAVE_BLUETOOTH_BLUETOOTH_H) + PyObject *ret = NULL; + ret = Py_BuildValue("i", _BT_HCI_MEMB(a, dev)); + return ret; #elif defined(__FreeBSD__) - char *node = _BT_HCI_MEMB(a, node); + 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); #else - PyObject *ret = NULL; - ret = Py_BuildValue("i", _BT_HCI_MEMB(a, dev)); - return ret; + return makebdaddr(&_BT_HCI_MEMB(a, bdaddr)); #endif } #endif /* BTPROTO_HCI */ @@ -2060,6 +2073,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, memset(addr, 0, sizeof(struct sockaddr_l2)); _BT_L2_MEMB(addr, family) = AF_BLUETOOTH; unsigned short psm; +#if defined(BDADDR_BREDR) // Linux, FreeBSD unsigned short cid = 0; unsigned char bdaddr_type = BDADDR_BREDR; if (!PyArg_ParseTuple(args, "sH|HB", &straddr, @@ -2070,9 +2084,18 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, "%s(): wrong format", caller); return 0; } + _BT_L2_MEMB(addr, bdaddr_type) = bdaddr_type; +#else + unsigned char cid = 0; + if (!PyArg_ParseTuple(args, "sH|B", &straddr, + &psm, &cid)) { + PyErr_Format(PyExc_OSError, + "%s(): wrong format", caller); + return 0; + } +#endif _BT_L2_MEMB(addr, psm) = psm; _BT_L2_MEMB(addr, cid) = cid; - _BT_L2_MEMB(addr, bdaddr_type) = bdaddr_type; if (setbdaddr(straddr, &_BT_L2_MEMB(addr, bdaddr)) < 0) return 0; @@ -2113,19 +2136,16 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, { struct sockaddr_hci *addr = &addrbuf->bt_hci; memset(addr, 0, sizeof(struct sockaddr_hci)); -#if defined(__NetBSD__) || defined(__DragonFly__) - const char *straddr; _BT_HCI_MEMB(addr, family) = AF_BLUETOOTH; - if (!PyBytes_Check(args)) { - PyErr_Format(PyExc_OSError, "%s: " - "wrong format", caller); +#if defined(HAVE_BLUETOOTH_BLUETOOTH_H) + unsigned short dev = _BT_HCI_MEMB(addr, dev); + if (!PyArg_ParseTuple(args, "H", &dev)) { + PyErr_Format(PyExc_OSError, + "%s(): wrong format", caller); return 0; } - straddr = PyBytes_AS_STRING(args); - if (setbdaddr(straddr, &_BT_HCI_MEMB(addr, bdaddr)) < 0) - return 0; + _BT_HCI_MEMB(addr, dev) = dev; #elif defined(__FreeBSD__) - _BT_HCI_MEMB(addr, family) = AF_BLUETOOTH; if (!PyBytes_Check(args)) { PyErr_Format(PyExc_OSError, "%s: " "wrong node format", caller); @@ -2146,14 +2166,15 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, strncpy(_BT_HCI_MEMB(addr, node), straddr, sizeof(_BT_HCI_MEMB(addr, node))); #else - _BT_HCI_MEMB(addr, family) = AF_BLUETOOTH; - unsigned short dev = _BT_HCI_MEMB(addr, dev); - if (!PyArg_ParseTuple(args, "H", &dev)) { - PyErr_Format(PyExc_OSError, - "%s(): wrong format", caller); + const char *straddr; + if (!PyBytes_Check(args)) { + PyErr_Format(PyExc_OSError, "%s: " + "wrong format", caller); return 0; } - _BT_HCI_MEMB(addr, dev) = dev; + straddr = PyBytes_AS_STRING(args); + if (setbdaddr(straddr, &_BT_HCI_MEMB(addr, bdaddr)) < 0) + return 0; #endif *len_ret = sizeof *addr; return 1; @@ -2739,7 +2760,7 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret) case BTPROTO_SCO: *len_ret = sizeof (struct sockaddr_sco); return 1; -#endif /* BTPROTO_HCI */ +#endif /* BTPROTO_SCO */ default: PyErr_SetString(PyExc_OSError, "getsockaddrlen: " "unknown BT protocol"); @@ -7845,20 +7866,22 @@ socket_exec(PyObject *m) ADD_INT_MACRO(m, AF_BLUETOOTH); #ifdef BTPROTO_L2CAP ADD_INT_MACRO(m, BTPROTO_L2CAP); +#if defined(BDADDR_BREDR) ADD_INT_MACRO(m, BDADDR_BREDR); ADD_INT_MACRO(m, BDADDR_LE_PUBLIC); ADD_INT_MACRO(m, BDADDR_LE_RANDOM); +#endif #endif /* BTPROTO_L2CAP */ #ifdef BTPROTO_HCI ADD_INT_MACRO(m, BTPROTO_HCI); ADD_INT_MACRO(m, SOL_HCI); -#if !defined(__NetBSD__) && !defined(__DragonFly__) +#if defined(HCI_FILTER) ADD_INT_MACRO(m, HCI_FILTER); -#if !defined(__FreeBSD__) +#endif +#if defined(HCI_TIME_STAMP) ADD_INT_MACRO(m, HCI_TIME_STAMP); ADD_INT_MACRO(m, HCI_DATA_DIR); -#endif /* !__FreeBSD__ */ -#endif /* !__NetBSD__ && !__DragonFly__ */ +#endif #endif /* BTPROTO_HCI */ #ifdef BTPROTO_RFCOMM ADD_INT_MACRO(m, BTPROTO_RFCOMM); diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h index e1d96377728eb9..63624d511c35a0 100644 --- a/Modules/socketmodule.h +++ b/Modules/socketmodule.h @@ -122,6 +122,9 @@ typedef int socklen_t; #endif #ifdef HAVE_BLUETOOTH_H +#ifdef __FreeBSD__ +#define L2CAP_SOCKET_CHECKED +#endif #include <bluetooth.h> #endif @@ -274,18 +277,22 @@ typedef union sock_addr { struct sockaddr_in6 in6; struct sockaddr_storage storage; #endif -#if defined(HAVE_BLUETOOTH_H) && defined(__FreeBSD__) - struct sockaddr_l2cap bt_l2; - struct sockaddr_rfcomm bt_rc; - struct sockaddr_sco bt_sco; - struct sockaddr_hci bt_hci; -#elif defined(HAVE_BLUETOOTH_BLUETOOTH_H) +#if defined(MS_WINDOWS) + struct SOCKADDR_BTH_REDEF bt_rc; +#elif defined(HAVE_BLUETOOTH_BLUETOOTH_H) // Linux struct sockaddr_l2 bt_l2; struct sockaddr_rc bt_rc; struct sockaddr_sco bt_sco; struct sockaddr_hci bt_hci; -#elif defined(MS_WINDOWS) - struct SOCKADDR_BTH_REDEF bt_rc; +#elif defined(HAVE_BLUETOOTH_H) +# if defined(__FreeBSD__) + struct sockaddr_l2cap bt_l2; + struct sockaddr_rfcomm bt_rc; + struct sockaddr_sco bt_sco; + struct sockaddr_hci bt_hci; +# else // NetBSD, DragonFly BSD + struct sockaddr_bt bt; +# endif #endif #ifdef HAVE_NETPACKET_PACKET_H struct sockaddr_ll ll; _______________________________________________ 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