-
-
Notifications
You must be signed in to change notification settings - Fork 30.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpo-30987 - Support for ISO-TP protocol in SocketCAN #2956
Changes from 11 commits
4d609c0
ccd65b8
0017156
85a1545
32399d4
fc058f8
2aa760d
fba09e6
17c58d7
7da8fed
1365fca
280141c
e2cc6f3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,6 +55,16 @@ def _have_socket_can(): | |
s.close() | ||
return True | ||
|
||
def _have_socket_can_isotp(): | ||
"""Check whether CAN ISOTP sockets are supported on this host.""" | ||
try: | ||
s = socket.socket(socket.PF_CAN, socket.SOCK_DGRAM, socket.CAN_ISOTP) | ||
except (AttributeError, OSError): | ||
return False | ||
else: | ||
s.close() | ||
return True | ||
|
||
def _have_socket_rds(): | ||
"""Check whether RDS sockets are supported on this host.""" | ||
try: | ||
|
@@ -77,6 +87,8 @@ def _have_socket_alg(): | |
|
||
HAVE_SOCKET_CAN = _have_socket_can() | ||
|
||
HAVE_SOCKET_CAN_ISOTP = _have_socket_can_isotp() | ||
|
||
HAVE_SOCKET_RDS = _have_socket_rds() | ||
|
||
HAVE_SOCKET_ALG = _have_socket_alg() | ||
|
@@ -1709,6 +1721,49 @@ def testBCM(self): | |
self.assertEqual(bytes_sent, len(header_plus_frame)) | ||
|
||
|
||
@unittest.skipUnless(HAVE_SOCKET_CAN_ISOTP, 'CAN ISOTP required for this test.') | ||
class ISOTPTest(unittest.TestCase): | ||
|
||
def __init__(self, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
self.interface = "vcan0" | ||
|
||
def testCrucialConstants(self): | ||
socket.AF_CAN | ||
socket.PF_CAN | ||
socket.CAN_ISOTP | ||
socket.SOCK_DGRAM | ||
|
||
def testCreateSocket(self): | ||
with socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW) as s: | ||
pass | ||
|
||
@unittest.skipUnless(hasattr(socket, "CAN_ISOTP"), | ||
'socket.CAN_ISOTP required for this test.') | ||
def testCreateISOTPSocket(self): | ||
with socket.socket(socket.PF_CAN, socket.SOCK_DGRAM, socket.CAN_ISOTP) as s: | ||
pass | ||
|
||
def testTooLongInterfaceName(self): | ||
# most systems limit IFNAMSIZ to 16, take 1024 to be sure | ||
with socket.socket(socket.PF_CAN, socket.SOCK_DGRAM, socket.CAN_ISOTP) as s: | ||
self.assertRaisesRegex(OSError, 'interface name too long', | ||
s.bind, ('x' * 1024,1,2)) | ||
|
||
def testBind(self): | ||
try: | ||
with socket.socket(socket.PF_CAN, socket.SOCK_DGRAM, socket.CAN_ISOTP) as s: | ||
addr = (self.interface,0x123,0x456) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Style nit pick: |
||
s.bind(addr) | ||
self.assertEqual(s.getsockname(), addr) | ||
except OSError as e: | ||
if e.errno == errno.ENODEV: | ||
self.skipTest('network interface `%s` does not exist' % | ||
self.interface) | ||
else: | ||
raise | ||
|
||
|
||
@unittest.skipUnless(HAVE_SOCKET_RDS, 'RDS sockets required for this test.') | ||
class BasicRDSTest(unittest.TestCase): | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
Added support for CAN ISO-TP protocol in the socket module. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1373,9 +1373,22 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto) | |
ifname = ifr.ifr_name; | ||
} | ||
|
||
return Py_BuildValue("O&h", PyUnicode_DecodeFSDefault, | ||
ifname, | ||
a->can_family); | ||
switch (proto) { | ||
#ifdef CAN_ISOTP | ||
case CAN_ISOTP: | ||
{ | ||
return Py_BuildValue("O&kk", PyUnicode_DecodeFSDefault, | ||
ifname, | ||
a->can_addr.tp.rx_id, | ||
a->can_addr.tp.tx_id); | ||
} | ||
#endif | ||
default: | ||
{ | ||
return Py_BuildValue("O&", PyUnicode_DecodeFSDefault, | ||
ifname); | ||
} | ||
} | ||
} | ||
#endif | ||
|
||
|
@@ -1869,7 +1882,9 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, | |
} | ||
#endif | ||
|
||
#if defined(AF_CAN) && defined(CAN_RAW) && defined(CAN_BCM) | ||
#if defined(AF_CAN) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use ifdef for simple checks: |
||
|
||
#if defined(CAN_RAW) && defined(CAN_BCM) | ||
case AF_CAN: | ||
switch (s->sock_proto) { | ||
case CAN_RAW: | ||
|
@@ -1880,7 +1895,6 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, | |
PyObject *interfaceName; | ||
struct ifreq ifr; | ||
Py_ssize_t len; | ||
|
||
addr = (struct sockaddr_can *)addr_ret; | ||
|
||
if (!PyArg_ParseTuple(args, "O&", PyUnicode_FSConverter, | ||
|
@@ -1913,6 +1927,54 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, | |
Py_DECREF(interfaceName); | ||
return 1; | ||
} | ||
#endif | ||
|
||
#if defined(CAN_ISOTP) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
case CAN_ISOTP: | ||
{ | ||
struct sockaddr_can *addr; | ||
PyObject *interfaceName; | ||
struct ifreq ifr; | ||
Py_ssize_t len; | ||
unsigned long int rx_id, tx_id; | ||
|
||
addr = (struct sockaddr_can *)addr_ret; | ||
|
||
if (!PyArg_ParseTuple(args, "O&kk", PyUnicode_FSConverter, | ||
&interfaceName, | ||
&rx_id, | ||
&tx_id)) | ||
return 0; | ||
|
||
len = PyBytes_GET_SIZE(interfaceName); | ||
|
||
if (len == 0) { | ||
ifr.ifr_ifindex = 0; | ||
} else if ((size_t)len < sizeof(ifr.ifr_name)) { | ||
strncpy(ifr.ifr_name, PyBytes_AS_STRING(interfaceName), sizeof(ifr.ifr_name)); | ||
ifr.ifr_name[(sizeof(ifr.ifr_name))-1] = '\0'; | ||
if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) { | ||
s->errorhandler(); | ||
Py_DECREF(interfaceName); | ||
return 0; | ||
} | ||
} else { | ||
PyErr_SetString(PyExc_OSError, | ||
"AF_CAN interface name too long"); | ||
Py_DECREF(interfaceName); | ||
return 0; | ||
} | ||
|
||
addr->can_family = AF_CAN; | ||
addr->can_ifindex = ifr.ifr_ifindex; | ||
addr->can_addr.tp.rx_id = rx_id; | ||
addr->can_addr.tp.tx_id = tx_id; | ||
|
||
*len_ret = sizeof(*addr); | ||
Py_DECREF(interfaceName); | ||
return 1; | ||
} | ||
#endif | ||
default: | ||
PyErr_SetString(PyExc_OSError, | ||
"getsockaddrarg: unsupported CAN protocol"); | ||
|
@@ -6993,6 +7055,8 @@ PyInit__socket(void) | |
PyModule_AddIntMacro(m, CAN_SFF_MASK); | ||
PyModule_AddIntMacro(m, CAN_EFF_MASK); | ||
PyModule_AddIntMacro(m, CAN_ERR_MASK); | ||
|
||
PyModule_AddIntMacro(m, CAN_ISOTP); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs a |
||
#endif | ||
#ifdef HAVE_LINUX_CAN_RAW_H | ||
PyModule_AddIntMacro(m, CAN_RAW_FILTER); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use
to make it more readable.