[Python-checkins] cpython: Issue #15359: Add CAN_BCM protocol support to the socket module. Patch by Brian

charles-francois.natali python-checkins at python.org
Tue Feb 5 19:43:00 CET 2013


http://hg.python.org/cpython/rev/f714af60508d
changeset:   82024:f714af60508d
user:        Charles-François Natali <cf.natali at gmail.com>
date:        Tue Feb 05 19:42:01 2013 +0100
summary:
  Issue #15359: Add CAN_BCM protocol support to the socket module. Patch by Brian
Thorne.

files:
  Doc/library/socket.rst  |   32 +++++++-
  Lib/test/test_socket.py |  106 +++++++++++++++++++++++++--
  Misc/NEWS               |    3 +
  Modules/socketmodule.c  |   17 ++++
  Modules/socketmodule.h  |    4 +
  configure               |    2 +-
  configure.ac            |    2 +-
  pyconfig.h.in           |    3 +
  8 files changed, 151 insertions(+), 18 deletions(-)


diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -107,8 +107,8 @@
 
   .. 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 @@
 
    .. 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 @@
    :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 @@
    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
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -121,6 +121,36 @@
     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 @@
         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 @@
 
 
 @unittest.skipUnless(HAVE_SOCKET_CAN, 'SocketCan required for this test.')
- at 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 @@
         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):
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -235,6 +235,9 @@
 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
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -1598,6 +1598,8 @@
     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 @@
     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
--- a/Modules/socketmodule.h
+++ b/Modules/socketmodule.h
@@ -80,6 +80,10 @@
 #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
diff --git a/configure b/configure
--- a/configure
+++ b/configure
@@ -7224,7 +7224,7 @@
 
 
 # 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
--- a/configure.ac
+++ b/configure.ac
@@ -1568,7 +1568,7 @@
 ])
 
 # 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
--- 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
 

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list