diff options
-rw-r--r-- | Lib/test/test_socket.py | 55 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Windows/2019-04-10-21-13-26.bpo-36590.ZTaKcu.rst | 1 | ||||
-rwxr-xr-x[-rw-r--r--] | Modules/socketmodule.c | 65 | ||||
-rwxr-xr-x[-rw-r--r--] | Modules/socketmodule.h | 43 |
4 files changed, 158 insertions, 6 deletions
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 11b2a38..ce816cd 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -114,6 +114,19 @@ def _have_socket_vsock(): return ret +def _have_socket_bluetooth(): + """Check whether AF_BLUETOOTH sockets are supported on this host.""" + try: + # RFCOMM is supported by all platforms with bluetooth support. Windows + # does not support omitting the protocol. + s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM) + except (AttributeError, OSError): + return False + else: + s.close() + return True + + @contextlib.contextmanager def socket_setdefaulttimeout(timeout): old_timeout = socket.getdefaulttimeout() @@ -138,6 +151,8 @@ HAVE_SOCKET_VSOCK = _have_socket_vsock() HAVE_SOCKET_UDPLITE = hasattr(socket, "IPPROTO_UDPLITE") +HAVE_SOCKET_BLUETOOTH = _have_socket_bluetooth() + # Size in bytes of the int type SIZEOF_INT = array.array("i").itemsize @@ -2257,6 +2272,45 @@ class BasicVSOCKTest(unittest.TestCase): socket.SO_VM_SOCKETS_BUFFER_MIN_SIZE)) +@unittest.skipUnless(HAVE_SOCKET_BLUETOOTH, + 'Bluetooth sockets required for this test.') +class BasicBluetoothTest(unittest.TestCase): + + def testBluetoothConstants(self): + socket.BDADDR_ANY + socket.BDADDR_LOCAL + socket.AF_BLUETOOTH + socket.BTPROTO_RFCOMM + + if sys.platform != "win32": + socket.BTPROTO_HCI + socket.SOL_HCI + socket.BTPROTO_L2CAP + + if not sys.platform.startswith("freebsd"): + socket.BTPROTO_SCO + + def testCreateRfcommSocket(self): + with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM) as s: + pass + + @unittest.skipIf(sys.platform == "win32", "windows does not support L2CAP sockets") + def testCreateL2capSocket(self): + with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_L2CAP) as s: + pass + + @unittest.skipIf(sys.platform == "win32", "windows does not support HCI sockets") + def testCreateHciSocket(self): + with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) as s: + pass + + @unittest.skipIf(sys.platform == "win32" or sys.platform.startswith("freebsd"), + "windows and freebsd do not support SCO sockets") + def testCreateScoSocket(self): + with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_SCO) as s: + pass + + class BasicTCPTest(SocketConnectedTest): def __init__(self, methodName='runTest'): @@ -6416,6 +6470,7 @@ def test_main(): BasicVSOCKTest, ThreadedVSOCKSocketStreamTest, ]) + tests.append(BasicBluetoothTest) tests.extend([ CmsgMacroTests, SendmsgUDPTest, diff --git a/Misc/NEWS.d/next/Windows/2019-04-10-21-13-26.bpo-36590.ZTaKcu.rst b/Misc/NEWS.d/next/Windows/2019-04-10-21-13-26.bpo-36590.ZTaKcu.rst new file mode 100644 index 0000000..6a186bb --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2019-04-10-21-13-26.bpo-36590.ZTaKcu.rst @@ -0,0 +1 @@ +Add native Bluetooth RFCOMM support to socket module.
\ No newline at end of file diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 99e350b..f220c26 100644..100755 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -520,6 +520,15 @@ remove_unusable_flags(PyObject *m) #endif #endif +#ifdef MS_WINDOWS +#define sockaddr_rc SOCKADDR_BTH_REDEF + +#define USE_BLUETOOTH 1 +#define AF_BLUETOOTH AF_BTH +#define BTPROTO_RFCOMM BTHPROTO_RFCOMM +#define _BT_RC_MEMB(sa, memb) ((sa)->memb) +#endif + /* Convert "sock_addr_t *" to "struct sockaddr *". */ #define SAS2SA(x) (&((x)->sa)) @@ -1256,12 +1265,23 @@ setbdaddr(const char *name, bdaddr_t *bdaddr) n = sscanf(name, "%X:%X:%X:%X:%X:%X%c", &b5, &b4, &b3, &b2, &b1, &b0, &ch); if (n == 6 && (b0 | b1 | b2 | b3 | b4 | b5) < 256) { + +#ifdef MS_WINDOWS + *bdaddr = (ULONGLONG)(b0 & 0xFF); + *bdaddr |= ((ULONGLONG)(b1 & 0xFF) << 8); + *bdaddr |= ((ULONGLONG)(b2 & 0xFF) << 16); + *bdaddr |= ((ULONGLONG)(b3 & 0xFF) << 24); + *bdaddr |= ((ULONGLONG)(b4 & 0xFF) << 32); + *bdaddr |= ((ULONGLONG)(b5 & 0xFF) << 40); +#else bdaddr->b[0] = b0; bdaddr->b[1] = b1; bdaddr->b[2] = b2; bdaddr->b[3] = b3; bdaddr->b[4] = b4; bdaddr->b[5] = b5; +#endif + return 6; } else { PyErr_SetString(PyExc_OSError, "bad bluetooth address"); @@ -1278,9 +1298,23 @@ makebdaddr(bdaddr_t *bdaddr) { char buf[(6 * 2) + 5 + 1]; +#ifdef MS_WINDOWS + int i; + unsigned int octets[6]; + + for (i = 0; i < 6; ++i) { + octets[i] = ((*bdaddr) >> (8 * i)) & 0xFF; + } + + sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + octets[5], octets[4], octets[3], + octets[2], octets[1], octets[0]); +#else sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]); +#endif + return PyUnicode_FromString(buf); } #endif @@ -1378,6 +1412,7 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto) case AF_BLUETOOTH: switch (proto) { +#ifdef BTPROTO_L2CAP case BTPROTO_L2CAP: { struct sockaddr_l2 *a = (struct sockaddr_l2 *) addr; @@ -1392,6 +1427,8 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto) return ret; } +#endif /* BTPROTO_L2CAP */ + case BTPROTO_RFCOMM: { struct sockaddr_rc *a = (struct sockaddr_rc *) addr; @@ -1406,6 +1443,7 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto) return ret; } +#ifdef BTPROTO_HCI case BTPROTO_HCI: { struct sockaddr_hci *a = (struct sockaddr_hci *) addr; @@ -1425,6 +1463,7 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto) return makebdaddr(&_BT_SCO_MEMB(a, bdaddr)); } #endif /* !__FreeBSD__ */ +#endif /* BTPROTO_HCI */ default: PyErr_SetString(PyExc_ValueError, @@ -1879,6 +1918,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, case AF_BLUETOOTH: { switch (s->sock_proto) { +#ifdef BTPROTO_L2CAP case BTPROTO_L2CAP: { struct sockaddr_l2 *addr; @@ -1899,6 +1939,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, *len_ret = sizeof *addr; return 1; } +#endif /* BTPROTO_L2CAP */ case BTPROTO_RFCOMM: { struct sockaddr_rc *addr; @@ -1918,6 +1959,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, *len_ret = sizeof *addr; return 1; } +#ifdef BTPROTO_HCI case BTPROTO_HCI: { struct sockaddr_hci *addr = (struct sockaddr_hci *)addr_ret; @@ -1964,6 +2006,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, return 1; } #endif /* !__FreeBSD__ */ +#endif /* BTPROTO_HCI */ default: PyErr_Format(PyExc_OSError, "%s(): unknown Bluetooth protocol", caller); @@ -2385,12 +2428,15 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret) switch(s->sock_proto) { +#ifdef BTPROTO_L2CAP case BTPROTO_L2CAP: *len_ret = sizeof (struct sockaddr_l2); return 1; +#endif /* BTPROTO_L2CAP */ case BTPROTO_RFCOMM: *len_ret = sizeof (struct sockaddr_rc); return 1; +#ifdef BTPROTO_HCI case BTPROTO_HCI: *len_ret = sizeof (struct sockaddr_hci); return 1; @@ -2399,6 +2445,7 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret) *len_ret = sizeof (struct sockaddr_sco); return 1; #endif /* !__FreeBSD__ */ +#endif /* BTPROTO_HCI */ default: PyErr_SetString(PyExc_OSError, "getsockaddrlen: " "unknown BT protocol"); @@ -7273,23 +7320,29 @@ PyInit__socket(void) #ifdef USE_BLUETOOTH PyModule_AddIntMacro(m, AF_BLUETOOTH); +#ifdef BTPROTO_L2CAP PyModule_AddIntMacro(m, BTPROTO_L2CAP); +#endif /* BTPROTO_L2CAP */ +#ifdef BTPROTO_HCI PyModule_AddIntMacro(m, BTPROTO_HCI); PyModule_AddIntMacro(m, SOL_HCI); #if !defined(__NetBSD__) && !defined(__DragonFly__) PyModule_AddIntMacro(m, HCI_FILTER); -#endif #if !defined(__FreeBSD__) -#if !defined(__NetBSD__) && !defined(__DragonFly__) PyModule_AddIntMacro(m, HCI_TIME_STAMP); -#endif PyModule_AddIntMacro(m, HCI_DATA_DIR); - PyModule_AddIntMacro(m, BTPROTO_SCO); -#endif +#endif /* !__FreeBSD__ */ +#endif /* !__NetBSD__ && !__DragonFly__ */ +#endif /* BTPROTO_HCI */ +#ifdef BTPROTO_RFCOMM PyModule_AddIntMacro(m, BTPROTO_RFCOMM); +#endif /* BTPROTO_RFCOMM */ PyModule_AddStringConstant(m, "BDADDR_ANY", "00:00:00:00:00:00"); PyModule_AddStringConstant(m, "BDADDR_LOCAL", "00:00:00:FF:FF:FF"); -#endif +#ifdef BTPROTO_SCO + PyModule_AddIntMacro(m, BTPROTO_SCO); +#endif /* BTPROTO_SCO */ +#endif /* USE_BLUETOOTH */ #ifdef AF_CAN /* Controller Area Network */ diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h index dff1f8f..3d95fe7 100644..100755 --- a/Modules/socketmodule.h +++ b/Modules/socketmodule.h @@ -14,6 +14,47 @@ #else /* MS_WINDOWS */ # include <winsock2.h> + +/* + * If Windows has bluetooth support, include bluetooth constants. + */ +#ifdef AF_BTH +# include <ws2bth.h> +# include <pshpack1.h> + +/* + * The current implementation assumes the bdaddr in the sockaddr structs + * will be a bdaddr_t. We treat this as an opaque type: on *nix systems, it + * will be a struct with a single member (an array of six bytes). On windows, + * we typedef this to ULONGLONG to match the Windows definition. + */ +typedef ULONGLONG bdaddr_t; + +/* + * Redefine SOCKADDR_BTH to provide names compatible with _BT_RC_MEMB() macros. + */ +struct SOCKADDR_BTH_REDEF { + union { + USHORT addressFamily; + USHORT family; + }; + + union { + ULONGLONG btAddr; + bdaddr_t bdaddr; + }; + + GUID serviceClassId; + + union { + ULONG port; + ULONG channel; + }; + +}; +# include <poppack.h> +#endif + /* Windows 'supports' CMSG_LEN, but does not follow the POSIX standard * interface at all, so there is no point including the code that * attempts to use it. @@ -199,6 +240,8 @@ typedef union sock_addr { 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; #endif #ifdef HAVE_NETPACKET_PACKET_H struct sockaddr_ll ll; |