2 * Copyright (c) Twisted Matrix Laboratories.
3 * See LICENSE for details.
6 #define PY_SSIZE_T_CLEAN 1
9 #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
10 /* This may cause some warnings, but if you want to get rid of them, upgrade
11 * your Python version. */
12 typedef int Py_ssize_t;
15 #include <sys/types.h>
16 #include <sys/socket.h>
21 * <http://pubs.opengroup.org/onlinepubs/007904875/basedefs/sys/socket.h.html
24 * "To forestall portability problems, it is recommended that applications
25 * not use values larger than (2**31)-1 for the socklen_t type."
28 #define SOCKLEN_MAX 0x7FFFFFFF
30 PyObject *sendmsg_socket_error;
32 static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds);
33 static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds);
34 static PyObject *sendmsg_getsockfam(PyObject *self, PyObject *args, PyObject *keywds);
36 static char sendmsg_doc[] = "\
37 Bindings for sendmsg(2), recvmsg(2), and a minimal helper for inspecting\n\
38 address family of a socket.\n\
41 static char sendmsg_sendmsg_doc[] = "\
42 Wrap the C sendmsg(2) function for sending \"messages\" on a socket.\n\
44 @param fd: The file descriptor of the socket over which to send a message.\n\
47 @param data: Bytes to write to the socket.\n\
50 @param flags: Flags to affect how the message is sent. See the C{MSG_}\n\
51 constants in the sendmsg(2) manual page. By default no flags are set.\n\
52 @type flags: C{int}\n\
54 @param ancillary: Extra data to send over the socket outside of the normal\n\
55 datagram or stream mechanism. By default no ancillary data is sent.\n\
56 @type ancillary: C{list} of C{tuple} of C{int}, C{int}, and C{str}.\n\
58 @raise OverflowError: Raised if too much ancillary data is given.\n\
59 @raise socket.error: Raised if the underlying syscall indicates an error.\n\
61 @return: The return value of the underlying syscall, if it succeeds.\n\
64 static char sendmsg_recvmsg_doc[] = "\
65 Wrap the C recvmsg(2) function for receiving \"messages\" on a socket.\n\
67 @param fd: The file descriptor of the socket over which to receve a message.\n\
70 @param flags: Flags to affect how the message is sent. See the C{MSG_}\n\
71 constants in the sendmsg(2) manual page. By default no flags are set.\n\
72 @type flags: C{int}\n\
74 @param maxsize: The maximum number of bytes to receive from the socket\n\
75 using the datagram or stream mechanism. The default maximum is 8192.\n\
76 @type maxsize: C{int}\n\
78 @param cmsg_size: The maximum number of bytes to receive from the socket\n\
79 outside of the normal datagram or stream mechanism. The default maximum is 4096.\n\
81 @raise OverflowError: Raised if too much ancillary data is given.\n\
82 @raise socket.error: Raised if the underlying syscall indicates an error.\n\
84 @return: A C{tuple} of three elements: the bytes received using the\n\
85 datagram/stream mechanism, flags as an C{int} describing the data\n\
86 received, and a C{list} of C{tuples} giving ancillary received data.\n\
89 static char sendmsg_getsockfam_doc[] = "\
90 Retrieve the address family of a given socket.\n\
92 @param fd: The file descriptor of the socket the address family of which\n\
96 @raise socket.error: Raised if the underlying getsockname call indicates\n\
99 @return: A C{int} representing the address family of the socket. For\n\
100 example, L{socket.AF_INET}, L{socket.AF_INET6}, or L{socket.AF_UNIX}.\n\
103 static PyMethodDef sendmsg_methods[] = {
104 {"send1msg", (PyCFunction) sendmsg_sendmsg, METH_VARARGS | METH_KEYWORDS,
105 sendmsg_sendmsg_doc},
106 {"recv1msg", (PyCFunction) sendmsg_recvmsg, METH_VARARGS | METH_KEYWORDS,
107 sendmsg_recvmsg_doc},
108 {"getsockfam", (PyCFunction) sendmsg_getsockfam,
109 METH_VARARGS | METH_KEYWORDS, sendmsg_getsockfam_doc},
110 {NULL, NULL, 0, NULL}
114 PyMODINIT_FUNC initsendmsg(void) {
117 sendmsg_socket_error = NULL; /* Make sure that this has a known value
118 before doing anything that might exit. */
120 module = Py_InitModule3("sendmsg", sendmsg_methods, sendmsg_doc);
127 The following is the only value mentioned by POSIX:
128 http://www.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html
131 if (-1 == PyModule_AddIntConstant(module, "SCM_RIGHTS", SCM_RIGHTS)) {
136 /* BSD, Darwin, Hurd */
137 #if defined(SCM_CREDS)
138 if (-1 == PyModule_AddIntConstant(module, "SCM_CREDS", SCM_CREDS)) {
144 #if defined(SCM_CREDENTIALS)
145 if (-1 == PyModule_AddIntConstant(module, "SCM_CREDENTIALS", SCM_CREDENTIALS)) {
150 /* Apparently everywhere, but not standardized. */
151 #if defined(SCM_TIMESTAMP)
152 if (-1 == PyModule_AddIntConstant(module, "SCM_TIMESTAMP", SCM_TIMESTAMP)) {
157 module = PyImport_ImportModule("socket");
162 sendmsg_socket_error = PyObject_GetAttrString(module, "error");
163 if (!sendmsg_socket_error) {
168 static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds) {
172 Py_ssize_t sendmsg_result;
173 struct msghdr message_header;
175 PyObject *ancillary = NULL;
176 PyObject *iterator = NULL;
177 PyObject *item = NULL;
178 PyObject *result_object = NULL;
180 static char *kwlist[] = {"fd", "data", "flags", "ancillary", NULL};
182 if (!PyArg_ParseTupleAndKeywords(
183 args, keywds, "it#|iO:sendmsg", kwlist,
192 message_header.msg_name = NULL;
193 message_header.msg_namelen = 0;
195 message_header.msg_iov = iov;
196 message_header.msg_iovlen = 1;
198 message_header.msg_control = NULL;
199 message_header.msg_controllen = 0;
201 message_header.msg_flags = 0;
205 if (!PyList_Check(ancillary)) {
206 PyErr_Format(PyExc_TypeError,
207 "send1msg argument 3 expected list, got %s",
208 ancillary->ob_type->tp_name);
212 iterator = PyObject_GetIter(ancillary);
214 if (iterator == NULL) {
218 size_t all_data_len = 0;
220 /* First we need to know how big the buffer needs to be in order to
221 have enough space for all of the messages. */
222 while ( (item = PyIter_Next(iterator)) ) {
225 size_t prev_all_data_len;
228 if (!PyTuple_Check(item)) {
229 PyErr_Format(PyExc_TypeError,
230 "send1msg argument 3 expected list of tuple, "
231 "got list containing %s",
232 item->ob_type->tp_name);
236 if (!PyArg_ParseTuple(
237 item, "iit#:sendmsg ancillary data (level, type, data)",
238 &level, &type, &data, &data_len)) {
242 prev_all_data_len = all_data_len;
243 all_data_len += CMSG_SPACE(data_len);
248 if (all_data_len < prev_all_data_len) {
249 PyErr_Format(PyExc_OverflowError,
250 "Too much msg_control to fit in a size_t: %zu",
259 /* Allocate the buffer for all of the ancillary elements, if we have
262 if (all_data_len > SOCKLEN_MAX) {
263 PyErr_Format(PyExc_OverflowError,
264 "Too much msg_control to fit in a socklen_t: %zu",
268 message_header.msg_control = PyMem_Malloc(all_data_len);
269 if (!message_header.msg_control) {
274 message_header.msg_control = NULL;
276 message_header.msg_controllen = (socklen_t) all_data_len;
278 iterator = PyObject_GetIter(ancillary); /* again */
284 /* Unpack the tuples into the control message. */
285 struct cmsghdr *control_message = CMSG_FIRSTHDR(&message_header);
286 while ( (item = PyIter_Next(iterator)) ) {
287 int data_len, type, level;
289 unsigned char *data, *cmsg_data;
291 /* We explicitly allocated enough space for all ancillary data
292 above; if there isn't enough room, all bets are off. */
293 assert(control_message);
295 if (!PyArg_ParseTuple(item,
296 "iit#:sendmsg ancillary data (level, type, data)",
304 control_message->cmsg_level = level;
305 control_message->cmsg_type = type;
306 data_size = CMSG_LEN(data_len);
308 if (data_size > SOCKLEN_MAX) {
309 PyErr_Format(PyExc_OverflowError,
310 "CMSG_LEN(%d) > SOCKLEN_MAX", data_len);
314 control_message->cmsg_len = (socklen_t) data_size;
316 cmsg_data = CMSG_DATA(control_message);
317 memcpy(cmsg_data, data, data_len);
322 control_message = CMSG_NXTHDR(&message_header, control_message);
327 if (PyErr_Occurred()) {
332 sendmsg_result = sendmsg(fd, &message_header, flags);
334 if (sendmsg_result < 0) {
335 PyErr_SetFromErrno(sendmsg_socket_error);
339 result_object = Py_BuildValue("n", sendmsg_result);
351 if (message_header.msg_control) {
352 PyMem_Free(message_header.msg_control);
353 message_header.msg_control = NULL;
355 return result_object;
358 static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds) {
362 int cmsg_size = 4096;
364 size_t cmsg_overhead;
365 Py_ssize_t recvmsg_result;
367 struct msghdr message_header;
368 struct cmsghdr *control_message;
372 PyObject *final_result = NULL;
374 static char *kwlist[] = {"fd", "flags", "maxsize", "cmsg_size", NULL};
376 if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|iii:recvmsg", kwlist,
377 &fd, &flags, &maxsize, &cmsg_size)) {
381 cmsg_space = CMSG_SPACE(cmsg_size);
384 if (cmsg_space > SOCKLEN_MAX) {
385 PyErr_Format(PyExc_OverflowError,
386 "CMSG_SPACE(cmsg_size) greater than SOCKLEN_MAX: %d",
391 message_header.msg_name = NULL;
392 message_header.msg_namelen = 0;
394 iov[0].iov_len = maxsize;
395 iov[0].iov_base = PyMem_Malloc(maxsize);
397 if (!iov[0].iov_base) {
402 message_header.msg_iov = iov;
403 message_header.msg_iovlen = 1;
405 cmsgbuf = PyMem_Malloc(cmsg_space);
408 PyMem_Free(iov[0].iov_base);
413 memset(cmsgbuf, 0, cmsg_space);
414 message_header.msg_control = cmsgbuf;
415 /* see above for overflow check */
416 message_header.msg_controllen = (socklen_t) cmsg_space;
418 recvmsg_result = recvmsg(fd, &message_header, flags);
419 if (recvmsg_result < 0) {
420 PyErr_SetFromErrno(sendmsg_socket_error);
424 ancillary = PyList_New(0);
429 for (control_message = CMSG_FIRSTHDR(&message_header);
431 control_message = CMSG_NXTHDR(&message_header,
435 /* Some platforms apparently always fill out the ancillary data
436 structure with a single bogus value if none is provided; ignore it,
437 if that is the case. */
439 if ((!(control_message->cmsg_level)) &&
440 (!(control_message->cmsg_type))) {
445 * Figure out how much of the cmsg size is cmsg structure overhead - in
446 * other words, how much is not part of the application data. This lets
447 * us compute the right application data size below. There should
448 * really be a CMSG_ macro for this.
450 cmsg_overhead = (char*)CMSG_DATA(control_message) - (char*)control_message;
452 entry = Py_BuildValue(
454 control_message->cmsg_level,
455 control_message->cmsg_type,
456 CMSG_DATA(control_message),
457 (Py_ssize_t) (control_message->cmsg_len - cmsg_overhead));
460 Py_DECREF(ancillary);
464 if (PyList_Append(ancillary, entry) < 0) {
465 Py_DECREF(ancillary);
473 final_result = Py_BuildValue(
477 message_header.msg_flags,
480 Py_DECREF(ancillary);
483 PyMem_Free(iov[0].iov_base);
488 static PyObject *sendmsg_getsockfam(PyObject *self, PyObject *args,
492 static char *kwlist[] = {"fd", NULL};
493 if (!PyArg_ParseTupleAndKeywords(args, keywds, "i", kwlist, &fd)) {
496 socklen_t sz = sizeof(sa);
497 if (getsockname(fd, &sa, &sz)) {
498 PyErr_SetFromErrno(sendmsg_socket_error);
501 return Py_BuildValue("i", sa.sa_family);