123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519 |
- /*
- * Copyright (c) Twisted Matrix Laboratories.
- * See LICENSE for details.
- */
- #define PY_SSIZE_T_CLEAN 1
- #include <Python.h>
- #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
- /* This may cause some warnings, but if you want to get rid of them, upgrade
- * your Python version. */
- typedef int Py_ssize_t;
- #endif
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <signal.h>
- #include <sys/param.h>
- #ifdef BSD
- #include <sys/uio.h>
- #endif
- /*
- * As per
- * <http://pubs.opengroup.org/onlinepubs/007904875/basedefs/sys/socket.h.html
- * #tag_13_61_05>:
- *
- * "To forestall portability problems, it is recommended that applications
- * not use values larger than (2**31)-1 for the socklen_t type."
- */
- #define SOCKLEN_MAX 0x7FFFFFFF
- PyObject *sendmsg_socket_error;
- static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds);
- static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds);
- static PyObject *sendmsg_getsockfam(PyObject *self, PyObject *args, PyObject *keywds);
- static char sendmsg_doc[] = "\
- Bindings for sendmsg(2), recvmsg(2), and a minimal helper for inspecting\n\
- address family of a socket.\n\
- ";
- static char sendmsg_sendmsg_doc[] = "\
- Wrap the C sendmsg(2) function for sending \"messages\" on a socket.\n\
- \n\
- @param fd: The file descriptor of the socket over which to send a message.\n\
- @type fd: C{int}\n\
- \n\
- @param data: Bytes to write to the socket.\n\
- @type data: C{str}\n\
- \n\
- @param flags: Flags to affect how the message is sent. See the C{MSG_}\n\
- constants in the sendmsg(2) manual page. By default no flags are set.\n\
- @type flags: C{int}\n\
- \n\
- @param ancillary: Extra data to send over the socket outside of the normal\n\
- datagram or stream mechanism. By default no ancillary data is sent.\n\
- @type ancillary: C{list} of C{tuple} of C{int}, C{int}, and C{str}.\n\
- \n\
- @raise OverflowError: Raised if too much ancillary data is given.\n\
- @raise socket.error: Raised if the underlying syscall indicates an error.\n\
- \n\
- @return: The return value of the underlying syscall, if it succeeds.\n\
- ";
- static char sendmsg_recvmsg_doc[] = "\
- Wrap the C recvmsg(2) function for receiving \"messages\" on a socket.\n\
- \n\
- @param fd: The file descriptor of the socket over which to receive a message.\n\
- @type fd: C{int}\n\
- \n\
- @param flags: Flags to affect how the message is sent. See the C{MSG_}\n\
- constants in the sendmsg(2) manual page. By default no flags are set.\n\
- @type flags: C{int}\n\
- \n\
- @param maxsize: The maximum number of bytes to receive from the socket\n\
- using the datagram or stream mechanism. The default maximum is 8192.\n\
- @type maxsize: C{int}\n\
- \n\
- @param cmsg_size: The maximum number of bytes to receive from the socket\n\
- outside of the normal datagram or stream mechanism. The default maximum is 4096.\n\
- \n\
- @raise OverflowError: Raised if too much ancillary data is given.\n\
- @raise socket.error: Raised if the underlying syscall indicates an error.\n\
- \n\
- @return: A C{tuple} of three elements: the bytes received using the\n\
- datagram/stream mechanism, flags as an C{int} describing the data\n\
- received, and a C{list} of C{tuples} giving ancillary received data.\n\
- ";
- static char sendmsg_getsockfam_doc[] = "\
- Retrieve the address family of a given socket.\n\
- \n\
- @param fd: The file descriptor of the socket the address family of which\n\
- to retrieve.\n\
- @type fd: C{int}\n\
- \n\
- @raise socket.error: Raised if the underlying getsockname call indicates\n\
- an error.\n\
- \n\
- @return: A C{int} representing the address family of the socket. For\n\
- example, L{socket.AF_INET}, L{socket.AF_INET6}, or L{socket.AF_UNIX}.\n\
- ";
- static PyMethodDef sendmsg_methods[] = {
- {"send1msg", (PyCFunction) sendmsg_sendmsg, METH_VARARGS | METH_KEYWORDS,
- sendmsg_sendmsg_doc},
- {"recv1msg", (PyCFunction) sendmsg_recvmsg, METH_VARARGS | METH_KEYWORDS,
- sendmsg_recvmsg_doc},
- {"getsockfam", (PyCFunction) sendmsg_getsockfam,
- METH_VARARGS | METH_KEYWORDS, sendmsg_getsockfam_doc},
- {NULL, NULL, 0, NULL}
- };
- PyMODINIT_FUNC init_sendmsg(void) {
- PyObject *module;
- sendmsg_socket_error = NULL; /* Make sure that this has a known value
- before doing anything that might exit. */
- module = Py_InitModule3("_sendmsg", sendmsg_methods, sendmsg_doc);
- if (!module) {
- return;
- }
- /*
- The following is the only value mentioned by POSIX:
- http://www.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html
- */
- if (-1 == PyModule_AddIntConstant(module, "SCM_RIGHTS", SCM_RIGHTS)) {
- return;
- }
- /* BSD, Darwin, Hurd */
- #if defined(SCM_CREDS)
- if (-1 == PyModule_AddIntConstant(module, "SCM_CREDS", SCM_CREDS)) {
- return;
- }
- #endif
- /* Linux */
- #if defined(SCM_CREDENTIALS)
- if (-1 == PyModule_AddIntConstant(module, "SCM_CREDENTIALS", SCM_CREDENTIALS)) {
- return;
- }
- #endif
- /* Apparently everywhere, but not standardized. */
- #if defined(SCM_TIMESTAMP)
- if (-1 == PyModule_AddIntConstant(module, "SCM_TIMESTAMP", SCM_TIMESTAMP)) {
- return;
- }
- #endif
- module = PyImport_ImportModule("socket");
- if (!module) {
- return;
- }
- sendmsg_socket_error = PyObject_GetAttrString(module, "error");
- if (!sendmsg_socket_error) {
- return;
- }
- }
- static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds) {
- int fd;
- int flags = 0;
- Py_ssize_t sendmsg_result, iovec_length;
- struct msghdr message_header;
- struct iovec iov[1];
- PyObject *ancillary = NULL;
- PyObject *iterator = NULL;
- PyObject *item = NULL;
- PyObject *result_object = NULL;
- static char *kwlist[] = {"fd", "data", "flags", "ancillary", NULL};
- if (!PyArg_ParseTupleAndKeywords(
- args, keywds, "it#|iO:sendmsg", kwlist,
- &fd,
- &iov[0].iov_base,
- &iovec_length,
- &flags,
- &ancillary)) {
- return NULL;
- }
- iov[0].iov_len = iovec_length;
- message_header.msg_name = NULL;
- message_header.msg_namelen = 0;
- message_header.msg_iov = iov;
- message_header.msg_iovlen = 1;
- message_header.msg_control = NULL;
- message_header.msg_controllen = 0;
- message_header.msg_flags = 0;
- if (ancillary) {
- if (!PyList_Check(ancillary)) {
- PyErr_Format(PyExc_TypeError,
- "send1msg argument 3 expected list, got %s",
- ancillary->ob_type->tp_name);
- goto finished;
- }
- iterator = PyObject_GetIter(ancillary);
- if (iterator == NULL) {
- goto finished;
- }
- size_t all_data_len = 0;
- /* First we need to know how big the buffer needs to be in order to
- have enough space for all of the messages. */
- while ( (item = PyIter_Next(iterator)) ) {
- int type, level;
- Py_ssize_t data_len;
- size_t prev_all_data_len;
- char *data;
- if (!PyTuple_Check(item)) {
- PyErr_Format(PyExc_TypeError,
- "send1msg argument 3 expected list of tuple, "
- "got list containing %s",
- item->ob_type->tp_name);
- goto finished;
- }
- if (!PyArg_ParseTuple(
- item, "iit#:sendmsg ancillary data (level, type, data)",
- &level, &type, &data, &data_len)) {
- goto finished;
- }
- prev_all_data_len = all_data_len;
- all_data_len += CMSG_SPACE(data_len);
- Py_DECREF(item);
- item = NULL;
- if (all_data_len < prev_all_data_len) {
- PyErr_Format(PyExc_OverflowError,
- "Too much msg_control to fit in a size_t: %zu",
- prev_all_data_len);
- goto finished;
- }
- }
- Py_DECREF(iterator);
- iterator = NULL;
- /* Allocate the buffer for all of the ancillary elements, if we have
- * any. */
- if (all_data_len) {
- if (all_data_len > SOCKLEN_MAX) {
- PyErr_Format(PyExc_OverflowError,
- "Too much msg_control to fit in a socklen_t: %zu",
- all_data_len);
- goto finished;
- }
- message_header.msg_control = PyMem_Malloc(all_data_len);
- if (!message_header.msg_control) {
- PyErr_NoMemory();
- goto finished;
- }
- /* From Python 3.5.2 socketmodule.c:3891:
- 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 this doesn't happen. */
- memset(message_header.msg_control, 0, all_data_len);
- } else {
- message_header.msg_control = NULL;
- }
- message_header.msg_controllen = (socklen_t) all_data_len;
- iterator = PyObject_GetIter(ancillary); /* again */
- if (!iterator) {
- goto finished;
- }
- /* Unpack the tuples into the control message. */
- struct cmsghdr *control_message = CMSG_FIRSTHDR(&message_header);
- while ( (item = PyIter_Next(iterator)) && control_message!=NULL ) {
- int type, level;
- Py_ssize_t data_len;
- size_t data_size;
- unsigned char *data, *cmsg_data;
- /* We explicitly allocated enough space for all ancillary data
- above; if there isn't enough room, all bets are off. */
- assert(control_message);
- if (!PyArg_ParseTuple(item,
- "iit#:sendmsg ancillary data (level, type, data)",
- &level,
- &type,
- &data,
- &data_len)) {
- goto finished;
- }
- control_message->cmsg_level = level;
- control_message->cmsg_type = type;
- data_size = CMSG_LEN(data_len);
- if (data_size > SOCKLEN_MAX) {
- PyErr_Format(PyExc_OverflowError,
- "CMSG_LEN(%zd) > SOCKLEN_MAX", data_len);
- goto finished;
- }
- control_message->cmsg_len = (socklen_t) data_size;
- cmsg_data = CMSG_DATA(control_message);
- memcpy(cmsg_data, data, data_len);
- Py_DECREF(item);
- item = NULL;
- control_message = CMSG_NXTHDR(&message_header, control_message);
- }
- Py_DECREF(iterator);
- iterator = NULL;
- if (PyErr_Occurred()) {
- goto finished;
- }
- }
- sendmsg_result = sendmsg(fd, &message_header, flags);
- if (sendmsg_result < 0) {
- PyErr_SetFromErrno(sendmsg_socket_error);
- goto finished;
- }
- result_object = Py_BuildValue("n", sendmsg_result);
- finished:
- if (item) {
- Py_DECREF(item);
- item = NULL;
- }
- if (iterator) {
- Py_DECREF(iterator);
- iterator = NULL;
- }
- if (message_header.msg_control) {
- PyMem_Free(message_header.msg_control);
- message_header.msg_control = NULL;
- }
- return result_object;
- }
- static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds) {
- int fd = -1;
- int flags = 0;
- int maxsize = 8192;
- int cmsg_size = 4096;
- size_t cmsg_space;
- size_t cmsg_overhead;
- Py_ssize_t recvmsg_result;
- struct msghdr message_header;
- struct cmsghdr *control_message;
- struct iovec iov[1];
- char *cmsgbuf;
- PyObject *ancillary;
- PyObject *final_result = NULL;
- static char *kwlist[] = {"fd", "flags", "maxsize", "cmsg_size", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|iii:recvmsg", kwlist,
- &fd, &flags, &maxsize, &cmsg_size)) {
- return NULL;
- }
- cmsg_space = CMSG_SPACE(cmsg_size);
- /* overflow check */
- if (cmsg_space > SOCKLEN_MAX) {
- PyErr_Format(PyExc_OverflowError,
- "CMSG_SPACE(cmsg_size) greater than SOCKLEN_MAX: %d",
- cmsg_size);
- return NULL;
- }
- message_header.msg_name = NULL;
- message_header.msg_namelen = 0;
- iov[0].iov_len = maxsize;
- iov[0].iov_base = PyMem_Malloc(maxsize);
- if (!iov[0].iov_base) {
- PyErr_NoMemory();
- return NULL;
- }
- message_header.msg_iov = iov;
- message_header.msg_iovlen = 1;
- cmsgbuf = PyMem_Malloc(cmsg_space);
- if (!cmsgbuf) {
- PyMem_Free(iov[0].iov_base);
- PyErr_NoMemory();
- return NULL;
- }
- memset(cmsgbuf, 0, cmsg_space);
- message_header.msg_control = cmsgbuf;
- /* see above for overflow check */
- message_header.msg_controllen = (socklen_t) cmsg_space;
- recvmsg_result = recvmsg(fd, &message_header, flags);
- if (recvmsg_result < 0) {
- PyErr_SetFromErrno(sendmsg_socket_error);
- goto finished;
- }
- ancillary = PyList_New(0);
- if (!ancillary) {
- goto finished;
- }
- for (control_message = CMSG_FIRSTHDR(&message_header);
- control_message;
- control_message = CMSG_NXTHDR(&message_header,
- control_message)) {
- PyObject *entry;
- /* Some platforms apparently always fill out the ancillary data
- structure with a single bogus value if none is provided; ignore it,
- if that is the case. */
- if ((!(control_message->cmsg_level)) &&
- (!(control_message->cmsg_type))) {
- continue;
- }
- /*
- * Figure out how much of the cmsg size is cmsg structure overhead - in
- * other words, how much is not part of the application data. This lets
- * us compute the right application data size below. There should
- * really be a CMSG_ macro for this.
- */
- cmsg_overhead = (char*)CMSG_DATA(control_message) - (char*)control_message;
- entry = Py_BuildValue(
- "(iis#)",
- control_message->cmsg_level,
- control_message->cmsg_type,
- CMSG_DATA(control_message),
- (Py_ssize_t) (control_message->cmsg_len - cmsg_overhead));
- if (!entry) {
- Py_DECREF(ancillary);
- goto finished;
- }
- if (PyList_Append(ancillary, entry) < 0) {
- Py_DECREF(ancillary);
- Py_DECREF(entry);
- goto finished;
- } else {
- Py_DECREF(entry);
- }
- }
- final_result = Py_BuildValue(
- "s#iO",
- iov[0].iov_base,
- recvmsg_result,
- message_header.msg_flags,
- ancillary);
- Py_DECREF(ancillary);
- finished:
- PyMem_Free(iov[0].iov_base);
- PyMem_Free(cmsgbuf);
- return final_result;
- }
- static PyObject *sendmsg_getsockfam(PyObject *self, PyObject *args,
- PyObject *keywds) {
- int fd;
- struct sockaddr sa;
- static char *kwlist[] = {"fd", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, keywds, "i", kwlist, &fd)) {
- return NULL;
- }
- socklen_t sz = sizeof(sa);
- if (getsockname(fd, &sa, &sz)) {
- PyErr_SetFromErrno(sendmsg_socket_error);
- return NULL;
- }
- return Py_BuildValue("i", sa.sa_family);
- }
|