Skip to content

Commit bb81651

Browse files
anderssontaleinat
authored andcommitted
bpo-31425: Expose AF_QIPCRTR in socket module (GH-3706)
The AF_QIPCRTR address family was introduced in Linux v4.7. Co-authored-by: Bjorn Andersson <bjorn.andersson@linaro.org>
1 parent 2aaf98c commit bb81651

File tree

8 files changed

+154
-2
lines changed

8 files changed

+154
-2
lines changed

Doc/library/socket.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,13 @@ created. Socket addresses are represented as follows:
193193
- *addr* - Optional bytes-like object specifying the hardware physical
194194
address, whose interpretation depends on the device.
195195

196+
- :const:`AF_QIPCRTR` is a Linux-only socket based interface for communicating
197+
with services running on co-processors in Qualcomm platforms. The address
198+
family is represented as a ``(node, port)`` tuple where the *node* and *port*
199+
are non-negative integers.
200+
201+
.. versionadded:: 3.7
202+
196203
If you use a hostname in the *host* portion of IPv4/v6 socket address, the
197204
program may show a nondeterministic behavior, as Python uses the first address
198205
returned from the DNS resolution. The socket address will be resolved
@@ -481,6 +488,13 @@ Constants
481488
:const:`HCI_DATA_DIR` are not available for FreeBSD, NetBSD, or
482489
DragonFlyBSD.
483490

491+
.. data:: AF_QIPCRTR
492+
493+
Constant for Qualcomm's IPC router protocol, used to communicate with
494+
service providing remote processors.
495+
496+
Availability: Linux >= 4.7.
497+
484498
Functions
485499
^^^^^^^^^
486500

Lib/test/test_socket.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ def _have_socket_alg():
9494
s.close()
9595
return True
9696

97+
def _have_socket_qipcrtr():
98+
"""Check whether AF_QIPCRTR sockets are supported on this host."""
99+
try:
100+
s = socket.socket(socket.AF_QIPCRTR, socket.SOCK_DGRAM, 0)
101+
except (AttributeError, OSError):
102+
return False
103+
else:
104+
s.close()
105+
return True
106+
97107
def _have_socket_vsock():
98108
"""Check whether AF_VSOCK sockets are supported on this host."""
99109
ret = get_cid() is not None
@@ -113,6 +123,8 @@ def _is_fd_in_blocking_mode(sock):
113123

114124
HAVE_SOCKET_ALG = _have_socket_alg()
115125

126+
HAVE_SOCKET_QIPCRTR = _have_socket_qipcrtr()
127+
116128
HAVE_SOCKET_VSOCK = _have_socket_vsock()
117129

118130
# Size in bytes of the int type
@@ -2054,6 +2066,34 @@ def _testSelect(self):
20542066
self.data = b'select'
20552067
self.cli.sendto(self.data, 0, (HOST, self.port))
20562068

2069+
@unittest.skipUnless(HAVE_SOCKET_QIPCRTR,
2070+
'QIPCRTR sockets required for this test.')
2071+
class BasicQIPCRTRTest(unittest.TestCase):
2072+
2073+
def testCrucialConstants(self):
2074+
socket.AF_QIPCRTR
2075+
2076+
def testCreateSocket(self):
2077+
with socket.socket(socket.AF_QIPCRTR, socket.SOCK_DGRAM) as s:
2078+
pass
2079+
2080+
def testUnbound(self):
2081+
with socket.socket(socket.AF_QIPCRTR, socket.SOCK_DGRAM) as s:
2082+
self.assertEqual(s.getsockname()[1], 0)
2083+
2084+
def testBindSock(self):
2085+
with socket.socket(socket.AF_QIPCRTR, socket.SOCK_DGRAM) as s:
2086+
support.bind_port(s, host=s.getsockname()[0])
2087+
self.assertNotEqual(s.getsockname()[1], 0)
2088+
2089+
def testInvalidBindSock(self):
2090+
with socket.socket(socket.AF_QIPCRTR, socket.SOCK_DGRAM) as s:
2091+
self.assertRaises(OSError, support.bind_port, s, host=-2)
2092+
2093+
def testAutoBindSock(self):
2094+
with socket.socket(socket.AF_QIPCRTR, socket.SOCK_DGRAM) as s:
2095+
s.connect((123, 123))
2096+
self.assertNotEqual(s.getsockname()[1], 0)
20572097

20582098
@unittest.skipIf(fcntl is None, "need fcntl")
20592099
@unittest.skipUnless(HAVE_SOCKET_VSOCK,
@@ -5978,6 +6018,7 @@ def test_main():
59786018
tests.extend([BasicCANTest, CANTest])
59796019
tests.extend([BasicRDSTest, RDSTest])
59806020
tests.append(LinuxKernelCryptoAPI)
6021+
tests.append(BasicQIPCRTRTest)
59816022
tests.extend([
59826023
BasicVSOCKTest,
59836024
ThreadedVSOCKSocketStreamTest,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add support for sockets of the AF_QIPCRTR address family, supported by the
2+
Linux kernel. This is used to communicate with services, such as GPS or
3+
radio, running on Qualcomm devices.

Modules/socketmodule.c

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ This module provides an interface to Berkeley socket IPC.
77
Limitations:
88
99
- Only AF_INET, AF_INET6 and AF_UNIX address families are supported in a
10-
portable manner, though AF_PACKET, AF_NETLINK and AF_TIPC are supported
11-
under Linux.
10+
portable manner, though AF_PACKET, AF_NETLINK, AF_QIPCRTR and AF_TIPC are
11+
supported under Linux.
1212
- No read/write operations (use sendall/recv or makefile instead).
1313
- Additional restrictions apply on some non-Unix platforms (compensated
1414
for by socket.py).
@@ -55,6 +55,8 @@ Module interface:
5555
the Ethernet protocol number to be received. For example:
5656
("eth0",0x1234). Optional 3rd,4th,5th elements in the tuple
5757
specify packet-type and ha-type/addr.
58+
- an AF_QIPCRTR socket address is a (node, port) tuple where the
59+
node and port are non-negative integers.
5860
- an AF_TIPC socket address is expressed as
5961
(addr_type, v1, v2, v3 [, scope]); where addr_type can be one of:
6062
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)
12931295
}
12941296
#endif /* AF_NETLINK */
12951297

1298+
#if defined(AF_QIPCRTR)
1299+
case AF_QIPCRTR:
1300+
{
1301+
struct sockaddr_qrtr *a = (struct sockaddr_qrtr *) addr;
1302+
return Py_BuildValue("II", a->sq_node, a->sq_port);
1303+
}
1304+
#endif /* AF_QIPCRTR */
1305+
12961306
#if defined(AF_VSOCK)
12971307
case AF_VSOCK:
12981308
{
@@ -1668,6 +1678,30 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
16681678
}
16691679
#endif /* AF_NETLINK */
16701680

1681+
#if defined(AF_QIPCRTR)
1682+
case AF_QIPCRTR:
1683+
{
1684+
struct sockaddr_qrtr* addr;
1685+
unsigned int node, port;
1686+
addr = (struct sockaddr_qrtr *)addr_ret;
1687+
if (!PyTuple_Check(args)) {
1688+
PyErr_Format(
1689+
PyExc_TypeError,
1690+
"getsockaddrarg: "
1691+
"AF_QIPCRTR address must be tuple, not %.500s",
1692+
Py_TYPE(args)->tp_name);
1693+
return 0;
1694+
}
1695+
if (!PyArg_ParseTuple(args, "II:getsockaddrarg", &node, &port))
1696+
return 0;
1697+
addr->sq_family = AF_QIPCRTR;
1698+
addr->sq_node = node;
1699+
addr->sq_port = port;
1700+
*len_ret = sizeof(*addr);
1701+
return 1;
1702+
}
1703+
#endif /* AF_QIPCRTR */
1704+
16711705
#if defined(AF_VSOCK)
16721706
case AF_VSOCK:
16731707
{
@@ -2263,6 +2297,14 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
22632297
}
22642298
#endif /* AF_NETLINK */
22652299

2300+
#if defined(AF_QIPCRTR)
2301+
case AF_QIPCRTR:
2302+
{
2303+
*len_ret = sizeof (struct sockaddr_qrtr);
2304+
return 1;
2305+
}
2306+
#endif /* AF_QIPCRTR */
2307+
22662308
#if defined(AF_VSOCK)
22672309
case AF_VSOCK:
22682310
{
@@ -6983,6 +7025,11 @@ PyInit__socket(void)
69837025
#endif
69847026
#endif /* AF_NETLINK */
69857027

7028+
#ifdef AF_QIPCRTR
7029+
/* Qualcomm IPCROUTER */
7030+
PyModule_AddIntMacro(m, AF_QIPCRTR);
7031+
#endif
7032+
69867033
#ifdef AF_VSOCK
69877034
PyModule_AddIntConstant(m, "AF_VSOCK", AF_VSOCK);
69887035
PyModule_AddIntConstant(m, "SO_VM_SOCKETS_BUFFER_SIZE", 0);

Modules/socketmodule.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,15 @@ typedef int socklen_t;
5454
# undef AF_NETLINK
5555
#endif
5656

57+
#ifdef HAVE_LINUX_QRTR_H
58+
# ifdef HAVE_ASM_TYPES_H
59+
# include <asm/types.h>
60+
# endif
61+
# include <linux/qrtr.h>
62+
#else
63+
# undef AF_QIPCRTR
64+
#endif
65+
5766
#ifdef HAVE_BLUETOOTH_BLUETOOTH_H
5867
#include <bluetooth/bluetooth.h>
5968
#include <bluetooth/rfcomm.h>
@@ -203,6 +212,9 @@ typedef union sock_addr {
203212
#ifdef HAVE_SOCKADDR_ALG
204213
struct sockaddr_alg alg;
205214
#endif
215+
#ifdef AF_QIPCRTR
216+
struct sockaddr_qrtr sq;
217+
#endif
206218
#ifdef AF_VSOCK
207219
struct sockaddr_vm vm;
208220
#endif

configure

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8023,6 +8023,28 @@ fi
80238023
done
80248024

80258025

8026+
# On Linux, qrtr.h requires asm/types.h
8027+
for ac_header in linux/qrtr.h
8028+
do :
8029+
ac_fn_c_check_header_compile "$LINENO" "linux/qrtr.h" "ac_cv_header_linux_qrtr_h" "
8030+
#ifdef HAVE_ASM_TYPES_H
8031+
#include <asm/types.h>
8032+
#endif
8033+
#ifdef HAVE_SYS_SOCKET_H
8034+
#include <sys/socket.h>
8035+
#endif
8036+
8037+
"
8038+
if test "x$ac_cv_header_linux_qrtr_h" = xyes; then :
8039+
cat >>confdefs.h <<_ACEOF
8040+
#define HAVE_LINUX_QRTR_H 1
8041+
_ACEOF
8042+
8043+
fi
8044+
8045+
done
8046+
8047+
80268048
for ac_header in linux/vm_sockets.h
80278049
do :
80288050
ac_fn_c_check_header_compile "$LINENO" "linux/vm_sockets.h" "ac_cv_header_linux_vm_sockets_h" "

configure.ac

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2112,6 +2112,16 @@ AC_CHECK_HEADERS(linux/netlink.h,,,[
21122112
#endif
21132113
])
21142114

2115+
# On Linux, qrtr.h requires asm/types.h
2116+
AC_CHECK_HEADERS(linux/qrtr.h,,,[
2117+
#ifdef HAVE_ASM_TYPES_H
2118+
#include <asm/types.h>
2119+
#endif
2120+
#ifdef HAVE_SYS_SOCKET_H
2121+
#include <sys/socket.h>
2122+
#endif
2123+
])
2124+
21152125
AC_CHECK_HEADERS(linux/vm_sockets.h,,,[
21162126
#ifdef HAVE_SYS_SOCKET_H
21172127
#include <sys/socket.h>

pyconfig.h.in

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,9 @@
615615
/* Define to 1 if you have the <linux/netlink.h> header file. */
616616
#undef HAVE_LINUX_NETLINK_H
617617

618+
/* Define to 1 if you have the <linux/qrtr.h> header file. */
619+
#undef HAVE_LINUX_QRTR_H
620+
618621
/* Define to 1 if you have the <linux/random.h> header file. */
619622
#undef HAVE_LINUX_RANDOM_H
620623

0 commit comments

Comments
 (0)