mirror of
https://github.com/python/cpython.git
synced 2024-11-23 18:04:37 +08:00
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:
parent
8983729dc0
commit
96fe56abec
@ -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
|
||||
|
@ -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
|
||||
---
|
||||
|
24
Lib/ssl.py
24
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()
|
||||
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
@ -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_"
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user