cpython: c64216addd7f (original) (raw)
--- a/Doc/library/socket.rst
+++ b/Doc/library/socket.rst
@@ -198,6 +198,7 @@ The module :mod:socket
exports the fol
SOMAXCONN
MSG_*
SOL_*
SCM_*[](#l1.7) IPPROTO_*[](#l1.8) IPPORT_*[](#l1.9) INADDR_*[](#l1.10)
@@ -511,6 +512,49 @@ The module :mod:socket
exports the fol
Availability: Unix (maybe not all platforms).
+..
- XXX: Are sendmsg(), recvmsg() and CMSG_*() available on any
- non-Unix platforms? The old (obsolete?) 4.2BSD form of the
- interface, in which struct msghdr has no msg_control or
- msg_controllen members, is not currently supported. +
+.. function:: CMSG_LEN(length) +
- Return the total length, without trailing padding, of an ancillary
- data item with associated data of the given length. This value
- can often be used as the buffer size for :meth:
~socket.recvmsg
to - receive a single item of ancillary data, but :rfc:
3542
requires - portable applications to use :func:
CMSG_SPACE
and thus include - space for padding, even when the item will be the last in the
- buffer. Raises :exc:
OverflowError
if length is outside the - permissible range of values. +
- Availability: most Unix platforms, possibly others. +
- .. versionadded:: 3.3 +
+ +.. function:: CMSG_SPACE(length) +
- Return the buffer size needed for :meth:
~socket.recvmsg
to - receive an ancillary data item with associated data of the given
- length, along with any trailing padding. The buffer space needed
- to receive multiple items is the sum of the :func:
CMSG_SPACE
- values for their associated data lengths. Raises
- :exc:
OverflowError
if length is outside the permissible range - of values. +
- Note that some systems might support ancillary data without
- providing this function. Also note that setting the buffer size
- using the results of this function may not precisely limit the
- amount of ancillary data that can be received, since additional
- data may be able to fit into the padding area. +
- Availability: most Unix platforms, possibly others. +
- .. versionadded:: 3.3 +
+ .. function:: getdefaulttimeout() Return the default timeout in seconds (float) for new socket objects. A value @@ -742,6 +786,109 @@ correspond to Unix system calls applicab to zero. (The format of address depends on the address family --- see above.) +.. method:: socket.recvmsg(bufsize[, ancbufsize[, flags]]) +
- Receive normal data (up to bufsize bytes) and ancillary data from
- the socket. The ancbufsize argument sets the size in bytes of
- the internal buffer used to receive the ancillary data; it defaults
- to 0, meaning that no ancillary data will be received. Appropriate
- buffer sizes for ancillary data can be calculated using
- :func:
CMSG_SPACE
or :func:CMSG_LEN
, and items which do not fit - into the buffer might be truncated or discarded. The flags
- argument defaults to 0 and has the same meaning as for
- :meth:
recv
. + - The return value is a 4-tuple: ``(data, ancdata, msg_flags,
- address)``. The data item is a :class:
bytes
object holding the - non-ancillary data received. The ancdata item is a list of zero
- or more tuples
(cmsg_level, cmsg_type, cmsg_data)
representing - the ancillary data (control messages) received: cmsg_level and
- cmsg_type are integers specifying the protocol level and
- protocol-specific type respectively, and cmsg_data is a
- :class:
bytes
object holding the associated data. The msg_flags - item is the bitwise OR of various flags indicating conditions on
- the received message; see your system documentation for details.
- If the receiving socket is unconnected, address is the address of
- the sending socket, if available; otherwise, its value is
- unspecified. +
- On some systems, :meth:
sendmsg
and :meth:recvmsg
can be used to - pass file descriptors between processes over an :const:
AF_UNIX
- socket. When this facility is used (it is often restricted to
- :const:
SOCK_STREAM
sockets), :meth:recvmsg
will return, in its - ancillary data, items of the form ``(socket.SOL_SOCKET,
- socket.SCM_RIGHTS, fds)``, where fds is a :class:
bytes
object - representing the new file descriptors as a binary array of the
- native C :c:type:
int
type. If :meth:recvmsg
raises an - exception after the system call returns, it will first attempt to
- close any file descriptors received via this mechanism. +
- Some systems do not indicate the truncated length of ancillary data
- items which have been only partially received. If an item appears
- to extend beyond the end of the buffer, :meth:
recvmsg
will issue - a :exc:
RuntimeWarning
, and will return the part of it which is - inside the buffer provided it has not been truncated before the
- start of its associated data. +
- On systems which support the :const:
SCM_RIGHTS
mechanism, the - following function will receive up to maxfds file descriptors,
- returning the message data and a list containing the descriptors
- (while ignoring unexpected conditions such as unrelated control
- messages being received). See also :meth:
sendmsg
. :: + import socket, array[](#l1.115)
def recv_fds(sock, msglen, maxfds):[](#l1.117)
fds = array.array("i") # Array of ints[](#l1.118)
msg, ancdata, flags, addr = sock.recvmsg(msglen, socket.CMSG_LEN(maxfds * fds.itemsize))[](#l1.119)
for cmsg_level, cmsg_type, cmsg_data in ancdata:[](#l1.120)
if (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS):[](#l1.121)
# Append data, ignoring any truncated integers at the end.[](#l1.122)
fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])[](#l1.123)
return msg, list(fds)[](#l1.124)
+ +.. method:: socket.recvmsg_into(buffers[, ancbufsize[, flags]]) +
- Receive normal data and ancillary data from the socket, behaving as
- :meth:
recvmsg
would, but scatter the non-ancillary data into a - series of buffers instead of returning a new bytes object. The
- buffers argument must be an iterable of objects that export
- writable buffers (e.g. :class:
bytearray
objects); these will be - filled with successive chunks of the non-ancillary data until it
- has all been written or there are no more buffers. The operating
- system may set a limit (:func:
~os.sysconf
valueSC_IOV_MAX
) - on the number of buffers that can be used. The ancbufsize and
- flags arguments have the same meaning as for :meth:
recvmsg
. + - The return value is a 4-tuple: ``(nbytes, ancdata, msg_flags,
- address)``, where nbytes is the total number of bytes of
- non-ancillary data written into the buffers, and ancdata,
- msg_flags and address are the same as for :meth:
recvmsg
. + - Example:: +
>>> import socket[](#l1.151)
>>> s1, s2 = socket.socketpair()[](#l1.152)
>>> b1 = bytearray(b'----')[](#l1.153)
>>> b2 = bytearray(b'0123456789')[](#l1.154)
>>> b3 = bytearray(b'--------------')[](#l1.155)
>>> s1.send(b'Mary had a little lamb')[](#l1.156)
22[](#l1.157)
>>> s2.recvmsg_into([b1, memoryview(b2)[2:9], b3])[](#l1.158)
(22, [], 0, None)[](#l1.159)
>>> [b1, b2, b3][](#l1.160)
[bytearray(b'Mary'), bytearray(b'01 had a 9'), bytearray(b'little lamb---')][](#l1.161)
+ .. method:: socket.recvfrom_into(buffer[, nbytes[, flags]]) Receive data from the socket, writing it into buffer instead of creating a @@ -789,6 +936,41 @@ correspond to Unix system calls applicab above.) +.. method:: socket.sendmsg(buffers[, ancdata[, flags[, address]]]) +
- Send normal and ancillary data to the socket, gathering the
- non-ancillary data from a series of buffers and concatenating it
- into a single message. The buffers argument specifies the
- non-ancillary data as an iterable of buffer-compatible objects
- (e.g. :class:
bytes
objects); the operating system may set a limit - (:func:
~os.sysconf
valueSC_IOV_MAX
) on the number of buffers - that can be used. The ancdata argument specifies the ancillary
- data (control messages) as an iterable of zero or more tuples
(cmsg_level, cmsg_type, cmsg_data)
, where cmsg_level and- cmsg_type are integers specifying the protocol level and
- protocol-specific type respectively, and cmsg_data is a
- buffer-compatible object holding the associated data. Note that
- some systems (in particular, systems without :func:
CMSG_SPACE
) - might support sending only one control message per call. The
- flags argument defaults to 0 and has the same meaning as for
- :meth:
send
. If address is supplied and notNone
, it sets a - destination address for the message. The return value is the
- number of bytes of non-ancillary data sent. +
- The following function sends the list of file descriptors fds
- over an :const:
AF_UNIX
socket, on systems which support the - :const:
SCM_RIGHTS
mechanism. See also :meth:recvmsg
. :: + import socket, array[](#l1.200)
def send_fds(sock, msg, fds):[](#l1.202)
return sock.sendmsg([msg], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array("i", fds))])[](#l1.203)
+ .. method:: socket.setblocking(flag) Set blocking or non-blocking mode of the socket: if flag is false, the
--- a/Doc/whatsnew/3.3.rst +++ b/Doc/whatsnew/3.3.rst @@ -212,6 +212,18 @@ signal
- :func:
signal.signal
and :func:signal.siginterrupt
raise an OSError, instead of a RuntimeError: OSError has an errno attribute. +socket +------ + +The :class:~socket.socket
class now exposes addititonal methods to +process ancillary data when supported by the underlying platform: + +* :func:~socket.socket.sendmsg
+* :func:~socket.socket.recvmsg
+* :func:~socket.socket.recvmsg_into
+ +(Contributed by David Watson in :issue:6560
, based on an earlier patch +by Heiko Wundram) ssl ---
--- a/Lib/ssl.py +++ b/Lib/ssl.py @@ -355,6 +355,14 @@ class SSLSocket(socket): else: return socket.sendto(self, data, flags_or_addr, addr)
- def sendmsg(self, *args, **kwargs):
self._checkClosed()[](#l3.8)
if self._sslobj:[](#l3.9)
raise ValueError("sendmsg not allowed on instances of %s" %[](#l3.10)
self.__class__)[](#l3.11)
else:[](#l3.12)
return socket.sendmsg(self, *args, **kwargs)[](#l3.13)
+ def sendall(self, data, flags=0): self._checkClosed() if self._sslobj: @@ -413,6 +421,22 @@ class SSLSocket(socket): else: return socket.recvfrom_into(self, buffer, nbytes, flags)
- def recvmsg(self, *args, **kwargs):
self._checkClosed()[](#l3.23)
if self._sslobj:[](#l3.24)
raise ValueError("recvmsg not allowed on instances of %s" %[](#l3.25)
self.__class__)[](#l3.26)
else:[](#l3.27)
return socket.recvmsg(self, *args, **kwargs)[](#l3.28)
- def recvmsg_into(self, *args, **kwargs):
self._checkClosed()[](#l3.31)
if self._sslobj:[](#l3.32)
raise ValueError("recvmsg_into not allowed on instances of %s" %[](#l3.33)
self.__class__)[](#l3.34)
else:[](#l3.35)
return socket.recvmsg_into(self, *args, **kwargs)[](#l3.36)
+ def pending(self): self._checkClosed() if self._sslobj:
--- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -7,6 +7,8 @@ import errno import io import socket import select +import tempfile +import _testcapi import time import traceback import queue @@ -34,6 +36,9 @@ except ImportError: thread = None threading = None +# Size in bytes of the int type +SIZEOF_INT = array.array("i").itemsize + class SocketTCPTest(unittest.TestCase): def setUp(self): @@ -55,6 +60,26 @@ class SocketUDPTest(unittest.TestCase): self.serv.close() self.serv = None +class ThreadSafeCleanupTestCase(unittest.TestCase):
- if threading:
def __init__(self, *args, **kwargs):[](#l4.34)
super().__init__(*args, **kwargs)[](#l4.35)
self._cleanup_lock = threading.RLock()[](#l4.36)
def addCleanup(self, *args, **kwargs):[](#l4.38)
with self._cleanup_lock:[](#l4.39)
return super().addCleanup(*args, **kwargs)[](#l4.40)
def doCleanups(self, *args, **kwargs):[](#l4.42)
with self._cleanup_lock:[](#l4.43)
return super().doCleanups(*args, **kwargs)[](#l4.44)
+ class ThreadableTest: """Threadable Test class @@ -237,6 +262,243 @@ class SocketPairTest(unittest.TestCase, ThreadableTest.clientTearDown(self) +# The following classes are used by the sendmsg()/recvmsg() tests. +# Combining, for instance, ConnectedStreamTestMixin and TCPTestBase +# gives a drop-in replacement for SocketConnectedTest, but different +# address families can be used, and the attributes serv_addr and +# cli_addr will be set to the addresses of the endpoints. + +class SocketTestBase(unittest.TestCase):
- Subclasses must provide methods newSocket() to return a new socket
- and bindSock(sock) to bind it to an unused address.
- def bindServer(self):
"""Bind server socket and set self.serv_addr to its address."""[](#l4.73)
self.bindSock(self.serv)[](#l4.74)
self.serv_addr = self.serv.getsockname()[](#l4.75)
+ + +class SocketListeningTestMixin(SocketTestBase):
+ + +class ThreadedSocketTestMixin(ThreadSafeCleanupTestCase, SocketTestBase,
- Client socket is self.cli and its address is self.cli_addr. See
- ThreadableTest for usage information.
- """
- def init(self, *args, **kwargs):
super().__init__(*args, **kwargs)[](#l4.99)
ThreadableTest.__init__(self)[](#l4.100)
- def newClientSocket(self):
"""Return a new socket for use as client."""[](#l4.107)
return self.newSocket()[](#l4.108)
- def bindClient(self):
"""Bind client socket and set self.cli_addr to its address."""[](#l4.111)
self.bindSock(self.cli)[](#l4.112)
self.cli_addr = self.cli.getsockname()[](#l4.113)
- def clientTearDown(self):
self.cli.close()[](#l4.116)
self.cli = None[](#l4.117)
ThreadableTest.clientTearDown(self)[](#l4.118)
+ + +class ConnectedStreamTestMixin(SocketListeningTestMixin,
ThreadedSocketTestMixin):[](#l4.122)
- """Mixin to allow client/server stream tests with connected client.
- Server's socket representing connection to client is self.cli_conn
- and client's connection to server is self.serv_conn. (Based on
- SocketConnectedTest.)
- """
- def setUp(self):
super().setUp()[](#l4.131)
# Indicate explicitly we're ready for the client thread to[](#l4.132)
# proceed and then perform the blocking call to accept[](#l4.133)
self.serverExplicitReady()[](#l4.134)
conn, addr = self.serv.accept()[](#l4.135)
self.cli_conn = conn[](#l4.136)
- def tearDown(self):
self.cli_conn.close()[](#l4.139)
self.cli_conn = None[](#l4.140)
super().tearDown()[](#l4.141)
- def clientSetUp(self):
super().clientSetUp()[](#l4.144)
self.cli.connect(self.serv_addr)[](#l4.145)
self.serv_conn = self.cli[](#l4.146)
- def clientTearDown(self):
self.serv_conn.close()[](#l4.149)
self.serv_conn = None[](#l4.150)
super().clientTearDown()[](#l4.151)
+ + +class UnixSocketTestBase(SocketTestBase):
This class is used for file descriptor passing tests, so we
create the sockets in a private directory so that other users
can't send anything that might be problematic for a privileged
user running the tests.
- def setUp(self):
self.dir_path = tempfile.mkdtemp()[](#l4.163)
self.addCleanup(os.rmdir, self.dir_path)[](#l4.164)
super().setUp()[](#l4.165)
- def bindSock(self, sock):
path = tempfile.mktemp(dir=self.dir_path)[](#l4.168)
sock.bind(path)[](#l4.169)
self.addCleanup(support.unlink, path)[](#l4.170)
+ +class UnixStreamBase(UnixSocketTestBase):
+ + +class InetTestBase(SocketTestBase):
+ +class TCPTestBase(InetTestBase):
+ +class UDPTestBase(InetTestBase):
+ +class SCTPStreamBase(InetTestBase):
- def newSocket(self):
return socket.socket(socket.AF_INET, socket.SOCK_STREAM,[](#l4.207)
socket.IPPROTO_SCTP)[](#l4.208)
+ + +class Inet6TestBase(InetTestBase):
Don't use "localhost" here - it may not have an IPv6 address
assigned to it by default (e.g. in /etc/hosts), and if someone
has assigned it an IPv4-mapped address, then it's unlikely to
work with the full IPv6 API.
- host = "::1"
+ +class UDP6TestBase(Inet6TestBase):
+ + +# Test-skipping decorators for use with ThreadableTest. + +def skipWithClientIf(condition, reason):
- If the decorated object is not a class, sets its attribute
- "client_skip" to a decorator which will return an empty function
- if the test is to be skipped, or the original function if it is
- not. This can be used to avoid running the client part of a
- skipped test when using ThreadableTest.
- """
- def client_pass(*args, **kwargs):
pass[](#l4.239)
- def skipdec(obj):
retval = unittest.skip(reason)(obj)[](#l4.241)
if not isinstance(obj, type):[](#l4.242)
retval.client_skip = lambda f: client_pass[](#l4.243)
return retval[](#l4.244)
- def noskipdec(obj):
if not (isinstance(obj, type) or hasattr(obj, "client_skip")):[](#l4.246)
obj.client_skip = lambda f: f[](#l4.247)
return obj[](#l4.248)
- return skipdec if condition else noskipdec
+ + +def requireAttrs(obj, *attributes):
- Sets client_skip attribute as skipWithClientIf() does.
- """
- missing = [name for name in attributes if not hasattr(obj, name)]
- return skipWithClientIf(
missing, "don't have " + ", ".join(name for name in missing))[](#l4.259)
+ + +def requireSocket(*args):
- When an argument is given as a string, will use the value of that
- attribute of the socket module, or skip the test if it doesn't
- exist. Sets client_skip attribute as skipWithClientIf() does.
- """
- err = None
- missing = [obj for obj in args if
isinstance(obj, str) and not hasattr(socket, obj)][](#l4.271)
- if missing:
err = "don't have " + ", ".join(name for name in missing)[](#l4.273)
- else:
callargs = [getattr(socket, obj) if isinstance(obj, str) else obj[](#l4.275)
for obj in args][](#l4.276)
try:[](#l4.277)
s = socket.socket(*callargs)[](#l4.278)
except socket.error as e:[](#l4.279)
# XXX: check errno?[](#l4.280)
err = str(e)[](#l4.281)
else:[](#l4.282)
s.close()[](#l4.283)
- return skipWithClientIf(
err is not None,[](#l4.285)
"can't create socket({0}): {1}".format([](#l4.286)
", ".join(str(o) for o in args), err))[](#l4.287)
+ + #######################################################################
Begin Tests
@@ -945,6 +1207,1839 @@ class BasicUDPTest(ThreadedUDPSocketTest def _testRecvFromNegative(self): self.cli.sendto(MSG, 0, (HOST, self.port)) + +# Tests for the sendmsg()/recvmsg() interface. Where possible, the +# same test code is used with different families and types of socket +# (e.g. stream, datagram), and tests using recvmsg() are repeated +# using recvmsg_into(). +# +# The generic test classes such as SendmsgTests and +# RecvmsgGenericTests inherit from SendrecvmsgBase and expect to be +# supplied with sockets cli_sock and serv_sock representing the +# client's and the server's end of the connection respectively, and +# attributes cli_addr and serv_addr holding their (numeric where +# appropriate) addresses. +# +# The final concrete test classes combine these with subclasses of +# SocketTestBase which set up client and server sockets of a specific +# type, and with subclasses of SendrecvmsgBase such as +# SendrecvmsgDgramBase and SendrecvmsgConnectedBase which map these +# sockets to cli_sock and serv_sock and override the methods and +# attributes of SendrecvmsgBase to fill in destination addresses if +# needed when sending, check for specific flags in msg_flags, etc. +# +# RecvmsgIntoMixin provides a version of doRecvmsg() implemented using +# recvmsg_into(). + +# XXX: like the other datagram (UDP) tests in this module, the code +# here assumes that datagram delivery on the local machine will be +# reliable. + +class SendrecvmsgBase(ThreadSafeCleanupTestCase):
Time in seconds to wait before considering a test failed, or
None for no timeout. Not all tests actually set a timeout.
- fail_timeout = 3.0
- def sendToServer(self, msg):
# Send msg to the server.[](#l4.337)
return self.cli_sock.send(msg)[](#l4.338)
Tuple of alternative default arguments for sendmsg() when called
via sendmsgToServer() (e.g. to include a destination address).
- sendmsg_to_server_defaults = ()
- def sendmsgToServer(self, *args):
# Call sendmsg() on self.cli_sock with the given arguments,[](#l4.345)
# filling in any arguments which are not supplied with the[](#l4.346)
# corresponding items of self.sendmsg_to_server_defaults, if[](#l4.347)
# any.[](#l4.348)
return self.cli_sock.sendmsg([](#l4.349)
*(args + self.sendmsg_to_server_defaults[len(args):]))[](#l4.350)
- def doRecvmsg(self, sock, bufsize, *args):
# Call recvmsg() on sock with given arguments and return its[](#l4.353)
# result. Should be used for tests which can use either[](#l4.354)
# recvmsg() or recvmsg_into() - RecvmsgIntoMixin overrides[](#l4.355)
# this method with one which emulates it using recvmsg_into(),[](#l4.356)
# thus allowing the same test to be used for both methods.[](#l4.357)
result = sock.recvmsg(bufsize, *args)[](#l4.358)
self.registerRecvmsgResult(result)[](#l4.359)
return result[](#l4.360)
- def registerRecvmsgResult(self, result):
# Called by doRecvmsg() with the return value of recvmsg() or[](#l4.363)
# recvmsg_into(). Can be overridden to arrange cleanup based[](#l4.364)
# on the returned ancillary data, for instance.[](#l4.365)
pass[](#l4.366)
- def checkRecvmsgAddress(self, addr1, addr2):
# Called to compare the received address with the address of[](#l4.369)
# the peer.[](#l4.370)
self.assertEqual(addr1, addr2)[](#l4.371)
Flags that are normally unset in msg_flags
- msg_flags_common_unset = 0
- for name in ("MSG_CTRUNC", "MSG_OOB"):
msg_flags_common_unset |= getattr(socket, name, 0)[](#l4.376)
Flags set when a complete record has been received (e.g. MSG_EOR
for SCTP)
- msg_flags_eor_indicator = 0
Flags set when a complete record has not been received
(e.g. MSG_TRUNC for datagram sockets)
- msg_flags_non_eor_indicator = 0
- def checkFlags(self, flags, eor=None, checkset=0, checkunset=0, ignore=0):
# Method to check the value of msg_flags returned by recvmsg[_into]().[](#l4.390)
#[](#l4.391)
# Checks that all bits in msg_flags_common_set attribute are[](#l4.392)
# set in "flags" and all bits in msg_flags_common_unset are[](#l4.393)
# unset.[](#l4.394)
#[](#l4.395)
# The "eor" argument specifies whether the flags should[](#l4.396)
# indicate that a full record (or datagram) has been received.[](#l4.397)
# If "eor" is None, no checks are done; otherwise, checks[](#l4.398)
# that:[](#l4.399)
#[](#l4.400)
# * if "eor" is true, all bits in msg_flags_eor_indicator are[](#l4.401)
# set and all bits in msg_flags_non_eor_indicator are unset[](#l4.402)
#[](#l4.403)
# * if "eor" is false, all bits in msg_flags_non_eor_indicator[](#l4.404)
# are set and all bits in msg_flags_eor_indicator are unset[](#l4.405)
#[](#l4.406)
# If "checkset" and/or "checkunset" are supplied, they require[](#l4.407)
# the given bits to be set or unset respectively, overriding[](#l4.408)
# what the attributes require for those bits.[](#l4.409)
#[](#l4.410)
# If any bits are set in "ignore", they will not be checked,[](#l4.411)
# regardless of the other inputs.[](#l4.412)
#[](#l4.413)
# Will raise Exception if the inputs require a bit to be both[](#l4.414)
# set and unset, and it is not ignored.[](#l4.415)
defaultset = self.msg_flags_common_set[](#l4.417)
defaultunset = self.msg_flags_common_unset[](#l4.418)
if eor:[](#l4.420)
defaultset |= self.msg_flags_eor_indicator[](#l4.421)
defaultunset |= self.msg_flags_non_eor_indicator[](#l4.422)
elif eor is not None:[](#l4.423)
defaultset |= self.msg_flags_non_eor_indicator[](#l4.424)
defaultunset |= self.msg_flags_eor_indicator[](#l4.425)
# Function arguments override defaults[](#l4.427)
defaultset &= ~checkunset[](#l4.428)
defaultunset &= ~checkset[](#l4.429)
# Merge arguments with remaining defaults, and check for conflicts[](#l4.431)
checkset |= defaultset[](#l4.432)
checkunset |= defaultunset[](#l4.433)
inboth = checkset & checkunset & ~ignore[](#l4.434)
if inboth:[](#l4.435)
raise Exception("contradictory set, unset requirements for flags "[](#l4.436)
"{0:#x}".format(inboth))[](#l4.437)
# Compare with given msg_flags value[](#l4.439)
mask = (checkset | checkunset) & ~ignore[](#l4.440)
self.assertEqual(flags & mask, checkset & mask)[](#l4.441)
+ + +class RecvmsgIntoMixin(SendrecvmsgBase):
- def doRecvmsg(self, sock, bufsize, *args):
buf = bytearray(bufsize)[](#l4.448)
result = sock.recvmsg_into([buf], *args)[](#l4.449)
self.registerRecvmsgResult(result)[](#l4.450)
self.assertGreaterEqual(result[0], 0)[](#l4.451)
self.assertLessEqual(result[0], bufsize)[](#l4.452)
return (bytes(buf[:result[0]]),) + result[1:][](#l4.453)
+ + +class SendrecvmsgDgramFlagsBase(SendrecvmsgBase):
- @property
- def msg_flags_non_eor_indicator(self):
return super().msg_flags_non_eor_indicator | socket.MSG_TRUNC[](#l4.461)
+ + +class SendrecvmsgSCTPFlagsBase(SendrecvmsgBase):
- @property
- def msg_flags_eor_indicator(self):
return super().msg_flags_eor_indicator | socket.MSG_EOR[](#l4.469)
+ + +class SendrecvmsgConnectionlessBase(SendrecvmsgBase):
Base class for tests on connectionless-mode sockets. Users must
supply sockets on attributes cli and serv to be mapped to
cli_sock and serv_sock respectively.
+ + +class SendrecvmsgConnectedBase(SendrecvmsgBase):
Base class for tests on connected sockets. Users must supply
sockets on attributes serv_conn and cli_conn (representing the
connections to the server and the client), to be mapped to
cli_sock and serv_sock respectively.
- def checkRecvmsgAddress(self, addr1, addr2):
# Address is currently "unspecified" for a connected socket,[](#l4.508)
# so we don't examine it[](#l4.509)
pass[](#l4.510)
+ + +class SendrecvmsgServerTimeoutBase(SendrecvmsgBase):
+ + +class SendmsgTests(SendrecvmsgServerTimeoutBase):
- def testSendmsg(self):
# Send a simple message with sendmsg().[](#l4.526)
self.assertEqual(self.serv_sock.recv(len(MSG)), MSG)[](#l4.527)
- def testSendmsgDataGenerator(self):
# Send from buffer obtained from a generator (not a sequence).[](#l4.533)
self.assertEqual(self.serv_sock.recv(len(MSG)), MSG)[](#l4.534)
- def _testSendmsgDataGenerator(self):
self.assertEqual(self.sendmsgToServer((o for o in [MSG])),[](#l4.537)
len(MSG))[](#l4.538)
- def testSendmsgAncillaryGenerator(self):
# Gather (empty) ancillary data from a generator.[](#l4.541)
self.assertEqual(self.serv_sock.recv(len(MSG)), MSG)[](#l4.542)
- def _testSendmsgAncillaryGenerator(self):
self.assertEqual(self.sendmsgToServer([MSG], (o for o in [])),[](#l4.545)
len(MSG))[](#l4.546)
- def testSendmsgArray(self):
# Send data from an array instead of the usual bytes object.[](#l4.549)
self.assertEqual(self.serv_sock.recv(len(MSG)), MSG)[](#l4.550)
- def _testSendmsgArray(self):
self.assertEqual(self.sendmsgToServer([array.array("B", MSG)]),[](#l4.553)
len(MSG))[](#l4.554)
- def testSendmsgGather(self):
# Send message data from more than one buffer (gather write).[](#l4.557)
self.assertEqual(self.serv_sock.recv(len(MSG)), MSG)[](#l4.558)
- def _testSendmsgGather(self):
self.assertEqual(self.sendmsgToServer([MSG[:3], MSG[3:]]), len(MSG))[](#l4.561)
- def testSendmsgBadArgs(self):
# Check that sendmsg() rejects invalid arguments.[](#l4.564)
self.assertEqual(self.serv_sock.recv(1000), b"done")[](#l4.565)
- def _testSendmsgBadArgs(self):
self.assertRaises(TypeError, self.cli_sock.sendmsg)[](#l4.568)
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.569)
b"not in an iterable")[](#l4.570)
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.571)
object())[](#l4.572)
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.573)
[object()])[](#l4.574)
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.575)
[MSG, object()])[](#l4.576)
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.577)
[MSG], object())[](#l4.578)
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.579)
[MSG], [], object())[](#l4.580)
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.581)
[MSG], [], 0, object())[](#l4.582)
self.sendToServer(b"done")[](#l4.583)
- def testSendmsgBadCmsg(self):
# Check that invalid ancillary data items are rejected.[](#l4.586)
self.assertEqual(self.serv_sock.recv(1000), b"done")[](#l4.587)
- def _testSendmsgBadCmsg(self):
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.590)
[MSG], [object()])[](#l4.591)
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.592)
[MSG], [(object(), 0, b"data")])[](#l4.593)
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.594)
[MSG], [(0, object(), b"data")])[](#l4.595)
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.596)
[MSG], [(0, 0, object())])[](#l4.597)
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.598)
[MSG], [(0, 0)])[](#l4.599)
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.600)
[MSG], [(0, 0, b"data", 42)])[](#l4.601)
self.sendToServer(b"done")[](#l4.602)
- @requireAttrs(socket, "CMSG_SPACE")
- def testSendmsgBadMultiCmsg(self):
# Check that invalid ancillary data items are rejected when[](#l4.606)
# more than one item is present.[](#l4.607)
self.assertEqual(self.serv_sock.recv(1000), b"done")[](#l4.608)
- @testSendmsgBadMultiCmsg.client_skip
- def _testSendmsgBadMultiCmsg(self):
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.612)
[MSG], [0, 0, b""])[](#l4.613)
self.assertRaises(TypeError, self.sendmsgToServer,[](#l4.614)
[MSG], [(0, 0, b""), object()])[](#l4.615)
self.sendToServer(b"done")[](#l4.616)
- def testSendmsgExcessCmsgReject(self):
# Check that sendmsg() rejects excess ancillary data items[](#l4.619)
# when the number that can be sent is limited.[](#l4.620)
self.assertEqual(self.serv_sock.recv(1000), b"done")[](#l4.621)
- def _testSendmsgExcessCmsgReject(self):
if not hasattr(socket, "CMSG_SPACE"):[](#l4.624)
# Can only send one item[](#l4.625)
with self.assertRaises(socket.error) as cm:[](#l4.626)
self.sendmsgToServer([MSG], [(0, 0, b""), (0, 0, b"")])[](#l4.627)
self.assertIsNone(cm.exception.errno)[](#l4.628)
self.sendToServer(b"done")[](#l4.629)
- def testSendmsgAfterClose(self):
# Check that sendmsg() fails on a closed socket.[](#l4.632)
pass[](#l4.633)
- def _testSendmsgAfterClose(self):
self.cli_sock.close()[](#l4.636)
self.assertRaises(socket.error, self.sendmsgToServer, [MSG])[](#l4.637)
+ + +class SendmsgStreamTests(SendmsgTests):
- def testSendmsgExplicitNoneAddr(self):
# Check that peer address can be specified as None.[](#l4.645)
self.assertEqual(self.serv_sock.recv(len(MSG)), MSG)[](#l4.646)
- def _testSendmsgExplicitNoneAddr(self):
self.assertEqual(self.sendmsgToServer([MSG], [], 0, None), len(MSG))[](#l4.649)
- def testSendmsgTimeout(self):
# Check that timeout works with sendmsg().[](#l4.652)
self.assertEqual(self.serv_sock.recv(512), b"a"*512)[](#l4.653)
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.654)
- def _testSendmsgTimeout(self):
try:[](#l4.657)
self.cli_sock.settimeout(0.03)[](#l4.658)
with self.assertRaises(socket.timeout):[](#l4.659)
while True:[](#l4.660)
self.sendmsgToServer([b"a"*512])[](#l4.661)
finally:[](#l4.662)
self.misc_event.set()[](#l4.663)
Linux supports MSG_DONTWAIT when sending, but in general, it
only works when receiving. Could add other platforms if they
support it too.
- @skipWithClientIf(sys.platform not in {"linux2"},
"MSG_DONTWAIT not known to work on this platform when "[](#l4.671)
"sending")[](#l4.672)
- def testSendmsgDontWait(self):
# Check that MSG_DONTWAIT in flags causes non-blocking behaviour.[](#l4.674)
self.assertEqual(self.serv_sock.recv(512), b"a"*512)[](#l4.675)
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.676)
- @testSendmsgDontWait.client_skip
- def _testSendmsgDontWait(self):
try:[](#l4.680)
with self.assertRaises(socket.error) as cm:[](#l4.681)
while True:[](#l4.682)
self.sendmsgToServer([b"a"*512], [], socket.MSG_DONTWAIT)[](#l4.683)
self.assertIn(cm.exception.errno,[](#l4.684)
(errno.EAGAIN, errno.EWOULDBLOCK))[](#l4.685)
finally:[](#l4.686)
self.misc_event.set()[](#l4.687)
+ + +class SendmsgConnectionlessTests(SendmsgTests):
Tests for sendmsg() which require a connectionless-mode
(e.g. datagram) socket, and do not involve recvmsg() or
recvmsg_into().
- def testSendmsgNoDestAddr(self):
# Check that sendmsg() fails when no destination address is[](#l4.696)
# given for unconnected socket.[](#l4.697)
pass[](#l4.698)
- def _testSendmsgNoDestAddr(self):
self.assertRaises(socket.error, self.cli_sock.sendmsg,[](#l4.701)
[MSG])[](#l4.702)
self.assertRaises(socket.error, self.cli_sock.sendmsg,[](#l4.703)
[MSG], [], 0, None)[](#l4.704)
+ + +class RecvmsgGenericTests(SendrecvmsgBase):
- def testRecvmsg(self):
# Receive a simple message with recvmsg[_into]().[](#l4.712)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock, len(MSG))[](#l4.713)
self.assertEqual(msg, MSG)[](#l4.714)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.715)
self.assertEqual(ancdata, [])[](#l4.716)
self.checkFlags(flags, eor=True)[](#l4.717)
- def testRecvmsgExplicitDefaults(self):
# Test recvmsg[_into]() with default arguments provided explicitly.[](#l4.723)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.724)
len(MSG), 0, 0)[](#l4.725)
self.assertEqual(msg, MSG)[](#l4.726)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.727)
self.assertEqual(ancdata, [])[](#l4.728)
self.checkFlags(flags, eor=True)[](#l4.729)
- def testRecvmsgShorter(self):
# Receive a message smaller than buffer.[](#l4.735)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.736)
len(MSG) + 42)[](#l4.737)
self.assertEqual(msg, MSG)[](#l4.738)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.739)
self.assertEqual(ancdata, [])[](#l4.740)
self.checkFlags(flags, eor=True)[](#l4.741)
- def testRecvmsgTrunc(self):
# Receive part of message, check for truncation indicators.[](#l4.747)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.748)
len(MSG) - 3)[](#l4.749)
self.assertEqual(msg, MSG[:-3])[](#l4.750)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.751)
self.assertEqual(ancdata, [])[](#l4.752)
self.checkFlags(flags, eor=False)[](#l4.753)
- def testRecvmsgShortAncillaryBuf(self):
# Test ancillary data buffer too small to hold any ancillary data.[](#l4.759)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.760)
len(MSG), 1)[](#l4.761)
self.assertEqual(msg, MSG)[](#l4.762)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.763)
self.assertEqual(ancdata, [])[](#l4.764)
self.checkFlags(flags, eor=True)[](#l4.765)
- def testRecvmsgLongAncillaryBuf(self):
# Test large ancillary data buffer.[](#l4.771)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.772)
len(MSG), 10240)[](#l4.773)
self.assertEqual(msg, MSG)[](#l4.774)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.775)
self.assertEqual(ancdata, [])[](#l4.776)
self.checkFlags(flags, eor=True)[](#l4.777)
- def testRecvmsgAfterClose(self):
# Check that recvmsg[_into]() fails on a closed socket.[](#l4.783)
self.serv_sock.close()[](#l4.784)
self.assertRaises(socket.error, self.doRecvmsg, self.serv_sock, 1024)[](#l4.785)
- def testRecvmsgTimeout(self):
# Check that timeout works.[](#l4.791)
try:[](#l4.792)
self.serv_sock.settimeout(0.03)[](#l4.793)
self.assertRaises(socket.timeout,[](#l4.794)
self.doRecvmsg, self.serv_sock, len(MSG))[](#l4.795)
finally:[](#l4.796)
self.misc_event.set()[](#l4.797)
- def _testRecvmsgTimeout(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.800)
- @requireAttrs(socket, "MSG_PEEK")
- def testRecvmsgPeek(self):
# Check that MSG_PEEK in flags enables examination of pending[](#l4.804)
# data without consuming it.[](#l4.805)
# Receive part of data with MSG_PEEK.[](#l4.807)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.808)
len(MSG) - 3, 0,[](#l4.809)
socket.MSG_PEEK)[](#l4.810)
self.assertEqual(msg, MSG[:-3])[](#l4.811)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.812)
self.assertEqual(ancdata, [])[](#l4.813)
# Ignoring MSG_TRUNC here (so this test is the same for stream[](#l4.814)
# and datagram sockets). Some wording in POSIX seems to[](#l4.815)
# suggest that it needn't be set when peeking, but that may[](#l4.816)
# just be a slip.[](#l4.817)
self.checkFlags(flags, eor=False,[](#l4.818)
ignore=getattr(socket, "MSG_TRUNC", 0))[](#l4.819)
# Receive all data with MSG_PEEK.[](#l4.821)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.822)
len(MSG), 0,[](#l4.823)
socket.MSG_PEEK)[](#l4.824)
self.assertEqual(msg, MSG)[](#l4.825)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.826)
self.assertEqual(ancdata, [])[](#l4.827)
self.checkFlags(flags, eor=True)[](#l4.828)
# Check that the same data can still be received normally.[](#l4.830)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock, len(MSG))[](#l4.831)
self.assertEqual(msg, MSG)[](#l4.832)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.833)
self.assertEqual(ancdata, [])[](#l4.834)
self.checkFlags(flags, eor=True)[](#l4.835)
- @requireAttrs(socket.socket, "sendmsg")
- def testRecvmsgFromSendmsg(self):
# Test receiving with recvmsg[_into]() when message is sent[](#l4.843)
# using sendmsg().[](#l4.844)
self.serv_sock.settimeout(self.fail_timeout)[](#l4.845)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock, len(MSG))[](#l4.846)
self.assertEqual(msg, MSG)[](#l4.847)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.848)
self.assertEqual(ancdata, [])[](#l4.849)
self.checkFlags(flags, eor=True)[](#l4.850)
- @testRecvmsgFromSendmsg.client_skip
- def _testRecvmsgFromSendmsg(self):
self.assertEqual(self.sendmsgToServer([MSG[:3], MSG[3:]]), len(MSG))[](#l4.854)
+ + +class RecvmsgGenericStreamTests(RecvmsgGenericTests):
- def testRecvmsgEOF(self):
# Receive end-of-stream indicator (b"", peer socket closed).[](#l4.862)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock, 1024)[](#l4.863)
self.assertEqual(msg, b"")[](#l4.864)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.865)
self.assertEqual(ancdata, [])[](#l4.866)
self.checkFlags(flags, eor=None) # Might not have end-of-record marker[](#l4.867)
- def testRecvmsgOverflow(self):
# Receive a message in more than one chunk.[](#l4.873)
seg1, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.874)
len(MSG) - 3)[](#l4.875)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.876)
self.assertEqual(ancdata, [])[](#l4.877)
self.checkFlags(flags, eor=False)[](#l4.878)
seg2, ancdata, flags, addr = self.doRecvmsg(self.serv_sock, 1024)[](#l4.880)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.881)
self.assertEqual(ancdata, [])[](#l4.882)
self.checkFlags(flags, eor=True)[](#l4.883)
msg = seg1 + seg2[](#l4.885)
self.assertEqual(msg, MSG)[](#l4.886)
+ + +class RecvmsgTests(RecvmsgGenericTests):
- def testRecvmsgBadArgs(self):
# Check that recvmsg() rejects invalid arguments.[](#l4.896)
self.assertRaises(TypeError, self.serv_sock.recvmsg)[](#l4.897)
self.assertRaises(ValueError, self.serv_sock.recvmsg,[](#l4.898)
-1, 0, 0)[](#l4.899)
self.assertRaises(ValueError, self.serv_sock.recvmsg,[](#l4.900)
len(MSG), -1, 0)[](#l4.901)
self.assertRaises(TypeError, self.serv_sock.recvmsg,[](#l4.902)
[bytearray(10)], 0, 0)[](#l4.903)
self.assertRaises(TypeError, self.serv_sock.recvmsg,[](#l4.904)
object(), 0, 0)[](#l4.905)
self.assertRaises(TypeError, self.serv_sock.recvmsg,[](#l4.906)
len(MSG), object(), 0)[](#l4.907)
self.assertRaises(TypeError, self.serv_sock.recvmsg,[](#l4.908)
len(MSG), 0, object())[](#l4.909)
msg, ancdata, flags, addr = self.serv_sock.recvmsg(len(MSG), 0, 0)[](#l4.911)
self.assertEqual(msg, MSG)[](#l4.912)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.913)
self.assertEqual(ancdata, [])[](#l4.914)
self.checkFlags(flags, eor=True)[](#l4.915)
+ + +class RecvmsgIntoTests(RecvmsgIntoMixin, RecvmsgGenericTests):
- def testRecvmsgIntoBadArgs(self):
# Check that recvmsg_into() rejects invalid arguments.[](#l4.925)
buf = bytearray(len(MSG))[](#l4.926)
self.assertRaises(TypeError, self.serv_sock.recvmsg_into)[](#l4.927)
self.assertRaises(TypeError, self.serv_sock.recvmsg_into,[](#l4.928)
len(MSG), 0, 0)[](#l4.929)
self.assertRaises(TypeError, self.serv_sock.recvmsg_into,[](#l4.930)
buf, 0, 0)[](#l4.931)
self.assertRaises(TypeError, self.serv_sock.recvmsg_into,[](#l4.932)
[object()], 0, 0)[](#l4.933)
self.assertRaises(TypeError, self.serv_sock.recvmsg_into,[](#l4.934)
[b"I'm not writable"], 0, 0)[](#l4.935)
self.assertRaises(TypeError, self.serv_sock.recvmsg_into,[](#l4.936)
[buf, object()], 0, 0)[](#l4.937)
self.assertRaises(ValueError, self.serv_sock.recvmsg_into,[](#l4.938)
[buf], -1, 0)[](#l4.939)
self.assertRaises(TypeError, self.serv_sock.recvmsg_into,[](#l4.940)
[buf], object(), 0)[](#l4.941)
self.assertRaises(TypeError, self.serv_sock.recvmsg_into,[](#l4.942)
[buf], 0, object())[](#l4.943)
nbytes, ancdata, flags, addr = self.serv_sock.recvmsg_into([buf], 0, 0)[](#l4.945)
self.assertEqual(nbytes, len(MSG))[](#l4.946)
self.assertEqual(buf, bytearray(MSG))[](#l4.947)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.948)
self.assertEqual(ancdata, [])[](#l4.949)
self.checkFlags(flags, eor=True)[](#l4.950)
- def testRecvmsgIntoGenerator(self):
# Receive into buffer obtained from a generator (not a sequence).[](#l4.956)
buf = bytearray(len(MSG))[](#l4.957)
nbytes, ancdata, flags, addr = self.serv_sock.recvmsg_into([](#l4.958)
(o for o in [buf]))[](#l4.959)
self.assertEqual(nbytes, len(MSG))[](#l4.960)
self.assertEqual(buf, bytearray(MSG))[](#l4.961)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.962)
self.assertEqual(ancdata, [])[](#l4.963)
self.checkFlags(flags, eor=True)[](#l4.964)
- def testRecvmsgIntoArray(self):
# Receive into an array rather than the usual bytearray.[](#l4.970)
buf = array.array("B", [0] * len(MSG))[](#l4.971)
nbytes, ancdata, flags, addr = self.serv_sock.recvmsg_into([buf])[](#l4.972)
self.assertEqual(nbytes, len(MSG))[](#l4.973)
self.assertEqual(buf.tostring(), MSG)[](#l4.974)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.975)
self.assertEqual(ancdata, [])[](#l4.976)
self.checkFlags(flags, eor=True)[](#l4.977)
- def testRecvmsgIntoScatter(self):
# Receive into multiple buffers (scatter write).[](#l4.983)
b1 = bytearray(b"----")[](#l4.984)
b2 = bytearray(b"0123456789")[](#l4.985)
b3 = bytearray(b"--------------")[](#l4.986)
nbytes, ancdata, flags, addr = self.serv_sock.recvmsg_into([](#l4.987)
[b1, memoryview(b2)[2:9], b3])[](#l4.988)
self.assertEqual(nbytes, len(b"Mary had a little lamb"))[](#l4.989)
self.assertEqual(b1, bytearray(b"Mary"))[](#l4.990)
self.assertEqual(b2, bytearray(b"01 had a 9"))[](#l4.991)
self.assertEqual(b3, bytearray(b"little lamb---"))[](#l4.992)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.993)
self.assertEqual(ancdata, [])[](#l4.994)
self.checkFlags(flags, eor=True)[](#l4.995)
+ + +class CmsgMacroTests(unittest.TestCase):
Test the functions CMSG_LEN() and CMSG_SPACE(). Tests
_into, which share
assumptions used by sendmsg() and recvmsgcode with these functions.
- @requireAttrs(socket, "CMSG_LEN")
- def testCMSG_LEN(self):
# Test CMSG_LEN() with various valid and invalid values,[](#l4.1011)
# checking the assumptions used by recvmsg() and sendmsg().[](#l4.1012)
toobig = self.socklen_t_limit - socket.CMSG_LEN(0) + 1[](#l4.1013)
values = list(range(257)) + list(range(toobig - 257, toobig))[](#l4.1014)
# struct cmsghdr has at least three members, two of which are ints[](#l4.1016)
self.assertGreater(socket.CMSG_LEN(0), array.array("i").itemsize * 2)[](#l4.1017)
for n in values:[](#l4.1018)
ret = socket.CMSG_LEN(n)[](#l4.1019)
# This is how recvmsg() calculates the data size[](#l4.1020)
self.assertEqual(ret - socket.CMSG_LEN(0), n)[](#l4.1021)
self.assertLessEqual(ret, self.socklen_t_limit)[](#l4.1022)
self.assertRaises(OverflowError, socket.CMSG_LEN, -1)[](#l4.1024)
# sendmsg() shares code with these functions, and requires[](#l4.1025)
# that it reject values over the limit.[](#l4.1026)
self.assertRaises(OverflowError, socket.CMSG_LEN, toobig)[](#l4.1027)
self.assertRaises(OverflowError, socket.CMSG_LEN, sys.maxsize)[](#l4.1028)
- @requireAttrs(socket, "CMSG_SPACE")
- def testCMSG_SPACE(self):
# Test CMSG_SPACE() with various valid and invalid values,[](#l4.1032)
# checking the assumptions used by sendmsg().[](#l4.1033)
toobig = self.socklen_t_limit - socket.CMSG_SPACE(1) + 1[](#l4.1034)
values = list(range(257)) + list(range(toobig - 257, toobig))[](#l4.1035)
last = socket.CMSG_SPACE(0)[](#l4.1037)
# struct cmsghdr has at least three members, two of which are ints[](#l4.1038)
self.assertGreater(last, array.array("i").itemsize * 2)[](#l4.1039)
for n in values:[](#l4.1040)
ret = socket.CMSG_SPACE(n)[](#l4.1041)
self.assertGreaterEqual(ret, last)[](#l4.1042)
self.assertGreaterEqual(ret, socket.CMSG_LEN(n))[](#l4.1043)
self.assertGreaterEqual(ret, n + socket.CMSG_LEN(0))[](#l4.1044)
self.assertLessEqual(ret, self.socklen_t_limit)[](#l4.1045)
last = ret[](#l4.1046)
self.assertRaises(OverflowError, socket.CMSG_SPACE, -1)[](#l4.1048)
# sendmsg() shares code with these functions, and requires[](#l4.1049)
# that it reject values over the limit.[](#l4.1050)
self.assertRaises(OverflowError, socket.CMSG_SPACE, toobig)[](#l4.1051)
self.assertRaises(OverflowError, socket.CMSG_SPACE, sys.maxsize)[](#l4.1052)
+ + +class SCMRightsTest(SendrecvmsgServerTimeoutBase):
Invalid file descriptor value that's unlikely to evaluate to a
real FD even if one of its bytes is replaced with a different
value (which shouldn't actually happen).
- badfd = -0x5555
- def newFDs(self, n):
# Return a list of n file descriptors for newly-created files[](#l4.1064)
# containing their list indices as ASCII numbers.[](#l4.1065)
fds = [][](#l4.1066)
for i in range(n):[](#l4.1067)
fd, path = tempfile.mkstemp()[](#l4.1068)
self.addCleanup(os.unlink, path)[](#l4.1069)
self.addCleanup(os.close, fd)[](#l4.1070)
os.write(fd, str(i).encode())[](#l4.1071)
fds.append(fd)[](#l4.1072)
return fds[](#l4.1073)
- def checkFDs(self, fds):
# Check that the file descriptors in the given list contain[](#l4.1076)
# their correct list indices as ASCII numbers.[](#l4.1077)
for n, fd in enumerate(fds):[](#l4.1078)
os.lseek(fd, 0, os.SEEK_SET)[](#l4.1079)
self.assertEqual(os.read(fd, 1024), str(n).encode())[](#l4.1080)
- def closeRecvmsgFDs(self, recvmsg_result):
# Close all file descriptors specified in the ancillary data[](#l4.1086)
# of the given return value from recvmsg() or recvmsg_into().[](#l4.1087)
for cmsg_level, cmsg_type, cmsg_data in recvmsg_result[1]:[](#l4.1088)
if (cmsg_level == socket.SOL_SOCKET and[](#l4.1089)
cmsg_type == socket.SCM_RIGHTS):[](#l4.1090)
fds = array.array("i")[](#l4.1091)
fds.fromstring(cmsg_data[:[](#l4.1092)
len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])[](#l4.1093)
for fd in fds:[](#l4.1094)
os.close(fd)[](#l4.1095)
- def createAndSendFDs(self, n):
# Send n new file descriptors created by newFDs() to the[](#l4.1098)
# server, with the constant MSG as the non-ancillary data.[](#l4.1099)
self.assertEqual([](#l4.1100)
self.sendmsgToServer([MSG],[](#l4.1101)
[(socket.SOL_SOCKET,[](#l4.1102)
socket.SCM_RIGHTS,[](#l4.1103)
array.array("i", self.newFDs(n)))]),[](#l4.1104)
len(MSG))[](#l4.1105)
- def checkRecvmsgFDs(self, numfds, result, maxcmsgs=1, ignoreflags=0):
# Check that constant MSG was received with numfds file[](#l4.1108)
# descriptors in a maximum of maxcmsgs control messages (which[](#l4.1109)
# must contain only complete integers). By default, check[](#l4.1110)
# that MSG_CTRUNC is unset, but ignore any flags in[](#l4.1111)
# ignoreflags.[](#l4.1112)
msg, ancdata, flags, addr = result[](#l4.1113)
self.assertEqual(msg, MSG)[](#l4.1114)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.1115)
self.checkFlags(flags, eor=True, checkunset=socket.MSG_CTRUNC,[](#l4.1116)
ignore=ignoreflags)[](#l4.1117)
self.assertIsInstance(ancdata, list)[](#l4.1119)
self.assertLessEqual(len(ancdata), maxcmsgs)[](#l4.1120)
fds = array.array("i")[](#l4.1121)
for item in ancdata:[](#l4.1122)
self.assertIsInstance(item, tuple)[](#l4.1123)
cmsg_level, cmsg_type, cmsg_data = item[](#l4.1124)
self.assertEqual(cmsg_level, socket.SOL_SOCKET)[](#l4.1125)
self.assertEqual(cmsg_type, socket.SCM_RIGHTS)[](#l4.1126)
self.assertIsInstance(cmsg_data, bytes)[](#l4.1127)
self.assertEqual(len(cmsg_data) % SIZEOF_INT, 0)[](#l4.1128)
fds.fromstring(cmsg_data)[](#l4.1129)
self.assertEqual(len(fds), numfds)[](#l4.1131)
self.checkFDs(fds)[](#l4.1132)
- def testFDPassSimple(self):
# Pass a single FD (array read from bytes object).[](#l4.1135)
self.checkRecvmsgFDs(1, self.doRecvmsg(self.serv_sock,[](#l4.1136)
len(MSG), 10240))[](#l4.1137)
- def _testFDPassSimple(self):
self.assertEqual([](#l4.1140)
self.sendmsgToServer([](#l4.1141)
[MSG],[](#l4.1142)
[(socket.SOL_SOCKET,[](#l4.1143)
socket.SCM_RIGHTS,[](#l4.1144)
array.array("i", self.newFDs(1)).tostring())]),[](#l4.1145)
len(MSG))[](#l4.1146)
- def testMultipleFDPass(self):
# Pass multiple FDs in a single array.[](#l4.1149)
self.checkRecvmsgFDs(4, self.doRecvmsg(self.serv_sock,[](#l4.1150)
len(MSG), 10240))[](#l4.1151)
- @requireAttrs(socket, "CMSG_SPACE")
- def testFDPassCMSG_SPACE(self):
# Test using CMSG_SPACE() to calculate ancillary buffer size.[](#l4.1158)
self.checkRecvmsgFDs([](#l4.1159)
4, self.doRecvmsg(self.serv_sock, len(MSG),[](#l4.1160)
socket.CMSG_SPACE(4 * SIZEOF_INT)))[](#l4.1161)
- @testFDPassCMSG_SPACE.client_skip
- def _testFDPassCMSG_SPACE(self):
self.createAndSendFDs(4)[](#l4.1165)
- def testFDPassCMSG_LEN(self):
# Test using CMSG_LEN() to calculate ancillary buffer size.[](#l4.1168)
self.checkRecvmsgFDs(1,[](#l4.1169)
self.doRecvmsg(self.serv_sock, len(MSG),[](#l4.1170)
socket.CMSG_LEN(4 * SIZEOF_INT)),[](#l4.1171)
# RFC 3542 says implementations may set[](#l4.1172)
# MSG_CTRUNC if there isn't enough space[](#l4.1173)
# for trailing padding.[](#l4.1174)
ignoreflags=socket.MSG_CTRUNC)[](#l4.1175)
- @requireAttrs(socket, "CMSG_SPACE")
- def testFDPassSeparate(self):
# Pass two FDs in two separate arrays. Arrays may be combined[](#l4.1182)
# into a single control message by the OS.[](#l4.1183)
self.checkRecvmsgFDs(2,[](#l4.1184)
self.doRecvmsg(self.serv_sock, len(MSG), 10240),[](#l4.1185)
maxcmsgs=2)[](#l4.1186)
- @testFDPassSeparate.client_skip
- def _testFDPassSeparate(self):
fd0, fd1 = self.newFDs(2)[](#l4.1190)
self.assertEqual([](#l4.1191)
self.sendmsgToServer([MSG], [(socket.SOL_SOCKET,[](#l4.1192)
socket.SCM_RIGHTS,[](#l4.1193)
array.array("i", [fd0])),[](#l4.1194)
(socket.SOL_SOCKET,[](#l4.1195)
socket.SCM_RIGHTS,[](#l4.1196)
array.array("i", [fd1]))]),[](#l4.1197)
len(MSG))[](#l4.1198)
- @requireAttrs(socket, "CMSG_SPACE")
- def testFDPassSeparateMinSpace(self):
# Pass two FDs in two separate arrays, receiving them into the[](#l4.1202)
# minimum space for two arrays.[](#l4.1203)
self.checkRecvmsgFDs(2,[](#l4.1204)
self.doRecvmsg(self.serv_sock, len(MSG),[](#l4.1205)
socket.CMSG_SPACE(SIZEOF_INT) +[](#l4.1206)
socket.CMSG_LEN(SIZEOF_INT)),[](#l4.1207)
maxcmsgs=2, ignoreflags=socket.MSG_CTRUNC)[](#l4.1208)
- @testFDPassSeparateMinSpace.client_skip
- def _testFDPassSeparateMinSpace(self):
fd0, fd1 = self.newFDs(2)[](#l4.1212)
self.assertEqual([](#l4.1213)
self.sendmsgToServer([MSG], [(socket.SOL_SOCKET,[](#l4.1214)
socket.SCM_RIGHTS,[](#l4.1215)
array.array("i", [fd0])),[](#l4.1216)
(socket.SOL_SOCKET,[](#l4.1217)
socket.SCM_RIGHTS,[](#l4.1218)
array.array("i", [fd1]))]),[](#l4.1219)
len(MSG))[](#l4.1220)
- def sendAncillaryIfPossible(self, msg, ancdata):
# Try to send msg and ancdata to server, but if the system[](#l4.1223)
# call fails, just send msg with no ancillary data.[](#l4.1224)
try:[](#l4.1225)
nbytes = self.sendmsgToServer([msg], ancdata)[](#l4.1226)
except socket.error as e:[](#l4.1227)
# Check that it was the system call that failed[](#l4.1228)
self.assertIsInstance(e.errno, int)[](#l4.1229)
nbytes = self.sendmsgToServer([msg])[](#l4.1230)
self.assertEqual(nbytes, len(msg))[](#l4.1231)
- def testFDPassEmpty(self):
# Try to pass an empty FD array. Can receive either no array[](#l4.1234)
# or an empty array.[](#l4.1235)
self.checkRecvmsgFDs(0, self.doRecvmsg(self.serv_sock,[](#l4.1236)
len(MSG), 10240),[](#l4.1237)
ignoreflags=socket.MSG_CTRUNC)[](#l4.1238)
- def _testFDPassEmpty(self):
self.sendAncillaryIfPossible(MSG, [(socket.SOL_SOCKET,[](#l4.1241)
socket.SCM_RIGHTS,[](#l4.1242)
b"")])[](#l4.1243)
- def testFDPassPartialInt(self):
# Try to pass a truncated FD array.[](#l4.1246)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.1247)
len(MSG), 10240)[](#l4.1248)
self.assertEqual(msg, MSG)[](#l4.1249)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.1250)
self.checkFlags(flags, eor=True, ignore=socket.MSG_CTRUNC)[](#l4.1251)
self.assertLessEqual(len(ancdata), 1)[](#l4.1252)
for cmsg_level, cmsg_type, cmsg_data in ancdata:[](#l4.1253)
self.assertEqual(cmsg_level, socket.SOL_SOCKET)[](#l4.1254)
self.assertEqual(cmsg_type, socket.SCM_RIGHTS)[](#l4.1255)
self.assertLess(len(cmsg_data), SIZEOF_INT)[](#l4.1256)
- def _testFDPassPartialInt(self):
self.sendAncillaryIfPossible([](#l4.1259)
MSG,[](#l4.1260)
[(socket.SOL_SOCKET,[](#l4.1261)
socket.SCM_RIGHTS,[](#l4.1262)
array.array("i", [self.badfd]).tostring()[:-1])])[](#l4.1263)
- @requireAttrs(socket, "CMSG_SPACE")
- def testFDPassPartialIntInMiddle(self):
# Try to pass two FD arrays, the first of which is truncated.[](#l4.1267)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.1268)
len(MSG), 10240)[](#l4.1269)
self.assertEqual(msg, MSG)[](#l4.1270)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.1271)
self.checkFlags(flags, eor=True, ignore=socket.MSG_CTRUNC)[](#l4.1272)
self.assertLessEqual(len(ancdata), 2)[](#l4.1273)
fds = array.array("i")[](#l4.1274)
# Arrays may have been combined in a single control message[](#l4.1275)
for cmsg_level, cmsg_type, cmsg_data in ancdata:[](#l4.1276)
self.assertEqual(cmsg_level, socket.SOL_SOCKET)[](#l4.1277)
self.assertEqual(cmsg_type, socket.SCM_RIGHTS)[](#l4.1278)
fds.fromstring(cmsg_data[:[](#l4.1279)
len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])[](#l4.1280)
self.assertLessEqual(len(fds), 2)[](#l4.1281)
self.checkFDs(fds)[](#l4.1282)
- @testFDPassPartialIntInMiddle.client_skip
- def _testFDPassPartialIntInMiddle(self):
fd0, fd1 = self.newFDs(2)[](#l4.1286)
self.sendAncillaryIfPossible([](#l4.1287)
MSG,[](#l4.1288)
[(socket.SOL_SOCKET,[](#l4.1289)
socket.SCM_RIGHTS,[](#l4.1290)
array.array("i", [fd0, self.badfd]).tostring()[:-1]),[](#l4.1291)
(socket.SOL_SOCKET,[](#l4.1292)
socket.SCM_RIGHTS,[](#l4.1293)
array.array("i", [fd1]))])[](#l4.1294)
- def checkTruncatedHeader(self, result, ignoreflags=0):
# Check that no ancillary data items are returned when data is[](#l4.1297)
# truncated inside the cmsghdr structure.[](#l4.1298)
msg, ancdata, flags, addr = result[](#l4.1299)
self.assertEqual(msg, MSG)[](#l4.1300)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.1301)
self.assertEqual(ancdata, [])[](#l4.1302)
self.checkFlags(flags, eor=True, checkset=socket.MSG_CTRUNC,[](#l4.1303)
ignore=ignoreflags)[](#l4.1304)
- def testCmsgTruncNoBufSize(self):
# Check that no ancillary data is received when no buffer size[](#l4.1307)
# is specified.[](#l4.1308)
self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG)),[](#l4.1309)
# BSD seems to set MSG_CTRUNC only[](#l4.1310)
# if an item has been partially[](#l4.1311)
# received.[](#l4.1312)
ignoreflags=socket.MSG_CTRUNC)[](#l4.1313)
- def testCmsgTrunc0(self):
# Check that no ancillary data is received when buffer size is 0.[](#l4.1319)
self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), 0),[](#l4.1320)
ignoreflags=socket.MSG_CTRUNC)[](#l4.1321)
- def testCmsgTrunc1(self):
self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG), 1))[](#l4.1330)
- def testCmsgTrunc2Int(self):
# The cmsghdr structure has at least three members, two of[](#l4.1336)
# which are ints, so we still shouldn't see any ancillary[](#l4.1337)
# data.[](#l4.1338)
self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG),[](#l4.1339)
SIZEOF_INT * 2))[](#l4.1340)
- def testCmsgTruncLen0Minus1(self):
self.checkTruncatedHeader(self.doRecvmsg(self.serv_sock, len(MSG),[](#l4.1346)
socket.CMSG_LEN(0) - 1))[](#l4.1347)
- def checkTruncatedArray(self, ancbuf, maxdata, mindata=0):
# Check that file descriptor data is truncated to between[](#l4.1356)
# mindata and maxdata bytes when received with buffer size[](#l4.1357)
# ancbuf, and that any complete file descriptor numbers are[](#l4.1358)
# valid.[](#l4.1359)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.1360)
len(MSG), ancbuf)[](#l4.1361)
self.assertEqual(msg, MSG)[](#l4.1362)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.1363)
self.checkFlags(flags, eor=True, checkset=socket.MSG_CTRUNC)[](#l4.1364)
if mindata == 0 and ancdata == []:[](#l4.1366)
return[](#l4.1367)
self.assertEqual(len(ancdata), 1)[](#l4.1368)
cmsg_level, cmsg_type, cmsg_data = ancdata[0][](#l4.1369)
self.assertEqual(cmsg_level, socket.SOL_SOCKET)[](#l4.1370)
self.assertEqual(cmsg_type, socket.SCM_RIGHTS)[](#l4.1371)
self.assertGreaterEqual(len(cmsg_data), mindata)[](#l4.1372)
self.assertLessEqual(len(cmsg_data), maxdata)[](#l4.1373)
fds = array.array("i")[](#l4.1374)
fds.fromstring(cmsg_data[:[](#l4.1375)
len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])[](#l4.1376)
self.checkFDs(fds)[](#l4.1377)
- def testCmsgTruncLen0(self):
self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0), maxdata=0)[](#l4.1380)
- def testCmsgTruncLen0Plus1(self):
self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(0) + 1, maxdata=1)[](#l4.1386)
- def testCmsgTruncLen1(self):
self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(SIZEOF_INT),[](#l4.1392)
maxdata=SIZEOF_INT)[](#l4.1393)
- def testCmsgTruncLen2Minus1(self):
self.checkTruncatedArray(ancbuf=socket.CMSG_LEN(2 * SIZEOF_INT) - 1,[](#l4.1399)
maxdata=(2 * SIZEOF_INT) - 1)[](#l4.1400)
+ + +class RFC3542AncillaryTest(SendrecvmsgServerTimeoutBase):
_into using the ancillary data
Test sendmsg() and recvmsgfeatures of the RFC 3542 Advanced Sockets API for IPv6.
Currently we can only handle certain data items (e.g. traffic
class, hop limit, MTU discovery and fragmentation settings)
without resorting to unportable means such as the struct module,
but the tests here are aimed at testing the ancillary data
handling in sendmsg() and recvmsg() rather than the IPv6 API
itself.
Test value to use when setting traffic class of packet.
-1 means "use kernel default".
- traffic_class = -1
- def ancillaryMapping(self, ancdata):
# Given ancillary data list ancdata, return a mapping from[](#l4.1424)
# pairs (cmsg_level, cmsg_type) to corresponding cmsg_data.[](#l4.1425)
# Check that no (level, type) pair appears more than once.[](#l4.1426)
d = {}[](#l4.1427)
for cmsg_level, cmsg_type, cmsg_data in ancdata:[](#l4.1428)
self.assertNotIn((cmsg_level, cmsg_type), d)[](#l4.1429)
d[(cmsg_level, cmsg_type)] = cmsg_data[](#l4.1430)
return d[](#l4.1431)
- def checkHopLimit(self, ancbufsize, maxhop=255, ignoreflags=0):
# Receive hop limit into ancbufsize bytes of ancillary data[](#l4.1434)
# space. Check that data is MSG, ancillary data is not[](#l4.1435)
# truncated (but ignore any flags in ignoreflags), and hop[](#l4.1436)
# limit is between 0 and maxhop inclusive.[](#l4.1437)
self.serv_sock.setsockopt(socket.IPPROTO_IPV6,[](#l4.1438)
socket.IPV6_RECVHOPLIMIT, 1)[](#l4.1439)
self.misc_event.set()[](#l4.1440)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.1441)
len(MSG), ancbufsize)[](#l4.1442)
self.assertEqual(msg, MSG)[](#l4.1444)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.1445)
self.checkFlags(flags, eor=True, checkunset=socket.MSG_CTRUNC,[](#l4.1446)
ignore=ignoreflags)[](#l4.1447)
self.assertEqual(len(ancdata), 1)[](#l4.1449)
self.assertIsInstance(ancdata[0], tuple)[](#l4.1450)
cmsg_level, cmsg_type, cmsg_data = ancdata[0][](#l4.1451)
self.assertEqual(cmsg_level, socket.IPPROTO_IPV6)[](#l4.1452)
self.assertEqual(cmsg_type, socket.IPV6_HOPLIMIT)[](#l4.1453)
self.assertIsInstance(cmsg_data, bytes)[](#l4.1454)
self.assertEqual(len(cmsg_data), SIZEOF_INT)[](#l4.1455)
a = array.array("i")[](#l4.1456)
a.fromstring(cmsg_data)[](#l4.1457)
self.assertGreaterEqual(a[0], 0)[](#l4.1458)
self.assertLessEqual(a[0], maxhop)[](#l4.1459)
- @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT")
- def testRecvHopLimit(self):
# Test receiving the packet hop limit as ancillary data.[](#l4.1463)
self.checkHopLimit(ancbufsize=10240)[](#l4.1464)
- @testRecvHopLimit.client_skip
- def _testRecvHopLimit(self):
# Need to wait until server has asked to receive ancillary[](#l4.1468)
# data, as implementations are not required to buffer it[](#l4.1469)
# otherwise.[](#l4.1470)
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1471)
self.sendToServer(MSG)[](#l4.1472)
- @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT")
- def testRecvHopLimitCMSG_SPACE(self):
# Test receiving hop limit, using CMSG_SPACE to calculate buffer size.[](#l4.1476)
self.checkHopLimit(ancbufsize=socket.CMSG_SPACE(SIZEOF_INT))[](#l4.1477)
- @testRecvHopLimitCMSG_SPACE.client_skip
- def _testRecvHopLimitCMSG_SPACE(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1481)
self.sendToServer(MSG)[](#l4.1482)
Could test receiving into buffer sized using CMSG_LEN, but RFC
3542 says portable applications must provide space for trailing
padding. Implementations may set MSG_CTRUNC if there isn't
enough space for the padding.
- @requireAttrs(socket.socket, "sendmsg")
- @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT")
- def testSetHopLimit(self):
# Test setting hop limit on outgoing packet and receiving it[](#l4.1492)
# at the other end.[](#l4.1493)
self.checkHopLimit(ancbufsize=10240, maxhop=self.hop_limit)[](#l4.1494)
- @testSetHopLimit.client_skip
- def _testSetHopLimit(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1498)
self.assertEqual([](#l4.1499)
self.sendmsgToServer([MSG],[](#l4.1500)
[(socket.IPPROTO_IPV6, socket.IPV6_HOPLIMIT,[](#l4.1501)
array.array("i", [self.hop_limit]))]),[](#l4.1502)
len(MSG))[](#l4.1503)
- def checkTrafficClassAndHopLimit(self, ancbufsize, maxhop=255,
ignoreflags=0):[](#l4.1506)
# Receive traffic class and hop limit into ancbufsize bytes of[](#l4.1507)
# ancillary data space. Check that data is MSG, ancillary[](#l4.1508)
# data is not truncated (but ignore any flags in ignoreflags),[](#l4.1509)
# and traffic class and hop limit are in range (hop limit no[](#l4.1510)
# more than maxhop).[](#l4.1511)
self.serv_sock.setsockopt(socket.IPPROTO_IPV6,[](#l4.1512)
socket.IPV6_RECVHOPLIMIT, 1)[](#l4.1513)
self.serv_sock.setsockopt(socket.IPPROTO_IPV6,[](#l4.1514)
socket.IPV6_RECVTCLASS, 1)[](#l4.1515)
self.misc_event.set()[](#l4.1516)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.1517)
len(MSG), ancbufsize)[](#l4.1518)
self.assertEqual(msg, MSG)[](#l4.1520)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.1521)
self.checkFlags(flags, eor=True, checkunset=socket.MSG_CTRUNC,[](#l4.1522)
ignore=ignoreflags)[](#l4.1523)
self.assertEqual(len(ancdata), 2)[](#l4.1524)
ancmap = self.ancillaryMapping(ancdata)[](#l4.1525)
tcdata = ancmap[(socket.IPPROTO_IPV6, socket.IPV6_TCLASS)][](#l4.1527)
self.assertEqual(len(tcdata), SIZEOF_INT)[](#l4.1528)
a = array.array("i")[](#l4.1529)
a.fromstring(tcdata)[](#l4.1530)
self.assertGreaterEqual(a[0], 0)[](#l4.1531)
self.assertLessEqual(a[0], 255)[](#l4.1532)
hldata = ancmap[(socket.IPPROTO_IPV6, socket.IPV6_HOPLIMIT)][](#l4.1534)
self.assertEqual(len(hldata), SIZEOF_INT)[](#l4.1535)
a = array.array("i")[](#l4.1536)
a.fromstring(hldata)[](#l4.1537)
self.assertGreaterEqual(a[0], 0)[](#l4.1538)
self.assertLessEqual(a[0], maxhop)[](#l4.1539)
- @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT",
"IPV6_RECVTCLASS", "IPV6_TCLASS")[](#l4.1542)
- def testRecvTrafficClassAndHopLimit(self):
# Test receiving traffic class and hop limit as ancillary data.[](#l4.1544)
self.checkTrafficClassAndHopLimit(ancbufsize=10240)[](#l4.1545)
- @testRecvTrafficClassAndHopLimit.client_skip
- def _testRecvTrafficClassAndHopLimit(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1549)
self.sendToServer(MSG)[](#l4.1550)
- @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT",
"IPV6_RECVTCLASS", "IPV6_TCLASS")[](#l4.1553)
- def testRecvTrafficClassAndHopLimitCMSG_SPACE(self):
# Test receiving traffic class and hop limit, using[](#l4.1555)
# CMSG_SPACE() to calculate buffer size.[](#l4.1556)
self.checkTrafficClassAndHopLimit([](#l4.1557)
ancbufsize=socket.CMSG_SPACE(SIZEOF_INT) * 2)[](#l4.1558)
- @testRecvTrafficClassAndHopLimitCMSG_SPACE.client_skip
- def _testRecvTrafficClassAndHopLimitCMSG_SPACE(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1562)
self.sendToServer(MSG)[](#l4.1563)
- @requireAttrs(socket.socket, "sendmsg")
- @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT",
"IPV6_RECVTCLASS", "IPV6_TCLASS")[](#l4.1567)
- def testSetTrafficClassAndHopLimit(self):
# Test setting traffic class and hop limit on outgoing packet,[](#l4.1569)
# and receiving them at the other end.[](#l4.1570)
self.checkTrafficClassAndHopLimit(ancbufsize=10240,[](#l4.1571)
maxhop=self.hop_limit)[](#l4.1572)
- @testSetTrafficClassAndHopLimit.client_skip
- def _testSetTrafficClassAndHopLimit(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1576)
self.assertEqual([](#l4.1577)
self.sendmsgToServer([MSG],[](#l4.1578)
[(socket.IPPROTO_IPV6, socket.IPV6_TCLASS,[](#l4.1579)
array.array("i", [self.traffic_class])),[](#l4.1580)
(socket.IPPROTO_IPV6, socket.IPV6_HOPLIMIT,[](#l4.1581)
array.array("i", [self.hop_limit]))]),[](#l4.1582)
len(MSG))[](#l4.1583)
- @requireAttrs(socket.socket, "sendmsg")
- @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT",
"IPV6_RECVTCLASS", "IPV6_TCLASS")[](#l4.1587)
- def testOddCmsgSize(self):
# Try to send ancillary data with first item one byte too[](#l4.1589)
# long. Fall back to sending with correct size if this fails,[](#l4.1590)
# and check that second item was handled correctly.[](#l4.1591)
self.checkTrafficClassAndHopLimit(ancbufsize=10240,[](#l4.1592)
maxhop=self.hop_limit)[](#l4.1593)
- @testOddCmsgSize.client_skip
- def _testOddCmsgSize(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1597)
try:[](#l4.1598)
nbytes = self.sendmsgToServer([](#l4.1599)
[MSG],[](#l4.1600)
[(socket.IPPROTO_IPV6, socket.IPV6_TCLASS,[](#l4.1601)
array.array("i", [self.traffic_class]).tostring() + b"\x00"),[](#l4.1602)
(socket.IPPROTO_IPV6, socket.IPV6_HOPLIMIT,[](#l4.1603)
array.array("i", [self.hop_limit]))])[](#l4.1604)
except socket.error as e:[](#l4.1605)
self.assertIsInstance(e.errno, int)[](#l4.1606)
nbytes = self.sendmsgToServer([](#l4.1607)
[MSG],[](#l4.1608)
[(socket.IPPROTO_IPV6, socket.IPV6_TCLASS,[](#l4.1609)
array.array("i", [self.traffic_class])),[](#l4.1610)
(socket.IPPROTO_IPV6, socket.IPV6_HOPLIMIT,[](#l4.1611)
array.array("i", [self.hop_limit]))])[](#l4.1612)
self.assertEqual(nbytes, len(MSG))[](#l4.1613)
- def checkHopLimitTruncatedHeader(self, ancbufsize, ignoreflags=0):
# Receive hop limit into ancbufsize bytes of ancillary data[](#l4.1618)
# space, which should be too small to contain the ancillary[](#l4.1619)
# data header (if ancbufsize is None, pass no second argument[](#l4.1620)
# to recvmsg()). Check that data is MSG, MSG_CTRUNC is set[](#l4.1621)
# (unless included in ignoreflags), and no ancillary data is[](#l4.1622)
# returned.[](#l4.1623)
self.serv_sock.setsockopt(socket.IPPROTO_IPV6,[](#l4.1624)
socket.IPV6_RECVHOPLIMIT, 1)[](#l4.1625)
self.misc_event.set()[](#l4.1626)
args = () if ancbufsize is None else (ancbufsize,)[](#l4.1627)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.1628)
len(MSG), *args)[](#l4.1629)
self.assertEqual(msg, MSG)[](#l4.1631)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.1632)
self.assertEqual(ancdata, [])[](#l4.1633)
self.checkFlags(flags, eor=True, checkset=socket.MSG_CTRUNC,[](#l4.1634)
ignore=ignoreflags)[](#l4.1635)
- @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT")
- def testCmsgTruncNoBufSize(self):
# Check that no ancillary data is received when no ancillary[](#l4.1639)
# buffer size is provided.[](#l4.1640)
self.checkHopLimitTruncatedHeader(ancbufsize=None,[](#l4.1641)
# BSD seems to set[](#l4.1642)
# MSG_CTRUNC only if an item[](#l4.1643)
# has been partially[](#l4.1644)
# received.[](#l4.1645)
ignoreflags=socket.MSG_CTRUNC)[](#l4.1646)
- @testCmsgTruncNoBufSize.client_skip
- def _testCmsgTruncNoBufSize(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1650)
self.sendToServer(MSG)[](#l4.1651)
- @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT")
- def testSingleCmsgTrunc0(self):
# Check that no ancillary data is received when ancillary[](#l4.1655)
# buffer size is zero.[](#l4.1656)
self.checkHopLimitTruncatedHeader(ancbufsize=0,[](#l4.1657)
ignoreflags=socket.MSG_CTRUNC)[](#l4.1658)
- @testSingleCmsgTrunc0.client_skip
- def _testSingleCmsgTrunc0(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1662)
self.sendToServer(MSG)[](#l4.1663)
- @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT")
- def testSingleCmsgTrunc1(self):
self.checkHopLimitTruncatedHeader(ancbufsize=1)[](#l4.1670)
- @testSingleCmsgTrunc1.client_skip
- def _testSingleCmsgTrunc1(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1674)
self.sendToServer(MSG)[](#l4.1675)
- @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT")
- def testSingleCmsgTrunc2Int(self):
self.checkHopLimitTruncatedHeader(ancbufsize=2 * SIZEOF_INT)[](#l4.1679)
- @testSingleCmsgTrunc2Int.client_skip
- def _testSingleCmsgTrunc2Int(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1683)
self.sendToServer(MSG)[](#l4.1684)
- @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT")
- def testSingleCmsgTruncLen0Minus1(self):
self.checkHopLimitTruncatedHeader(ancbufsize=socket.CMSG_LEN(0) - 1)[](#l4.1688)
- @testSingleCmsgTruncLen0Minus1.client_skip
- def _testSingleCmsgTruncLen0Minus1(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1692)
self.sendToServer(MSG)[](#l4.1693)
- @requireAttrs(socket, "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT")
- def testSingleCmsgTruncInData(self):
# Test truncation of a control message inside its associated[](#l4.1697)
# data. The message may be returned with its data truncated,[](#l4.1698)
# or not returned at all.[](#l4.1699)
self.serv_sock.setsockopt(socket.IPPROTO_IPV6,[](#l4.1700)
socket.IPV6_RECVHOPLIMIT, 1)[](#l4.1701)
self.misc_event.set()[](#l4.1702)
msg, ancdata, flags, addr = self.doRecvmsg([](#l4.1703)
self.serv_sock, len(MSG), socket.CMSG_LEN(SIZEOF_INT) - 1)[](#l4.1704)
self.assertEqual(msg, MSG)[](#l4.1706)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.1707)
self.checkFlags(flags, eor=True, checkset=socket.MSG_CTRUNC)[](#l4.1708)
self.assertLessEqual(len(ancdata), 1)[](#l4.1710)
if ancdata:[](#l4.1711)
cmsg_level, cmsg_type, cmsg_data = ancdata[0][](#l4.1712)
self.assertEqual(cmsg_level, socket.IPPROTO_IPV6)[](#l4.1713)
self.assertEqual(cmsg_type, socket.IPV6_HOPLIMIT)[](#l4.1714)
self.assertLess(len(cmsg_data), SIZEOF_INT)[](#l4.1715)
- @testSingleCmsgTruncInData.client_skip
- def _testSingleCmsgTruncInData(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1719)
self.sendToServer(MSG)[](#l4.1720)
- def checkTruncatedSecondHeader(self, ancbufsize, ignoreflags=0):
# Receive traffic class and hop limit into ancbufsize bytes of[](#l4.1723)
# ancillary data space, which should be large enough to[](#l4.1724)
# contain the first item, but too small to contain the header[](#l4.1725)
# of the second. Check that data is MSG, MSG_CTRUNC is set[](#l4.1726)
# (unless included in ignoreflags), and only one ancillary[](#l4.1727)
# data item is returned.[](#l4.1728)
self.serv_sock.setsockopt(socket.IPPROTO_IPV6,[](#l4.1729)
socket.IPV6_RECVHOPLIMIT, 1)[](#l4.1730)
self.serv_sock.setsockopt(socket.IPPROTO_IPV6,[](#l4.1731)
socket.IPV6_RECVTCLASS, 1)[](#l4.1732)
self.misc_event.set()[](#l4.1733)
msg, ancdata, flags, addr = self.doRecvmsg(self.serv_sock,[](#l4.1734)
len(MSG), ancbufsize)[](#l4.1735)
self.assertEqual(msg, MSG)[](#l4.1737)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.1738)
self.checkFlags(flags, eor=True, checkset=socket.MSG_CTRUNC,[](#l4.1739)
ignore=ignoreflags)[](#l4.1740)
self.assertEqual(len(ancdata), 1)[](#l4.1742)
cmsg_level, cmsg_type, cmsg_data = ancdata[0][](#l4.1743)
self.assertEqual(cmsg_level, socket.IPPROTO_IPV6)[](#l4.1744)
self.assertIn(cmsg_type, {socket.IPV6_TCLASS, socket.IPV6_HOPLIMIT})[](#l4.1745)
self.assertEqual(len(cmsg_data), SIZEOF_INT)[](#l4.1746)
a = array.array("i")[](#l4.1747)
a.fromstring(cmsg_data)[](#l4.1748)
self.assertGreaterEqual(a[0], 0)[](#l4.1749)
self.assertLessEqual(a[0], 255)[](#l4.1750)
- @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT",
"IPV6_RECVTCLASS", "IPV6_TCLASS")[](#l4.1755)
- def testSecondCmsgTrunc0(self):
self.checkTruncatedSecondHeader(socket.CMSG_SPACE(SIZEOF_INT),[](#l4.1757)
ignoreflags=socket.MSG_CTRUNC)[](#l4.1758)
- @testSecondCmsgTrunc0.client_skip
- def _testSecondCmsgTrunc0(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1762)
self.sendToServer(MSG)[](#l4.1763)
- @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT",
"IPV6_RECVTCLASS", "IPV6_TCLASS")[](#l4.1766)
- def testSecondCmsgTrunc1(self):
self.checkTruncatedSecondHeader(socket.CMSG_SPACE(SIZEOF_INT) + 1)[](#l4.1768)
- @testSecondCmsgTrunc1.client_skip
- def _testSecondCmsgTrunc1(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1772)
self.sendToServer(MSG)[](#l4.1773)
- @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT",
"IPV6_RECVTCLASS", "IPV6_TCLASS")[](#l4.1776)
- def testSecondCmsgTrunc2Int(self):
self.checkTruncatedSecondHeader(socket.CMSG_SPACE(SIZEOF_INT) +[](#l4.1778)
2 * SIZEOF_INT)[](#l4.1779)
- @testSecondCmsgTrunc2Int.client_skip
- def _testSecondCmsgTrunc2Int(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1783)
self.sendToServer(MSG)[](#l4.1784)
- @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT",
"IPV6_RECVTCLASS", "IPV6_TCLASS")[](#l4.1787)
- def testSecondCmsgTruncLen0Minus1(self):
self.checkTruncatedSecondHeader(socket.CMSG_SPACE(SIZEOF_INT) +[](#l4.1789)
socket.CMSG_LEN(0) - 1)[](#l4.1790)
- @testSecondCmsgTruncLen0Minus1.client_skip
- def _testSecondCmsgTruncLen0Minus1(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1794)
self.sendToServer(MSG)[](#l4.1795)
- @requireAttrs(socket, "CMSG_SPACE", "IPV6_RECVHOPLIMIT", "IPV6_HOPLIMIT",
"IPV6_RECVTCLASS", "IPV6_TCLASS")[](#l4.1798)
- def testSecomdCmsgTruncInData(self):
# Test truncation of the second of two control messages inside[](#l4.1800)
# its associated data.[](#l4.1801)
self.serv_sock.setsockopt(socket.IPPROTO_IPV6,[](#l4.1802)
socket.IPV6_RECVHOPLIMIT, 1)[](#l4.1803)
self.serv_sock.setsockopt(socket.IPPROTO_IPV6,[](#l4.1804)
socket.IPV6_RECVTCLASS, 1)[](#l4.1805)
self.misc_event.set()[](#l4.1806)
msg, ancdata, flags, addr = self.doRecvmsg([](#l4.1807)
self.serv_sock, len(MSG),[](#l4.1808)
socket.CMSG_SPACE(SIZEOF_INT) + socket.CMSG_LEN(SIZEOF_INT) - 1)[](#l4.1809)
self.assertEqual(msg, MSG)[](#l4.1811)
self.checkRecvmsgAddress(addr, self.cli_addr)[](#l4.1812)
self.checkFlags(flags, eor=True, checkset=socket.MSG_CTRUNC)[](#l4.1813)
cmsg_types = {socket.IPV6_TCLASS, socket.IPV6_HOPLIMIT}[](#l4.1815)
cmsg_level, cmsg_type, cmsg_data = ancdata.pop(0)[](#l4.1817)
self.assertEqual(cmsg_level, socket.IPPROTO_IPV6)[](#l4.1818)
cmsg_types.remove(cmsg_type)[](#l4.1819)
self.assertEqual(len(cmsg_data), SIZEOF_INT)[](#l4.1820)
a = array.array("i")[](#l4.1821)
a.fromstring(cmsg_data)[](#l4.1822)
self.assertGreaterEqual(a[0], 0)[](#l4.1823)
self.assertLessEqual(a[0], 255)[](#l4.1824)
if ancdata:[](#l4.1826)
cmsg_level, cmsg_type, cmsg_data = ancdata.pop(0)[](#l4.1827)
self.assertEqual(cmsg_level, socket.IPPROTO_IPV6)[](#l4.1828)
cmsg_types.remove(cmsg_type)[](#l4.1829)
self.assertLess(len(cmsg_data), SIZEOF_INT)[](#l4.1830)
self.assertEqual(ancdata, [])[](#l4.1832)
- @testSecomdCmsgTruncInData.client_skip
- def _testSecomdCmsgTruncInData(self):
self.assertTrue(self.misc_event.wait(timeout=self.fail_timeout))[](#l4.1836)
self.sendToServer(MSG)[](#l4.1837)
+ + +# Derive concrete test classes for different socket types. + +class SendrecvmsgUDPTestBase(SendrecvmsgDgramFlagsBase,
+ +@requireAttrs(socket.socket, "sendmsg") +@unittest.skipUnless(thread, 'Threading required for this test.') +class SendmsgUDPTest(SendmsgConnectionlessTests, SendrecvmsgUDPTestBase):
+ +@requireAttrs(socket.socket, "recvmsg") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgUDPTest(RecvmsgTests, SendrecvmsgUDPTestBase):
+ +@requireAttrs(socket.socket, "recvmsg_into") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgIntoUDPTest(RecvmsgIntoTests, SendrecvmsgUDPTestBase):
+ + +class SendrecvmsgUDP6TestBase(SendrecvmsgDgramFlagsBase,
+ +@requireAttrs(socket.socket, "sendmsg") +@unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") +@requireSocket("AF_INET6", "SOCK_DGRAM") +@unittest.skipUnless(thread, 'Threading required for this test.') +class SendmsgUDP6Test(SendmsgConnectionlessTests, SendrecvmsgUDP6TestBase):
+ +@requireAttrs(socket.socket, "recvmsg") +@unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") +@requireSocket("AF_INET6", "SOCK_DGRAM") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgUDP6Test(RecvmsgTests, SendrecvmsgUDP6TestBase):
+ +@requireAttrs(socket.socket, "recvmsg_into") +@unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") +@requireSocket("AF_INET6", "SOCK_DGRAM") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgIntoUDP6Test(RecvmsgIntoTests, SendrecvmsgUDP6TestBase):
+ +@requireAttrs(socket.socket, "recvmsg") +@unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") +@requireAttrs(socket, "IPPROTO_IPV6") +@requireSocket("AF_INET6", "SOCK_DGRAM") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgRFC3542AncillaryUDP6Test(RFC3542AncillaryTest,
+ +@requireAttrs(socket.socket, "recvmsg_into") +@unittest.skipUnless(socket.has_ipv6, "Python not built with IPv6 support") +@requireAttrs(socket, "IPPROTO_IPV6") +@requireSocket("AF_INET6", "SOCK_DGRAM") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgIntoRFC3542AncillaryUDP6Test(RecvmsgIntoMixin,
+ + +class SendrecvmsgTCPTestBase(SendrecvmsgConnectedBase,
+ +@requireAttrs(socket.socket, "sendmsg") +@unittest.skipUnless(thread, 'Threading required for this test.') +class SendmsgTCPTest(SendmsgStreamTests, SendrecvmsgTCPTestBase):
+ +@requireAttrs(socket.socket, "recvmsg") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgTCPTest(RecvmsgTests, RecvmsgGenericStreamTests,
+ +@requireAttrs(socket.socket, "recvmsg_into") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgIntoTCPTest(RecvmsgIntoTests, RecvmsgGenericStreamTests,
+ + +class SendrecvmsgSCTPStreamTestBase(SendrecvmsgSCTPFlagsBase,
+ +@requireAttrs(socket.socket, "sendmsg") +@requireSocket("AF_INET", "SOCK_STREAM", "IPPROTO_SCTP") +@unittest.skipUnless(thread, 'Threading required for this test.') +class SendmsgSCTPStreamTest(SendmsgStreamTests, SendrecvmsgSCTPStreamTestBase):
+ +@requireAttrs(socket.socket, "recvmsg") +@requireSocket("AF_INET", "SOCK_STREAM", "IPPROTO_SCTP") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgSCTPStreamTest(RecvmsgTests, RecvmsgGenericStreamTests,
+ +@requireAttrs(socket.socket, "recvmsg_into") +@requireSocket("AF_INET", "SOCK_STREAM", "IPPROTO_SCTP") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgIntoSCTPStreamTest(RecvmsgIntoTests, RecvmsgGenericStreamTests,
+ + +class SendrecvmsgUnixStreamTestBase(SendrecvmsgConnectedBase,
+ +@requireAttrs(socket.socket, "sendmsg") +@requireAttrs(socket, "AF_UNIX") +@unittest.skipUnless(thread, 'Threading required for this test.') +class SendmsgUnixStreamTest(SendmsgStreamTests, SendrecvmsgUnixStreamTestBase):
+ +@requireAttrs(socket.socket, "recvmsg") +@requireAttrs(socket, "AF_UNIX") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgUnixStreamTest(RecvmsgTests, RecvmsgGenericStreamTests,
+ +@requireAttrs(socket.socket, "recvmsg_into") +@requireAttrs(socket, "AF_UNIX") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgIntoUnixStreamTest(RecvmsgIntoTests, RecvmsgGenericStreamTests,
+ +@requireAttrs(socket.socket, "sendmsg", "recvmsg") +@requireAttrs(socket, "AF_UNIX", "SOL_SOCKET", "SCM_RIGHTS") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgSCMRightsStreamTest(SCMRightsTest, SendrecvmsgUnixStreamTestBase):
+ +@requireAttrs(socket.socket, "sendmsg", "recvmsg_into") +@requireAttrs(socket, "AF_UNIX", "SOL_SOCKET", "SCM_RIGHTS") +@unittest.skipUnless(thread, 'Threading required for this test.') +class RecvmsgIntoSCMRightsStreamTest(RecvmsgIntoMixin, SCMRightsTest,
+ + +# Test interrupting the interruptible send/receive methods with a +# signal when a timeout is set. These tests avoid having multiple +# threads alive during the test so that the OS cannot deliver the +# signal to the wrong one. + +class InterruptedTimeoutBase(unittest.TestCase):
Base class for interrupted send/receive tests. Installs an
empty handler for SIGALRM and removes it on teardown, along with
any scheduled alarms.
- def setUp(self):
super().setUp()[](#l4.2006)
orig_alrm_handler = signal.signal(signal.SIGALRM,[](#l4.2007)
lambda signum, frame: None)[](#l4.2008)
self.addCleanup(signal.signal, signal.SIGALRM, orig_alrm_handler)[](#l4.2009)
self.addCleanup(self.setAlarm, 0)[](#l4.2010)
Provide setAlarm() method to schedule delivery of SIGALRM after
given number of seconds, or cancel it if zero, and an
appropriate time value to use. Use setitimer() if available.
- if hasattr(signal, "setitimer"):
alarm_time = 0.05[](#l4.2019)
def setAlarm(self, seconds):[](#l4.2021)
signal.setitimer(signal.ITIMER_REAL, seconds)[](#l4.2022)
- else:
# Old systems may deliver the alarm up to one second early[](#l4.2024)
alarm_time = 2[](#l4.2025)
def setAlarm(self, seconds):[](#l4.2027)
signal.alarm(seconds)[](#l4.2028)
+ + +# Require siginterrupt() in order to ensure that system calls are +# interrupted by default. +@requireAttrs(signal, "siginterrupt") +@unittest.skipUnless(hasattr(signal, "alarm") or hasattr(signal, "setitimer"),
"Don't have signal.alarm or signal.setitimer")[](#l4.2035)
+class InterruptedRecvTimeoutTest(InterruptedTimeoutBase, UDPTestBase):
- def checkInterruptedRecv(self, func, *args, **kwargs):
# Check that func(*args, **kwargs) raises socket.error with an[](#l4.2045)
# errno of EINTR when interrupted by a signal.[](#l4.2046)
self.setAlarm(self.alarm_time)[](#l4.2047)
with self.assertRaises(socket.error) as cm:[](#l4.2048)
func(*args, **kwargs)[](#l4.2049)
self.assertNotIsInstance(cm.exception, socket.timeout)[](#l4.2050)
self.assertEqual(cm.exception.errno, errno.EINTR)[](#l4.2051)
- def testInterruptedRecvIntoTimeout(self):
self.checkInterruptedRecv(self.serv.recv_into, bytearray(1024))[](#l4.2057)
- def testInterruptedRecvfromTimeout(self):
self.checkInterruptedRecv(self.serv.recvfrom, 1024)[](#l4.2060)
- def testInterruptedRecvfromIntoTimeout(self):
self.checkInterruptedRecv(self.serv.recvfrom_into, bytearray(1024))[](#l4.2063)
- @requireAttrs(socket.socket, "recvmsg")
- def testInterruptedRecvmsgTimeout(self):
self.checkInterruptedRecv(self.serv.recvmsg, 1024)[](#l4.2067)
- @requireAttrs(socket.socket, "recvmsg_into")
- def testInterruptedRecvmsgIntoTimeout(self):
self.checkInterruptedRecv(self.serv.recvmsg_into, [bytearray(1024)])[](#l4.2071)
+ + +# Require siginterrupt() in order to ensure that system calls are +# interrupted by default. +@requireAttrs(signal, "siginterrupt") +@unittest.skipUnless(hasattr(signal, "alarm") or hasattr(signal, "setitimer"),
"Don't have signal.alarm or signal.setitimer")[](#l4.2078)
+@unittest.skipUnless(thread, 'Threading required for this test.') +class InterruptedSendTimeoutTest(InterruptedTimeoutBase,
ThreadSafeCleanupTestCase,[](#l4.2081)
SocketListeningTestMixin, TCPTestBase):[](#l4.2082)
Test interrupting the interruptible send*() methods with signals
when a timeout is set.
- def setUp(self):
super().setUp()[](#l4.2087)
self.serv_conn = self.newSocket()[](#l4.2088)
self.addCleanup(self.serv_conn.close)[](#l4.2089)
# Use a thread to complete the connection, but wait for it to[](#l4.2090)
# terminate before running the test, so that there is only one[](#l4.2091)
# thread to accept the signal.[](#l4.2092)
cli_thread = threading.Thread(target=self.doConnect)[](#l4.2093)
cli_thread.start()[](#l4.2094)
self.cli_conn, addr = self.serv.accept()[](#l4.2095)
self.addCleanup(self.cli_conn.close)[](#l4.2096)
cli_thread.join()[](#l4.2097)
self.serv_conn.settimeout(self.timeout)[](#l4.2098)
- def checkInterruptedSend(self, func, *args, **kwargs):
# Check that func(*args, **kwargs), run in a loop, raises[](#l4.2104)
# socket.error with an errno of EINTR when interrupted by a[](#l4.2105)
# signal.[](#l4.2106)
with self.assertRaises(socket.error) as cm:[](#l4.2107)
while True:[](#l4.2108)
self.setAlarm(self.alarm_time)[](#l4.2109)
func(*args, **kwargs)[](#l4.2110)
self.assertNotIsInstance(cm.exception, socket.timeout)[](#l4.2111)
self.assertEqual(cm.exception.errno, errno.EINTR)[](#l4.2112)
- def testInterruptedSendTimeout(self):
self.checkInterruptedSend(self.serv_conn.send, b"a"*512)[](#l4.2115)
- def testInterruptedSendtoTimeout(self):
# Passing an actual address here as Python's wrapper for[](#l4.2118)
# sendto() doesn't allow passing a zero-length one; POSIX[](#l4.2119)
# requires that the address is ignored since the socket is[](#l4.2120)
# connection-mode, however.[](#l4.2121)
self.checkInterruptedSend(self.serv_conn.sendto, b"a"*512,[](#l4.2122)
self.serv_addr)[](#l4.2123)
- @requireAttrs(socket.socket, "sendmsg")
- def testInterruptedSendmsgTimeout(self):
self.checkInterruptedSend(self.serv_conn.sendmsg, [b"a"*512])[](#l4.2127)
+ + @unittest.skipUnless(thread, 'Threading required for this test.') class TCPCloserTest(ThreadedTCPSocketTest): @@ -2077,6 +4172,31 @@ def test_main(): if isTipcAvailable(): tests.append(TIPCTest) tests.append(TIPCThreadableTest)
- tests.extend([
CmsgMacroTests,[](#l4.2138)
SendmsgUDPTest,[](#l4.2139)
RecvmsgUDPTest,[](#l4.2140)
RecvmsgIntoUDPTest,[](#l4.2141)
SendmsgUDP6Test,[](#l4.2142)
RecvmsgUDP6Test,[](#l4.2143)
RecvmsgRFC3542AncillaryUDP6Test,[](#l4.2144)
RecvmsgIntoRFC3542AncillaryUDP6Test,[](#l4.2145)
RecvmsgIntoUDP6Test,[](#l4.2146)
SendmsgTCPTest,[](#l4.2147)
RecvmsgTCPTest,[](#l4.2148)
RecvmsgIntoTCPTest,[](#l4.2149)
SendmsgSCTPStreamTest,[](#l4.2150)
RecvmsgSCTPStreamTest,[](#l4.2151)
RecvmsgIntoSCTPStreamTest,[](#l4.2152)
SendmsgUnixStreamTest,[](#l4.2153)
RecvmsgUnixStreamTest,[](#l4.2154)
RecvmsgIntoUnixStreamTest,[](#l4.2155)
RecvmsgSCMRightsStreamTest,[](#l4.2156)
RecvmsgIntoSCMRightsStreamTest,[](#l4.2157)
# These are slow when setitimer() is not available[](#l4.2158)
InterruptedRecvTimeoutTest,[](#l4.2159)
InterruptedSendTimeoutTest,[](#l4.2160)
- ])
thread_info = support.threading_setup() support.run_unittest(*tests)
--- a/Lib/test/test_ssl.py +++ b/Lib/test/test_ssl.py @@ -186,8 +186,11 @@ class BasicSocketTests(unittest.TestCase self.assertRaises(socket.error, ss.recv_into, bytearray(b'x')) self.assertRaises(socket.error, ss.recvfrom, 1) self.assertRaises(socket.error, ss.recvfrom_into, bytearray(b'x'), 1)
self.assertRaises(socket.error, ss.recvmsg, 1)[](#l5.7)
self.assertRaises(socket.error, ss.recvmsg_into, [bytearray(b'x')])[](#l5.8) self.assertRaises(socket.error, ss.send, b'x')[](#l5.9) self.assertRaises(socket.error, ss.sendto, b'x', ('0.0.0.0', 0))[](#l5.10)
self.assertRaises(socket.error, ss.sendmsg, [b'x'])[](#l5.11)
def test_timeout(self): # Issue #8524: when creating an SSL socket, the timeout of the @@ -1520,17 +1523,30 @@ else: count, addr = s.recvfrom_into(b) return b[:count]
def _recvmsg(*args, **kwargs):[](#l5.19)
return s.recvmsg(*args, **kwargs)[0][](#l5.20)
def _recvmsg_into(bufsize, *args, **kwargs):[](#l5.22)
b = bytearray(bufsize)[](#l5.23)
return bytes(b[:s.recvmsg_into([b], *args, **kwargs)[0]])[](#l5.24)
def _sendmsg(msg, *args, **kwargs):[](#l5.26)
return s.sendmsg([msg])[](#l5.27)
+ # (name, method, whether to expect success, *args) send_methods = [ ('send', s.send, True, []), ('sendto', s.sendto, False, ["some.address"]),
('sendmsg', _sendmsg, False, []),[](#l5.33) ('sendall', s.sendall, True, []),[](#l5.34) ][](#l5.35) recv_methods = [[](#l5.36) ('recv', s.recv, True, []),[](#l5.37) ('recvfrom', s.recvfrom, False, ["some.address"]),[](#l5.38)
('recvmsg', _recvmsg, False, [100]),[](#l5.39) ('recv_into', _recv_into, True, []),[](#l5.40) ('recvfrom_into', _recvfrom_into, False, []),[](#l5.41)
('recvmsg_into', _recvmsg_into, False, [100]),[](#l5.42) ][](#l5.43) data_prefix = "PREFIX_"[](#l5.44)
--- a/Misc/NEWS +++ b/Misc/NEWS @@ -265,6 +265,10 @@ Core and Builtins Library ------- +- Issue #6560: The sendmsg/recvmsg API is now exposed by the socket module
- when provided by the underlying platform, supporting processing of
- ancillary data in pure Python code. +
- Issue #12326: On Linux, sys.platform doesn't contain the major version anymore. It is now always 'linux', instead of 'linux2' or 'linux3' depending on the Linux version used to build Python.
--- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -263,6 +263,7 @@ if_indextoname(index) -- return the corr #ifdef HAVE_NET_IF_H #include <net/if.h> #endif +#include <unistd.h> /* Generic socket object definitions and includes / #define PySocket_BUILDING_SOCKET @@ -469,6 +470,17 @@ static PyTypeObject sock_type; #include <sys/poll.h> #endif +/ Largest value to try to store in a socklen_t (used when handling
- ancillary data). POSIX requires socklen_t to hold at least
- (2**31)-1 and recommends against storing larger values, but
- socklen_t was originally int in the BSD interface, so to be on the
- safe side we use the smaller of (2**31)-1 and INT_MAX. */ +#if INT_MAX > 0x7fffffff +#define SOCKLEN_T_LIMIT 0x7fffffff +#else +#define SOCKLEN_T_LIMIT INT_MAX +#endif +
#ifdef Py_SOCKET_FD_CAN_BE_GE_FD_SETSIZE /* Platform can select file descriptors beyond FD_SETSIZE */ #define IS_SELECTABLE(s) 1 @@ -1678,6 +1690,117 @@ getsockaddrlen(PySocketSockObject s, so } +/ Support functions for the sendmsg() and recvmsg_into methods.
- Currently, these methods are only compiled if the RFC 2292/3542
- CMSG_LEN() macro is available. Older systems seem to have used
- sizeof(struct cmsghdr) + (length) where CMSG_LEN() is used now, so
- it may be possible to define CMSG_LEN() that way if it's not
- provided. Some architectures might need extra padding after the
- cmsghdr, however, and CMSG_LEN() would have to take account of
- this. / +#ifdef CMSG_LEN +/ If length is in range, set *result to CMSG_LEN(length) and return
- true; otherwise, return false. */ +static int +get_CMSG_LEN(size_t length, size_t *result) +{
- size_t tmp;
- if (length > (SOCKLEN_T_LIMIT - CMSG_LEN(0)))
return 0;[](#l7.50)
- tmp = CMSG_LEN(length);
- if (tmp > SOCKLEN_T_LIMIT || tmp < length)
return 0;[](#l7.53)
- *result = tmp;
- return 1;
+} + +#ifdef CMSG_SPACE +/* If length is in range, set *result to CMSG_SPACE(length) and return
- true; otherwise, return false. */ +static int +get_CMSG_SPACE(size_t length, size_t *result) +{
- size_t tmp;
- /* Use CMSG_SPACE(1) here in order to take account of the padding
necessary before *and* after the data. */[](#l7.67)
- if (length > (SOCKLEN_T_LIMIT - CMSG_SPACE(1)))
return 0;[](#l7.69)
- tmp = CMSG_SPACE(length);
- if (tmp > SOCKLEN_T_LIMIT || tmp < length)
return 0;[](#l7.72)
- *result = tmp;
- return 1;
+} +#endif + +/* Return true iff msg->msg_controllen is valid, cmsgh is a valid
- pointer in msg->msg_control with at least "space" bytes after it,
- and its cmsg_len member inside the buffer. */ +static int +cmsg_min_space(struct msghdr *msg, struct cmsghdr *cmsgh, size_t space) +{
- size_t cmsg_offset;
- static const size_t cmsg_len_end = (offsetof(struct cmsghdr, cmsg_len) +
sizeof(cmsgh->cmsg_len));[](#l7.86)
- if (cmsgh == NULL || msg->msg_control == NULL || msg->msg_controllen < 0)
return 0;[](#l7.89)
- if (space < cmsg_len_end)
space = cmsg_len_end;[](#l7.91)
- cmsg_offset = (char *)cmsgh - (char *)msg->msg_control;
- return (cmsg_offset <= (size_t)-1 - space &&
cmsg_offset + space <= msg->msg_controllen);[](#l7.94)
+} + +/* If pointer CMSG_DATA(cmsgh) is in buffer msg->msg_control, set
- *space to number of bytes following it in the buffer and return
- true; otherwise, return false. Assumes cmsgh, msg->msg_control and
- msg->msg_controllen are valid. */ +static int +get_cmsg_data_space(struct msghdr *msg, struct cmsghdr *cmsgh, size_t *space) +{
- size_t data_offset;
- char *data_ptr;
- if ((data_ptr = (char *)CMSG_DATA(cmsgh)) == NULL)
return 0;[](#l7.108)
- data_offset = data_ptr - (char *)msg->msg_control;
- if (data_offset > msg->msg_controllen)
return 0;[](#l7.111)
- *space = msg->msg_controllen - data_offset;
- return 1;
+} + +/* If cmsgh is invalid or not contained in the buffer pointed to by
- msg->msg_control, return -1. If cmsgh is valid and its associated
- data is entirely contained in the buffer, set *data_len to the
- length of the associated data and return 0. If only part of the
- associated data is contained in the buffer but cmsgh is otherwise
- valid, set *data_len to the length contained in the buffer and
- return 1. */ +static int +get_cmsg_data_len(struct msghdr *msg, struct cmsghdr *cmsgh, size_t *data_len) +{
- size_t space, cmsg_data_len;
- if (!cmsg_min_space(msg, cmsgh, CMSG_LEN(0)) ||
cmsgh->cmsg_len < CMSG_LEN(0))[](#l7.129)
return -1;[](#l7.130)
- cmsg_data_len = cmsgh->cmsg_len - CMSG_LEN(0);
- if (!get_cmsg_data_space(msg, cmsgh, &space))
return -1;[](#l7.133)
- if (space >= cmsg_data_len) {
*data_len = cmsg_data_len;[](#l7.135)
return 0;[](#l7.136)
- }
- *data_len = space;
- return 1;
+} +#endif /* CMSG_LEN / + + / s._accept() -> (fd, address) */ static PyObject @@ -2631,6 +2754,333 @@ PyDoc_STRVAR(recvfrom_into_doc, Like recv_into(buffer[, nbytes[, flags]]) but also return the sender's address info."); +/ The sendmsg() and recvmsg_into methods require a working
- CMSG_LEN(). See the comment near get_CMSG_LEN(). / +#ifdef CMSG_LEN +/
- */ +static PyObject * +sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen,
int flags, Py_ssize_t controllen,[](#l7.166)
PyObject *(*makeval)(ssize_t, void *), void *makeval_data)[](#l7.167)
- ssize_t bytes_received = -1;
- int timeout;
- sock_addr_t addrbuf;
- socklen_t addrbuflen;
- static const struct msghdr msg_blank;
- struct msghdr msg;
- PyObject *cmsg_list = NULL, *retval = NULL;
- void *controlbuf = NULL;
- struct cmsghdr *cmsgh;
- size_t cmsgdatalen = 0;
- int cmsg_status;
- /* XXX: POSIX says that msg_name and msg_namelen "shall be
ignored" when the socket is connected (Linux fills them in[](#l7.182)
anyway for AF_UNIX sockets at least). Normally msg_namelen[](#l7.183)
seems to be set to 0 if there's no address, but try to[](#l7.184)
initialize msg_name to something that won't be mistaken for a[](#l7.185)
real address if that doesn't happen. */[](#l7.186)
- if (!getsockaddrlen(s, &addrbuflen))
return NULL;[](#l7.188)
- memset(&addrbuf, 0, addrbuflen);
- SAS2SA(&addrbuf)->sa_family = AF_UNSPEC;
- if (controllen < 0 || controllen > SOCKLEN_T_LIMIT) {
PyErr_SetString(PyExc_ValueError,[](#l7.193)
"invalid ancillary data buffer length");[](#l7.194)
return NULL;[](#l7.195)
- }
- if (controllen > 0 && (controlbuf = PyMem_Malloc(controllen)) == NULL)
return PyErr_NoMemory();[](#l7.198)
- /* Make the system call. */
- if (!IS_SELECTABLE(s)) {
select_error();[](#l7.202)
goto finally;[](#l7.203)
- }
- BEGIN_SELECT_LOOP(s)
- Py_BEGIN_ALLOW_THREADS;
- msg = msg_blank; /* Set all members to 0 or NULL */
- msg.msg_name = SAS2SA(&addrbuf);
- msg.msg_namelen = addrbuflen;
- msg.msg_iov = iov;
- msg.msg_iovlen = iovlen;
- msg.msg_control = controlbuf;
- msg.msg_controllen = controllen;
- timeout = internal_select_ex(s, 0, interval);
- if (!timeout)
bytes_received = recvmsg(s->sock_fd, &msg, flags);[](#l7.217)
- Py_END_ALLOW_THREADS;
- if (timeout == 1) {
PyErr_SetString(socket_timeout, "timed out");[](#l7.220)
goto finally;[](#l7.221)
- }
- END_SELECT_LOOP(s)
- /* Make list of (level, type, data) tuples from control messages. */
- if ((cmsg_list = PyList_New(0)) == NULL)
goto err_closefds;[](#l7.232)
- /* Check for empty ancillary data as old CMSG_FIRSTHDR()
implementations didn't do so. */[](#l7.234)
- for (cmsgh = ((msg.msg_controllen > 0) ? CMSG_FIRSTHDR(&msg) : NULL);
cmsgh != NULL; cmsgh = CMSG_NXTHDR(&msg, cmsgh)) {[](#l7.236)
PyObject *bytes, *tuple;[](#l7.237)
int tmp;[](#l7.238)
cmsg_status = get_cmsg_data_len(&msg, cmsgh, &cmsgdatalen);[](#l7.240)
if (cmsg_status != 0) {[](#l7.241)
if (PyErr_WarnEx(PyExc_RuntimeWarning,[](#l7.242)
"received malformed or improperly-truncated "[](#l7.243)
"ancillary data", 1) == -1)[](#l7.244)
goto err_closefds;[](#l7.245)
}[](#l7.246)
if (cmsg_status < 0)[](#l7.247)
break;[](#l7.248)
if (cmsgdatalen > PY_SSIZE_T_MAX) {[](#l7.249)
PyErr_SetString(socket_error, "control message too long");[](#l7.250)
goto err_closefds;[](#l7.251)
}[](#l7.252)
bytes = PyBytes_FromStringAndSize((char *)CMSG_DATA(cmsgh),[](#l7.254)
cmsgdatalen);[](#l7.255)
tuple = Py_BuildValue("iiN", (int)cmsgh->cmsg_level,[](#l7.256)
(int)cmsgh->cmsg_type, bytes);[](#l7.257)
if (tuple == NULL)[](#l7.258)
goto err_closefds;[](#l7.259)
tmp = PyList_Append(cmsg_list, tuple);[](#l7.260)
Py_DECREF(tuple);[](#l7.261)
if (tmp != 0)[](#l7.262)
goto err_closefds;[](#l7.263)
- retval = Py_BuildValue("NOiN",
(*makeval)(bytes_received, makeval_data),[](#l7.270)
cmsg_list,[](#l7.271)
(int)msg.msg_flags,[](#l7.272)
makesockaddr(s->sock_fd, SAS2SA(&addrbuf),[](#l7.273)
((msg.msg_namelen > addrbuflen) ?[](#l7.274)
addrbuflen : msg.msg_namelen),[](#l7.275)
s->sock_proto));[](#l7.276)
- if (retval == NULL)
goto err_closefds;[](#l7.278)
+ +err_closefds: +#ifdef SCM_RIGHTS
- /* Close all descriptors coming from SCM_RIGHTS, so they don't leak. */
- for (cmsgh = ((msg.msg_controllen > 0) ? CMSG_FIRSTHDR(&msg) : NULL);
cmsgh != NULL; cmsgh = CMSG_NXTHDR(&msg, cmsgh)) {[](#l7.289)
cmsg_status = get_cmsg_data_len(&msg, cmsgh, &cmsgdatalen);[](#l7.290)
if (cmsg_status < 0)[](#l7.291)
break;[](#l7.292)
if (cmsgh->cmsg_level == SOL_SOCKET &&[](#l7.293)
cmsgh->cmsg_type == SCM_RIGHTS) {[](#l7.294)
size_t numfds;[](#l7.295)
int *fdp;[](#l7.296)
numfds = cmsgdatalen / sizeof(int);[](#l7.298)
fdp = (int *)CMSG_DATA(cmsgh);[](#l7.299)
while (numfds-- > 0)[](#l7.300)
close(*fdp++);[](#l7.301)
}[](#l7.302)
if (cmsg_status != 0)[](#l7.303)
break;[](#l7.304)
- }
+} + + +static PyObject * +makeval_recvmsg(ssize_t received, void *data) +{
- if (received < PyBytes_GET_SIZE(*buf))
_PyBytes_Resize(buf, received);[](#l7.317)
- Py_XINCREF(*buf);
- return *buf;
+} + +/* s.recvmsg(bufsize[, ancbufsize[, flags]]) method */ + +static PyObject * +sock_recvmsg(PySocketSockObject *s, PyObject *args) +{
- Py_ssize_t bufsize, ancbufsize = 0;
- int flags = 0;
- struct iovec iov;
- PyObject *buf = NULL, *retval = NULL;
- if (bufsize < 0) {
PyErr_SetString(PyExc_ValueError, "negative buffer size in recvmsg()");[](#l7.336)
return NULL;[](#l7.337)
- }
- if ((buf = PyBytes_FromStringAndSize(NULL, bufsize)) == NULL)
return NULL;[](#l7.340)
- iov.iov_base = PyBytes_AS_STRING(buf);
- iov.iov_len = bufsize;
- /* Note that we're passing a pointer to our pointer to the bytes
object here (&buf); makeval_recvmsg() may incref the object, or[](#l7.345)
deallocate it and set our pointer to NULL. */[](#l7.346)
- retval = sock_recvmsg_guts(s, &iov, 1, flags, ancbufsize,
&makeval_recvmsg, &buf);[](#l7.348)
- Py_XDECREF(buf);
- return retval;
+} + +PyDoc_STRVAR(recvmsg_doc, +"recvmsg(bufsize[, ancbufsize[, flags]]) -> (data, ancdata, msg_flags, address)\n[](#l7.354) +\n[](#l7.355) +Receive normal data (up to bufsize bytes) and ancillary data from the\n[](#l7.356) +socket. The ancbufsize argument sets the size in bytes of the\n[](#l7.357) +internal buffer used to receive the ancillary data; it defaults to 0,\n[](#l7.358) +meaning that no ancillary data will be received. Appropriate buffer\n[](#l7.359) +sizes for ancillary data can be calculated using CMSG_SPACE() or\n[](#l7.360) +CMSG_LEN(), and items which do not fit into the buffer might be\n[](#l7.361) +truncated or discarded. The flags argument defaults to 0 and has the\n[](#l7.362) +same meaning as for recv().\n[](#l7.363) +\n[](#l7.364) +The return value is a 4-tuple: (data, ancdata, msg_flags, address).\n[](#l7.365) +The data item is a bytes object holding the non-ancillary data\n[](#l7.366) +received. The ancdata item is a list of zero or more tuples\n[](#l7.367) +(cmsg_level, cmsg_type, cmsg_data) representing the ancillary data\n[](#l7.368) +(control messages) received: cmsg_level and cmsg_type are integers\n[](#l7.369) +specifying the protocol level and protocol-specific type respectively,\n[](#l7.370) +and cmsg_data is a bytes object holding the associated data. The\n[](#l7.371) +msg_flags item is the bitwise OR of various flags indicating\n[](#l7.372) +conditions on the received message; see your system documentation for\n[](#l7.373) +details. If the receiving socket is unconnected, address is the\n[](#l7.374) +address of the sending socket, if available; otherwise, its value is\n[](#l7.375) +unspecified.\n[](#l7.376) +\n[](#l7.377) +If recvmsg() raises an exception after the system call returns, it\n[](#l7.378) +will first attempt to close any file descriptors received via the\n[](#l7.379) +SCM_RIGHTS mechanism."); + + +static PyObject * +makeval_recvmsg_into(ssize_t received, void *data) +{
+} + +/* s.recvmsg_into(buffers[, ancbufsize[, flags]]) method */ + +static PyObject * +sock_recvmsg_into(PySocketSockObject *s, PyObject *args) +{
- Py_ssize_t ancbufsize = 0;
- int flags = 0;
- struct iovec *iovs = NULL;
- Py_ssize_t i, nitems, nbufs = 0;
- Py_buffer *bufs = NULL;
- PyObject *buffers_arg, *fast, *retval = NULL;
- if (!PyArg_ParseTuple(args, "O|ni:recvmsg_into",
&buffers_arg, &ancbufsize, &flags))[](#l7.402)
return NULL;[](#l7.403)
- if ((fast = PySequence_Fast(buffers_arg,
"recvmsg_into() argument 1 must be an "[](#l7.406)
"iterable")) == NULL)[](#l7.407)
return NULL;[](#l7.408)
- nitems = PySequence_Fast_GET_SIZE(fast);
- if (nitems > INT_MAX) {
PyErr_SetString(socket_error, "recvmsg_into() argument 1 is too long");[](#l7.411)
goto finally;[](#l7.412)
- }
- /* Fill in an iovec for each item, and save the Py_buffer
structs to release afterwards. */[](#l7.416)
- if (nitems > 0 && ((iovs = PyMem_New(struct iovec, nitems)) == NULL ||
(bufs = PyMem_New(Py_buffer, nitems)) == NULL)) {[](#l7.418)
PyErr_NoMemory();[](#l7.419)
goto finally;[](#l7.420)
- }
- for (; nbufs < nitems; nbufs++) {
if (!PyArg_Parse(PySequence_Fast_GET_ITEM(fast, nbufs),[](#l7.423)
"w*;recvmsg_into() argument 1 must be an iterable "[](#l7.424)
"of single-segment read-write buffers",[](#l7.425)
&bufs[nbufs]))[](#l7.426)
goto finally;[](#l7.427)
iovs[nbufs].iov_base = bufs[nbufs].buf;[](#l7.428)
iovs[nbufs].iov_len = bufs[nbufs].len;[](#l7.429)
- }
- retval = sock_recvmsg_guts(s, iovs, nitems, flags, ancbufsize,
&makeval_recvmsg_into, NULL);[](#l7.433)
- for (i = 0; i < nbufs; i++)
PyBuffer_Release(&bufs[i]);[](#l7.436)
- PyMem_Free(bufs);
- PyMem_Free(iovs);
- Py_DECREF(fast);
- return retval;
+} + +PyDoc_STRVAR(recvmsg_into_doc, +"recvmsg_into(buffers[, ancbufsize[, flags]]) -> (nbytes, ancdata, msg_flags, address)\n[](#l7.444) +\n[](#l7.445) +Receive normal data and ancillary data from the socket, scattering the\n[](#l7.446) +non-ancillary data into a series of buffers. The buffers argument\n[](#l7.447) +must be an iterable of objects that export writable buffers\n[](#l7.448) +(e.g. bytearray objects); these will be filled with successive chunks\n[](#l7.449) +of the non-ancillary data until it has all been written or there are\n[](#l7.450) +no more buffers. The ancbufsize argument sets the size in bytes of\n[](#l7.451) +the internal buffer used to receive the ancillary data; it defaults to\n[](#l7.452) +0, meaning that no ancillary data will be received. Appropriate\n[](#l7.453) +buffer sizes for ancillary data can be calculated using CMSG_SPACE()\n[](#l7.454) +or CMSG_LEN(), and items which do not fit into the buffer might be\n[](#l7.455) +truncated or discarded. The flags argument defaults to 0 and has the\n[](#l7.456) +same meaning as for recv().\n[](#l7.457) +\n[](#l7.458) +The return value is a 4-tuple: (nbytes, ancdata, msg_flags, address).\n[](#l7.459) +The nbytes item is the total number of bytes of non-ancillary data\n[](#l7.460) +written into the buffers. The ancdata item is a list of zero or more\n[](#l7.461) +tuples (cmsg_level, cmsg_type, cmsg_data) representing the ancillary\n[](#l7.462) +data (control messages) received: cmsg_level and cmsg_type are\n[](#l7.463) +integers specifying the protocol level and protocol-specific type\n[](#l7.464) +respectively, and cmsg_data is a bytes object holding the associated\n[](#l7.465) +data. The msg_flags item is the bitwise OR of various flags\n[](#l7.466) +indicating conditions on the received message; see your system\n[](#l7.467) +documentation for details. If the receiving socket is unconnected,\n[](#l7.468) +address is the address of the sending socket, if available; otherwise,\n[](#l7.469) +its value is unspecified.\n[](#l7.470) +\n[](#l7.471) +If recvmsg_into() raises an exception after the system call returns,\n[](#l7.472) +it will first attempt to close any file descriptors received via the\n[](#l7.473) +SCM_RIGHTS mechanism."); +#endif /* CMSG_LEN / + + / s.send(data [,flags]) method */ static PyObject @@ -2826,6 +3276,237 @@ Like send(data, flags) but allows specif For IP sockets, the address is a pair (hostaddr, port)."); +/ The sendmsg() and recvmsg_into methods require a working
- CMSG_LEN(). See the comment near get_CMSG_LEN(). / +#ifdef CMSG_LEN +/ s.sendmsg(buffers[, ancdata[, flags[, address]]]) method */ +
+static PyObject * +sock_sendmsg(PySocketSockObject *s, PyObject *args) +{
- Py_ssize_t i, ndataparts, ndatabufs = 0, ncmsgs, ncmsgbufs = 0;
- Py_buffer *databufs = NULL;
- struct iovec *iovs = NULL;
- sock_addr_t addrbuf;
- static const struct msghdr msg_blank;
- struct msghdr msg;
- struct cmsginfo {
int level;[](#l7.500)
int type;[](#l7.501)
Py_buffer data;[](#l7.502)
- } *cmsgs = NULL;
- void *controlbuf = NULL;
- size_t controllen, controllen_last;
- ssize_t bytes_sent = -1;
- int addrlen, timeout, flags = 0;
- PyObject *data_arg, *cmsg_arg = NULL, *addr_arg = NULL, *data_fast = NULL,
*cmsg_fast = NULL, *retval = NULL;[](#l7.509)
- if (!PyArg_ParseTuple(args, "O|OiO:sendmsg",
&data_arg, &cmsg_arg, &flags, &addr_arg))[](#l7.512)
return NULL;[](#l7.513)
- /* Parse destination address. */
- if (addr_arg != NULL && addr_arg != Py_None) {
if (!getsockaddrarg(s, addr_arg, SAS2SA(&addrbuf), &addrlen))[](#l7.519)
goto finally;[](#l7.520)
msg.msg_name = &addrbuf;[](#l7.521)
msg.msg_namelen = addrlen;[](#l7.522)
- }
- /* Fill in an iovec for each message part, and save the Py_buffer
structs to release afterwards. */[](#l7.526)
- if ((data_fast = PySequence_Fast(data_arg,
"sendmsg() argument 1 must be an "[](#l7.528)
"iterable")) == NULL)[](#l7.529)
goto finally;[](#l7.530)
- ndataparts = PySequence_Fast_GET_SIZE(data_fast);
- if (ndataparts > INT_MAX) {
PyErr_SetString(socket_error, "sendmsg() argument 1 is too long");[](#l7.533)
goto finally;[](#l7.534)
- }
- msg.msg_iovlen = ndataparts;
- if (ndataparts > 0 &&
((msg.msg_iov = iovs = PyMem_New(struct iovec, ndataparts)) == NULL ||[](#l7.538)
(databufs = PyMem_New(Py_buffer, ndataparts)) == NULL)) {[](#l7.539)
PyErr_NoMemory();[](#l7.540)
goto finally;[](#l7.541)
- }
- for (; ndatabufs < ndataparts; ndatabufs++) {
if (!PyArg_Parse(PySequence_Fast_GET_ITEM(data_fast, ndatabufs),[](#l7.544)
"y*;sendmsg() argument 1 must be an iterable of "[](#l7.545)
"buffer-compatible objects",[](#l7.546)
&databufs[ndatabufs]))[](#l7.547)
goto finally;[](#l7.548)
iovs[ndatabufs].iov_base = databufs[ndatabufs].buf;[](#l7.549)
iovs[ndatabufs].iov_len = databufs[ndatabufs].len;[](#l7.550)
- }
- if (cmsg_arg == NULL)
ncmsgs = 0;[](#l7.554)
- else {
if ((cmsg_fast = PySequence_Fast(cmsg_arg,[](#l7.556)
"sendmsg() argument 2 must be an "[](#l7.557)
"iterable")) == NULL)[](#l7.558)
goto finally;[](#l7.559)
ncmsgs = PySequence_Fast_GET_SIZE(cmsg_fast);[](#l7.560)
- }
- if (ncmsgs > 1) {
PyErr_SetString(socket_error,[](#l7.565)
"sending multiple control messages is not supported "[](#l7.566)
"on this system");[](#l7.567)
goto finally;[](#l7.568)
- }
- /* Save level, type and Py_buffer for each control message,
and calculate total size. */[](#l7.572)
- if (ncmsgs > 0 && (cmsgs = PyMem_New(struct cmsginfo, ncmsgs)) == NULL) {
PyErr_NoMemory();[](#l7.574)
goto finally;[](#l7.575)
- }
- controllen = controllen_last = 0;
- while (ncmsgbufs < ncmsgs) {
size_t bufsize, space;[](#l7.579)
if (!PyArg_Parse(PySequence_Fast_GET_ITEM(cmsg_fast, ncmsgbufs),[](#l7.581)
"(iiy*):[sendmsg() ancillary data items]",[](#l7.582)
&cmsgs[ncmsgbufs].level,[](#l7.583)
&cmsgs[ncmsgbufs].type,[](#l7.584)
&cmsgs[ncmsgbufs].data))[](#l7.585)
goto finally;[](#l7.586)
bufsize = cmsgs[ncmsgbufs++].data.len;[](#l7.587)
if (!get_CMSG_SPACE(bufsize, &space)) {[](#l7.590)
if (!get_CMSG_LEN(bufsize, &space)) {[](#l7.592)
PyErr_SetString(socket_error, "ancillary data item too large");[](#l7.594)
goto finally;[](#l7.595)
}[](#l7.596)
controllen += space;[](#l7.597)
if (controllen > SOCKLEN_T_LIMIT || controllen < controllen_last) {[](#l7.598)
PyErr_SetString(socket_error, "too much ancillary data");[](#l7.599)
goto finally;[](#l7.600)
}[](#l7.601)
controllen_last = controllen;[](#l7.602)
- }
- /* Construct ancillary data block from control message info. */
- if (ncmsgbufs > 0) {
struct cmsghdr *cmsgh = NULL;[](#l7.607)
if ((msg.msg_control = controlbuf =[](#l7.609)
PyMem_Malloc(controllen)) == NULL) {[](#l7.610)
PyErr_NoMemory();[](#l7.611)
goto finally;[](#l7.612)
}[](#l7.613)
msg.msg_controllen = controllen;[](#l7.614)
/* Need to zero out the buffer as a workaround for glibc's[](#l7.616)
CMSG_NXTHDR() implementation. After getting the pointer to[](#l7.617)
the next header, it checks its (uninitialized) cmsg_len[](#l7.618)
member to see if the "message" fits in the buffer, and[](#l7.619)
returns NULL if it doesn't. Zero-filling the buffer[](#l7.620)
ensures that that doesn't happen. */[](#l7.621)
memset(controlbuf, 0, controllen);[](#l7.622)
for (i = 0; i < ncmsgbufs; i++) {[](#l7.624)
size_t msg_len, data_len = cmsgs[i].data.len;[](#l7.625)
int enough_space = 0;[](#l7.626)
cmsgh = (i == 0) ? CMSG_FIRSTHDR(&msg) : CMSG_NXTHDR(&msg, cmsgh);[](#l7.628)
if (cmsgh == NULL) {[](#l7.629)
PyErr_Format(PyExc_RuntimeError,[](#l7.630)
"unexpected NULL result from %s()",[](#l7.631)
(i == 0) ? "CMSG_FIRSTHDR" : "CMSG_NXTHDR");[](#l7.632)
goto finally;[](#l7.633)
}[](#l7.634)
if (!get_CMSG_LEN(data_len, &msg_len)) {[](#l7.635)
PyErr_SetString(PyExc_RuntimeError,[](#l7.636)
"item size out of range for CMSG_LEN()");[](#l7.637)
goto finally;[](#l7.638)
}[](#l7.639)
if (cmsg_min_space(&msg, cmsgh, msg_len)) {[](#l7.640)
size_t space;[](#l7.641)
cmsgh->cmsg_len = msg_len;[](#l7.643)
if (get_cmsg_data_space(&msg, cmsgh, &space))[](#l7.644)
enough_space = (space >= data_len);[](#l7.645)
}[](#l7.646)
if (!enough_space) {[](#l7.647)
PyErr_SetString(PyExc_RuntimeError,[](#l7.648)
"ancillary data does not fit in calculated "[](#l7.649)
"space");[](#l7.650)
goto finally;[](#l7.651)
}[](#l7.652)
cmsgh->cmsg_level = cmsgs[i].level;[](#l7.653)
cmsgh->cmsg_type = cmsgs[i].type;[](#l7.654)
memcpy(CMSG_DATA(cmsgh), cmsgs[i].data.buf, data_len);[](#l7.655)
}[](#l7.656)
- }
- /* Make the system call. */
- if (!IS_SELECTABLE(s)) {
select_error();[](#l7.661)
goto finally;[](#l7.662)
- }
- BEGIN_SELECT_LOOP(s)
- Py_BEGIN_ALLOW_THREADS;
- timeout = internal_select_ex(s, 1, interval);
- if (!timeout)
bytes_sent = sendmsg(s->sock_fd, &msg, flags);[](#l7.669)
- Py_END_ALLOW_THREADS;
- if (timeout == 1) {
PyErr_SetString(socket_timeout, "timed out");[](#l7.672)
goto finally;[](#l7.673)
- }
- END_SELECT_LOOP(s)
- if (bytes_sent < 0) {
s->errorhandler();[](#l7.678)
goto finally;[](#l7.679)
- }
- retval = PyLong_FromSsize_t(bytes_sent);
- PyMem_Free(controlbuf);
- for (i = 0; i < ncmsgbufs; i++)
PyBuffer_Release(&cmsgs[i].data);[](#l7.686)
- PyMem_Free(cmsgs);
- Py_XDECREF(cmsg_fast);
- for (i = 0; i < ndatabufs; i++)
PyBuffer_Release(&databufs[i]);[](#l7.690)
- PyMem_Free(databufs);
- PyMem_Free(iovs);
- Py_XDECREF(data_fast);
- return retval;
+} + +PyDoc_STRVAR(sendmsg_doc, +"sendmsg(buffers[, ancdata[, flags[, address]]]) -> count\n[](#l7.698) +\n[](#l7.699) +Send normal and ancillary data to the socket, gathering the\n[](#l7.700) +non-ancillary data from a series of buffers and concatenating it into\n[](#l7.701) +a single message. The buffers argument specifies the non-ancillary\n[](#l7.702) +data as an iterable of buffer-compatible objects (e.g. bytes objects).\n[](#l7.703) +The ancdata argument specifies the ancillary data (control messages)\n[](#l7.704) +as an iterable of zero or more tuples (cmsg_level, cmsg_type,\n[](#l7.705) +cmsg_data), where cmsg_level and cmsg_type are integers specifying the\n[](#l7.706) +protocol level and protocol-specific type respectively, and cmsg_data\n[](#l7.707) +is a buffer-compatible object holding the associated data. The flags\n[](#l7.708) +argument defaults to 0 and has the same meaning as for send(). If\n[](#l7.709) +address is supplied and not None, it sets a destination address for\n[](#l7.710) +the message. The return value is the number of bytes of non-ancillary\n[](#l7.711) +data sent."); +#endif /* CMSG_LEN / + + / s.shutdown(how) method */ static PyObject * @@ -2952,6 +3633,14 @@ static PyMethodDef sock_methods[] = { setsockopt_doc}, {"shutdown", (PyCFunction)sock_shutdown, METH_O, shutdown_doc}, +#ifdef CMSG_LEN
- {"recvmsg", (PyCFunction)sock_recvmsg, METH_VARARGS,
recvmsg_doc},[](#l7.725)
- {"recvmsg_into", (PyCFunction)sock_recvmsg_into, METH_VARARGS,
recvmsg_into_doc,},[](#l7.727)
- {"sendmsg", (PyCFunction)sock_sendmsg, METH_VARARGS,
sendmsg_doc},[](#l7.729)
+#endif {NULL, NULL} /* sentinel / }; @@ -4377,6 +5066,68 @@ Returns the interface name corresponding #endif / HAVE_IF_NAMEINDEX / +#ifdef CMSG_LEN +/ Python interface to CMSG_LEN(length). */ + +static PyObject * +socket_CMSG_LEN(PyObject *self, PyObject *args) +{
- if (!PyArg_ParseTuple(args, "n:CMSG_LEN", &length))
return NULL;[](#l7.748)
- if (length < 0 || !get_CMSG_LEN(length, &result)) {
PyErr_Format(PyExc_OverflowError, "CMSG_LEN() argument out of range");[](#l7.750)
return NULL;[](#l7.751)
- }
- return PyLong_FromSize_t(result);
+} + +PyDoc_STRVAR(CMSG_LEN_doc, +"CMSG_LEN(length) -> control message length\n[](#l7.757) +\n[](#l7.758) +Return the total length, without trailing padding, of an ancillary\n[](#l7.759) +data item with associated data of the given length. This value can\n[](#l7.760) +often be used as the buffer size for recvmsg() to receive a single\n[](#l7.761) +item of ancillary data, but RFC 3542 requires portable applications to\n[](#l7.762) +use CMSG_SPACE() and thus include space for padding, even when the\n[](#l7.763) +item will be the last in the buffer. Raises OverflowError if length\n[](#l7.764) +is outside the permissible range of values."); + + +#ifdef CMSG_SPACE +/* Python interface to CMSG_SPACE(length). */ + +static PyObject * +socket_CMSG_SPACE(PyObject *self, PyObject *args) +{
- if (!PyArg_ParseTuple(args, "n:CMSG_SPACE", &length))
return NULL;[](#l7.778)
- if (length < 0 || !get_CMSG_SPACE(length, &result)) {
PyErr_SetString(PyExc_OverflowError,[](#l7.780)
"CMSG_SPACE() argument out of range");[](#l7.781)
return NULL;[](#l7.782)
- }
- return PyLong_FromSize_t(result);
+} + +PyDoc_STRVAR(CMSG_SPACE_doc, +"CMSG_SPACE(length) -> buffer size\n[](#l7.788) +\n[](#l7.789) +Return the buffer size needed for recvmsg() to receive an ancillary\n[](#l7.790) +data item with associated data of the given length, along with any\n[](#l7.791) +trailing padding. The buffer space needed to receive multiple items\n[](#l7.792) +is the sum of the CMSG_SPACE() values for their associated data\n[](#l7.793) +lengths. Raises OverflowError if length is outside the permissible\n[](#l7.794) +range of values."); +#endif /* CMSG_SPACE / +#endif / CMSG_LEN / + + / List of functions exported by this module. */ static PyMethodDef socket_methods[] = { @@ -4440,6 +5191,14 @@ static PyMethodDef socket_methods[] = { {"if_indextoname", socket_if_indextoname, METH_O, if_indextoname_doc}, #endif +#ifdef CMSG_LEN
+#endif +#endif {NULL, NULL} /* Sentinel */ }; @@ -4927,6 +5686,15 @@ PyInit__socket(void) #ifdef SO_SETFIB PyModule_AddIntConstant(m, "SO_SETFIB", SO_SETFIB); #endif +#ifdef SO_PASSCRED
+#endif +#ifdef LOCAL_PEERCRED
+#endif /* Maximum number of connections for "listen" / #ifdef SOMAXCONN @@ -4935,6 +5703,17 @@ PyInit__socket(void) PyModule_AddIntConstant(m, "SOMAXCONN", 5); / Common value */ #endif
+#endif +#ifdef SCM_CREDENTIALS
+#endif + /* Flags for send, recv */ #ifdef MSG_OOB PyModule_AddIntConstant(m, "MSG_OOB", MSG_OOB); @@ -4966,6 +5745,33 @@ PyInit__socket(void) #ifdef MSG_ETAG PyModule_AddIntConstant(m, "MSG_ETAG", MSG_ETAG); #endif +#ifdef MSG_NOSIGNAL
+#endif +#ifdef MSG_NOTIFICATION
+#endif +#ifdef MSG_CMSG_CLOEXEC
+#endif /* Protocol level and numbers, usable for [gs]etsockopt */ #ifdef SOL_SOCKET @@ -5105,6 +5911,9 @@ PyInit__socket(void) #ifdef IPPROTO_VRRP PyModule_AddIntConstant(m, "IPPROTO_VRRP", IPPROTO_VRRP); #endif +#ifdef IPPROTO_SCTP
+#endif #ifdef IPPROTO_BIP PyModule_AddIntConstant(m, "IPPROTO_BIP", IPPROTO_BIP); #endif