diff options
author | Charles-François Natali <cf.natali@gmail.com> | 2013-02-05 18:42:01 (GMT) |
---|---|---|
committer | Charles-François Natali <cf.natali@gmail.com> | 2013-02-05 18:42:01 (GMT) |
commit | 773e42dff813bb18cb25016ae1fe1ed0886fd484 (patch) | |
tree | d0a6331ff5cdd70f2d3e73ac851e626c8ebdb968 | |
parent | c44911f49aeb0cdb54f006f99111b562b29fc46f (diff) | |
download | cpython-773e42dff813bb18cb25016ae1fe1ed0886fd484.zip cpython-773e42dff813bb18cb25016ae1fe1ed0886fd484.tar.gz cpython-773e42dff813bb18cb25016ae1fe1ed0886fd484.tar.bz2 |
Issue #15359: Add CAN_BCM protocol support to the socket module. Patch by Brian
Thorne.
-rw-r--r-- | Doc/library/socket.rst | 32 | ||||
-rw-r--r-- | Lib/test/test_socket.py | 106 | ||||
-rw-r--r-- | Misc/NEWS | 3 | ||||
-rw-r--r-- | Modules/socketmodule.c | 17 | ||||
-rw-r--r-- | Modules/socketmodule.h | 4 | ||||
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | pyconfig.h.in | 3 |
8 files changed, 151 insertions, 18 deletions
diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 5737b40..5a6bc1d 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -107,8 +107,8 @@ created. Socket addresses are represented as follows: .. versionadded:: 3.3 -- Certain other address families (:const:`AF_BLUETOOTH`, :const:`AF_PACKET`) - support specific representations. +- Certain other address families (:const:`AF_BLUETOOTH`, :const:`AF_PACKET`, + :const:`AF_CAN`) support specific representations. .. XXX document them! @@ -257,6 +257,16 @@ The module :mod:`socket` exports the following constants and functions: .. versionadded:: 3.3 +.. data:: CAN_BCM + CAN_BCM_* + + CAN_BCM, in the CAN protocol family, is the broadcast manager (BCM) protocol. + Broadcast manager constants, documented in the Linux documentation, are also + defined in the socket module. + + Availability: Linux >= 2.6.25. + + .. versionadded:: 3.4 .. data:: AF_RDS PF_RDS @@ -452,13 +462,16 @@ The module :mod:`socket` exports the following constants and functions: :const:`AF_INET6`, :const:`AF_UNIX`, :const:`AF_CAN` or :const:`AF_RDS`. 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 :const:`CAN_RAW` in case the address family is :const:`AF_CAN`. + constants. The protocol number is usually zero and may be omitted or in the + case where the address family is :const:`AF_CAN` the protocol should be one + of :const:`CAN_RAW` or :const:`CAN_BCM`. .. versionchanged:: 3.3 The AF_CAN family was added. The AF_RDS family was added. + .. versionchanged:: 3.4 + The CAN_BCM protocol was added. .. function:: socketpair([family[, type[, proto]]]) @@ -1331,7 +1344,16 @@ the interface:: 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:: +network using the raw socket protocol. To use CAN with the broadcast +manager protocol instead, open a socket with:: + + socket.socket(socket.AF_CAN, socket.SOCK_DGRAM, socket.CAN_BCM) + +After binding (:const:`CAN_RAW`) or connecting (:const:`CAN_BCM`) the socket, you +can use the :method:`socket.send`, and the :method:`socket.recv` operations (and +their counterparts) on the socket object as usual. + +This example might require special priviledge:: import socket import struct diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 53ad35d..19377d0 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -121,6 +121,36 @@ class SocketCANTest(unittest.TestCase): interface = 'vcan0' bufsize = 128 + """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" + can_frame_size = struct.calcsize(can_frame_fmt) + + """The Broadcast Management Command frame structure is defined + in <linux/can/bcm.h>: + + struct bcm_msg_head { + __u32 opcode; + __u32 flags; + __u32 count; + struct timeval ival1, ival2; + canid_t can_id; + __u32 nframes; + struct can_frame frames[0]; + } + + `bcm_msg_head` must be 8 bytes aligned because of the `frames` member (see + `struct can_frame` definition). Must use native not standard types for packing. + """ + bcm_cmd_msg_fmt = "@3I4l2I" + bcm_cmd_msg_fmt += "x" * (struct.calcsize(bcm_cmd_msg_fmt) % 8) + def setUp(self): self.s = socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW) self.addCleanup(self.s.close) @@ -1291,10 +1321,35 @@ class BasicCANTest(unittest.TestCase): socket.PF_CAN socket.CAN_RAW + @unittest.skipUnless(hasattr(socket, "CAN_BCM"), + 'socket.CAN_BCM required for this test.') + def testBCMConstants(self): + socket.CAN_BCM + + # opcodes + socket.CAN_BCM_TX_SETUP # create (cyclic) transmission task + socket.CAN_BCM_TX_DELETE # remove (cyclic) transmission task + socket.CAN_BCM_TX_READ # read properties of (cyclic) transmission task + socket.CAN_BCM_TX_SEND # send one CAN frame + socket.CAN_BCM_RX_SETUP # create RX content filter subscription + socket.CAN_BCM_RX_DELETE # remove RX content filter subscription + socket.CAN_BCM_RX_READ # read properties of RX content filter subscription + socket.CAN_BCM_TX_STATUS # reply to TX_READ request + socket.CAN_BCM_TX_EXPIRED # notification on performed transmissions (count=0) + socket.CAN_BCM_RX_STATUS # reply to RX_READ request + socket.CAN_BCM_RX_TIMEOUT # cyclic message is absent + socket.CAN_BCM_RX_CHANGED # updated CAN frame (detected content change) + def testCreateSocket(self): with socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW) as s: pass + @unittest.skipUnless(hasattr(socket, "CAN_BCM"), + 'socket.CAN_BCM required for this test.') + def testCreateBCMSocket(self): + with socket.socket(socket.PF_CAN, socket.SOCK_DGRAM, socket.CAN_BCM) as s: + pass + def testBindAny(self): with socket.socket(socket.PF_CAN, socket.SOCK_RAW, socket.CAN_RAW) as s: s.bind(('', )) @@ -1327,19 +1382,8 @@ class BasicCANTest(unittest.TestCase): @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) @@ -1388,6 +1432,46 @@ class CANTest(ThreadedCANSocketTest): self.cf2 = self.build_can_frame(0x12, b'\x99\x22\x33') self.cli.send(self.cf2) + @unittest.skipUnless(hasattr(socket, "CAN_BCM"), + 'socket.CAN_BCM required for this test.') + def _testBCM(self): + cf, addr = self.cli.recvfrom(self.bufsize) + self.assertEqual(self.cf, cf) + can_id, can_dlc, data = self.dissect_can_frame(cf) + self.assertEqual(self.can_id, can_id) + self.assertEqual(self.data, data) + + @unittest.skipUnless(hasattr(socket, "CAN_BCM"), + 'socket.CAN_BCM required for this test.') + def testBCM(self): + bcm = socket.socket(socket.PF_CAN, socket.SOCK_DGRAM, socket.CAN_BCM) + self.addCleanup(bcm.close) + bcm.connect((self.interface,)) + self.can_id = 0x123 + self.data = bytes([0xc0, 0xff, 0xee]) + self.cf = self.build_can_frame(self.can_id, self.data) + opcode = socket.CAN_BCM_TX_SEND + flags = 0 + count = 0 + ival1_seconds = ival1_usec = ival2_seconds = ival2_usec = 0 + bcm_can_id = 0x0222 + nframes = 1 + assert len(self.cf) == 16 + header = struct.pack(self.bcm_cmd_msg_fmt, + opcode, + flags, + count, + ival1_seconds, + ival1_usec, + ival2_seconds, + ival2_usec, + bcm_can_id, + nframes, + ) + header_plus_frame = header + self.cf + bytes_sent = bcm.send(header_plus_frame) + self.assertEqual(bytes_sent, len(header_plus_frame)) + @unittest.skipUnless(HAVE_SOCKET_RDS, 'RDS sockets required for this test.') class BasicRDSTest(unittest.TestCase): @@ -235,6 +235,9 @@ Core and Builtins Library ------- +- Issue #15359: Add CAN_BCM protocol support to the socket module. Patch by + Brian Thorne. + - Issue #16948: Fix quoted printable body encoding for non-latin1 character sets in the email package. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 94793c9..f405130 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1598,6 +1598,8 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, case AF_CAN: switch (s->sock_proto) { case CAN_RAW: + /* fall-through */ + case CAN_BCM: { struct sockaddr_can *addr; PyObject *interfaceName; @@ -6031,6 +6033,21 @@ PyInit__socket(void) PyModule_AddIntConstant(m, "CAN_RAW_LOOPBACK", CAN_RAW_LOOPBACK); PyModule_AddIntConstant(m, "CAN_RAW_RECV_OWN_MSGS", CAN_RAW_RECV_OWN_MSGS); #endif +#ifdef HAVE_LINUX_CAN_BCM_H + PyModule_AddIntConstant(m, "CAN_BCM", CAN_BCM); + PyModule_AddIntConstant(m, "CAN_BCM_TX_SETUP", TX_SETUP); + PyModule_AddIntConstant(m, "CAN_BCM_TX_DELETE", TX_DELETE); + PyModule_AddIntConstant(m, "CAN_BCM_TX_READ", TX_READ); + PyModule_AddIntConstant(m, "CAN_BCM_TX_SEND", TX_SEND); + PyModule_AddIntConstant(m, "CAN_BCM_RX_SETUP", RX_SETUP); + PyModule_AddIntConstant(m, "CAN_BCM_RX_DELETE", RX_DELETE); + PyModule_AddIntConstant(m, "CAN_BCM_RX_READ", RX_READ); + PyModule_AddIntConstant(m, "CAN_BCM_TX_STATUS", TX_STATUS); + PyModule_AddIntConstant(m, "CAN_BCM_TX_EXPIRED", TX_EXPIRED); + PyModule_AddIntConstant(m, "CAN_BCM_RX_STATUS", RX_STATUS); + PyModule_AddIntConstant(m, "CAN_BCM_RX_TIMEOUT", RX_TIMEOUT); + PyModule_AddIntConstant(m, "CAN_BCM_RX_CHANGED", RX_CHANGED); +#endif #ifdef SOL_RDS PyModule_AddIntConstant(m, "SOL_RDS", SOL_RDS); #endif diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h index 48e0fd4..b83f9af 100644 --- a/Modules/socketmodule.h +++ b/Modules/socketmodule.h @@ -80,6 +80,10 @@ typedef int socklen_t; #include <linux/can/raw.h> #endif +#ifdef HAVE_LINUX_CAN_BCM_H +#include <linux/can/bcm.h> +#endif + #ifdef HAVE_SYS_SYS_DOMAIN_H #include <sys/sys_domain.h> #endif @@ -7224,7 +7224,7 @@ done # On Linux, can.h and can/raw.h require sys/socket.h -for ac_header in linux/can.h linux/can/raw.h +for ac_header in linux/can.h linux/can/raw.h linux/can/bcm.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" " diff --git a/configure.ac b/configure.ac index ec1abb4..34f19f3 100644 --- a/configure.ac +++ b/configure.ac @@ -1568,7 +1568,7 @@ AC_CHECK_HEADERS(linux/netlink.h,,,[ ]) # On Linux, can.h and can/raw.h require sys/socket.h -AC_CHECK_HEADERS(linux/can.h linux/can/raw.h,,,[ +AC_CHECK_HEADERS(linux/can.h linux/can/raw.h linux/can/bcm.h,,,[ #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif diff --git a/pyconfig.h.in b/pyconfig.h.in index 10e2c91..231146a 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -501,6 +501,9 @@ /* Define to 1 if you have the `linkat' function. */ #undef HAVE_LINKAT +/* Define to 1 if you have the <linux/can/bcm.h> header file. */ +#undef HAVE_LINUX_CAN_BCM_H + /* Define to 1 if you have the <linux/can.h> header file. */ #undef HAVE_LINUX_CAN_H |