Issue #10141: socket: add SocketCAN (PF_CAN) support. Initial patch by Matthias
Fuchs, updated by Tiago Gonçalves.
This commit is contained in:
parent
90c30e87be
commit
47413c1171
|
@ -80,6 +80,11 @@ Socket addresses are represented as follows:
|
||||||
If *addr_type* is TIPC_ADDR_ID, then *v1* is the node, *v2* is the
|
If *addr_type* is TIPC_ADDR_ID, then *v1* is the node, *v2* is the
|
||||||
reference, and *v3* should be set to 0.
|
reference, and *v3* should be set to 0.
|
||||||
|
|
||||||
|
- A tuple ``(interface, )`` is used for the :const:`AF_CAN` address family,
|
||||||
|
where *interface* is a string representing a network interface name like
|
||||||
|
``'can0'``. The network interface name ``''`` can be used to receive packets
|
||||||
|
from all network interfaces of this family.
|
||||||
|
|
||||||
- Certain other address families (:const:`AF_BLUETOOTH`, :const:`AF_PACKET`)
|
- Certain other address families (:const:`AF_BLUETOOTH`, :const:`AF_PACKET`)
|
||||||
support specific representations.
|
support specific representations.
|
||||||
|
|
||||||
|
@ -216,6 +221,19 @@ The module :mod:`socket` exports the following constants and functions:
|
||||||
in the Unix header files are defined; for a few symbols, default values are
|
in the Unix header files are defined; for a few symbols, default values are
|
||||||
provided.
|
provided.
|
||||||
|
|
||||||
|
.. data:: AF_CAN
|
||||||
|
PF_CAN
|
||||||
|
SOL_CAN_*
|
||||||
|
CAN_*
|
||||||
|
|
||||||
|
Many constants of these forms, documented in the Linux documentation, are
|
||||||
|
also defined in the socket module.
|
||||||
|
|
||||||
|
Availability: Linux >= 2.6.25.
|
||||||
|
|
||||||
|
.. versionadded:: 3.3
|
||||||
|
|
||||||
|
|
||||||
.. data:: SIO_*
|
.. data:: SIO_*
|
||||||
RCVALL_*
|
RCVALL_*
|
||||||
|
|
||||||
|
@ -387,10 +405,14 @@ The module :mod:`socket` exports the following constants and functions:
|
||||||
|
|
||||||
Create a new socket using the given address family, socket type and protocol
|
Create a new socket using the given address family, socket type and protocol
|
||||||
number. The address family should be :const:`AF_INET` (the default),
|
number. The address family should be :const:`AF_INET` (the default),
|
||||||
:const:`AF_INET6` or :const:`AF_UNIX`. The socket type should be
|
:const:`AF_INET6`, :const:`AF_UNIX` or :const:`AF_CAN`. The socket type
|
||||||
:const:`SOCK_STREAM` (the default), :const:`SOCK_DGRAM` or perhaps one of the
|
should be :const:`SOCK_STREAM` (the default), :const:`SOCK_DGRAM`,
|
||||||
other ``SOCK_`` constants. The protocol number is usually zero and may be
|
:const:`SOCK_RAW` or perhaps one of the other ``SOCK_`` constants. The
|
||||||
omitted in that case.
|
protocol number is usually zero and may be omitted in that case or
|
||||||
|
:const:`CAN_RAW` in case the address family is :const:`AF_CAN`.
|
||||||
|
|
||||||
|
.. versionchanged:: 3.3
|
||||||
|
The AF_CAN family was added.
|
||||||
|
|
||||||
|
|
||||||
.. function:: socketpair([family[, type[, proto]]])
|
.. function:: socketpair([family[, type[, proto]]])
|
||||||
|
@ -1213,7 +1235,7 @@ sends traffic to the first one connected successfully. ::
|
||||||
print('Received', repr(data))
|
print('Received', repr(data))
|
||||||
|
|
||||||
|
|
||||||
The last example shows how to write a very simple network sniffer with raw
|
The next example shows how to write a very simple network sniffer with raw
|
||||||
sockets on Windows. The example requires administrator privileges to modify
|
sockets on Windows. The example requires administrator privileges to modify
|
||||||
the interface::
|
the interface::
|
||||||
|
|
||||||
|
@ -1238,6 +1260,45 @@ the interface::
|
||||||
# disabled promiscuous mode
|
# disabled promiscuous mode
|
||||||
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
|
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
|
||||||
|
|
||||||
|
The last example shows how to use the socket interface to communicate to a CAN
|
||||||
|
network. This example might require special priviledge::
|
||||||
|
|
||||||
|
import socket
|
||||||
|
import struct
|
||||||
|
|
||||||
|
|
||||||
|
# CAN frame packing/unpacking (see `struct can_frame` in <linux/can.h>)
|
||||||
|
|
||||||
|
can_frame_fmt = "=IB3x8s"
|
||||||
|
|
||||||
|
def build_can_frame(can_id, data):
|
||||||
|
can_dlc = len(data)
|
||||||
|
data = data.ljust(8, b'\x00')
|
||||||
|
return struct.pack(can_frame_fmt, can_id, can_dlc, data)
|
||||||
|
|
||||||
|
def dissect_can_frame(frame):
|
||||||
|
can_id, can_dlc, data = struct.unpack(can_frame_fmt, frame)
|
||||||
|
return (can_id, can_dlc, data[:can_dlc])
|
||||||
|
|
||||||
|
|
||||||
|
# create a raw socket and bind it to the `vcan0` interface
|
||||||
|
s = socket.socket(socket.AF_CAN, socket.SOCK_RAW, socket.CAN_RAW)
|
||||||
|
s.bind(('vcan0',))
|
||||||
|
|
||||||
|
while True:
|
||||||
|
cf, addr = s.recvfrom(16)
|
||||||
|
|
||||||
|
print('Received: can_id=%x, can_dlc=%x, data=%s' % dissect_can_frame(cf))
|
||||||
|
|
||||||
|
try:
|
||||||
|
s.send(cf)
|
||||||
|
except socket.error:
|
||||||
|
print('Error sending CAN frame')
|
||||||
|
|
||||||
|
try:
|
||||||
|
s.send(build_can_frame(0x01, b'\x01\x02\x03'))
|
||||||
|
except socket.error:
|
||||||
|
print('Error sending CAN frame')
|
||||||
|
|
||||||
Running an example several times with too small delay between executions, could
|
Running an example several times with too small delay between executions, could
|
||||||
lead to this error::
|
lead to this error::
|
||||||
|
|
|
@ -300,15 +300,22 @@ signal
|
||||||
socket
|
socket
|
||||||
------
|
------
|
||||||
|
|
||||||
The :class:`~socket.socket` class now exposes addititonal methods to
|
* The :class:`~socket.socket` class now exposes additional methods to process
|
||||||
process ancillary data when supported by the underlying platform:
|
ancillary data when supported by the underlying platform:
|
||||||
|
|
||||||
* :func:`~socket.socket.sendmsg`
|
* :func:`~socket.socket.sendmsg`
|
||||||
* :func:`~socket.socket.recvmsg`
|
* :func:`~socket.socket.recvmsg`
|
||||||
* :func:`~socket.socket.recvmsg_into`
|
* :func:`~socket.socket.recvmsg_into`
|
||||||
|
|
||||||
|
(Contributed by David Watson in :issue:`6560`, based on an earlier patch by
|
||||||
|
Heiko Wundram)
|
||||||
|
|
||||||
|
* The :class:`~socket.socket` class now supports the PF_CAN protocol family
|
||||||
|
(http://en.wikipedia.org/wiki/Socketcan), on Linux
|
||||||
|
(http://lwn.net/Articles/253425).
|
||||||
|
|
||||||
|
(Contributed by Matthias Fuchs, updated by Tiago Gonçalves in :issue:`10141`)
|
||||||
|
|
||||||
(Contributed by David Watson in :issue:`6560`, based on an earlier patch
|
|
||||||
by Heiko Wundram)
|
|
||||||
|
|
||||||
ssl
|
ssl
|
||||||
---
|
---
|
||||||
|
|
|
@ -21,6 +21,7 @@ from weakref import proxy
|
||||||
import signal
|
import signal
|
||||||
import math
|
import math
|
||||||
import pickle
|
import pickle
|
||||||
|
import struct
|
||||||
try:
|
try:
|
||||||
import fcntl
|
import fcntl
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
@ -36,6 +37,18 @@ except ImportError:
|
||||||
thread = None
|
thread = None
|
||||||
threading = None
|
threading = None
|
||||||
|
|
||||||
|
def _have_socket_can():
|
||||||
|
"""Check whether CAN sockets are supported on this host."""
|
||||||
|
try:
|
||||||
|
s = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW)
|
||||||
|
except (AttributeError, socket.error, OSError):
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
s.close()
|
||||||
|
return True
|
||||||
|
|
||||||
|
HAVE_SOCKET_CAN = _have_socket_can()
|
||||||
|
|
||||||
# Size in bytes of the int type
|
# Size in bytes of the int type
|
||||||
SIZEOF_INT = array.array("i").itemsize
|
SIZEOF_INT = array.array("i").itemsize
|
||||||
|
|
||||||
|
@ -80,6 +93,30 @@ class ThreadSafeCleanupTestCase(unittest.TestCase):
|
||||||
with self._cleanup_lock:
|
with self._cleanup_lock:
|
||||||
return super().doCleanups(*args, **kwargs)
|
return super().doCleanups(*args, **kwargs)
|
||||||
|
|
||||||
|
class SocketCANTest(unittest.TestCase):
|
||||||
|
|
||||||
|
"""To be able to run this test, a `vcan0` CAN interface can be created with
|
||||||
|
the following commands:
|
||||||
|
# modprobe vcan
|
||||||
|
# ip link add dev vcan0 type vcan
|
||||||
|
# ifconfig vcan0 up
|
||||||
|
"""
|
||||||
|
interface = 'vcan0'
|
||||||
|
bufsize = 128
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.s = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW)
|
||||||
|
try:
|
||||||
|
self.s.bind((self.interface,))
|
||||||
|
except socket.error:
|
||||||
|
self.skipTest('network interface `%s` does not exist' %
|
||||||
|
self.interface)
|
||||||
|
self.s.close()
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.s.close()
|
||||||
|
self.s = None
|
||||||
|
|
||||||
class ThreadableTest:
|
class ThreadableTest:
|
||||||
"""Threadable Test class
|
"""Threadable Test class
|
||||||
|
|
||||||
|
@ -210,6 +247,26 @@ class ThreadedUDPSocketTest(SocketUDPTest, ThreadableTest):
|
||||||
self.cli = None
|
self.cli = None
|
||||||
ThreadableTest.clientTearDown(self)
|
ThreadableTest.clientTearDown(self)
|
||||||
|
|
||||||
|
class ThreadedCANSocketTest(SocketCANTest, ThreadableTest):
|
||||||
|
|
||||||
|
def __init__(self, methodName='runTest'):
|
||||||
|
SocketCANTest.__init__(self, methodName=methodName)
|
||||||
|
ThreadableTest.__init__(self)
|
||||||
|
|
||||||
|
def clientSetUp(self):
|
||||||
|
self.cli = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW)
|
||||||
|
try:
|
||||||
|
self.cli.bind((self.interface,))
|
||||||
|
except socket.error:
|
||||||
|
self.skipTest('network interface `%s` does not exist' %
|
||||||
|
self.interface)
|
||||||
|
self.cli.close()
|
||||||
|
|
||||||
|
def clientTearDown(self):
|
||||||
|
self.cli.close()
|
||||||
|
self.cli = None
|
||||||
|
ThreadableTest.clientTearDown(self)
|
||||||
|
|
||||||
class SocketConnectedTest(ThreadedTCPSocketTest):
|
class SocketConnectedTest(ThreadedTCPSocketTest):
|
||||||
"""Socket tests for client-server connection.
|
"""Socket tests for client-server connection.
|
||||||
|
|
||||||
|
@ -1072,6 +1129,112 @@ class GeneralModuleTests(unittest.TestCase):
|
||||||
srv.close()
|
srv.close()
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(HAVE_SOCKET_CAN, 'SocketCan required for this test.')
|
||||||
|
class BasicCANTest(unittest.TestCase):
|
||||||
|
|
||||||
|
def testCrucialConstants(self):
|
||||||
|
socket.AF_CAN
|
||||||
|
socket.PF_CAN
|
||||||
|
socket.CAN_RAW
|
||||||
|
|
||||||
|
def testCreateSocket(self):
|
||||||
|
with socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW) as s:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def testBindAny(self):
|
||||||
|
with socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW) as s:
|
||||||
|
s.bind(('', ))
|
||||||
|
|
||||||
|
def testTooLongInterfaceName(self):
|
||||||
|
# most systems limit IFNAMSIZ to 16, take 1024 to be sure
|
||||||
|
with socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW) as s:
|
||||||
|
self.assertRaisesRegexp(socket.error, 'interface name too long',
|
||||||
|
s.bind, ('x' * 1024,))
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(socket, "CAN_RAW_LOOPBACK"),
|
||||||
|
'socket.CAN_RAW_LOOPBACK required for this test.')
|
||||||
|
def testLoopback(self):
|
||||||
|
with socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW) as s:
|
||||||
|
for loopback in (0, 1):
|
||||||
|
s.setsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_LOOPBACK,
|
||||||
|
loopback)
|
||||||
|
self.assertEqual(loopback,
|
||||||
|
s.getsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_LOOPBACK))
|
||||||
|
|
||||||
|
@unittest.skipUnless(hasattr(socket, "CAN_RAW_FILTER"),
|
||||||
|
'socket.CAN_RAW_FILTER required for this test.')
|
||||||
|
def testFilter(self):
|
||||||
|
can_id, can_mask = 0x200, 0x700
|
||||||
|
can_filter = struct.pack("=II", can_id, can_mask)
|
||||||
|
with socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW) as s:
|
||||||
|
s.setsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_FILTER, can_filter)
|
||||||
|
self.assertEqual(can_filter,
|
||||||
|
s.getsockopt(socket.SOL_CAN_RAW, socket.CAN_RAW_FILTER, 8))
|
||||||
|
|
||||||
|
|
||||||
|
@unittest.skipUnless(HAVE_SOCKET_CAN, 'SocketCan required for this test.')
|
||||||
|
@unittest.skipUnless(thread, 'Threading required for this test.')
|
||||||
|
class CANTest(ThreadedCANSocketTest):
|
||||||
|
|
||||||
|
"""The CAN frame structure is defined in <linux/can.h>:
|
||||||
|
|
||||||
|
struct can_frame {
|
||||||
|
canid_t can_id; /* 32 bit CAN_ID + EFF/RTR/ERR flags */
|
||||||
|
__u8 can_dlc; /* data length code: 0 .. 8 */
|
||||||
|
__u8 data[8] __attribute__((aligned(8)));
|
||||||
|
};
|
||||||
|
"""
|
||||||
|
can_frame_fmt = "=IB3x8s"
|
||||||
|
|
||||||
|
def __init__(self, methodName='runTest'):
|
||||||
|
ThreadedCANSocketTest.__init__(self, methodName=methodName)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def build_can_frame(cls, can_id, data):
|
||||||
|
"""Build a CAN frame."""
|
||||||
|
can_dlc = len(data)
|
||||||
|
data = data.ljust(8, b'\x00')
|
||||||
|
return struct.pack(cls.can_frame_fmt, can_id, can_dlc, data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def dissect_can_frame(cls, frame):
|
||||||
|
"""Dissect a CAN frame."""
|
||||||
|
can_id, can_dlc, data = struct.unpack(cls.can_frame_fmt, frame)
|
||||||
|
return (can_id, can_dlc, data[:can_dlc])
|
||||||
|
|
||||||
|
def testSendFrame(self):
|
||||||
|
cf, addr = self.s.recvfrom(self.bufsize)
|
||||||
|
self.assertEqual(self.cf, cf)
|
||||||
|
self.assertEqual(addr[0], self.interface)
|
||||||
|
self.assertEqual(addr[1], socket.AF_CAN)
|
||||||
|
|
||||||
|
def _testSendFrame(self):
|
||||||
|
self.cf = self.build_can_frame(0x00, b'\x01\x02\x03\x04\x05')
|
||||||
|
self.cli.send(self.cf)
|
||||||
|
|
||||||
|
def testSendMaxFrame(self):
|
||||||
|
cf, addr = self.s.recvfrom(self.bufsize)
|
||||||
|
self.assertEqual(self.cf, cf)
|
||||||
|
|
||||||
|
def _testSendMaxFrame(self):
|
||||||
|
self.cf = self.build_can_frame(0x00, b'\x07' * 8)
|
||||||
|
self.cli.send(self.cf)
|
||||||
|
|
||||||
|
def testSendMultiFrames(self):
|
||||||
|
cf, addr = self.s.recvfrom(self.bufsize)
|
||||||
|
self.assertEqual(self.cf1, cf)
|
||||||
|
|
||||||
|
cf, addr = self.s.recvfrom(self.bufsize)
|
||||||
|
self.assertEqual(self.cf2, cf)
|
||||||
|
|
||||||
|
def _testSendMultiFrames(self):
|
||||||
|
self.cf1 = self.build_can_frame(0x07, b'\x44\x33\x22\x11')
|
||||||
|
self.cli.send(self.cf1)
|
||||||
|
|
||||||
|
self.cf2 = self.build_can_frame(0x12, b'\x99\x22\x33')
|
||||||
|
self.cli.send(self.cf2)
|
||||||
|
|
||||||
|
|
||||||
@unittest.skipUnless(thread, 'Threading required for this test.')
|
@unittest.skipUnless(thread, 'Threading required for this test.')
|
||||||
class BasicTCPTest(SocketConnectedTest):
|
class BasicTCPTest(SocketConnectedTest):
|
||||||
|
|
||||||
|
@ -4194,6 +4357,7 @@ def test_main():
|
||||||
if isTipcAvailable():
|
if isTipcAvailable():
|
||||||
tests.append(TIPCTest)
|
tests.append(TIPCTest)
|
||||||
tests.append(TIPCThreadableTest)
|
tests.append(TIPCThreadableTest)
|
||||||
|
tests.extend([BasicCANTest, CANTest])
|
||||||
tests.extend([
|
tests.extend([
|
||||||
CmsgMacroTests,
|
CmsgMacroTests,
|
||||||
SendmsgUDPTest,
|
SendmsgUDPTest,
|
||||||
|
|
|
@ -319,6 +319,7 @@ John Fouhy
|
||||||
Martin Franklin
|
Martin Franklin
|
||||||
Robin Friedrich
|
Robin Friedrich
|
||||||
Ivan Frohne
|
Ivan Frohne
|
||||||
|
Matthias Fuchs
|
||||||
Jim Fulton
|
Jim Fulton
|
||||||
Tadayoshi Funaba
|
Tadayoshi Funaba
|
||||||
Gyro Funch
|
Gyro Funch
|
||||||
|
@ -354,6 +355,7 @@ Michael Gilfix
|
||||||
Yannick Gingras
|
Yannick Gingras
|
||||||
Christoph Gohlke
|
Christoph Gohlke
|
||||||
Tim Golden
|
Tim Golden
|
||||||
|
Tiago Gonçalves
|
||||||
Chris Gonnerman
|
Chris Gonnerman
|
||||||
David Goodger
|
David Goodger
|
||||||
Hans de Graaff
|
Hans de Graaff
|
||||||
|
|
|
@ -1322,6 +1322,9 @@ Tools/Demos
|
||||||
Extension Modules
|
Extension Modules
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #10141: socket: Add SocketCAN (PF_CAN) support. Initial patch by
|
||||||
|
Matthias Fuchs, updated by Tiago Gonçalves.
|
||||||
|
|
||||||
- Issue #13070: Fix a crash when a TextIOWrapper caught in a reference cycle
|
- Issue #13070: Fix a crash when a TextIOWrapper caught in a reference cycle
|
||||||
would be finalized after the reference to its underlying BufferedRWPair's
|
would be finalized after the reference to its underlying BufferedRWPair's
|
||||||
writer got cleared by the GC.
|
writer got cleared by the GC.
|
||||||
|
|
|
@ -1220,6 +1220,25 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LINUX_CAN_H
|
||||||
|
case AF_CAN:
|
||||||
|
{
|
||||||
|
struct sockaddr_can *a = (struct sockaddr_can *)addr;
|
||||||
|
char *ifname = "";
|
||||||
|
struct ifreq ifr;
|
||||||
|
/* need to look up interface name given index */
|
||||||
|
if (a->can_ifindex) {
|
||||||
|
ifr.ifr_ifindex = a->can_ifindex;
|
||||||
|
if (ioctl(sockfd, SIOCGIFNAME, &ifr) == 0)
|
||||||
|
ifname = ifr.ifr_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Py_BuildValue("O&h", PyUnicode_DecodeFSDefault,
|
||||||
|
ifname,
|
||||||
|
a->can_family);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* More cases here... */
|
/* More cases here... */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1587,6 +1606,53 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LINUX_CAN_H
|
||||||
|
case AF_CAN:
|
||||||
|
switch (s->sock_proto) {
|
||||||
|
case CAN_RAW:
|
||||||
|
{
|
||||||
|
struct sockaddr_can *addr;
|
||||||
|
PyObject *interfaceName;
|
||||||
|
struct ifreq ifr;
|
||||||
|
addr = (struct sockaddr_can *)addr_ret;
|
||||||
|
Py_ssize_t len;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "O&", PyUnicode_FSConverter,
|
||||||
|
&interfaceName))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
len = PyBytes_GET_SIZE(interfaceName);
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
ifr.ifr_ifindex = 0;
|
||||||
|
} else if (len < sizeof(ifr.ifr_name)) {
|
||||||
|
strcpy(ifr.ifr_name, PyBytes_AS_STRING(interfaceName));
|
||||||
|
if (ioctl(s->sock_fd, SIOCGIFINDEX, &ifr) < 0) {
|
||||||
|
s->errorhandler();
|
||||||
|
Py_DECREF(interfaceName);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PyErr_SetString(socket_error,
|
||||||
|
"AF_CAN interface name too long");
|
||||||
|
Py_DECREF(interfaceName);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
addr->can_family = AF_CAN;
|
||||||
|
addr->can_ifindex = ifr.ifr_ifindex;
|
||||||
|
|
||||||
|
*len_ret = sizeof(*addr);
|
||||||
|
Py_DECREF(interfaceName);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
PyErr_SetString(socket_error,
|
||||||
|
"getsockaddrarg: unsupported CAN protocol");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* More cases here... */
|
/* More cases here... */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1680,6 +1746,14 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LINUX_CAN_H
|
||||||
|
case AF_CAN:
|
||||||
|
{
|
||||||
|
*len_ret = sizeof (struct sockaddr_can);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* More cases here... */
|
/* More cases here... */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -5533,6 +5607,15 @@ PyInit__socket(void)
|
||||||
PyModule_AddStringConstant(m, "BDADDR_LOCAL", "00:00:00:FF:FF:FF");
|
PyModule_AddStringConstant(m, "BDADDR_LOCAL", "00:00:00:FF:FF:FF");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef AF_CAN
|
||||||
|
/* Controller Area Network */
|
||||||
|
PyModule_AddIntConstant(m, "AF_CAN", AF_CAN);
|
||||||
|
#endif
|
||||||
|
#ifdef PF_CAN
|
||||||
|
/* Controller Area Network */
|
||||||
|
PyModule_AddIntConstant(m, "PF_CAN", PF_CAN);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef AF_PACKET
|
#ifdef AF_PACKET
|
||||||
PyModule_AddIntMacro(m, AF_PACKET);
|
PyModule_AddIntMacro(m, AF_PACKET);
|
||||||
#endif
|
#endif
|
||||||
|
@ -5803,6 +5886,28 @@ PyInit__socket(void)
|
||||||
#else
|
#else
|
||||||
PyModule_AddIntConstant(m, "SOL_UDP", 17);
|
PyModule_AddIntConstant(m, "SOL_UDP", 17);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef SOL_CAN_BASE
|
||||||
|
PyModule_AddIntConstant(m, "SOL_CAN_BASE", SOL_CAN_BASE);
|
||||||
|
#endif
|
||||||
|
#ifdef SOL_CAN_RAW
|
||||||
|
PyModule_AddIntConstant(m, "SOL_CAN_RAW", SOL_CAN_RAW);
|
||||||
|
PyModule_AddIntConstant(m, "CAN_RAW", CAN_RAW);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_LINUX_CAN_H
|
||||||
|
PyModule_AddIntConstant(m, "CAN_EFF_FLAG", CAN_EFF_FLAG);
|
||||||
|
PyModule_AddIntConstant(m, "CAN_RTR_FLAG", CAN_RTR_FLAG);
|
||||||
|
PyModule_AddIntConstant(m, "CAN_ERR_FLAG", CAN_ERR_FLAG);
|
||||||
|
|
||||||
|
PyModule_AddIntConstant(m, "CAN_SFF_MASK", CAN_SFF_MASK);
|
||||||
|
PyModule_AddIntConstant(m, "CAN_EFF_MASK", CAN_EFF_MASK);
|
||||||
|
PyModule_AddIntConstant(m, "CAN_ERR_MASK", CAN_ERR_MASK);
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_LINUX_CAN_RAW_H
|
||||||
|
PyModule_AddIntConstant(m, "CAN_RAW_FILTER", CAN_RAW_FILTER);
|
||||||
|
PyModule_AddIntConstant(m, "CAN_RAW_ERR_FILTER", CAN_RAW_ERR_FILTER);
|
||||||
|
PyModule_AddIntConstant(m, "CAN_RAW_LOOPBACK", CAN_RAW_LOOPBACK);
|
||||||
|
PyModule_AddIntConstant(m, "CAN_RAW_RECV_OWN_MSGS", CAN_RAW_RECV_OWN_MSGS);
|
||||||
|
#endif
|
||||||
#ifdef IPPROTO_IP
|
#ifdef IPPROTO_IP
|
||||||
PyModule_AddIntConstant(m, "IPPROTO_IP", IPPROTO_IP);
|
PyModule_AddIntConstant(m, "IPPROTO_IP", IPPROTO_IP);
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -72,6 +72,14 @@ typedef int socklen_t;
|
||||||
# include <linux/tipc.h>
|
# include <linux/tipc.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LINUX_CAN_H
|
||||||
|
#include <linux/can.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LINUX_CAN_RAW_H
|
||||||
|
#include <linux/can/raw.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef Py__SOCKET_H
|
#ifndef Py__SOCKET_H
|
||||||
#define Py__SOCKET_H
|
#define Py__SOCKET_H
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -126,6 +134,9 @@ typedef union sock_addr {
|
||||||
#ifdef HAVE_NETPACKET_PACKET_H
|
#ifdef HAVE_NETPACKET_PACKET_H
|
||||||
struct sockaddr_ll ll;
|
struct sockaddr_ll ll;
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef HAVE_LINUX_CAN_H
|
||||||
|
struct sockaddr_can can;
|
||||||
|
#endif
|
||||||
} sock_addr_t;
|
} sock_addr_t;
|
||||||
|
|
||||||
/* The object holding a socket. It holds some extra information,
|
/* The object holding a socket. It holds some extra information,
|
||||||
|
|
|
@ -1376,6 +1376,13 @@ AC_CHECK_HEADERS(linux/netlink.h,,,[
|
||||||
#endif
|
#endif
|
||||||
])
|
])
|
||||||
|
|
||||||
|
# On Linux, can.h and can/raw.h require sys/socket.h
|
||||||
|
AC_CHECK_HEADERS(linux/can.h linux/can/raw.h,,,[
|
||||||
|
#ifdef HAVE_SYS_SOCKET_H
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#endif
|
||||||
|
])
|
||||||
|
|
||||||
# checks for typedefs
|
# checks for typedefs
|
||||||
was_it_defined=no
|
was_it_defined=no
|
||||||
AC_MSG_CHECKING(for clock_t in time.h)
|
AC_MSG_CHECKING(for clock_t in time.h)
|
||||||
|
|
|
@ -467,6 +467,12 @@
|
||||||
/* Define to 1 if you have the `linkat' function. */
|
/* Define to 1 if you have the `linkat' function. */
|
||||||
#undef HAVE_LINKAT
|
#undef HAVE_LINKAT
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <linux/can.h> header file. */
|
||||||
|
#undef HAVE_LINUX_CAN_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <linux/can/raw.h> header file. */
|
||||||
|
#undef HAVE_LINUX_CAN_RAW_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <linux/netlink.h> header file. */
|
/* Define to 1 if you have the <linux/netlink.h> header file. */
|
||||||
#undef HAVE_LINUX_NETLINK_H
|
#undef HAVE_LINUX_NETLINK_H
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue