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 %"
51 PY_FORMAT_SIZE_T
"d", (Py_ssize_t
)handle
);
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 Py_BEGIN_ALLOW_THREADS
133 res
= conn_send_string(self
, buffer
+ offset
, size
);
137 return mp_SetError(PyExc_IOError
, res
);
143 connection_recvbytes(ConnectionObject
*self
, PyObject
*args
)
146 Py_ssize_t res
, maxlength
= PY_SSIZE_T_MAX
;
147 PyObject
*result
= NULL
;
149 if (!PyArg_ParseTuple(args
, "|" F_PY_SSIZE_T
, &maxlength
))
152 CHECK_READABLE(self
);
155 PyErr_SetString(PyExc_ValueError
, "maxlength < 0");
159 Py_BEGIN_ALLOW_THREADS
160 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
;
195 if (!PyArg_ParseTuple(args
, "w#|" F_PY_SSIZE_T
,
196 &buffer
, &length
, &offset
))
199 CHECK_READABLE(self
);
202 PyErr_SetString(PyExc_ValueError
, "negative offset");
206 if (offset
> length
) {
207 PyErr_SetString(PyExc_ValueError
, "offset too large");
211 Py_BEGIN_ALLOW_THREADS
212 res
= conn_recv_string(self
, buffer
+offset
, length
-offset
,
213 &freeme
, PY_SSIZE_T_MAX
);
217 if (res
== MP_BAD_MESSAGE_LENGTH
) {
218 if ((self
->flags
& WRITABLE
) == 0) {
219 Py_BEGIN_ALLOW_THREADS
222 self
->handle
= INVALID_HANDLE_VALUE
;
224 self
->flags
= WRITABLE
;
227 mp_SetError(PyExc_IOError
, res
);
229 if (freeme
== NULL
) {
230 result
= PyInt_FromSsize_t(res
);
232 result
= PyObject_CallFunction(BufferTooShort
,
237 PyErr_SetObject(BufferTooShort
, result
);
248 * Functions for transferring objects
252 connection_send_obj(ConnectionObject
*self
, PyObject
*obj
)
257 PyObject
*pickled_string
= NULL
;
259 CHECK_WRITABLE(self
);
261 pickled_string
= PyObject_CallFunctionObjArgs(pickle_dumps
, obj
,
262 pickle_protocol
, NULL
);
266 if (PyString_AsStringAndSize(pickled_string
, &buffer
, &length
) < 0)
269 Py_BEGIN_ALLOW_THREADS
270 res
= conn_send_string(self
, buffer
, (int)length
);
274 mp_SetError(PyExc_IOError
, res
);
278 Py_XDECREF(pickled_string
);
282 Py_XDECREF(pickled_string
);
287 connection_recv_obj(ConnectionObject
*self
)
291 PyObject
*temp
= NULL
, *result
= NULL
;
293 CHECK_READABLE(self
);
295 Py_BEGIN_ALLOW_THREADS
296 res
= conn_recv_string(self
, self
->buffer
, CONNECTION_BUFFER_SIZE
,
297 &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 %" PY_FORMAT_SIZE_T
"d>",
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 */