processing.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. * Extension module used by `processing` package
  3. *
  4. * processing.c
  5. *
  6. * Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
  7. */
  8. #include "processing.h"
  9. PyObject *create_win32_namespace(void);
  10. PyObject *dumpsFunction, *loadsFunction, *protocol;
  11. PyObject *ProcessError, *BufferTooShort;
  12. /*
  13. * Function which raises exceptions based on error codes
  14. */
  15. PyObject *
  16. SetException(PyObject *Type, int num)
  17. {
  18. switch (num) {
  19. #ifdef MS_WINDOWS
  20. case STANDARD_ERROR:
  21. if (Type == NULL)
  22. Type = PyExc_WindowsError;
  23. PyErr_SetExcFromWindowsErr(Type, 0);
  24. break;
  25. case WSA_ERROR:
  26. if (Type == NULL)
  27. Type = PyExc_WindowsError;
  28. PyErr_SetExcFromWindowsErr(Type, WSAGetLastError());
  29. break;
  30. #else /* !MS_WINDOWS */
  31. case STANDARD_ERROR:
  32. if (Type == NULL)
  33. Type = PyExc_OSError;
  34. PyErr_SetFromErrno(Type);
  35. break;
  36. #endif /* !MS_WINDOWS */
  37. case MEMORY_ERROR:
  38. PyErr_NoMemory();
  39. break;
  40. case END_OF_FILE:
  41. PyErr_SetNone(PyExc_EOFError);
  42. break;
  43. case EARLY_END_OF_FILE:
  44. PyErr_SetString(PyExc_IOError, "got end of file during message");
  45. break;
  46. case BAD_MESSAGE_LENGTH:
  47. PyErr_SetString(PyExc_IOError, "bad message length");
  48. break;
  49. case EXCEPTION_HAS_BEEN_SET:
  50. return NULL;
  51. default:
  52. PyErr_Format(PyExc_RuntimeError, "unkown number: %d", num);
  53. }
  54. return NULL;
  55. }
  56. /*
  57. * Windows only
  58. */
  59. #ifdef MS_WINDOWS
  60. /* On Windows we set an event to signal Ctrl-C; compare with timemodule.c */
  61. HANDLE hInterruptEvent = NULL;
  62. long main_thread = 0;
  63. static BOOL WINAPI
  64. ProcessingCtrlHandler(DWORD dwCtrlType)
  65. {
  66. SetEvent(hInterruptEvent);
  67. return FALSE;
  68. }
  69. /* Duplicate a handle -- also works on windows sockets */
  70. HANDLE
  71. duplicate_handle(HANDLE h)
  72. {
  73. HANDLE dup_h;
  74. BOOL success = DuplicateHandle(
  75. GetCurrentProcess(), h, GetCurrentProcess(),
  76. &dup_h, 0, FALSE, DUPLICATE_SAME_ACCESS
  77. );
  78. return success ? dup_h : INVALID_HANDLE_VALUE;
  79. }
  80. /* On Windows we provide alternative to socket.fromfd() */
  81. #if defined(MS_WINDOWS) && PY_VERSION_HEX < 0x02060000
  82. typedef struct {
  83. PyObject_HEAD
  84. SOCKET sock_fd;
  85. int sock_family;
  86. int sock_type;
  87. int sock_proto;
  88. PyObject *(*errorhandler)(void);
  89. double sock_timeout;
  90. } PySocketSockObject;
  91. PyObject *
  92. processing_changefd(PyObject *self, PyObject *args)
  93. {
  94. PySocketSockObject *s;
  95. int family, type, proto=0;
  96. SOCKET fd, newfd;
  97. if (!PyArg_ParseTuple(args, "Oiii|i", &s, &fd, &family, &type, &proto))
  98. return NULL;
  99. /* Note INVALID_HANDLE_VALUE == INVALID_SOCKET == -1 (modulo casting) */
  100. newfd = (SOCKET)duplicate_handle((HANDLE)fd);
  101. if (newfd == INVALID_SOCKET) {
  102. PyErr_SetString(PyExc_OSError, "failed to duplicate socket handle");
  103. return NULL;
  104. }
  105. if (s->sock_fd != INVALID_SOCKET) {
  106. Py_BEGIN_ALLOW_THREADS
  107. CloseHandle((HANDLE)s->sock_fd);
  108. Py_END_ALLOW_THREADS
  109. }
  110. s->sock_fd = newfd;
  111. s->sock_family = family;
  112. s->sock_type = type;
  113. s->sock_proto = proto;
  114. Py_RETURN_NONE;
  115. }
  116. #endif /* defined(MS_WINDOWS) && PY_VERSION_HEX < 0x02060000 */
  117. /*
  118. * Unix only
  119. */
  120. #else /* !MS_WINDOWS */
  121. #if HAVE_FD_TRANSFER
  122. /* Functions for transferring file descriptors between processes.
  123. Reimplements some of the functionality of the `fdcred`
  124. module at `http://www.mca-ltd.com/resources/fdcred_1.tgz`. */
  125. static PyObject *
  126. processing_sendfd(PyObject *self, PyObject *args)
  127. {
  128. int conn, fd, res;
  129. char dummy_char;
  130. char buf[CMSG_SPACE(sizeof(int))];
  131. struct msghdr msg = {0};
  132. struct iovec dummy_iov;
  133. struct cmsghdr *cmsg;
  134. if (!PyArg_ParseTuple(args, "ii", &conn, &fd))
  135. return NULL;
  136. dummy_iov.iov_base = &dummy_char;
  137. dummy_iov.iov_len = 1;
  138. msg.msg_control = buf;
  139. msg.msg_controllen = sizeof(buf);
  140. msg.msg_iov = &dummy_iov;
  141. msg.msg_iovlen = 1;
  142. cmsg = CMSG_FIRSTHDR(&msg);
  143. cmsg->cmsg_level = SOL_SOCKET;
  144. cmsg->cmsg_type = SCM_RIGHTS;
  145. cmsg->cmsg_len = CMSG_LEN(sizeof(int));
  146. msg.msg_controllen = cmsg->cmsg_len;
  147. *(int*)CMSG_DATA(cmsg) = fd;
  148. Py_BEGIN_ALLOW_THREADS
  149. res = sendmsg(conn, &msg, 0);
  150. Py_END_ALLOW_THREADS
  151. if (res < 0)
  152. return PyErr_SetFromErrno(PyExc_OSError);
  153. Py_RETURN_NONE;
  154. }
  155. static PyObject *
  156. processing_recvfd(PyObject *self, PyObject *args)
  157. {
  158. int conn, fd, res;
  159. char dummy_char;
  160. char buf[CMSG_SPACE(sizeof(int))];
  161. struct msghdr msg = {0};
  162. struct iovec dummy_iov;
  163. struct cmsghdr *cmsg;
  164. if (!PyArg_ParseTuple(args, "i", &conn))
  165. return NULL;
  166. dummy_iov.iov_base = &dummy_char;
  167. dummy_iov.iov_len = 1;
  168. msg.msg_control = buf;
  169. msg.msg_controllen = sizeof(buf);
  170. msg.msg_iov = &dummy_iov;
  171. msg.msg_iovlen = 1;
  172. cmsg = CMSG_FIRSTHDR(&msg);
  173. cmsg->cmsg_level = SOL_SOCKET;
  174. cmsg->cmsg_type = SCM_RIGHTS;
  175. cmsg->cmsg_len = CMSG_LEN(sizeof(int));
  176. msg.msg_controllen = cmsg->cmsg_len;
  177. Py_BEGIN_ALLOW_THREADS
  178. res = recvmsg(conn, &msg, 0);
  179. Py_END_ALLOW_THREADS
  180. if (res < 0)
  181. return PyErr_SetFromErrno(PyExc_OSError);
  182. fd = *(int*)CMSG_DATA(cmsg);
  183. return Py_BuildValue("i", fd);
  184. }
  185. #endif /* HAVE_FD_TRANSFER */
  186. #endif /* !MS_WINDOWS */
  187. /*
  188. * All platforms
  189. */
  190. static PyObject*
  191. processing_rwbuffer(PyObject *self, PyObject *args)
  192. {
  193. PyObject *obj;
  194. Py_ssize_t offset = 0, size = Py_END_OF_BUFFER;
  195. if (!PyArg_ParseTuple(args, "O|" F_PY_SSIZE_T F_PY_SSIZE_T,
  196. &obj, &offset, &size))
  197. return NULL;
  198. return PyBuffer_FromReadWriteObject(obj, offset, size);
  199. }
  200. static PyObject*
  201. processing_address_of_buffer(PyObject *self, PyObject *obj)
  202. {
  203. void *buffer;
  204. Py_ssize_t buffer_len;
  205. if (PyObject_AsWriteBuffer(obj, &buffer, &buffer_len) < 0)
  206. return NULL;
  207. return Py_BuildValue("N" F_PY_SSIZE_T,
  208. PyLong_FromVoidPtr(buffer), buffer_len);
  209. }
  210. /*
  211. * Function table
  212. */
  213. static PyMethodDef module_methods[] = {
  214. {"readWriteBuffer", processing_rwbuffer, METH_VARARGS,
  215. "readWriteBuffer(obj [, offset[, size]]) -> buffer\n"
  216. "Create a writable view of obj assuming obj supports buffer inteface"},
  217. {"addressOfBuffer", processing_address_of_buffer, METH_O,
  218. "addressOfBuffer(obj) -> integer\n"
  219. "Return address of obj assuming obj supports buffer inteface"},
  220. #if HAVE_FD_TRANSFER
  221. {"sendFd", processing_sendfd, METH_VARARGS,
  222. "sendFd(sockfd, fd) -> None\n"
  223. "Send file descriptor given by fd over the unix domain socket\n"
  224. "whose file decriptor is sockfd"},
  225. {"recvFd", processing_recvfd, METH_VARARGS,
  226. "recvFd(sockfd) -> fd\n"
  227. "Receive a file descriptor over a unix domain socket\n"
  228. "whose file decriptor is sockfd"},
  229. #endif
  230. #if defined(MS_WINDOWS) && PY_VERSION_HEX < 0x02060000
  231. {"changeFd", (PyCFunction)processing_changefd, METH_VARARGS,
  232. "changeFd(fd, family, type [, proto]) -> None\n"
  233. "Replace the file descriptor etc of an existing socket object\n"
  234. "the old fd is closed, and replaced with a duplicate of fd"},
  235. #endif
  236. {NULL}
  237. };
  238. /*
  239. * Initialize
  240. */
  241. PyMODINIT_FUNC
  242. init_processing(void)
  243. {
  244. PyObject *module, *temp;
  245. /* Initialize module */
  246. module = Py_InitModule("_processing", module_methods);
  247. if (!module)
  248. return;
  249. /* Get copy of objects from cPickle */
  250. temp = PyImport_ImportModule("cPickle");
  251. if (!temp)
  252. return;
  253. dumpsFunction = PyObject_GetAttrString(temp, "dumps");
  254. loadsFunction = PyObject_GetAttrString(temp, "loads");
  255. protocol = PyObject_GetAttrString(temp, "HIGHEST_PROTOCOL");
  256. Py_XDECREF(temp);
  257. /* Add ProcessError to module */
  258. ProcessError = PyErr_NewException("_processing.ProcessError", NULL, NULL);
  259. if (!ProcessError)
  260. return;
  261. Py_INCREF(ProcessError);
  262. PyModule_AddObject(module, "ProcessError", ProcessError);
  263. /* Add BufferTooShort to module */
  264. BufferTooShort = PyErr_NewException("_processing.BufferTooShort",
  265. ProcessError, NULL);
  266. if (!BufferTooShort)
  267. return;
  268. Py_INCREF(BufferTooShort);
  269. PyModule_AddObject(module, "BufferTooShort", BufferTooShort);
  270. /* Add connection type to module */
  271. if (PyType_Ready(&ConnectionType) < 0)
  272. return;
  273. Py_INCREF(&ConnectionType);
  274. PyModule_AddObject(module, "Connection", (PyObject*)&ConnectionType);
  275. #if defined(MS_WINDOWS) || HAVE_SEM_OPEN
  276. /* Add SemLock type to module */
  277. if (PyType_Ready(&SemLockType) < 0)
  278. return;
  279. Py_INCREF(&SemLockType);
  280. PyModule_AddObject(module, "SemLock", (PyObject*)&SemLockType);
  281. #endif
  282. #ifdef MS_WINDOWS
  283. /* Add PipeConnection to module */
  284. if (PyType_Ready(&PipeConnectionType) < 0)
  285. return;
  286. Py_INCREF(&PipeConnectionType);
  287. PyModule_AddObject(module,"PipeConnection",(PyObject*)&PipeConnectionType);
  288. /* Initialize win32 class and add to processing */
  289. temp = create_win32_namespace();
  290. if (!temp)
  291. return;
  292. PyModule_AddObject(module, "win32", temp);
  293. /* Initialize the event handle used to signal Ctrl-C */
  294. main_thread = GetCurrentThreadId(); /* hope not imported by subthread */
  295. hInterruptEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  296. if (!hInterruptEvent) {
  297. PyErr_SetFromWindowsErr(0);
  298. return;
  299. }
  300. if (!SetConsoleCtrlHandler(ProcessingCtrlHandler, TRUE)) {
  301. PyErr_SetFromWindowsErr(0);
  302. return;
  303. }
  304. PyModule_AddObject(module, "_hInterruptEvent",
  305. Py_BuildValue(F_HANDLE, hInterruptEvent));
  306. PyModule_AddObject(module, "_main_thread_ident",
  307. Py_BuildValue(F_HANDLE, main_thread));
  308. #endif
  309. /* Add configuration macros */
  310. #ifdef HAVE_SEM_OPEN
  311. PyModule_AddObject(module, "HAVE_SEM_OPEN",
  312. Py_BuildValue("i", HAVE_SEM_OPEN));
  313. #endif
  314. #ifdef HAVE_SEM_TIMEDWAIT
  315. PyModule_AddObject(module, "HAVE_SEM_TIMEDWAIT",
  316. Py_BuildValue("i", HAVE_SEM_TIMEDWAIT));
  317. #endif
  318. #ifdef HAVE_FD_TRANSFER
  319. PyModule_AddObject(module, "HAVE_FD_TRANSFER",
  320. Py_BuildValue("i", HAVE_FD_TRANSFER));
  321. #endif
  322. #ifdef HAVE_BROKEN_SEM_GETVALUE
  323. PyModule_AddObject(module, "HAVE_BROKEN_SEM_GETVALUE",
  324. Py_BuildValue("i", HAVE_BROKEN_SEM_GETVALUE));
  325. #endif
  326. #ifdef HAVE_BROKEN_SEM_UNLINK
  327. PyModule_AddObject(module, "HAVE_BROKEN_SEM_UNLINK",
  328. Py_BuildValue("i", HAVE_BROKEN_SEM_UNLINK));
  329. #endif
  330. }