2
* Copyright (c) 2010 Apple Inc. All rights reserved.
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
17
#define PY_SSIZE_T_CLEAN 1
20
#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
21
/* This may cause some warnings, but if you want to get rid of them, upgrade
22
* your Python version. */
23
typedef int Py_ssize_t;
26
#include <sys/types.h>
27
#include <sys/socket.h>
32
* <http://pubs.opengroup.org/onlinepubs/007904875/basedefs/sys/socket.h.html
35
* "To forestall portability problems, it is recommended that applications
36
* not use values larger than (2**31)-1 for the socklen_t type."
39
#define SOCKLEN_MAX 0x7FFFFFFF
41
PyObject *sendmsg_socket_error;
43
static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds);
44
static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds);
46
static PyMethodDef sendmsg_methods[] = {
47
{"sendmsg", (PyCFunction) sendmsg_sendmsg, METH_VARARGS | METH_KEYWORDS,
49
{"recvmsg", (PyCFunction) sendmsg_recvmsg, METH_VARARGS | METH_KEYWORDS,
55
PyMODINIT_FUNC initsendmsg(void) {
58
sendmsg_socket_error = NULL; /* Make sure that this has a known value
59
before doing anything that might exit. */
61
module = Py_InitModule("sendmsg", sendmsg_methods);
68
The following is the only value mentioned by POSIX:
69
http://www.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html
72
if (-1 == PyModule_AddIntConstant(module, "SCM_RIGHTS", SCM_RIGHTS)) {
77
/* BSD, Darwin, Hurd */
78
#if defined(SCM_CREDS)
79
if (-1 == PyModule_AddIntConstant(module, "SCM_CREDS", SCM_CREDS)) {
85
#if defined(SCM_CREDENTIALS)
86
if (-1 == PyModule_AddIntConstant(module, "SCM_CREDENTIALS", SCM_CREDENTIALS)) {
91
/* Apparently everywhere, but not standardized. */
92
#if defined(SCM_TIMESTAMP)
93
if (-1 == PyModule_AddIntConstant(module, "SCM_TIMESTAMP", SCM_TIMESTAMP)) {
98
module = PyImport_ImportModule("socket");
103
sendmsg_socket_error = PyObject_GetAttrString(module, "error");
104
if (!sendmsg_socket_error) {
109
static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds) {
113
Py_ssize_t sendmsg_result;
114
struct msghdr message_header;
116
PyObject *ancillary = NULL;
117
static char *kwlist[] = {"fd", "data", "flags", "ancillary", NULL};
119
if (!PyArg_ParseTupleAndKeywords(
120
args, keywds, "it#|iO:sendmsg", kwlist,
129
message_header.msg_name = NULL;
130
message_header.msg_namelen = 0;
132
message_header.msg_iov = iov;
133
message_header.msg_iovlen = 1;
135
message_header.msg_control = NULL;
136
message_header.msg_controllen = 0;
138
message_header.msg_flags = 0;
142
if (!PyList_Check(ancillary)) {
143
PyErr_Format(PyExc_TypeError,
144
"sendmsg argument 3 expected list, got %s",
145
ancillary->ob_type->tp_name);
149
PyObject *iterator = PyObject_GetIter(ancillary);
150
PyObject *item = NULL;
152
if (iterator == NULL) {
156
size_t all_data_len = 0;
158
/* First we need to know how big the buffer needs to be in order to
159
have enough space for all of the messages. */
160
while ( (item = PyIter_Next(iterator)) ) {
163
size_t prev_all_data_len;
165
if (!PyArg_ParseTuple(
166
item, "iit#:sendmsg ancillary data (level, type, data)",
167
&level, &type, &data, &data_len)) {
173
prev_all_data_len = all_data_len;
174
all_data_len += CMSG_SPACE(data_len);
178
if (all_data_len < prev_all_data_len) {
180
PyErr_Format(PyExc_OverflowError,
181
"Too much msg_control to fit in a size_t: %zu",
190
/* Allocate the buffer for all of the ancillary elements, if we have
193
if (all_data_len > SOCKLEN_MAX) {
194
PyErr_Format(PyExc_OverflowError,
195
"Too much msg_control to fit in a socklen_t: %zu",
199
message_header.msg_control = malloc(all_data_len);
200
if (!message_header.msg_control) {
205
message_header.msg_control = NULL;
207
message_header.msg_controllen = (socklen_t) all_data_len;
209
iterator = PyObject_GetIter(ancillary); /* again */
213
free(message_header.msg_control);
217
/* Unpack the tuples into the control message. */
218
struct cmsghdr *control_message = CMSG_FIRSTHDR(&message_header);
219
while ( (item = PyIter_Next(iterator)) ) {
220
int data_len, type, level;
222
unsigned char *data, *cmsg_data;
224
/* We explicitly allocated enough space for all ancillary data
225
above; if there isn't enough room, all bets are off. */
226
assert(control_message);
228
if (!PyArg_ParseTuple(item,
229
"iit#:sendmsg ancillary data (level, type, data)",
236
free(message_header.msg_control);
240
control_message->cmsg_level = level;
241
control_message->cmsg_type = type;
242
data_size = CMSG_LEN(data_len);
244
if (data_size > SOCKLEN_MAX) {
247
free(message_header.msg_control);
249
PyErr_Format(PyExc_OverflowError,
250
"CMSG_LEN(%d) > SOCKLEN_MAX", data_len);
255
control_message->cmsg_len = (socklen_t) data_size;
257
cmsg_data = CMSG_DATA(control_message);
258
memcpy(cmsg_data, data, data_len);
262
control_message = CMSG_NXTHDR(&message_header, control_message);
267
if (PyErr_Occurred()) {
268
free(message_header.msg_control);
273
sendmsg_result = sendmsg(fd, &message_header, flags);
275
if (sendmsg_result < 0) {
276
PyErr_SetFromErrno(sendmsg_socket_error);
277
if (message_header.msg_control) {
278
free(message_header.msg_control);
283
return Py_BuildValue("n", sendmsg_result);
286
static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds) {
290
int cmsg_size = 4*1024;
292
Py_ssize_t recvmsg_result;
294
struct msghdr message_header;
295
struct cmsghdr *control_message;
299
PyObject *final_result = NULL;
301
static char *kwlist[] = {"fd", "flags", "maxsize", "cmsg_size", NULL};
303
if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|iii:recvmsg", kwlist,
304
&fd, &flags, &maxsize, &cmsg_size)) {
308
cmsg_space = CMSG_SPACE(cmsg_size);
311
if (cmsg_space > SOCKLEN_MAX) {
312
PyErr_Format(PyExc_OverflowError,
313
"CMSG_SPACE(cmsg_size) greater than SOCKLEN_MAX: %d",
318
message_header.msg_name = NULL;
319
message_header.msg_namelen = 0;
321
iov[0].iov_len = maxsize;
322
iov[0].iov_base = malloc(maxsize);
324
if (!iov[0].iov_base) {
329
message_header.msg_iov = iov;
330
message_header.msg_iovlen = 1;
332
cmsgbuf = malloc(cmsg_space);
335
free(iov[0].iov_base);
340
memset(cmsgbuf, 0, cmsg_space);
341
message_header.msg_control = cmsgbuf;
342
/* see above for overflow check */
343
message_header.msg_controllen = (socklen_t) cmsg_space;
345
recvmsg_result = recvmsg(fd, &message_header, flags);
346
if (recvmsg_result < 0) {
347
PyErr_SetFromErrno(sendmsg_socket_error);
351
ancillary = PyList_New(0);
356
for (control_message = CMSG_FIRSTHDR(&message_header);
358
control_message = CMSG_NXTHDR(&message_header,
362
/* Some platforms apparently always fill out the ancillary data
363
structure with a single bogus value if none is provided; ignore it,
364
if that is the case. */
366
if ((!(control_message->cmsg_level)) &&
367
(!(control_message->cmsg_type))) {
371
entry = Py_BuildValue(
373
control_message->cmsg_level,
374
control_message->cmsg_type,
375
CMSG_DATA(control_message),
376
(Py_ssize_t) (control_message->cmsg_len - sizeof(struct cmsghdr)));
379
Py_DECREF(ancillary);
383
if (PyList_Append(ancillary, entry) < 0) {
384
Py_DECREF(ancillary);
392
final_result = Py_BuildValue(
396
message_header.msg_flags,
399
Py_DECREF(ancillary);
402
free(iov[0].iov_base);