The core of the fix to allow opens to go async inside a compound request.
[Samba.git] / lib / tevent / pytevent.c
blob22541bb624f58c3ed37836204e52386fa5a2ea2c
1 /*
2 Unix SMB/CIFS implementation.
3 Python bindings for tevent
5 Copyright (C) Jelmer Vernooij 2010
7 ** NOTE! The following LGPL license applies to the tevent
8 ** library. This does NOT imply that all of Samba is released
9 ** under the LGPL
11 This library is free software; you can redistribute it and/or
12 modify it under the terms of the GNU Lesser General Public
13 License as published by the Free Software Foundation; either
14 version 3 of the License, or (at your option) any later version.
16 This library is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 Lesser General Public License for more details.
21 You should have received a copy of the GNU Lesser General Public
22 License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 #include <Python.h>
26 #include <tevent.h>
28 typedef struct {
29 PyObject_HEAD
30 struct tevent_context *ev;
31 } TeventContext_Object;
33 typedef struct {
34 PyObject_HEAD
35 struct tevent_queue *queue;
36 } TeventQueue_Object;
38 typedef struct {
39 PyObject_HEAD
40 struct tevent_req *req;
41 } TeventReq_Object;
43 typedef struct {
44 PyObject_HEAD
45 struct tevent_signal *signal;
46 } TeventSignal_Object;
48 typedef struct {
49 PyObject_HEAD
50 struct tevent_timer *timer;
51 } TeventTimer_Object;
53 typedef struct {
54 PyObject_HEAD
55 struct tevent_fd *fd;
56 } TeventFd_Object;
58 staticforward PyTypeObject TeventContext_Type;
59 staticforward PyTypeObject TeventReq_Type;
60 staticforward PyTypeObject TeventQueue_Type;
61 staticforward PyTypeObject TeventSignal_Type;
62 staticforward PyTypeObject TeventTimer_Type;
63 staticforward PyTypeObject TeventFd_Type;
65 static int py_context_init(struct tevent_context *ev)
67 /* FIXME */
68 return 0;
71 static struct tevent_fd *py_add_fd(struct tevent_context *ev,
72 TALLOC_CTX *mem_ctx,
73 int fd, uint16_t flags,
74 tevent_fd_handler_t handler,
75 void *private_data,
76 const char *handler_name,
77 const char *location)
79 /* FIXME */
80 return NULL;
83 static void py_set_fd_close_fn(struct tevent_fd *fde,
84 tevent_fd_close_fn_t close_fn)
86 /* FIXME */
89 uint16_t py_get_fd_flags(struct tevent_fd *fde)
91 /* FIXME */
92 return 0;
95 static void py_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
97 /* FIXME */
100 /* timed_event functions */
101 static struct tevent_timer *py_add_timer(struct tevent_context *ev,
102 TALLOC_CTX *mem_ctx,
103 struct timeval next_event,
104 tevent_timer_handler_t handler,
105 void *private_data,
106 const char *handler_name,
107 const char *location)
109 /* FIXME */
110 return NULL;
113 /* immediate event functions */
114 static void py_schedule_immediate(struct tevent_immediate *im,
115 struct tevent_context *ev,
116 tevent_immediate_handler_t handler,
117 void *private_data,
118 const char *handler_name,
119 const char *location)
121 /* FIXME */
124 /* signal functions */
125 static struct tevent_signal *py_add_signal(struct tevent_context *ev,
126 TALLOC_CTX *mem_ctx,
127 int signum, int sa_flags,
128 tevent_signal_handler_t handler,
129 void *private_data,
130 const char *handler_name,
131 const char *location)
133 /* FIXME */
134 return NULL;
137 /* loop functions */
138 static int py_loop_once(struct tevent_context *ev, const char *location)
140 /* FIXME */
141 return 0;
144 static int py_loop_wait(struct tevent_context *ev, const char *location)
146 /* FIXME */
147 return 0;
150 const static struct tevent_ops py_tevent_ops = {
151 .context_init = py_context_init,
152 .add_fd = py_add_fd,
153 .set_fd_close_fn = py_set_fd_close_fn,
154 .get_fd_flags = py_get_fd_flags,
155 .set_fd_flags = py_set_fd_flags,
156 .add_timer = py_add_timer,
157 .schedule_immediate = py_schedule_immediate,
158 .add_signal = py_add_signal,
159 .loop_wait = py_loop_wait,
160 .loop_once = py_loop_once,
163 static PyObject *py_register_backend(PyObject *self, PyObject *args)
165 PyObject *name, *py_backend;
167 if (!PyArg_ParseTuple(args, "O", &py_backend))
168 return NULL;
170 name = PyObject_GetAttrString(py_backend, "name");
171 if (name == NULL) {
172 PyErr_SetNone(PyExc_AttributeError);
173 return NULL;
176 if (!PyString_Check(name)) {
177 PyErr_SetNone(PyExc_TypeError);
178 return NULL;
181 if (!tevent_register_backend(PyString_AsString(name), &py_tevent_ops)) { /* FIXME: What to do with backend */
182 PyErr_SetNone(PyExc_RuntimeError);
183 return NULL;
186 Py_RETURN_NONE;
189 static PyObject *py_tevent_context_reinitialise(TeventContext_Object *self)
191 int ret = tevent_re_initialise(self->ev);
192 if (ret != 0) {
193 PyErr_SetNone(PyExc_RuntimeError);
194 return NULL;
196 Py_RETURN_NONE;
199 static PyObject *py_tevent_queue_stop(TeventQueue_Object *self)
201 tevent_queue_stop(self->queue);
202 Py_RETURN_NONE;
205 static PyObject *py_tevent_queue_start(TeventQueue_Object *self)
207 tevent_queue_start(self->queue);
208 Py_RETURN_NONE;
211 static void py_queue_trigger(struct tevent_req *req, void *private_data)
213 PyObject *callback = private_data, *ret;
215 ret = PyObject_CallFunction(callback, "");
216 Py_XDECREF(ret);
219 static PyObject *py_tevent_queue_add(TeventQueue_Object *self, PyObject *args)
221 TeventContext_Object *py_ev;
222 TeventReq_Object *py_req;
223 PyObject *trigger;
224 bool ret;
226 if (!PyArg_ParseTuple(args, "O!O!O",
227 &TeventContext_Type, &py_ev,
228 &TeventReq_Type, &py_req,
229 &trigger))
230 return NULL;
232 Py_INCREF(trigger);
234 ret = tevent_queue_add(self->queue, py_ev->ev, py_req->req,
235 py_queue_trigger, trigger);
236 if (!ret) {
237 PyErr_SetString(PyExc_RuntimeError, "queue add failed");
238 Py_DECREF(trigger);
239 return NULL;
242 Py_RETURN_NONE;
245 static PyMethodDef py_tevent_queue_methods[] = {
246 { "stop", (PyCFunction)py_tevent_queue_stop, METH_NOARGS,
247 "S.stop()" },
248 { "start", (PyCFunction)py_tevent_queue_start, METH_NOARGS,
249 "S.start()" },
250 { "add", (PyCFunction)py_tevent_queue_add, METH_VARARGS,
251 "S.add(ctx, req, trigger, baton)" },
252 { NULL },
255 static PyObject *py_tevent_context_wakeup_send(PyObject *self, PyObject *args)
257 /* FIXME */
259 Py_RETURN_NONE;
262 static PyObject *py_tevent_context_loop_wait(TeventContext_Object *self)
264 if (tevent_loop_wait(self->ev) != 0) {
265 PyErr_SetNone(PyExc_RuntimeError);
266 return NULL;
268 Py_RETURN_NONE;
271 static PyObject *py_tevent_context_loop_once(TeventContext_Object *self)
273 if (tevent_loop_once(self->ev) != 0) {
274 PyErr_SetNone(PyExc_RuntimeError);
275 return NULL;
277 Py_RETURN_NONE;
280 #ifdef TEVENT_DEPRECATED
281 static bool py_tevent_finished(PyObject *callback)
283 PyObject *py_ret;
284 bool ret;
286 py_ret = PyObject_CallFunction(callback, "");
287 if (py_ret == NULL)
288 return true;
289 ret = PyObject_IsTrue(py_ret);
290 Py_DECREF(py_ret);
291 return ret;
294 static PyObject *py_tevent_context_loop_until(TeventContext_Object *self, PyObject *args)
296 PyObject *callback;
297 if (!PyArg_ParseTuple(args, "O", &callback))
298 return NULL;
300 if (tevent_loop_until(self->ev, py_tevent_finished, callback) != 0) {
301 PyErr_SetNone(PyExc_RuntimeError);
302 return NULL;
305 if (PyErr_Occurred())
306 return NULL;
308 Py_RETURN_NONE;
310 #endif
312 static void py_tevent_signal_handler(struct tevent_context *ev,
313 struct tevent_signal *se,
314 int signum,
315 int count,
316 void *siginfo,
317 void *private_data)
319 PyObject *callback = (PyObject *)private_data, *ret;
321 ret = PyObject_CallFunction(callback, "ii", signum, count);
322 Py_XDECREF(ret);
325 static void py_tevent_signal_dealloc(TeventSignal_Object *self)
327 talloc_free(self->signal);
328 PyObject_Del(self);
331 static PyTypeObject TeventSignal_Type = {
332 .tp_name = "Signal",
333 .tp_basicsize = sizeof(TeventSignal_Object),
334 .tp_dealloc = (destructor)py_tevent_signal_dealloc,
335 .tp_flags = Py_TPFLAGS_DEFAULT,
338 static PyObject *py_tevent_context_add_signal(TeventContext_Object *self, PyObject *args)
340 int signum, sa_flags;
341 PyObject *handler;
342 struct tevent_signal *sig;
343 TeventSignal_Object *ret;
345 if (!PyArg_ParseTuple(args, "iiO", &signum, &sa_flags, &handler))
346 return NULL;
348 Py_INCREF(handler);
349 sig = tevent_add_signal(self->ev, NULL, signum, sa_flags,
350 py_tevent_signal_handler, handler);
352 ret = PyObject_New(TeventSignal_Object, &TeventSignal_Type);
353 if (ret == NULL) {
354 PyErr_NoMemory();
355 talloc_free(sig);
356 return NULL;
359 ret->signal = sig;
361 return (PyObject *)ret;
364 static void py_timer_handler(struct tevent_context *ev,
365 struct tevent_timer *te,
366 struct timeval current_time,
367 void *private_data)
369 PyObject *callback = private_data, *ret;
370 ret = PyObject_CallFunction(callback, "l", te);
371 Py_XDECREF(ret);
374 static PyObject *py_tevent_context_add_timer(TeventContext_Object *self, PyObject *args)
376 TeventTimer_Object *ret;
377 struct timeval next_event;
378 struct tevent_timer *timer;
379 PyObject *handler;
380 if (!PyArg_ParseTuple(args, "lO", &next_event, &handler))
381 return NULL;
383 timer = tevent_add_timer(self->ev, NULL, next_event, py_timer_handler,
384 handler);
385 if (timer == NULL) {
386 PyErr_SetNone(PyExc_RuntimeError);
387 return NULL;
390 ret = PyObject_New(TeventTimer_Object, &TeventTimer_Type);
391 if (ret == NULL) {
392 PyErr_NoMemory();
393 talloc_free(timer);
394 return NULL;
396 ret->timer = timer;
398 return (PyObject *)ret;
401 static void py_fd_handler(struct tevent_context *ev,
402 struct tevent_fd *fde,
403 uint16_t flags,
404 void *private_data)
406 PyObject *callback = private_data, *ret;
408 ret = PyObject_CallFunction(callback, "i", flags);
409 Py_XDECREF(ret);
412 static PyObject *py_tevent_context_add_fd(TeventContext_Object *self, PyObject *args)
414 int fd, flags;
415 PyObject *handler;
416 struct tevent_fd *tfd;
417 TeventFd_Object *ret;
419 if (!PyArg_ParseTuple(args, "iiO", &fd, &flags, &handler))
420 return NULL;
422 tfd = tevent_add_fd(self->ev, NULL, fd, flags, py_fd_handler, handler);
423 if (tfd == NULL) {
424 PyErr_SetNone(PyExc_RuntimeError);
425 return NULL;
428 ret = PyObject_New(TeventFd_Object, &TeventFd_Type);
429 if (ret == NULL) {
430 talloc_free(tfd);
431 return NULL;
433 ret->fd = tfd;
435 return (PyObject *)ret;
438 #ifdef TEVENT_DEPRECATED
439 static PyObject *py_tevent_context_set_allow_nesting(TeventContext_Object *self)
441 tevent_loop_allow_nesting(self->ev);
442 Py_RETURN_NONE;
444 #endif
446 static PyMethodDef py_tevent_context_methods[] = {
447 { "reinitialise", (PyCFunction)py_tevent_context_reinitialise, METH_NOARGS,
448 "S.reinitialise()" },
449 { "wakeup_send", (PyCFunction)py_tevent_context_wakeup_send,
450 METH_VARARGS, "S.wakeup_send(wakeup_time) -> req" },
451 { "loop_wait", (PyCFunction)py_tevent_context_loop_wait,
452 METH_NOARGS, "S.loop_wait()" },
453 { "loop_once", (PyCFunction)py_tevent_context_loop_once,
454 METH_NOARGS, "S.loop_once()" },
455 #ifdef TEVENT_DEPRECATED
456 { "loop_until", (PyCFunction)py_tevent_context_loop_until,
457 METH_VARARGS, "S.loop_until(callback)" },
458 #endif
459 { "add_signal", (PyCFunction)py_tevent_context_add_signal,
460 METH_VARARGS, "S.add_signal(signum, sa_flags, handler) -> signal" },
461 { "add_timer", (PyCFunction)py_tevent_context_add_timer,
462 METH_VARARGS, "S.add_timer(next_event, handler) -> timer" },
463 { "add_fd", (PyCFunction)py_tevent_context_add_fd,
464 METH_VARARGS, "S.add_fd(fd, flags, handler) -> fd" },
465 #ifdef TEVENT_DEPRECATED
466 { "allow_nesting", (PyCFunction)py_tevent_context_set_allow_nesting,
467 METH_NOARGS, "Whether to allow nested tevent loops." },
468 #endif
469 { NULL },
472 static PyObject *py_tevent_req_wakeup_recv(PyObject *self)
474 /* FIXME */
475 Py_RETURN_NONE;
478 static PyObject *py_tevent_req_received(PyObject *self)
480 /* FIXME */
481 Py_RETURN_NONE;
484 static PyObject *py_tevent_req_is_error(PyObject *self)
486 /* FIXME */
487 Py_RETURN_NONE;
490 static PyObject *py_tevent_req_poll(PyObject *self)
492 /* FIXME */
493 Py_RETURN_NONE;
496 static PyObject *py_tevent_req_is_in_progress(PyObject *self)
498 /* FIXME */
499 Py_RETURN_NONE;
502 static PyGetSetDef py_tevent_req_getsetters[] = {
503 { "in_progress", (getter)py_tevent_req_is_in_progress, NULL,
504 "Whether the request is in progress" },
505 { NULL }
508 static PyObject *py_tevent_req_post(PyObject *self, PyObject *args)
510 /* FIXME */
511 Py_RETURN_NONE;
514 static PyObject *py_tevent_req_set_error(PyObject *self, PyObject *args)
516 /* FIXME */
517 Py_RETURN_NONE;
520 static PyObject *py_tevent_req_done(PyObject *self)
522 /* FIXME */
523 Py_RETURN_NONE;
526 static PyObject *py_tevent_req_notify_callback(PyObject *self)
528 /* FIXME */
529 Py_RETURN_NONE;
532 static PyObject *py_tevent_req_set_endtime(PyObject *self, PyObject *args)
534 /* FIXME */
535 Py_RETURN_NONE;
538 static PyObject *py_tevent_req_cancel(TeventReq_Object *self)
540 if (!tevent_req_cancel(self->req)) {
541 PyErr_SetNone(PyExc_RuntimeError);
542 return NULL;
544 Py_RETURN_NONE;
547 static PyMethodDef py_tevent_req_methods[] = {
548 { "wakeup_recv", (PyCFunction)py_tevent_req_wakeup_recv, METH_NOARGS,
549 "Wakeup received" },
550 { "received", (PyCFunction)py_tevent_req_received, METH_NOARGS,
551 "Receive finished" },
552 { "is_error", (PyCFunction)py_tevent_req_is_error, METH_NOARGS,
553 "is_error() -> (error, state)" },
554 { "poll", (PyCFunction)py_tevent_req_poll, METH_VARARGS,
555 "poll(ctx)" },
556 { "post", (PyCFunction)py_tevent_req_post, METH_VARARGS,
557 "post(ctx) -> req" },
558 { "set_error", (PyCFunction)py_tevent_req_set_error, METH_VARARGS,
559 "set_error(error)" },
560 { "done", (PyCFunction)py_tevent_req_done, METH_NOARGS,
561 "done()" },
562 { "notify_callback", (PyCFunction)py_tevent_req_notify_callback,
563 METH_NOARGS, "notify_callback()" },
564 { "set_endtime", (PyCFunction)py_tevent_req_set_endtime,
565 METH_VARARGS, "set_endtime(ctx, endtime)" },
566 { "cancel", (PyCFunction)py_tevent_req_cancel,
567 METH_NOARGS, "cancel()" },
568 { NULL }
571 static void py_tevent_req_dealloc(TeventReq_Object *self)
573 talloc_free(self->req);
574 PyObject_DEL(self);
577 static PyTypeObject TeventReq_Type = {
578 .tp_name = "tevent.Request",
579 .tp_basicsize = sizeof(TeventReq_Object),
580 .tp_methods = py_tevent_req_methods,
581 .tp_dealloc = (destructor)py_tevent_req_dealloc,
582 .tp_getset = py_tevent_req_getsetters,
583 /* FIXME: .tp_new = py_tevent_req_new, */
586 static PyObject *py_tevent_queue_get_length(TeventQueue_Object *self)
588 return PyInt_FromLong(tevent_queue_length(self->queue));
591 static PyGetSetDef py_tevent_queue_getsetters[] = {
592 { "length", (getter)py_tevent_queue_get_length,
593 NULL, "The number of elements in the queue." },
594 { NULL },
597 static void py_tevent_queue_dealloc(TeventQueue_Object *self)
599 talloc_free(self->queue);
600 PyObject_Del(self);
603 static PyTypeObject TeventQueue_Type = {
604 .tp_name = "tevent.Queue",
605 .tp_basicsize = sizeof(TeventQueue_Object),
606 .tp_dealloc = (destructor)py_tevent_queue_dealloc,
607 .tp_flags = Py_TPFLAGS_DEFAULT,
608 .tp_getset = py_tevent_queue_getsetters,
609 .tp_methods = py_tevent_queue_methods,
612 static PyObject *py_tevent_context_signal_support(PyObject *_self)
614 TeventContext_Object *self = (TeventContext_Object *)_self;
615 return PyBool_FromLong(tevent_signal_support(self->ev));
618 static PyGetSetDef py_tevent_context_getsetters[] = {
619 { "signal_support", (getter)py_tevent_context_signal_support,
620 NULL, "if this platform and tevent context support signal handling" },
621 { NULL }
624 static void py_tevent_context_dealloc(TeventContext_Object *self)
626 talloc_free(self->ev);
627 PyObject_Del(self);
630 static PyObject *py_tevent_context_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
632 const char * const kwnames[] = { "name", NULL };
633 char *name = NULL;
634 struct tevent_context *ev;
635 TeventContext_Object *ret;
637 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|s", kwnames, &name))
638 return NULL;
640 if (name == NULL) {
641 ev = tevent_context_init(NULL);
642 } else {
643 ev = tevent_context_init_byname(NULL, name);
646 if (ev == NULL) {
647 PyErr_SetNone(PyExc_RuntimeError);
648 return NULL;
651 ret = PyObject_New(TeventContext_Object, type);
652 if (ret == NULL) {
653 PyErr_NoMemory();
654 talloc_free(ev);
655 return NULL;
658 ret->ev = ev;
659 return (PyObject *)ret;
662 static PyTypeObject TeventContext_Type = {
663 .tp_name = "_tevent.Context",
664 .tp_new = py_tevent_context_new,
665 .tp_basicsize = sizeof(TeventContext_Object),
666 .tp_dealloc = (destructor)py_tevent_context_dealloc,
667 .tp_methods = py_tevent_context_methods,
668 .tp_getset = py_tevent_context_getsetters,
669 .tp_flags = Py_TPFLAGS_DEFAULT,
672 static PyObject *py_set_default_backend(PyObject *self, PyObject *args)
674 char *backend_name;
675 if (!PyArg_ParseTuple(args, "s", &backend_name))
676 return NULL;
678 tevent_set_default_backend(backend_name);
680 Py_RETURN_NONE;
683 static PyObject *py_backend_list(PyObject *self)
685 PyObject *ret;
686 int i;
687 const char **backends;
689 ret = PyList_New(0);
690 if (ret == NULL) {
691 return NULL;
694 backends = tevent_backend_list(NULL);
695 if (backends == NULL) {
696 PyErr_SetNone(PyExc_RuntimeError);
697 Py_DECREF(ret);
698 return NULL;
700 for (i = 0; backends[i]; i++) {
701 PyList_Append(ret, PyString_FromString(backends[i]));
704 talloc_free(backends);
706 return ret;
709 static PyMethodDef tevent_methods[] = {
710 { "register_backend", (PyCFunction)py_register_backend, METH_VARARGS,
711 "register_backend(backend)" },
712 { "set_default_backend", (PyCFunction)py_set_default_backend,
713 METH_VARARGS, "set_default_backend(backend)" },
714 { "backend_list", (PyCFunction)py_backend_list,
715 METH_NOARGS, "backend_list() -> list" },
716 { NULL },
719 void init_tevent(void)
721 PyObject *m;
723 if (PyType_Ready(&TeventContext_Type) < 0)
724 return;
726 if (PyType_Ready(&TeventQueue_Type) < 0)
727 return;
729 if (PyType_Ready(&TeventReq_Type) < 0)
730 return;
732 if (PyType_Ready(&TeventSignal_Type) < 0)
733 return;
735 if (PyType_Ready(&TeventTimer_Type) < 0)
736 return;
738 if (PyType_Ready(&TeventFd_Type) < 0)
739 return;
741 m = Py_InitModule3("_tevent", tevent_methods, "Tevent integration for twisted.");
742 if (m == NULL)
743 return;
745 Py_INCREF(&TeventContext_Type);
746 PyModule_AddObject(m, "Context", (PyObject *)&TeventContext_Type);
748 Py_INCREF(&TeventQueue_Type);
749 PyModule_AddObject(m, "Queue", (PyObject *)&TeventQueue_Type);
751 Py_INCREF(&TeventReq_Type);
752 PyModule_AddObject(m, "Request", (PyObject *)&TeventReq_Type);
754 Py_INCREF(&TeventSignal_Type);
755 PyModule_AddObject(m, "Signal", (PyObject *)&TeventSignal_Type);
757 Py_INCREF(&TeventTimer_Type);
758 PyModule_AddObject(m, "Timer", (PyObject *)&TeventTimer_Type);
760 Py_INCREF(&TeventFd_Type);
761 PyModule_AddObject(m, "Fd", (PyObject *)&TeventFd_Type);