]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-31425: Expose AF_QIPCRTR in socket module (GH-3706)
authorBjorn Andersson <bjorn@kryo.se>
Wed, 26 Sep 2018 13:47:52 +0000 (06:47 -0700)
committerTal Einat <taleinat+github@gmail.com>
Wed, 26 Sep 2018 13:47:52 +0000 (16:47 +0300)
The AF_QIPCRTR address family was introduced in Linux v4.7.

Co-authored-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Doc/library/socket.rst
Lib/test/test_socket.py
Misc/NEWS.d/next/Library/2017-10-24-10-18-35.bpo-31425.1lgw47.rst [new file with mode: 0644]
Modules/socketmodule.c
Modules/socketmodule.h
configure
configure.ac
pyconfig.h.in

index 32e7c5e6c079894695e093ab6fd347cdb35c7298..44370fef35c396848573bef9aea0505a02cc8a57 100644 (file)
@@ -193,6 +193,13 @@ created.  Socket addresses are represented as follows:
   - *addr* - Optional bytes-like object specifying the hardware physical
     address, whose interpretation depends on the device.
 
+- :const:`AF_QIPCRTR` is a Linux-only socket based interface for communicating
+  with services running on co-processors in Qualcomm platforms. The address
+  family is represented as a ``(node, port)`` tuple where the *node* and *port*
+  are non-negative integers.
+
+  .. versionadded:: 3.7
+
 If you use a hostname in the *host* portion of IPv4/v6 socket address, the
 program may show a nondeterministic behavior, as Python uses the first address
 returned from the DNS resolution.  The socket address will be resolved
@@ -481,6 +488,13 @@ Constants
    :const:`HCI_DATA_DIR` are not available for FreeBSD, NetBSD, or
    DragonFlyBSD.
 
+.. data:: AF_QIPCRTR
+
+   Constant for Qualcomm's IPC router protocol, used to communicate with
+   service providing remote processors.
+
+   Availability: Linux >= 4.7.
+
 Functions
 ^^^^^^^^^
 
index bd4fad1f638043234d8ae6c0cb337c5fd4156f64..bbbf27b60978ebe80c846fbb9826f718b955064d 100644 (file)
@@ -94,6 +94,16 @@ def _have_socket_alg():
         s.close()
     return True
 
+def _have_socket_qipcrtr():
+    """Check whether AF_QIPCRTR sockets are supported on this host."""
+    try:
+        s = socket.socket(socket.AF_QIPCRTR, socket.SOCK_DGRAM, 0)
+    except (AttributeError, OSError):
+        return False
+    else:
+        s.close()
+    return True
+
 def _have_socket_vsock():
     """Check whether AF_VSOCK sockets are supported on this host."""
     ret = get_cid() is not None
@@ -113,6 +123,8 @@ HAVE_SOCKET_RDS = _have_socket_rds()
 
 HAVE_SOCKET_ALG = _have_socket_alg()
 
+HAVE_SOCKET_QIPCRTR = _have_socket_qipcrtr()
+
 HAVE_SOCKET_VSOCK = _have_socket_vsock()
 
 # Size in bytes of the int type
@@ -2054,6 +2066,34 @@ class RDSTest(ThreadedRDSSocketTest):
         self.data = b'select'
         self.cli.sendto(self.data, 0, (HOST, self.port))
 
+@unittest.skipUnless(HAVE_SOCKET_QIPCRTR,
+          'QIPCRTR sockets required for this test.')
+class BasicQIPCRTRTest(unittest.TestCase):
+
+    def testCrucialConstants(self):
+        socket.AF_QIPCRTR
+
+    def testCreateSocket(self):
+        with socket.socket(socket.AF_QIPCRTR, socket.SOCK_DGRAM) as s:
+            pass
+
+    def testUnbound(self):
+        with socket.socket(socket.AF_QIPCRTR, socket.SOCK_DGRAM) as s:
+            self.assertEqual(s.getsockname()[1], 0)
+
+    def testBindSock(self):
+        with socket.socket(socket.AF_QIPCRTR, socket.SOCK_DGRAM) as s:
+            support.bind_port(s, host=s.getsockname()[0])
+            self.assertNotEqual(s.getsockname()[1], 0)
+
+    def testInvalidBindSock(self):
+        with socket.socket(socket.AF_QIPCRTR, socket.SOCK_DGRAM) as s:
+            self.assertRaises(OSError, support.bind_port, s, host=-2)
+
+    def testAutoBindSock(self):
+        with socket.socket(socket.AF_QIPCRTR, socket.SOCK_DGRAM) as s:
+            s.connect((123, 123))
+            self.assertNotEqual(s.getsockname()[1], 0)
 
 @unittest.skipIf(fcntl is None, "need fcntl")
 @unittest.skipUnless(HAVE_SOCKET_VSOCK,
@@ -5978,6 +6018,7 @@ def test_main():
     tests.extend([BasicCANTest, CANTest])
     tests.extend([BasicRDSTest, RDSTest])
     tests.append(LinuxKernelCryptoAPI)
+    tests.append(BasicQIPCRTRTest)
     tests.extend([
         BasicVSOCKTest,
         ThreadedVSOCKSocketStreamTest,
diff --git a/Misc/NEWS.d/next/Library/2017-10-24-10-18-35.bpo-31425.1lgw47.rst b/Misc/NEWS.d/next/Library/2017-10-24-10-18-35.bpo-31425.1lgw47.rst
new file mode 100644 (file)
index 0000000..c5d6467
--- /dev/null
@@ -0,0 +1,3 @@
+Add support for sockets of the AF_QIPCRTR address family, supported by the
+Linux kernel. This is used to communicate with services, such as GPS or
+radio, running on Qualcomm devices.
index adaefad556ca72e619fdec6c327d5374cea593b1..9149641fce5a22ec3140557af06ead538792ed0c 100644 (file)
@@ -7,8 +7,8 @@ This module provides an interface to Berkeley socket IPC.
 Limitations:
 
 - Only AF_INET, AF_INET6 and AF_UNIX address families are supported in a
-  portable manner, though AF_PACKET, AF_NETLINK and AF_TIPC are supported
-  under Linux.
+  portable manner, though AF_PACKET, AF_NETLINK, AF_QIPCRTR and AF_TIPC are
+  supported under Linux.
 - No read/write operations (use sendall/recv or makefile instead).
 - Additional restrictions apply on some non-Unix platforms (compensated
   for by socket.py).
@@ -55,6 +55,8 @@ Module interface:
   the Ethernet protocol number to be received. For example:
   ("eth0",0x1234).  Optional 3rd,4th,5th elements in the tuple
   specify packet-type and ha-type/addr.
+- an AF_QIPCRTR socket address is a (node, port) tuple where the
+  node and port are non-negative integers.
 - an AF_TIPC socket address is expressed as
  (addr_type, v1, v2, v3 [, scope]); where addr_type can be one of:
     TIPC_ADDR_NAMESEQ, TIPC_ADDR_NAME, and TIPC_ADDR_ID;
@@ -1293,6 +1295,14 @@ makesockaddr(SOCKET_T sockfd, struct sockaddr *addr, size_t addrlen, int proto)
        }
 #endif /* AF_NETLINK */
 
+#if defined(AF_QIPCRTR)
+       case AF_QIPCRTR:
+       {
+           struct sockaddr_qrtr *a = (struct sockaddr_qrtr *) addr;
+           return Py_BuildValue("II", a->sq_node, a->sq_port);
+       }
+#endif /* AF_QIPCRTR */
+
 #if defined(AF_VSOCK)
        case AF_VSOCK:
        {
@@ -1668,6 +1678,30 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
     }
 #endif /* AF_NETLINK */
 
+#if defined(AF_QIPCRTR)
+    case AF_QIPCRTR:
+    {
+        struct sockaddr_qrtr* addr;
+        unsigned int node, port;
+        addr = (struct sockaddr_qrtr *)addr_ret;
+        if (!PyTuple_Check(args)) {
+            PyErr_Format(
+                PyExc_TypeError,
+                "getsockaddrarg: "
+                "AF_QIPCRTR address must be tuple, not %.500s",
+                Py_TYPE(args)->tp_name);
+            return 0;
+        }
+        if (!PyArg_ParseTuple(args, "II:getsockaddrarg", &node, &port))
+            return 0;
+        addr->sq_family = AF_QIPCRTR;
+        addr->sq_node = node;
+        addr->sq_port = port;
+        *len_ret = sizeof(*addr);
+        return 1;
+    }
+#endif /* AF_QIPCRTR */
+
 #if defined(AF_VSOCK)
     case AF_VSOCK:
     {
@@ -2263,6 +2297,14 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
     }
 #endif /* AF_NETLINK */
 
+#if defined(AF_QIPCRTR)
+    case AF_QIPCRTR:
+    {
+        *len_ret = sizeof (struct sockaddr_qrtr);
+        return 1;
+    }
+#endif /* AF_QIPCRTR */
+
 #if defined(AF_VSOCK)
        case AF_VSOCK:
        {
@@ -6983,6 +7025,11 @@ PyInit__socket(void)
 #endif
 #endif /* AF_NETLINK */
 
+#ifdef AF_QIPCRTR
+    /* Qualcomm IPCROUTER */
+    PyModule_AddIntMacro(m, AF_QIPCRTR);
+#endif
+
 #ifdef AF_VSOCK
     PyModule_AddIntConstant(m, "AF_VSOCK", AF_VSOCK);
     PyModule_AddIntConstant(m, "SO_VM_SOCKETS_BUFFER_SIZE", 0);
index 0b2edc158782baba31f1f352c64c25d75f8aa649..dff1f8f4e9ce4a884b2e0f2b62ce07ee2d26eeec 100644 (file)
@@ -54,6 +54,15 @@ typedef int socklen_t;
 #  undef AF_NETLINK
 #endif
 
+#ifdef HAVE_LINUX_QRTR_H
+# ifdef HAVE_ASM_TYPES_H
+#  include <asm/types.h>
+# endif
+# include <linux/qrtr.h>
+#else
+#  undef AF_QIPCRTR
+#endif
+
 #ifdef HAVE_BLUETOOTH_BLUETOOTH_H
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/rfcomm.h>
@@ -203,6 +212,9 @@ typedef union sock_addr {
 #ifdef HAVE_SOCKADDR_ALG
     struct sockaddr_alg alg;
 #endif
+#ifdef AF_QIPCRTR
+    struct sockaddr_qrtr sq;
+#endif
 #ifdef AF_VSOCK
     struct sockaddr_vm vm;
 #endif
index 38546d6ca7b403de09fb23ae46554a147c3a2a3a..9d2c4e4ad7e6f2d2ae1eddbec3e5cd6706dc5434 100755 (executable)
--- a/configure
+++ b/configure
@@ -8023,6 +8023,28 @@ fi
 done
 
 
+# On Linux, qrtr.h requires asm/types.h
+for ac_header in linux/qrtr.h
+do :
+  ac_fn_c_check_header_compile "$LINENO" "linux/qrtr.h" "ac_cv_header_linux_qrtr_h" "
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+"
+if test "x$ac_cv_header_linux_qrtr_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LINUX_QRTR_H 1
+_ACEOF
+
+fi
+
+done
+
+
 for ac_header in linux/vm_sockets.h
 do :
   ac_fn_c_check_header_compile "$LINENO" "linux/vm_sockets.h" "ac_cv_header_linux_vm_sockets_h" "
index 96331ec221be2561700490934706ef29a797a0d2..2235a13d1160dd3d1e85d886a0b167691d0c3fd1 100644 (file)
@@ -2112,6 +2112,16 @@ AC_CHECK_HEADERS(linux/netlink.h,,,[
 #endif
 ])
 
+# On Linux, qrtr.h requires asm/types.h
+AC_CHECK_HEADERS(linux/qrtr.h,,,[
+#ifdef HAVE_ASM_TYPES_H
+#include <asm/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+])
+
 AC_CHECK_HEADERS(linux/vm_sockets.h,,,[
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
index 41e0479cad2e323e2843b30a1a1f6c0ad5337ac2..254a2dcab4da4447444d0a13345898db9c335122 100644 (file)
 /* Define to 1 if you have the <linux/netlink.h> header file. */
 #undef HAVE_LINUX_NETLINK_H
 
+/* Define to 1 if you have the <linux/qrtr.h> header file. */
+#undef HAVE_LINUX_QRTR_H
+
 /* Define to 1 if you have the <linux/random.h> header file. */
 #undef HAVE_LINUX_RANDOM_H