python_methods.h (33250B)
1 /*
2 * Copyright (c) 2017-2022 Joris Vink <joris@coders.se>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #define CORO_STATE_RUNNABLE 1
18 #define CORO_STATE_SUSPENDED 2
19
20 struct python_coro {
21 u_int64_t id;
22 int state;
23 int killed;
24 PyObject *obj;
25 char *name;
26 PyObject *result;
27 struct pylock_op *lockop;
28 struct pysocket_op *sockop;
29 struct pygather_op *gatherop;
30 struct http_request *request;
31 PyObject *exception;
32 char *exception_msg;
33 TAILQ_ENTRY(python_coro) list;
34 };
35
36 TAILQ_HEAD(coro_list, python_coro);
37
38 static PyObject *python_kore_app(PyObject *, PyObject *);
39 static PyObject *python_kore_log(PyObject *, PyObject *);
40 static PyObject *python_kore_time(PyObject *, PyObject *);
41 static PyObject *python_kore_lock(PyObject *, PyObject *);
42 static PyObject *python_kore_fatal(PyObject *, PyObject *);
43 static PyObject *python_kore_queue(PyObject *, PyObject *);
44 static PyObject *python_kore_worker(PyObject *, PyObject *);
45 static PyObject *python_kore_tracer(PyObject *, PyObject *);
46 static PyObject *python_kore_fatalx(PyObject *, PyObject *);
47 static PyObject *python_kore_task_id(PyObject *, PyObject *);
48 static PyObject *python_kore_sigtrap(PyObject *, PyObject *);
49 static PyObject *python_kore_setname(PyObject *, PyObject *);
50 static PyObject *python_kore_suspend(PyObject *, PyObject *);
51 static PyObject *python_kore_shutdown(PyObject *, PyObject *);
52 static PyObject *python_kore_coroname(PyObject *, PyObject *);
53 static PyObject *python_kore_corotrace(PyObject *, PyObject *);
54 static PyObject *python_kore_task_kill(PyObject *, PyObject *);
55 static PyObject *python_kore_prerequest(PyObject *, PyObject *);
56 static PyObject *python_kore_task_create(PyObject *, PyObject *);
57 static PyObject *python_kore_socket_wrap(PyObject *, PyObject *);
58 static PyObject *python_kore_proc(PyObject *, PyObject *, PyObject *);
59 static PyObject *python_kore_route(PyObject *, PyObject *, PyObject *);
60 static PyObject *python_kore_timer(PyObject *, PyObject *, PyObject *);
61 static PyObject *python_kore_domain(PyObject *, PyObject *, PyObject *);
62 static PyObject *python_kore_gather(PyObject *, PyObject *, PyObject *);
63 static PyObject *python_kore_sendobj(PyObject *, PyObject *,
64 PyObject *);
65 static PyObject *python_kore_server(PyObject *, PyObject *,
66 PyObject *);
67 static PyObject *python_kore_privsep(PyObject *, PyObject *,
68 PyObject *);
69
70
71 #if defined(KORE_USE_PGSQL)
72 static PyObject *python_kore_pgsql_query(PyObject *, PyObject *,
73 PyObject *);
74 static PyObject *python_kore_pgsql_register(PyObject *, PyObject *);
75 #endif
76
77 #if defined(KORE_USE_CURL)
78 static PyObject *python_kore_curl_handle(PyObject *, PyObject *);
79 static PyObject *python_kore_httpclient(PyObject *,
80 PyObject *, PyObject *);
81 #endif
82
83 static PyObject *python_websocket_broadcast(PyObject *, PyObject *);
84
85 #define METHOD(n, c, a) { n, (PyCFunction)c, a, NULL }
86 #define GETTER(n, g) { n, (getter)g, NULL, NULL, NULL }
87 #define SETTER(n, s) { n, NULL, (setter)s, NULL, NULL }
88 #define GETSET(n, g, s) { n, (getter)g, (setter)s, NULL, NULL }
89
90 static struct PyMethodDef pykore_methods[] = {
91 METHOD("app", python_kore_app, METH_VARARGS),
92 METHOD("log", python_kore_log, METH_VARARGS),
93 METHOD("time", python_kore_time, METH_NOARGS),
94 METHOD("lock", python_kore_lock, METH_NOARGS),
95 METHOD("queue", python_kore_queue, METH_VARARGS),
96 METHOD("worker", python_kore_worker, METH_VARARGS),
97 METHOD("tracer", python_kore_tracer, METH_VARARGS),
98 METHOD("fatal", python_kore_fatal, METH_VARARGS),
99 METHOD("fatalx", python_kore_fatalx, METH_VARARGS),
100 METHOD("task_id", python_kore_task_id, METH_NOARGS),
101 METHOD("sigtrap", python_kore_sigtrap, METH_VARARGS),
102 METHOD("setname", python_kore_setname, METH_VARARGS),
103 METHOD("suspend", python_kore_suspend, METH_VARARGS),
104 METHOD("shutdown", python_kore_shutdown, METH_NOARGS),
105 METHOD("coroname", python_kore_coroname, METH_VARARGS),
106 METHOD("corotrace", python_kore_corotrace, METH_VARARGS),
107 METHOD("task_kill", python_kore_task_kill, METH_VARARGS),
108 METHOD("prerequest", python_kore_prerequest, METH_VARARGS),
109 METHOD("task_create", python_kore_task_create, METH_VARARGS),
110 METHOD("socket_wrap", python_kore_socket_wrap, METH_VARARGS),
111 METHOD("proc", python_kore_proc, METH_VARARGS | METH_KEYWORDS),
112 METHOD("route", python_kore_route, METH_VARARGS | METH_KEYWORDS),
113 METHOD("timer", python_kore_timer, METH_VARARGS | METH_KEYWORDS),
114 METHOD("domain", python_kore_domain, METH_VARARGS | METH_KEYWORDS),
115 METHOD("server", python_kore_server, METH_VARARGS | METH_KEYWORDS),
116 METHOD("gather", python_kore_gather, METH_VARARGS | METH_KEYWORDS),
117 METHOD("privsep", python_kore_privsep, METH_VARARGS | METH_KEYWORDS),
118 METHOD("sendobj", python_kore_sendobj, METH_VARARGS | METH_KEYWORDS),
119 METHOD("websocket_broadcast", python_websocket_broadcast, METH_VARARGS),
120 #if defined(KORE_USE_PGSQL)
121 METHOD("dbsetup", python_kore_pgsql_register, METH_VARARGS),
122 METHOD("dbquery", python_kore_pgsql_query,
123 METH_VARARGS | METH_KEYWORDS),
124 #endif
125 #if defined(KORE_USE_CURL)
126 METHOD("curl", python_kore_curl_handle, METH_VARARGS),
127 METHOD("httpclient", python_kore_httpclient,
128 METH_VARARGS | METH_KEYWORDS),
129 #endif
130 { NULL, NULL, 0, NULL }
131 };
132
133 static struct PyModuleDef pykore_module = {
134 PyModuleDef_HEAD_INIT, "kore", NULL, -1, pykore_methods
135 };
136
137 struct pyconfig {
138 PyObject_HEAD
139 };
140
141 static int pyconfig_setattr(PyObject *, PyObject *, PyObject *);
142
143 static PyTypeObject pyconfig_type = {
144 PyVarObject_HEAD_INIT(NULL, 0)
145 .tp_name = "kore.config",
146 .tp_doc = "kore configuration",
147 .tp_setattro = pyconfig_setattr,
148 .tp_basicsize = sizeof(struct pyconfig),
149 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
150 };
151
152 #if defined(__linux__)
153 struct pyseccomp {
154 PyObject_HEAD
155 size_t elm;
156 u_int8_t *filters;
157 };
158
159 static PyObject *pyseccomp_allow(struct pyseccomp *, PyObject *);
160 static PyObject *pyseccomp_allow_arg(struct pyseccomp *, PyObject *);
161 static PyObject *pyseccomp_allow_flag(struct pyseccomp *, PyObject *);
162 static PyObject *pyseccomp_allow_mask(struct pyseccomp *, PyObject *);
163
164 static PyObject *pyseccomp_deny(struct pyseccomp *, PyObject *, PyObject *);
165 static PyObject *pyseccomp_deny_arg(struct pyseccomp *, PyObject *, PyObject *);
166 static PyObject *pyseccomp_deny_flag(struct pyseccomp *,
167 PyObject *, PyObject *);
168 static PyObject *pyseccomp_deny_mask(struct pyseccomp *,
169 PyObject *, PyObject *);
170
171 static PyObject *pyseccomp_bpf_stmt(struct pyseccomp *, PyObject *);
172
173 static PyMethodDef pyseccomp_methods[] = {
174 METHOD("allow", pyseccomp_allow, METH_VARARGS),
175 METHOD("bpf_stmt", pyseccomp_bpf_stmt, METH_VARARGS),
176 METHOD("allow_arg", pyseccomp_allow_arg, METH_VARARGS),
177 METHOD("allow_flag", pyseccomp_allow_flag, METH_VARARGS),
178 METHOD("allow_mask", pyseccomp_allow_mask, METH_VARARGS),
179 METHOD("deny", pyseccomp_deny, METH_VARARGS | METH_KEYWORDS),
180 METHOD("deny_arg", pyseccomp_deny_arg, METH_VARARGS | METH_KEYWORDS),
181 METHOD("deny_flag", pyseccomp_deny_flag, METH_VARARGS | METH_KEYWORDS),
182 METHOD("deny_mask", pyseccomp_deny_mask, METH_VARARGS | METH_KEYWORDS),
183 METHOD(NULL, NULL, -1)
184 };
185
186 static void pyseccomp_dealloc(struct pyseccomp *);
187
188 static PyTypeObject pyseccomp_type = {
189 PyVarObject_HEAD_INIT(NULL, 0)
190 .tp_name = "kore.seccomp",
191 .tp_doc = "kore seccomp configuration",
192 .tp_methods = pyseccomp_methods,
193 .tp_basicsize = sizeof(struct pyseccomp),
194 .tp_dealloc = (destructor)pyseccomp_dealloc,
195 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
196 };
197 #endif
198
199 struct pyroute {
200 PyObject_HEAD
201 char *path;
202 PyObject *func;
203 PyObject *kwargs;
204 struct kore_domain *domain;
205 TAILQ_ENTRY(pyroute) list;
206 };
207
208 static PyObject *pyroute_inner(struct pyroute *, PyObject *);
209 static void pyroute_dealloc(struct pyroute *);
210
211 static PyMethodDef pyroute_methods[] = {
212 METHOD("inner", pyroute_inner, METH_VARARGS),
213 METHOD(NULL, NULL, -1)
214 };
215
216 static PyTypeObject pyroute_type = {
217 PyVarObject_HEAD_INIT(NULL, 0)
218 .tp_name = "kore.route",
219 .tp_doc = "kore route function",
220 .tp_methods = pyroute_methods,
221 .tp_basicsize = sizeof(struct pyroute),
222 .tp_dealloc = (destructor)pyroute_dealloc,
223 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
224 };
225
226 struct pydomain {
227 PyObject_HEAD
228 struct kore_domain *config;
229 struct kore_module_handle *next;
230 PyObject *kwargs;
231 };
232
233 static PyObject *pydomain_filemaps(struct pydomain *, PyObject *);
234 static PyObject *pydomain_redirect(struct pydomain *, PyObject *);
235 static PyObject *pydomain_route(struct pydomain *, PyObject *, PyObject *);
236
237 static PyMethodDef pydomain_methods[] = {
238 METHOD("filemaps", pydomain_filemaps, METH_VARARGS),
239 METHOD("redirect", pydomain_redirect, METH_VARARGS),
240 METHOD("route", pydomain_route, METH_VARARGS | METH_KEYWORDS),
241 METHOD(NULL, NULL, -1)
242 };
243
244 static int pydomain_set_accesslog(struct pydomain *, PyObject *, void *);
245
246 static PyGetSetDef pydomain_getset[] = {
247 SETTER("accesslog", pydomain_set_accesslog),
248 SETTER(NULL, NULL),
249 };
250
251 static void pydomain_dealloc(struct pydomain *);
252
253 static PyTypeObject pydomain_type = {
254 PyVarObject_HEAD_INIT(NULL, 0)
255 .tp_name = "kore.domain",
256 .tp_doc = "kore domain configuration",
257 .tp_getset = pydomain_getset,
258 .tp_methods = pydomain_methods,
259 .tp_basicsize = sizeof(struct pydomain),
260 .tp_dealloc = (destructor)pydomain_dealloc,
261 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
262 };
263
264 #define PYSUSPEND_OP_INIT 1
265 #define PYSUSPEND_OP_WAIT 2
266 #define PYSUSPEND_OP_CONTINUE 3
267
268 struct pysuspend_op {
269 PyObject_HEAD
270 int state;
271 int delay;
272 struct python_coro *coro;
273 struct kore_timer *timer;
274 };
275
276 static void pysuspend_op_dealloc(struct pysuspend_op *);
277
278 static PyObject *pysuspend_op_await(PyObject *);
279 static PyObject *pysuspend_op_iternext(struct pysuspend_op *);
280
281 static PyAsyncMethods pysuspend_op_async = {
282 (unaryfunc)pysuspend_op_await,
283 NULL,
284 NULL
285 };
286
287 static PyTypeObject pysuspend_op_type = {
288 PyVarObject_HEAD_INIT(NULL, 0)
289 .tp_name = "kore.suspend",
290 .tp_doc = "suspension operation",
291 .tp_as_async = &pysuspend_op_async,
292 .tp_iternext = (iternextfunc)pysuspend_op_iternext,
293 .tp_basicsize = sizeof(struct pysuspend_op),
294 .tp_dealloc = (destructor)pysuspend_op_dealloc,
295 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
296 };
297
298 struct pytimer {
299 PyObject_HEAD
300 int flags;
301 struct kore_timer *run;
302 PyObject *callable;
303 PyObject *udata;
304 };
305
306 static PyObject *pytimer_close(struct pytimer *, PyObject *);
307
308 static PyMethodDef pytimer_methods[] = {
309 METHOD("close", pytimer_close, METH_NOARGS),
310 METHOD(NULL, NULL, -1)
311 };
312
313 static void pytimer_dealloc(struct pytimer *);
314
315 static PyTypeObject pytimer_type = {
316 PyVarObject_HEAD_INIT(NULL, 0)
317 .tp_name = "kore.timer",
318 .tp_doc = "kore timer implementation",
319 .tp_methods = pytimer_methods,
320 .tp_basicsize = sizeof(struct pytimer),
321 .tp_dealloc = (destructor)pytimer_dealloc,
322 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
323 };
324
325 /* XXX */
326 struct pysocket;
327 struct pysocket_op;
328
329 struct pysocket_event {
330 struct kore_event evt;
331 struct pysocket *s;
332 };
333
334 struct pysocket {
335 PyObject_HEAD
336 int fd;
337 int family;
338 int protocol;
339 int scheduled;
340 PyObject *socket;
341 socklen_t addr_len;
342
343 struct pysocket_event event;
344 struct pysocket_op *recvop;
345 struct pysocket_op *sendop;
346
347 union {
348 struct sockaddr_in ipv4;
349 struct sockaddr_un sun;
350 } addr;
351 };
352
353 static PyObject *pysocket_send(struct pysocket *, PyObject *);
354 static PyObject *pysocket_recv(struct pysocket *, PyObject *);
355 static PyObject *pysocket_close(struct pysocket *, PyObject *);
356 static PyObject *pysocket_accept(struct pysocket *, PyObject *);
357 static PyObject *pysocket_sendto(struct pysocket *, PyObject *);
358 static PyObject *pysocket_connect(struct pysocket *, PyObject *);
359 static PyObject *pysocket_recvmsg(struct pysocket *, PyObject *);
360 static PyObject *pysocket_recvfrom(struct pysocket *, PyObject *);
361
362 static PyMethodDef pysocket_methods[] = {
363 METHOD("recv", pysocket_recv, METH_VARARGS),
364 METHOD("send", pysocket_send, METH_VARARGS),
365 METHOD("close", pysocket_close, METH_NOARGS),
366 METHOD("accept", pysocket_accept, METH_NOARGS),
367 METHOD("sendto", pysocket_sendto, METH_VARARGS),
368 METHOD("connect", pysocket_connect, METH_VARARGS),
369 METHOD("recvmsg", pysocket_recvmsg, METH_VARARGS),
370 METHOD("recvfrom", pysocket_recvfrom, METH_VARARGS),
371 METHOD(NULL, NULL, -1),
372 };
373
374 static void pysocket_dealloc(struct pysocket *);
375
376 static PyTypeObject pysocket_type = {
377 PyVarObject_HEAD_INIT(NULL, 0)
378 .tp_name = "kore.socket",
379 .tp_doc = "kore socket implementation",
380 .tp_methods = pysocket_methods,
381 .tp_basicsize = sizeof(struct pysocket),
382 .tp_dealloc = (destructor)pysocket_dealloc,
383 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
384 };
385
386 #define PYSOCKET_TYPE_ACCEPT 1
387 #define PYSOCKET_TYPE_CONNECT 2
388 #define PYSOCKET_TYPE_RECV 3
389 #define PYSOCKET_TYPE_SEND 4
390 #define PYSOCKET_TYPE_RECVFROM 5
391 #define PYSOCKET_TYPE_SENDTO 6
392 #define PYSOCKET_TYPE_RECVMSG 7
393
394 struct pysocket_op {
395 PyObject_HEAD
396 int eof;
397 int type;
398 void *self;
399 struct python_coro *coro;
400 int state;
401 size_t length;
402 struct kore_buf buffer;
403 struct pysocket *socket;
404 struct kore_timer *timer;
405
406 union {
407 struct sockaddr_in ipv4;
408 struct sockaddr_un sun;
409 } sendaddr;
410 };
411
412 static void pysocket_op_dealloc(struct pysocket_op *);
413
414 static PyObject *pysocket_op_await(PyObject *);
415 static PyObject *pysocket_op_iternext(struct pysocket_op *);
416
417 static PyAsyncMethods pysocket_op_async = {
418 (unaryfunc)pysocket_op_await,
419 NULL,
420 NULL
421 };
422
423 static PyTypeObject pysocket_op_type = {
424 PyVarObject_HEAD_INIT(NULL, 0)
425 .tp_name = "kore.socketop",
426 .tp_doc = "socket operation",
427 .tp_as_async = &pysocket_op_async,
428 .tp_iternext = (iternextfunc)pysocket_op_iternext,
429 .tp_basicsize = sizeof(struct pysocket_op),
430 .tp_dealloc = (destructor)pysocket_op_dealloc,
431 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
432 };
433
434 struct pyqueue_waiting {
435 struct python_coro *coro;
436 struct pyqueue_op *op;
437 TAILQ_ENTRY(pyqueue_waiting) list;
438 };
439
440 struct pyqueue_object {
441 PyObject *obj;
442 TAILQ_ENTRY(pyqueue_object) list;
443 };
444
445 struct pyqueue {
446 PyObject_HEAD
447 TAILQ_HEAD(, pyqueue_object) objects;
448 TAILQ_HEAD(, pyqueue_waiting) waiting;
449 };
450
451 static PyObject *pyqueue_pop(struct pyqueue *, PyObject *);
452 static PyObject *pyqueue_push(struct pyqueue *, PyObject *);
453 static PyObject *pyqueue_popnow(struct pyqueue *, PyObject *);
454
455 static PyMethodDef pyqueue_methods[] = {
456 METHOD("pop", pyqueue_pop, METH_NOARGS),
457 METHOD("push", pyqueue_push, METH_VARARGS),
458 METHOD("popnow", pyqueue_popnow, METH_NOARGS),
459 METHOD(NULL, NULL, -1)
460 };
461
462 static void pyqueue_dealloc(struct pyqueue *);
463
464 static PyTypeObject pyqueue_type = {
465 PyVarObject_HEAD_INIT(NULL, 0)
466 .tp_name = "kore.queue",
467 .tp_doc = "queue",
468 .tp_methods = pyqueue_methods,
469 .tp_basicsize = sizeof(struct pyqueue),
470 .tp_dealloc = (destructor)pyqueue_dealloc,
471 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
472 };
473
474 struct pyqueue_op {
475 PyObject_HEAD
476 struct pyqueue *queue;
477 struct pyqueue_waiting *waiting;
478 };
479
480 static void pyqueue_op_dealloc(struct pyqueue_op *);
481
482 static PyObject *pyqueue_op_await(PyObject *);
483 static PyObject *pyqueue_op_iternext(struct pyqueue_op *);
484
485 static PyAsyncMethods pyqueue_op_async = {
486 (unaryfunc)pyqueue_op_await,
487 NULL,
488 NULL
489 };
490
491 static PyTypeObject pyqueue_op_type = {
492 PyVarObject_HEAD_INIT(NULL, 0)
493 .tp_name = "kore.queueop",
494 .tp_doc = "queue waitable",
495 .tp_as_async = &pyqueue_op_async,
496 .tp_iternext = (iternextfunc)pyqueue_op_iternext,
497 .tp_basicsize = sizeof(struct pyqueue_op),
498 .tp_dealloc = (destructor)pyqueue_op_dealloc,
499 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
500 };
501
502 struct pylock {
503 PyObject_HEAD
504 struct python_coro *owner;
505 TAILQ_HEAD(, pylock_op) ops;
506 };
507
508 static PyObject *pylock_aexit(struct pylock *, PyObject *);
509 static PyObject *pylock_aenter(struct pylock *, PyObject *);
510 static PyObject *pylock_release(struct pylock *, PyObject *);
511 static PyObject *pylock_trylock(struct pylock *, PyObject *);
512
513 static PyMethodDef pylock_methods[] = {
514 METHOD("acquire", pylock_aenter, METH_NOARGS),
515 METHOD("release", pylock_release, METH_NOARGS),
516 METHOD("trylock", pylock_trylock, METH_NOARGS),
517 METHOD("__aexit__", pylock_aexit, METH_VARARGS),
518 METHOD("__aenter__", pylock_aenter, METH_NOARGS),
519 METHOD(NULL, NULL, -1)
520 };
521
522 static void pylock_dealloc(struct pylock *);
523
524 static PyTypeObject pylock_type = {
525 PyVarObject_HEAD_INIT(NULL, 0)
526 .tp_name = "kore.lock",
527 .tp_doc = "locking mechanism",
528 .tp_methods = pylock_methods,
529 .tp_basicsize = sizeof(struct pylock),
530 .tp_dealloc = (destructor)pylock_dealloc,
531 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
532 };
533
534 struct pylock_op {
535 PyObject_HEAD
536 int locking;
537 int active;
538 struct pylock *lock;
539 struct python_coro *coro;
540 TAILQ_ENTRY(pylock_op) list;
541 };
542
543 static void pylock_op_dealloc(struct pylock_op *);
544
545 static PyObject *pylock_op_await(PyObject *);
546 static PyObject *pylock_op_iternext(struct pylock_op *);
547
548 static PyAsyncMethods pylock_op_async = {
549 (unaryfunc)pylock_op_await,
550 NULL,
551 NULL
552 };
553
554 static PyTypeObject pylock_op_type = {
555 PyVarObject_HEAD_INIT(NULL, 0)
556 .tp_name = "kore.lockop",
557 .tp_doc = "lock awaitable",
558 .tp_as_async = &pylock_op_async,
559 .tp_iternext = (iternextfunc)pylock_op_iternext,
560 .tp_basicsize = sizeof(struct pylock_op),
561 .tp_dealloc = (destructor)pylock_op_dealloc,
562 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
563 };
564
565 #define PYTHON_PROC_MAX_ENV 32
566
567 struct pyproc {
568 PyObject_HEAD
569 pid_t pid;
570 pid_t apid;
571 int reaped;
572 int status;
573 struct pyproc_op *op;
574 struct pysocket *in;
575 struct pysocket *out;
576 struct python_coro *coro;
577 struct kore_timer *timer;
578 TAILQ_ENTRY(pyproc) list;
579 };
580
581 static void pyproc_dealloc(struct pyproc *);
582
583 static PyObject *pyproc_kill(struct pyproc *, PyObject *);
584 static PyObject *pyproc_reap(struct pyproc *, PyObject *);
585 static PyObject *pyproc_recv(struct pyproc *, PyObject *);
586 static PyObject *pyproc_send(struct pyproc *, PyObject *);
587 static PyObject *pyproc_close_stdin(struct pyproc *, PyObject *);
588
589 static PyMethodDef pyproc_methods[] = {
590 METHOD("kill", pyproc_kill, METH_NOARGS),
591 METHOD("reap", pyproc_reap, METH_NOARGS),
592 METHOD("recv", pyproc_recv, METH_VARARGS),
593 METHOD("send", pyproc_send, METH_VARARGS),
594 METHOD("close_stdin", pyproc_close_stdin, METH_NOARGS),
595 METHOD(NULL, NULL, -1),
596 };
597
598 static PyObject *pyproc_get_pid(struct pyproc *, void *);
599
600 static PyGetSetDef pyproc_getset[] = {
601 GETTER("pid", pyproc_get_pid),
602 GETTER(NULL, NULL),
603 };
604
605 static PyTypeObject pyproc_type = {
606 PyVarObject_HEAD_INIT(NULL, 0)
607 .tp_name = "kore.proc",
608 .tp_doc = "async process",
609 .tp_getset = pyproc_getset,
610 .tp_methods = pyproc_methods,
611 .tp_basicsize = sizeof(struct pyproc),
612 .tp_dealloc = (destructor)pyproc_dealloc,
613 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
614 };
615
616 struct pyproc_op {
617 PyObject_HEAD
618 struct pyproc *proc;
619 struct python_coro *coro;
620 };
621
622 static void pyproc_op_dealloc(struct pyproc_op *);
623
624 static PyObject *pyproc_op_await(PyObject *);
625 static PyObject *pyproc_op_iternext(struct pyproc_op *);
626
627 static PyAsyncMethods pyproc_op_async = {
628 (unaryfunc)pyproc_op_await,
629 NULL,
630 NULL
631 };
632
633 static PyTypeObject pyproc_op_type = {
634 PyVarObject_HEAD_INIT(NULL, 0)
635 .tp_name = "kore.proc_op",
636 .tp_doc = "proc reaper awaitable",
637 .tp_as_async = &pyproc_op_async,
638 .tp_iternext = (iternextfunc)pyproc_op_iternext,
639 .tp_basicsize = sizeof(struct pyproc_op),
640 .tp_dealloc = (destructor)pyproc_op_dealloc,
641 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
642 };
643
644 struct pygather_coro {
645 struct python_coro *coro;
646 PyObject *result;
647 TAILQ_ENTRY(pygather_coro) list;
648 };
649
650 struct pygather_result {
651 PyObject *obj;
652 TAILQ_ENTRY(pygather_result) list;
653 };
654
655 struct pygather_op {
656 PyObject_HEAD
657 int count;
658 int running;
659 int concurrency;
660 struct python_coro *coro;
661 TAILQ_HEAD(, pygather_result) results;
662 TAILQ_HEAD(, pygather_coro) coroutines;
663 };
664
665 static void pygather_op_dealloc(struct pygather_op *);
666
667 static PyObject *pygather_op_await(PyObject *);
668 static PyObject *pygather_op_iternext(struct pygather_op *);
669
670 static PyAsyncMethods pygather_op_async = {
671 (unaryfunc)pygather_op_await,
672 NULL,
673 NULL
674 };
675
676 static PyTypeObject pygather_op_type = {
677 PyVarObject_HEAD_INIT(NULL, 0)
678 .tp_name = "kore.pygather_op",
679 .tp_doc = "coroutine gathering",
680 .tp_as_async = &pygather_op_async,
681 .tp_iternext = (iternextfunc)pygather_op_iternext,
682 .tp_basicsize = sizeof(struct pygather_op),
683 .tp_dealloc = (destructor)pygather_op_dealloc,
684 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
685 };
686
687 struct pyconnection {
688 PyObject_HEAD
689 struct connection *c;
690 };
691
692 static PyObject *pyconnection_disconnect(struct pyconnection *, PyObject *);
693 static PyObject *pyconnection_websocket_send(struct pyconnection *, PyObject *);
694
695 static PyMethodDef pyconnection_methods[] = {
696 METHOD("disconnect", pyconnection_disconnect, METH_NOARGS),
697 METHOD("websocket_send", pyconnection_websocket_send, METH_VARARGS),
698 METHOD(NULL, NULL, -1),
699 };
700
701 static PyObject *pyconnection_get_fd(struct pyconnection *, void *);
702 static PyObject *pyconnection_get_addr(struct pyconnection *, void *);
703
704 static PyObject *pyconnection_get_peer_x509(struct pyconnection *, void *);
705 static PyObject *pyconnection_get_peer_x509dict(struct pyconnection *, void *);
706
707 static PyGetSetDef pyconnection_getset[] = {
708 GETTER("fd", pyconnection_get_fd),
709 GETTER("addr", pyconnection_get_addr),
710 GETTER("x509", pyconnection_get_peer_x509),
711 GETTER("x509dict", pyconnection_get_peer_x509dict),
712 GETTER(NULL, NULL),
713 };
714
715 static void pyconnection_dealloc(struct pyconnection *);
716
717 static PyTypeObject pyconnection_type = {
718 PyVarObject_HEAD_INIT(NULL, 0)
719 .tp_name = "kore.connection",
720 .tp_doc = "struct connection",
721 .tp_getset = pyconnection_getset,
722 .tp_methods = pyconnection_methods,
723 .tp_basicsize = sizeof(struct pyconnection),
724 .tp_dealloc = (destructor)pyconnection_dealloc,
725 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
726 };
727
728 #define PYHTTP_STATE_INIT 0
729 #define PYHTTP_STATE_PREPROCESS 1
730 #define PYHTTP_STATE_RUN 2
731
732 struct pyhttp_request {
733 PyObject_HEAD
734 struct http_request *req;
735 PyObject *dict;
736 PyObject *data;
737 };
738
739 struct pyhttp_iterobj {
740 int remove;
741 PyObject *iterator;
742 struct connection *connection;
743 struct kore_buf buf;
744 };
745
746 struct pyhttp_file {
747 PyObject_HEAD
748 struct http_file *file;
749 };
750
751 static void pyhttp_dealloc(struct pyhttp_request *);
752 static void pyhttp_file_dealloc(struct pyhttp_file *);
753
754 static PyObject *pyhttp_cookie(struct pyhttp_request *, PyObject *);
755 static PyObject *pyhttp_headers(struct pyhttp_request *, PyObject *);
756 static PyObject *pyhttp_response(struct pyhttp_request *, PyObject *);
757 static PyObject *pyhttp_argument(struct pyhttp_request *, PyObject *);
758 static PyObject *pyhttp_body_read(struct pyhttp_request *, PyObject *);
759 static PyObject *pyhttp_file_lookup(struct pyhttp_request *, PyObject *);
760 static PyObject *pyhttp_populate_get(struct pyhttp_request *, PyObject *);
761 static PyObject *pyhttp_populate_post(struct pyhttp_request *, PyObject *);
762 static PyObject *pyhttp_populate_multi(struct pyhttp_request *, PyObject *);
763 static PyObject *pyhttp_populate_cookies(struct pyhttp_request *, PyObject *);
764 static PyObject *pyhttp_request_header(struct pyhttp_request *, PyObject *);
765 static PyObject *pyhttp_response_header(struct pyhttp_request *, PyObject *);
766 static PyObject *pyhttp_websocket_handshake(struct pyhttp_request *,
767 PyObject *);
768
769 static PyMethodDef pyhttp_request_methods[] = {
770 METHOD("cookie", pyhttp_cookie, METH_VARARGS),
771 METHOD("headers", pyhttp_headers, METH_NOARGS),
772 METHOD("response", pyhttp_response, METH_VARARGS),
773 METHOD("argument", pyhttp_argument, METH_VARARGS),
774 METHOD("body_read", pyhttp_body_read, METH_VARARGS),
775 METHOD("file_lookup", pyhttp_file_lookup, METH_VARARGS),
776 METHOD("populate_get", pyhttp_populate_get, METH_NOARGS),
777 METHOD("populate_post", pyhttp_populate_post, METH_NOARGS),
778 METHOD("populate_multi", pyhttp_populate_multi, METH_NOARGS),
779 METHOD("populate_cookies", pyhttp_populate_cookies, METH_NOARGS),
780 METHOD("request_header", pyhttp_request_header, METH_VARARGS),
781 METHOD("response_header", pyhttp_response_header, METH_VARARGS),
782 METHOD("websocket_handshake", pyhttp_websocket_handshake, METH_VARARGS),
783 METHOD(NULL, NULL, -1)
784 };
785
786 static PyObject *pyhttp_get_host(struct pyhttp_request *, void *);
787 static PyObject *pyhttp_get_path(struct pyhttp_request *, void *);
788 static PyObject *pyhttp_get_body(struct pyhttp_request *, void *);
789 static PyObject *pyhttp_get_agent(struct pyhttp_request *, void *);
790 static PyObject *pyhttp_get_method(struct pyhttp_request *, void *);
791 static PyObject *pyhttp_get_protocol(struct pyhttp_request *, void *);
792 static PyObject *pyhttp_get_body_path(struct pyhttp_request *, void *);
793 static PyObject *pyhttp_get_connection(struct pyhttp_request *, void *);
794 static PyObject *pyhttp_get_body_digest(struct pyhttp_request *, void *);
795
796 static PyGetSetDef pyhttp_request_getset[] = {
797 GETTER("host", pyhttp_get_host),
798 GETTER("path", pyhttp_get_path),
799 GETTER("body", pyhttp_get_body),
800 GETTER("agent", pyhttp_get_agent),
801 GETTER("method", pyhttp_get_method),
802 GETTER("protocol", pyhttp_get_protocol),
803 GETTER("body_path", pyhttp_get_body_path),
804 GETTER("body_digest", pyhttp_get_body_digest),
805 GETTER("connection", pyhttp_get_connection),
806 GETTER(NULL, NULL)
807 };
808
809 static PyTypeObject pyhttp_request_type = {
810 PyVarObject_HEAD_INIT(NULL, 0)
811 .tp_name = "kore.http_request",
812 .tp_doc = "struct http_request",
813 .tp_setattro = PyObject_GenericSetAttr,
814 .tp_getattro = PyObject_GenericGetAttr,
815 .tp_getset = pyhttp_request_getset,
816 .tp_methods = pyhttp_request_methods,
817 .tp_dealloc = (destructor)pyhttp_dealloc,
818 .tp_basicsize = sizeof(struct pyhttp_request),
819 .tp_dictoffset = offsetof(struct pyhttp_request, dict),
820 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
821 };
822
823 static PyObject *pyhttp_file_read(struct pyhttp_file *, PyObject *);
824
825 static PyMethodDef pyhttp_file_methods[] = {
826 METHOD("read", pyhttp_file_read, METH_VARARGS),
827 METHOD(NULL, NULL, -1)
828 };
829
830 static PyObject *pyhttp_file_get_name(struct pyhttp_file *, void *);
831 static PyObject *pyhttp_file_get_filename(struct pyhttp_file *, void *);
832
833 static PyGetSetDef pyhttp_file_getset[] = {
834 GETTER("name", pyhttp_file_get_name),
835 GETTER("filename", pyhttp_file_get_filename),
836 GETTER(NULL, NULL)
837 };
838
839 static PyTypeObject pyhttp_file_type = {
840 PyVarObject_HEAD_INIT(NULL, 0)
841 .tp_name = "kore.http_file",
842 .tp_doc = "struct http_file",
843 .tp_getset = pyhttp_file_getset,
844 .tp_methods = pyhttp_file_methods,
845 .tp_dealloc = (destructor)pyhttp_file_dealloc,
846 .tp_basicsize = sizeof(struct pyhttp_file),
847 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
848 };
849
850 #if defined(KORE_USE_CURL)
851
852 #define CURL_CLIENT_OP_RUN 1
853 #define CURL_CLIENT_OP_RESULT 2
854
855 struct pycurl_slist {
856 struct curl_slist *slist;
857 LIST_ENTRY(pycurl_slist) list;
858 };
859
860 struct pycurl_data {
861 struct kore_curl curl;
862 LIST_HEAD(, pycurl_slist) slists;
863 };
864
865 struct pycurl_handle {
866 PyObject_HEAD
867 char *url;
868 struct kore_buf *body;
869 struct pycurl_data data;
870 };
871
872 struct pycurl_handle_op {
873 PyObject_HEAD
874 int state;
875 struct python_coro *coro;
876 struct pycurl_handle *handle;
877 };
878
879 static PyObject *pycurl_handle_op_await(PyObject *);
880 static PyObject *pycurl_handle_op_iternext(struct pycurl_handle_op *);
881
882 static void pycurl_handle_dealloc(struct pycurl_handle *);
883 static void pycurl_handle_op_dealloc(struct pycurl_handle_op *);
884
885 static PyObject *pycurl_handle_run(struct pycurl_handle *, PyObject *);
886 static PyObject *pycurl_handle_setopt(struct pycurl_handle *, PyObject *);
887 static PyObject *pycurl_handle_setbody(struct pycurl_handle *, PyObject *);
888
889 static PyObject *pycurl_handle_setopt_string(struct pycurl_data *,
890 int, PyObject *);
891 static PyObject *pycurl_handle_setopt_long(struct pycurl_data *,
892 int, PyObject *);
893 static PyObject *pycurl_handle_setopt_slist(struct pycurl_data *,
894 int, PyObject *);
895
896 static PyMethodDef pycurl_handle_methods[] = {
897 METHOD("run", pycurl_handle_run, METH_VARARGS),
898 METHOD("setopt", pycurl_handle_setopt, METH_VARARGS),
899 METHOD("setbody", pycurl_handle_setbody, METH_VARARGS),
900 METHOD(NULL, NULL, -1)
901 };
902
903 static PyTypeObject pycurl_handle_type = {
904 PyVarObject_HEAD_INIT(NULL, 0)
905 .tp_name = "kore.curl",
906 .tp_doc = "An asynchronous CURL handle",
907 .tp_methods = pycurl_handle_methods,
908 .tp_basicsize = sizeof(struct pycurl_handle),
909 .tp_dealloc = (destructor)pycurl_handle_dealloc,
910 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
911 };
912
913 static PyAsyncMethods pycurl_handle_op_async = {
914 (unaryfunc)pycurl_handle_op_await,
915 NULL,
916 NULL
917 };
918
919 static PyTypeObject pycurl_handle_op_type = {
920 PyVarObject_HEAD_INIT(NULL, 0)
921 .tp_name = "kore.curlop",
922 .tp_doc = "Asynchronous CURL operation",
923 .tp_as_async = &pycurl_handle_op_async,
924 .tp_iternext = (iternextfunc)pycurl_handle_op_iternext,
925 .tp_basicsize = sizeof(struct pycurl_handle_op),
926 .tp_dealloc = (destructor)pycurl_handle_op_dealloc,
927 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
928 };
929
930 struct pyhttp_client {
931 PyObject_HEAD
932 char *url;
933 char *unix;
934 char *tlskey;
935 char *tlscert;
936 char *cabundle;
937 PyObject *curlopt;
938 int tlsverify;
939 };
940
941 struct pyhttp_client_op {
942 PyObject_HEAD
943 int state;
944 int headers;
945 struct python_coro *coro;
946 struct pyhttp_client *client;
947 struct pycurl_data data;
948 };
949
950
951 static PyObject *pyhttp_client_op_await(PyObject *);
952 static PyObject *pyhttp_client_op_iternext(struct pyhttp_client_op *);
953
954 static void pyhttp_client_dealloc(struct pyhttp_client *);
955 static void pyhttp_client_op_dealloc(struct pyhttp_client_op *);
956
957 static PyObject *pyhttp_client_get(struct pyhttp_client *,
958 PyObject *, PyObject *);
959 static PyObject *pyhttp_client_put(struct pyhttp_client *,
960 PyObject *, PyObject *);
961 static PyObject *pyhttp_client_post(struct pyhttp_client *,
962 PyObject *, PyObject *);
963 static PyObject *pyhttp_client_head(struct pyhttp_client *,
964 PyObject *, PyObject *);
965 static PyObject *pyhttp_client_patch(struct pyhttp_client *,
966 PyObject *, PyObject *);
967 static PyObject *pyhttp_client_delete(struct pyhttp_client *,
968 PyObject *, PyObject *);
969 static PyObject *pyhttp_client_options(struct pyhttp_client *,
970 PyObject *, PyObject *);
971
972 static PyMethodDef pyhttp_client_methods[] = {
973 METHOD("get", pyhttp_client_get, METH_VARARGS | METH_KEYWORDS),
974 METHOD("put", pyhttp_client_put, METH_VARARGS | METH_KEYWORDS),
975 METHOD("post", pyhttp_client_post, METH_VARARGS | METH_KEYWORDS),
976 METHOD("head", pyhttp_client_head, METH_VARARGS | METH_KEYWORDS),
977 METHOD("patch", pyhttp_client_patch, METH_VARARGS | METH_KEYWORDS),
978 METHOD("delete", pyhttp_client_delete, METH_VARARGS | METH_KEYWORDS),
979 METHOD("options", pyhttp_client_options, METH_VARARGS | METH_KEYWORDS),
980 METHOD(NULL, NULL, -1)
981 };
982
983 static PyTypeObject pyhttp_client_type = {
984 PyVarObject_HEAD_INIT(NULL, 0)
985 .tp_name = "kore.httpclient",
986 .tp_doc = "An asynchronous HTTP client",
987 .tp_methods = pyhttp_client_methods,
988 .tp_basicsize = sizeof(struct pyhttp_client),
989 .tp_dealloc = (destructor)pyhttp_client_dealloc,
990 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
991 };
992
993 static PyAsyncMethods pyhttp_client_op_async = {
994 (unaryfunc)pyhttp_client_op_await,
995 NULL,
996 NULL
997 };
998
999 static PyTypeObject pyhttp_client_op_type = {
1000 PyVarObject_HEAD_INIT(NULL, 0)
1001 .tp_name = "kore.httpclientop",
1002 .tp_doc = "Asynchronous HTTP client operation",
1003 .tp_as_async = &pyhttp_client_op_async,
1004 .tp_iternext = (iternextfunc)pyhttp_client_op_iternext,
1005 .tp_basicsize = sizeof(struct pyhttp_client_op),
1006 .tp_dealloc = (destructor)pyhttp_client_op_dealloc,
1007 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1008 };
1009 #endif
1010
1011 #if defined(KORE_USE_PGSQL)
1012
1013 #define PYKORE_PGSQL_PREINIT 1
1014 #define PYKORE_PGSQL_INITIALIZE 2
1015 #define PYKORE_PGSQL_QUERY 3
1016 #define PYKORE_PGSQL_WAIT 4
1017
1018 struct pykore_pgsql {
1019 PyObject_HEAD
1020 struct kore_pgsql sql;
1021 int state;
1022 int binary;
1023
1024 char *db;
1025 struct python_coro *coro;
1026 char *query;
1027 PyObject *result;
1028
1029 struct {
1030 int count;
1031 const char **values;
1032 int *lengths;
1033 int *formats;
1034 PyObject **objs;
1035 } param;
1036 };
1037
1038 static void pykore_pgsql_dealloc(struct pykore_pgsql *);
1039
1040 static PyObject *pykore_pgsql_await(PyObject *);
1041 static PyObject *pykore_pgsql_iternext(struct pykore_pgsql *);
1042
1043 static PyAsyncMethods pykore_pgsql_async = {
1044 (unaryfunc)pykore_pgsql_await,
1045 NULL,
1046 NULL
1047 };
1048
1049 static PyTypeObject pykore_pgsql_type = {
1050 PyVarObject_HEAD_INIT(NULL, 0)
1051 .tp_name = "kore.pgsql",
1052 .tp_doc = "struct kore_pgsql",
1053 .tp_as_async = &pykore_pgsql_async,
1054 .tp_iternext = (iternextfunc)pykore_pgsql_iternext,
1055 .tp_basicsize = sizeof(struct pykore_pgsql),
1056 .tp_dealloc = (destructor)pykore_pgsql_dealloc,
1057 .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
1058 };
1059 #endif