2
* Definition of a `Connection` type.
3
* Used by `socket_connection.c` and `pipe_connection.c`.
7
* Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
20
#define CHECK_READABLE(self) \
21
if (!(self->flags & READABLE)) { \
22
PyErr_SetString(PyExc_IOError, "connection is write-only"); \
26
#define CHECK_WRITABLE(self) \
27
if (!(self->flags & WRITABLE)) { \
28
PyErr_SetString(PyExc_IOError, "connection is read-only"); \
33
* Allocation and deallocation
37
connection_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
39
ConnectionObject *self;
41
BOOL readable = TRUE, writable = TRUE;
43
static char *kwlist[] = {"handle", "readable", "writable", NULL};
45
if (!PyArg_ParseTupleAndKeywords(args, kwds, F_HANDLE "|ii", kwlist,
46
&handle, &readable, &writable))
49
if (handle == INVALID_HANDLE_VALUE || (Py_ssize_t)handle < 0) {
50
PyErr_Format(PyExc_IOError, "invalid handle %zd",
55
if (!readable && !writable) {
56
PyErr_SetString(PyExc_ValueError,
57
"either readable or writable must be true");
61
self = PyObject_New(ConnectionObject, type);
65
self->weakreflist = NULL;
66
self->handle = handle;
70
self->flags |= READABLE;
72
self->flags |= WRITABLE;
73
assert(self->flags >= 1 && self->flags <= 3);
75
return (PyObject*)self;
79
connection_dealloc(ConnectionObject* self)
81
if (self->weakreflist != NULL)
82
PyObject_ClearWeakRefs((PyObject*)self);
84
if (self->handle != INVALID_HANDLE_VALUE) {
85
Py_BEGIN_ALLOW_THREADS
93
* Functions for transferring buffers
97
connection_sendbytes(ConnectionObject *self, PyObject *args)
100
Py_ssize_t length, offset=0, size=PY_SSIZE_T_MIN;
103
if (!PyArg_ParseTuple(args, F_RBUFFER "#|" F_PY_SSIZE_T F_PY_SSIZE_T,
104
&buffer, &length, &offset, &size))
107
CHECK_WRITABLE(self);
110
PyErr_SetString(PyExc_ValueError, "offset is negative");
113
if (length < offset) {
114
PyErr_SetString(PyExc_ValueError, "buffer length < offset");
118
if (size == PY_SSIZE_T_MIN) {
119
size = length - offset;
122
PyErr_SetString(PyExc_ValueError, "size is negative");
125
if (offset + size > length) {
126
PyErr_SetString(PyExc_ValueError,
127
"buffer length < offset + size");
132
res = conn_send_string(self, buffer + offset, size);
135
return mp_SetError(PyExc_IOError, res);
141
connection_recvbytes(ConnectionObject *self, PyObject *args)
144
Py_ssize_t res, maxlength = PY_SSIZE_T_MAX;
145
PyObject *result = NULL;
147
if (!PyArg_ParseTuple(args, "|" F_PY_SSIZE_T, &maxlength))
150
CHECK_READABLE(self);
153
PyErr_SetString(PyExc_ValueError, "maxlength < 0");
157
res = conn_recv_string(self, self->buffer, CONNECTION_BUFFER_SIZE,
161
if (res == MP_BAD_MESSAGE_LENGTH) {
162
if ((self->flags & WRITABLE) == 0) {
163
Py_BEGIN_ALLOW_THREADS
166
self->handle = INVALID_HANDLE_VALUE;
168
self->flags = WRITABLE;
171
mp_SetError(PyExc_IOError, res);
173
if (freeme == NULL) {
174
result = PyString_FromStringAndSize(self->buffer, res);
176
result = PyString_FromStringAndSize(freeme, res);
185
connection_recvbytes_into(ConnectionObject *self, PyObject *args)
187
char *freeme = NULL, *buffer = NULL;
188
Py_ssize_t res, length, offset = 0;
189
PyObject *result = NULL;
192
CHECK_READABLE(self);
194
if (!PyArg_ParseTuple(args, "w*|" F_PY_SSIZE_T,
202
PyErr_SetString(PyExc_ValueError, "negative offset");
206
if (offset > length) {
207
PyErr_SetString(PyExc_ValueError, "offset too large");
211
res = conn_recv_string(self, buffer+offset, length-offset,
212
&freeme, PY_SSIZE_T_MAX);
215
if (res == MP_BAD_MESSAGE_LENGTH) {
216
if ((self->flags & WRITABLE) == 0) {
217
Py_BEGIN_ALLOW_THREADS
220
self->handle = INVALID_HANDLE_VALUE;
222
self->flags = WRITABLE;
225
mp_SetError(PyExc_IOError, res);
227
if (freeme == NULL) {
228
result = PyInt_FromSsize_t(res);
230
result = PyObject_CallFunction(BufferTooShort,
235
PyErr_SetObject(BufferTooShort, result);
243
PyBuffer_Release(&pbuf);
252
* Functions for transferring objects
256
connection_send_obj(ConnectionObject *self, PyObject *obj)
261
PyObject *pickled_string = NULL;
263
CHECK_WRITABLE(self);
265
pickled_string = PyObject_CallFunctionObjArgs(pickle_dumps, obj,
266
pickle_protocol, NULL);
270
if (PyString_AsStringAndSize(pickled_string, &buffer, &length) < 0)
273
res = conn_send_string(self, buffer, (int)length);
276
mp_SetError(PyExc_IOError, res);
280
Py_XDECREF(pickled_string);
284
Py_XDECREF(pickled_string);
289
connection_recv_obj(ConnectionObject *self)
293
PyObject *temp = NULL, *result = NULL;
295
CHECK_READABLE(self);
297
res = conn_recv_string(self, self->buffer, CONNECTION_BUFFER_SIZE,
298
&freeme, PY_SSIZE_T_MAX);
301
if (res == MP_BAD_MESSAGE_LENGTH) {
302
if ((self->flags & WRITABLE) == 0) {
303
Py_BEGIN_ALLOW_THREADS
306
self->handle = INVALID_HANDLE_VALUE;
308
self->flags = WRITABLE;
311
mp_SetError(PyExc_IOError, res);
313
if (freeme == NULL) {
314
temp = PyString_FromStringAndSize(self->buffer, res);
316
temp = PyString_FromStringAndSize(freeme, res);
322
result = PyObject_CallFunctionObjArgs(pickle_loads,
333
connection_poll(ConnectionObject *self, PyObject *args)
335
PyObject *timeout_obj = NULL;
336
double timeout = 0.0;
339
CHECK_READABLE(self);
341
if (!PyArg_ParseTuple(args, "|O", &timeout_obj))
344
if (timeout_obj == NULL) {
346
} else if (timeout_obj == Py_None) {
347
timeout = -1.0; /* block forever */
349
timeout = PyFloat_AsDouble(timeout_obj);
350
if (PyErr_Occurred())
356
Py_BEGIN_ALLOW_THREADS
357
res = conn_poll(self, timeout);
366
return mp_SetError(PyExc_IOError, res);
371
connection_fileno(ConnectionObject* self)
373
if (self->handle == INVALID_HANDLE_VALUE) {
374
PyErr_SetString(PyExc_IOError, "handle is invalid");
377
return PyInt_FromLong((long)self->handle);
381
connection_close(ConnectionObject *self)
383
if (self->handle != INVALID_HANDLE_VALUE) {
384
Py_BEGIN_ALLOW_THREADS
387
self->handle = INVALID_HANDLE_VALUE;
394
connection_repr(ConnectionObject *self)
396
static char *conn_type[] = {"read-only", "write-only", "read-write"};
398
assert(self->flags >= 1 && self->flags <= 3);
399
return FROM_FORMAT("<%s %s, handle %zd>",
400
conn_type[self->flags - 1],
401
CONNECTION_NAME, (Py_ssize_t)self->handle);
405
* Getters and setters
409
connection_closed(ConnectionObject *self, void *closure)
411
return PyBool_FromLong((long)(self->handle == INVALID_HANDLE_VALUE));
415
connection_readable(ConnectionObject *self, void *closure)
417
return PyBool_FromLong((long)(self->flags & READABLE));
421
connection_writable(ConnectionObject *self, void *closure)
423
return PyBool_FromLong((long)(self->flags & WRITABLE));
430
static PyMethodDef connection_methods[] = {
431
{"send_bytes", (PyCFunction)connection_sendbytes, METH_VARARGS,
432
"send the byte data from a readable buffer-like object"},
433
{"recv_bytes", (PyCFunction)connection_recvbytes, METH_VARARGS,
434
"receive byte data as a string"},
435
{"recv_bytes_into",(PyCFunction)connection_recvbytes_into,METH_VARARGS,
436
"receive byte data into a writeable buffer-like object\n"
437
"returns the number of bytes read"},
439
{"send", (PyCFunction)connection_send_obj, METH_O,
440
"send a (picklable) object"},
441
{"recv", (PyCFunction)connection_recv_obj, METH_NOARGS,
442
"receive a (picklable) object"},
444
{"poll", (PyCFunction)connection_poll, METH_VARARGS,
445
"whether there is any input available to be read"},
446
{"fileno", (PyCFunction)connection_fileno, METH_NOARGS,
447
"file descriptor or handle of the connection"},
448
{"close", (PyCFunction)connection_close, METH_NOARGS,
449
"close the connection"},
451
{NULL} /* Sentinel */
454
static PyGetSetDef connection_getset[] = {
455
{"closed", (getter)connection_closed, NULL,
456
"True if the connection is closed", NULL},
457
{"readable", (getter)connection_readable, NULL,
458
"True if the connection is readable", NULL},
459
{"writable", (getter)connection_writable, NULL,
460
"True if the connection is writable", NULL},
468
PyDoc_STRVAR(connection_doc,
469
"Connection type whose constructor signature is\n\n"
470
" Connection(handle, readable=True, writable=True).\n\n"
471
"The constructor does *not* duplicate the handle.");
473
PyTypeObject CONNECTION_TYPE = {
474
PyVarObject_HEAD_INIT(NULL, 0)
475
/* tp_name */ "_multiprocessing." CONNECTION_NAME,
476
/* tp_basicsize */ sizeof(ConnectionObject),
478
/* tp_dealloc */ (destructor)connection_dealloc,
483
/* tp_repr */ (reprfunc)connection_repr,
484
/* tp_as_number */ 0,
485
/* tp_as_sequence */ 0,
486
/* tp_as_mapping */ 0,
492
/* tp_as_buffer */ 0,
493
/* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
494
Py_TPFLAGS_HAVE_WEAKREFS,
495
/* tp_doc */ connection_doc,
498
/* tp_richcompare */ 0,
499
/* tp_weaklistoffset */ offsetof(ConnectionObject, weakreflist),
502
/* tp_methods */ connection_methods,
504
/* tp_getset */ connection_getset,
507
/* tp_descr_get */ 0,
508
/* tp_descr_set */ 0,
509
/* tp_dictoffset */ 0,
512
/* tp_new */ connection_new,
515
#endif /* CONNECTION_H */