connection.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. * Definition of a `Connection` type.
  3. * Used by `socket_connection.c` and `pipe_connection.c`.
  4. *
  5. * connection.h
  6. *
  7. * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
  8. */
  9. #ifndef CONNECTION_H
  10. #define CONNECTION_H
  11. /*
  12. * Allocation and deallocation
  13. */
  14. static PyObject *
  15. Connection_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
  16. {
  17. Connection *self;
  18. HANDLE handle;
  19. BOOL make_duplicate = TRUE, make_inheritable = TRUE;
  20. static char *kwlist[] = {"handle", "duplicate", "inheritable", NULL};
  21. if (!PyArg_ParseTupleAndKeywords(args, kwds, F_HANDLE "|ii", kwlist,
  22. &handle, &make_duplicate, &make_inheritable))
  23. return NULL;
  24. if (handle == INVALID_HANDLE_VALUE || (Py_ssize_t)handle < 0) {
  25. PyErr_Format(PyExc_IOError, "invalid handle %" PY_FORMAT_SIZE_T "d",
  26. (Py_ssize_t)handle);
  27. return NULL;
  28. }
  29. self = (Connection*)type->tp_alloc(type, 0);
  30. if (self == NULL)
  31. return NULL;
  32. self->weakreflist = NULL;
  33. if (make_duplicate)
  34. self->handle = DUPLICATE(handle);
  35. else
  36. self->handle = handle;
  37. if (self->handle == INVALID_HANDLE_VALUE) {
  38. self->ob_type->tp_free((PyObject*)self);
  39. return SetException(PyExc_IOError, STANDARD_ERROR);
  40. }
  41. #ifdef MS_WINDOWS
  42. if (make_inheritable) {
  43. if (!SetHandleInformation(self->handle, HANDLE_FLAG_INHERIT,
  44. HANDLE_FLAG_INHERIT))
  45. {
  46. PyErr_SetExcFromWindowsErr(PyExc_IOError, 0);
  47. Py_BEGIN_ALLOW_THREADS
  48. CloseHandle(self->handle);
  49. Py_END_ALLOW_THREADS
  50. SetLastError(0);
  51. self->ob_type->tp_free((PyObject*)self);
  52. return NULL;
  53. }
  54. }
  55. #endif
  56. return (PyObject*)self;
  57. }
  58. static void
  59. Connection_dealloc(Connection* self)
  60. {
  61. if (self->weakreflist != NULL)
  62. PyObject_ClearWeakRefs((PyObject*)self);
  63. if (self->handle != INVALID_HANDLE_VALUE) {
  64. Py_BEGIN_ALLOW_THREADS
  65. CLOSE(self->handle);
  66. Py_END_ALLOW_THREADS
  67. }
  68. self->ob_type->tp_free((PyObject*)self);
  69. }
  70. /*
  71. * Functions for transferring buffers
  72. */
  73. static PyObject *
  74. Connection_sendbytes(Connection* self, PyObject *args)
  75. {
  76. char *buffer;
  77. Py_ssize_t length;
  78. int res;
  79. if (!PyArg_ParseTuple(args, "s#", &buffer, &length))
  80. return NULL;
  81. Py_BEGIN_ALLOW_THREADS
  82. res = conn_send_string(self, buffer, length);
  83. Py_END_ALLOW_THREADS
  84. if (res < 0)
  85. return SetException(PyExc_IOError, res);
  86. Py_RETURN_NONE;
  87. }
  88. static PyObject *
  89. Connection_recvbytes(Connection *self)
  90. {
  91. char *freeme = NULL;
  92. Py_ssize_t nbytes;
  93. PyObject *result = NULL;
  94. Py_BEGIN_ALLOW_THREADS
  95. nbytes = conn_recv_string(self, self->buffer, BUFFER_SIZE, &freeme);
  96. Py_END_ALLOW_THREADS
  97. if (nbytes < 0) {
  98. SetException(PyExc_IOError, nbytes);
  99. } else {
  100. if (freeme == NULL) {
  101. result = PyString_FromStringAndSize(self->buffer, nbytes);
  102. } else {
  103. result = PyString_FromStringAndSize(freeme, nbytes);
  104. PyMem_Free(freeme);
  105. }
  106. }
  107. return result;
  108. }
  109. static PyObject *
  110. Connection_recvbytes_into(Connection *self, PyObject *args)
  111. {
  112. char *freeme = NULL, *buffer = NULL;
  113. Py_ssize_t nbytes, length, offset=0;
  114. PyObject *result = NULL;
  115. if (!PyArg_ParseTuple(args, "w#|" F_PY_SSIZE_T, &buffer, &length, &offset))
  116. return NULL;
  117. if (offset < 0) {
  118. PyErr_SetString(PyExc_ValueError, "negative offset");
  119. return NULL;
  120. }
  121. if (offset > length) {
  122. PyErr_SetString(PyExc_ValueError, "offset too large");
  123. return NULL;
  124. }
  125. Py_BEGIN_ALLOW_THREADS
  126. nbytes = conn_recv_string(self, buffer+offset, length-offset, &freeme);
  127. Py_END_ALLOW_THREADS
  128. if (nbytes < 0) {
  129. SetException(PyExc_IOError, nbytes);
  130. } else {
  131. if (freeme == NULL) {
  132. result = PyInt_FromSsize_t(nbytes);
  133. } else {
  134. result = PyObject_CallFunction(BufferTooShort,
  135. "s#", freeme, nbytes);
  136. PyMem_Free(freeme);
  137. PyErr_SetObject(BufferTooShort, result);
  138. Py_XDECREF(result);
  139. return NULL;
  140. }
  141. }
  142. return result;
  143. }
  144. /*
  145. * Functions for transferring objects
  146. */
  147. static PyObject *
  148. Connection_send_obj(Connection *self, PyObject *obj)
  149. {
  150. char *buffer;
  151. int res;
  152. Py_ssize_t length;
  153. PyObject *pickled_string = NULL;
  154. pickled_string = PyObject_CallFunctionObjArgs(dumpsFunction, obj,
  155. protocol, NULL);
  156. if (!pickled_string)
  157. goto failure;
  158. if (PyString_AsStringAndSize(pickled_string, &buffer, &length) < 0)
  159. goto failure;
  160. if (TOO_LONG(length)) {
  161. PyErr_SetString(PyExc_ValueError, "string too long");
  162. goto failure;
  163. }
  164. Py_BEGIN_ALLOW_THREADS
  165. res = conn_send_string(self, buffer, (int)length);
  166. Py_END_ALLOW_THREADS
  167. if (res < 0) {
  168. SetException(PyExc_IOError, res);
  169. goto failure;
  170. }
  171. Py_XDECREF(pickled_string);
  172. Py_RETURN_NONE;
  173. failure:
  174. Py_XDECREF(pickled_string);
  175. return NULL;
  176. }
  177. static PyObject *
  178. Connection_recv_obj(Connection *self)
  179. {
  180. char *freeme = NULL;
  181. Py_ssize_t nbytes;
  182. PyObject *result = NULL;
  183. Py_BEGIN_ALLOW_THREADS
  184. nbytes = conn_recv_string(self, self->buffer, BUFFER_SIZE, &freeme);
  185. Py_END_ALLOW_THREADS
  186. if (nbytes < 0) {
  187. SetException(PyExc_IOError, nbytes);
  188. } else {
  189. if (freeme == NULL) {
  190. result = PyObject_CallFunction(loadsFunction, "s#",
  191. self->buffer, nbytes);
  192. } else {
  193. result = PyObject_CallFunction(loadsFunction, "s#",
  194. freeme, nbytes);
  195. PyMem_Free(freeme);
  196. }
  197. }
  198. return result;
  199. }
  200. /*
  201. * Other functions
  202. */
  203. static PyObject *
  204. Connection_poll(Connection *self, PyObject *args)
  205. {
  206. PyObject *timeout_obj = NULL;
  207. double timeout = 0.0;
  208. int res;
  209. if (!PyArg_ParseTuple(args, "|O", &timeout_obj))
  210. return NULL;
  211. if (timeout_obj == NULL) {
  212. timeout = 0.0;
  213. } else if (timeout_obj == Py_None) {
  214. timeout = -1.0; /* block forever */
  215. } else {
  216. timeout = PyFloat_AsDouble(timeout_obj);
  217. if (PyErr_Occurred())
  218. return NULL;
  219. if (timeout < 0.0)
  220. timeout = 0.0;
  221. }
  222. Py_BEGIN_ALLOW_THREADS
  223. res = conn_poll(self, timeout);
  224. Py_END_ALLOW_THREADS
  225. switch (res) {
  226. case TRUE:
  227. Py_RETURN_TRUE;
  228. case FALSE:
  229. Py_RETURN_FALSE;
  230. default:
  231. return SetException(PyExc_IOError, res);
  232. }
  233. }
  234. static PyObject *
  235. Connection_fileno(Connection* self)
  236. {
  237. if (self->handle == INVALID_HANDLE_VALUE) {
  238. PyErr_SetString(PyExc_IOError, "handle is invalid");
  239. return NULL;
  240. }
  241. return PyInt_FromLong((long)self->handle);
  242. }
  243. static PyObject *
  244. Connection_close(Connection *self)
  245. {
  246. if (self->handle != INVALID_HANDLE_VALUE) {
  247. Py_BEGIN_ALLOW_THREADS
  248. CLOSE(self->handle);
  249. Py_END_ALLOW_THREADS
  250. self->handle = INVALID_HANDLE_VALUE;
  251. }
  252. Py_RETURN_NONE;
  253. }
  254. static PyObject *
  255. Connection_repr(Connection *self)
  256. {
  257. return PyString_FromFormat("%s(handle=%" PY_FORMAT_SIZE_T "d)",
  258. CONNECTION_NAME, (Py_ssize_t)self->handle);
  259. }
  260. /*
  261. * Getters and setters
  262. */
  263. static PyObject *
  264. Connection_closed(Connection *self, void *closure)
  265. {
  266. return PyBool_FromLong(self->handle == INVALID_HANDLE_VALUE);
  267. }
  268. /*
  269. * Method table
  270. */
  271. static PyMethodDef Connection_methods[] = {
  272. {"sendBytes", (PyCFunction)Connection_sendbytes, METH_VARARGS,
  273. "send the byte data from a readable buffer-like object"},
  274. {"recvBytes", (PyCFunction)Connection_recvbytes, METH_NOARGS,
  275. "receive byte data as a string"},
  276. {"recvBytesInto", (PyCFunction)Connection_recvbytes_into, METH_VARARGS,
  277. "receive byte data into a writeable buffer-like object\n"
  278. "returns the number of bytes read"},
  279. {"send", (PyCFunction)Connection_send_obj, METH_O,
  280. "send a (picklable) object"},
  281. {"recv", (PyCFunction)Connection_recv_obj, METH_NOARGS,
  282. "receive a (picklable) object"},
  283. {"poll", (PyCFunction)Connection_poll, METH_VARARGS,
  284. "whether there is any input available to be read"},
  285. {"fileno", (PyCFunction)Connection_fileno, METH_NOARGS,
  286. "file descriptor or handle of the connection"},
  287. {"close", (PyCFunction)Connection_close, METH_NOARGS,
  288. "close the connection"},
  289. /* deprecated names */
  290. {"sendbytes", (PyCFunction)Connection_sendbytes, METH_VARARGS,
  291. "send the byte data from a readable buffer-like object"},
  292. {"recvbytes", (PyCFunction)Connection_recvbytes, METH_NOARGS,
  293. "receive byte data as a string"},
  294. {"recvbytes_into", (PyCFunction)Connection_recvbytes_into, METH_VARARGS,
  295. "receive byte data into a writeable buffer-like object\n"
  296. "returns the number of bytes read"},
  297. {NULL} /* Sentinel */
  298. };
  299. /*
  300. * Member table
  301. */
  302. static PyGetSetDef Connection_getsetters[] = {
  303. {"closed", (getter)Connection_closed, NULL,
  304. "True if the connection is closed", NULL},
  305. {NULL}
  306. };
  307. /*
  308. * Connection type
  309. */
  310. PyTypeObject CONNECTION_TYPE = {
  311. PyObject_HEAD_INIT(NULL)
  312. 0, /* ob_size */
  313. "_processing." CONNECTION_NAME,
  314. /* tp_name */
  315. sizeof(Connection), /* tp_basicsize */
  316. 0, /* tp_itemsize */
  317. (destructor)Connection_dealloc,
  318. /* tp_dealloc */
  319. 0, /* tp_print */
  320. 0, /* tp_getattr */
  321. 0, /* tp_setattr */
  322. 0, /* tp_compare */
  323. (reprfunc)Connection_repr, /* tp_repr */
  324. 0, /* tp_as_number */
  325. 0, /* tp_as_sequence */
  326. 0, /* tp_as_mapping */
  327. 0, /* tp_hash */
  328. 0, /* tp_call */
  329. 0, /* tp_str */
  330. 0, /* tp_getattro */
  331. 0, /* tp_setattro */
  332. 0, /* tp_as_buffer */
  333. Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_WEAKREFS,
  334. /* tp_flags */
  335. "Connection type whose constructor signature is\n\n"
  336. " Connection(handle, duplicate=True, inheritable=True).\n\n"
  337. "If duplicate is true then the connection uses a copy of handle;\n"
  338. "otherwise the connection claims ownership of the handle.\n"
  339. "On Windows inheritable determines whether the handle is made\n"
  340. "inheritable; on Unix it is ignored.",
  341. /* tp_doc */
  342. 0, /* tp_traverse */
  343. 0, /* tp_clear */
  344. 0, /* tp_richcompare */
  345. offsetof(Connection, weakreflist),
  346. /* tp_weaklistoffset */
  347. 0, /* tp_iter */
  348. 0, /* tp_iternext */
  349. Connection_methods, /* tp_methods */
  350. 0, /* tp_members */
  351. Connection_getsetters, /* tp_getset */
  352. 0, /* tp_base */
  353. 0, /* tp_dict */
  354. 0, /* tp_descr_get */
  355. 0, /* tp_descr_set */
  356. 0, /* tp_dictoffset */
  357. 0, /* tp_init */
  358. 0, /* tp_alloc */
  359. (newfunc)Connection_new, /* tp_new */
  360. };
  361. #endif /* CONNECTION_H */