From 112a3400ece0401dd2d6f4eef329096b8352185b Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Sat, 23 Sep 2017 05:44:23 +0000 Subject: [PATCH 1/2] bpo-31425: Expose AF_QIPCRTR in socket module The AF_QIPCRTR address family was introduced in Linux v4.7, expose this in the Python socket module to allow applications to operate on sockets of this type. Signed-off-by: Bjorn Andersson --- Doc/library/socket.rst | 7 +++ Lib/test/test_socket.py | 41 ++++++++++++++++ .../2017-10-24-10-18-35.bpo-31425.1lgw47.rst | 3 ++ Modules/socketmodule.c | 49 ++++++++++++++++++- Modules/socketmodule.h | 12 +++++ configure | 22 +++++++++ configure.ac | 10 ++++ pyconfig.h.in | 3 ++ 8 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2017-10-24-10-18-35.bpo-31425.1lgw47.rst diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index 42fd7ea0f0bd044..ed522e8ed681805 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -161,6 +161,13 @@ created. Socket addresses are represented as follows: .. versionadded:: 3.7 +- :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 + integers. + + .. versionadded:: 3.7 + - Certain other address families (:const:`AF_PACKET`, :const:`AF_CAN`) support specific representations. diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index e70a8f69a7a4b53..6b82d4f48bf1b1b 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -93,6 +93,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 @@ -106,6 +116,8 @@ def _have_socket_vsock(): 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 @@ -1924,6 +1936,34 @@ def _testCongestion(self): r, w, x = select.select([self.serv], [], [], 3.0) self.assertIn(self.serv, r) +@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, @@ -5762,6 +5802,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 index 000000000000000..c5d646775b94213 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2017-10-24-10-18-35.bpo-31425.1lgw47.rst @@ -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. diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 91c879f9d6355fb..69268c77636e26f 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -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). @@ -1207,6 +1207,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: { @@ -1579,6 +1587,30 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, } #endif /* AF_NETLINK */ +#if defined(AF_QIPCRTR) + case AF_QIPCRTR: + { + struct sockaddr_qrtr* addr; + 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 + #if defined(AF_VSOCK) case AF_VSOCK: { @@ -2125,6 +2157,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 + #if defined(AF_VSOCK) case AF_VSOCK: { @@ -6710,6 +6750,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); diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h index fdb4e871cef81e6..0721d641a9a99cd 100644 --- a/Modules/socketmodule.h +++ b/Modules/socketmodule.h @@ -54,6 +54,15 @@ typedef int socklen_t; # undef AF_NETLINK #endif +#ifdef HAVE_LINUX_QRTR_H +# ifdef HAVE_ASM_TYPES_H +# include +# endif +# include +#else +# undef AF_QIPCRTR +#endif + #ifdef HAVE_BLUETOOTH_BLUETOOTH_H #include #include @@ -202,6 +211,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 diff --git a/configure b/configure index d02675742d27d91..9ffee8354f61b50 100755 --- a/configure +++ b/configure @@ -7983,6 +7983,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 +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#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" " diff --git a/configure.ac b/configure.ac index 68a95c3be6af4a3..d5b573576330acd 100644 --- a/configure.ac +++ b/configure.ac @@ -2093,6 +2093,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 +#endif +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +]) + AC_CHECK_HEADERS(linux/vm_sockets.h,,,[ #ifdef HAVE_SYS_SOCKET_H #include diff --git a/pyconfig.h.in b/pyconfig.h.in index 66b9e8882745009..3d3fa017f252697 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -592,6 +592,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_NETLINK_H +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_QRTR_H + /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_RANDOM_H From 1011b9d088ccf75d296f27dd388ca3126ef010fc Mon Sep 17 00:00:00 2001 From: Tal Einat Date: Wed, 26 Sep 2018 13:16:26 +0300 Subject: [PATCH 2/2] bpo-31425: address latest code review comments --- Doc/library/socket.rst | 11 +++++++++-- Modules/socketmodule.c | 8 +++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Doc/library/socket.rst b/Doc/library/socket.rst index ed522e8ed681805..20926b2e08b05cc 100644 --- a/Doc/library/socket.rst +++ b/Doc/library/socket.rst @@ -163,8 +163,8 @@ created. Socket addresses are represented as follows: - :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 - integers. + family is represented as a ``(node, port)`` tuple where the *node* and *port* + are non-negative integers. .. versionadded:: 3.7 @@ -450,6 +450,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 ^^^^^^^^^ diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index 69268c77636e26f..fcd20ce5bcfc077 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -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; @@ -1591,7 +1593,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, case AF_QIPCRTR: { struct sockaddr_qrtr* addr; - int node, port; + unsigned int node, port; addr = (struct sockaddr_qrtr *)addr_ret; if (!PyTuple_Check(args)) { PyErr_Format( @@ -1609,7 +1611,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args, *len_ret = sizeof(*addr); return 1; } -#endif +#endif /* AF_QIPCRTR */ #if defined(AF_VSOCK) case AF_VSOCK: @@ -2163,7 +2165,7 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret) *len_ret = sizeof (struct sockaddr_qrtr); return 1; } -#endif +#endif /* AF_QIPCRTR */ #if defined(AF_VSOCK) case AF_VSOCK: