Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 10b8cf4

Browse files
author
Charles-François Natali
committed
Issue #7777: socket: Add Reliable Datagram Sockets (PF_RDS) support.
1 parent 0c929d9 commit 10b8cf4

5 files changed

Lines changed: 260 additions & 5 deletions

File tree

Doc/library/socket.rst

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,19 @@ The module :mod:`socket` exports the following constants and functions:
236236
.. versionadded:: 3.3
237237

238238

239+
.. data:: AF_RDS
240+
PF_RDS
241+
SOL_RDS
242+
RDS_*
243+
244+
Many constants of these forms, documented in the Linux documentation, are
245+
also defined in the socket module.
246+
247+
Availability: Linux >= 2.6.30.
248+
249+
.. versionadded:: 3.3
250+
251+
239252
.. data:: SIO_*
240253
RCVALL_*
241254

@@ -407,14 +420,15 @@ The module :mod:`socket` exports the following constants and functions:
407420

408421
Create a new socket using the given address family, socket type and protocol
409422
number. The address family should be :const:`AF_INET` (the default),
410-
:const:`AF_INET6`, :const:`AF_UNIX` or :const:`AF_CAN`. The socket type
411-
should be :const:`SOCK_STREAM` (the default), :const:`SOCK_DGRAM`,
412-
:const:`SOCK_RAW` or perhaps one of the other ``SOCK_`` constants. The
413-
protocol number is usually zero and may be omitted in that case or
414-
:const:`CAN_RAW` in case the address family is :const:`AF_CAN`.
423+
:const:`AF_INET6`, :const:`AF_UNIX`, :const:`AF_CAN` or :const:`AF_RDS`. The
424+
socket type should be :const:`SOCK_STREAM` (the default),
425+
:const:`SOCK_DGRAM`, :const:`SOCK_RAW` or perhaps one of the other ``SOCK_``
426+
constants. The protocol number is usually zero and may be omitted in that
427+
case or :const:`CAN_RAW` in case the address family is :const:`AF_CAN`.
415428

416429
.. versionchanged:: 3.3
417430
The AF_CAN family was added.
431+
The AF_RDS family was added.
418432

419433

420434
.. function:: socketpair([family[, type[, proto]]])

Doc/whatsnew/3.3.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,9 @@ socket
495495

496496
(Contributed by Matthias Fuchs, updated by Tiago Gonçalves in :issue:`10141`)
497497

498+
* The :class:`~socket.socket` class now supports the PF_RDS protocol family
499+
(http://en.wikipedia.org/wiki/Reliable_Datagram_Sockets and
500+
http://oss.oracle.com/projects/rds/).
498501

499502
ssl
500503
---

Lib/test/test_socket.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,20 @@ def _have_socket_can():
4747
s.close()
4848
return True
4949

50+
def _have_socket_rds():
51+
"""Check whether RDS sockets are supported on this host."""
52+
try:
53+
s = socket.socket(socket.PF_RDS, socket.SOCK_SEQPACKET, 0)
54+
except (AttributeError, OSError):
55+
return False
56+
else:
57+
s.close()
58+
return True
59+
5060
HAVE_SOCKET_CAN = _have_socket_can()
5161

62+
HAVE_SOCKET_RDS = _have_socket_rds()
63+
5264
# Size in bytes of the int type
5365
SIZEOF_INT = array.array("i").itemsize
5466

@@ -113,6 +125,23 @@ def setUp(self):
113125
self.skipTest('network interface `%s` does not exist' %
114126
self.interface)
115127

128+
129+
class SocketRDSTest(unittest.TestCase):
130+
131+
"""To be able to run this test, the `rds` kernel module must be loaded:
132+
# modprobe rds
133+
"""
134+
bufsize = 8192
135+
136+
def setUp(self):
137+
self.serv = socket.socket(socket.PF_RDS, socket.SOCK_SEQPACKET, 0)
138+
self.addCleanup(self.serv.close)
139+
try:
140+
self.port = support.bind_port(self.serv)
141+
except OSError:
142+
self.skipTest('unable to bind RDS socket')
143+
144+
116145
class ThreadableTest:
117146
"""Threadable Test class
118147
@@ -271,6 +300,29 @@ def clientTearDown(self):
271300
self.cli = None
272301
ThreadableTest.clientTearDown(self)
273302

303+
class ThreadedRDSSocketTest(SocketRDSTest, ThreadableTest):
304+
305+
def __init__(self, methodName='runTest'):
306+
SocketRDSTest.__init__(self, methodName=methodName)
307+
ThreadableTest.__init__(self)
308+
self.evt = threading.Event()
309+
310+
def clientSetUp(self):
311+
self.cli = socket.socket(socket.PF_RDS, socket.SOCK_SEQPACKET, 0)
312+
try:
313+
# RDS sockets must be bound explicitly to send or receive data
314+
self.cli.bind((HOST, 0))
315+
self.cli_addr = self.cli.getsockname()
316+
except OSError:
317+
# skipTest should not be called here, and will be called in the
318+
# server instead
319+
pass
320+
321+
def clientTearDown(self):
322+
self.cli.close()
323+
self.cli = None
324+
ThreadableTest.clientTearDown(self)
325+
274326
class SocketConnectedTest(ThreadedTCPSocketTest):
275327
"""Socket tests for client-server connection.
276328
@@ -1239,6 +1291,112 @@ def _testSendMultiFrames(self):
12391291
self.cli.send(self.cf2)
12401292

12411293

1294+
@unittest.skipUnless(HAVE_SOCKET_RDS, 'RDS sockets required for this test.')
1295+
class BasicRDSTest(unittest.TestCase):
1296+
1297+
def testCrucialConstants(self):
1298+
socket.AF_RDS
1299+
socket.PF_RDS
1300+
1301+
def testCreateSocket(self):
1302+
with socket.socket(socket.PF_RDS, socket.SOCK_SEQPACKET, 0) as s:
1303+
pass
1304+
1305+
def testSocketBufferSize(self):
1306+
bufsize = 16384
1307+
with socket.socket(socket.PF_RDS, socket.SOCK_SEQPACKET, 0) as s:
1308+
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, bufsize)
1309+
s.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, bufsize)
1310+
1311+
1312+
@unittest.skipUnless(HAVE_SOCKET_RDS, 'RDS sockets required for this test.')
1313+
@unittest.skipUnless(thread, 'Threading required for this test.')
1314+
class RDSTest(ThreadedRDSSocketTest):
1315+
1316+
def __init__(self, methodName='runTest'):
1317+
ThreadedRDSSocketTest.__init__(self, methodName=methodName)
1318+
1319+
def testSendAndRecv(self):
1320+
data, addr = self.serv.recvfrom(self.bufsize)
1321+
self.assertEqual(self.data, data)
1322+
self.assertEqual(self.cli_addr, addr)
1323+
1324+
def _testSendAndRecv(self):
1325+
self.data = b'spam'
1326+
self.cli.sendto(self.data, 0, (HOST, self.port))
1327+
1328+
def testPeek(self):
1329+
data, addr = self.serv.recvfrom(self.bufsize, socket.MSG_PEEK)
1330+
self.assertEqual(self.data, data)
1331+
data, addr = self.serv.recvfrom(self.bufsize)
1332+
self.assertEqual(self.data, data)
1333+
1334+
def _testPeek(self):
1335+
self.data = b'spam'
1336+
self.cli.sendto(self.data, 0, (HOST, self.port))
1337+
1338+
@requireAttrs(socket.socket, 'recvmsg')
1339+
def testSendAndRecvMsg(self):
1340+
data, ancdata, msg_flags, addr = self.serv.recvmsg(self.bufsize)
1341+
self.assertEqual(self.data, data)
1342+
1343+
@requireAttrs(socket.socket, 'sendmsg')
1344+
def _testSendAndRecvMsg(self):
1345+
self.data = b'hello ' * 10
1346+
self.cli.sendmsg([self.data], (), 0, (HOST, self.port))
1347+
1348+
def testSendAndRecvMulti(self):
1349+
data, addr = self.serv.recvfrom(self.bufsize)
1350+
self.assertEqual(self.data1, data)
1351+
1352+
data, addr = self.serv.recvfrom(self.bufsize)
1353+
self.assertEqual(self.data2, data)
1354+
1355+
def _testSendAndRecvMulti(self):
1356+
self.data1 = b'bacon'
1357+
self.cli.sendto(self.data1, 0, (HOST, self.port))
1358+
1359+
self.data2 = b'egg'
1360+
self.cli.sendto(self.data2, 0, (HOST, self.port))
1361+
1362+
def testSelect(self):
1363+
r, w, x = select.select([self.serv], [], [], 3.0)
1364+
self.assertIn(self.serv, r)
1365+
data, addr = self.serv.recvfrom(self.bufsize)
1366+
self.assertEqual(self.data, data)
1367+
1368+
def _testSelect(self):
1369+
self.data = b'select'
1370+
self.cli.sendto(self.data, 0, (HOST, self.port))
1371+
1372+
def testCongestion(self):
1373+
# wait until the sender is done
1374+
self.evt.wait()
1375+
1376+
def _testCongestion(self):
1377+
# test the behavior in case of congestion
1378+
self.data = b'fill'
1379+
self.cli.setblocking(False)
1380+
try:
1381+
# try to lower the receiver's socket buffer size
1382+
self.cli.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 16384)
1383+
except OSError:
1384+
pass
1385+
with self.assertRaises(OSError) as cm:
1386+
try:
1387+
# fill the receiver's socket buffer
1388+
while True:
1389+
self.cli.sendto(self.data, 0, (HOST, self.port))
1390+
finally:
1391+
# signal the receiver we're done
1392+
self.evt.set()
1393+
# sendto() should have failed with ENOBUFS
1394+
self.assertEqual(cm.exception.errno, errno.ENOBUFS)
1395+
# and we should have received a congestion notification through poll
1396+
r, w, x = select.select([self.serv], [], [], 3.0)
1397+
self.assertIn(self.serv, r)
1398+
1399+
12421400
@unittest.skipUnless(thread, 'Threading required for this test.')
12431401
class BasicTCPTest(SocketConnectedTest):
12441402

@@ -4362,6 +4520,7 @@ def test_main():
43624520
tests.append(TIPCTest)
43634521
tests.append(TIPCThreadableTest)
43644522
tests.extend([BasicCANTest, CANTest])
4523+
tests.extend([BasicRDSTest, RDSTest])
43654524
tests.extend([
43664525
CmsgMacroTests,
43674526
SendmsgUDPTest,

Misc/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,6 +1516,8 @@ Tools/Demos
15161516
Extension Modules
15171517
-----------------
15181518

1519+
- Issue #7777: socket: Add Reliable Datagram Sockets (PF_RDS) support.
1520+
15191521
- Issue #13159: FileIO and BZ2Compressor/BZ2Decompressor now use a linear-time
15201522
buffer growth strategy instead of a quadratic-time one.
15211523

Modules/socketmodule.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,6 +1328,11 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
13281328
}
13291329
#endif
13301330

1331+
#ifdef AF_RDS
1332+
case AF_RDS:
1333+
/* RDS sockets use sockaddr_in: fall-through */
1334+
#endif
1335+
13311336
case AF_INET:
13321337
{
13331338
struct sockaddr_in* addr;
@@ -1686,6 +1691,11 @@ getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
16861691
}
16871692
#endif
16881693

1694+
#ifdef AF_RDS
1695+
case AF_RDS:
1696+
/* RDS sockets use sockaddr_in: fall-through */
1697+
#endif
1698+
16891699
case AF_INET:
16901700
{
16911701
*len_ret = sizeof (struct sockaddr_in);
@@ -5614,6 +5624,14 @@ PyInit__socket(void)
56145624
PyModule_AddIntConstant(m, "PF_CAN", PF_CAN);
56155625
#endif
56165626

5627+
/* Reliable Datagram Sockets */
5628+
#ifdef AF_RDS
5629+
PyModule_AddIntConstant(m, "AF_RDS", AF_RDS);
5630+
#endif
5631+
#ifdef PF_RDS
5632+
PyModule_AddIntConstant(m, "PF_RDS", PF_RDS);
5633+
#endif
5634+
56175635
#ifdef AF_PACKET
56185636
PyModule_AddIntMacro(m, AF_PACKET);
56195637
#endif
@@ -5909,6 +5927,27 @@ PyInit__socket(void)
59095927
PyModule_AddIntConstant(m, "CAN_RAW_LOOPBACK", CAN_RAW_LOOPBACK);
59105928
PyModule_AddIntConstant(m, "CAN_RAW_RECV_OWN_MSGS", CAN_RAW_RECV_OWN_MSGS);
59115929
#endif
5930+
#ifdef SOL_RDS
5931+
PyModule_AddIntConstant(m, "SOL_RDS", SOL_RDS);
5932+
#endif
5933+
#ifdef RDS_CANCEL_SENT_TO
5934+
PyModule_AddIntConstant(m, "RDS_CANCEL_SENT_TO", RDS_CANCEL_SENT_TO);
5935+
#endif
5936+
#ifdef RDS_GET_MR
5937+
PyModule_AddIntConstant(m, "RDS_GET_MR", RDS_GET_MR);
5938+
#endif
5939+
#ifdef RDS_FREE_MR
5940+
PyModule_AddIntConstant(m, "RDS_FREE_MR", RDS_FREE_MR);
5941+
#endif
5942+
#ifdef RDS_RECVERR
5943+
PyModule_AddIntConstant(m, "RDS_RECVERR", RDS_RECVERR);
5944+
#endif
5945+
#ifdef RDS_CONG_MONITOR
5946+
PyModule_AddIntConstant(m, "RDS_CONG_MONITOR", RDS_CONG_MONITOR);
5947+
#endif
5948+
#ifdef RDS_GET_MR_FOR_DEST
5949+
PyModule_AddIntConstant(m, "RDS_GET_MR_FOR_DEST", RDS_GET_MR_FOR_DEST);
5950+
#endif
59125951
#ifdef IPPROTO_IP
59135952
PyModule_AddIntConstant(m, "IPPROTO_IP", IPPROTO_IP);
59145953
#else
@@ -6261,6 +6300,44 @@ PyInit__socket(void)
62616300
PyModule_AddIntConstant(m, "IPX_TYPE", IPX_TYPE);
62626301
#endif
62636302

6303+
/* Reliable Datagram Sockets */
6304+
#ifdef RDS_CMSG_RDMA_ARGS
6305+
PyModule_AddIntConstant(m, "RDS_CMSG_RDMA_ARGS", RDS_CMSG_RDMA_ARGS);
6306+
#endif
6307+
#ifdef RDS_CMSG_RDMA_DEST
6308+
PyModule_AddIntConstant(m, "RDS_CMSG_RDMA_DEST", RDS_CMSG_RDMA_DEST);
6309+
#endif
6310+
#ifdef RDS_CMSG_RDMA_MAP
6311+
PyModule_AddIntConstant(m, "RDS_CMSG_RDMA_MAP", RDS_CMSG_RDMA_MAP);
6312+
#endif
6313+
#ifdef RDS_CMSG_RDMA_STATUS
6314+
PyModule_AddIntConstant(m, "RDS_CMSG_RDMA_STATUS", RDS_CMSG_RDMA_STATUS);
6315+
#endif
6316+
#ifdef RDS_CMSG_RDMA_UPDATE
6317+
PyModule_AddIntConstant(m, "RDS_CMSG_RDMA_UPDATE", RDS_CMSG_RDMA_UPDATE);
6318+
#endif
6319+
#ifdef RDS_RDMA_READWRITE
6320+
PyModule_AddIntConstant(m, "RDS_RDMA_READWRITE", RDS_RDMA_READWRITE);
6321+
#endif
6322+
#ifdef RDS_RDMA_FENCE
6323+
PyModule_AddIntConstant(m, "RDS_RDMA_FENCE", RDS_RDMA_FENCE);
6324+
#endif
6325+
#ifdef RDS_RDMA_INVALIDATE
6326+
PyModule_AddIntConstant(m, "RDS_RDMA_INVALIDATE", RDS_RDMA_INVALIDATE);
6327+
#endif
6328+
#ifdef RDS_RDMA_USE_ONCE
6329+
PyModule_AddIntConstant(m, "RDS_RDMA_USE_ONCE", RDS_RDMA_USE_ONCE);
6330+
#endif
6331+
#ifdef RDS_RDMA_DONTWAIT
6332+
PyModule_AddIntConstant(m, "RDS_RDMA_DONTWAIT", RDS_RDMA_DONTWAIT);
6333+
#endif
6334+
#ifdef RDS_RDMA_NOTIFY_ME
6335+
PyModule_AddIntConstant(m, "RDS_RDMA_NOTIFY_ME", RDS_RDMA_NOTIFY_ME);
6336+
#endif
6337+
#ifdef RDS_RDMA_SILENT
6338+
PyModule_AddIntConstant(m, "RDS_RDMA_SILENT", RDS_RDMA_SILENT);
6339+
#endif
6340+
62646341
/* get{addr,name}info parameters */
62656342
#ifdef EAI_ADDRFAMILY
62666343
PyModule_AddIntConstant(m, "EAI_ADDRFAMILY", EAI_ADDRFAMILY);

0 commit comments

Comments
 (0)