Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions Lib/test/test_socket.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -138,6 +151,8 @@ def socket_setdefaulttimeout(timeout):

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

Expand Down Expand Up @@ -2244,6 +2259,45 @@ def testSocketBufferSize(self):
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'):
Expand Down Expand Up @@ -6395,6 +6449,7 @@ def test_main():
BasicVSOCKTest,
ThreadedVSOCKSocketStreamTest,
])
tests.append(BasicBluetoothTest)
tests.extend([
CmsgMacroTests,
SendmsgUDPTest,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add native Bluetooth RFCOMM support to socket module.
65 changes: 59 additions & 6 deletions Modules/socketmodule.c
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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))

Expand Down Expand Up @@ -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");
Expand All @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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");
Expand Down Expand Up @@ -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 */
Expand Down
43 changes: 43 additions & 0 deletions Modules/socketmodule.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down