8000 bpo-36590: Add Bluetooth RFCOMM and support for Windows. (GH-12767) · python/cpython@8fbece1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8fbece1

Browse files
topnotcherzooba
authored andcommitted
bpo-36590: Add Bluetooth RFCOMM and support for Windows. (GH-12767)
Support for RFCOMM, L2CAP, HCI, SCO is based on the BTPROTO_* macros being defined. Winsock only supports RFCOMM, even though it has a BTHPROTO_L2CAP macro. L2CAP support would build on windows, but not necessarily work. This also adds some basic unittests for constants (all of which existed prior to this commit, just not on windows) and creating sockets. pair: Nate Duarte <slacknate@gmail.com>
1 parent cb65b3a commit 8fbece1

File tree

4 files changed

+158
-6
lines changed

4 files changed

+158
-6
lines changed

Lib/test/test_socket.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,19 @@ def _have_socket_vsock():
114114
return ret
115115

116116

117+
def _have_socket_bluetooth():
118+
"""Check whether AF_BLUETOOTH sockets are supported on this host."""
119+
try:
120+
# RFCOMM is supported by all platforms with bluetooth support. Windows
121+
# does not support omitting the protocol.
122+
s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM)
123+
except (AttributeError, OSError):
124+
return False
125+
else:
126+
s.close()
127+
return True
128+
129+
117130
@contextlib.contextmanager
118131
def socket_setdefaulttimeout(timeout):
119132
old_timeout = socket.getdefaulttimeout()
@@ -138,6 +151,8 @@ def socket_setdefaulttimeout(timeout):
138151

139152
HAVE_SOCKET_UDPLITE = hasattr(socket, "IPPROTO_UDPLITE")
140153

154+
HAVE_SOCKET_BLUETOOTH = _have_socket_bluetooth()
155+
141156
# Size in bytes of the int type
142157
SIZEOF_INT = array.array("i").itemsize
143158

@@ -2257,6 +2272,45 @@ def testSocketBufferSize(self):
22572272
socket.SO_VM_SOCKETS_BUFFER_MIN_SIZE))
22582273

22592274

2275+
@unittest.skipUnless(HAVE_SOCKET_BLUETOOTH,
2276+
'Bluetooth sockets required for this test.')
2277+
class BasicBluetoothTest(unittest.TestCase):
2278+
2279+
def testBluetoothConstants(self):
2280+
socket.BDADDR_ANY
2281+
socket.BDADDR_LOCAL
2282+
socket.AF_BLUETOOTH
2283+
socket.BTPROTO_RFCOMM
2284+
2285+
if sys.platform != "win32":
2286+
socket.BTPROTO_HCI
2287+
socket.SOL_HCI
2288+
socket.BTPROTO_L2CAP
2289+
2290+
if not sys.platform.startswith("freebsd"):
2291+
socket.BTPROTO_SCO
2292+
2293+
def testCreateRfcommSocket(self):
2294+
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_RFCOMM) as s:
2295+
pass
2296+
2297+
@unittest.skipIf(sys.platform == "win32", "windows does not support L2CAP sockets")
2298+
def testCreateL2capSocket(self):
2299+
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_L2CAP) as s:
2300+
pass
2301+
2302+
@unittest.skipIf(sys.platform == "win32", "windows does not support HCI sockets")
2303+
def testCreateHciSocket(self):
2304+
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) as s:
2305+
pass
2306+
2307+
@unittest.skipIf(sys.platform == "win32" or sys.platform.startswith("freebsd"),
2308+
"windows and freebsd do not support SCO sockets")
2309+
def testCreateScoSocket(self):
2310+
with socket.socket(socket.AF_BLUETOOTH, socket.SOCK_SEQPACKET, socket.BTPROTO_SCO) as s:
2311+
pass
2312+
2313+
22602314
class BasicTCPTest(SocketConnectedTest):
22612315

22622316
def __init__(self, methodName='runTest'):
@@ -6416,6 +6470,7 @@ def test_main():
64166470
BasicVSOCKTest,
64176471
ThreadedVSOCKSocketStreamTest,
64186472
])
6473+
tests.append(BasicBluetoothTest)
64196474
tests.extend([
64206475
CmsgMacroTests,
64216476
SendmsgUDPTest,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add native Bluetooth RFCOMM support to socket module.

Modules/socketmodule.c

100644100755
Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,15 @@ remove_unusable_flags(PyObject *m)
520520
#endif
521521
#endif
522522

523+
#ifdef MS_WINDOWS
524+
#define sockaddr_rc SOCKADDR_BTH_REDEF
525+
526+
#define USE_BLUETOOTH 1
527+
#define AF_BLUETOOTH AF_BTH
528+
#define BTPROTO_RFCOMM BTHPROTO_RFCOMM
529+
#define _BT_RC_MEMB(sa, memb) ((sa)->memb)
530+
#endif
531+
523532
/* Convert "sock_addr_t *" to "struct sockaddr *". */
524533
#define SAS2SA(x) (&((x)->sa))
525534

@@ -1256,12 +1265,23 @@ setbdaddr(const char *name, bdaddr_t *bdaddr)
12561265
n = sscanf(name, "%X:%X:%X:%X:%X:%X%c",
12571266
&b5, &b4, &b3, &b2, &b1, &b0, &ch);
12581267
if (n == 6 && (b0 | b1 | b2 | b3 | b4 | b5) < 256) {
1268+
1269+
#ifdef MS_WINDOWS
1270+
*bdaddr = (ULONGLONG)(b0 & 0xFF);
1271+
*bdaddr |= ((ULONGLONG)(b1 & 0xFF) << 8);
1272+
*bdaddr |= ((ULONGLONG)(b2 & 0xFF) << 16);
1273+
*bdaddr |= ((ULONGLONG)(b3 & 0xFF) << 24);
1274+
*bdaddr |= ((ULONGLONG)(b4 & 0xFF) << 32);
1275+
*bdaddr |= ((ULONGLONG)(b5 & 0xFF) << 40);
1276+
#else
12591277
bdaddr->b[0] = b0;
12601278
bdaddr->b[1] = b1;
12611279
bdaddr->b[2] = b2;
12621280
bdaddr->b[3] = b3;
12631281
bdaddr->b[4] = b4;
12641282
bdaddr->b[5] = b5;
1283+
#endif
1284+
12651285
return 6;
12661286
} else {
12671287
PyErr_SetString(PyExc_OSError, "bad bluetooth address");
@@ -1278,9 +1298,23 @@ makebdaddr(bdaddr_t *bdaddr)
12781298
{
12791299
char buf[(6 * 2) + 5 + 1];
12801300

1301+
#ifdef MS_WINDOWS
1302+
int i;
1303+
unsigned int octets[6];
1304+
1305+
for (i = 0; i < 6; ++i) {
1306+
octets[i] = ((*bdaddr) >> (8 * i)) & 0xFF;
1307+
}
1308+
1309+
sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
1310+
octets[5], octets[4], octets[3],
1311+
octets[2], octets[1], octets[0]);
1312+
#else
12811313
sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
12821314
bdaddr->b[5], bdaddr->b[4], bdaddr->b[3],
12831315
bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]);
1316+
#endif
1317+
12841318
return PyUnicode_FromString(buf);
12851319
}
12861320
#endif
@@ -1378,6 +1412,7 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
13781412
case AF_BLUETOOTH:
13791413
switch (proto) {
13801414

1415+
#ifdef BTPROTO_L2CAP
13811416
case BTPROTO_L2CAP:
13821417
{
13831418
struct sockaddr_l2 *a = (struct sockaddr_l2 *) addr;
@@ -1392,6 +1427,8 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
13921427
return ret;
13931428
}
13941429

1430+
#endif /* BTPROTO_L2CAP */
1431+
13951432
case BTPROTO_RFCOMM:
13961433
{
13971434
struct sockaddr_rc *a = (struct sockaddr_rc *) addr;
@@ -1406,6 +1443,7 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
14061443
return ret;
14071444
}
14081445

1446+
#ifdef BTPROTO_HCI
14091447
case BTPROTO_HCI:
14101448
{
14111449
struct sockaddr_hci *a = (struct sockaddr_hci *) addr;
@@ -1425,6 +1463,7 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
14251463
return makebdaddr(&_BT_SCO_MEMB(a, bdaddr));
14261464
}
14271465
#endif /* !__FreeBSD__ */
1466+
#endif /* BTPROTO_HCI */
14281467

14291468
default:
14301469
PyErr_SetString(PyExc_ValueError,
@@ -1879,6 +1918,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
18791918
case AF_BLUETOOTH:
18801919
{
18811920
switch (s->sock_proto) {
1921+
#ifdef BTPROTO_L2CAP
18821922
case BTPROTO_L2CAP:
18831923
{
18841924
struct sockaddr_l2 *addr;
@@ -1899,6 +1939,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
18991939
*len_ret = sizeof *addr;
19001940
return 1;
19011941
}
1942+
#endif /* BTPROTO_L2CAP */
19021943
case BTPROTO_RFCOMM:
19031944
{
19041945
struct sockaddr_rc *addr;
@@ -1918,6 +1959,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
19181959
*len_ret = sizeof *addr;
19191960
return 1;
19201961
}
1962+
#ifdef BTPROTO_HCI
19211963
case BTPROTO_HCI:
19221964
{
19231965
struct sockaddr_hci *addr = (struct sockaddr_hci *)addr_ret;
@@ -1964,6 +2006,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
19642006
return 1;
19652007
}
19662008
#endif /* !__FreeBSD__ */
2009+
#endif /* BTPROTO_HCI */
19672010
default:
19682011
PyErr_Format(PyExc_OSError,
19692012
"%s(): unknown Bluetooth protocol", caller);
@@ -2385,12 +2428,15 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
23852428
switch(s->sock_proto)
23862429
{
23872430

2431+
#ifdef BTPROTO_L2CAP
23882432
case BTPROTO_L2CAP:
23892433
*len_ret = sizeof (struct sockaddr_l2);
23902434
return 1;
2435+
#endif /* BTPROTO_L2CAP */
23912436
case BTPROTO_RFCOMM:
23922437
*len_ret = sizeof (struct sockaddr_rc);
23932438
return 1;
2439+
#ifdef BTPROTO_HCI
23942440
case BTPROTO_HCI:
23952441
*len_ret = sizeof (struct sockaddr_hci);
23962442
return 1;
@@ -2399,6 +2445,7 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
23992445
*len_ret = sizeof (struct sockaddr_sco);
24002446
return 1;
24012447
#endif /* !__FreeBSD__ */
2448+
#endif /* BTPROTO_HCI */
24022449
default:
24032450
PyErr_SetString(PyExc_OSError, "getsockaddrlen: "
24042451
"unknown BT protocol");
@@ -7273,23 +7320,29 @@ PyInit__socket(void)
72737320

72747321
#ifdef USE_BLUETOOTH
72757322
PyModule_AddIntMacro(m, AF_BLUETOOTH);
7323+
#ifdef BTPROTO_L2CAP
72767324
PyModule_AddIntMacro(m, BTPROTO_L2CAP);
7325+
#endif /* BTPROTO_L2CAP */
7326+
#ifdef BTPROTO_HCI
72777327
PyModule_AddIntMacro(m, BTPROTO_HCI);
72787328
PyModule_AddIntMacro(m, SOL_HCI);
72797329
#if !defined(__NetBSD__) && !defined(__DragonFly__)
72807330
PyModule_AddIntMacro(m, HCI_FILTER);
7281-
#endif
72827331
#if !defined(__FreeBSD__)
7283-
#if !defined(__NetBSD__) && !defined(__DragonFly__)
72847332
PyModule_AddIntMacro(m, HCI_TIME_STAMP);
7285-
#endif
72867333
PyModule_AddIntMacro(m, HCI_DATA_DIR);
7287-
PyModule_AddIntMacro(m, BTPROTO_SCO);
7288-
#endif
7334+
#endif /* !__FreeBSD__ */
7335+
#endif /* !__NetBSD__ && !__DragonFly__ */
7336+
#endif /* BTPROTO_HCI */
7337+
#ifdef BTPROTO_RFCOMM
72897338
PyModule_AddIntMacro(m, BTPROTO_RFCOMM);
7339+
#endif /* BTPROTO_RFCOMM */
72907340
PyModule_AddStringConstant(m, "BDADDR_ANY", "00:00:00:00:00:00");
72917341
PyModule_AddStringConstant(m, "BDADDR_LOCAL", "00:00:00:FF:FF:FF");
7292-
#endif
7342+
#ifdef BTPROTO_SCO
7343+
PyModule_AddIntMacro(m, BTPROTO_SCO);
7344+
#endif /* BTPROTO_SCO */
7345+
#endif /* USE_BLUETOOTH */
72937346

72947347
#ifdef AF_CAN
72957348
/* Controller Area Network */

10000 Modules/socketmodule.h

100644100755
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,47 @@
1414

1515
#else /* MS_WINDOWS */
1616
# include <winsock2.h>
17+
18+
/*
19+
* If Windows has bluetooth support, include bluetooth constants.
20+
*/
21+
#ifdef AF_BTH
22+
# include <ws2bth.h>
23+
# include <pshpack1.h>
24+
25+
/*
26+
* The current implementation assumes the bdaddr in the sockaddr structs
27+
* will be a bdaddr_t. We treat this as an opaque type: on *nix systems, it
28+
* will be a struct with a single member (an array of six bytes). On windows,
29+
* we typedef this to ULONGLONG to match the Windows definition.
30+
*/
31+
typedef ULONGLONG bdaddr_t;
32+
33+
/*
34+
* Redefine SOCKADDR_BTH to provide names compatible with _BT_RC_MEMB() macros.
35+
*/
36+
struct SOCKADDR_BTH_REDEF {
37+
union {
38+
USHORT addressFamily;
39+
USHORT family;
40+
};
41+
42+
union {
43+
ULONGLONG btAddr;
44+
bdaddr_t bdaddr;
45+
};
46+
47+
GUID serviceClassId;
48+
49+
union {
50+
ULONG port;
51+
ULONG channel;
52+
};
53+
54+
};
< 8956 code>55+
# include <poppack.h>
56+
#endif
57+
1758
/* Windows 'supports' CMSG_LEN, but does not follow the POSIX standard
1859
* interface at all, so there is no point including the code that
1960
* attempts to use it.
@@ -199,6 +240,8 @@ typedef union sock_addr {
199240
struct sockaddr_rc bt_rc;
200241
struct sockaddr_sco bt_sco;
201242
struct sockaddr_hci bt_hci;
243+
#elif defined(MS_WINDOWS)
244+
struct SOCKADDR_BTH_REDEF bt_rc;
202245
#endif
203246
#ifdef HAVE_NETPACKET_PACKET_H
204247
struct sockaddr_ll ll;

0 commit comments

Comments
 (0)
0