~ubuntu-branches/ubuntu/utopic/calendarserver/utopic

« back to all changes in this revision

Viewing changes to twext/python/sendmsg.c

  • Committer: Package Import Robot
  • Author(s): Rahul Amaram
  • Date: 2012-05-29 18:12:12 UTC
  • mfrom: (1.1.2)
  • Revision ID: package-import@ubuntu.com-20120529181212-mxjdfncopy6vou0f
Tags: 3.2+dfsg-1
* New upstream release
* Moved from using cdbs to dh sequencer
* Modified calenderserver init.d script based on /etc/init.d/skeleton script
* Removed ldapdirectory.patch as the OpenLDAP directory service has been 
  merged upstream
* Moved package to section "net" as calendarserver is more service than 
  library (Closes: #665859)
* Changed Architecture of calendarserver package to any as the package
  now includes compiled architecture dependent Python extensions
* Unowned files are no longer left on the system upon purging
  (Closes: #668731)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2010 Apple Inc. All rights reserved.
 
3
 *
 
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
 
7
 *
 
8
 * http://www.apache.org/licenses/LICENSE-2.0
 
9
 *
 
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.
 
15
 */
 
16
 
 
17
#define PY_SSIZE_T_CLEAN 1
 
18
#include <Python.h>
 
19
 
 
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;
 
24
#endif
 
25
 
 
26
#include <sys/types.h>
 
27
#include <sys/socket.h>
 
28
#include <signal.h>
 
29
 
 
30
/*
 
31
 * As per
 
32
 * <http://pubs.opengroup.org/onlinepubs/007904875/basedefs/sys/socket.h.html
 
33
 * #tag_13_61_05>:
 
34
 *
 
35
 *     "To forestall portability problems, it is recommended that applications
 
36
 *     not use values larger than (2**31)-1 for the socklen_t type."
 
37
 */
 
38
 
 
39
#define SOCKLEN_MAX 0x7FFFFFFF
 
40
 
 
41
PyObject *sendmsg_socket_error;
 
42
 
 
43
static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds);
 
44
static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds);
 
45
 
 
46
static PyMethodDef sendmsg_methods[] = {
 
47
    {"sendmsg", (PyCFunction) sendmsg_sendmsg, METH_VARARGS | METH_KEYWORDS,
 
48
     NULL},
 
49
    {"recvmsg", (PyCFunction) sendmsg_recvmsg, METH_VARARGS | METH_KEYWORDS,
 
50
     NULL},
 
51
    {NULL, NULL, 0, NULL}
 
52
};
 
53
 
 
54
 
 
55
PyMODINIT_FUNC initsendmsg(void) {
 
56
    PyObject *module;
 
57
 
 
58
    sendmsg_socket_error = NULL; /* Make sure that this has a known value
 
59
                                    before doing anything that might exit. */
 
60
 
 
61
    module = Py_InitModule("sendmsg", sendmsg_methods);
 
62
 
 
63
    if (!module) {
 
64
        return;
 
65
    }
 
66
 
 
67
    /*
 
68
      The following is the only value mentioned by POSIX:
 
69
      http://www.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html
 
70
    */
 
71
 
 
72
    if (-1 == PyModule_AddIntConstant(module, "SCM_RIGHTS", SCM_RIGHTS)) {
 
73
        return;
 
74
    }
 
75
 
 
76
 
 
77
    /* BSD, Darwin, Hurd */
 
78
#if defined(SCM_CREDS)
 
79
    if (-1 == PyModule_AddIntConstant(module, "SCM_CREDS", SCM_CREDS)) {
 
80
        return;
 
81
    }
 
82
#endif
 
83
 
 
84
    /* Linux */
 
85
#if defined(SCM_CREDENTIALS)
 
86
    if (-1 == PyModule_AddIntConstant(module, "SCM_CREDENTIALS", SCM_CREDENTIALS)) {
 
87
        return;
 
88
    }
 
89
#endif
 
90
 
 
91
    /* Apparently everywhere, but not standardized. */
 
92
#if defined(SCM_TIMESTAMP)
 
93
    if (-1 == PyModule_AddIntConstant(module, "SCM_TIMESTAMP", SCM_TIMESTAMP)) {
 
94
        return;
 
95
    }
 
96
#endif
 
97
 
 
98
    module = PyImport_ImportModule("socket");
 
99
    if (!module) {
 
100
        return;
 
101
    }
 
102
 
 
103
    sendmsg_socket_error = PyObject_GetAttrString(module, "error");
 
104
    if (!sendmsg_socket_error) {
 
105
        return;
 
106
    }
 
107
}
 
108
 
 
109
static PyObject *sendmsg_sendmsg(PyObject *self, PyObject *args, PyObject *keywds) {
 
110
 
 
111
    int fd;
 
112
    int flags = 0;
 
113
    Py_ssize_t sendmsg_result;
 
114
    struct msghdr message_header;
 
115
    struct iovec iov[1];
 
116
    PyObject *ancillary = NULL;
 
117
    static char *kwlist[] = {"fd", "data", "flags", "ancillary", NULL};
 
118
 
 
119
    if (!PyArg_ParseTupleAndKeywords(
 
120
            args, keywds, "it#|iO:sendmsg", kwlist,
 
121
            &fd,
 
122
            &iov[0].iov_base,
 
123
            &iov[0].iov_len,
 
124
            &flags,
 
125
            &ancillary)) {
 
126
        return NULL;
 
127
    }
 
128
 
 
129
    message_header.msg_name = NULL;
 
130
    message_header.msg_namelen = 0;
 
131
 
 
132
    message_header.msg_iov = iov;
 
133
    message_header.msg_iovlen = 1;
 
134
 
 
135
    message_header.msg_control = NULL;
 
136
    message_header.msg_controllen = 0;
 
137
 
 
138
    message_header.msg_flags = 0;
 
139
 
 
140
    if (ancillary) {
 
141
 
 
142
        if (!PyList_Check(ancillary)) {
 
143
            PyErr_Format(PyExc_TypeError,
 
144
                         "sendmsg argument 3 expected list, got %s",
 
145
                         ancillary->ob_type->tp_name);
 
146
            return NULL;
 
147
        }
 
148
 
 
149
        PyObject *iterator = PyObject_GetIter(ancillary);
 
150
        PyObject *item = NULL;
 
151
 
 
152
        if (iterator == NULL) {
 
153
            return NULL;
 
154
        }
 
155
 
 
156
        size_t all_data_len = 0;
 
157
 
 
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)) ) {
 
161
            int type, level;
 
162
            Py_ssize_t data_len;
 
163
            size_t prev_all_data_len;
 
164
            char *data;
 
165
            if (!PyArg_ParseTuple(
 
166
                        item, "iit#:sendmsg ancillary data (level, type, data)",
 
167
                        &level, &type, &data, &data_len)) {
 
168
                Py_DECREF(item);
 
169
                Py_DECREF(iterator);
 
170
                return NULL;
 
171
            }
 
172
 
 
173
            prev_all_data_len = all_data_len;
 
174
            all_data_len += CMSG_SPACE(data_len);
 
175
 
 
176
            Py_DECREF(item);
 
177
 
 
178
            if (all_data_len < prev_all_data_len) {
 
179
                Py_DECREF(iterator);
 
180
                PyErr_Format(PyExc_OverflowError,
 
181
                             "Too much msg_control to fit in a size_t: %zu",
 
182
                             prev_all_data_len);
 
183
                return NULL;
 
184
            }
 
185
        }
 
186
 
 
187
        Py_DECREF(iterator);
 
188
        iterator = NULL;
 
189
 
 
190
        /* Allocate the buffer for all of the ancillary elements, if we have
 
191
         * any.  */
 
192
        if (all_data_len) {
 
193
            if (all_data_len > SOCKLEN_MAX) {
 
194
                PyErr_Format(PyExc_OverflowError,
 
195
                             "Too much msg_control to fit in a socklen_t: %zu",
 
196
                             all_data_len);
 
197
                return NULL;
 
198
            }
 
199
            message_header.msg_control = malloc(all_data_len);
 
200
            if (!message_header.msg_control) {
 
201
                PyErr_NoMemory();
 
202
                return NULL;
 
203
            }
 
204
        } else {
 
205
            message_header.msg_control = NULL;
 
206
        }
 
207
        message_header.msg_controllen = (socklen_t) all_data_len;
 
208
 
 
209
        iterator = PyObject_GetIter(ancillary); /* again */
 
210
        item = NULL;
 
211
 
 
212
        if (!iterator) {
 
213
            free(message_header.msg_control);
 
214
            return NULL;
 
215
        }
 
216
 
 
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;
 
221
            size_t data_size;
 
222
            unsigned char *data, *cmsg_data;
 
223
 
 
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);
 
227
 
 
228
            if (!PyArg_ParseTuple(item,
 
229
                                  "iit#:sendmsg ancillary data (level, type, data)",
 
230
                                  &level,
 
231
                                  &type,
 
232
                                  &data,
 
233
                                  &data_len)) {
 
234
                Py_DECREF(item);
 
235
                Py_DECREF(iterator);
 
236
                free(message_header.msg_control);
 
237
                return NULL;
 
238
            }
 
239
 
 
240
            control_message->cmsg_level = level;
 
241
            control_message->cmsg_type = type;
 
242
            data_size = CMSG_LEN(data_len);
 
243
 
 
244
            if (data_size > SOCKLEN_MAX) {
 
245
                Py_DECREF(item);
 
246
                Py_DECREF(iterator);
 
247
                free(message_header.msg_control);
 
248
 
 
249
                PyErr_Format(PyExc_OverflowError,
 
250
                             "CMSG_LEN(%d) > SOCKLEN_MAX", data_len);
 
251
 
 
252
                return NULL;
 
253
            }
 
254
 
 
255
            control_message->cmsg_len = (socklen_t) data_size;
 
256
 
 
257
            cmsg_data = CMSG_DATA(control_message);
 
258
            memcpy(cmsg_data, data, data_len);
 
259
 
 
260
            Py_DECREF(item);
 
261
 
 
262
            control_message = CMSG_NXTHDR(&message_header, control_message);
 
263
        }
 
264
 
 
265
        Py_DECREF(iterator);
 
266
 
 
267
        if (PyErr_Occurred()) {
 
268
            free(message_header.msg_control);
 
269
            return NULL;
 
270
        }
 
271
    }
 
272
 
 
273
    sendmsg_result = sendmsg(fd, &message_header, flags);
 
274
 
 
275
    if (sendmsg_result < 0) {
 
276
        PyErr_SetFromErrno(sendmsg_socket_error);
 
277
        if (message_header.msg_control) {
 
278
            free(message_header.msg_control);
 
279
        }
 
280
        return NULL;
 
281
    }
 
282
 
 
283
    return Py_BuildValue("n", sendmsg_result);
 
284
}
 
285
 
 
286
static PyObject *sendmsg_recvmsg(PyObject *self, PyObject *args, PyObject *keywds) {
 
287
    int fd = -1;
 
288
    int flags = 0;
 
289
    int maxsize = 8192;
 
290
    int cmsg_size = 4*1024;
 
291
    size_t cmsg_space;
 
292
    Py_ssize_t recvmsg_result;
 
293
 
 
294
    struct msghdr message_header;
 
295
    struct cmsghdr *control_message;
 
296
    struct iovec iov[1];
 
297
    char *cmsgbuf;
 
298
    PyObject *ancillary;
 
299
    PyObject *final_result = NULL;
 
300
 
 
301
    static char *kwlist[] = {"fd", "flags", "maxsize", "cmsg_size", NULL};
 
302
 
 
303
    if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|iii:recvmsg", kwlist,
 
304
                                     &fd, &flags, &maxsize, &cmsg_size)) {
 
305
        return NULL;
 
306
    }
 
307
 
 
308
    cmsg_space = CMSG_SPACE(cmsg_size);
 
309
 
 
310
    /* overflow check */
 
311
    if (cmsg_space > SOCKLEN_MAX) {
 
312
        PyErr_Format(PyExc_OverflowError,
 
313
                     "CMSG_SPACE(cmsg_size) greater than SOCKLEN_MAX: %d",
 
314
                     cmsg_size);
 
315
        return NULL;
 
316
    }
 
317
 
 
318
    message_header.msg_name = NULL;
 
319
    message_header.msg_namelen = 0;
 
320
 
 
321
    iov[0].iov_len = maxsize;
 
322
    iov[0].iov_base = malloc(maxsize);
 
323
 
 
324
    if (!iov[0].iov_base) {
 
325
        PyErr_NoMemory();
 
326
        return NULL;
 
327
    }
 
328
 
 
329
    message_header.msg_iov = iov;
 
330
    message_header.msg_iovlen = 1;
 
331
 
 
332
    cmsgbuf = malloc(cmsg_space);
 
333
 
 
334
    if (!cmsgbuf) {
 
335
        free(iov[0].iov_base);
 
336
        PyErr_NoMemory();
 
337
        return NULL;
 
338
    }
 
339
 
 
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;
 
344
 
 
345
    recvmsg_result = recvmsg(fd, &message_header, flags);
 
346
    if (recvmsg_result < 0) {
 
347
        PyErr_SetFromErrno(sendmsg_socket_error);
 
348
        goto finished;
 
349
    }
 
350
 
 
351
    ancillary = PyList_New(0);
 
352
    if (!ancillary) {
 
353
        goto finished;
 
354
    }
 
355
 
 
356
    for (control_message = CMSG_FIRSTHDR(&message_header);
 
357
         control_message;
 
358
         control_message = CMSG_NXTHDR(&message_header,
 
359
                                       control_message)) {
 
360
        PyObject *entry;
 
361
 
 
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. */
 
365
 
 
366
        if ((!(control_message->cmsg_level)) &&
 
367
            (!(control_message->cmsg_type))) {
 
368
            continue;
 
369
        }
 
370
 
 
371
        entry = Py_BuildValue(
 
372
            "(iis#)",
 
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)));
 
377
 
 
378
        if (!entry) {
 
379
            Py_DECREF(ancillary);
 
380
            goto finished;
 
381
        }
 
382
 
 
383
        if (PyList_Append(ancillary, entry) < 0) {
 
384
            Py_DECREF(ancillary);
 
385
            Py_DECREF(entry);
 
386
            goto finished;
 
387
        } else {
 
388
            Py_DECREF(entry);
 
389
        }
 
390
    }
 
391
 
 
392
    final_result = Py_BuildValue(
 
393
        "s#iO",
 
394
        iov[0].iov_base,
 
395
        recvmsg_result,
 
396
        message_header.msg_flags,
 
397
        ancillary);
 
398
 
 
399
    Py_DECREF(ancillary);
 
400
 
 
401
  finished:
 
402
    free(iov[0].iov_base);
 
403
    free(cmsgbuf);
 
404
    return final_result;
 
405
}
 
406