--- py3k_2/Modules/socketmodule.c 2009-07-23 17:07:55.474581000 +0200
+++ py3k/Modules/socketmodule.c 2009-07-24 10:17:33.540000250 +0200
@@ -2388,6 +2388,7 @@
return n;
}
+
/* s.recvfrom(nbytes [,flags]) method */
static PyObject *
@@ -2440,6 +2441,156 @@
Like recv(buffersize, flags) but also return the sender's address info.");
+/* s.recvmsg(datalen, controllen, flags) method */
+
+static PyObject *
+sock_recvmsg(PySocketSockObject *s, PyObject *args)
+{
+ PyObject *dbuf, *cbuf, *alist, *tmp;
+ ssize_t n = -1;
+ int status, timeout;
+ int rdlen, rclen, flags = 0;
+ struct msghdr mhdr;
+ struct cmsghdr *chdr;
+ struct iovec iov[1];
+
+ if (!PyArg_ParseTuple(args, "ii|i:recvmsg", &rdlen, &rclen, &flags))
+ return NULL;
+
+ if (rdlen < 0 || rclen < 0)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "negative buffersize in recvmsg");
+ return NULL;
+ }
+
+ /* allocate buffers */
+ dbuf = PyBytes_FromStringAndSize((char *) 0, rdlen);
+ if (dbuf == NULL)
+ {
+ return NULL;
+ }
+
+ cbuf = PyBytes_FromStringAndSize((char *) 0, rclen);
+ if (cbuf == NULL)
+ {
+ Py_DECREF(dbuf);
+ return NULL;
+ }
+
+ alist = PyList_New(0);
+ if (alist == NULL)
+ {
+ Py_DECREF(dbuf);
+ Py_DECREF(cbuf);
+ return NULL;
+ }
+
+ /* set up the msghdr struct */
+ memset(&mhdr, 0, sizeof(struct msghdr));
+
+ /* iov -- we use only one buffer, and don't use scatter-gather
+ possible TODO */
+ iov[0].iov_base = PyBytes_AS_STRING(dbuf);
+ iov[0].iov_len = rdlen;
+
+ /* msghdr */
+ mhdr.msg_name = NULL; /* TODO make use of this */
+ mhdr.msg_namelen = 0;
+ mhdr.msg_iov = iov;
+ mhdr.msg_iovlen = 1;
+ mhdr.msg_control = PyBytes_AS_STRING(cbuf);
+ mhdr.msg_controllen = rclen;
+ mhdr.msg_flags = 0;
+
+ /* call recvmsg() */
+ if (!IS_SELECTABLE(s)) {
+ select_error();
+ return -1;
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ timeout = internal_select(s, 0);
+ if (!timeout)
+ n = recvmsg(s->sock_fd, &mhdr, flags);
+ Py_END_ALLOW_THREADS
+
+ if (timeout == 1)
+ {
+ PyErr_SetString(socket_timeout, "timed out");
+ goto err;
+ }
+
+ if (n < 0)
+ {
+ s->errorhandler();
+ goto err;
+ }
+
+ for (chdr = CMSG_FIRSTHDR(&mhdr); chdr != NULL;
+ chdr = CMSG_NXTHDR(&mhdr, chdr))
+ {
+ tmp = Py_BuildValue("(iiy#)", chdr->cmsg_level,
+ chdr->cmsg_type, (char *)CMSG_DATA(chdr),
+ /* TODO XXX ugly hack, to compute
+ CMSG_DATA's size. Any better ways to
+ do this? */
+ (int)chdr->cmsg_len -
+ ((int)CMSG_DATA(chdr) -
+ (int)chdr));
+ if (tmp == NULL)
+ goto err;
+
+ status = PyList_Append(alist, tmp);
+ Py_DECREF(tmp);
+
+ if (status == -1)
+ goto err;
+ }
+
+ /* if we received less than we anticipated, resize the buffer */
+ if (n != rdlen)
+ {
+ if (_PyBytes_Resize(&dbuf, n) == -1)
+ {
+ Py_DECREF(cbuf);
+ Py_DECREF(alist);
+ return NULL;
+ }
+ }
+
+ /* assemble the final return value, watch out for offsets! */
+ tmp = PyTuple_New(3);
+ if (tmp == NULL)
+ goto err;
+
+ PyTuple_SetItem(tmp, 0, dbuf);
+ PyTuple_SetItem(tmp, 1, alist);
+ PyTuple_SetItem(tmp, 2, Py_BuildValue("i", mhdr.msg_flags));
+
+ /* dbuf and alist are now in tmp, remove reference to
+ cbuf and return */
+ Py_DECREF(cbuf);
+
+ return tmp;
+
+err:
+ Py_DECREF(dbuf);
+ Py_DECREF(cbuf);
+ Py_DECREF(alist);
+ return NULL;
+}
+
+PyDoc_STRVAR(recvmsg_doc,
+"recvmsg(datalen, controllen, flags) method -> (bytes(), [(msglevel, \
+msgtype, msgdata) ... ], flags)\n\
+\n\
+Returns a tuple with three elements, 0: data bytes, 1: list of tuples \
+with three elements\n\
+containing msg_level, msg_type, msg_data, 2: msg_flags\n\
+Currently it's incapable of using multiple buffers and addresses.");
+
+
/* s.recvfrom_into(buffer[, nbytes [,flags]]) method */
static PyObject *
@@ -2655,6 +2806,146 @@
For IP sockets, the address is a pair (hostaddr, port).");
+/* s.sendmsg(data, [(msglevel, msgtype, msgdata), ...], flags) method */
+
+static PyObject *
+sock_sendmsg(PySocketSockObject *s, PyObject *args)
+{
+ Py_buffer dbuf;
+ PyObject *cbuf;
+ PyObject *tmp;
+ Py_buffer tmpdata;
+ PyObject *control;
+ size_t cbuflen = 0;
+ size_t controllen;
+ int tmplev, tmptype;
+ int timeout, flags = 0;
+ int i, n = -1;
+ struct msghdr mhdr;
+ struct cmsghdr *chdr;
+ struct iovec iov[1];
+
+ if (!PyArg_ParseTuple(args, "y*O!I|:sendmsg", &dbuf, &PyList_Type,
+ &control, &flags)) {
+ return NULL;
+ }
+
+ controllen = PyList_Size(control);
+
+ /* set up the msghdr struct
+ count the bytes to allocate for msg_control */
+ for (i=0; icmsg_len = CMSG_LEN(tmpdata.len);
+ chdr->cmsg_level = tmplev;
+ chdr->cmsg_type = tmptype;
+ memcpy(CMSG_DATA(chdr), tmpdata.buf, tmpdata.len);
+ }
+
+ /* call sendmsg() */
+ if (!IS_SELECTABLE(s))
+ {
+ Py_DECREF(cbuf);
+ return select_error();
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ timeout = internal_select(s, 1);
+ if (!timeout)
+ n = sendmsg(s->sock_fd, &mhdr, flags);
+ Py_END_ALLOW_THREADS
+
+ /* free the parameters */
+ PyBuffer_Release(&dbuf);
+ Py_DECREF(cbuf);
+
+ if (timeout == 1)
+ {
+ PyErr_SetString(socket_timeout, "timed out");
+ return NULL;
+ }
+
+ if (n < 0)
+ {
+ return s->errorhandler();
+ }
+
+ return Py_BuildValue("I", n);
+
+err:
+ Py_DECREF(cbuf);
+ return NULL;
+}
+
+PyDoc_STRVAR(sendmsg_doc,
+"sendmsg(data, [(msglevel, msgtype, msgdata), ...], flags) -> sent\n\
+\n\
+Returns the bytes sent. Accepts 3 parameters, 1: the data bytes, 2: a list\n\
+containing tuples, that contain the msg_level, msg_type, msg_data, 3:\n\
+flags. Currently it's incapable of using multiple buffers and addresses.");
+
+
/* s.shutdown(how) method */
static PyObject *
@@ -2742,6 +3033,8 @@
recv_into_doc},
{"recvfrom", (PyCFunction)sock_recvfrom, METH_VARARGS,
recvfrom_doc},
+ {"recvmsg", (PyCFunction)sock_recvmsg, METH_VARARGS,
+ recvmsg_doc},
{"recvfrom_into", (PyCFunction)sock_recvfrom_into, METH_VARARGS | METH_KEYWORDS,
recvfrom_into_doc},
{"send", (PyCFunction)sock_send, METH_VARARGS,
@@ -2750,6 +3043,8 @@
sendall_doc},
{"sendto", (PyCFunction)sock_sendto, METH_VARARGS,
sendto_doc},
+ {"sendmsg", (PyCFunction)sock_sendmsg, METH_VARARGS,
+ sendmsg_doc},
{"setblocking", (PyCFunction)sock_setblocking, METH_O,
setblocking_doc},
{"settimeout", (PyCFunction)sock_settimeout, METH_O,
@@ -4513,6 +4808,14 @@
PyModule_AddIntConstant(m, "SO_TYPE", SO_TYPE);
#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
+
/* Maximum number of connections for "listen" */
#ifdef SOMAXCONN
PyModule_AddIntConstant(m, "SOMAXCONN", SOMAXCONN);
@@ -4551,6 +4854,9 @@
#ifdef MSG_ETAG
PyModule_AddIntConstant(m, "MSG_ETAG", MSG_ETAG);
#endif
+#ifdef MSG_ERRQUEUE
+ PyModule_AddIntConstant(m, "MSG_ERRQUEUE", MSG_ERRQUEUE);
+#endif
/* Protocol level and numbers, usable for [gs]etsockopt */
#ifdef SOL_SOCKET