diff -r 7af576e3cb0c Doc/library/socket.rst --- a/Doc/library/socket.rst Mon Aug 01 17:31:12 2011 +0200 +++ b/Doc/library/socket.rst Mon Aug 01 21:44:43 2011 +0100 @@ -80,6 +80,11 @@ If *addr_type* is TIPC_ADDR_ID, then *v1* is the node, *v2* is the 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`) support specific representations. @@ -215,6 +220,14 @@ in the Unix header files are defined; for a few symbols, default values are 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. + .. data:: SIO_* RCVALL_* @@ -386,10 +399,10 @@ Create a new socket using the given address family, socket type and protocol number. The address family should be :const:`AF_INET` (the default), - :const:`AF_INET6` or :const:`AF_UNIX`. The socket type should be - :const:`SOCK_STREAM` (the default), :const:`SOCK_DGRAM` or perhaps one of the - other ``SOCK_`` constants. The protocol number is usually zero and may be - omitted in that case. + :const:`AF_INET6`, :const:`AF_UNIX` or :const:`AF_CAN`. The socket type should be + :const:`SOCK_STREAM` (the default), :const:`SOCK_DGRAM`, :const:`SOCK_RAW` or + perhaps one of the other ``SOCK_`` constants. The protocol number is usually zero + and may be omitted in that case or `CAN_RAW` in case the address familiy is `AF_CAN`. .. function:: socketpair([family[, type[, proto]]]) @@ -1031,7 +1044,7 @@ 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 the interface:: @@ -1056,6 +1069,27 @@ # disabled promiscuous mode 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 + + # create a raw socket and bind it to the `can0` interface + s = socket.socket(socket.AF_CAN, socket.SOCK_RAW, socket.CAN_RAW) + s.bind(('can0',)) + + while True: + cf, addr = s.recvfrom(16) + + try: + s.send(cf) + except socket.error: + print('Error sending CAN frame') + + try: + s.send(b'\x00\x00\x00\x00\x08\x00\x00\x00\x11\x22\x33\x44\x55\x66\x77\x88') + except socket.error: + print('Error sending CAN frame') .. seealso:: diff -r 7af576e3cb0c Lib/test/test_socket.py --- a/Lib/test/test_socket.py Mon Aug 01 17:31:12 2011 +0200 +++ b/Lib/test/test_socket.py Mon Aug 01 21:44:43 2011 +0100 @@ -55,6 +55,19 @@ self.serv.close() self.serv = None +class SocketCANTest(unittest.TestCase): + + def setUp(self): + self.s = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW) + try: + self.s.bind(("vcan0",)) + except socket.error: + self.skipTest('network interface `vcan0` does not exists') + + def tearDown(self): + self.s.close() + self.s = None + class ThreadableTest: """Threadable Test class @@ -136,8 +149,8 @@ def clientRun(self, test_func): self.server_ready.wait() + self.clientSetUp() self.client_ready.set() - self.clientSetUp() if not hasattr(test_func, '__call__'): raise TypeError("test_func must be a callable function") try: @@ -182,6 +195,22 @@ self.cli = None 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(("vcan0",)) + except socket.error: + self.skipTest('network interface `vcan0` does not exists') + def clientTearDown(self): + self.cli.close() + self.cli = None + ThreadableTest.clientTearDown(self) + class SocketConnectedTest(ThreadedTCPSocketTest): """Socket tests for client-server connection. @@ -947,6 +976,61 @@ def _testRecvFromNegative(self): self.cli.sendto(MSG, 0, (HOST, self.port)) +def isSocketCANAvailable(): + """Check if the CAN.ko and the VCAN.ko modules are loaded + + The CAN.ko module is usually loaded if the Linux kernel was compiled with + socketCAN support. The VCAN.ko module usually needs to be loaded manually. + """ + if not hasattr(socket, "PF_CAN"): + if support.verbose: + print("Linux socketCAN specific'") + return False + + if not os.path.isfile("/proc/modules"): + return False + is_loaded_can_module = False + is_loaded_vcan_module = False + with open("/proc/modules") as f: + for line in f: + if line.startswith("can "): + is_loaded_can_module = True + if line.startswith("vcan "): + is_loaded_vcan_module = True + + if not is_loaded_can_module: + if support.verbose: + print("can.ko module is not loaded, please 'sudo modprobe can'") + return False + + if not is_loaded_vcan_module: + if support.verbose: + print("vcan.ko module is not loaded, please 'sudo modprobe vcan'") + return False + + return True + +@unittest.skipUnless(thread, 'Threading required for this test.') +class BasicCANTest(ThreadedCANSocketTest): + def __init__(self, methodName='runTest'): + ThreadedCANSocketTest.__init__(self, methodName=methodName) + + def testSendCF(self): + self.cf = b'\x00\x00\x00\x00\x08\x00\x00\x00\x11\x22\x33\x44\x55\x66\x77\x88' + self.s.send(self.cf) + + def _testSendCF(self): + cf, addr = self.cli.recvfrom(16) + self.assertEqual(self.cf, cf) + + def testCrucialConstants(self): + socket.AF_CAN + socket.PF_CAN + socket.CAN_RAW + + def _testCrucialConstants(self): + pass + @unittest.skipUnless(thread, 'Threading required for this test.') class TCPCloserTest(ThreadedTCPSocketTest): @@ -2079,6 +2163,8 @@ if isTipcAvailable(): tests.append(TIPCTest) tests.append(TIPCThreadableTest) + if sys.platform == 'linux2' and isSocketCANAvailable(): + tests.append(BasicCANTest) thread_info = support.threading_setup() support.run_unittest(*tests) diff -r 7af576e3cb0c Modules/socketmodule.c --- a/Modules/socketmodule.c Mon Aug 01 17:31:12 2011 +0200 +++ b/Modules/socketmodule.c Mon Aug 01 21:44:43 2011 +0100 @@ -1208,6 +1208,23 @@ } #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 give 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... */ default: @@ -1575,6 +1592,44 @@ } #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; + + if (!PyArg_ParseTuple(args, "O&", PyUnicode_FSConverter, &interfaceName)) + return 0; + + if (!strcmp(PyBytes_AS_STRING(interfaceName), "")) { + ifr.ifr_ifindex = 0; + } else { + 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; + } + } + + 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... */ default: @@ -1668,6 +1723,14 @@ } #endif +#ifdef HAVE_LINUX_CAN_H + case AF_CAN: + { + *len_ret = sizeof (struct sockaddr_can); + return 1; + } +#endif + /* More cases here... */ default: @@ -4778,6 +4841,15 @@ PyModule_AddStringConstant(m, "BDADDR_LOCAL", "00:00:00:FF:FF:FF"); #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 PyModule_AddIntMacro(m, AF_PACKET); #endif @@ -5001,6 +5073,28 @@ #else PyModule_AddIntConstant(m, "SOL_UDP", 17); #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 PyModule_AddIntConstant(m, "IPPROTO_IP", IPPROTO_IP); #else diff -r 7af576e3cb0c Modules/socketmodule.h --- a/Modules/socketmodule.h Mon Aug 01 17:31:12 2011 +0200 +++ b/Modules/socketmodule.h Mon Aug 01 21:44:43 2011 +0100 @@ -72,6 +72,14 @@ # include #endif +#ifdef HAVE_LINUX_CAN_H +#include +#endif + +#ifdef HAVE_LINUX_CAN_RAW_H +#include +#endif + #ifndef Py__SOCKET_H #define Py__SOCKET_H #ifdef __cplusplus @@ -126,6 +134,9 @@ #ifdef HAVE_NETPACKET_PACKET_H struct sockaddr_ll ll; #endif +#ifdef HAVE_LINUX_CAN_H + struct sockaddr_can can; +#endif } sock_addr_t; /* The object holding a socket. It holds some extra information, diff -r 7af576e3cb0c configure.in --- a/configure.in Mon Aug 01 17:31:12 2011 +0200 +++ b/configure.in Mon Aug 01 21:44:43 2011 +0100 @@ -1347,6 +1347,13 @@ #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 +#endif +]) + # checks for typedefs was_it_defined=no AC_MSG_CHECKING(for clock_t in time.h)