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

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