Add support for the send/recvmsg API to the socket module. Patch by David Watson and Heiko Wundram. (Closes #6560)

This commit is contained in:
Nick Coghlan 2011-08-22 11:55:57 +10:00
parent 8983729dc0
commit 96fe56abec
7 changed files with 3167 additions and 0 deletions

View File

@ -198,6 +198,7 @@ The module :mod:`socket` exports the following constants and functions:
SOMAXCONN
MSG_*
SOL_*
SCM_*
IPPROTO_*
IPPORT_*
INADDR_*
@ -511,6 +512,49 @@ The module :mod:`socket` exports the following constants and functions:
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 applicable to sockets.
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
def recv_fds(sock, msglen, maxfds):
fds = array.array("i") # Array of ints
msg, ancdata, flags, addr = sock.recvmsg(msglen, socket.CMSG_LEN(maxfds * fds.itemsize))
for cmsg_level, cmsg_type, cmsg_data in ancdata:
if (cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS):
# Append data, ignoring any truncated integers at the end.
fds.fromstring(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
return msg, list(fds)
Availability: most Unix platforms, possibly others.
.. versionadded:: 3.3
.. 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` value ``SC_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
>>> s1, s2 = socket.socketpair()
>>> b1 = bytearray(b'----')
>>> b2 = bytearray(b'0123456789')
>>> b3 = bytearray(b'--------------')
>>> s1.send(b'Mary had a little lamb')
22
>>> s2.recvmsg_into([b1, memoryview(b2)[2:9], b3])
(22, [], 0, None)
>>> [b1, b2, b3]
[bytearray(b'Mary'), bytearray(b'01 had a 9'), bytearray(b'little lamb---')]
Availability: most Unix platforms, possibly others.
.. versionadded:: 3.3
.. 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 applicable to sockets.
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` value ``SC_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 not ``None``, 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
def send_fds(sock, msg, fds):
return sock.sendmsg([msg], [(socket.SOL_SOCKET, socket.SCM_RIGHTS, array.array("i", fds))])
Availability: most Unix platforms, possibly others.
.. versionadded:: 3.3
.. method:: socket.setblocking(flag)
Set blocking or non-blocking mode of the socket: if *flag* is false, the

View File

@ -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
---

View File

@ -355,6 +355,14 @@ class SSLSocket(socket):
else:
return socket.sendto(self, data, flags_or_addr, addr)
def sendmsg(self, *args, **kwargs):
self._checkClosed()
if self._sslobj:
raise ValueError("sendmsg not allowed on instances of %s" %
self.__class__)
else:
return socket.sendmsg(self, *args, **kwargs)
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()
if self._sslobj:
raise ValueError("recvmsg not allowed on instances of %s" %
self.__class__)
else:
return socket.recvmsg(self, *args, **kwargs)
def recvmsg_into(self, *args, **kwargs):
self._checkClosed()
if self._sslobj:
raise ValueError("recvmsg_into not allowed on instances of %s" %
self.__class__)
else:
return socket.recvmsg_into(self, *args, **kwargs)
def pending(self):
self._checkClosed()
if self._sslobj:

File diff suppressed because it is too large Load Diff

View File

@ -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)
self.assertRaises(socket.error, ss.recvmsg_into, [bytearray(b'x')])
self.assertRaises(socket.error, ss.send, b'x')
self.assertRaises(socket.error, ss.sendto, b'x', ('0.0.0.0', 0))
self.assertRaises(socket.error, ss.sendmsg, [b'x'])
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):
return s.recvmsg(*args, **kwargs)[0]
def _recvmsg_into(bufsize, *args, **kwargs):
b = bytearray(bufsize)
return bytes(b[:s.recvmsg_into([b], *args, **kwargs)[0]])
def _sendmsg(msg, *args, **kwargs):
return s.sendmsg([msg])
# (name, method, whether to expect success, *args)
send_methods = [
('send', s.send, True, []),
('sendto', s.sendto, False, ["some.address"]),
('sendmsg', _sendmsg, False, []),
('sendall', s.sendall, True, []),
]
recv_methods = [
('recv', s.recv, True, []),
('recvfrom', s.recvfrom, False, ["some.address"]),
('recvmsg', _recvmsg, False, [100]),
('recv_into', _recv_into, True, []),
('recvfrom_into', _recvfrom_into, False, []),
('recvmsg_into', _recvmsg_into, False, [100]),
]
data_prefix = "PREFIX_"

View File

@ -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.

View File

@ -263,6 +263,7 @@ if_indextoname(index) -- return the corresponding interface name\n\
#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, socklen_t *len_ret)
}
/* 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;
tmp = CMSG_LEN(length);
if (tmp > SOCKLEN_T_LIMIT || tmp < length)
return 0;
*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. */
if (length > (SOCKLEN_T_LIMIT - CMSG_SPACE(1)))
return 0;
tmp = CMSG_SPACE(length);
if (tmp > SOCKLEN_T_LIMIT || tmp < length)
return 0;
*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));
if (cmsgh == NULL || msg->msg_control == NULL || msg->msg_controllen < 0)
return 0;
if (space < cmsg_len_end)
space = cmsg_len_end;
cmsg_offset = (char *)cmsgh - (char *)msg->msg_control;
return (cmsg_offset <= (size_t)-1 - space &&
cmsg_offset + space <= msg->msg_controllen);
}
/* 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;
data_offset = data_ptr - (char *)msg->msg_control;
if (data_offset > msg->msg_controllen)
return 0;
*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))
return -1;
cmsg_data_len = cmsgh->cmsg_len - CMSG_LEN(0);
if (!get_cmsg_data_space(msg, cmsgh, &space))
return -1;
if (space >= cmsg_data_len) {
*data_len = cmsg_data_len;
return 0;
}
*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
/*
* Call recvmsg() with the supplied iovec structures, flags, and
* ancillary data buffer size (controllen). Returns the tuple return
* value for recvmsg() or recvmsg_into(), with the first item provided
* by the supplied makeval() function. makeval() will be called with
* the length read and makeval_data as arguments, and must return a
* new reference (which will be decrefed if there is a subsequent
* error). On error, closes any file descriptors received via
* SCM_RIGHTS.
*/
static PyObject *
sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen,
int flags, Py_ssize_t controllen,
PyObject *(*makeval)(ssize_t, void *), void *makeval_data)
{
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
anyway for AF_UNIX sockets at least). Normally msg_namelen
seems to be set to 0 if there's no address, but try to
initialize msg_name to something that won't be mistaken for a
real address if that doesn't happen. */
if (!getsockaddrlen(s, &addrbuflen))
return NULL;
memset(&addrbuf, 0, addrbuflen);
SAS2SA(&addrbuf)->sa_family = AF_UNSPEC;
if (controllen < 0 || controllen > SOCKLEN_T_LIMIT) {
PyErr_SetString(PyExc_ValueError,
"invalid ancillary data buffer length");
return NULL;
}
if (controllen > 0 && (controlbuf = PyMem_Malloc(controllen)) == NULL)
return PyErr_NoMemory();
/* Make the system call. */
if (!IS_SELECTABLE(s)) {
select_error();
goto finally;
}
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);
Py_END_ALLOW_THREADS;
if (timeout == 1) {
PyErr_SetString(socket_timeout, "timed out");
goto finally;
}
END_SELECT_LOOP(s)
if (bytes_received < 0) {
s->errorhandler();
goto finally;
}
/* Make list of (level, type, data) tuples from control messages. */
if ((cmsg_list = PyList_New(0)) == NULL)
goto err_closefds;
/* Check for empty ancillary data as old CMSG_FIRSTHDR()
implementations didn't do so. */
for (cmsgh = ((msg.msg_controllen > 0) ? CMSG_FIRSTHDR(&msg) : NULL);
cmsgh != NULL; cmsgh = CMSG_NXTHDR(&msg, cmsgh)) {
PyObject *bytes, *tuple;
int tmp;
cmsg_status = get_cmsg_data_len(&msg, cmsgh, &cmsgdatalen);
if (cmsg_status != 0) {
if (PyErr_WarnEx(PyExc_RuntimeWarning,
"received malformed or improperly-truncated "
"ancillary data", 1) == -1)
goto err_closefds;
}
if (cmsg_status < 0)
break;
if (cmsgdatalen > PY_SSIZE_T_MAX) {
PyErr_SetString(socket_error, "control message too long");
goto err_closefds;
}
bytes = PyBytes_FromStringAndSize((char *)CMSG_DATA(cmsgh),
cmsgdatalen);
tuple = Py_BuildValue("iiN", (int)cmsgh->cmsg_level,
(int)cmsgh->cmsg_type, bytes);
if (tuple == NULL)
goto err_closefds;
tmp = PyList_Append(cmsg_list, tuple);
Py_DECREF(tuple);
if (tmp != 0)
goto err_closefds;
if (cmsg_status != 0)
break;
}
retval = Py_BuildValue("NOiN",
(*makeval)(bytes_received, makeval_data),
cmsg_list,
(int)msg.msg_flags,
makesockaddr(s->sock_fd, SAS2SA(&addrbuf),
((msg.msg_namelen > addrbuflen) ?
addrbuflen : msg.msg_namelen),
s->sock_proto));
if (retval == NULL)
goto err_closefds;
finally:
Py_XDECREF(cmsg_list);
PyMem_Free(controlbuf);
return retval;
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)) {
cmsg_status = get_cmsg_data_len(&msg, cmsgh, &cmsgdatalen);
if (cmsg_status < 0)
break;
if (cmsgh->cmsg_level == SOL_SOCKET &&
cmsgh->cmsg_type == SCM_RIGHTS) {
size_t numfds;
int *fdp;
numfds = cmsgdatalen / sizeof(int);
fdp = (int *)CMSG_DATA(cmsgh);
while (numfds-- > 0)
close(*fdp++);
}
if (cmsg_status != 0)
break;
}
#endif /* SCM_RIGHTS */
goto finally;
}
static PyObject *
makeval_recvmsg(ssize_t received, void *data)
{
PyObject **buf = data;
if (received < PyBytes_GET_SIZE(*buf))
_PyBytes_Resize(buf, received);
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 (!PyArg_ParseTuple(args, "n|ni:recvmsg", &bufsize, &ancbufsize, &flags))
return NULL;
if (bufsize < 0) {
PyErr_SetString(PyExc_ValueError, "negative buffer size in recvmsg()");
return NULL;
}
if ((buf = PyBytes_FromStringAndSize(NULL, bufsize)) == NULL)
return NULL;
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
deallocate it and set our pointer to NULL. */
retval = sock_recvmsg_guts(s, &iov, 1, flags, ancbufsize,
&makeval_recvmsg, &buf);
Py_XDECREF(buf);
return retval;
}
PyDoc_STRVAR(recvmsg_doc,
"recvmsg(bufsize[, ancbufsize[, flags]]) -> (data, ancdata, msg_flags, address)\n\
\n\
Receive normal data (up to bufsize bytes) and ancillary data from the\n\
socket. The ancbufsize argument sets the size in bytes of the\n\
internal buffer used to receive the ancillary data; it defaults to 0,\n\
meaning that no ancillary data will be received. Appropriate buffer\n\
sizes for ancillary data can be calculated using CMSG_SPACE() or\n\
CMSG_LEN(), and items which do not fit into the buffer might be\n\
truncated or discarded. The flags argument defaults to 0 and has the\n\
same meaning as for recv().\n\
\n\
The return value is a 4-tuple: (data, ancdata, msg_flags, address).\n\
The data item is a bytes object holding the non-ancillary data\n\
received. The ancdata item is a list of zero or more tuples\n\
(cmsg_level, cmsg_type, cmsg_data) representing the ancillary data\n\
(control messages) received: cmsg_level and cmsg_type are integers\n\
specifying the protocol level and protocol-specific type respectively,\n\
and cmsg_data is a bytes object holding the associated data. The\n\
msg_flags item is the bitwise OR of various flags indicating\n\
conditions on the received message; see your system documentation for\n\
details. If the receiving socket is unconnected, address is the\n\
address of the sending socket, if available; otherwise, its value is\n\
unspecified.\n\
\n\
If recvmsg() raises an exception after the system call returns, it\n\
will first attempt to close any file descriptors received via the\n\
SCM_RIGHTS mechanism.");
static PyObject *
makeval_recvmsg_into(ssize_t received, void *data)
{
return PyLong_FromSsize_t(received);
}
/* 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))
return NULL;
if ((fast = PySequence_Fast(buffers_arg,
"recvmsg_into() argument 1 must be an "
"iterable")) == NULL)
return NULL;
nitems = PySequence_Fast_GET_SIZE(fast);
if (nitems > INT_MAX) {
PyErr_SetString(socket_error, "recvmsg_into() argument 1 is too long");
goto finally;
}
/* Fill in an iovec for each item, and save the Py_buffer
structs to release afterwards. */
if (nitems > 0 && ((iovs = PyMem_New(struct iovec, nitems)) == NULL ||
(bufs = PyMem_New(Py_buffer, nitems)) == NULL)) {
PyErr_NoMemory();
goto finally;
}
for (; nbufs < nitems; nbufs++) {
if (!PyArg_Parse(PySequence_Fast_GET_ITEM(fast, nbufs),
"w*;recvmsg_into() argument 1 must be an iterable "
"of single-segment read-write buffers",
&bufs[nbufs]))
goto finally;
iovs[nbufs].iov_base = bufs[nbufs].buf;
iovs[nbufs].iov_len = bufs[nbufs].len;
}
retval = sock_recvmsg_guts(s, iovs, nitems, flags, ancbufsize,
&makeval_recvmsg_into, NULL);
finally:
for (i = 0; i < nbufs; i++)
PyBuffer_Release(&bufs[i]);
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\
\n\
Receive normal data and ancillary data from the socket, scattering the\n\
non-ancillary data into a series of buffers. The buffers argument\n\
must be an iterable of objects that export writable buffers\n\
(e.g. bytearray objects); these will be filled with successive chunks\n\
of the non-ancillary data until it has all been written or there are\n\
no more buffers. The ancbufsize argument sets the size in bytes of\n\
the internal buffer used to receive the ancillary data; it defaults to\n\
0, meaning that no ancillary data will be received. Appropriate\n\
buffer sizes for ancillary data can be calculated using CMSG_SPACE()\n\
or CMSG_LEN(), and items which do not fit into the buffer might be\n\
truncated or discarded. The flags argument defaults to 0 and has the\n\
same meaning as for recv().\n\
\n\
The return value is a 4-tuple: (nbytes, ancdata, msg_flags, address).\n\
The nbytes item is the total number of bytes of non-ancillary data\n\
written into the buffers. The ancdata item is a list of zero or more\n\
tuples (cmsg_level, cmsg_type, cmsg_data) representing the ancillary\n\
data (control messages) received: cmsg_level and cmsg_type are\n\
integers specifying the protocol level and protocol-specific type\n\
respectively, and cmsg_data is a bytes object holding the associated\n\
data. The msg_flags item is the bitwise OR of various flags\n\
indicating conditions on the received message; see your system\n\
documentation for details. If the receiving socket is unconnected,\n\
address is the address of the sending socket, if available; otherwise,\n\
its value is unspecified.\n\
\n\
If recvmsg_into() raises an exception after the system call returns,\n\
it will first attempt to close any file descriptors received via the\n\
SCM_RIGHTS mechanism.");
#endif /* CMSG_LEN */
/* s.send(data [,flags]) method */
static PyObject *
@ -2826,6 +3276,237 @@ Like send(data, flags) but allows specifying the destination address.\n\
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;
int type;
Py_buffer data;
} *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;
if (!PyArg_ParseTuple(args, "O|OiO:sendmsg",
&data_arg, &cmsg_arg, &flags, &addr_arg))
return NULL;
msg = msg_blank; /* Set all members to 0 or NULL */
/* Parse destination address. */
if (addr_arg != NULL && addr_arg != Py_None) {
if (!getsockaddrarg(s, addr_arg, SAS2SA(&addrbuf), &addrlen))
goto finally;
msg.msg_name = &addrbuf;
msg.msg_namelen = addrlen;
}
/* Fill in an iovec for each message part, and save the Py_buffer
structs to release afterwards. */
if ((data_fast = PySequence_Fast(data_arg,
"sendmsg() argument 1 must be an "
"iterable")) == NULL)
goto finally;
ndataparts = PySequence_Fast_GET_SIZE(data_fast);
if (ndataparts > INT_MAX) {
PyErr_SetString(socket_error, "sendmsg() argument 1 is too long");
goto finally;
}
msg.msg_iovlen = ndataparts;
if (ndataparts > 0 &&
((msg.msg_iov = iovs = PyMem_New(struct iovec, ndataparts)) == NULL ||
(databufs = PyMem_New(Py_buffer, ndataparts)) == NULL)) {
PyErr_NoMemory();
goto finally;
}
for (; ndatabufs < ndataparts; ndatabufs++) {
if (!PyArg_Parse(PySequence_Fast_GET_ITEM(data_fast, ndatabufs),
"y*;sendmsg() argument 1 must be an iterable of "
"buffer-compatible objects",
&databufs[ndatabufs]))
goto finally;
iovs[ndatabufs].iov_base = databufs[ndatabufs].buf;
iovs[ndatabufs].iov_len = databufs[ndatabufs].len;
}
if (cmsg_arg == NULL)
ncmsgs = 0;
else {
if ((cmsg_fast = PySequence_Fast(cmsg_arg,
"sendmsg() argument 2 must be an "
"iterable")) == NULL)
goto finally;
ncmsgs = PySequence_Fast_GET_SIZE(cmsg_fast);
}
#ifndef CMSG_SPACE
if (ncmsgs > 1) {
PyErr_SetString(socket_error,
"sending multiple control messages is not supported "
"on this system");
goto finally;
}
#endif
/* Save level, type and Py_buffer for each control message,
and calculate total size. */
if (ncmsgs > 0 && (cmsgs = PyMem_New(struct cmsginfo, ncmsgs)) == NULL) {
PyErr_NoMemory();
goto finally;
}
controllen = controllen_last = 0;
while (ncmsgbufs < ncmsgs) {
size_t bufsize, space;
if (!PyArg_Parse(PySequence_Fast_GET_ITEM(cmsg_fast, ncmsgbufs),
"(iiy*):[sendmsg() ancillary data items]",
&cmsgs[ncmsgbufs].level,
&cmsgs[ncmsgbufs].type,
&cmsgs[ncmsgbufs].data))
goto finally;
bufsize = cmsgs[ncmsgbufs++].data.len;
#ifdef CMSG_SPACE
if (!get_CMSG_SPACE(bufsize, &space)) {
#else
if (!get_CMSG_LEN(bufsize, &space)) {
#endif
PyErr_SetString(socket_error, "ancillary data item too large");
goto finally;
}
controllen += space;
if (controllen > SOCKLEN_T_LIMIT || controllen < controllen_last) {
PyErr_SetString(socket_error, "too much ancillary data");
goto finally;
}
controllen_last = controllen;
}
/* Construct ancillary data block from control message info. */
if (ncmsgbufs > 0) {
struct cmsghdr *cmsgh = NULL;
if ((msg.msg_control = controlbuf =
PyMem_Malloc(controllen)) == NULL) {
PyErr_NoMemory();
goto finally;
}
msg.msg_controllen = controllen;
/* Need to zero out the buffer as a workaround for glibc's
CMSG_NXTHDR() implementation. After getting the pointer to
the next header, it checks its (uninitialized) cmsg_len
member to see if the "message" fits in the buffer, and
returns NULL if it doesn't. Zero-filling the buffer
ensures that that doesn't happen. */
memset(controlbuf, 0, controllen);
for (i = 0; i < ncmsgbufs; i++) {
size_t msg_len, data_len = cmsgs[i].data.len;
int enough_space = 0;
cmsgh = (i == 0) ? CMSG_FIRSTHDR(&msg) : CMSG_NXTHDR(&msg, cmsgh);
if (cmsgh == NULL) {
PyErr_Format(PyExc_RuntimeError,
"unexpected NULL result from %s()",
(i == 0) ? "CMSG_FIRSTHDR" : "CMSG_NXTHDR");
goto finally;
}
if (!get_CMSG_LEN(data_len, &msg_len)) {
PyErr_SetString(PyExc_RuntimeError,
"item size out of range for CMSG_LEN()");
goto finally;
}
if (cmsg_min_space(&msg, cmsgh, msg_len)) {
size_t space;
cmsgh->cmsg_len = msg_len;
if (get_cmsg_data_space(&msg, cmsgh, &space))
enough_space = (space >= data_len);
}
if (!enough_space) {
PyErr_SetString(PyExc_RuntimeError,
"ancillary data does not fit in calculated "
"space");
goto finally;
}
cmsgh->cmsg_level = cmsgs[i].level;
cmsgh->cmsg_type = cmsgs[i].type;
memcpy(CMSG_DATA(cmsgh), cmsgs[i].data.buf, data_len);
}
}
/* Make the system call. */
if (!IS_SELECTABLE(s)) {
select_error();
goto finally;
}
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);
Py_END_ALLOW_THREADS;
if (timeout == 1) {
PyErr_SetString(socket_timeout, "timed out");
goto finally;
}
END_SELECT_LOOP(s)
if (bytes_sent < 0) {
s->errorhandler();
goto finally;
}
retval = PyLong_FromSsize_t(bytes_sent);
finally:
PyMem_Free(controlbuf);
for (i = 0; i < ncmsgbufs; i++)
PyBuffer_Release(&cmsgs[i].data);
PyMem_Free(cmsgs);
Py_XDECREF(cmsg_fast);
for (i = 0; i < ndatabufs; i++)
PyBuffer_Release(&databufs[i]);
PyMem_Free(databufs);
PyMem_Free(iovs);
Py_XDECREF(data_fast);
return retval;
}
PyDoc_STRVAR(sendmsg_doc,
"sendmsg(buffers[, ancdata[, flags[, address]]]) -> count\n\
\n\
Send normal and ancillary data to the socket, gathering the\n\
non-ancillary data from a series of buffers and concatenating it into\n\
a single message. The buffers argument specifies the non-ancillary\n\
data as an iterable of buffer-compatible objects (e.g. bytes objects).\n\
The ancdata argument specifies the ancillary data (control messages)\n\
as an iterable of zero or more tuples (cmsg_level, cmsg_type,\n\
cmsg_data), where cmsg_level and cmsg_type are integers specifying the\n\
protocol level and protocol-specific type respectively, and cmsg_data\n\
is a buffer-compatible object holding the associated data. The flags\n\
argument defaults to 0 and has the same meaning as for send(). If\n\
address is supplied and not None, it sets a destination address for\n\
the message. The return value is the number of bytes of non-ancillary\n\
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},
{"recvmsg_into", (PyCFunction)sock_recvmsg_into, METH_VARARGS,
recvmsg_into_doc,},
{"sendmsg", (PyCFunction)sock_sendmsg, METH_VARARGS,
sendmsg_doc},
#endif
{NULL, NULL} /* sentinel */
};
@ -4377,6 +5066,68 @@ Returns the interface name corresponding to the interface index if_index.");
#endif /* HAVE_IF_NAMEINDEX */
#ifdef CMSG_LEN
/* Python interface to CMSG_LEN(length). */
static PyObject *
socket_CMSG_LEN(PyObject *self, PyObject *args)
{
Py_ssize_t length;
size_t result;
if (!PyArg_ParseTuple(args, "n:CMSG_LEN", &length))
return NULL;
if (length < 0 || !get_CMSG_LEN(length, &result)) {
PyErr_Format(PyExc_OverflowError, "CMSG_LEN() argument out of range");
return NULL;
}
return PyLong_FromSize_t(result);
}
PyDoc_STRVAR(CMSG_LEN_doc,
"CMSG_LEN(length) -> control message length\n\
\n\
Return the total length, without trailing padding, of an ancillary\n\
data item with associated data of the given length. This value can\n\
often be used as the buffer size for recvmsg() to receive a single\n\
item of ancillary data, but RFC 3542 requires portable applications to\n\
use CMSG_SPACE() and thus include space for padding, even when the\n\
item will be the last in the buffer. Raises OverflowError if length\n\
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)
{
Py_ssize_t length;
size_t result;
if (!PyArg_ParseTuple(args, "n:CMSG_SPACE", &length))
return NULL;
if (length < 0 || !get_CMSG_SPACE(length, &result)) {
PyErr_SetString(PyExc_OverflowError,
"CMSG_SPACE() argument out of range");
return NULL;
}
return PyLong_FromSize_t(result);
}
PyDoc_STRVAR(CMSG_SPACE_doc,
"CMSG_SPACE(length) -> buffer size\n\
\n\
Return the buffer size needed for recvmsg() to receive an ancillary\n\
data item with associated data of the given length, along with any\n\
trailing padding. The buffer space needed to receive multiple items\n\
is the sum of the CMSG_SPACE() values for their associated data\n\
lengths. Raises OverflowError if length is outside the permissible\n\
range of values.");
#endif /* CMSG_SPACE */
#endif /* CMSG_LEN */
/* List of functions exported by this module. */
static PyMethodDef socket_methods[] = {
@ -4439,6 +5190,14 @@ static PyMethodDef socket_methods[] = {
METH_VARARGS, if_nametoindex_doc},
{"if_indextoname", socket_if_indextoname,
METH_O, if_indextoname_doc},
#endif
#ifdef CMSG_LEN
{"CMSG_LEN", socket_CMSG_LEN,
METH_VARARGS, CMSG_LEN_doc},
#ifdef CMSG_SPACE
{"CMSG_SPACE", socket_CMSG_SPACE,
METH_VARARGS, CMSG_SPACE_doc},
#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
PyModule_AddIntConstant(m, "SO_PASSCRED", SO_PASSCRED);
#endif
#ifdef SO_PEERCRED
PyModule_AddIntConstant(m, "SO_PEERCRED", SO_PEERCRED);
#endif
#ifdef LOCAL_PEERCRED
PyModule_AddIntConstant(m, "LOCAL_PEERCRED", 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
/* Ancilliary message types */
#ifdef SCM_RIGHTS
PyModule_AddIntConstant(m, "SCM_RIGHTS", SCM_RIGHTS);
#endif
#ifdef SCM_CREDENTIALS
PyModule_AddIntConstant(m, "SCM_CREDENTIALS", SCM_CREDENTIALS);
#endif
#ifdef SCM_CREDS
PyModule_AddIntConstant(m, "SCM_CREDS", SCM_CREDS);
#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
PyModule_AddIntConstant(m, "MSG_NOSIGNAL", MSG_NOSIGNAL);
#endif
#ifdef MSG_NOTIFICATION
PyModule_AddIntConstant(m, "MSG_NOTIFICATION", MSG_NOTIFICATION);
#endif
#ifdef MSG_CMSG_CLOEXEC
PyModule_AddIntConstant(m, "MSG_CMSG_CLOEXEC", MSG_CMSG_CLOEXEC);
#endif
#ifdef MSG_ERRQUEUE
PyModule_AddIntConstant(m, "MSG_ERRQUEUE", MSG_ERRQUEUE);
#endif
#ifdef MSG_CONFIRM
PyModule_AddIntConstant(m, "MSG_CONFIRM", MSG_CONFIRM);
#endif
#ifdef MSG_MORE
PyModule_AddIntConstant(m, "MSG_MORE", MSG_MORE);
#endif
#ifdef MSG_EOF
PyModule_AddIntConstant(m, "MSG_EOF", MSG_EOF);
#endif
#ifdef MSG_BCAST
PyModule_AddIntConstant(m, "MSG_BCAST", MSG_BCAST);
#endif
#ifdef MSG_MCAST
PyModule_AddIntConstant(m, "MSG_MCAST", MSG_MCAST);
#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
PyModule_AddIntConstant(m, "IPPROTO_SCTP", IPPROTO_SCTP);
#endif
#ifdef IPPROTO_BIP
PyModule_AddIntConstant(m, "IPPROTO_BIP", IPPROTO_BIP);
#endif