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