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 if (PyErr_Occurred())
138 return mp_SetError(PyExc_IOError
, res
);
145 connection_recvbytes(ConnectionObject
*self
, PyObject
*args
)
148 Py_ssize_t res
, maxlength
= PY_SSIZE_T_MAX
;
149 PyObject
*result
= NULL
;
151 if (!PyArg_ParseTuple(args
, "|" F_PY_SSIZE_T
, &maxlength
))
154 CHECK_READABLE(self
);
157 PyErr_SetString(PyExc_ValueError
, "maxlength < 0");
161 res
= conn_recv_string(self
, self
->buffer
, CONNECTION_BUFFER_SIZE
,
165 if (res
== MP_BAD_MESSAGE_LENGTH
) {
166 if ((self
->flags
& WRITABLE
) == 0) {
167 Py_BEGIN_ALLOW_THREADS
170 self
->handle
= INVALID_HANDLE_VALUE
;
172 self
->flags
= WRITABLE
;
175 mp_SetError(PyExc_IOError
, res
);
177 if (freeme
== NULL
) {
178 result
= PyString_FromStringAndSize(self
->buffer
, res
);
180 result
= PyString_FromStringAndSize(freeme
, res
);
189 connection_recvbytes_into(ConnectionObject
*self
, PyObject
*args
)
191 char *freeme
= NULL
, *buffer
= NULL
;
192 Py_ssize_t res
, length
, offset
= 0;
193 PyObject
*result
= NULL
;
196 CHECK_READABLE(self
);
198 if (!PyArg_ParseTuple(args
, "w*|" F_PY_SSIZE_T
,
206 PyErr_SetString(PyExc_ValueError
, "negative offset");
210 if (offset
> length
) {
211 PyErr_SetString(PyExc_ValueError
, "offset too large");
215 res
= conn_recv_string(self
, buffer
+offset
, length
-offset
,
216 &freeme
, PY_SSIZE_T_MAX
);
219 if (res
== MP_BAD_MESSAGE_LENGTH
) {
220 if ((self
->flags
& WRITABLE
) == 0) {
221 Py_BEGIN_ALLOW_THREADS
224 self
->handle
= INVALID_HANDLE_VALUE
;
226 self
->flags
= WRITABLE
;
229 mp_SetError(PyExc_IOError
, res
);
231 if (freeme
== NULL
) {
232 result
= PyInt_FromSsize_t(res
);
234 result
= PyObject_CallFunction(BufferTooShort
,
239 PyErr_SetObject(BufferTooShort
, result
);
247 PyBuffer_Release(&pbuf
);
256 * Functions for transferring objects
260 connection_send_obj(ConnectionObject
*self
, PyObject
*obj
)
265 PyObject
*pickled_string
= NULL
;
267 CHECK_WRITABLE(self
);
269 pickled_string
= PyObject_CallFunctionObjArgs(pickle_dumps
, obj
,
270 pickle_protocol
, NULL
);
274 if (PyString_AsStringAndSize(pickled_string
, &buffer
, &length
) < 0)
277 res
= conn_send_string(self
, buffer
, (int)length
);
280 mp_SetError(PyExc_IOError
, res
);
284 Py_XDECREF(pickled_string
);
288 Py_XDECREF(pickled_string
);
293 connection_recv_obj(ConnectionObject
*self
)
297 PyObject
*temp
= NULL
, *result
= NULL
;
299 CHECK_READABLE(self
);
301 res
= conn_recv_string(self
, self
->buffer
, CONNECTION_BUFFER_SIZE
,
302 &freeme
, PY_SSIZE_T_MAX
);
305 if (res
== MP_BAD_MESSAGE_LENGTH
) {
306 if ((self
->flags
& WRITABLE
) == 0) {
307 Py_BEGIN_ALLOW_THREADS
310 self
->handle
= INVALID_HANDLE_VALUE
;
312 self
->flags
= WRITABLE
;
315 mp_SetError(PyExc_IOError
, res
);
317 if (freeme
== NULL
) {
318 temp
= PyString_FromStringAndSize(self
->buffer
, res
);
320 temp
= PyString_FromStringAndSize(freeme
, res
);
326 result
= PyObject_CallFunctionObjArgs(pickle_loads
,
337 connection_poll(ConnectionObject
*self
, PyObject
*args
)
339 PyObject
*timeout_obj
= NULL
;
340 double timeout
= 0.0;
343 CHECK_READABLE(self
);
345 if (!PyArg_ParseTuple(args
, "|O", &timeout_obj
))
348 if (timeout_obj
== NULL
) {
350 } else if (timeout_obj
== Py_None
) {
351 timeout
= -1.0; /* block forever */
353 timeout
= PyFloat_AsDouble(timeout_obj
);
354 if (PyErr_Occurred())
360 Py_BEGIN_ALLOW_THREADS
361 res
= conn_poll(self
, timeout
, _save
);
370 return mp_SetError(PyExc_IOError
, res
);
375 connection_fileno(ConnectionObject
* self
)
377 if (self
->handle
== INVALID_HANDLE_VALUE
) {
378 PyErr_SetString(PyExc_IOError
, "handle is invalid");
381 return PyInt_FromLong((long)self
->handle
);
385 connection_close(ConnectionObject
*self
)
387 if (self
->handle
!= INVALID_HANDLE_VALUE
) {
388 Py_BEGIN_ALLOW_THREADS
391 self
->handle
= INVALID_HANDLE_VALUE
;
398 connection_repr(ConnectionObject
*self
)
400 static char *conn_type
[] = {"read-only", "write-only", "read-write"};
402 assert(self
->flags
>= 1 && self
->flags
<= 3);
403 return FROM_FORMAT("<%s %s, handle %zd>",
404 conn_type
[self
->flags
- 1],
405 CONNECTION_NAME
, (Py_ssize_t
)self
->handle
);
409 * Getters and setters
413 connection_closed(ConnectionObject
*self
, void *closure
)
415 return PyBool_FromLong((long)(self
->handle
== INVALID_HANDLE_VALUE
));
419 connection_readable(ConnectionObject
*self
, void *closure
)
421 return PyBool_FromLong((long)(self
->flags
& READABLE
));
425 connection_writable(ConnectionObject
*self
, void *closure
)
427 return PyBool_FromLong((long)(self
->flags
& WRITABLE
));
434 static PyMethodDef connection_methods
[] = {
435 {"send_bytes", (PyCFunction
)connection_sendbytes
, METH_VARARGS
,
436 "send the byte data from a readable buffer-like object"},
437 {"recv_bytes", (PyCFunction
)connection_recvbytes
, METH_VARARGS
,
438 "receive byte data as a string"},
439 {"recv_bytes_into",(PyCFunction
)connection_recvbytes_into
,METH_VARARGS
,
440 "receive byte data into a writeable buffer-like object\n"
441 "returns the number of bytes read"},
443 {"send", (PyCFunction
)connection_send_obj
, METH_O
,
444 "send a (picklable) object"},
445 {"recv", (PyCFunction
)connection_recv_obj
, METH_NOARGS
,
446 "receive a (picklable) object"},
448 {"poll", (PyCFunction
)connection_poll
, METH_VARARGS
,
449 "whether there is any input available to be read"},
450 {"fileno", (PyCFunction
)connection_fileno
, METH_NOARGS
,
451 "file descriptor or handle of the connection"},
452 {"close", (PyCFunction
)connection_close
, METH_NOARGS
,
453 "close the connection"},
455 {NULL
} /* Sentinel */
458 static PyGetSetDef connection_getset
[] = {
459 {"closed", (getter
)connection_closed
, NULL
,
460 "True if the connection is closed", NULL
},
461 {"readable", (getter
)connection_readable
, NULL
,
462 "True if the connection is readable", NULL
},
463 {"writable", (getter
)connection_writable
, NULL
,
464 "True if the connection is writable", NULL
},
472 PyDoc_STRVAR(connection_doc
,
473 "Connection type whose constructor signature is\n\n"
474 " Connection(handle, readable=True, writable=True).\n\n"
475 "The constructor does *not* duplicate the handle.");
477 PyTypeObject CONNECTION_TYPE
= {
478 PyVarObject_HEAD_INIT(NULL
, 0)
479 /* tp_name */ "_multiprocessing." CONNECTION_NAME
,
480 /* tp_basicsize */ sizeof(ConnectionObject
),
482 /* tp_dealloc */ (destructor
)connection_dealloc
,
487 /* tp_repr */ (reprfunc
)connection_repr
,
488 /* tp_as_number */ 0,
489 /* tp_as_sequence */ 0,
490 /* tp_as_mapping */ 0,
496 /* tp_as_buffer */ 0,
497 /* tp_flags */ Py_TPFLAGS_DEFAULT
| Py_TPFLAGS_BASETYPE
|
498 Py_TPFLAGS_HAVE_WEAKREFS
,
499 /* tp_doc */ connection_doc
,
502 /* tp_richcompare */ 0,
503 /* tp_weaklistoffset */ offsetof(ConnectionObject
, weakreflist
),
506 /* tp_methods */ connection_methods
,
508 /* tp_getset */ connection_getset
,
511 /* tp_descr_get */ 0,
512 /* tp_descr_set */ 0,
513 /* tp_dictoffset */ 0,
516 /* tp_new */ connection_new
,
519 #endif /* CONNECTION_H */