python.c (155566B)
1 /*
2 * Copyright (c) 2016 Stanislav Yudin <stan@endlessinsomnia.com>
3 * Copyright (c) 2017-2022 Joris Vink <joris@coders.se>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <sys/param.h>
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <sys/socket.h>
22 #include <sys/wait.h>
23 #include <sys/un.h>
24
25 #include <ctype.h>
26 #include <libgen.h>
27 #include <inttypes.h>
28 #include <signal.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <stdarg.h>
32 #include <stddef.h>
33
34 #include "kore.h"
35 #include "http.h"
36
37 #if defined(KORE_USE_PGSQL)
38 #include "pgsql.h"
39 #endif
40
41 #if defined(KORE_USE_CURL)
42 #include "curl.h"
43 #endif
44
45 #if defined(KORE_USE_ACME)
46 #include "acme.h"
47 #endif
48
49 #include "python_api.h"
50 #include "python_methods.h"
51
52 #if defined(KORE_USE_CURL)
53 #include "python_curlopt.h"
54 #endif
55
56 #include <frameobject.h>
57
58 #if PY_VERSION_HEX >= 0x030b0000
59 #include <internal/pycore_frame.h>
60 #endif
61
62 #if PY_VERSION_HEX < 0x030A0000
63 typedef enum {
64 PYGEN_RETURN = 0,
65 PYGEN_ERROR = -1,
66 PYGEN_NEXT = 1,
67 } PySendResult;
68 #endif
69
70 struct reqcall {
71 PyObject *f;
72 TAILQ_ENTRY(reqcall) list;
73 };
74
75 union deconst {
76 char *p;
77 const char *cp;
78 };
79
80 TAILQ_HEAD(reqcall_list, reqcall);
81
82 PyMODINIT_FUNC python_module_init(void);
83
84 static PyObject *python_import(const char *);
85 static int python_resolve_frame_line(void *);
86 static PyObject *pyconnection_alloc(struct connection *);
87 static PyObject *python_callable(PyObject *, const char *);
88 static void python_split_arguments(char *, char **, size_t);
89 static void python_kore_recvobj(struct kore_msg *, const void *);
90
91 static PyObject *python_cmsg_to_list(struct msghdr *);
92 static const char *python_string_from_dict(PyObject *, const char *);
93 static int python_bool_from_dict(PyObject *, const char *, int *);
94 static int python_long_from_dict(PyObject *, const char *, long *);
95
96 static int pyhttp_response_sent(struct netbuf *);
97 static PyObject *pyhttp_file_alloc(struct http_file *);
98 static PyObject *pyhttp_request_alloc(const struct http_request *);
99
100 static struct python_coro *python_coro_create(PyObject *,
101 struct http_request *);
102 static struct kore_domain *python_route_domain_resolve(struct pyroute *);
103
104 static int python_route_install(struct pyroute *);
105 static int python_route_params(PyObject *, struct kore_route *,
106 const char *, int, int);
107 static int python_route_methods(PyObject *, PyObject *,
108 struct kore_route *);
109 static int python_route_auth(PyObject *, struct kore_route *);
110 static int python_route_hooks(PyObject *, struct kore_route *);
111 static int python_route_hook_set(PyObject *, const char *,
112 struct kore_runtime_call **);
113
114 static int python_coro_run(struct python_coro *);
115 static void python_coro_wakeup(struct python_coro *);
116 static void python_coro_suspend(struct python_coro *);
117 static void python_coro_trace(const char *, struct python_coro *);
118
119 static void pysocket_evt_handle(void *, int);
120 static void pysocket_op_timeout(void *, u_int64_t);
121 static PyObject *pysocket_op_create(struct pysocket *,
122 int, const void *, size_t);
123
124 static struct pysocket *pysocket_alloc(void);
125 static PyObject *pysocket_async_recv(struct pysocket_op *);
126 static PyObject *pysocket_async_send(struct pysocket_op *);
127 static PyObject *pysocket_async_accept(struct pysocket_op *);
128 static PyObject *pysocket_async_connect(struct pysocket_op *);
129
130 static void pylock_do_release(struct pylock *);
131
132 static void pytimer_run(void *, u_int64_t);
133 static void pyproc_timeout(void *, u_int64_t);
134 static void pysuspend_wakeup(void *, u_int64_t);
135
136 static void pygather_reap_coro(struct pygather_op *,
137 struct python_coro *);
138
139 static int pyhttp_preprocess(struct http_request *);
140 static int pyhttp_iterobj_chunk_sent(struct netbuf *);
141 static int pyhttp_iterobj_next(struct pyhttp_iterobj *);
142 static void pyhttp_iterobj_disconnect(struct connection *);
143
144 static int pyconnection_x509_cb(void *, int, int, const char *,
145 const void *, size_t, int);
146
147 #if defined(KORE_USE_PGSQL)
148 static int pykore_pgsql_result(struct pykore_pgsql *);
149 static void pykore_pgsql_callback(struct kore_pgsql *, void *);
150 static int pykore_pgsql_params(struct pykore_pgsql *, PyObject *);
151 static int pykore_pgsql_params(struct pykore_pgsql *, PyObject *);
152 #endif
153
154 #if defined(KORE_USE_CURL)
155 static void python_curl_http_callback(struct kore_curl *, void *);
156 static void python_curl_handle_callback(struct kore_curl *, void *);
157 static PyObject *pyhttp_client_request(struct pyhttp_client *, int,
158 PyObject *);
159 static PyObject *python_curlopt_set(struct pycurl_data *,
160 long, PyObject *);
161 static int python_curlopt_from_dict(struct pycurl_data *,
162 PyObject *);
163 #endif
164
165 static void python_append_path(const char *);
166 static void python_push_integer(PyObject *, const char *, long);
167 static void python_push_type(const char *, PyObject *, PyTypeObject *);
168
169 static int python_validator_check(PyObject *);
170 static int python_runtime_resolve(const char *, const struct stat *);
171 static int python_runtime_http_request(void *, struct http_request *);
172 static void python_runtime_http_request_free(void *, struct http_request *);
173 static void python_runtime_http_body_chunk(void *, struct http_request *,
174 const void *, size_t);
175 static int python_runtime_validator(void *, struct http_request *,
176 const void *);
177 static void python_runtime_wsmessage(void *, struct connection *,
178 u_int8_t, const void *, size_t);
179 static void python_runtime_execute(void *);
180 static int python_runtime_onload(void *, int);
181 static void python_runtime_signal(void *, int);
182 static void python_runtime_configure(void *, int, char **);
183 static void python_runtime_connect(void *, struct connection *);
184
185 static void python_module_load(struct kore_module *);
186 static void python_module_free(struct kore_module *);
187 static void python_module_reload(struct kore_module *);
188 static void *python_module_getsym(struct kore_module *, const char *);
189
190 static void *python_malloc(void *, size_t);
191 static void *python_calloc(void *, size_t, size_t);
192 static void *python_realloc(void *, void *, size_t);
193 static void python_free(void *, void *);
194
195 struct kore_module_functions kore_python_module = {
196 .free = python_module_free,
197 .load = python_module_load,
198 .getsym = python_module_getsym,
199 .reload = python_module_reload
200 };
201
202 struct kore_runtime kore_python_runtime = {
203 KORE_RUNTIME_PYTHON,
204 .resolve = python_runtime_resolve,
205 .http_request = python_runtime_http_request,
206 .http_body_chunk = python_runtime_http_body_chunk,
207 .http_request_free = python_runtime_http_request_free,
208 .validator = python_runtime_validator,
209 .wsconnect = python_runtime_connect,
210 .wsmessage = python_runtime_wsmessage,
211 .wsdisconnect = python_runtime_connect,
212 .onload = python_runtime_onload,
213 .signal = python_runtime_signal,
214 .connect = python_runtime_connect,
215 .execute = python_runtime_execute,
216 .configure = python_runtime_configure,
217 };
218
219 static struct {
220 const char *symbol;
221 int value;
222 } python_integers[] = {
223 { "LOG_ERR", LOG_ERR },
224 { "LOG_INFO", LOG_INFO },
225 { "LOG_NOTICE", LOG_NOTICE },
226 { "RESULT_OK", KORE_RESULT_OK },
227 { "RESULT_RETRY", KORE_RESULT_RETRY },
228 { "RESULT_ERROR", KORE_RESULT_ERROR },
229 { "MODULE_LOAD", KORE_MODULE_LOAD },
230 { "MODULE_UNLOAD", KORE_MODULE_UNLOAD },
231 { "TIMER_ONESHOT", KORE_TIMER_ONESHOT },
232 { "CONN_PROTO_HTTP", CONN_PROTO_HTTP },
233 { "CONN_PROTO_UNKNOWN", CONN_PROTO_UNKNOWN },
234 { "CONN_PROTO_WEBSOCKET", CONN_PROTO_WEBSOCKET },
235 { "CONN_STATE_ESTABLISHED", CONN_STATE_ESTABLISHED },
236 { "HTTP_METHOD_GET", HTTP_METHOD_GET },
237 { "HTTP_METHOD_PUT", HTTP_METHOD_PUT },
238 { "HTTP_METHOD_HEAD", HTTP_METHOD_HEAD },
239 { "HTTP_METHOD_POST", HTTP_METHOD_POST },
240 { "HTTP_METHOD_DELETE", HTTP_METHOD_DELETE },
241 { "HTTP_METHOD_OPTIONS", HTTP_METHOD_OPTIONS },
242 { "HTTP_METHOD_PATCH", HTTP_METHOD_PATCH },
243 { "WEBSOCKET_OP_TEXT", WEBSOCKET_OP_TEXT },
244 { "WEBSOCKET_OP_BINARY", WEBSOCKET_OP_BINARY },
245 { "WEBSOCKET_BROADCAST_LOCAL", WEBSOCKET_BROADCAST_LOCAL },
246 { "WEBSOCKET_BROADCAST_GLOBAL", WEBSOCKET_BROADCAST_GLOBAL },
247 { NULL, -1 }
248 };
249
250 static PyMemAllocatorEx allocator = {
251 .ctx = NULL,
252 .malloc = python_malloc,
253 .calloc = python_calloc,
254 .realloc = python_realloc,
255 .free = python_free
256 };
257
258 #if defined(__linux__)
259 #include "seccomp.h"
260
261 static struct sock_filter filter_python[] = {
262 /* Required for kore.proc */
263 #if defined(SYS_dup2)
264 KORE_SYSCALL_ALLOW(dup2),
265 #endif
266 #if defined(SYS_dup3)
267 KORE_SYSCALL_ALLOW(dup3),
268 #endif
269 #if defined(SYS_pipe)
270 KORE_SYSCALL_ALLOW(pipe),
271 #endif
272 #if defined(SYS_pipe2)
273 KORE_SYSCALL_ALLOW(pipe2),
274 #endif
275 KORE_SYSCALL_ALLOW(wait4),
276 KORE_SYSCALL_ALLOW(execve),
277
278 /* Socket related. */
279 KORE_SYSCALL_ALLOW(bind),
280 KORE_SYSCALL_ALLOW(listen),
281 KORE_SYSCALL_ALLOW(sendto),
282 KORE_SYSCALL_ALLOW(recvfrom),
283 KORE_SYSCALL_ALLOW(getsockname),
284 KORE_SYSCALL_ALLOW(getpeername),
285 KORE_SYSCALL_ALLOW_ARG(socket, 0, AF_INET),
286 KORE_SYSCALL_ALLOW_ARG(socket, 0, AF_INET6),
287 KORE_SYSCALL_ALLOW_ARG(socket, 0, AF_UNIX),
288 };
289
290 #define PYSECCOMP_ACTION_ALLOW 1
291 #define PYSECCOMP_ACTION_DENY 2
292
293 #define PYSECCOMP_SYSCALL_FILTER 1
294 #define PYSECCOMP_SYSCALL_ARG 2
295 #define PYSECCOMP_SYSCALL_MASK 3
296 #define PYSECCOMP_SYSCALL_FLAG 4
297
298 static int pyseccomp_filter_install(struct pyseccomp *,
299 const char *, int, int, int, int);
300 static PyObject *pyseccomp_common_action(struct pyseccomp *, PyObject *,
301 PyObject *, int, int);
302
303 static struct pyseccomp *py_seccomp = NULL;
304 #endif
305
306 static TAILQ_HEAD(, pyproc) procs;
307 static TAILQ_HEAD(, pyroute) routes;
308 static struct reqcall_list prereq;
309
310 static struct kore_pool coro_pool;
311 static struct kore_pool iterobj_pool;
312 static struct kore_pool queue_wait_pool;
313 static struct kore_pool gather_coro_pool;
314 static struct kore_pool queue_object_pool;
315 static struct kore_pool gather_result_pool;
316
317 static u_int64_t coro_id;
318 static int coro_count;
319 static int coro_tracing;
320 static struct coro_list coro_runnable;
321 static struct coro_list coro_suspended;
322
323 extern const char *__progname;
324
325 static PyObject *pickle = NULL;
326 static PyObject *kore_app = NULL;
327 static PyObject *pickle_dumps = NULL;
328 static PyObject *pickle_loads = NULL;
329 static PyObject *python_tracer = NULL;
330
331 /* XXX */
332 static struct python_coro *coro_running = NULL;
333
334 #if !defined(KORE_SINGLE_BINARY)
335 static const char *kore_pymodule = NULL;
336 #endif
337
338 void
339 kore_python_init(void)
340 {
341 struct kore_runtime_call *rcall;
342
343 coro_id = 0;
344 coro_count = 0;
345 coro_tracing = 0;
346
347 TAILQ_INIT(&prereq);
348
349 TAILQ_INIT(&procs);
350 TAILQ_INIT(&routes);
351 TAILQ_INIT(&coro_runnable);
352 TAILQ_INIT(&coro_suspended);
353
354 kore_pool_init(&coro_pool, "coropool", sizeof(struct python_coro), 100);
355
356 kore_pool_init(&iterobj_pool, "iterobj_pool",
357 sizeof(struct pyhttp_iterobj), 100);
358 kore_pool_init(&queue_wait_pool, "queue_wait_pool",
359 sizeof(struct pyqueue_waiting), 100);
360 kore_pool_init(&gather_coro_pool, "gather_coro_pool",
361 sizeof(struct pygather_coro), 100);
362 kore_pool_init(&queue_object_pool, "queue_object_pool",
363 sizeof(struct pyqueue_object), 100);
364 kore_pool_init(&gather_result_pool, "gather_result_pool",
365 sizeof(struct pygather_result), 100);
366
367 PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocator);
368 PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocator);
369 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocator);
370
371 #if defined(KORE_DEBUG)
372 PyMem_SetupDebugHooks();
373 #endif
374
375 kore_msg_register(KORE_PYTHON_SEND_OBJ, python_kore_recvobj);
376
377 if (PyImport_AppendInittab("kore", &python_module_init) == -1)
378 fatal("kore_python_init: failed to add new module");
379
380 rcall = kore_runtime_getcall("kore_python_preinit");
381 if (rcall != NULL) {
382 kore_runtime_execute(rcall);
383 kore_free(rcall);
384 }
385
386 Py_InitializeEx(0);
387
388 if ((pickle = PyImport_ImportModule("pickle")) == NULL)
389 fatal("failed to import pickle module");
390
391 if ((pickle_dumps = PyObject_GetAttrString(pickle, "dumps")) == NULL)
392 fatal("pickle module has no dumps method");
393
394 if ((pickle_loads = PyObject_GetAttrString(pickle, "loads")) == NULL)
395 fatal("pickle module has no loads method");
396
397 #if defined(__linux__)
398 kore_seccomp_filter("python", filter_python,
399 KORE_FILTER_LEN(filter_python));
400 #endif
401
402 #if !defined(KORE_SINGLE_BINARY)
403 if (kore_pymodule) {
404 if (!kore_configure_setting("deployment", "dev"))
405 fatal("failed to set initial deployment");
406 }
407 #endif
408 }
409
410 void
411 kore_python_cleanup(void)
412 {
413 if (Py_IsInitialized()) {
414 PyErr_Clear();
415 Py_Finalize();
416 }
417 }
418
419 void
420 kore_python_path(const char *path)
421 {
422 python_append_path(path);
423 }
424
425 void
426 kore_python_coro_run(void)
427 {
428 struct pygather_op *op;
429 struct python_coro *coro;
430
431 while ((coro = TAILQ_FIRST(&coro_runnable)) != NULL) {
432 if (coro->state != CORO_STATE_RUNNABLE)
433 fatal("non-runnable coro on coro_runnable");
434
435 if (python_coro_run(coro) == KORE_RESULT_OK) {
436 if (coro->gatherop != NULL) {
437 op = coro->gatherop;
438 if (op->coro->request != NULL)
439 http_request_wakeup(op->coro->request);
440 else
441 python_coro_wakeup(op->coro);
442 pygather_reap_coro(op, coro);
443 } else {
444 kore_python_coro_delete(coro);
445 }
446 }
447 }
448
449 /*
450 * Let Kore do HTTP processing so awoken coroutines run asap without
451 * having to wait for a tick from the event loop.
452 *
453 * Maybe it is more beneficial that we track if something related
454 * to HTTP requests was awoken and only run if true?
455 */
456 http_process();
457
458 #if defined(KORE_USE_CURL)
459 /*
460 * If a coroutine fired off a curl instance, immediately
461 * let it make progress.
462 */
463 kore_curl_do_timeout();
464 #endif
465 }
466
467 void
468 kore_python_coro_delete(void *obj)
469 {
470 struct python_coro *coro;
471
472 coro = obj;
473 coro_count--;
474
475 python_coro_trace(coro->killed ? "killed" : "deleted", coro);
476
477 coro_running = coro;
478
479 if (coro->lockop != NULL) {
480 coro->lockop->active = 0;
481 TAILQ_REMOVE(&coro->lockop->lock->ops, coro->lockop, list);
482 Py_DECREF((PyObject *)coro->lockop);
483 coro->lockop = NULL;
484 }
485
486 Py_DECREF(coro->obj);
487 coro_running = NULL;
488
489 if (coro->state == CORO_STATE_RUNNABLE)
490 TAILQ_REMOVE(&coro_runnable, coro, list);
491 else
492 TAILQ_REMOVE(&coro_suspended, coro, list);
493
494 kore_free(coro->name);
495 Py_XDECREF(coro->result);
496
497 kore_pool_put(&coro_pool, coro);
498 }
499
500 int
501 kore_python_coro_pending(void)
502 {
503 return (!TAILQ_EMPTY(&coro_runnable));
504 }
505
506 void
507 kore_python_routes_resolve(void)
508 {
509 struct pyroute *route;
510
511 while ((route = TAILQ_FIRST(&routes)) != NULL) {
512 TAILQ_REMOVE(&routes, route, list);
513 if (!python_route_install(route))
514 fatalx("failed to install route for %s", route->path);
515 Py_DECREF((PyObject *)route);
516 }
517 }
518
519 void
520 kore_python_log_error(const char *function)
521 {
522 const char *sval;
523 PyObject *ret, *repr, *type, *value, *traceback;
524
525 if (!PyErr_Occurred() || PyErr_ExceptionMatches(PyExc_StopIteration))
526 return;
527
528 PyErr_Fetch(&type, &value, &traceback);
529
530 if (type == NULL || value == NULL) {
531 kore_log(LOG_ERR, "unknown python exception in '%s'", function);
532 return;
533 }
534
535 if (value == NULL || !PyObject_IsInstance(value, type))
536 PyErr_NormalizeException(&type, &value, &traceback);
537
538 /*
539 * If we're in an active coroutine and it was tied to a gather
540 * operation we have to make sure we can use the Exception that
541 * was thrown as the result value so we can propagate it via the
542 * return list of kore.gather().
543 */
544 if (coro_running != NULL && coro_running->gatherop != NULL) {
545 PyErr_SetObject(PyExc_StopIteration, value);
546 } else if (python_tracer != NULL) {
547 /*
548 * Call the user-supplied tracer callback.
549 */
550 ret = PyObject_CallFunctionObjArgs(python_tracer,
551 type, value, traceback, NULL);
552 Py_XDECREF(ret);
553 } else {
554 if ((repr = PyObject_Repr(value)) == NULL)
555 sval = "unknown";
556 else
557 sval = PyUnicode_AsUTF8(repr);
558
559 kore_log(LOG_ERR,
560 "uncaught exception %s in '%s'", sval, function);
561
562 Py_XDECREF(repr);
563 }
564
565 Py_DECREF(type);
566 Py_DECREF(value);
567 Py_XDECREF(traceback);
568 }
569
570 void
571 kore_python_proc_reap(void)
572 {
573 struct pyproc *proc;
574 struct python_coro *coro;
575 pid_t child;
576 int status;
577
578 for (;;) {
579 if ((child = waitpid(-1, &status, WNOHANG)) == -1) {
580 if (errno == ECHILD)
581 return;
582 if (errno == EINTR)
583 continue;
584 kore_log(LOG_NOTICE, "waitpid: %s", errno_s);
585 return;
586 }
587
588 if (child == 0)
589 return;
590
591 proc = NULL;
592
593 TAILQ_FOREACH(proc, &procs, list) {
594 if (proc->pid == child)
595 break;
596 }
597
598 if (proc == NULL)
599 continue;
600
601 proc->pid = -1;
602 proc->reaped = 1;
603 proc->status = status;
604
605 if (proc->timer != NULL) {
606 kore_timer_remove(proc->timer);
607 proc->timer = NULL;
608 }
609
610 /*
611 * If someone is waiting on proc.reap() then wakeup that
612 * coroutine, otherwise wakeup the coroutine that created
613 * the process.
614 */
615 if (proc->op != NULL)
616 coro = proc->op->coro;
617 else
618 coro = proc->coro;
619
620 if (coro->request != NULL)
621 http_request_wakeup(coro->request);
622 else
623 python_coro_wakeup(coro);
624 }
625 }
626
627 #if defined(__linux__)
628 void
629 kore_python_seccomp_hook(const char *method)
630 {
631 struct kore_runtime *rt;
632 PyObject *func, *result;
633
634 if ((func = kore_module_getsym(method, &rt)) == NULL)
635 return;
636
637 if (rt->type != KORE_RUNTIME_PYTHON)
638 return;
639
640 py_seccomp = PyObject_New(struct pyseccomp, &pyseccomp_type);
641 if (py_seccomp == NULL)
642 fatal("failed to create seccomp object");
643
644 py_seccomp->elm = 0;
645 py_seccomp->filters = NULL;
646
647 result = PyObject_CallFunctionObjArgs(func,
648 (PyObject *)py_seccomp, NULL);
649 kore_python_log_error(method);
650
651 kore_seccomp_filter("koreapp", py_seccomp->filters, py_seccomp->elm);
652
653 Py_XDECREF(result);
654 }
655
656 void
657 kore_python_seccomp_cleanup(void)
658 {
659 Py_XDECREF(py_seccomp);
660 py_seccomp = NULL;
661 }
662
663 static void
664 pyseccomp_dealloc(struct pyseccomp *seccomp)
665 {
666 kore_free(seccomp->filters);
667
668 seccomp->elm = 0;
669 seccomp->filters = NULL;
670 }
671
672 static PyObject *
673 pyseccomp_bpf_stmt(struct pyseccomp *seccomp, PyObject *args)
674 {
675 u_int32_t k;
676 u_int16_t code;
677 size_t len, off;
678 struct sock_filter filter[1];
679
680 if (!PyArg_ParseTuple(args, "HI", &code, &k))
681 return (NULL);
682
683 filter[0].k = k;
684 filter[0].jt = 0;
685 filter[0].jf = 0;
686 filter[0].code = code;
687
688 len = sizeof(struct sock_filter);
689 off = seccomp->elm * sizeof(struct sock_filter);
690 seccomp->filters = kore_realloc(seccomp->filters, off + len);
691
692 memcpy(seccomp->filters + off, filter, len);
693 seccomp->elm += 1;
694
695 Py_RETURN_NONE;
696 }
697
698 static PyObject *
699 pyseccomp_allow(struct pyseccomp *seccomp, PyObject *args)
700 {
701 const char *syscall;
702
703 if (!PyArg_ParseTuple(args, "s", &syscall))
704 return (NULL);
705
706 if (!pyseccomp_filter_install(seccomp, syscall,
707 PYSECCOMP_SYSCALL_FILTER, 0, 0, SECCOMP_RET_ALLOW))
708 return (NULL);
709
710 Py_RETURN_NONE;
711 }
712
713 static PyObject *
714 pyseccomp_allow_arg(struct pyseccomp *seccomp, PyObject *args)
715 {
716 return (pyseccomp_common_action(seccomp, args, NULL,
717 PYSECCOMP_SYSCALL_ARG, PYSECCOMP_ACTION_ALLOW));
718 }
719
720 static PyObject *
721 pyseccomp_allow_flag(struct pyseccomp *seccomp, PyObject *args)
722 {
723 return (pyseccomp_common_action(seccomp, args, NULL,
724 PYSECCOMP_SYSCALL_FLAG, PYSECCOMP_ACTION_ALLOW));
725 }
726
727 static PyObject *
728 pyseccomp_allow_mask(struct pyseccomp *seccomp, PyObject *args)
729 {
730 return (pyseccomp_common_action(seccomp, args, NULL,
731 PYSECCOMP_SYSCALL_MASK, PYSECCOMP_ACTION_ALLOW));
732 }
733
734 static PyObject *
735 pyseccomp_deny(struct pyseccomp *seccomp, PyObject *args, PyObject *kwargs)
736 {
737 long err;
738 const char *syscall;
739
740 if (!PyArg_ParseTuple(args, "s", &syscall))
741 return (NULL);
742
743 err = EACCES;
744
745 if (kwargs != NULL)
746 python_long_from_dict(kwargs, "errno", &err);
747
748 if (!pyseccomp_filter_install(seccomp, syscall,
749 PYSECCOMP_SYSCALL_FILTER, 0, 0, SECCOMP_RET_ERRNO | (int)err))
750 return (NULL);
751
752 Py_RETURN_NONE;
753 }
754
755 static PyObject *
756 pyseccomp_deny_arg(struct pyseccomp *seccomp, PyObject *args, PyObject *kwargs)
757 {
758 return (pyseccomp_common_action(seccomp, args, kwargs,
759 PYSECCOMP_SYSCALL_ARG, PYSECCOMP_ACTION_DENY));
760 }
761
762 static PyObject *
763 pyseccomp_deny_flag(struct pyseccomp *seccomp, PyObject *args, PyObject *kwargs)
764 {
765 return (pyseccomp_common_action(seccomp, args, kwargs,
766 PYSECCOMP_SYSCALL_FLAG, PYSECCOMP_ACTION_DENY));
767 }
768
769 static PyObject *
770 pyseccomp_deny_mask(struct pyseccomp *seccomp, PyObject *args, PyObject *kwargs)
771 {
772 return (pyseccomp_common_action(seccomp, args, kwargs,
773 PYSECCOMP_SYSCALL_MASK, PYSECCOMP_ACTION_DENY));
774 }
775
776 static PyObject *
777 pyseccomp_common_action(struct pyseccomp *sc, PyObject *args,
778 PyObject *kwargs, int which, int action)
779 {
780 long err;
781 const char *syscall;
782 int arg, val;
783
784 if (!PyArg_ParseTuple(args, "sii", &syscall, &arg, &val))
785 return (NULL);
786
787 switch (action) {
788 case PYSECCOMP_ACTION_ALLOW:
789 action = SECCOMP_RET_ALLOW;
790 break;
791 case PYSECCOMP_ACTION_DENY:
792 err = EACCES;
793 if (kwargs != NULL)
794 python_long_from_dict(kwargs, "errno", &err);
795 action = SECCOMP_RET_ERRNO | (int)err;
796 break;
797 default:
798 fatal("%s: bad action %d", __func__, action);
799 }
800
801 if (!pyseccomp_filter_install(sc, syscall, which, arg, val, action))
802 return (NULL);
803
804 Py_RETURN_NONE;
805 }
806
807 static int
808 pyseccomp_filter_install(struct pyseccomp *seccomp, const char *syscall,
809 int which, int arg, int val, int action)
810 {
811 struct sock_filter *filter;
812 size_t elm, len, off;
813
814 switch (which) {
815 case PYSECCOMP_SYSCALL_FILTER:
816 filter = kore_seccomp_syscall_filter(syscall, action);
817 break;
818 case PYSECCOMP_SYSCALL_ARG:
819 filter = kore_seccomp_syscall_arg(syscall, action, arg, val);
820 break;
821 case PYSECCOMP_SYSCALL_MASK:
822 filter = kore_seccomp_syscall_mask(syscall, action, arg, val);
823 break;
824 case PYSECCOMP_SYSCALL_FLAG:
825 filter = kore_seccomp_syscall_flag(syscall, action, arg, val);
826 break;
827 default:
828 fatal("%s: invalid syscall instruction %d", __func__, which);
829 }
830
831 if (filter == NULL) {
832 PyErr_Format(PyExc_RuntimeError,
833 "system call '%s' does not exist", syscall);
834 return (KORE_RESULT_ERROR);
835 }
836
837 elm = 0;
838
839 /*
840 * Find the number of elements in the BPF program, by looking for
841 * the KORE_BPF_GUARD element.
842 */
843 for (;;) {
844 if (filter[elm].code == USHRT_MAX &&
845 filter[elm].jt == UCHAR_MAX &&
846 filter[elm].jf == UCHAR_MAX &&
847 filter[elm].k == UINT_MAX)
848 break;
849
850 elm++;
851 }
852
853 len = elm * sizeof(struct sock_filter);
854 off = seccomp->elm * sizeof(struct sock_filter);
855 seccomp->filters = kore_realloc(seccomp->filters, off + len);
856
857 memcpy(seccomp->filters + off, filter, len);
858 seccomp->elm += elm;
859
860 kore_free(filter);
861
862 return (KORE_RESULT_OK);
863 }
864 #endif
865
866 static int
867 python_long_from_dict(PyObject *dict, const char *key, long *result)
868 {
869 PyObject *obj;
870
871 if ((obj = PyDict_GetItemString(dict, key)) == NULL)
872 return (KORE_RESULT_ERROR);
873
874 if (!PyLong_CheckExact(obj))
875 return (KORE_RESULT_ERROR);
876
877 PyErr_Clear();
878 *result = PyLong_AsLong(obj);
879 if (*result == -1 && PyErr_Occurred()) {
880 PyErr_Clear();
881 return (KORE_RESULT_ERROR);
882 }
883
884 return (KORE_RESULT_OK);
885 }
886
887 static int
888 python_bool_from_dict(PyObject *dict, const char *key, int *result)
889 {
890 PyObject *obj;
891
892 if ((obj = PyDict_GetItemString(dict, key)) == NULL)
893 return (KORE_RESULT_ERROR);
894
895 if (!PyBool_Check(obj))
896 return (KORE_RESULT_ERROR);
897
898 *result = (obj == Py_True);
899
900 return (KORE_RESULT_OK);
901 }
902
903 static const char *
904 python_string_from_dict(PyObject *dict, const char *key)
905 {
906 PyObject *obj;
907
908 if ((obj = PyDict_GetItemString(dict, key)) == NULL)
909 return (NULL);
910
911 if (!PyUnicode_Check(obj))
912 return (NULL);
913
914 return (PyUnicode_AsUTF8AndSize(obj, NULL));
915 }
916
917 static PyObject *
918 python_cmsg_to_list(struct msghdr *msg)
919 {
920 struct cmsghdr *c;
921 size_t len;
922 Py_ssize_t idx;
923 PyObject *list, *tuple;
924
925 if ((list = PyList_New(0)) == NULL)
926 return (NULL);
927
928 idx = 0;
929
930 for (c = CMSG_FIRSTHDR(msg); c != NULL; c = CMSG_NXTHDR(msg, c)) {
931 len = c->cmsg_len - sizeof(*c);
932
933 tuple = Py_BuildValue("(Iiiy#)", len,
934 c->cmsg_level, c->cmsg_type, CMSG_DATA(c), len);
935
936 if (tuple == NULL) {
937 Py_DECREF(list);
938 return (NULL);
939 }
940
941 /* Steals a reference to tuple. */
942 if (PyList_Insert(list, idx++, tuple) == -1) {
943 Py_DECREF(tuple);
944 Py_DECREF(list);
945 return (NULL);
946 }
947 }
948
949 return (list);
950 }
951
952 static void *
953 python_malloc(void *ctx, size_t len)
954 {
955 return (kore_malloc(len));
956 }
957
958 static void *
959 python_calloc(void *ctx, size_t memb, size_t len)
960 {
961 return (kore_calloc(memb, len));
962 }
963
964 static void *
965 python_realloc(void *ctx, void *ptr, size_t len)
966 {
967 return (kore_realloc(ptr, len));
968 }
969
970 static void
971 python_free(void *ctx, void *ptr)
972 {
973 kore_free(ptr);
974 }
975
976 static void
977 python_module_free(struct kore_module *module)
978 {
979 kore_free(module->path);
980 Py_DECREF(module->handle);
981 kore_free(module);
982 }
983
984 static void
985 python_split_arguments(char *args, char **argv, size_t elm)
986 {
987 size_t idx;
988 char *p, *line, *end;
989
990 if (elm <= 1)
991 fatal("not enough elements (%zu)", elm);
992
993 idx = 0;
994 line = args;
995
996 for (p = line; *p != '\0'; p++) {
997 if (idx >= elm - 1)
998 break;
999
1000 if (*p == ' ') {
1001 *p = '\0';
1002 if (*line != '\0')
1003 argv[idx++] = line;
1004 line = p + 1;
1005 continue;
1006 }
1007
1008 if (*p != '"')
1009 continue;
1010
1011 line = p + 1;
1012 if ((end = strchr(line, '"')) == NULL)
1013 break;
1014
1015 *end = '\0';
1016 argv[idx++] = line;
1017 line = end + 1;
1018
1019 while (isspace(*(unsigned char *)line))
1020 line++;
1021
1022 p = line;
1023 }
1024
1025 if (idx < elm - 1 && *line != '\0')
1026 argv[idx++] = line;
1027
1028 argv[idx] = NULL;
1029 }
1030
1031 static void
1032 python_module_reload(struct kore_module *module)
1033 {
1034 PyObject *handle;
1035
1036 PyErr_Clear();
1037 if ((handle = PyImport_ReloadModule(module->handle)) == NULL) {
1038 kore_python_log_error("python_module_reload");
1039 return;
1040 }
1041
1042 Py_DECREF(module->handle);
1043 module->handle = handle;
1044 }
1045
1046 static void
1047 python_module_load(struct kore_module *module)
1048 {
1049 module->handle = python_import(module->path);
1050 if (module->handle == NULL)
1051 fatal("%s: failed to import module", module->path);
1052 }
1053
1054 static void *
1055 python_module_getsym(struct kore_module *module, const char *symbol)
1056 {
1057 return (python_callable(module->handle, symbol));
1058 }
1059
1060 static struct python_coro *
1061 python_coro_create(PyObject *obj, struct http_request *req)
1062 {
1063 struct python_coro *coro;
1064
1065 if (!PyCoro_CheckExact(obj))
1066 fatal("%s: object is not a coroutine", __func__);
1067
1068 coro = kore_pool_get(&coro_pool);
1069 coro_count++;
1070
1071 coro->name = NULL;
1072 coro->result = NULL;
1073 coro->sockop = NULL;
1074 coro->lockop = NULL;
1075 coro->gatherop = NULL;
1076 coro->exception = NULL;
1077 coro->exception_msg = NULL;
1078
1079 coro->obj = obj;
1080 coro->killed = 0;
1081 coro->request = req;
1082 coro->id = coro_id++;
1083 coro->state = CORO_STATE_RUNNABLE;
1084
1085 TAILQ_INSERT_TAIL(&coro_runnable, coro, list);
1086
1087 if (coro->request != NULL)
1088 http_request_sleep(coro->request);
1089
1090 python_coro_trace("created", coro);
1091
1092 return (coro);
1093 }
1094
1095 static int
1096 python_coro_run(struct python_coro *coro)
1097 {
1098 PySendResult res;
1099 PyObject *item;
1100 PyObject *type, *traceback;
1101
1102 if (coro->state != CORO_STATE_RUNNABLE)
1103 fatal("non-runnable coro attempted to run");
1104
1105 coro_running = coro;
1106
1107 for (;;) {
1108 python_coro_trace("running", coro);
1109
1110 PyErr_Clear();
1111 #if PY_VERSION_HEX < 0x030A0000
1112 res = PYGEN_RETURN;
1113 item = _PyGen_Send((PyGenObject *)coro->obj, NULL);
1114 #else
1115 /*
1116 * Python 3.10.x its PyIter_Send() will return a PYGEN_ERROR
1117 * if the coro returned (instead of yielding) and the result
1118 * ends up being Py_None. This means the returned item is
1119 * NULL but no StopIteration exception has occurred.
1120 */
1121 res = PyIter_Send(coro->obj, NULL, &item);
1122 #endif
1123 if (item == NULL || res == PYGEN_ERROR) {
1124 Py_XDECREF(item);
1125 if (coro->gatherop == NULL && PyErr_Occurred() &&
1126 PyErr_ExceptionMatches(PyExc_StopIteration)) {
1127 PyErr_Fetch(&type, &coro->result, &traceback);
1128 Py_DECREF(type);
1129 Py_XDECREF(traceback);
1130 } else if (PyErr_Occurred()) {
1131 kore_python_log_error("coroutine");
1132 if (coro->request != NULL) {
1133 http_response(coro->request,
1134 HTTP_STATUS_INTERNAL_ERROR,
1135 NULL, 0);
1136 }
1137 }
1138
1139 coro_running = NULL;
1140 return (KORE_RESULT_OK);
1141 }
1142
1143 #if PY_VERSION_HEX >= 0x030A0000
1144 if (res == PYGEN_RETURN) {
1145 coro->result = item;
1146 coro_running = NULL;
1147 return (KORE_RESULT_OK);
1148 }
1149 #endif
1150
1151 if (item == Py_None) {
1152 Py_DECREF(item);
1153 break;
1154 }
1155
1156 Py_DECREF(item);
1157 }
1158
1159 python_coro_suspend(coro);
1160 coro_running = NULL;
1161
1162 if (coro->request != NULL)
1163 http_request_sleep(coro->request);
1164
1165 return (KORE_RESULT_RETRY);
1166 }
1167
1168 static void
1169 python_coro_wakeup(struct python_coro *coro)
1170 {
1171 if (coro->state != CORO_STATE_SUSPENDED)
1172 return;
1173
1174 coro->state = CORO_STATE_RUNNABLE;
1175 TAILQ_REMOVE(&coro_suspended, coro, list);
1176 TAILQ_INSERT_TAIL(&coro_runnable, coro, list);
1177
1178 python_coro_trace("wokeup", coro);
1179 }
1180
1181 static void
1182 python_coro_suspend(struct python_coro *coro)
1183 {
1184 if (coro->state != CORO_STATE_RUNNABLE)
1185 return;
1186
1187 coro->state = CORO_STATE_SUSPENDED;
1188 TAILQ_REMOVE(&coro_runnable, coro, list);
1189 TAILQ_INSERT_TAIL(&coro_suspended, coro, list);
1190
1191 python_coro_trace("suspended", coro);
1192 }
1193
1194 static int
1195 python_resolve_frame_line(void *ptr)
1196 {
1197 int line;
1198 #if PY_VERSION_HEX >= 0x030b0000
1199 int addr;
1200 _PyInterpreterFrame *frame;
1201
1202 frame = ptr;
1203 addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT);
1204 line = PyCode_Addr2Line(frame->f_code, addr);
1205 #else
1206 line = PyFrame_GetLineNumber(ptr);
1207 #endif
1208
1209 return (line);
1210 }
1211
1212 static void
1213 python_coro_trace(const char *label, struct python_coro *coro)
1214 {
1215 int line;
1216 PyCoroObject *obj;
1217 PyCodeObject *code;
1218 #if PY_VERSION_HEX >= 0x030b0000
1219 _PyInterpreterFrame *frame;
1220 #else
1221 PyFrameObject *frame;
1222 #endif
1223 const char *func, *fname, *file;
1224
1225 if (coro_tracing == 0)
1226 return;
1227
1228 obj = (PyCoroObject *)coro->obj;
1229
1230 #if PY_VERSION_HEX >= 0x030b0000
1231 frame = (_PyInterpreterFrame *)obj->cr_iframe;
1232 #else
1233 frame = obj->cr_frame;
1234 #endif
1235 if (frame != NULL && frame->f_code != NULL) {
1236 code = frame->f_code;
1237 func = PyUnicode_AsUTF8AndSize(code->co_name, NULL);
1238 file = PyUnicode_AsUTF8AndSize(code->co_filename, NULL);
1239
1240 if ((fname = strrchr(file, '/')) == NULL)
1241 fname = file;
1242 else
1243 fname++;
1244 } else {
1245 func = "unknown";
1246 fname = "unknown";
1247 }
1248
1249 if (frame != NULL)
1250 line = python_resolve_frame_line(frame);
1251 else
1252 line = -1;
1253
1254 if (coro->name) {
1255 kore_log(LOG_NOTICE, "coro '%s' %s <%s> @ [%s:%d]",
1256 coro->name, label, func, fname, line);
1257 } else {
1258 kore_log(LOG_NOTICE, "coro %" PRIu64 " %s <%s> @ [%s:%d]",
1259 coro->id, label, func, fname, line);
1260 }
1261 }
1262
1263 static void
1264 pyconnection_dealloc(struct pyconnection *pyc)
1265 {
1266 PyObject_Del((PyObject *)pyc);
1267 }
1268
1269 static void
1270 pyhttp_dealloc(struct pyhttp_request *pyreq)
1271 {
1272 Py_XDECREF(pyreq->dict);
1273 Py_XDECREF(pyreq->data);
1274 PyObject_Del((PyObject *)pyreq);
1275 }
1276
1277 static void
1278 pyhttp_file_dealloc(struct pyhttp_file *pyfile)
1279 {
1280 PyObject_Del((PyObject *)pyfile);
1281 }
1282
1283 static int
1284 python_runtime_resolve(const char *module, const struct stat *st)
1285 {
1286 const char *ext;
1287
1288 if (!S_ISDIR(st->st_mode) && !S_ISREG(st->st_mode))
1289 return (KORE_RESULT_ERROR);
1290
1291 if (S_ISDIR(st->st_mode)) {
1292 kore_module_load(module, NULL, KORE_MODULE_PYTHON);
1293 if (chdir(module) == -1)
1294 fatal("chdir(%s): %s", module, errno_s);
1295 } else {
1296 if ((ext = strrchr(module, '.')) == NULL)
1297 return (KORE_RESULT_ERROR);
1298
1299 if (strcasecmp(ext, ".py"))
1300 return (KORE_RESULT_ERROR);
1301
1302 kore_module_load(module, NULL, KORE_MODULE_PYTHON);
1303 }
1304
1305 #if !defined(KORE_SINGLE_BINARY)
1306 kore_pymodule = module;
1307 #endif
1308
1309 kore_hooks_set(KORE_PYTHON_CONFIG_HOOK,
1310 KORE_PYTHON_TEARDOWN_HOOK, KORE_PYTHON_DAEMONIZED_HOOK);
1311
1312 return (KORE_RESULT_OK);
1313 }
1314
1315 static int
1316 python_runtime_http_request(void *addr, struct http_request *req)
1317 {
1318 int ret, idx, cnt;
1319 PyObject *pyret, *args, *callable;
1320 PyObject *cargs[HTTP_CAPTURE_GROUPS + 1];
1321
1322 if (req->py_coro != NULL) {
1323 python_coro_wakeup(req->py_coro);
1324 if (python_coro_run(req->py_coro) == KORE_RESULT_OK) {
1325 kore_python_coro_delete(req->py_coro);
1326 req->py_coro = NULL;
1327
1328 if (req->fsm_state != PYHTTP_STATE_PREPROCESS)
1329 return (KORE_RESULT_OK);
1330 }
1331 return (KORE_RESULT_RETRY);
1332 }
1333
1334 switch (req->fsm_state) {
1335 case PYHTTP_STATE_INIT:
1336 req->py_rqnext = TAILQ_FIRST(&prereq);
1337 req->fsm_state = PYHTTP_STATE_PREPROCESS;
1338 if (req->py_req == NULL) {
1339 if ((req->py_req = pyhttp_request_alloc(req)) == NULL)
1340 fatal("%s: pyreq alloc failed", __func__);
1341 }
1342 /* fallthrough */
1343 case PYHTTP_STATE_PREPROCESS:
1344 ret = pyhttp_preprocess(req);
1345 switch (ret) {
1346 case KORE_RESULT_OK:
1347 req->fsm_state = PYHTTP_STATE_RUN;
1348 break;
1349 case KORE_RESULT_RETRY:
1350 return (KORE_RESULT_RETRY);
1351 case KORE_RESULT_ERROR:
1352 return (KORE_RESULT_OK);
1353 default:
1354 fatal("invalid state pyhttp state %d", req->fsm_state);
1355 }
1356 /* fallthrough */
1357 case PYHTTP_STATE_RUN:
1358 break;
1359 }
1360
1361 cnt = 0;
1362 callable = (PyObject *)addr;
1363
1364 /* starts at 1 to skip the full path. */
1365 if (req->rt->type == HANDLER_TYPE_DYNAMIC) {
1366 for (idx = 1; idx < HTTP_CAPTURE_GROUPS - 1; idx++) {
1367 if (req->cgroups[idx].rm_so == -1 ||
1368 req->cgroups[idx].rm_eo == -1)
1369 break;
1370
1371 cargs[cnt] = PyUnicode_FromStringAndSize(req->path +
1372 req->cgroups[idx].rm_so,
1373 req->cgroups[idx].rm_eo - req->cgroups[idx].rm_so);
1374
1375 if (cargs[cnt] == NULL) {
1376 while (cnt >= 0)
1377 Py_XDECREF(cargs[cnt--]);
1378 kore_python_log_error("http request");
1379 http_response(req,
1380 HTTP_STATUS_INTERNAL_ERROR, NULL, 0);
1381 return (KORE_RESULT_OK);
1382 }
1383
1384 cnt++;
1385 }
1386 }
1387
1388 cargs[cnt] = NULL;
1389
1390 if ((args = PyTuple_New(cnt + 1)) == NULL)
1391 fatal("%s: PyTuple_New failed", __func__);
1392
1393 Py_INCREF(req->py_req);
1394 if (PyTuple_SetItem(args, 0, req->py_req) != 0)
1395 fatal("python_runtime_http_request: PyTuple_SetItem failed");
1396
1397 for (idx = 0; cargs[idx] != NULL; idx++) {
1398 if (PyTuple_SetItem(args, 1 + idx, cargs[idx]) != 0)
1399 fatal("%s: PyTuple_SetItem failed (%d)", __func__, idx);
1400 }
1401
1402 PyErr_Clear();
1403 pyret = PyObject_Call(callable, args, NULL);
1404 Py_DECREF(args);
1405
1406 if (pyret == NULL) {
1407 kore_python_log_error("python_runtime_http_request");
1408 http_response(req, HTTP_STATUS_INTERNAL_ERROR, NULL, 0);
1409 return (KORE_RESULT_OK);
1410 }
1411
1412 if (PyCoro_CheckExact(pyret)) {
1413 req->py_coro = python_coro_create(pyret, req);
1414 if (python_coro_run(req->py_coro) == KORE_RESULT_OK) {
1415 http_request_wakeup(req);
1416 kore_python_coro_delete(req->py_coro);
1417 req->py_coro = NULL;
1418 return (KORE_RESULT_OK);
1419 }
1420 return (KORE_RESULT_RETRY);
1421 }
1422
1423 if (pyret != Py_None)
1424 fatal("python_runtime_http_request: unexpected return type");
1425
1426 Py_DECREF(pyret);
1427
1428 return (KORE_RESULT_OK);
1429 }
1430
1431 static void
1432 python_runtime_http_request_free(void *addr, struct http_request *req)
1433 {
1434 PyObject *ret;
1435
1436 if (req->py_req == NULL) {
1437 if ((req->py_req = pyhttp_request_alloc(req)) == NULL)
1438 fatal("%s: pyreq alloc failed", __func__);
1439 }
1440
1441 PyErr_Clear();
1442 ret = PyObject_CallFunctionObjArgs(addr, req->py_req, NULL);
1443
1444 if (ret == NULL)
1445 kore_python_log_error("python_runtime_http_request_free");
1446
1447 Py_XDECREF(ret);
1448 }
1449
1450 static void
1451 python_runtime_http_body_chunk(void *addr, struct http_request *req,
1452 const void *data, size_t len)
1453 {
1454 PyObject *args, *ret;
1455
1456 if (req->py_req == NULL) {
1457 if ((req->py_req = pyhttp_request_alloc(req)) == NULL)
1458 fatal("%s: pyreq alloc failed", __func__);
1459 }
1460
1461 if ((args = Py_BuildValue("(Oy#)", req->py_req, data, len)) == NULL) {
1462 kore_python_log_error("python_runtime_http_body_chunk");
1463 return;
1464 }
1465
1466 PyErr_Clear();
1467 ret = PyObject_Call(addr, args, NULL);
1468
1469 if (ret == NULL)
1470 kore_python_log_error("python_runtime_http_body_chunk");
1471
1472 Py_XDECREF(ret);
1473 Py_DECREF(args);
1474 }
1475
1476 static int
1477 python_runtime_validator(void *addr, struct http_request *req, const void *data)
1478 {
1479 int ret;
1480 struct python_coro *coro;
1481 PyObject *pyret, *args, *callable, *arg;
1482
1483 if (req->py_req == NULL) {
1484 if ((req->py_req = pyhttp_request_alloc(req)) == NULL)
1485 fatal("%s: pyreq alloc failed", __func__);
1486 }
1487
1488 if (req->py_validator != NULL) {
1489 coro = req->py_validator;
1490 python_coro_wakeup(coro);
1491 if (python_coro_run(coro) == KORE_RESULT_OK) {
1492 ret = python_validator_check(coro->result);
1493 kore_python_coro_delete(coro);
1494 req->py_validator = NULL;
1495 return (ret);
1496 }
1497
1498 return (KORE_RESULT_RETRY);
1499 }
1500
1501 callable = (PyObject *)addr;
1502
1503 if (req->flags & HTTP_VALIDATOR_IS_REQUEST) {
1504 if ((args = PyTuple_New(1)) == NULL)
1505 fatal("%s: PyTuple_New failed", __func__);
1506
1507 Py_INCREF(req->py_req);
1508 if (PyTuple_SetItem(args, 0, req->py_req) != 0)
1509 fatal("%s: PyTuple_SetItem failed", __func__);
1510 } else {
1511 if ((arg = PyUnicode_FromString(data)) == NULL)
1512 fatal("python_runtime_validator: PyUnicode failed");
1513
1514 if ((args = PyTuple_New(2)) == NULL)
1515 fatal("%s: PyTuple_New failed", __func__);
1516
1517 Py_INCREF(req->py_req);
1518 if (PyTuple_SetItem(args, 0, req->py_req) != 0 ||
1519 PyTuple_SetItem(args, 1, arg) != 0)
1520 fatal("%s: PyTuple_SetItem failed", __func__);
1521 }
1522
1523 PyErr_Clear();
1524 pyret = PyObject_Call(callable, args, NULL);
1525 Py_DECREF(args);
1526
1527 if (pyret == NULL) {
1528 kore_python_log_error("python_runtime_validator");
1529 fatal("failed to execute python call");
1530 }
1531
1532 if (PyCoro_CheckExact(pyret)) {
1533 coro = python_coro_create(pyret, req);
1534 req->py_validator = coro;
1535 if (python_coro_run(coro) == KORE_RESULT_OK) {
1536 http_request_wakeup(req);
1537 ret = python_validator_check(coro->result);
1538 kore_python_coro_delete(coro);
1539 req->py_validator = NULL;
1540 return (ret);
1541 }
1542 return (KORE_RESULT_RETRY);
1543 }
1544
1545 ret = python_validator_check(pyret);
1546 Py_DECREF(pyret);
1547
1548 return (ret);
1549 }
1550
1551 static int
1552 python_validator_check(PyObject *obj)
1553 {
1554 int ret;
1555
1556 if (obj == NULL)
1557 return (KORE_RESULT_ERROR);
1558
1559 if (!PyBool_Check(obj)) {
1560 kore_log(LOG_WARNING,
1561 "validator did not return True/False");
1562 ret = KORE_RESULT_ERROR;
1563 }
1564
1565 if (obj == Py_True)
1566 ret = KORE_RESULT_OK;
1567 else
1568 ret = KORE_RESULT_ERROR;
1569
1570 return (ret);
1571 }
1572
1573 static void
1574 python_runtime_wsmessage(void *addr, struct connection *c, u_int8_t op,
1575 const void *data, size_t len)
1576 {
1577 PyObject *callable, *args, *pyret, *pyc, *pyop, *pydata;
1578
1579 callable = (PyObject *)addr;
1580
1581 if ((pyc = pyconnection_alloc(c)) == NULL)
1582 fatal("python_runtime_wsmessage: pyc alloc failed");
1583
1584 if ((pyop = PyLong_FromLong((long)op)) == NULL)
1585 fatal("python_runtime_wsmessage: PyLong_FromLong failed");
1586
1587 switch (op) {
1588 case WEBSOCKET_OP_TEXT:
1589 if ((pydata = PyUnicode_FromStringAndSize(data, len)) == NULL)
1590 fatal("wsmessage: PyUnicode_AsUTF8AndSize failed");
1591 break;
1592 case WEBSOCKET_OP_BINARY:
1593 if ((pydata = PyBytes_FromStringAndSize(data, len)) == NULL)
1594 fatal("wsmessage: PyBytes_FromString failed");
1595 break;
1596 default:
1597 fatal("python_runtime_wsmessage: invalid op");
1598 }
1599
1600 if ((args = PyTuple_New(3)) == NULL)
1601 fatal("python_runtime_wsmessage: PyTuple_New failed");
1602
1603 if (PyTuple_SetItem(args, 0, pyc) != 0 ||
1604 PyTuple_SetItem(args, 1, pyop) != 0 ||
1605 PyTuple_SetItem(args, 2, pydata) != 0)
1606 fatal("python_runtime_wsmessage: PyTuple_SetItem failed");
1607
1608 PyErr_Clear();
1609 pyret = PyObject_Call(callable, args, NULL);
1610 Py_DECREF(args);
1611
1612 if (pyret == NULL) {
1613 kore_python_log_error("python_runtime_wsconnect");
1614 fatal("failed to execute python call");
1615 }
1616
1617 Py_DECREF(pyret);
1618 }
1619
1620 static void
1621 python_runtime_execute(void *addr)
1622 {
1623 PyObject *callable, *args, *pyret;
1624
1625 callable = (PyObject *)addr;
1626
1627 if ((args = PyTuple_New(0)) == NULL)
1628 fatal("python_runtime_execute: PyTuple_New failed");
1629
1630 PyErr_Clear();
1631 pyret = PyObject_Call(callable, args, NULL);
1632 Py_DECREF(args);
1633
1634 if (pyret == NULL) {
1635 kore_python_log_error("python_runtime_execute");
1636 fatal("failed to execute python call");
1637 }
1638
1639 Py_DECREF(pyret);
1640 }
1641
1642 static void
1643 python_runtime_configure(void *addr, int argc, char **argv)
1644 {
1645 int i;
1646 PyObject *callable, *args, *pyret, *pyarg, *list;
1647
1648 callable = (PyObject *)addr;
1649
1650 if ((args = PyTuple_New(1)) == NULL)
1651 fatal("python_runtime_configure: PyTuple_New failed");
1652
1653 if ((list = PyList_New(argc + 1)) == NULL)
1654 fatal("python_runtime_configure: PyList_New failed");
1655
1656 if ((pyarg = PyUnicode_FromString(__progname)) == NULL)
1657 fatal("python_runtime_configure: PyUnicode_FromString");
1658
1659 if (PyList_SetItem(list, 0, pyarg) == -1)
1660 fatal("python_runtime_configure: PyList_SetItem");
1661
1662 for (i = 0; i < argc; i++) {
1663 if ((pyarg = PyUnicode_FromString(argv[i])) == NULL)
1664 fatal("python_runtime_configure: PyUnicode_FromString");
1665
1666 if (PyList_SetItem(list, i + 1, pyarg) == -1)
1667 fatal("python_runtime_configure: PyList_SetItem");
1668 }
1669
1670 if (PyTuple_SetItem(args, 0, list) != 0)
1671 fatal("python_runtime_configure: PyTuple_SetItem");
1672
1673 PyErr_Clear();
1674 pyret = PyObject_Call(callable, args, NULL);
1675 Py_DECREF(args);
1676
1677 if (pyret == NULL) {
1678 kore_python_log_error("python_runtime_configure");
1679 fatal("failed to configure your application");
1680 }
1681
1682 Py_DECREF(pyret);
1683 }
1684
1685 static int
1686 python_runtime_onload(void *addr, int action)
1687 {
1688 int ret;
1689 PyObject *pyret, *args, *pyact, *callable;
1690
1691 callable = (PyObject *)addr;
1692
1693 if ((pyact = PyLong_FromLong(action)) == NULL)
1694 fatal("python_runtime_onload: PyLong_FromLong failed");
1695
1696 if ((args = PyTuple_New(1)) == NULL)
1697 fatal("python_runtime_onload: PyTuple_New failed");
1698
1699 if (PyTuple_SetItem(args, 0, pyact) != 0)
1700 fatal("python_runtime_onload: PyTuple_SetItem failed");
1701
1702 PyErr_Clear();
1703 pyret = PyObject_Call(callable, args, NULL);
1704 Py_DECREF(args);
1705
1706 if (pyret == NULL) {
1707 kore_python_log_error("python_runtime_onload");
1708 return (KORE_RESULT_ERROR);
1709 }
1710
1711 if (!PyLong_Check(pyret))
1712 fatal("python_runtime_onload: unexpected return type");
1713
1714 ret = (int)PyLong_AsLong(pyret);
1715 Py_DECREF(pyret);
1716
1717 return (ret);
1718 }
1719
1720 static void
1721 python_runtime_connect(void *addr, struct connection *c)
1722 {
1723 PyObject *pyc, *pyret, *args, *callable;
1724
1725 callable = (PyObject *)addr;
1726
1727 if ((pyc = pyconnection_alloc(c)) == NULL)
1728 fatal("python_runtime_connect: pyc alloc failed");
1729
1730 if ((args = PyTuple_New(1)) == NULL)
1731 fatal("python_runtime_connect: PyTuple_New failed");
1732
1733 if (PyTuple_SetItem(args, 0, pyc) != 0)
1734 fatal("python_runtime_connect: PyTuple_SetItem failed");
1735
1736 PyErr_Clear();
1737 pyret = PyObject_Call(callable, args, NULL);
1738 Py_DECREF(args);
1739
1740 if (pyret == NULL) {
1741 kore_python_log_error("python_runtime_connect");
1742 kore_connection_disconnect(c);
1743 }
1744
1745 Py_DECREF(pyret);
1746 }
1747
1748 static void
1749 python_runtime_signal(void *addr, int sig)
1750 {
1751 PyObject *obj, *ret;
1752
1753 if ((obj = Py_BuildValue("i", sig)) == NULL) {
1754 kore_python_log_error("python_runtime_signal");
1755 return;
1756 }
1757
1758 ret = PyObject_CallFunctionObjArgs(addr, obj, NULL);
1759
1760 Py_DECREF(obj);
1761 Py_XDECREF(ret);
1762 }
1763
1764 PyMODINIT_FUNC
1765 python_module_init(void)
1766 {
1767 int i;
1768 struct pyconfig *config;
1769 PyObject *pykore;
1770
1771 if ((pykore = PyModule_Create(&pykore_module)) == NULL)
1772 fatal("python_module_init: failed to setup pykore module");
1773
1774 python_push_type("pyproc", pykore, &pyproc_type);
1775 python_push_type("pylock", pykore, &pylock_type);
1776 python_push_type("pytimer", pykore, &pytimer_type);
1777 python_push_type("pyqueue", pykore, &pyqueue_type);
1778 python_push_type("pyroute", pykore, &pyroute_type);
1779 python_push_type("pysocket", pykore, &pysocket_type);
1780 python_push_type("pydomain", pykore, &pydomain_type);
1781 python_push_type("pyconnection", pykore, &pyconnection_type);
1782
1783 #if defined(__linux__)
1784 python_push_type("pyseccomp", pykore, &pyseccomp_type);
1785 #endif
1786
1787 #if defined(KORE_USE_CURL)
1788 python_push_type("pycurlhandle", pykore, &pycurl_handle_type);
1789 python_push_type("pyhttpclient", pykore, &pyhttp_client_type);
1790
1791 for (i = 0; py_curlopt[i].name != NULL; i++) {
1792 python_push_integer(pykore, py_curlopt[i].name,
1793 py_curlopt[i].value);
1794 }
1795 #endif
1796
1797 python_push_type("pyhttp_file", pykore, &pyhttp_file_type);
1798 python_push_type("pyhttp_request", pykore, &pyhttp_request_type);
1799
1800 for (i = 0; python_integers[i].symbol != NULL; i++) {
1801 python_push_integer(pykore, python_integers[i].symbol,
1802 python_integers[i].value);
1803 }
1804
1805 if ((config = PyObject_New(struct pyconfig, &pyconfig_type)) == NULL)
1806 fatal("failed to create config object");
1807
1808 if (PyObject_SetAttrString(pykore, "config", (PyObject *)config) == -1)
1809 fatal("failed to add config object");
1810
1811 return (pykore);
1812 }
1813
1814 static int
1815 pyconfig_setattr(PyObject *self, PyObject *attr, PyObject *val)
1816 {
1817 char *v;
1818 int ret;
1819 PyObject *repr;
1820 const char *name, *value;
1821
1822 ret = -1;
1823 repr = NULL;
1824
1825 if (!PyUnicode_Check(attr))
1826 fatal("setattr: attribute name not a unicode string");
1827
1828 if (PyLong_CheckExact(val)) {
1829 if ((repr = PyObject_Repr(val)) == NULL)
1830 return (-1);
1831 value = PyUnicode_AsUTF8(repr);
1832 } else if (PyUnicode_CheckExact(val)) {
1833 value = PyUnicode_AsUTF8(val);
1834 } else if (PyBool_Check(val)) {
1835 if (val == Py_False)
1836 value = "False";
1837 else
1838 value = "True";
1839 } else {
1840 fatal("invalid object, config expects integer, bool or string");
1841 }
1842
1843 name = PyUnicode_AsUTF8(attr);
1844 v = kore_strdup(value);
1845
1846 if (!kore_configure_setting(name, v)) {
1847 ret = -1;
1848 PyErr_SetString(PyExc_RuntimeError,
1849 "configured cannot be changed at runtime");
1850 } else {
1851 ret = 0;
1852 }
1853
1854 kore_free(v);
1855
1856 Py_XDECREF(repr);
1857
1858 return (ret);
1859 }
1860
1861 static void
1862 python_append_path(const char *path)
1863 {
1864 PyObject *mpath, *spath;
1865
1866 if ((mpath = PyUnicode_FromString(path)) == NULL)
1867 fatal("python_append_path: PyUnicode_FromString failed");
1868
1869 if ((spath = PySys_GetObject("path")) == NULL)
1870 fatal("python_append_path: PySys_GetObject failed");
1871
1872 PyList_Append(spath, mpath);
1873 Py_DECREF(mpath);
1874 }
1875
1876 static void
1877 python_push_type(const char *name, PyObject *module, PyTypeObject *type)
1878 {
1879 if (PyType_Ready(type) == -1)
1880 fatal("python_push_type: failed to ready %s", name);
1881
1882 Py_INCREF(type);
1883
1884 if (PyModule_AddObject(module, name, (PyObject *)type) == -1)
1885 fatal("python_push_type: failed to push %s", name);
1886 }
1887
1888 static void
1889 python_push_integer(PyObject *module, const char *name, long value)
1890 {
1891 if (PyModule_AddIntConstant(module, name, value) == -1)
1892 fatal("python_push_integer: failed to add %s", name);
1893 }
1894
1895 #if defined(KORE_USE_PGSQL)
1896 static PyObject *
1897 python_kore_pgsql_register(PyObject *self, PyObject *args)
1898 {
1899 const char *db, *conninfo;
1900
1901 if (!PyArg_ParseTuple(args, "ss", &db, &conninfo))
1902 return (NULL);
1903
1904 (void)kore_pgsql_register(db, conninfo);
1905
1906 Py_RETURN_TRUE;
1907 }
1908 #endif
1909
1910 static PyObject *
1911 python_kore_app(PyObject *self, PyObject *args)
1912 {
1913 PyObject *obj;
1914
1915 if (!PyArg_ParseTuple(args, "O", &obj)) {
1916 PyErr_Clear();
1917
1918 if (kore_app == NULL)
1919 Py_RETURN_NONE;
1920
1921 Py_INCREF(kore_app);
1922 return (kore_app);
1923 }
1924
1925 Py_XDECREF(kore_app);
1926
1927 kore_app = obj;
1928 Py_INCREF(kore_app);
1929
1930 Py_RETURN_TRUE;
1931 }
1932
1933 static PyObject *
1934 python_kore_log(PyObject *self, PyObject *args)
1935 {
1936 int prio;
1937 const char *message;
1938
1939 if (!PyArg_ParseTuple(args, "is", &prio, &message))
1940 return (NULL);
1941
1942 kore_log(prio, "%s", message);
1943
1944 Py_RETURN_TRUE;
1945 }
1946
1947 static PyObject *
1948 python_kore_time(PyObject *self, PyObject *args)
1949 {
1950 u_int64_t now;
1951
1952 now = kore_time_ms();
1953
1954 return (PyLong_FromUnsignedLongLong(now));
1955 }
1956
1957 static PyObject *
1958 python_kore_server(PyObject *self, PyObject *args, PyObject *kwargs)
1959 {
1960 struct kore_server *srv;
1961 const char *name, *ip, *port, *path;
1962
1963 if (kwargs == NULL) {
1964 PyErr_SetString(PyExc_RuntimeError, "missing keyword args");
1965 return (NULL);
1966 }
1967
1968 ip = python_string_from_dict(kwargs, "ip");
1969 path = python_string_from_dict(kwargs, "path");
1970
1971 if (ip == NULL && path == NULL) {
1972 PyErr_SetString(PyExc_RuntimeError,
1973 "missing ip or path keywords");
1974 return (NULL);
1975 }
1976
1977 if (ip != NULL && path != NULL) {
1978 PyErr_SetString(PyExc_RuntimeError, "ip/path are exclusive");
1979 return (NULL);
1980 }
1981
1982 name = python_string_from_dict(kwargs, "name");
1983 if (name == NULL)
1984 name = "default";
1985
1986 if ((srv = kore_server_lookup(name)) != NULL) {
1987 PyErr_Format(PyExc_RuntimeError,
1988 "server '%s' already exist", name);
1989 return (NULL);
1990 }
1991
1992 srv = kore_server_create(name);
1993 python_bool_from_dict(kwargs, "tls", &srv->tls);
1994
1995 if (srv->tls && !kore_tls_supported()) {
1996 kore_server_free(srv);
1997 PyErr_SetString(PyExc_RuntimeError,
1998 "TLS not supported in this Kore build");
1999 return (NULL);
2000 }
2001
2002 if (ip != NULL) {
2003 if ((port = python_string_from_dict(kwargs, "port")) == NULL) {
2004 kore_server_free(srv);
2005 PyErr_SetString(PyExc_RuntimeError,
2006 "missing or invalid 'port' keyword");
2007 return (NULL);
2008 }
2009
2010 if (!kore_server_bind(srv, ip, port, NULL)) {
2011 PyErr_Format(PyExc_RuntimeError,
2012 "failed to bind to '%s:%s'", ip, port);
2013 return (NULL);
2014 }
2015 } else {
2016 if (!kore_server_bind_unix(srv, path, NULL)) {
2017 PyErr_Format(PyExc_RuntimeError,
2018 "failed to bind to '%s'", path);
2019 return (NULL);
2020 }
2021 }
2022
2023 kore_server_finalize(srv);
2024
2025 Py_RETURN_NONE;
2026 }
2027
2028 static PyObject *
2029 python_kore_privsep(PyObject *self, PyObject *args, PyObject *kwargs)
2030 {
2031 struct kore_privsep *ps;
2032 const char *val;
2033 PyObject *skip, *obj;
2034 Py_ssize_t list_len, idx;
2035
2036 if (!PyArg_ParseTuple(args, "s", &val))
2037 return (NULL);
2038
2039 if (!strcmp(val, "worker")) {
2040 ps = &worker_privsep;
2041 } else if (!strcmp(val, "keymgr")) {
2042 ps = &keymgr_privsep;
2043 #if defined(KORE_USE_ACME)
2044 } else if (!strcmp(val, "acme")) {
2045 ps = &acme_privsep;
2046 #endif
2047 } else {
2048 PyErr_Format(PyExc_RuntimeError,
2049 "unknown privsep process '%s'", val);
2050 return (NULL);
2051 }
2052
2053 if ((val = python_string_from_dict(kwargs, "root")) != NULL) {
2054 kore_free(ps->root);
2055 ps->root = kore_strdup(val);
2056 }
2057
2058 if ((val = python_string_from_dict(kwargs, "runas")) != NULL) {
2059 kore_free(ps->runas);
2060 ps->runas = kore_strdup(val);
2061 }
2062
2063 if ((skip = PyDict_GetItemString(kwargs, "skip")) != NULL) {
2064 if (!PyList_CheckExact(skip)) {
2065 PyErr_Format(PyExc_RuntimeError,
2066 "privsep skip keyword needs to be a list");
2067 return (NULL);
2068 }
2069
2070 list_len = PyList_Size(skip);
2071
2072 for (idx = 0; idx < list_len; idx++) {
2073 if ((obj = PyList_GetItem(skip, idx)) == NULL)
2074 return (NULL);
2075
2076 if (!PyUnicode_Check(obj))
2077 return (NULL);
2078
2079 if ((val = PyUnicode_AsUTF8AndSize(obj, NULL)) == NULL)
2080 return (NULL);
2081
2082 if (!strcmp(val, "chroot")) {
2083 ps->skip_chroot = 1;
2084 } else {
2085 PyErr_Format(PyExc_RuntimeError,
2086 "unknown skip keyword '%s'", val);
2087 return (NULL);
2088 }
2089 }
2090 }
2091
2092 Py_RETURN_NONE;
2093 }
2094
2095 static PyObject *
2096 python_kore_prerequest(PyObject *self, PyObject *args)
2097 {
2098 PyObject *f;
2099 struct reqcall *rq;
2100
2101 if (!PyArg_ParseTuple(args, "O", &f))
2102 return (NULL);
2103
2104 rq = kore_calloc(1, sizeof(*rq));
2105 rq->f = f;
2106
2107 Py_INCREF(f);
2108 TAILQ_INSERT_TAIL(&prereq, rq, list);
2109
2110 return (f);
2111 }
2112
2113 static PyObject *
2114 python_kore_task_create(PyObject *self, PyObject *args)
2115 {
2116 PyObject *obj;
2117 struct python_coro *coro;
2118
2119 if (!PyArg_ParseTuple(args, "O", &obj))
2120 return (NULL);
2121
2122 if (!PyCoro_CheckExact(obj))
2123 fatal("%s: object is not a coroutine", __func__);
2124
2125 coro = python_coro_create(obj, NULL);
2126 Py_INCREF(obj);
2127
2128 return (PyLong_FromUnsignedLongLong(coro->id));
2129 }
2130
2131 static PyObject *
2132 python_kore_task_id(PyObject *self, PyObject *args)
2133 {
2134 if (coro_running == NULL) {
2135 PyErr_SetString(PyExc_RuntimeError,
2136 "no coroutine active");
2137 return (NULL);
2138 }
2139
2140 return (PyLong_FromUnsignedLongLong(coro_running->id));
2141 }
2142
2143 static PyObject *
2144 python_kore_task_kill(PyObject *self, PyObject *args)
2145 {
2146 u_int64_t id;
2147 struct python_coro *coro, *active;
2148
2149 if (!PyArg_ParseTuple(args, "K", &id))
2150 return (NULL);
2151
2152 if (coro_running != NULL && coro_running->id == id) {
2153 PyErr_SetString(PyExc_RuntimeError,
2154 "refusing to kill active coroutine");
2155 return (NULL);
2156 }
2157
2158 /* Remember active coro, as delete sets coro_running to NULL. */
2159 active = coro_running;
2160
2161 TAILQ_FOREACH(coro, &coro_runnable, list) {
2162 if (coro->id == id) {
2163 coro->killed++;
2164 kore_python_coro_delete(coro);
2165 coro_running = active;
2166 Py_RETURN_TRUE;
2167 }
2168 }
2169
2170 TAILQ_FOREACH(coro, &coro_suspended, list) {
2171 if (coro->id == id) {
2172 coro->killed++;
2173 kore_python_coro_delete(coro);
2174 coro_running = active;
2175 Py_RETURN_TRUE;
2176 }
2177 }
2178
2179 Py_RETURN_FALSE;
2180 }
2181
2182 static PyObject *
2183 python_kore_socket_wrap(PyObject *self, PyObject *args)
2184 {
2185 struct pysocket *sock;
2186 PyObject *pysock, *pyfd, *pyfam, *pyproto;
2187
2188 sock = NULL;
2189 pyfd = NULL;
2190 pyfam = NULL;
2191 pyproto = NULL;
2192
2193 if (!PyArg_ParseTuple(args, "O", &pysock))
2194 return (NULL);
2195
2196 if ((pyfd = PyObject_CallMethod(pysock, "fileno", NULL)) == NULL)
2197 return (NULL);
2198
2199 if ((pyfam = PyObject_GetAttrString(pysock, "family")) == NULL)
2200 goto out;
2201
2202 if ((pyproto = PyObject_GetAttrString(pysock, "proto")) == NULL)
2203 goto out;
2204
2205 if ((sock = pysocket_alloc()) == NULL)
2206 goto out;
2207
2208 sock->socket = pysock;
2209 Py_INCREF(sock->socket);
2210
2211 sock->fd = (int)PyLong_AsLong(pyfd);
2212 sock->family = (int)PyLong_AsLong(pyfam);
2213 sock->protocol = (int)PyLong_AsLong(pyproto);
2214
2215 memset(&sock->addr, 0, sizeof(sock->addr));
2216
2217 switch (sock->family) {
2218 case AF_INET:
2219 case AF_UNIX:
2220 break;
2221 default:
2222 PyErr_SetString(PyExc_RuntimeError, "unsupported family");
2223 Py_DECREF((PyObject *)sock);
2224 sock = NULL;
2225 goto out;
2226 }
2227
2228 out:
2229 Py_XDECREF(pyfd);
2230 Py_XDECREF(pyfam);
2231 Py_XDECREF(pyproto);
2232
2233 return ((PyObject *)sock);
2234 }
2235
2236 static PyObject *
2237 python_kore_queue(PyObject *self, PyObject *args)
2238 {
2239 struct pyqueue *queue;
2240
2241 if ((queue = PyObject_New(struct pyqueue, &pyqueue_type)) == NULL)
2242 return (NULL);
2243
2244 TAILQ_INIT(&queue->objects);
2245 TAILQ_INIT(&queue->waiting);
2246
2247 return ((PyObject *)queue);
2248 }
2249
2250 static PyObject *
2251 python_kore_worker(PyObject *self, PyObject *args)
2252 {
2253 if (worker == NULL) {
2254 Py_RETURN_NONE;
2255 }
2256
2257 return (PyLong_FromLong(worker->id));
2258 }
2259
2260 static PyObject *
2261 python_kore_tracer(PyObject *self, PyObject *args)
2262 {
2263 PyObject *obj;
2264
2265 if (python_tracer != NULL) {
2266 PyErr_SetString(PyExc_RuntimeError, "tracer already set");
2267 return (NULL);
2268 }
2269
2270 if (!PyArg_ParseTuple(args, "O", &obj))
2271 return (NULL);
2272
2273 if (!PyCallable_Check(obj)) {
2274 PyErr_SetString(PyExc_RuntimeError, "object not callable");
2275 Py_DECREF(obj);
2276 return (NULL);
2277 }
2278
2279 Py_INCREF(obj);
2280 python_tracer = obj;
2281
2282 Py_RETURN_TRUE;
2283 }
2284
2285 static PyObject *
2286 python_kore_domain(PyObject *self, PyObject *args, PyObject *kwargs)
2287 {
2288 #if defined(KORE_USE_ACME)
2289 int acme;
2290 char *acert, *akey;
2291 #endif
2292 struct kore_server *srv;
2293 long depth;
2294 const char *name;
2295 struct pydomain *domain;
2296 const char *cert, *key, *ca, *attach, *crl;
2297
2298 ca = NULL;
2299 depth = -1;
2300 key = NULL;
2301 crl = NULL;
2302 cert = NULL;
2303 attach = NULL;
2304
2305 #if defined(KORE_USE_ACME)
2306 acme = 0;
2307 #endif
2308
2309 if (!PyArg_ParseTuple(args, "s", &name))
2310 return (NULL);
2311
2312 if (kwargs != NULL)
2313 attach = python_string_from_dict(kwargs, "attach");
2314
2315 if (attach == NULL)
2316 attach = "default";
2317
2318 if ((srv = kore_server_lookup(attach)) == NULL) {
2319 PyErr_Format(PyExc_RuntimeError,
2320 "server '%s' does not exist", attach);
2321 return (NULL);
2322 }
2323
2324 if (srv->tls) {
2325 if (kwargs == NULL) {
2326 PyErr_Format(PyExc_RuntimeError,
2327 "no keywords for TLS enabled domain %s", name);
2328 return (NULL);
2329 }
2330 key = python_string_from_dict(kwargs, "key");
2331 cert = python_string_from_dict(kwargs, "cert");
2332
2333 #if defined(KORE_USE_ACME)
2334 python_bool_from_dict(kwargs, "acme", &acme);
2335
2336 if (acme) {
2337 kore_acme_get_paths(name, &akey, &acert);
2338 acme_domains++;
2339 key = akey;
2340 cert = acert;
2341 }
2342 #endif
2343
2344 if (key == NULL || cert == NULL) {
2345 PyErr_Format(PyExc_RuntimeError,
2346 "missing key or cert keywords for TLS listener");
2347 return (NULL);
2348 }
2349
2350 ca = python_string_from_dict(kwargs, "client_verify");
2351 if (ca != NULL) {
2352 python_long_from_dict(kwargs, "verify_depth", &depth);
2353 if (depth < 0) {
2354 PyErr_Format(PyExc_RuntimeError,
2355 "invalid depth '%d'", depth);
2356 return (NULL);
2357 }
2358 crl = python_string_from_dict(kwargs, "crl");
2359 }
2360 } else if (key != NULL || cert != NULL || ca != NULL) {
2361 kore_log(LOG_INFO, "ignoring tls settings for '%s'", name);
2362 }
2363
2364 if (kore_domain_lookup(srv, name) != NULL) {
2365 PyErr_SetString(PyExc_RuntimeError, "domain exists");
2366 return (NULL);
2367 }
2368
2369 if ((domain = PyObject_New(struct pydomain, &pydomain_type)) == NULL)
2370 return (NULL);
2371
2372 domain->next = NULL;
2373 domain->kwargs = NULL;
2374
2375 if ((domain->config = kore_domain_new(name)) == NULL)
2376 fatal("failed to create new domain configuration");
2377
2378 if (!kore_domain_attach(domain->config, srv))
2379 fatal("failed to attach domain configuration");
2380
2381 if (srv->tls) {
2382 domain->config->certkey = kore_strdup(key);
2383 domain->config->certfile = kore_strdup(cert);
2384
2385 #if defined(KORE_USE_ACME)
2386 domain->config->acme = acme;
2387
2388 if (domain->config->acme) {
2389 kore_free(akey);
2390 kore_free(acert);
2391 }
2392 #endif
2393 if (ca != NULL) {
2394 domain->config->cafile = kore_strdup(ca);
2395 domain->config->x509_verify_depth = depth;
2396 if (crl != NULL)
2397 domain->config->crlfile = kore_strdup(crl);
2398 }
2399 }
2400
2401 return ((PyObject *)domain);
2402 }
2403
2404 static PyObject *
2405 python_kore_route(PyObject *self, PyObject *args, PyObject *kwargs)
2406 {
2407 const char *path;
2408 PyObject *inner;
2409 struct pyroute *route;
2410
2411 if ((route = PyObject_New(struct pyroute, &pyroute_type)) == NULL)
2412 return (NULL);
2413
2414 if (!PyArg_ParseTuple(args, "s", &path))
2415 return (NULL);
2416
2417 route->domain = NULL;
2418 route->kwargs = kwargs;
2419 route->path = kore_strdup(path);
2420
2421 Py_XINCREF(route->kwargs);
2422
2423 inner = PyObject_GetAttrString((PyObject *)route, "inner");
2424 if (inner == NULL) {
2425 Py_DECREF((PyObject *)route);
2426 PyErr_SetString(PyExc_RuntimeError, "failed to find inner");
2427 return (NULL);
2428 }
2429
2430 return (inner);
2431 }
2432
2433 static PyObject *
2434 python_kore_gather(PyObject *self, PyObject *args, PyObject *kwargs)
2435 {
2436 struct pygather_op *op;
2437 PyObject *obj;
2438 struct pygather_coro *coro;
2439 Py_ssize_t sz, idx;
2440 int concurrency;
2441
2442 if (coro_running == NULL) {
2443 PyErr_SetString(PyExc_RuntimeError,
2444 "kore.gather only available in coroutines");
2445 return (NULL);
2446 }
2447
2448 sz = PyTuple_Size(args);
2449
2450 if (sz > INT_MAX) {
2451 PyErr_SetString(PyExc_TypeError, "too many arguments");
2452 return (NULL);
2453 }
2454
2455 if (kwargs != NULL &&
2456 (obj = PyDict_GetItemString(kwargs, "concurrency")) != NULL) {
2457 if (!PyLong_Check(obj)) {
2458 PyErr_SetString(PyExc_TypeError,
2459 "concurrency level must be an integer");
2460 return (NULL);
2461 }
2462
2463 PyErr_Clear();
2464 concurrency = (int)PyLong_AsLong(obj);
2465 if (concurrency == -1 && PyErr_Occurred())
2466 return (NULL);
2467
2468 if (concurrency == 0)
2469 concurrency = sz;
2470 } else {
2471 concurrency = sz;
2472 }
2473
2474 op = PyObject_New(struct pygather_op, &pygather_op_type);
2475 if (op == NULL)
2476 return (NULL);
2477
2478 op->running = 0;
2479 op->count = (int)sz;
2480 op->coro = coro_running;
2481 op->concurrency = concurrency;
2482
2483 TAILQ_INIT(&op->results);
2484 TAILQ_INIT(&op->coroutines);
2485
2486 for (idx = 0; idx < sz; idx++) {
2487 if ((obj = PyTuple_GetItem(args, idx)) == NULL) {
2488 Py_DECREF((PyObject *)op);
2489 return (NULL);
2490 }
2491
2492 if (!PyCoro_CheckExact(obj)) {
2493 Py_DECREF((PyObject *)op);
2494 PyErr_SetString(PyExc_TypeError, "not a coroutine");
2495 return (NULL);
2496 }
2497
2498 Py_INCREF(obj);
2499
2500 coro = kore_pool_get(&gather_coro_pool);
2501 coro->coro = python_coro_create(obj, NULL);
2502 coro->coro->gatherop = op;
2503 TAILQ_INSERT_TAIL(&op->coroutines, coro, list);
2504
2505 if (idx > concurrency - 1)
2506 python_coro_suspend(coro->coro);
2507 else
2508 op->running++;
2509 }
2510
2511 return ((PyObject *)op);
2512 }
2513
2514 static PyObject *
2515 python_kore_lock(PyObject *self, PyObject *args)
2516 {
2517 struct pylock *lock;
2518
2519 if ((lock = PyObject_New(struct pylock, &pylock_type)) == NULL)
2520 return (NULL);
2521
2522 lock->owner = NULL;
2523 TAILQ_INIT(&lock->ops);
2524
2525 return ((PyObject *)lock);
2526 }
2527
2528 static PyObject *
2529 python_kore_fatal(PyObject *self, PyObject *args)
2530 {
2531 const char *reason;
2532
2533 if (!PyArg_ParseTuple(args, "s", &reason))
2534 reason = "python_kore_fatal: PyArg_ParseTuple failed";
2535
2536 fatal("%s", reason);
2537
2538 /* not reached */
2539 Py_RETURN_TRUE;
2540 }
2541
2542 static PyObject *
2543 python_kore_fatalx(PyObject *self, PyObject *args)
2544 {
2545 const char *reason;
2546
2547 if (!PyArg_ParseTuple(args, "s", &reason))
2548 reason = "python_kore_fatalx: PyArg_ParseTuple failed";
2549
2550 fatalx("%s", reason);
2551
2552 /* not reached */
2553 Py_RETURN_TRUE;
2554 }
2555
2556 static PyObject *
2557 python_kore_setname(PyObject *self, PyObject *args)
2558 {
2559 const char *name;
2560 extern char *kore_progname;
2561
2562 if (!PyArg_ParseTuple(args, "s", &name))
2563 return (NULL);
2564
2565 kore_free(kore_progname);
2566 kore_progname = kore_strdup(name);
2567
2568 Py_RETURN_NONE;
2569 }
2570
2571 static PyObject *
2572 python_kore_sigtrap(PyObject *self, PyObject *args)
2573 {
2574 int sig;
2575
2576 if (!PyArg_ParseTuple(args, "i", &sig))
2577 return (NULL);
2578
2579 kore_signal_trap(sig);
2580
2581 Py_RETURN_NONE;
2582 }
2583
2584 static PyObject *
2585 python_kore_sendobj(PyObject *self, PyObject *args, PyObject *kwargs)
2586 {
2587 long val;
2588 u_int16_t dst;
2589 char *ptr;
2590 Py_ssize_t length;
2591 PyObject *object, *bytes;
2592
2593 if (!PyArg_ParseTuple(args, "O", &object))
2594 return (NULL);
2595
2596 bytes = PyObject_CallFunctionObjArgs(pickle_dumps, object, NULL);
2597 if (bytes == NULL)
2598 return (NULL);
2599
2600 if (PyBytes_AsStringAndSize(bytes, &ptr, &length) == -1) {
2601 Py_DECREF(bytes);
2602 return (NULL);
2603 }
2604
2605 dst = KORE_MSG_WORKER_ALL;
2606
2607 if (kwargs != NULL) {
2608 if (python_long_from_dict(kwargs, "worker", &val)) {
2609 if (val <= 0 || val > worker_count ||
2610 val >= KORE_WORKER_MAX) {
2611 PyErr_Format(PyExc_RuntimeError,
2612 "worker %ld invalid", val);
2613 Py_DECREF(bytes);
2614 return (NULL);
2615 }
2616
2617 dst = val;
2618 }
2619 }
2620
2621 kore_msg_send(dst, KORE_PYTHON_SEND_OBJ, ptr, length);
2622 Py_DECREF(bytes);
2623
2624 Py_RETURN_NONE;
2625 }
2626
2627 static void
2628 python_kore_recvobj(struct kore_msg *msg, const void *data)
2629 {
2630 struct kore_runtime *rt;
2631 PyObject *onmsg, *ret, *bytes, *obj;
2632
2633 if ((onmsg = kore_module_getsym("koreapp.onmsg", &rt)) == NULL)
2634 return;
2635
2636 if (rt->type != KORE_RUNTIME_PYTHON)
2637 return;
2638
2639 if ((bytes = PyBytes_FromStringAndSize(data, msg->length)) == NULL) {
2640 Py_DECREF(onmsg);
2641 kore_python_log_error("koreapp.onmsg");
2642 return;
2643 }
2644
2645 obj = PyObject_CallFunctionObjArgs(pickle_loads, bytes, NULL);
2646 Py_DECREF(bytes);
2647
2648 if (obj == NULL) {
2649 Py_DECREF(onmsg);
2650 kore_python_log_error("koreapp.onmsg");
2651 return;
2652 }
2653
2654 ret = PyObject_CallFunctionObjArgs(onmsg, obj, NULL);
2655 kore_python_log_error("koreapp.onmsg");
2656
2657 Py_DECREF(obj);
2658 Py_DECREF(onmsg);
2659 Py_XDECREF(ret);
2660 }
2661
2662 static PyObject *
2663 python_kore_suspend(PyObject *self, PyObject *args)
2664 {
2665 struct pysuspend_op *op;
2666 int delay;
2667
2668 if (!PyArg_ParseTuple(args, "i", &delay))
2669 return (NULL);
2670
2671 op = PyObject_New(struct pysuspend_op, &pysuspend_op_type);
2672 if (op == NULL)
2673 return (NULL);
2674
2675 op->timer = NULL;
2676 op->delay = delay;
2677 op->coro = coro_running;
2678 op->state = PYSUSPEND_OP_INIT;
2679
2680 return ((PyObject *)op);
2681 }
2682
2683 static PyObject *
2684 python_kore_shutdown(PyObject *self, PyObject *args)
2685 {
2686 kore_shutdown();
2687
2688 Py_RETURN_TRUE;
2689 }
2690
2691 static PyObject *
2692 python_kore_coroname(PyObject *self, PyObject *args)
2693 {
2694 const char *name;
2695
2696 if (coro_running == NULL) {
2697 PyErr_SetString(PyExc_RuntimeError,
2698 "kore.coroname() only available in coroutines");
2699 return (NULL);
2700 }
2701
2702 if (!PyArg_ParseTuple(args, "s", &name))
2703 return (NULL);
2704
2705 kore_free(coro_running->name);
2706 coro_running->name = kore_strdup(name);
2707
2708 Py_RETURN_NONE;
2709 }
2710
2711 static PyObject *
2712 python_kore_corotrace(PyObject *self, PyObject *args)
2713 {
2714 if (!PyArg_ParseTuple(args, "b", &coro_tracing))
2715 return (NULL);
2716
2717 Py_RETURN_NONE;
2718 }
2719
2720 static PyObject *
2721 python_kore_timer(PyObject *self, PyObject *args, PyObject *kwargs)
2722 {
2723 u_int64_t ms;
2724 PyObject *obj;
2725 int flags;
2726 struct pytimer *timer;
2727
2728 if (worker == NULL) {
2729 PyErr_SetString(PyExc_RuntimeError,
2730 "kore.timer not supported on parent process");
2731 return (NULL);
2732 }
2733
2734 if (!PyArg_ParseTuple(args, "OKi", &obj, &ms, &flags))
2735 return (NULL);
2736
2737 if (flags & ~(KORE_TIMER_FLAGS)) {
2738 PyErr_SetString(PyExc_RuntimeError, "invalid flags");
2739 return (NULL);
2740 }
2741
2742 if ((timer = PyObject_New(struct pytimer, &pytimer_type)) == NULL)
2743 return (NULL);
2744
2745 timer->udata = NULL;
2746 timer->flags = flags;
2747 timer->callable = obj;
2748 timer->run = kore_timer_add(pytimer_run, ms, timer, flags);
2749
2750 Py_INCREF((PyObject *)timer);
2751 Py_INCREF(timer->callable);
2752
2753 if (kwargs != NULL) {
2754 if ((obj = PyDict_GetItemString(kwargs, "data")) != NULL) {
2755 Py_INCREF(obj);
2756 timer->udata = obj;
2757 }
2758 }
2759
2760 return ((PyObject *)timer);
2761 }
2762
2763 static PyObject *
2764 python_kore_proc(PyObject *self, PyObject *args, PyObject *kwargs)
2765 {
2766 union deconst cp;
2767 const char *cmd;
2768 struct pyproc *proc;
2769 Py_ssize_t idx, len;
2770 PyObject *obj, *item;
2771 int timeo, in_pipe[2], out_pipe[2];
2772 char *copy, *argv[32], *env[PYTHON_PROC_MAX_ENV + 1];
2773
2774 timeo = -1;
2775
2776 if (coro_running == NULL) {
2777 PyErr_SetString(PyExc_RuntimeError,
2778 "kore.proc only available in coroutines");
2779 return (NULL);
2780 }
2781
2782 if (!PyArg_ParseTuple(args, "s|i", &cmd, &timeo))
2783 return (NULL);
2784
2785 if (kwargs != NULL &&
2786 (obj = PyDict_GetItemString(kwargs, "env")) != NULL) {
2787 if (!PyList_CheckExact(obj)) {
2788 PyErr_SetString(PyExc_RuntimeError,
2789 "kore.proc: env is not of type 'list'");
2790 return (NULL);
2791 }
2792
2793 len = PyList_Size(obj);
2794 if (len > PYTHON_PROC_MAX_ENV) {
2795 PyErr_SetString(PyExc_RuntimeError,
2796 "kore.proc: too many entries in 'env' keyword");
2797 return (NULL);
2798 }
2799
2800 for (idx = 0; idx < len; idx++) {
2801 if ((item = PyList_GetItem(obj, idx)) == NULL)
2802 return (NULL);
2803
2804 if (!PyUnicode_CheckExact(item))
2805 return (NULL);
2806
2807 if ((cp.cp = PyUnicode_AsUTF8(item)) == NULL)
2808 return (NULL);
2809
2810 env[idx] = cp.p;
2811 }
2812
2813 env[idx] = NULL;
2814 }
2815
2816 if (pipe(in_pipe) == -1) {
2817 PyErr_SetString(PyExc_RuntimeError, errno_s);
2818 return (NULL);
2819 }
2820
2821 if (pipe(out_pipe) == -1) {
2822 close(in_pipe[0]);
2823 close(in_pipe[1]);
2824 PyErr_SetString(PyExc_RuntimeError, errno_s);
2825 return (NULL);
2826 }
2827
2828 if ((proc = PyObject_New(struct pyproc, &pyproc_type)) == NULL) {
2829 close(in_pipe[0]);
2830 close(in_pipe[1]);
2831 close(out_pipe[0]);
2832 close(out_pipe[1]);
2833 return (NULL);
2834 }
2835
2836 proc->pid = -1;
2837 proc->op = NULL;
2838 proc->apid = -1;
2839 proc->reaped = 0;
2840 proc->status = 0;
2841 proc->timer = NULL;
2842 proc->coro = coro_running;
2843 proc->in = pysocket_alloc();
2844 proc->out = pysocket_alloc();
2845
2846 if (proc->in == NULL || proc->out == NULL) {
2847 Py_DECREF((PyObject *)proc);
2848 return (NULL);
2849 }
2850
2851 TAILQ_INSERT_TAIL(&procs, proc, list);
2852
2853 proc->pid = fork();
2854 if (proc->pid == -1) {
2855 if (errno == ENOSYS) {
2856 Py_DECREF((PyObject *)proc);
2857 PyErr_SetString(PyExc_RuntimeError, errno_s);
2858 return (NULL);
2859 }
2860 fatal("python_kore_proc: fork(): %s", errno_s);
2861 }
2862
2863 if (proc->pid == 0) {
2864 close(in_pipe[1]);
2865 close(out_pipe[0]);
2866
2867 if (dup2(out_pipe[1], STDOUT_FILENO) == -1 ||
2868 dup2(out_pipe[1], STDERR_FILENO) == -1 ||
2869 dup2(in_pipe[0], STDIN_FILENO) == -1)
2870 fatal("dup2: %s", errno_s);
2871
2872 copy = kore_strdup(cmd);
2873 python_split_arguments(copy, argv, 32);
2874
2875 (void)execve(argv[0], argv, env);
2876 kore_log(LOG_ERR, "kore.proc failed to execute %s (%s)",
2877 argv[0], errno_s);
2878 exit(1);
2879 }
2880
2881 close(in_pipe[0]);
2882 close(out_pipe[1]);
2883
2884 if (!kore_connection_nonblock(in_pipe[1], 0) ||
2885 !kore_connection_nonblock(out_pipe[0], 0))
2886 fatal("failed to mark kore.proc pipes are non-blocking");
2887
2888 proc->apid = proc->pid;
2889 proc->in->fd = in_pipe[1];
2890 proc->out->fd = out_pipe[0];
2891
2892 if (timeo != -1) {
2893 proc->timer = kore_timer_add(pyproc_timeout,
2894 timeo, proc, KORE_TIMER_ONESHOT);
2895 }
2896
2897 return ((PyObject *)proc);
2898 }
2899
2900 static PyObject *
2901 python_import(const char *path)
2902 {
2903 struct stat st;
2904 PyObject *module;
2905 char *dir, *file, *copy, *p;
2906
2907 if (stat(path, &st) == -1)
2908 fatal("python_import: stat(%s): %s", path, errno_s);
2909
2910 if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode))
2911 fatal("python_import: '%s' is not a file or directory", path);
2912
2913 copy = kore_strdup(path);
2914 if ((p = dirname(copy)) == NULL)
2915 fatal("dirname: %s: %s", path, errno_s);
2916
2917 dir = kore_strdup(p);
2918 kore_free(copy);
2919
2920 copy = kore_strdup(path);
2921 if ((p = basename(copy)) == NULL)
2922 fatal("basename: %s: %s", path, errno_s);
2923
2924 file = kore_strdup(p);
2925 kore_free(copy);
2926
2927 if ((p = strrchr(file, '.')) != NULL)
2928 *p = '\0';
2929
2930 python_append_path(dir);
2931
2932 if (S_ISDIR(st.st_mode))
2933 python_append_path(path);
2934
2935 module = PyImport_ImportModule(file);
2936 if (module == NULL)
2937 PyErr_Print();
2938
2939 kore_free(dir);
2940 kore_free(file);
2941
2942 return (module);
2943 }
2944
2945 static PyObject *
2946 python_callable(PyObject *module, const char *symbol)
2947 {
2948 char *base, *method;
2949 PyObject *res, *obj, *meth;
2950
2951 res = NULL;
2952 obj = NULL;
2953 base = kore_strdup(symbol);
2954
2955 if ((method = strchr(base, '.')) != NULL)
2956 *(method)++ = '\0';
2957
2958 if ((obj = PyObject_GetAttrString(module, base)) == NULL)
2959 goto out;
2960
2961 if (method != NULL) {
2962 if ((meth = PyObject_GetAttrString(obj, method)) == NULL)
2963 goto out;
2964
2965 Py_DECREF(obj);
2966 obj = meth;
2967 }
2968
2969 if (!PyCallable_Check(obj))
2970 goto out;
2971
2972 res = obj;
2973 obj = NULL;
2974
2975 out:
2976 if (obj != NULL)
2977 Py_DECREF(obj);
2978
2979 PyErr_Clear();
2980 kore_free(base);
2981
2982 return (res);
2983 }
2984
2985 static PyObject *
2986 pyconnection_alloc(struct connection *c)
2987 {
2988 struct pyconnection *pyc;
2989
2990 pyc = PyObject_New(struct pyconnection, &pyconnection_type);
2991 if (pyc == NULL)
2992 return (NULL);
2993
2994 pyc->c = c;
2995
2996 return ((PyObject *)pyc);
2997 }
2998
2999 static PyObject *
3000 pyconnection_disconnect(struct pyconnection *pyc, PyObject *args)
3001 {
3002 kore_connection_disconnect(pyc->c);
3003
3004 Py_RETURN_TRUE;
3005 }
3006
3007 static PyObject *
3008 pyconnection_get_fd(struct pyconnection *pyc, void *closure)
3009 {
3010 PyObject *fd;
3011
3012 if ((fd = PyLong_FromLong(pyc->c->fd)) == NULL)
3013 return (PyErr_NoMemory());
3014
3015 return (fd);
3016 }
3017
3018 static PyObject *
3019 pyconnection_get_addr(struct pyconnection *pyc, void *closure)
3020 {
3021 void *ptr;
3022 PyObject *result;
3023 char addr[INET6_ADDRSTRLEN];
3024
3025 switch (pyc->c->family) {
3026 case AF_INET:
3027 ptr = &pyc->c->addr.ipv4.sin_addr;
3028 break;
3029 case AF_INET6:
3030 ptr = &pyc->c->addr.ipv6.sin6_addr;
3031 break;
3032 default:
3033 PyErr_SetString(PyExc_RuntimeError, "invalid family");
3034 return (NULL);
3035 }
3036
3037 if (inet_ntop(pyc->c->family, ptr, addr, sizeof(addr)) == NULL) {
3038 PyErr_SetString(PyExc_RuntimeError, "inet_ntop failed");
3039 return (NULL);
3040 }
3041
3042 if ((result = PyUnicode_FromString(addr)) == NULL)
3043 return (PyErr_NoMemory());
3044
3045 return (result);
3046 }
3047
3048 static PyObject *
3049 pyconnection_get_peer_x509(struct pyconnection *pyc, void *closure)
3050 {
3051 size_t len;
3052 u_int8_t *der;
3053 PyObject *bytes;
3054
3055 if (pyc->c->tls_cert == NULL) {
3056 Py_RETURN_NONE;
3057 }
3058
3059 if (!kore_tls_x509_data(pyc->c, &der, &len)) {
3060 PyErr_SetString(PyExc_RuntimeError,
3061 "failed to obtain certificate data");
3062 return (NULL);
3063 }
3064
3065 bytes = PyBytes_FromStringAndSize((char *)der, len);
3066 kore_free(der);
3067
3068 return (bytes);
3069 }
3070
3071 static PyObject *
3072 pyconnection_get_peer_x509dict(struct pyconnection *pyc, void *closure)
3073 {
3074 KORE_X509_NAMES *name;
3075 PyObject *dict, *issuer, *subject, *ret;
3076
3077 ret = NULL;
3078 issuer = NULL;
3079 subject = NULL;
3080
3081 if (pyc->c->tls_cert == NULL) {
3082 Py_RETURN_NONE;
3083 }
3084
3085 if ((dict = PyDict_New()) == NULL)
3086 goto out;
3087
3088 if ((issuer = PyDict_New()) == NULL)
3089 goto out;
3090
3091 if (PyDict_SetItemString(dict, "issuer", issuer) == -1)
3092 goto out;
3093
3094 if ((subject = PyDict_New()) == NULL)
3095 goto out;
3096
3097 if (PyDict_SetItemString(dict, "subject", subject) == -1)
3098 goto out;
3099
3100 PyErr_Clear();
3101
3102 if ((name = kore_tls_x509_subject_name(pyc->c)) == NULL) {
3103 PyErr_Format(PyExc_RuntimeError,
3104 "failed to obtain x509 subjectName");
3105 goto out;
3106 }
3107
3108 if (!kore_tls_x509name_foreach(name, 0, subject,
3109 pyconnection_x509_cb)) {
3110 if (PyErr_Occurred() == NULL) {
3111 PyErr_Format(PyExc_RuntimeError,
3112 "failed to add subject name to dictionary");
3113 }
3114 goto out;
3115 }
3116
3117 if ((name = kore_tls_x509_issuer_name(pyc->c)) == NULL) {
3118 PyErr_Format(PyExc_RuntimeError,
3119 "failed to obtain x509 issuerName");
3120 goto out;
3121 }
3122
3123 if (!kore_tls_x509name_foreach(name, 0, issuer, pyconnection_x509_cb)) {
3124 if (PyErr_Occurred() == NULL) {
3125 PyErr_Format(PyExc_RuntimeError,
3126 "failed to add issuer name to dictionary");
3127 }
3128 goto out;
3129 }
3130
3131 ret = dict;
3132 dict = NULL;
3133
3134 out:
3135 Py_XDECREF(dict);
3136 Py_XDECREF(issuer);
3137 Py_XDECREF(subject);
3138
3139 return (ret);
3140 }
3141
3142 static int
3143 pyconnection_x509_cb(void *udata, int islast, int nid, const char *field,
3144 const void *data, size_t len, int flags)
3145 {
3146 PyObject *dict, *obj;
3147
3148 dict = udata;
3149
3150 if ((obj = PyUnicode_FromStringAndSize(data, len)) == NULL)
3151 return (KORE_RESULT_ERROR);
3152
3153 if (PyDict_SetItemString(dict, field, obj) == -1) {
3154 Py_DECREF(obj);
3155 return (KORE_RESULT_ERROR);
3156 }
3157
3158 Py_DECREF(obj);
3159 return (KORE_RESULT_OK);
3160 }
3161
3162 static void
3163 pytimer_run(void *arg, u_int64_t now)
3164 {
3165 PyObject *ret;
3166 struct pytimer *timer = arg;
3167
3168 PyErr_Clear();
3169 ret = PyObject_CallFunctionObjArgs(timer->callable, timer->udata, NULL);
3170 Py_XDECREF(ret);
3171 Py_XDECREF(timer->udata);
3172
3173 timer->udata = NULL;
3174 kore_python_log_error("pytimer_run");
3175
3176 if (timer->flags & KORE_TIMER_ONESHOT) {
3177 timer->run = NULL;
3178 Py_DECREF((PyObject *)timer);
3179 }
3180 }
3181
3182 static void
3183 pytimer_dealloc(struct pytimer *timer)
3184 {
3185 if (timer->run != NULL) {
3186 kore_timer_remove(timer->run);
3187 timer->run = NULL;
3188 }
3189
3190 if (timer->callable != NULL) {
3191 Py_DECREF(timer->callable);
3192 timer->callable = NULL;
3193 }
3194
3195 PyObject_Del((PyObject *)timer);
3196 }
3197
3198 static PyObject *
3199 pytimer_close(struct pytimer *timer, PyObject *args)
3200 {
3201 if (timer->run != NULL) {
3202 kore_timer_remove(timer->run);
3203 timer->run = NULL;
3204 }
3205
3206 if (timer->callable != NULL) {
3207 Py_DECREF(timer->callable);
3208 timer->callable = NULL;
3209 }
3210
3211 if (timer->udata != NULL) {
3212 Py_DECREF(timer->udata);
3213 timer->udata = NULL;
3214 }
3215
3216 Py_INCREF((PyObject *)timer);
3217 Py_RETURN_TRUE;
3218 }
3219
3220 static void
3221 pysuspend_op_dealloc(struct pysuspend_op *op)
3222 {
3223 if (op->timer != NULL) {
3224 kore_timer_remove(op->timer);
3225 op->timer = NULL;
3226 }
3227
3228 PyObject_Del((PyObject *)op);
3229 }
3230
3231 static PyObject *
3232 pysuspend_op_await(PyObject *sop)
3233 {
3234 Py_INCREF(sop);
3235 return (sop);
3236 }
3237
3238 static PyObject *
3239 pysuspend_op_iternext(struct pysuspend_op *op)
3240 {
3241 switch (op->state) {
3242 case PYSUSPEND_OP_INIT:
3243 op->timer = kore_timer_add(pysuspend_wakeup, op->delay,
3244 op, KORE_TIMER_ONESHOT);
3245 op->state = PYSUSPEND_OP_WAIT;
3246 break;
3247 case PYSUSPEND_OP_WAIT:
3248 break;
3249 case PYSUSPEND_OP_CONTINUE:
3250 PyErr_SetNone(PyExc_StopIteration);
3251 return (NULL);
3252 default:
3253 fatal("unknown state %d for pysuspend_op", op->state);
3254 }
3255
3256 Py_RETURN_NONE;
3257 }
3258
3259 static void
3260 pysuspend_wakeup(void *arg, u_int64_t now)
3261 {
3262 struct pysuspend_op *op = arg;
3263
3264 op->timer = NULL;
3265 op->state = PYSUSPEND_OP_CONTINUE;
3266
3267 if (op->coro->request != NULL)
3268 http_request_wakeup(op->coro->request);
3269 else
3270 python_coro_wakeup(op->coro);
3271 }
3272
3273 static struct pysocket *
3274 pysocket_alloc(void)
3275 {
3276 struct pysocket *sock;
3277
3278 if ((sock = PyObject_New(struct pysocket, &pysocket_type)) == NULL)
3279 return (NULL);
3280
3281 sock->fd = -1;
3282 sock->family = -1;
3283 sock->protocol = -1;
3284 sock->scheduled = 0;
3285
3286 sock->socket = NULL;
3287 sock->recvop = NULL;
3288 sock->sendop = NULL;
3289
3290 sock->event.s = sock;
3291 sock->event.evt.flags = 0;
3292 sock->event.evt.type = KORE_TYPE_PYSOCKET;
3293 sock->event.evt.handle = pysocket_evt_handle;
3294
3295 return (sock);
3296 }
3297
3298 static void
3299 pysocket_dealloc(struct pysocket *sock)
3300 {
3301 if (sock->scheduled && sock->fd != -1) {
3302 kore_platform_disable_read(sock->fd);
3303 #if !defined(__linux__)
3304 kore_platform_disable_write(sock->fd);
3305 #endif
3306 }
3307
3308 if (sock->socket != NULL) {
3309 Py_DECREF(sock->socket);
3310 } else if (sock->fd != -1) {
3311 (void)close(sock->fd);
3312 }
3313
3314 PyObject_Del((PyObject *)sock);
3315 }
3316
3317 static PyObject *
3318 pysocket_send(struct pysocket *sock, PyObject *args)
3319 {
3320 Py_buffer buf;
3321 PyObject *ret;
3322
3323 if (!PyArg_ParseTuple(args, "y*", &buf))
3324 return (NULL);
3325
3326 ret = pysocket_op_create(sock, PYSOCKET_TYPE_SEND, buf.buf, buf.len);
3327 PyBuffer_Release(&buf);
3328
3329 return (ret);
3330 }
3331
3332 static PyObject *
3333 pysocket_sendto(struct pysocket *sock, PyObject *args)
3334 {
3335 Py_buffer buf;
3336 struct pysocket_op *op;
3337 PyObject *ret;
3338 int port;
3339 const char *ip, *sockaddr;
3340
3341 switch (sock->family) {
3342 case AF_INET:
3343 if (!PyArg_ParseTuple(args, "siy*", &ip, &port, &buf))
3344 return (NULL);
3345 if (port <= 0 || port >= USHRT_MAX) {
3346 PyErr_SetString(PyExc_RuntimeError, "invalid port");
3347 return (NULL);
3348 }
3349 break;
3350 case AF_UNIX:
3351 if (!PyArg_ParseTuple(args, "sy*", &sockaddr, &buf))
3352 return (NULL);
3353 break;
3354 default:
3355 PyErr_SetString(PyExc_RuntimeError, "unsupported family");
3356 return (NULL);
3357 }
3358
3359 ret = pysocket_op_create(sock, PYSOCKET_TYPE_SENDTO, buf.buf, buf.len);
3360 PyBuffer_Release(&buf);
3361
3362 op = (struct pysocket_op *)ret;
3363
3364 switch (sock->family) {
3365 case AF_INET:
3366 op->sendaddr.ipv4.sin_family = AF_INET;
3367 op->sendaddr.ipv4.sin_port = htons(port);
3368 op->sendaddr.ipv4.sin_addr.s_addr = inet_addr(ip);
3369 break;
3370 case AF_UNIX:
3371 op->sendaddr.sun.sun_family = AF_UNIX;
3372 if (kore_strlcpy(op->sendaddr.sun.sun_path, sockaddr,
3373 sizeof(op->sendaddr.sun.sun_path)) >=
3374 sizeof(op->sendaddr.sun.sun_path)) {
3375 Py_DECREF(ret);
3376 PyErr_SetString(PyExc_RuntimeError,
3377 "unix socket path too long");
3378 return (NULL);
3379 }
3380 break;
3381 default:
3382 Py_DECREF(ret);
3383 PyErr_SetString(PyExc_RuntimeError, "unsupported family");
3384 return (NULL);
3385 }
3386
3387 return (ret);
3388 }
3389
3390 static PyObject *
3391 pysocket_recv(struct pysocket *sock, PyObject *args)
3392 {
3393 Py_ssize_t len;
3394 struct pysocket_op *op;
3395 PyObject *obj;
3396 int timeo;
3397
3398 timeo = -1;
3399
3400 if (!PyArg_ParseTuple(args, "n|i", &len, &timeo))
3401 return (NULL);
3402
3403 obj = pysocket_op_create(sock, PYSOCKET_TYPE_RECV, NULL, len);
3404 if (obj == NULL)
3405 return (NULL);
3406
3407 op = (struct pysocket_op *)obj;
3408
3409 if (timeo != -1) {
3410 op->timer = kore_timer_add(pysocket_op_timeout,
3411 timeo, op, KORE_TIMER_ONESHOT);
3412 }
3413
3414 return (obj);
3415 }
3416
3417 static PyObject *
3418 pysocket_recvmsg(struct pysocket *sock, PyObject *args)
3419 {
3420 Py_ssize_t len;
3421
3422 if (!PyArg_ParseTuple(args, "n", &len))
3423 return (NULL);
3424
3425 return (pysocket_op_create(sock, PYSOCKET_TYPE_RECVMSG, NULL, len));
3426 }
3427
3428 static PyObject *
3429 pysocket_recvfrom(struct pysocket *sock, PyObject *args)
3430 {
3431 Py_ssize_t len;
3432
3433 if (!PyArg_ParseTuple(args, "n", &len))
3434 return (NULL);
3435
3436 return (pysocket_op_create(sock, PYSOCKET_TYPE_RECVFROM, NULL, len));
3437 }
3438
3439 static PyObject *
3440 pysocket_accept(struct pysocket *sock, PyObject *args)
3441 {
3442 return (pysocket_op_create(sock, PYSOCKET_TYPE_ACCEPT, NULL, 0));
3443 }
3444
3445 static PyObject *
3446 pysocket_connect(struct pysocket *sock, PyObject *args)
3447 {
3448 const char *host;
3449 int port, len;
3450
3451 port = 0;
3452
3453 if (!PyArg_ParseTuple(args, "s|i", &host, &port))
3454 return (NULL);
3455
3456 if (port < 0 || port > USHRT_MAX) {
3457 PyErr_SetString(PyExc_RuntimeError, "invalid port number");
3458 return (NULL);
3459 }
3460
3461 switch (sock->family) {
3462 case AF_INET:
3463 sock->addr.ipv4.sin_family = AF_INET;
3464 sock->addr.ipv4.sin_port = htons(port);
3465 if (inet_pton(sock->family, host,
3466 &sock->addr.ipv4.sin_addr) == -1) {
3467 PyErr_SetString(PyExc_RuntimeError, "invalid host");
3468 return (NULL);
3469 }
3470 sock->addr_len = sizeof(sock->addr.ipv4);
3471 break;
3472 case AF_UNIX:
3473 sock->addr.sun.sun_family = AF_UNIX;
3474 len = snprintf(sock->addr.sun.sun_path,
3475 sizeof(sock->addr.sun.sun_path), "%s", host);
3476 if (len == -1 ||
3477 (size_t)len >= sizeof(sock->addr.sun.sun_path)) {
3478 PyErr_SetString(PyExc_RuntimeError, "path too long");
3479 return (NULL);
3480 }
3481 #if defined(__linux__)
3482 /* Assume abstract socket if prefixed with '@'. */
3483 if (sock->addr.sun.sun_path[0] == '@')
3484 sock->addr.sun.sun_path[0] = '\0';
3485 #endif
3486 sock->addr_len = sizeof(sock->addr.sun.sun_family) + len;
3487 break;
3488 default:
3489 fatal("unsupported socket family %d", sock->family);
3490 }
3491
3492 return (pysocket_op_create(sock, PYSOCKET_TYPE_CONNECT, NULL, 0));
3493 }
3494
3495 static PyObject *
3496 pysocket_close(struct pysocket *sock, PyObject *args)
3497 {
3498 if (sock->scheduled) {
3499 sock->scheduled = 0;
3500 kore_platform_disable_read(sock->fd);
3501 #if !defined(__linux__)
3502 kore_platform_disable_write(sock->fd);
3503 #endif
3504 }
3505
3506 if (sock->socket != NULL) {
3507 Py_DECREF(sock->socket);
3508 sock->socket = NULL;
3509 } else if (sock->fd != -1) {
3510 (void)close(sock->fd);
3511 }
3512
3513 sock->fd = -1;
3514 sock->event.evt.handle(&sock->event, 1);
3515
3516 Py_RETURN_TRUE;
3517 }
3518
3519 static void
3520 pysocket_op_dealloc(struct pysocket_op *op)
3521 {
3522 if (op->type == PYSOCKET_TYPE_RECV ||
3523 op->type == PYSOCKET_TYPE_RECVMSG ||
3524 op->type == PYSOCKET_TYPE_RECVFROM ||
3525 op->type == PYSOCKET_TYPE_SEND ||
3526 op->type == PYSOCKET_TYPE_SENDTO)
3527 kore_buf_cleanup(&op->buffer);
3528
3529 switch (op->type) {
3530 case PYSOCKET_TYPE_RECV:
3531 case PYSOCKET_TYPE_ACCEPT:
3532 case PYSOCKET_TYPE_RECVMSG:
3533 case PYSOCKET_TYPE_RECVFROM:
3534 if (op->socket->recvop != op)
3535 fatal("recvop mismatch");
3536 op->socket->recvop = NULL;
3537 break;
3538 case PYSOCKET_TYPE_SEND:
3539 case PYSOCKET_TYPE_SENDTO:
3540 case PYSOCKET_TYPE_CONNECT:
3541 if (op->socket->sendop != op)
3542 fatal("sendop mismatch");
3543 op->socket->sendop = NULL;
3544 break;
3545 }
3546
3547 if (op->timer != NULL) {
3548 kore_timer_remove(op->timer);
3549 op->timer = NULL;
3550 }
3551
3552 op->coro->sockop = NULL;
3553 Py_DECREF(op->socket);
3554
3555 PyObject_Del((PyObject *)op);
3556 }
3557
3558 static PyObject *
3559 pysocket_op_create(struct pysocket *sock, int type, const void *ptr, size_t len)
3560 {
3561 struct pysocket_op *op;
3562
3563 if (coro_running->sockop != NULL)
3564 fatal("pysocket_op_create: coro has active socketop");
3565
3566 switch (type) {
3567 case PYSOCKET_TYPE_RECV:
3568 case PYSOCKET_TYPE_ACCEPT:
3569 case PYSOCKET_TYPE_RECVMSG:
3570 case PYSOCKET_TYPE_RECVFROM:
3571 if (sock->recvop != NULL) {
3572 PyErr_SetString(PyExc_RuntimeError,
3573 "only one recv operation can be done per socket");
3574 return (NULL);
3575 }
3576 break;
3577 case PYSOCKET_TYPE_SEND:
3578 case PYSOCKET_TYPE_SENDTO:
3579 case PYSOCKET_TYPE_CONNECT:
3580 if (sock->sendop != NULL) {
3581 PyErr_SetString(PyExc_RuntimeError,
3582 "only one send operation can be done per socket");
3583 return (NULL);
3584 }
3585 break;
3586 default:
3587 fatal("unknown pysocket_op type %u", type);
3588 }
3589
3590 op = PyObject_New(struct pysocket_op, &pysocket_op_type);
3591 if (op == NULL)
3592 return (NULL);
3593
3594 op->eof = 0;
3595 op->self = op;
3596 op->type = type;
3597 op->timer = NULL;
3598 op->socket = sock;
3599 op->coro = coro_running;
3600
3601 coro_running->sockop = op;
3602 Py_INCREF(op->socket);
3603
3604 switch (type) {
3605 case PYSOCKET_TYPE_RECV:
3606 case PYSOCKET_TYPE_RECVMSG:
3607 case PYSOCKET_TYPE_RECVFROM:
3608 sock->recvop = op;
3609 kore_buf_init(&op->buffer, len);
3610 break;
3611 case PYSOCKET_TYPE_SEND:
3612 case PYSOCKET_TYPE_SENDTO:
3613 sock->sendop = op;
3614 kore_buf_init(&op->buffer, len);
3615 kore_buf_append(&op->buffer, ptr, len);
3616 kore_buf_reset(&op->buffer);
3617 break;
3618 case PYSOCKET_TYPE_ACCEPT:
3619 sock->recvop = op;
3620 break;
3621 case PYSOCKET_TYPE_CONNECT:
3622 sock->sendop = op;
3623 break;
3624 default:
3625 fatal("unknown pysocket_op type %u", type);
3626 }
3627
3628 if (sock->scheduled == 0) {
3629 sock->scheduled = 1;
3630 kore_platform_event_all(sock->fd, &sock->event);
3631 }
3632
3633 return ((PyObject *)op);
3634 }
3635
3636 static PyObject *
3637 pysocket_op_await(PyObject *obj)
3638 {
3639 Py_INCREF(obj);
3640 return (obj);
3641 }
3642
3643 static PyObject *
3644 pysocket_op_iternext(struct pysocket_op *op)
3645 {
3646 PyObject *ret;
3647
3648 if (op->socket->fd == -1) {
3649 PyErr_SetNone(PyExc_StopIteration);
3650 return (NULL);
3651 }
3652
3653 if (op->eof) {
3654 if (op->coro->exception != NULL) {
3655 PyErr_SetString(op->coro->exception,
3656 op->coro->exception_msg);
3657 op->coro->exception = NULL;
3658 return (NULL);
3659 }
3660
3661 if (op->type != PYSOCKET_TYPE_RECV) {
3662 PyErr_SetString(PyExc_RuntimeError, "socket EOF");
3663 return (NULL);
3664 }
3665
3666 /* Drain the recv socket. */
3667 op->socket->event.evt.flags |= KORE_EVENT_READ;
3668 return (pysocket_async_recv(op));
3669 }
3670
3671 switch (op->type) {
3672 case PYSOCKET_TYPE_CONNECT:
3673 ret = pysocket_async_connect(op);
3674 break;
3675 case PYSOCKET_TYPE_ACCEPT:
3676 ret = pysocket_async_accept(op);
3677 break;
3678 case PYSOCKET_TYPE_RECV:
3679 case PYSOCKET_TYPE_RECVMSG:
3680 case PYSOCKET_TYPE_RECVFROM:
3681 ret = pysocket_async_recv(op);
3682 break;
3683 case PYSOCKET_TYPE_SEND:
3684 case PYSOCKET_TYPE_SENDTO:
3685 ret = pysocket_async_send(op);
3686 break;
3687 default:
3688 PyErr_SetString(PyExc_RuntimeError, "invalid op type");
3689 return (NULL);
3690 }
3691
3692 return (ret);
3693 }
3694
3695 static void
3696 pysocket_op_timeout(void *arg, u_int64_t now)
3697 {
3698 struct pysocket_op *op = arg;
3699
3700 op->eof = 1;
3701 op->timer = NULL;
3702
3703 op->coro->exception = PyExc_TimeoutError;
3704 op->coro->exception_msg = "timeout before operation completed";
3705
3706 if (op->coro->request != NULL)
3707 http_request_wakeup(op->coro->request);
3708 else
3709 python_coro_wakeup(op->coro);
3710 }
3711
3712 static PyObject *
3713 pysocket_async_connect(struct pysocket_op *op)
3714 {
3715 if (connect(op->socket->fd, (struct sockaddr *)&op->socket->addr,
3716 op->socket->addr_len) == -1) {
3717 if (errno != EALREADY && errno != EINPROGRESS &&
3718 errno != EISCONN && errno != EAGAIN) {
3719 PyErr_SetString(PyExc_RuntimeError, errno_s);
3720 return (NULL);
3721 }
3722
3723 if (errno != EISCONN) {
3724 Py_RETURN_NONE;
3725 }
3726 }
3727
3728 PyErr_SetNone(PyExc_StopIteration);
3729 return (NULL);
3730 }
3731
3732 static PyObject *
3733 pysocket_async_accept(struct pysocket_op *op)
3734 {
3735 int fd;
3736 struct pysocket *sock;
3737
3738 if (!(op->socket->event.evt.flags & KORE_EVENT_READ)) {
3739 Py_RETURN_NONE;
3740 }
3741
3742 if ((sock = pysocket_alloc()) == NULL)
3743 return (NULL);
3744
3745 sock->addr_len = sizeof(sock->addr);
3746
3747 if ((fd = accept(op->socket->fd,
3748 (struct sockaddr *)&sock->addr, &sock->addr_len)) == -1) {
3749 Py_DECREF((PyObject *)sock);
3750 if (errno == EAGAIN || errno == EWOULDBLOCK) {
3751 op->socket->event.evt.flags &= ~KORE_EVENT_READ;
3752 Py_RETURN_NONE;
3753 }
3754 PyErr_SetString(PyExc_RuntimeError, errno_s);
3755 return (NULL);
3756 }
3757
3758 if (!kore_connection_nonblock(fd, 0)) {
3759 Py_DECREF((PyObject *)sock);
3760 PyErr_SetString(PyExc_RuntimeError, errno_s);
3761 return (NULL);
3762 }
3763
3764 sock->fd = fd;
3765 sock->socket = NULL;
3766 sock->family = op->socket->family;
3767 sock->protocol = op->socket->protocol;
3768
3769 PyErr_SetObject(PyExc_StopIteration, (PyObject *)sock);
3770 Py_DECREF((PyObject *)sock);
3771
3772 return (NULL);
3773 }
3774
3775 static PyObject *
3776 pysocket_async_recv(struct pysocket_op *op)
3777 {
3778 ssize_t ret;
3779 size_t len;
3780 u_int16_t port;
3781 struct iovec iov;
3782 struct msghdr msg;
3783 socklen_t socklen;
3784 struct sockaddr *sendaddr;
3785 const char *ptr, *ip;
3786 u_int8_t ancdata[1024];
3787 PyObject *bytes, *result, *tuple, *list;
3788
3789 if (!(op->socket->event.evt.flags & KORE_EVENT_READ)) {
3790 Py_RETURN_NONE;
3791 }
3792
3793 socklen = 0;
3794
3795 for (;;) {
3796 switch (op->type) {
3797 case PYSOCKET_TYPE_RECV:
3798 ret = read(op->socket->fd, op->buffer.data,
3799 op->buffer.length);
3800 break;
3801 case PYSOCKET_TYPE_RECVMSG:
3802 memset(&msg, 0, sizeof(msg));
3803
3804 iov.iov_base = op->buffer.data;
3805 iov.iov_len = op->buffer.length;
3806
3807 msg.msg_iov = &iov;
3808 msg.msg_iovlen = 1;
3809 msg.msg_name = &op->sendaddr;
3810 msg.msg_namelen = sizeof(op->sendaddr);
3811 msg.msg_control = ancdata;
3812 msg.msg_controllen = sizeof(ancdata);
3813
3814 memset(&op->sendaddr, 0, sizeof(op->sendaddr));
3815 ret = recvmsg(op->socket->fd, &msg, 0);
3816 break;
3817 case PYSOCKET_TYPE_RECVFROM:
3818 sendaddr = (struct sockaddr *)&op->sendaddr;
3819 switch (op->socket->family) {
3820 case AF_INET:
3821 socklen = sizeof(op->sendaddr.ipv4);
3822 break;
3823 case AF_UNIX:
3824 socklen = sizeof(op->sendaddr.sun);
3825 break;
3826 default:
3827 fatal("%s: non AF_INET/AF_UNIX", __func__);
3828 }
3829
3830 memset(sendaddr, 0, socklen);
3831 ret = recvfrom(op->socket->fd, op->buffer.data,
3832 op->buffer.length, 0, sendaddr, &socklen);
3833 break;
3834 default:
3835 fatal("%s: unknown type %d", __func__, op->type);
3836 }
3837
3838 if (ret == -1) {
3839 if (errno == EINTR)
3840 continue;
3841 if (errno == EAGAIN || errno == EWOULDBLOCK) {
3842 op->socket->event.evt.flags &= ~KORE_EVENT_READ;
3843 Py_RETURN_NONE;
3844 }
3845 PyErr_SetString(PyExc_RuntimeError, errno_s);
3846 return (NULL);
3847 }
3848
3849 break;
3850 }
3851
3852 op->coro->exception = NULL;
3853 op->coro->exception_msg = NULL;
3854
3855 if (op->timer != NULL) {
3856 kore_timer_remove(op->timer);
3857 op->timer = NULL;
3858 }
3859
3860 if (op->type == PYSOCKET_TYPE_RECV && ret == 0) {
3861 PyErr_SetNone(PyExc_StopIteration);
3862 return (NULL);
3863 }
3864
3865 ptr = (const char *)op->buffer.data;
3866 if ((bytes = PyBytes_FromStringAndSize(ptr, ret)) == NULL)
3867 return (NULL);
3868
3869 list = NULL;
3870
3871 switch (op->type) {
3872 case PYSOCKET_TYPE_RECV:
3873 PyErr_SetObject(PyExc_StopIteration, bytes);
3874 Py_DECREF(bytes);
3875 return (NULL);
3876 case PYSOCKET_TYPE_RECVMSG:
3877 socklen = msg.msg_namelen;
3878 if ((list = python_cmsg_to_list(&msg)) == NULL) {
3879 Py_DECREF(bytes);
3880 return (NULL);
3881 }
3882 break;
3883 case PYSOCKET_TYPE_RECVFROM:
3884 break;
3885 default:
3886 fatal("%s: unknown type %d", __func__, op->type);
3887 }
3888
3889 switch(op->socket->family) {
3890 case AF_INET:
3891 port = ntohs(op->sendaddr.ipv4.sin_port);
3892 ip = inet_ntoa(op->sendaddr.ipv4.sin_addr);
3893
3894 if (op->type == PYSOCKET_TYPE_RECVFROM)
3895 tuple = Py_BuildValue("(sHN)", ip, port, bytes);
3896 else
3897 tuple = Py_BuildValue("(sHNN)", ip, port, bytes, list);
3898 break;
3899 case AF_UNIX:
3900 len = strlen(op->sendaddr.sun.sun_path);
3901 #if defined(__linux__)
3902 if (len == 0 && socklen > 0) {
3903 len = socklen - sizeof(sa_family_t);
3904 op->sendaddr.sun.sun_path[0] = '@';
3905 op->sendaddr.sun.sun_path[len] = '\0';
3906 }
3907 #endif
3908 if (len == 0) {
3909 if (op->type == PYSOCKET_TYPE_RECVFROM) {
3910 tuple = Py_BuildValue("(ON)", Py_None, bytes);
3911 } else {
3912 tuple = Py_BuildValue("(ONN)",
3913 Py_None, bytes, list);
3914 }
3915 } else {
3916 if (op->type == PYSOCKET_TYPE_RECVFROM) {
3917 tuple = Py_BuildValue("(sN)",
3918 op->sendaddr.sun.sun_path, bytes);
3919 } else {
3920 tuple = Py_BuildValue("(sNN)",
3921 op->sendaddr.sun.sun_path, bytes, list);
3922 }
3923 }
3924 break;
3925 default:
3926 fatal("%s: non AF_INET/AF_UNIX", __func__);
3927 }
3928
3929 if (tuple == NULL) {
3930 Py_XDECREF(list);
3931 Py_DECREF(bytes);
3932 return (NULL);
3933 }
3934
3935 result = PyObject_CallFunctionObjArgs(PyExc_StopIteration, tuple, NULL);
3936 if (result == NULL) {
3937 Py_DECREF(tuple);
3938 return (NULL);
3939 }
3940
3941 Py_DECREF(tuple);
3942 PyErr_SetObject(PyExc_StopIteration, result);
3943 Py_DECREF(result);
3944
3945 return (NULL);
3946 }
3947
3948 static PyObject *
3949 pysocket_async_send(struct pysocket_op *op)
3950 {
3951 ssize_t ret;
3952 socklen_t socklen;
3953 const struct sockaddr *sendaddr;
3954
3955 if (!(op->socket->event.evt.flags & KORE_EVENT_WRITE)) {
3956 Py_RETURN_NONE;
3957 }
3958
3959 for (;;) {
3960 if (op->type == PYSOCKET_TYPE_SEND) {
3961 ret = write(op->socket->fd,
3962 op->buffer.data + op->buffer.offset,
3963 op->buffer.length - op->buffer.offset);
3964 } else {
3965 sendaddr = (const struct sockaddr *)&op->sendaddr;
3966
3967 switch (op->socket->family) {
3968 case AF_INET:
3969 socklen = sizeof(op->sendaddr.ipv4);
3970 break;
3971 case AF_UNIX:
3972 socklen = sizeof(op->sendaddr.sun);
3973 #if defined(__linux__)
3974 if (op->sendaddr.sun.sun_path[0] == '@') {
3975 socklen = sizeof(sa_family_t) +
3976 strlen(op->sendaddr.sun.sun_path);
3977 op->sendaddr.sun.sun_path[0] = '\0';
3978 }
3979 #endif
3980 break;
3981 default:
3982 fatal("non AF_INET/AF_UNIX in %s", __func__);
3983 }
3984
3985 ret = sendto(op->socket->fd,
3986 op->buffer.data + op->buffer.offset,
3987 op->buffer.length - op->buffer.offset,
3988 0, sendaddr, socklen);
3989 }
3990
3991 if (ret == -1) {
3992 if (errno == EINTR)
3993 continue;
3994 if (errno == EAGAIN || errno == EWOULDBLOCK) {
3995 op->socket->event.evt.flags &=
3996 ~KORE_EVENT_WRITE;
3997 Py_RETURN_NONE;
3998 }
3999 PyErr_SetString(PyExc_RuntimeError, errno_s);
4000 return (NULL);
4001 }
4002 break;
4003 }
4004
4005 op->buffer.offset += (size_t)ret;
4006
4007 if (op->buffer.offset == op->buffer.length) {
4008 PyErr_SetNone(PyExc_StopIteration);
4009 return (NULL);
4010 }
4011
4012 Py_RETURN_NONE;
4013 }
4014
4015 static void
4016 pysocket_evt_handle(void *arg, int eof)
4017 {
4018 struct pysocket_event *event = arg;
4019 struct pysocket *socket = event->s;
4020
4021 if ((eof || (event->evt.flags & KORE_EVENT_READ)) &&
4022 socket->recvop != NULL) {
4023 if (socket->recvop->coro->request != NULL)
4024 http_request_wakeup(socket->recvop->coro->request);
4025 else
4026 python_coro_wakeup(socket->recvop->coro);
4027 socket->recvop->eof = eof;
4028 }
4029
4030 if ((eof || (event->evt.flags & KORE_EVENT_WRITE)) &&
4031 socket->sendop != NULL) {
4032 if (socket->sendop->coro->request != NULL)
4033 http_request_wakeup(socket->sendop->coro->request);
4034 else
4035 python_coro_wakeup(socket->sendop->coro);
4036 socket->sendop->eof = eof;
4037 }
4038 }
4039
4040 static void
4041 pyqueue_dealloc(struct pyqueue *queue)
4042 {
4043 struct pyqueue_object *object;
4044 struct pyqueue_waiting *waiting;
4045
4046 while ((object = TAILQ_FIRST(&queue->objects)) != NULL) {
4047 TAILQ_REMOVE(&queue->objects, object, list);
4048 Py_DECREF(object->obj);
4049 kore_pool_put(&queue_object_pool, object);
4050 }
4051
4052 while ((waiting = TAILQ_FIRST(&queue->waiting)) != NULL) {
4053 TAILQ_REMOVE(&queue->waiting, waiting, list);
4054 if (waiting->op != NULL)
4055 waiting->op->waiting = NULL;
4056 kore_pool_put(&queue_wait_pool, waiting);
4057 }
4058
4059 PyObject_Del((PyObject *)queue);
4060 }
4061
4062 static PyObject *
4063 pyqueue_pop(struct pyqueue *queue, PyObject *args)
4064 {
4065 struct pyqueue_op *op;
4066
4067 if ((op = PyObject_New(struct pyqueue_op, &pyqueue_op_type)) == NULL)
4068 return (NULL);
4069
4070 op->queue = queue;
4071 op->waiting = kore_pool_get(&queue_wait_pool);
4072 op->waiting->op = op;
4073
4074 op->waiting->coro = coro_running;
4075 TAILQ_INSERT_TAIL(&queue->waiting, op->waiting, list);
4076
4077 Py_INCREF((PyObject *)queue);
4078
4079 return ((PyObject *)op);
4080 }
4081
4082 static PyObject *
4083 pyqueue_popnow(struct pyqueue *queue, PyObject *args)
4084 {
4085 PyObject *obj;
4086 struct pyqueue_object *object;
4087
4088 if ((object = TAILQ_FIRST(&queue->objects)) == NULL) {
4089 Py_RETURN_NONE;
4090 }
4091
4092 TAILQ_REMOVE(&queue->objects, object, list);
4093
4094 obj = object->obj;
4095 kore_pool_put(&queue_object_pool, object);
4096
4097 return (obj);
4098 }
4099
4100 static PyObject *
4101 pyqueue_push(struct pyqueue *queue, PyObject *args)
4102 {
4103 PyObject *obj;
4104 struct pyqueue_object *object;
4105 struct pyqueue_waiting *waiting;
4106
4107 if (!PyArg_ParseTuple(args, "O", &obj))
4108 return (NULL);
4109
4110 Py_INCREF(obj);
4111
4112 object = kore_pool_get(&queue_object_pool);
4113 object->obj = obj;
4114
4115 TAILQ_INSERT_TAIL(&queue->objects, object, list);
4116
4117 /* Wakeup first in line if any. */
4118 if ((waiting = TAILQ_FIRST(&queue->waiting)) != NULL) {
4119 TAILQ_REMOVE(&queue->waiting, waiting, list);
4120
4121 /* wakeup HTTP request if one is tied. */
4122 if (waiting->coro->request != NULL)
4123 http_request_wakeup(waiting->coro->request);
4124 else
4125 python_coro_wakeup(waiting->coro);
4126
4127 waiting->op->waiting = NULL;
4128 kore_pool_put(&queue_wait_pool, waiting);
4129 }
4130
4131 Py_RETURN_TRUE;
4132 }
4133
4134 static void
4135 pyqueue_op_dealloc(struct pyqueue_op *op)
4136 {
4137 if (op->waiting != NULL) {
4138 TAILQ_REMOVE(&op->queue->waiting, op->waiting, list);
4139 kore_pool_put(&queue_wait_pool, op->waiting);
4140 op->waiting = NULL;
4141 }
4142
4143 Py_DECREF((PyObject *)op->queue);
4144 PyObject_Del((PyObject *)op);
4145 }
4146
4147 static PyObject *
4148 pyqueue_op_await(PyObject *obj)
4149 {
4150 Py_INCREF(obj);
4151 return (obj);
4152 }
4153
4154 static PyObject *
4155 pyqueue_op_iternext(struct pyqueue_op *op)
4156 {
4157 PyObject *obj;
4158 struct pyqueue_object *object;
4159 struct pyqueue_waiting *waiting;
4160
4161 if ((object = TAILQ_FIRST(&op->queue->objects)) == NULL) {
4162 Py_RETURN_NONE;
4163 }
4164
4165 TAILQ_REMOVE(&op->queue->objects, object, list);
4166
4167 obj = object->obj;
4168 kore_pool_put(&queue_object_pool, object);
4169
4170 TAILQ_FOREACH(waiting, &op->queue->waiting, list) {
4171 if (waiting->coro->id == coro_running->id) {
4172 TAILQ_REMOVE(&op->queue->waiting, waiting, list);
4173 waiting->op->waiting = NULL;
4174 kore_pool_put(&queue_wait_pool, waiting);
4175 break;
4176 }
4177 }
4178
4179 PyErr_SetObject(PyExc_StopIteration, obj);
4180 Py_DECREF(obj);
4181
4182 return (NULL);
4183 }
4184
4185 static void
4186 pylock_dealloc(struct pylock *lock)
4187 {
4188 struct pylock_op *op;
4189
4190 while ((op = TAILQ_FIRST(&lock->ops)) != NULL) {
4191 TAILQ_REMOVE(&lock->ops, op, list);
4192 op->active = 0;
4193 op->coro->lockop = NULL;
4194 Py_DECREF((PyObject *)op);
4195 }
4196
4197 PyObject_Del((PyObject *)lock);
4198 }
4199
4200 static PyObject *
4201 pylock_trylock(struct pylock *lock, PyObject *args)
4202 {
4203 if (lock->owner != NULL)
4204 Py_RETURN_FALSE;
4205
4206 lock->owner = coro_running;
4207
4208 Py_RETURN_TRUE;
4209 }
4210
4211 static PyObject *
4212 pylock_release(struct pylock *lock, PyObject *args)
4213 {
4214 if (lock->owner == NULL) {
4215 PyErr_SetString(PyExc_RuntimeError, "no lock owner set");
4216 return (NULL);
4217 }
4218
4219 if (lock->owner->id != coro_running->id) {
4220 PyErr_SetString(PyExc_RuntimeError, "lock not owned by caller");
4221 return (NULL);
4222 }
4223
4224 pylock_do_release(lock);
4225
4226 Py_RETURN_NONE;
4227 }
4228
4229 static PyObject *
4230 pylock_aenter(struct pylock *lock, PyObject *args)
4231 {
4232 struct pylock_op *op;
4233
4234 if (coro_running->lockop != NULL) {
4235 fatal("%s: lockop not NULL for %" PRIu64,
4236 __func__, coro_running->id);
4237 }
4238
4239 if (lock->owner != NULL && lock->owner->id == coro_running->id) {
4240 PyErr_SetString(PyExc_RuntimeError, "recursive lock detected");
4241 return (NULL);
4242 }
4243
4244 if ((op = PyObject_New(struct pylock_op, &pylock_op_type)) == NULL)
4245 return (NULL);
4246
4247 op->active = 1;
4248 op->lock = lock;
4249 op->locking = 1;
4250 op->coro = coro_running;
4251
4252 coro_running->lockop = op;
4253
4254 Py_INCREF((PyObject *)op);
4255 Py_INCREF((PyObject *)lock);
4256
4257 TAILQ_INSERT_TAIL(&lock->ops, op, list);
4258
4259 return ((PyObject *)op);
4260 }
4261
4262 static PyObject *
4263 pylock_aexit(struct pylock *lock, PyObject *args)
4264 {
4265 struct pylock_op *op;
4266
4267 if (coro_running->lockop != NULL) {
4268 fatal("%s: lockop not NULL for %" PRIu64,
4269 __func__, coro_running->id);
4270 }
4271
4272 if (lock->owner == NULL || lock->owner->id != coro_running->id) {
4273 PyErr_SetString(PyExc_RuntimeError, "invalid lock owner");
4274 return (NULL);
4275 }
4276
4277 if ((op = PyObject_New(struct pylock_op, &pylock_op_type)) == NULL)
4278 return (NULL);
4279
4280 op->active = 1;
4281 op->lock = lock;
4282 op->locking = 0;
4283 op->coro = coro_running;
4284
4285 coro_running->lockop = op;
4286
4287 Py_INCREF((PyObject *)op);
4288 Py_INCREF((PyObject *)lock);
4289
4290 TAILQ_INSERT_TAIL(&lock->ops, op, list);
4291
4292 return ((PyObject *)op);
4293 }
4294
4295 static void
4296 pylock_do_release(struct pylock *lock)
4297 {
4298 struct pylock_op *op;
4299
4300 lock->owner = NULL;
4301
4302 TAILQ_FOREACH(op, &lock->ops, list) {
4303 if (op->locking == 0)
4304 continue;
4305
4306 op->active = 0;
4307 op->coro->lockop = NULL;
4308 TAILQ_REMOVE(&lock->ops, op, list);
4309
4310 if (op->coro->request != NULL)
4311 http_request_wakeup(op->coro->request);
4312 else
4313 python_coro_wakeup(op->coro);
4314
4315 Py_DECREF((PyObject *)op);
4316 break;
4317 }
4318 }
4319
4320 static void
4321 pylock_op_dealloc(struct pylock_op *op)
4322 {
4323 if (op->active) {
4324 TAILQ_REMOVE(&op->lock->ops, op, list);
4325 op->active = 0;
4326 }
4327
4328 op->coro->lockop = NULL;
4329
4330 Py_DECREF((PyObject *)op->lock);
4331 PyObject_Del((PyObject *)op);
4332 }
4333
4334 static PyObject *
4335 pylock_op_await(PyObject *obj)
4336 {
4337 Py_INCREF(obj);
4338 return (obj);
4339 }
4340
4341 static PyObject *
4342 pylock_op_iternext(struct pylock_op *op)
4343 {
4344 if (op->locking == 0) {
4345 if (op->lock->owner == NULL) {
4346 PyErr_SetString(PyExc_RuntimeError,
4347 "no lock owner set");
4348 return (NULL);
4349 }
4350
4351 if (op->lock->owner->id != coro_running->id) {
4352 PyErr_SetString(PyExc_RuntimeError,
4353 "lock not owned by caller");
4354 return (NULL);
4355 }
4356
4357 pylock_do_release(op->lock);
4358 } else {
4359 if (op->lock->owner != NULL) {
4360 /*
4361 * We could be beat by another coroutine that grabbed
4362 * the lock even if we were the one woken up for it.
4363 */
4364 if (op->active == 0) {
4365 op->active = 1;
4366 op->coro->lockop = op;
4367 TAILQ_INSERT_HEAD(&op->lock->ops, op, list);
4368 Py_INCREF((PyObject *)op);
4369 }
4370 Py_RETURN_NONE;
4371 }
4372
4373 op->lock->owner = coro_running;
4374 }
4375
4376 if (op->active) {
4377 op->active = 0;
4378 op->coro->lockop = NULL;
4379 TAILQ_REMOVE(&op->lock->ops, op, list);
4380 Py_DECREF((PyObject *)op);
4381 }
4382
4383 PyErr_SetNone(PyExc_StopIteration);
4384
4385 return (NULL);
4386 }
4387
4388 static void
4389 pyproc_timeout(void *arg, u_int64_t now)
4390 {
4391 struct pyproc *proc = arg;
4392
4393 proc->timer = NULL;
4394
4395 if (proc->coro->sockop != NULL)
4396 proc->coro->sockop->eof = 1;
4397
4398 proc->coro->exception = PyExc_TimeoutError;
4399 proc->coro->exception_msg = "timeout before process exited";
4400
4401 if (proc->coro->request != NULL)
4402 http_request_wakeup(proc->coro->request);
4403 else
4404 python_coro_wakeup(proc->coro);
4405 }
4406
4407 static void
4408 pyproc_dealloc(struct pyproc *proc)
4409 {
4410 int status;
4411
4412 TAILQ_REMOVE(&procs, proc, list);
4413
4414 if (proc->timer != NULL) {
4415 kore_timer_remove(proc->timer);
4416 proc->timer = NULL;
4417 }
4418
4419 if (proc->pid != -1) {
4420 if (kill(proc->pid, SIGKILL) == -1) {
4421 kore_log(LOG_NOTICE,
4422 "kore.proc failed to send SIGKILL %d (%s)",
4423 proc->pid, errno_s);
4424 }
4425
4426 for (;;) {
4427 if (waitpid(proc->pid, &status, 0) == -1) {
4428 if (errno == EINTR)
4429 continue;
4430 kore_log(LOG_NOTICE,
4431 "kore.proc failed to wait for %d (%s)",
4432 proc->pid, errno_s);
4433 }
4434 break;
4435 }
4436 }
4437
4438 if (proc->in != NULL) {
4439 Py_DECREF((PyObject *)proc->in);
4440 proc->in = NULL;
4441 }
4442
4443 if (proc->out != NULL) {
4444 Py_DECREF((PyObject *)proc->out);
4445 proc->out = NULL;
4446 }
4447
4448 PyObject_Del((PyObject *)proc);
4449 }
4450
4451 static PyObject *
4452 pyproc_kill(struct pyproc *proc, PyObject *args)
4453 {
4454 if (proc->pid != -1 && kill(proc->pid, SIGKILL) == -1)
4455 kore_log(LOG_NOTICE, "kill(%d): %s", proc->pid, errno_s);
4456
4457 Py_RETURN_TRUE;
4458 }
4459
4460 static PyObject *
4461 pyproc_reap(struct pyproc *proc, PyObject *args)
4462 {
4463 struct pyproc_op *op;
4464
4465 if (proc->op != NULL) {
4466 PyErr_Format(PyExc_RuntimeError,
4467 "process %d already being reaped", proc->apid);
4468 return (NULL);
4469 }
4470
4471 if (proc->timer != NULL) {
4472 kore_timer_remove(proc->timer);
4473 proc->timer = NULL;
4474 }
4475
4476 if ((op = PyObject_New(struct pyproc_op, &pyproc_op_type)) == NULL)
4477 return (NULL);
4478
4479 op->proc = proc;
4480 op->coro = coro_running;
4481
4482 proc->op = op;
4483
4484 Py_INCREF((PyObject *)proc);
4485
4486 return ((PyObject *)op);
4487 }
4488
4489 static PyObject *
4490 pyproc_recv(struct pyproc *proc, PyObject *args)
4491 {
4492 Py_ssize_t len;
4493 struct pysocket_op *op;
4494 PyObject *obj;
4495 int timeo;
4496
4497 timeo = -1;
4498
4499 if (proc->out == NULL) {
4500 PyErr_SetString(PyExc_RuntimeError, "stdout closed");
4501 return (NULL);
4502 }
4503
4504 if (!PyArg_ParseTuple(args, "n|i", &len, &timeo))
4505 return (NULL);
4506
4507 obj = pysocket_op_create(proc->out, PYSOCKET_TYPE_RECV, NULL, len);
4508 if (obj == NULL)
4509 return (NULL);
4510
4511 op = (struct pysocket_op *)obj;
4512
4513 if (timeo != -1) {
4514 op->timer = kore_timer_add(pysocket_op_timeout,
4515 timeo, op, KORE_TIMER_ONESHOT);
4516 }
4517
4518 return (obj);
4519 }
4520
4521 static PyObject *
4522 pyproc_send(struct pyproc *proc, PyObject *args)
4523 {
4524 Py_buffer buf;
4525 PyObject *ret;
4526
4527 if (proc->in == NULL) {
4528 PyErr_SetString(PyExc_RuntimeError, "stdin closed");
4529 return (NULL);
4530 }
4531
4532 if (!PyArg_ParseTuple(args, "y*", &buf))
4533 return (NULL);
4534
4535 ret = pysocket_op_create(proc->in,
4536 PYSOCKET_TYPE_SEND, buf.buf, buf.len);
4537
4538 PyBuffer_Release(&buf);
4539
4540 return (ret);
4541 }
4542
4543 static PyObject *
4544 pyproc_close_stdin(struct pyproc *proc, PyObject *args)
4545 {
4546 if (proc->in != NULL) {
4547 Py_DECREF((PyObject *)proc->in);
4548 proc->in = NULL;
4549 }
4550
4551 Py_RETURN_TRUE;
4552 }
4553
4554 static PyObject *
4555 pyproc_get_pid(struct pyproc *proc, void *closure)
4556 {
4557 return (PyLong_FromLong(proc->apid));
4558 }
4559
4560 static void
4561 pyproc_op_dealloc(struct pyproc_op *op)
4562 {
4563 Py_DECREF((PyObject *)op->proc);
4564 PyObject_Del((PyObject *)op);
4565 }
4566
4567 static PyObject *
4568 pyproc_op_await(PyObject *sop)
4569 {
4570 Py_INCREF(sop);
4571 return (sop);
4572 }
4573
4574 static PyObject *
4575 pyproc_op_iternext(struct pyproc_op *op)
4576 {
4577 int ret;
4578 PyObject *res;
4579
4580 if (op->proc->coro->exception != NULL) {
4581 PyErr_SetString(op->proc->coro->exception,
4582 op->proc->coro->exception_msg);
4583 op->proc->coro->exception = NULL;
4584 return (NULL);
4585 }
4586
4587 if (op->proc->reaped == 0)
4588 Py_RETURN_NONE;
4589
4590 if (WIFSTOPPED(op->proc->status)) {
4591 op->proc->reaped = 0;
4592 Py_RETURN_NONE;
4593 }
4594
4595 if (WIFEXITED(op->proc->status)) {
4596 ret = WEXITSTATUS(op->proc->status);
4597 } else {
4598 ret = op->proc->status;
4599 }
4600
4601 if ((res = PyLong_FromLong(ret)) == NULL)
4602 return (NULL);
4603
4604 PyErr_SetObject(PyExc_StopIteration, res);
4605 Py_DECREF(res);
4606
4607 return (NULL);
4608 }
4609
4610 static void
4611 pygather_reap_coro(struct pygather_op *op, struct python_coro *reap)
4612 {
4613 struct pygather_coro *coro;
4614 struct pygather_result *result;
4615 #if PY_VERSION_HEX >= 0x030A0000
4616 PyObject *type, *traceback;
4617 #endif
4618
4619 TAILQ_FOREACH(coro, &op->coroutines, list) {
4620 if (coro->coro->id == reap->id)
4621 break;
4622 }
4623
4624 if (coro == NULL)
4625 fatal("coroutine %" PRIu64 " not found in gather", reap->id);
4626
4627 op->running--;
4628 if (op->running < 0)
4629 fatal("gatherop: running miscount (%d)", op->running);
4630
4631 result = kore_pool_get(&gather_result_pool);
4632 result->obj = NULL;
4633
4634 #if PY_VERSION_HEX < 0x030A0000
4635 if (_PyGen_FetchStopIterationValue(&result->obj) == -1) {
4636 result->obj = Py_None;
4637 Py_INCREF(Py_None);
4638 }
4639 #else
4640 if (PyErr_Occurred()) {
4641 Py_XDECREF(coro->coro->result);
4642 PyErr_Fetch(&type, &coro->coro->result, &traceback);
4643 Py_DECREF(type);
4644 Py_XDECREF(traceback);
4645 } else {
4646 if (coro->coro->result == NULL) {
4647 coro->coro->result = Py_None;
4648 Py_INCREF(Py_None);
4649 }
4650 }
4651
4652 result->obj = coro->coro->result;
4653 Py_INCREF(result->obj);
4654 #endif
4655
4656 TAILQ_INSERT_TAIL(&op->results, result, list);
4657
4658 TAILQ_REMOVE(&op->coroutines, coro, list);
4659 kore_pool_put(&gather_coro_pool, coro);
4660
4661 kore_python_coro_delete(reap);
4662 }
4663
4664 static void
4665 pygather_op_dealloc(struct pygather_op *op)
4666 {
4667 struct python_coro *old;
4668 struct pygather_coro *coro, *next;
4669 struct pygather_result *res, *rnext;
4670
4671 /*
4672 * Since we are calling kore_python_coro_delete() on all the
4673 * remaining coroutines in this gather op we must remember the
4674 * original coroutine that is running as the removal will end
4675 * up setting coro_running to NULL.
4676 */
4677 old = coro_running;
4678
4679 for (coro = TAILQ_FIRST(&op->coroutines); coro != NULL; coro = next) {
4680 next = TAILQ_NEXT(coro, list);
4681 TAILQ_REMOVE(&op->coroutines, coro, list);
4682
4683 /* Make sure we don't end up in pygather_reap_coro(). */
4684 coro->coro->gatherop = NULL;
4685
4686 kore_python_coro_delete(coro->coro);
4687 kore_pool_put(&gather_coro_pool, coro);
4688 }
4689
4690 coro_running = old;
4691
4692 for (res = TAILQ_FIRST(&op->results); res != NULL; res = rnext) {
4693 rnext = TAILQ_NEXT(res, list);
4694 TAILQ_REMOVE(&op->results, res, list);
4695
4696 Py_DECREF(res->obj);
4697 kore_pool_put(&gather_result_pool, res);
4698 }
4699
4700 PyObject_Del((PyObject *)op);
4701 }
4702
4703 static PyObject *
4704 pygather_op_await(PyObject *obj)
4705 {
4706 Py_INCREF(obj);
4707 return (obj);
4708 }
4709
4710 static PyObject *
4711 pygather_op_iternext(struct pygather_op *op)
4712 {
4713 int idx;
4714 struct pygather_coro *coro;
4715 struct pygather_result *res, *next;
4716 PyObject *list, *obj;
4717
4718 if (!TAILQ_EMPTY(&op->coroutines)) {
4719 if (op->running > 0)
4720 Py_RETURN_NONE;
4721
4722 TAILQ_FOREACH(coro, &op->coroutines, list) {
4723 if (op->running >= op->concurrency)
4724 break;
4725 python_coro_wakeup(coro->coro);
4726 op->running++;
4727 }
4728
4729 Py_RETURN_NONE;
4730 }
4731
4732 if ((list = PyList_New(op->count)) == NULL)
4733 return (NULL);
4734
4735 idx = 0;
4736
4737 for (res = TAILQ_FIRST(&op->results); res != NULL; res = next) {
4738 next = TAILQ_NEXT(res, list);
4739 TAILQ_REMOVE(&op->results, res, list);
4740
4741 obj = res->obj;
4742 res->obj = NULL;
4743 kore_pool_put(&gather_result_pool, res);
4744
4745 if (PyList_SetItem(list, idx++, obj) != 0) {
4746 Py_DECREF(list);
4747 return (NULL);
4748 }
4749 }
4750
4751 PyErr_SetObject(PyExc_StopIteration, list);
4752 Py_DECREF(list);
4753
4754 return (NULL);
4755 }
4756
4757 static PyObject *
4758 pyhttp_request_alloc(const struct http_request *req)
4759 {
4760 union { const void *cp; void *p; } ptr;
4761 struct pyhttp_request *pyreq;
4762
4763 pyreq = PyObject_New(struct pyhttp_request, &pyhttp_request_type);
4764 if (pyreq == NULL)
4765 return (NULL);
4766
4767 /*
4768 * Hack around all http apis taking a non-const pointer and us having
4769 * a const pointer for the req data structure. This is because we
4770 * could potentially be called from a validator where the argument
4771 * is a http_request pointer.
4772 */
4773 ptr.cp = req;
4774 pyreq->req = ptr.p;
4775 pyreq->data = NULL;
4776 pyreq->dict = NULL;
4777
4778 return ((PyObject *)pyreq);
4779 }
4780
4781 static PyObject *
4782 pyhttp_file_alloc(struct http_file *file)
4783 {
4784 struct pyhttp_file *pyfile;
4785
4786 pyfile = PyObject_New(struct pyhttp_file, &pyhttp_file_type);
4787 if (pyfile == NULL)
4788 return (NULL);
4789
4790 pyfile->file = file;
4791
4792 return ((PyObject *)pyfile);
4793 }
4794
4795 static int
4796 pyhttp_preprocess(struct http_request *req)
4797 {
4798 struct reqcall *rq;
4799 PyObject *ret;
4800
4801 rq = req->py_rqnext;
4802
4803 while (rq) {
4804 req->py_rqnext = TAILQ_NEXT(rq, list);
4805
4806 PyErr_Clear();
4807 ret = PyObject_CallFunctionObjArgs(rq->f, req->py_req, NULL);
4808
4809 if (ret == NULL) {
4810 kore_python_log_error("preprocess");
4811 http_response(req, HTTP_STATUS_INTERNAL_ERROR, NULL, 0);
4812 return (KORE_RESULT_ERROR);
4813 }
4814
4815 if (ret == Py_False) {
4816 Py_DECREF(ret);
4817 return (KORE_RESULT_ERROR);
4818 }
4819
4820 if (PyCoro_CheckExact(ret)) {
4821 req->py_coro = python_coro_create(ret, req);
4822 if (python_coro_run(req->py_coro) == KORE_RESULT_OK) {
4823 http_request_wakeup(req);
4824 kore_python_coro_delete(req->py_coro);
4825 req->py_coro = NULL;
4826 rq = req->py_rqnext;
4827 continue;
4828 }
4829 return (KORE_RESULT_RETRY);
4830 }
4831
4832 Py_DECREF(ret);
4833 rq = req->py_rqnext;
4834 }
4835
4836 return (KORE_RESULT_OK);
4837 }
4838
4839 static PyObject *
4840 pyhttp_response(struct pyhttp_request *pyreq, PyObject *args)
4841 {
4842 struct connection *c;
4843 char *ptr;
4844 Py_ssize_t length;
4845 int status;
4846 struct pyhttp_iterobj *iterobj;
4847 PyObject *obj, *iterator;
4848
4849 length = -1;
4850
4851 if (!PyArg_ParseTuple(args, "iO", &status, &obj))
4852 return (NULL);
4853
4854 if (PyBytes_CheckExact(obj)) {
4855 if (PyBytes_AsStringAndSize(obj, &ptr, &length) == -1)
4856 return (NULL);
4857
4858 if (length < 0) {
4859 PyErr_SetString(PyExc_TypeError, "invalid length");
4860 return (NULL);
4861 }
4862
4863 Py_INCREF(obj);
4864
4865 http_response_stream(pyreq->req, status, ptr, length,
4866 pyhttp_response_sent, obj);
4867 } else if (obj == Py_None) {
4868 http_response(pyreq->req, status, NULL, 0);
4869 } else {
4870 c = pyreq->req->owner;
4871 if (c->state == CONN_STATE_DISCONNECTING) {
4872 Py_RETURN_FALSE;
4873 }
4874
4875 if ((iterator = PyObject_GetIter(obj)) == NULL)
4876 return (NULL);
4877
4878 iterobj = kore_pool_get(&iterobj_pool);
4879 iterobj->iterator = iterator;
4880 iterobj->connection = c;
4881 iterobj->remove = 0;
4882
4883 kore_buf_init(&iterobj->buf, 4096);
4884
4885 c->hdlr_extra = iterobj;
4886 c->flags |= CONN_IS_BUSY;
4887 c->disconnect = pyhttp_iterobj_disconnect;
4888
4889 pyreq->req->flags |= HTTP_REQUEST_NO_CONTENT_LENGTH;
4890 http_response_header(pyreq->req, "transfer-encoding",
4891 "chunked");
4892
4893 http_response(pyreq->req, status, NULL, 0);
4894 pyhttp_iterobj_next(iterobj);
4895 }
4896
4897 Py_RETURN_TRUE;
4898 }
4899
4900 static int
4901 pyhttp_response_sent(struct netbuf *nb)
4902 {
4903 PyObject *data;
4904
4905 data = nb->extra;
4906 Py_DECREF(data);
4907
4908 return (KORE_RESULT_OK);
4909 }
4910
4911 static int
4912 pyhttp_iterobj_next(struct pyhttp_iterobj *iterobj)
4913 {
4914 struct netbuf *nb;
4915 PyObject *obj;
4916 const char *ptr;
4917 Py_ssize_t length;
4918
4919 PyErr_Clear();
4920
4921 if ((obj = PyIter_Next(iterobj->iterator)) == NULL) {
4922 if (PyErr_Occurred()) {
4923 kore_python_log_error("pyhttp_iterobj_next");
4924 return (KORE_RESULT_ERROR);
4925 }
4926
4927 return (KORE_RESULT_OK);
4928 }
4929
4930 if ((ptr = PyUnicode_AsUTF8AndSize(obj, &length)) == NULL) {
4931 kore_python_log_error("pyhttp_iterobj_next");
4932 return (KORE_RESULT_ERROR);
4933 }
4934
4935 kore_buf_reset(&iterobj->buf);
4936 kore_buf_appendf(&iterobj->buf, "%lx\r\n", length);
4937 kore_buf_append(&iterobj->buf, ptr, length);
4938 kore_buf_appendf(&iterobj->buf, "\r\n");
4939
4940 Py_DECREF(obj);
4941
4942 net_send_stream(iterobj->connection, iterobj->buf.data,
4943 iterobj->buf.offset, pyhttp_iterobj_chunk_sent, &nb);
4944
4945 nb->extra = iterobj;
4946
4947 return (KORE_RESULT_RETRY);
4948 }
4949
4950 static int
4951 pyhttp_iterobj_chunk_sent(struct netbuf *nb)
4952 {
4953 int ret;
4954 struct pyhttp_iterobj *iterobj;
4955
4956 iterobj = nb->extra;
4957
4958 if (iterobj->remove) {
4959 ret = KORE_RESULT_ERROR;
4960 } else {
4961 ret = pyhttp_iterobj_next(iterobj);
4962 }
4963
4964 if (ret != KORE_RESULT_RETRY) {
4965 iterobj->connection->hdlr_extra = NULL;
4966 iterobj->connection->disconnect = NULL;
4967 iterobj->connection->flags &= ~CONN_IS_BUSY;
4968
4969 if (iterobj->remove == 0)
4970 http_start_recv(iterobj->connection);
4971
4972 kore_buf_reset(&iterobj->buf);
4973 kore_buf_appendf(&iterobj->buf, "0\r\n\r\n");
4974 net_send_queue(iterobj->connection,
4975 iterobj->buf.data, iterobj->buf.offset);
4976
4977 Py_DECREF(iterobj->iterator);
4978
4979 kore_buf_cleanup(&iterobj->buf);
4980 kore_pool_put(&iterobj_pool, iterobj);
4981 } else {
4982 ret = KORE_RESULT_OK;
4983 }
4984
4985 return (ret);
4986 }
4987
4988 static void
4989 pyhttp_iterobj_disconnect(struct connection *c)
4990 {
4991 struct pyhttp_iterobj *iterobj;
4992
4993 iterobj = c->hdlr_extra;
4994 iterobj->remove = 1;
4995 c->hdlr_extra = NULL;
4996 }
4997
4998 static PyObject *
4999 pyhttp_response_header(struct pyhttp_request *pyreq, PyObject *args)
5000 {
5001 const char *header, *value;
5002
5003 if (!PyArg_ParseTuple(args, "ss", &header, &value))
5004 return (NULL);
5005
5006 http_response_header(pyreq->req, header, value);
5007
5008 Py_RETURN_TRUE;
5009 }
5010
5011 static PyObject *
5012 pyhttp_request_header(struct pyhttp_request *pyreq, PyObject *args)
5013 {
5014 const char *value;
5015 const char *header;
5016 PyObject *result;
5017
5018 if (!PyArg_ParseTuple(args, "s", &header))
5019 return (NULL);
5020
5021 if (!http_request_header(pyreq->req, header, &value)) {
5022 Py_RETURN_NONE;
5023 }
5024
5025 if ((result = PyUnicode_FromString(value)) == NULL)
5026 return (PyErr_NoMemory());
5027
5028 return (result);
5029 }
5030
5031 static PyObject *
5032 pyhttp_body_read(struct pyhttp_request *pyreq, PyObject *args)
5033 {
5034 ssize_t ret;
5035 size_t len;
5036 Py_ssize_t pylen;
5037 PyObject *result;
5038 u_int8_t buf[1024];
5039
5040 if (!PyArg_ParseTuple(args, "n", &pylen) || pylen < 0)
5041 return (NULL);
5042
5043 len = (size_t)pylen;
5044 if (len > sizeof(buf)) {
5045 PyErr_SetString(PyExc_RuntimeError, "len > sizeof(buf)");
5046 return (NULL);
5047 }
5048
5049 ret = http_body_read(pyreq->req, buf, len);
5050 if (ret == -1) {
5051 PyErr_SetString(PyExc_RuntimeError, "http_body_read() failed");
5052 return (NULL);
5053 }
5054
5055 result = Py_BuildValue("ny#", ret, buf, ret);
5056 if (result == NULL)
5057 return (PyErr_NoMemory());
5058
5059 return (result);
5060 }
5061
5062 static PyObject *
5063 pyhttp_populate_get(struct pyhttp_request *pyreq, PyObject *args)
5064 {
5065 http_populate_get(pyreq->req);
5066 Py_RETURN_TRUE;
5067 }
5068
5069 static PyObject *
5070 pyhttp_populate_post(struct pyhttp_request *pyreq, PyObject *args)
5071 {
5072 http_populate_post(pyreq->req);
5073 Py_RETURN_TRUE;
5074 }
5075
5076 static PyObject *
5077 pyhttp_populate_multi(struct pyhttp_request *pyreq, PyObject *args)
5078 {
5079 http_populate_multipart_form(pyreq->req);
5080 Py_RETURN_TRUE;
5081 }
5082
5083 static PyObject *
5084 pyhttp_populate_cookies(struct pyhttp_request *pyreq, PyObject *args)
5085 {
5086 http_populate_cookies(pyreq->req);
5087 Py_RETURN_TRUE;
5088 }
5089
5090 static PyObject *
5091 pyhttp_argument(struct pyhttp_request *pyreq, PyObject *args)
5092 {
5093 const char *name;
5094 PyObject *value;
5095 char *string;
5096
5097 if (!PyArg_ParseTuple(args, "s", &name))
5098 return (NULL);
5099
5100 if (!http_argument_get_string(pyreq->req, name, &string)) {
5101 Py_RETURN_NONE;
5102 }
5103
5104 if ((value = PyUnicode_FromString(string)) == NULL)
5105 return (PyErr_NoMemory());
5106
5107 return (value);
5108 }
5109
5110 static PyObject *
5111 pyhttp_cookie(struct pyhttp_request *pyreq, PyObject *args)
5112 {
5113 const char *name;
5114 PyObject *value;
5115 char *string;
5116
5117 if (!PyArg_ParseTuple(args, "s", &name))
5118 return (NULL);
5119
5120 if (!http_request_cookie(pyreq->req, name, &string)) {
5121 Py_RETURN_NONE;
5122 }
5123
5124 if ((value = PyUnicode_FromString(string)) == NULL)
5125 return (NULL);
5126
5127 return (value);
5128 }
5129
5130 static PyObject *
5131 pyhttp_headers(struct pyhttp_request *pyreq, PyObject *args)
5132 {
5133 struct http_header *hdr;
5134 struct http_request *req;
5135 PyObject *obj, *dict, *ret;
5136
5137 ret = NULL;
5138 obj = NULL;
5139 dict = NULL;
5140
5141 req = pyreq->req;
5142
5143 if ((dict = PyDict_New()) == NULL)
5144 goto cleanup;
5145
5146 if ((obj = PyUnicode_FromString(req->host)) == NULL)
5147 goto cleanup;
5148
5149 if (PyDict_SetItemString(dict, "host", obj) == -1)
5150 goto cleanup;
5151
5152 TAILQ_FOREACH(hdr, &req->req_headers, list) {
5153 if ((obj = PyUnicode_FromString(hdr->value)) == NULL)
5154 goto cleanup;
5155 if (PyDict_SetItemString(dict, hdr->header, obj) == -1)
5156 goto cleanup;
5157 }
5158
5159 ret = dict;
5160 obj = NULL;
5161 dict = NULL;
5162
5163 cleanup:
5164 Py_XDECREF(obj);
5165 Py_XDECREF(dict);
5166
5167 return (ret);
5168 }
5169
5170 static PyObject *
5171 pyhttp_file_lookup(struct pyhttp_request *pyreq, PyObject *args)
5172 {
5173 const char *name;
5174 struct http_file *file;
5175 PyObject *pyfile;
5176
5177 if (!PyArg_ParseTuple(args, "s", &name))
5178 return (NULL);
5179
5180 if ((file = http_file_lookup(pyreq->req, name)) == NULL) {
5181 Py_RETURN_NONE;
5182 }
5183
5184 if ((pyfile = pyhttp_file_alloc(file)) == NULL)
5185 return (PyErr_NoMemory());
5186
5187 return (pyfile);
5188 }
5189
5190 static PyObject *
5191 pyhttp_file_read(struct pyhttp_file *pyfile, PyObject *args)
5192 {
5193 ssize_t ret;
5194 size_t len;
5195 Py_ssize_t pylen;
5196 PyObject *result;
5197 u_int8_t buf[1024];
5198
5199 if (!PyArg_ParseTuple(args, "n", &pylen) || pylen < 0)
5200 return (NULL);
5201
5202 len = (size_t)pylen;
5203 if (len > sizeof(buf)) {
5204 PyErr_SetString(PyExc_RuntimeError, "len > sizeof(buf)");
5205 return (NULL);
5206 }
5207
5208 ret = http_file_read(pyfile->file, buf, len);
5209 if (ret == -1) {
5210 PyErr_SetString(PyExc_RuntimeError, "http_file_read() failed");
5211 return (NULL);
5212 }
5213
5214 result = Py_BuildValue("ny#", ret, buf, ret);
5215 if (result == NULL)
5216 return (PyErr_NoMemory());
5217
5218 return (result);
5219 }
5220
5221 static PyObject *
5222 pyhttp_websocket_handshake(struct pyhttp_request *pyreq, PyObject *args)
5223 {
5224 struct connection *c;
5225 PyObject *onconnect, *onmsg, *ondisconnect;
5226
5227 if (!PyArg_ParseTuple(args, "OOO", &onconnect, &onmsg, &ondisconnect))
5228 return (NULL);
5229
5230 kore_websocket_handshake(pyreq->req, NULL, NULL, NULL);
5231
5232 c = pyreq->req->owner;
5233
5234 Py_INCREF(onconnect);
5235 Py_INCREF(onmsg);
5236 Py_INCREF(ondisconnect);
5237
5238 c->ws_connect = kore_calloc(1, sizeof(struct kore_runtime_call));
5239 c->ws_connect->addr = onconnect;
5240 c->ws_connect->runtime = &kore_python_runtime;
5241
5242 c->ws_message = kore_calloc(1, sizeof(struct kore_runtime_call));
5243 c->ws_message->addr = onmsg;
5244 c->ws_message->runtime = &kore_python_runtime;
5245
5246 c->ws_disconnect = kore_calloc(1, sizeof(struct kore_runtime_call));
5247 c->ws_disconnect->addr = ondisconnect;
5248 c->ws_disconnect->runtime = &kore_python_runtime;
5249
5250 python_runtime_connect(onconnect, c);
5251
5252 Py_RETURN_TRUE;
5253 }
5254
5255 static PyObject *
5256 pyconnection_websocket_send(struct pyconnection *pyc, PyObject *args)
5257 {
5258 int op;
5259 ssize_t len;
5260 const char *data;
5261
5262 if (pyc->c->proto != CONN_PROTO_WEBSOCKET) {
5263 PyErr_SetString(PyExc_TypeError, "not a websocket connection");
5264 return (NULL);
5265 }
5266
5267 len = -1;
5268
5269 if (!PyArg_ParseTuple(args, "iy#", &op, &data, &len))
5270 return (NULL);
5271
5272 if (len < 0) {
5273 PyErr_SetString(PyExc_TypeError, "invalid length");
5274 return (NULL);
5275 }
5276
5277 switch (op) {
5278 case WEBSOCKET_OP_TEXT:
5279 case WEBSOCKET_OP_BINARY:
5280 break;
5281 default:
5282 PyErr_SetString(PyExc_TypeError, "invalid op parameter");
5283 return (NULL);
5284 }
5285
5286 kore_websocket_send(pyc->c, op, data, len);
5287
5288 Py_RETURN_TRUE;
5289 }
5290
5291 static PyObject *
5292 python_websocket_broadcast(PyObject *self, PyObject *args)
5293 {
5294 struct connection *c;
5295 ssize_t len;
5296 struct pyconnection *pyc;
5297 const char *data;
5298 PyObject *pysrc;
5299 int op, broadcast;
5300
5301 len = -1;
5302
5303 if (!PyArg_ParseTuple(args, "Oiy#i", &pysrc, &op, &data, &len,
5304 &broadcast))
5305 return (NULL);
5306
5307 if (len < 0) {
5308 PyErr_SetString(PyExc_TypeError, "invalid length");
5309 return (NULL);
5310 }
5311
5312 switch (op) {
5313 case WEBSOCKET_OP_TEXT:
5314 case WEBSOCKET_OP_BINARY:
5315 break;
5316 default:
5317 PyErr_SetString(PyExc_TypeError, "invalid op parameter");
5318 return (NULL);
5319 }
5320
5321 if (pysrc == Py_None) {
5322 c = NULL;
5323 } else {
5324 if (!PyObject_TypeCheck(pysrc, &pyconnection_type))
5325 return (NULL);
5326 pyc = (struct pyconnection *)pysrc;
5327 c = pyc->c;
5328 }
5329
5330 kore_websocket_broadcast(c, op, data, len, broadcast);
5331
5332 Py_RETURN_TRUE;
5333 }
5334
5335 static PyObject *
5336 pyhttp_get_host(struct pyhttp_request *pyreq, void *closure)
5337 {
5338 PyObject *host;
5339
5340 if ((host = PyUnicode_FromString(pyreq->req->host)) == NULL)
5341 return (PyErr_NoMemory());
5342
5343 return (host);
5344 }
5345
5346 static PyObject *
5347 pyhttp_get_path(struct pyhttp_request *pyreq, void *closure)
5348 {
5349 PyObject *path;
5350
5351 if ((path = PyUnicode_FromString(pyreq->req->path)) == NULL)
5352 return (PyErr_NoMemory());
5353
5354 return (path);
5355 }
5356
5357 static PyObject *
5358 pyhttp_get_body(struct pyhttp_request *pyreq, void *closure)
5359 {
5360 ssize_t ret;
5361 struct kore_buf buf;
5362 PyObject *body;
5363 u_int8_t data[BUFSIZ];
5364
5365 kore_buf_init(&buf, 1024);
5366 if (!http_body_rewind(pyreq->req)) {
5367 PyErr_SetString(PyExc_RuntimeError,
5368 "http_body_rewind() failed");
5369 return (NULL);
5370 }
5371
5372 for (;;) {
5373 ret = http_body_read(pyreq->req, data, sizeof(data));
5374 if (ret == -1) {
5375 kore_buf_cleanup(&buf);
5376 PyErr_SetString(PyExc_RuntimeError,
5377 "http_body_read() failed");
5378 return (NULL);
5379 }
5380
5381 if (ret == 0)
5382 break;
5383
5384 kore_buf_append(&buf, data, (size_t)ret);
5385 }
5386
5387 body = PyBytes_FromStringAndSize((char *)buf.data, buf.offset);
5388 kore_buf_free(&buf);
5389
5390 if (body == NULL)
5391 return (PyErr_NoMemory());
5392
5393 return (body);
5394 }
5395
5396 static PyObject *
5397 pyhttp_get_agent(struct pyhttp_request *pyreq, void *closure)
5398 {
5399 return (PyUnicode_FromString(pyreq->req->path));
5400 }
5401
5402 static PyObject *
5403 pyhttp_get_method(struct pyhttp_request *pyreq, void *closure)
5404 {
5405 return (PyLong_FromUnsignedLong(pyreq->req->method));
5406 }
5407
5408 static PyObject *
5409 pyhttp_get_protocol(struct pyhttp_request *pyreq, void *closure)
5410 {
5411 struct connection *c;
5412 const char *proto;
5413
5414 c = pyreq->req->owner;
5415
5416 if (c->owner->server->tls)
5417 proto = "https";
5418 else
5419 proto = "http";
5420
5421 return (PyUnicode_FromString(proto));
5422 }
5423
5424 static PyObject *
5425 pyhttp_get_body_path(struct pyhttp_request *pyreq, void *closure)
5426 {
5427 if (pyreq->req->http_body_path == NULL) {
5428 Py_RETURN_NONE;
5429 }
5430
5431 return (PyUnicode_FromString(pyreq->req->http_body_path));
5432 }
5433
5434 static PyObject *
5435 pyhttp_get_body_digest(struct pyhttp_request *pyreq, void *closure)
5436 {
5437 PyObject *digest;
5438
5439 digest = PyBytes_FromStringAndSize((char *)pyreq->req->http_body_digest,
5440 sizeof(pyreq->req->http_body_digest));
5441
5442 return (digest);
5443 }
5444
5445 static PyObject *
5446 pyhttp_get_connection(struct pyhttp_request *pyreq, void *closure)
5447 {
5448 PyObject *pyc;
5449
5450 if (pyreq->req->owner == NULL) {
5451 Py_RETURN_NONE;
5452 }
5453
5454 if ((pyc = pyconnection_alloc(pyreq->req->owner)) == NULL)
5455 return (PyErr_NoMemory());
5456
5457 return (pyc);
5458 }
5459
5460 static PyObject *
5461 pyhttp_file_get_name(struct pyhttp_file *pyfile, void *closure)
5462 {
5463 PyObject *name;
5464
5465 if ((name = PyUnicode_FromString(pyfile->file->name)) == NULL)
5466 return (PyErr_NoMemory());
5467
5468 return (name);
5469 }
5470
5471 static PyObject *
5472 pyhttp_file_get_filename(struct pyhttp_file *pyfile, void *closure)
5473 {
5474 PyObject *name;
5475
5476 if ((name = PyUnicode_FromString(pyfile->file->filename)) == NULL)
5477 return (PyErr_NoMemory());
5478
5479 return (name);
5480 }
5481
5482 void
5483 pyroute_dealloc(struct pyroute *route)
5484 {
5485 kore_free(route->path);
5486
5487 Py_XDECREF(route->func);
5488 Py_XDECREF(route->kwargs);
5489
5490 PyObject_Del((PyObject *)route);
5491 }
5492
5493 static PyObject *
5494 pyroute_inner(struct pyroute *route, PyObject *args)
5495 {
5496 PyObject *obj;
5497
5498 if (!PyArg_ParseTuple(args, "O", &obj))
5499 return (NULL);
5500
5501 if (!PyCallable_Check(obj))
5502 return (NULL);
5503
5504 route->func = obj;
5505 Py_INCREF(route->func);
5506
5507 TAILQ_INSERT_TAIL(&routes, route, list);
5508
5509 return (route->func);
5510 }
5511
5512 void
5513 pydomain_dealloc(struct pydomain *domain)
5514 {
5515 PyObject_Del((PyObject *)domain);
5516 }
5517
5518 static int
5519 pydomain_set_accesslog(struct pydomain *domain, PyObject *arg, void *closure)
5520 {
5521 const char *path;
5522
5523 if (!PyUnicode_CheckExact(arg))
5524 return (-1);
5525
5526 if (domain->config->accesslog != -1) {
5527 PyErr_Format(PyExc_RuntimeError,
5528 "domain %s accesslog already set", domain->config->domain);
5529 return (-1);
5530 }
5531
5532 path = PyUnicode_AsUTF8(arg);
5533
5534 domain->config->accesslog = open(path,
5535 O_CREAT | O_APPEND | O_WRONLY,
5536 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
5537
5538 if (domain->config->accesslog == -1) {
5539 PyErr_Format(PyExc_RuntimeError,
5540 "failed to open accesslog for %s (%s:%s)",
5541 domain->config->domain, path, errno_s);
5542 return (-1);
5543 }
5544
5545 return (0);
5546 }
5547
5548 static PyObject *
5549 pydomain_filemaps(struct pydomain *domain, PyObject *args)
5550 {
5551 Py_ssize_t idx;
5552 struct kore_route *rt;
5553 const char *url, *path;
5554 PyObject *dict, *key, *value, *auth;
5555
5556 if (!PyArg_ParseTuple(args, "O", &dict))
5557 return (NULL);
5558
5559 if (!PyDict_CheckExact(dict)) {
5560 PyErr_SetString(PyExc_RuntimeError, "filemaps not a dict");
5561 return (NULL);
5562 }
5563
5564 idx = 0;
5565 while (PyDict_Next(dict, &idx, &key, &value)) {
5566 if (!PyUnicode_CheckExact(key)) {
5567 PyErr_SetString(PyExc_RuntimeError,
5568 "filemap key not a string");
5569 return (NULL);
5570 }
5571
5572 url = PyUnicode_AsUTF8(key);
5573
5574 if (!PyUnicode_CheckExact(value) &&
5575 !PyTuple_CheckExact(value)) {
5576 PyErr_SetString(PyExc_RuntimeError,
5577 "filemap value can be either be a string or tuple");
5578 return (NULL);
5579 }
5580
5581 if (PyTuple_CheckExact(value)) {
5582 auth = PyTuple_GetItem(value, 1);
5583 if (!PyDict_CheckExact(auth)) {
5584 PyErr_SetString(PyExc_RuntimeError,
5585 "filemap value tuple auth is not a dict");
5586 return (NULL);
5587 }
5588
5589 value = PyTuple_GetItem(value, 0);
5590 if (!PyUnicode_CheckExact(value)) {
5591 PyErr_SetString(PyExc_RuntimeError,
5592 "filemap value tuple path is invalid");
5593 return (NULL);
5594 }
5595 } else {
5596 auth = NULL;
5597 }
5598
5599 path = PyUnicode_AsUTF8(value);
5600
5601 rt = kore_filemap_create(domain->config, path, url, NULL);
5602 if (rt == NULL) {
5603 PyErr_Format(PyExc_RuntimeError,
5604 "failed to create filemap %s->%s for %s",
5605 url, path, domain->config->domain);
5606 return (NULL);
5607 }
5608
5609 if (auth != NULL) {
5610 if (!python_route_auth(auth, rt)) {
5611 kore_python_log_error("python_route_auth");
5612 kore_route_free(rt);
5613 return (KORE_RESULT_ERROR);
5614 }
5615 }
5616 }
5617
5618 Py_RETURN_NONE;
5619 }
5620
5621 static PyObject *
5622 pydomain_redirect(struct pydomain *domain, PyObject *args)
5623 {
5624 int status;
5625 const char *src, *dst;
5626
5627 if (!PyArg_ParseTuple(args, "sis", &src, &status, &dst))
5628 return (NULL);
5629
5630 if (!http_redirect_add(domain->config, src, status, dst)) {
5631 fatal("failed to add redirect '%s' on '%s'",
5632 src, domain->config->domain);
5633 }
5634
5635 Py_RETURN_NONE;
5636 }
5637
5638 static PyObject *
5639 pydomain_route(struct pydomain *domain, PyObject *args, PyObject *kwargs)
5640 {
5641 PyObject *obj;
5642 const char *path;
5643 struct pyroute *route;
5644
5645 if (!PyArg_ParseTuple(args, "sO", &path, &obj))
5646 return (NULL);
5647
5648 if (!PyCallable_Check(obj))
5649 return (NULL);
5650
5651 if ((route = PyObject_New(struct pyroute, &pyroute_type)) == NULL)
5652 return (NULL);
5653
5654 route->kwargs = kwargs;
5655 route->domain = domain->config;
5656 route->path = kore_strdup(path);
5657
5658 Py_XINCREF(route->kwargs);
5659
5660 route->func = obj;
5661 Py_INCREF(route->func);
5662
5663 TAILQ_INSERT_TAIL(&routes, route, list);
5664
5665 Py_RETURN_NONE;
5666 }
5667
5668 static int
5669 python_route_install(struct pyroute *route)
5670 {
5671 const char *val;
5672 struct kore_domain *domain;
5673 struct kore_route *rt, *entry;
5674 PyObject *kwargs, *repr, *obj;
5675
5676 if ((repr = PyObject_Repr(route->func)) == NULL) {
5677 kore_python_log_error("python_route_install");
5678 return (KORE_RESULT_ERROR);
5679 }
5680
5681 domain = python_route_domain_resolve(route);
5682
5683 rt = kore_calloc(1, sizeof(*rt));
5684 rt->dom = domain;
5685 rt->methods = HTTP_METHOD_ALL;
5686 rt->path = kore_strdup(route->path);
5687
5688 TAILQ_INIT(&rt->params);
5689
5690 val = PyUnicode_AsUTF8(repr);
5691 rt->func = kore_strdup(val);
5692
5693 kwargs = route->kwargs;
5694
5695 rt->rcall = kore_calloc(1, sizeof(struct kore_runtime_call));
5696 rt->rcall->addr = route->func;
5697 rt->rcall->runtime = &kore_python_runtime;
5698 Py_INCREF(rt->rcall->addr);
5699
5700 if (kwargs != NULL) {
5701 if ((obj = PyDict_GetItemString(kwargs, "methods")) != NULL) {
5702 if (!python_route_methods(obj, kwargs, rt)) {
5703 kore_python_log_error("python_route_install");
5704 kore_route_free(rt);
5705 return (KORE_RESULT_ERROR);
5706 }
5707 }
5708
5709 if ((obj = PyDict_GetItemString(kwargs, "auth")) != NULL) {
5710 if (!python_route_auth(obj, rt)) {
5711 kore_python_log_error("python_route_install");
5712 kore_route_free(rt);
5713 return (KORE_RESULT_ERROR);
5714 }
5715 }
5716
5717 if ((obj = PyDict_GetItemString(kwargs, "hooks")) != NULL) {
5718 if (!python_route_hooks(obj, rt)) {
5719 kore_python_log_error("python_route_install");
5720 kore_route_free(rt);
5721 return (KORE_RESULT_ERROR);
5722 }
5723 }
5724 }
5725
5726 if (rt->path[0] == '/') {
5727 rt->type = HANDLER_TYPE_STATIC;
5728 } else {
5729 rt->type = HANDLER_TYPE_DYNAMIC;
5730 if (regcomp(&rt->rctx, rt->path, REG_EXTENDED))
5731 fatal("failed to compile regex for '%s'", rt->path);
5732 }
5733
5734 TAILQ_FOREACH(entry, &domain->routes, list) {
5735 if (!strcmp(entry->path, rt->path) &&
5736 (entry->methods & rt->methods))
5737 fatal("duplicate route for '%s'", route->path);
5738 }
5739
5740 TAILQ_INSERT_TAIL(&domain->routes, rt, list);
5741
5742 return (KORE_RESULT_OK);
5743 }
5744
5745 static struct kore_domain *
5746 python_route_domain_resolve(struct pyroute *route)
5747 {
5748 struct kore_server *srv;
5749 const char *name;
5750 struct kore_domain *domain;
5751
5752 if (route->domain != NULL)
5753 return (route->domain);
5754
5755 if (route->kwargs != NULL)
5756 name = python_string_from_dict(route->kwargs, "domain");
5757 else
5758 name = NULL;
5759
5760 if (name != NULL) {
5761 domain = NULL;
5762 LIST_FOREACH(srv, &kore_servers, list) {
5763 TAILQ_FOREACH(domain, &srv->domains, list) {
5764 if (!strcmp(domain->domain, name))
5765 break;
5766 }
5767 }
5768
5769 if (domain == NULL)
5770 fatal("domain '%s' does not exist", name);
5771 } else {
5772 if ((domain = kore_domain_byid(1)) != NULL)
5773 fatal("ambiguous domain on route, please specify one");
5774 if ((domain = kore_domain_byid(0)) == NULL)
5775 fatal("no domains configured, please configure one");
5776 }
5777
5778 return (domain);
5779 }
5780
5781 static int
5782 python_route_methods(PyObject *obj, PyObject *kwargs, struct kore_route *rt)
5783 {
5784 const char *val;
5785 PyObject *item;
5786 int method;
5787 Py_ssize_t list_len, idx;
5788
5789 if (!PyList_CheckExact(obj)) {
5790 PyErr_SetString(PyExc_RuntimeError, "methods not a list");
5791 return (KORE_RESULT_ERROR);
5792 }
5793
5794 rt->methods = 0;
5795 list_len = PyList_Size(obj);
5796
5797 for (idx = 0; idx < list_len; idx++) {
5798 if ((item = PyList_GetItem(obj, idx)) == NULL)
5799 return (KORE_RESULT_ERROR);
5800
5801 if ((val = PyUnicode_AsUTF8(item)) == NULL)
5802 return (KORE_RESULT_ERROR);
5803
5804 if ((method = http_method_value(val)) == 0) {
5805 PyErr_Format(PyExc_RuntimeError,
5806 "unknown HTTP method: %s", val);
5807 return (KORE_RESULT_ERROR);
5808 }
5809
5810 rt->methods |= method;
5811 if (method == HTTP_METHOD_GET)
5812 rt->methods |= HTTP_METHOD_HEAD;
5813
5814 if (!python_route_params(kwargs, rt, val, method, 0))
5815 return (KORE_RESULT_ERROR);
5816
5817 if (!python_route_params(kwargs, rt, "qs", method, 1))
5818 return (KORE_RESULT_ERROR);
5819 }
5820
5821 return (KORE_RESULT_OK);
5822 }
5823
5824 static int
5825 python_route_params(PyObject *kwargs, struct kore_route *rt,
5826 const char *method, int type, int qs)
5827 {
5828 Py_ssize_t idx;
5829 const char *val;
5830 int vtype;
5831 struct kore_validator *vldr;
5832 struct kore_route_params *param;
5833 PyObject *obj, *key, *item;
5834
5835 if ((obj = PyDict_GetItemString(kwargs, method)) == NULL)
5836 return (KORE_RESULT_OK);
5837
5838 if (!PyDict_CheckExact(obj))
5839 return (KORE_RESULT_ERROR);
5840
5841 idx = 0;
5842 while (PyDict_Next(obj, &idx, &key, &item)) {
5843 if (!PyUnicode_CheckExact(key))
5844 return (KORE_RESULT_ERROR);
5845
5846 val = PyUnicode_AsUTF8(key);
5847
5848 if (PyUnicode_CheckExact(item)) {
5849 vtype = KORE_VALIDATOR_TYPE_REGEX;
5850 } else if (PyCallable_Check(item)) {
5851 vtype = KORE_VALIDATOR_TYPE_FUNCTION;
5852 } else {
5853 PyErr_Format(PyExc_RuntimeError,
5854 "validator '%s' must be regex or function", val);
5855 return (KORE_RESULT_ERROR);
5856 }
5857
5858 vldr = kore_calloc(1, sizeof(*vldr));
5859 vldr->type = vtype;
5860
5861 if (vtype == KORE_VALIDATOR_TYPE_REGEX) {
5862 val = PyUnicode_AsUTF8(item);
5863 if (regcomp(&(vldr->rctx),
5864 val, REG_EXTENDED | REG_NOSUB)) {
5865 PyErr_Format(PyExc_RuntimeError,
5866 "Invalid regex (%s)", val);
5867 kore_free(vldr);
5868 return (KORE_RESULT_ERROR);
5869 }
5870 } else {
5871 vldr->rcall = kore_calloc(1, sizeof(*vldr->rcall));
5872 vldr->rcall->addr = item;
5873 vldr->rcall->runtime = &kore_python_runtime;
5874 Py_INCREF(item);
5875 }
5876
5877 val = PyUnicode_AsUTF8(key);
5878 vldr->name = kore_strdup(val);
5879
5880 param = kore_calloc(1, sizeof(*param));
5881 param->flags = 0;
5882 param->method = type;
5883 param->validator = vldr;
5884 param->name = kore_strdup(val);
5885
5886 if (type == HTTP_METHOD_GET || qs == 1)
5887 param->flags = KORE_PARAMS_QUERY_STRING;
5888
5889 TAILQ_INSERT_TAIL(&rt->params, param, list);
5890 }
5891
5892 return (KORE_RESULT_OK);
5893 }
5894
5895 static int
5896 python_route_auth(PyObject *dict, struct kore_route *rt)
5897 {
5898 int type;
5899 struct kore_auth *auth;
5900 struct kore_validator *vldr;
5901 PyObject *obj, *repr;
5902 const char *value, *redir;
5903
5904 if (!PyDict_CheckExact(dict))
5905 return (KORE_RESULT_ERROR);
5906
5907 if ((value = python_string_from_dict(dict, "type")) == NULL) {
5908 PyErr_SetString(PyExc_RuntimeError,
5909 "missing or invalid 'type' keyword");
5910 return (KORE_RESULT_ERROR);
5911 }
5912
5913 if (!strcmp(value, "cookie")) {
5914 type = KORE_AUTH_TYPE_COOKIE;
5915 } else if (!strcmp(value, "header")) {
5916 type = KORE_AUTH_TYPE_HEADER;
5917 } else {
5918 PyErr_Format(PyExc_RuntimeError,
5919 "invalid 'type' (%s) in auth dictionary for '%s'",
5920 value, rt->path);
5921 return (KORE_RESULT_ERROR);
5922 }
5923
5924 if ((value = python_string_from_dict(dict, "value")) == NULL) {
5925 PyErr_SetString(PyExc_RuntimeError,
5926 "missing or invalid 'value' keyword");
5927 return (KORE_RESULT_ERROR);
5928 }
5929
5930 redir = python_string_from_dict(dict, "redirect");
5931
5932 if ((obj = PyDict_GetItemString(dict, "verify")) == NULL ||
5933 !PyCallable_Check(obj)) {
5934 PyErr_Format(PyExc_RuntimeError,
5935 "missing 'verify' in auth dictionary for '%s'", rt->path);
5936 return (KORE_RESULT_ERROR);
5937 }
5938
5939 auth = kore_calloc(1, sizeof(*auth));
5940 auth->type = type;
5941 auth->value = kore_strdup(value);
5942
5943 if (redir != NULL)
5944 auth->redirect = kore_strdup(redir);
5945
5946 vldr = kore_calloc(1, sizeof(*vldr));
5947 vldr->type = KORE_VALIDATOR_TYPE_FUNCTION;
5948
5949 vldr->rcall = kore_calloc(1, sizeof(*vldr->rcall));
5950 vldr->rcall->addr = obj;
5951 vldr->rcall->runtime = &kore_python_runtime;
5952 Py_INCREF(obj);
5953
5954 if ((repr = PyObject_Repr(obj)) == NULL) {
5955 kore_free(vldr->rcall);
5956 kore_free(vldr);
5957 kore_free(auth);
5958 return (KORE_RESULT_ERROR);
5959 }
5960
5961 value = PyUnicode_AsUTF8(repr);
5962 vldr->name = kore_strdup(value);
5963 Py_DECREF(repr);
5964
5965 auth->validator = vldr;
5966 rt->auth = auth;
5967
5968 return (KORE_RESULT_OK);
5969 }
5970
5971 static int
5972 python_route_hooks(PyObject *dict, struct kore_route *rt)
5973 {
5974 if (!PyDict_CheckExact(dict))
5975 return (KORE_RESULT_ERROR);
5976
5977 if (!python_route_hook_set(dict, "on_free", &rt->on_free))
5978 return (KORE_RESULT_ERROR);
5979
5980 if (!python_route_hook_set(dict, "on_headers", &rt->on_headers))
5981 return (KORE_RESULT_ERROR);
5982
5983 if (!python_route_hook_set(dict, "on_body_chunk", &rt->on_body_chunk))
5984 return (KORE_RESULT_ERROR);
5985
5986 return (KORE_RESULT_OK);
5987 }
5988
5989 static int
5990 python_route_hook_set(PyObject *dict, const char *name,
5991 struct kore_runtime_call **out)
5992 {
5993 PyObject *obj;
5994 struct kore_runtime_call *rcall;
5995
5996 if ((obj = PyDict_GetItemString(dict, name)) == NULL)
5997 return (KORE_RESULT_OK);
5998
5999 if (!PyCallable_Check(obj)) {
6000 PyErr_Format(PyExc_RuntimeError,
6001 "%s for a route not callable", name);
6002 Py_DECREF(obj);
6003 return (KORE_RESULT_ERROR);
6004 }
6005
6006 rcall = kore_calloc(1, sizeof(struct kore_runtime_call));
6007 rcall->addr = obj;
6008 rcall->runtime = &kore_python_runtime;
6009
6010 Py_INCREF(rcall->addr);
6011 *out = rcall;
6012
6013 return (KORE_RESULT_OK);
6014 }
6015
6016 #if defined(KORE_USE_PGSQL)
6017 static PyObject *
6018 python_kore_pgsql_query(PyObject *self, PyObject *args, PyObject *kwargs)
6019 {
6020 struct pykore_pgsql *op;
6021 PyObject *obj;
6022 const char *db, *query;
6023
6024 if (!PyArg_ParseTuple(args, "ss", &db, &query))
6025 return (NULL);
6026
6027 op = PyObject_New(struct pykore_pgsql, &pykore_pgsql_type);
6028 if (op == NULL)
6029 return (NULL);
6030
6031 op->binary = 0;
6032 op->param.count = 0;
6033 op->param.objs = NULL;
6034 op->param.values = NULL;
6035 op->param.lengths = NULL;
6036 op->param.formats = NULL;
6037
6038 op->result = NULL;
6039 op->coro = coro_running;
6040 op->db = kore_strdup(db);
6041 op->query = kore_strdup(query);
6042 op->state = PYKORE_PGSQL_PREINIT;
6043
6044 memset(&op->sql, 0, sizeof(op->sql));
6045
6046 if (kwargs != NULL) {
6047 if ((obj = PyDict_GetItemString(kwargs, "params")) != NULL) {
6048 if (!pykore_pgsql_params(op, obj)) {
6049 Py_DECREF((PyObject *)op);
6050 return (NULL);
6051 }
6052 }
6053
6054 if ((obj = PyDict_GetItemString(kwargs, "binary")) != NULL) {
6055 if (obj == Py_True) {
6056 op->binary = 1;
6057 } else if (obj == Py_False) {
6058 op->binary = 0;
6059 } else {
6060 Py_DECREF((PyObject *)op);
6061 PyErr_SetString(PyExc_RuntimeError,
6062 "pgsql: binary not True or False");
6063 return (NULL);
6064 }
6065 }
6066 }
6067
6068 return ((PyObject *)op);
6069 }
6070
6071 static int
6072 pykore_pgsql_params(struct pykore_pgsql *op, PyObject *list)
6073 {
6074 union { const char *cp; char *p; } ptr;
6075 PyObject *item;
6076 int format;
6077 Py_ssize_t i, len, vlen;
6078
6079 if (!PyList_CheckExact(list)) {
6080 if (list == Py_None)
6081 return (KORE_RESULT_OK);
6082
6083 PyErr_SetString(PyExc_RuntimeError,
6084 "pgsql: params keyword must be a list");
6085 return (KORE_RESULT_ERROR);
6086 }
6087
6088 len = PyList_Size(list);
6089 if (len == 0)
6090 return (KORE_RESULT_OK);
6091
6092 if (len > INT_MAX) {
6093 PyErr_SetString(PyExc_RuntimeError,
6094 "pgsql: list length too large");
6095 return (KORE_RESULT_ERROR);
6096 }
6097
6098 op->param.count = len;
6099 op->param.lengths = kore_calloc(len, sizeof(int));
6100 op->param.formats = kore_calloc(len, sizeof(int));
6101 op->param.values = kore_calloc(len, sizeof(char *));
6102 op->param.objs = kore_calloc(len, sizeof(PyObject *));
6103
6104 for (i = 0; i < len; i++) {
6105 if ((item = PyList_GetItem(list, i)) == NULL)
6106 return (KORE_RESULT_ERROR);
6107
6108 if (PyUnicode_CheckExact(item)) {
6109 format = 0;
6110 ptr.cp = PyUnicode_AsUTF8AndSize(item, &vlen);
6111 } else if (PyBytes_CheckExact(item)) {
6112 format = 1;
6113 if (PyBytes_AsStringAndSize(item, &ptr.p, &vlen) == -1)
6114 ptr.p = NULL;
6115 } else {
6116 PyErr_Format(PyExc_RuntimeError,
6117 "pgsql: item %zu is not a string or bytes", i);
6118 return (KORE_RESULT_ERROR);
6119 }
6120
6121 if (ptr.cp == NULL)
6122 return (KORE_RESULT_ERROR);
6123
6124 op->param.lengths[i] = vlen;
6125 op->param.values[i] = ptr.cp;
6126 op->param.formats[i] = format;
6127
6128 /* Hold on to it since we are directly referencing its data. */
6129 op->param.objs[i] = item;
6130 Py_INCREF(item);
6131 }
6132
6133 return (KORE_RESULT_OK);
6134 }
6135
6136 static void
6137 pykore_pgsql_dealloc(struct pykore_pgsql *pysql)
6138 {
6139 Py_ssize_t i;
6140
6141 kore_free(pysql->db);
6142 kore_free(pysql->query);
6143 kore_pgsql_cleanup(&pysql->sql);
6144
6145 if (pysql->result != NULL)
6146 Py_DECREF(pysql->result);
6147
6148 for (i = 0; i < pysql->param.count; i++)
6149 Py_XDECREF(pysql->param.objs[i]);
6150
6151 kore_free(pysql->param.objs);
6152 kore_free(pysql->param.values);
6153 kore_free(pysql->param.lengths);
6154 kore_free(pysql->param.formats);
6155
6156 PyObject_Del((PyObject *)pysql);
6157 }
6158
6159 static PyObject *
6160 pykore_pgsql_iternext(struct pykore_pgsql *pysql)
6161 {
6162 switch (pysql->state) {
6163 case PYKORE_PGSQL_PREINIT:
6164 kore_pgsql_init(&pysql->sql);
6165 kore_pgsql_bind_callback(&pysql->sql,
6166 pykore_pgsql_callback, pysql);
6167 pysql->state = PYKORE_PGSQL_INITIALIZE;
6168 /* fallthrough */
6169 case PYKORE_PGSQL_INITIALIZE:
6170 if (!kore_pgsql_setup(&pysql->sql, pysql->db,
6171 KORE_PGSQL_ASYNC)) {
6172 if (pysql->sql.state == KORE_PGSQL_STATE_INIT)
6173 break;
6174 PyErr_Format(PyExc_RuntimeError, "pgsql error: %s",
6175 pysql->sql.error);
6176 return (NULL);
6177 }
6178 /* fallthrough */
6179 case PYKORE_PGSQL_QUERY:
6180 if (pysql->param.count > 0) {
6181 if (!kore_pgsql_query_param_fields(&pysql->sql,
6182 pysql->query, pysql->binary,
6183 pysql->param.count, pysql->param.values,
6184 pysql->param.lengths, pysql->param.formats)) {
6185 PyErr_Format(PyExc_RuntimeError,
6186 "pgsql error: %s", pysql->sql.error);
6187 return (NULL);
6188 }
6189 } else {
6190 if (!kore_pgsql_query(&pysql->sql, pysql->query)) {
6191 PyErr_Format(PyExc_RuntimeError,
6192 "pgsql error: %s", pysql->sql.error);
6193 return (NULL);
6194 }
6195 }
6196 pysql->state = PYKORE_PGSQL_WAIT;
6197 break;
6198 wait_again:
6199 case PYKORE_PGSQL_WAIT:
6200 switch (pysql->sql.state) {
6201 case KORE_PGSQL_STATE_WAIT:
6202 break;
6203 case KORE_PGSQL_STATE_COMPLETE:
6204 PyErr_SetNone(PyExc_StopIteration);
6205 if (pysql->result != NULL) {
6206 PyErr_SetObject(PyExc_StopIteration,
6207 pysql->result);
6208 Py_DECREF(pysql->result);
6209 pysql->result = NULL;
6210 } else {
6211 PyErr_SetObject(PyExc_StopIteration, Py_None);
6212 }
6213 return (NULL);
6214 case KORE_PGSQL_STATE_ERROR:
6215 PyErr_Format(PyExc_RuntimeError,
6216 "failed to perform query: %s", pysql->sql.error);
6217 return (NULL);
6218 case KORE_PGSQL_STATE_RESULT:
6219 if (!pykore_pgsql_result(pysql))
6220 return (NULL);
6221 goto wait_again;
6222 default:
6223 kore_pgsql_continue(&pysql->sql);
6224 goto wait_again;
6225 }
6226 break;
6227 default:
6228 PyErr_SetString(PyExc_RuntimeError, "bad pykore_pgsql state");
6229 return (NULL);
6230 }
6231
6232 /* tell caller to wait. */
6233 Py_RETURN_NONE;
6234 }
6235
6236 static void
6237 pykore_pgsql_callback(struct kore_pgsql *pgsql, void *arg)
6238 {
6239 struct pykore_pgsql *op = arg;
6240
6241 if (op->coro->request != NULL)
6242 http_request_wakeup(op->coro->request);
6243 else
6244 python_coro_wakeup(op->coro);
6245 }
6246
6247 static PyObject *
6248 pykore_pgsql_await(PyObject *obj)
6249 {
6250 Py_INCREF(obj);
6251 return (obj);
6252 }
6253
6254 static int
6255 pykore_pgsql_result(struct pykore_pgsql *pysql)
6256 {
6257 const char *val;
6258 char key[64];
6259 PyObject *list, *pyrow, *pyval;
6260 int rows, row, field, fields, len;
6261
6262 if ((list = PyList_New(0)) == NULL) {
6263 PyErr_SetNone(PyExc_MemoryError);
6264 return (KORE_RESULT_ERROR);
6265 }
6266
6267 rows = kore_pgsql_ntuples(&pysql->sql);
6268 fields = kore_pgsql_nfields(&pysql->sql);
6269
6270 for (row = 0; row < rows; row++) {
6271 if ((pyrow = PyDict_New()) == NULL) {
6272 Py_DECREF(list);
6273 PyErr_SetNone(PyExc_MemoryError);
6274 return (KORE_RESULT_ERROR);
6275 }
6276
6277 for (field = 0; field < fields; field++) {
6278 val = kore_pgsql_getvalue(&pysql->sql, row, field);
6279 len = kore_pgsql_getlength(&pysql->sql, row, field);
6280
6281 if (kore_pgsql_column_binary(&pysql->sql, field)) {
6282 pyval = PyBytes_FromStringAndSize(val, len);
6283 } else {
6284 pyval = PyUnicode_FromString(val);
6285 }
6286
6287 if (pyval == NULL) {
6288 Py_DECREF(pyrow);
6289 Py_DECREF(list);
6290 PyErr_SetNone(PyExc_MemoryError);
6291 return (KORE_RESULT_ERROR);
6292 }
6293
6294 (void)snprintf(key, sizeof(key), "%s",
6295 kore_pgsql_fieldname(&pysql->sql, field));
6296
6297 if (PyDict_SetItemString(pyrow, key, pyval) == -1) {
6298 Py_DECREF(pyval);
6299 Py_DECREF(pyrow);
6300 Py_DECREF(list);
6301 PyErr_SetString(PyExc_RuntimeError,
6302 "failed to add new value to row");
6303 return (KORE_RESULT_ERROR);
6304 }
6305
6306 Py_DECREF(pyval);
6307 }
6308
6309 if (PyList_Insert(list, row, pyrow) == -1) {
6310 Py_DECREF(pyrow);
6311 Py_DECREF(list);
6312 PyErr_SetString(PyExc_RuntimeError,
6313 "failed to add new row to list");
6314 return (KORE_RESULT_ERROR);
6315 }
6316
6317 Py_DECREF(pyrow);
6318 }
6319
6320 pysql->result = list;
6321 kore_pgsql_continue(&pysql->sql);
6322
6323 return (KORE_RESULT_OK);
6324 }
6325 #endif
6326
6327 #if defined(KORE_USE_CURL)
6328 static PyObject *
6329 python_curlopt_set(struct pycurl_data *data, long opt, PyObject *value)
6330 {
6331 int i;
6332
6333 for (i = 0; py_curlopt[i].name != NULL; i++) {
6334 if (py_curlopt[i].value == opt)
6335 break;
6336 }
6337
6338 if (py_curlopt[i].name == NULL) {
6339 PyErr_Format(PyExc_RuntimeError, "invalid option '%ld'", opt);
6340 return (NULL);
6341 }
6342
6343 if (py_curlopt[i].cb == NULL) {
6344 PyErr_Format(PyExc_RuntimeError, "option '%s' not implemented",
6345 py_curlopt[i].name);
6346 return (NULL);
6347 }
6348
6349 return (py_curlopt[i].cb(data, i, value));
6350 }
6351
6352 static int
6353 python_curlopt_from_dict(struct pycurl_data *data, PyObject *dict)
6354 {
6355 long opt;
6356 Py_ssize_t idx;
6357 PyObject *key, *value, *obj;
6358
6359 idx = 0;
6360
6361 if (!PyDict_CheckExact(dict)) {
6362 PyErr_SetString(PyExc_RuntimeError,
6363 "curlopt must be a dictionary");
6364 return (KORE_RESULT_ERROR);
6365 }
6366
6367 while (PyDict_Next(dict, &idx, &key, &value)) {
6368 if (!PyLong_CheckExact(key)) {
6369 PyErr_Format(PyExc_RuntimeError,
6370 "invalid key in curlopt keyword");
6371 return (KORE_RESULT_ERROR);
6372 }
6373
6374 opt = PyLong_AsLong(key);
6375
6376 if ((obj = python_curlopt_set(data, opt, value)) == NULL)
6377 return (KORE_RESULT_ERROR);
6378
6379 Py_DECREF(obj);
6380 }
6381
6382 return (KORE_RESULT_OK);
6383 }
6384
6385 static PyObject *
6386 python_kore_curl_handle(PyObject *self, PyObject *args)
6387 {
6388 const char *url;
6389 struct pycurl_handle *handle;
6390
6391 if (!PyArg_ParseTuple(args, "s", &url))
6392 return (NULL);
6393
6394 handle = PyObject_New(struct pycurl_handle, &pycurl_handle_type);
6395 if (handle == NULL)
6396 return (NULL);
6397
6398 handle->url = kore_strdup(url);
6399 memset(&handle->data.curl, 0, sizeof(handle->data.curl));
6400
6401 handle->body = NULL;
6402 LIST_INIT(&handle->data.slists);
6403
6404 if (!kore_curl_init(&handle->data.curl, handle->url, KORE_CURL_ASYNC)) {
6405 Py_DECREF((PyObject *)handle);
6406 PyErr_SetString(PyExc_RuntimeError, "failed to setup call");
6407 return (NULL);
6408 }
6409
6410 return ((PyObject *)handle);
6411 }
6412
6413 static void
6414 pycurl_handle_dealloc(struct pycurl_handle *handle)
6415 {
6416 struct pycurl_slist *psl;
6417
6418 while ((psl = LIST_FIRST(&handle->data.slists))) {
6419 LIST_REMOVE(psl, list);
6420 curl_slist_free_all(psl->slist);
6421 kore_free(psl);
6422 }
6423
6424 if (handle->body != NULL)
6425 kore_buf_free(handle->body);
6426
6427 kore_free(handle->url);
6428 kore_curl_cleanup(&handle->data.curl);
6429
6430 PyObject_Del((PyObject *)handle);
6431 }
6432
6433 static PyObject *
6434 pycurl_handle_setbody(struct pycurl_handle *handle, PyObject *args)
6435 {
6436 PyObject *obj;
6437 char *ptr;
6438 Py_ssize_t length;
6439
6440 if (!PyArg_ParseTuple(args, "O", &obj))
6441 return (NULL);
6442
6443 if (handle->body != NULL) {
6444 PyErr_SetString(PyExc_RuntimeError,
6445 "curl handle already has body attached");
6446 return (NULL);
6447 }
6448
6449 if (!PyBytes_CheckExact(obj)) {
6450 PyErr_SetString(PyExc_RuntimeError,
6451 "curl.setbody expects bytes");
6452 return (NULL);
6453 }
6454
6455 if (PyBytes_AsStringAndSize(obj, &ptr, &length) == -1)
6456 return (NULL);
6457
6458 if (length < 0) {
6459 PyErr_SetString(PyExc_TypeError, "invalid length");
6460 return (NULL);
6461 }
6462
6463 handle->body = kore_buf_alloc(length);
6464 kore_buf_append(handle->body, ptr, length);
6465 kore_buf_reset(handle->body);
6466
6467 curl_easy_setopt(handle->data.curl.handle,
6468 CURLOPT_READFUNCTION, kore_curl_frombuf);
6469 curl_easy_setopt(handle->data.curl.handle,
6470 CURLOPT_READDATA, handle->body);
6471
6472 curl_easy_setopt(handle->data.curl.handle, CURLOPT_UPLOAD, 1);
6473
6474 Py_RETURN_TRUE;
6475 }
6476
6477 static PyObject *
6478 pycurl_handle_setopt(struct pycurl_handle *handle, PyObject *args)
6479 {
6480 int opt;
6481 PyObject *value;
6482
6483 if (!PyArg_ParseTuple(args, "iO", &opt, &value))
6484 return (NULL);
6485
6486 return (python_curlopt_set(&handle->data, opt, value));
6487 }
6488
6489 static PyObject *
6490 pycurl_handle_setopt_string(struct pycurl_data *data, int idx, PyObject *obj)
6491 {
6492 const char *str;
6493 CURLoption option;
6494
6495 if (!PyUnicode_Check(obj)) {
6496 PyErr_Format(PyExc_RuntimeError,
6497 "option '%s' requires a string as argument",
6498 py_curlopt[idx].name);
6499 return (NULL);
6500 }
6501
6502 if ((str = PyUnicode_AsUTF8(obj)) == NULL)
6503 return (NULL);
6504
6505 option = CURLOPTTYPE_OBJECTPOINT + py_curlopt[idx].value;
6506 curl_easy_setopt(data->curl.handle, option, str);
6507
6508 Py_RETURN_TRUE;
6509 }
6510
6511 static PyObject *
6512 pycurl_handle_setopt_long(struct pycurl_data *data, int idx, PyObject *obj)
6513 {
6514 long val;
6515 CURLoption option;
6516
6517 if (!PyLong_CheckExact(obj)) {
6518 PyErr_Format(PyExc_RuntimeError,
6519 "option '%s' requires a long as argument",
6520 py_curlopt[idx].name);
6521 return (NULL);
6522 }
6523
6524 PyErr_Clear();
6525 val = PyLong_AsLong(obj);
6526 if (val == -1 && PyErr_Occurred())
6527 return (NULL);
6528
6529 option = CURLOPTTYPE_LONG + py_curlopt[idx].value;
6530 curl_easy_setopt(data->curl.handle, option, val);
6531
6532 Py_RETURN_TRUE;
6533 }
6534
6535 static PyObject *
6536 pycurl_handle_setopt_slist(struct pycurl_data *data, int idx, PyObject *obj)
6537 {
6538 struct pycurl_slist *psl;
6539 PyObject *item;
6540 const char *sval;
6541 struct curl_slist *slist;
6542 CURLoption option;
6543 Py_ssize_t list_len, i;
6544
6545 if (!PyList_CheckExact(obj)) {
6546 PyErr_Format(PyExc_RuntimeError,
6547 "option '%s' requires a list as argument",
6548 py_curlopt[idx].name);
6549 return (NULL);
6550 }
6551
6552 slist = NULL;
6553 list_len = PyList_Size(obj);
6554
6555 for (i = 0; i < list_len; i++) {
6556 if ((item = PyList_GetItem(obj, i)) == NULL)
6557 return (NULL);
6558
6559 if (!PyUnicode_Check(item))
6560 return (NULL);
6561
6562 if ((sval = PyUnicode_AsUTF8AndSize(item, NULL)) == NULL)
6563 return (NULL);
6564
6565 if ((slist = curl_slist_append(slist, sval)) == NULL)
6566 fatal("%s: curl_slist_append failed", __func__);
6567 }
6568
6569 psl = kore_calloc(1, sizeof(*psl));
6570 psl->slist = slist;
6571 LIST_INSERT_HEAD(&data->slists, psl, list);
6572
6573 option = CURLOPTTYPE_OBJECTPOINT + py_curlopt[idx].value;
6574 curl_easy_setopt(data->curl.handle, option, slist);
6575
6576 Py_RETURN_TRUE;
6577 }
6578
6579 static PyObject *
6580 pycurl_handle_run(struct pycurl_handle *handle, PyObject *args)
6581 {
6582 struct pycurl_handle_op *op;
6583
6584 op = PyObject_New(struct pycurl_handle_op, &pycurl_handle_op_type);
6585 if (op == NULL)
6586 return (NULL);
6587
6588 Py_INCREF(handle);
6589
6590 op->handle = handle;
6591 op->coro = coro_running;
6592 op->state = CURL_CLIENT_OP_RUN;
6593
6594 kore_curl_bind_callback(&handle->data.curl,
6595 python_curl_handle_callback, op);
6596
6597 return ((PyObject *)op);
6598 }
6599
6600 static void
6601 pycurl_handle_op_dealloc(struct pycurl_handle_op *op)
6602 {
6603 Py_DECREF(op->handle);
6604 PyObject_Del((PyObject *)op);
6605 }
6606
6607 static PyObject *
6608 pycurl_handle_op_await(PyObject *op)
6609 {
6610 Py_INCREF(op);
6611 return (op);
6612 }
6613
6614 static PyObject *
6615 pycurl_handle_op_iternext(struct pycurl_handle_op *op)
6616 {
6617 size_t len;
6618 PyObject *result;
6619 const u_int8_t *response;
6620
6621 if (op->state == CURL_CLIENT_OP_RUN) {
6622 kore_curl_run(&op->handle->data.curl);
6623 op->state = CURL_CLIENT_OP_RESULT;
6624 Py_RETURN_NONE;
6625 }
6626
6627 if (op->handle->body != NULL) {
6628 kore_buf_free(op->handle->body);
6629 op->handle->body = NULL;
6630 }
6631
6632 if (!kore_curl_success(&op->handle->data.curl)) {
6633 /* Do not log the url here, may contain some sensitive data. */
6634 PyErr_Format(PyExc_RuntimeError, "request failed: %s",
6635 kore_curl_strerror(&op->handle->data.curl));
6636 return (NULL);
6637 }
6638
6639 kore_curl_response_as_bytes(&op->handle->data.curl, &response, &len);
6640
6641 if ((result = PyBytes_FromStringAndSize((const char *)response,
6642 len)) == NULL)
6643 return (NULL);
6644
6645 PyErr_SetObject(PyExc_StopIteration, result);
6646 Py_DECREF(result);
6647
6648 return (NULL);
6649 }
6650
6651 static PyObject *
6652 python_kore_httpclient(PyObject *self, PyObject *args, PyObject *kwargs)
6653 {
6654 struct pyhttp_client *client;
6655 const char *url, *v;
6656
6657 if (!PyArg_ParseTuple(args, "s", &url))
6658 return (NULL);
6659
6660 client = PyObject_New(struct pyhttp_client, &pyhttp_client_type);
6661 if (client == NULL)
6662 return (NULL);
6663
6664 client->unix = NULL;
6665 client->tlskey = NULL;
6666 client->curlopt = NULL;
6667 client->tlscert = NULL;
6668 client->cabundle = NULL;
6669
6670 client->tlsverify = 1;
6671 client->url = kore_strdup(url);
6672
6673 if (kwargs != NULL) {
6674 if ((v = python_string_from_dict(kwargs, "tlscert")) != NULL)
6675 client->tlscert = kore_strdup(v);
6676
6677 if ((v = python_string_from_dict(kwargs, "tlskey")) != NULL)
6678 client->tlskey = kore_strdup(v);
6679
6680 if ((v = python_string_from_dict(kwargs, "cabundle")) != NULL)
6681 client->cabundle = kore_strdup(v);
6682
6683 if ((v = python_string_from_dict(kwargs, "unix")) != NULL)
6684 client->unix = kore_strdup(v);
6685
6686 client->curlopt = PyDict_GetItemString(kwargs, "curlopt");
6687 Py_XINCREF(client->curlopt);
6688
6689 python_bool_from_dict(kwargs, "tlsverify", &client->tlsverify);
6690 }
6691
6692 if ((client->tlscert != NULL && client->tlskey == NULL) ||
6693 (client->tlskey != NULL && client->tlscert == NULL)) {
6694 Py_DECREF((PyObject *)client);
6695 PyErr_SetString(PyExc_RuntimeError,
6696 "invalid TLS client configuration");
6697 return (NULL);
6698 }
6699
6700 return ((PyObject *)client);
6701 }
6702
6703 static void
6704 pyhttp_client_dealloc(struct pyhttp_client *client)
6705 {
6706 kore_free(client->url);
6707 kore_free(client->unix);
6708 kore_free(client->tlskey);
6709 kore_free(client->tlscert);
6710 kore_free(client->cabundle);
6711
6712 Py_XDECREF(client->curlopt);
6713
6714 PyObject_Del((PyObject *)client);
6715 }
6716
6717 static PyObject *
6718 pyhttp_client_get(struct pyhttp_client *client, PyObject *args,
6719 PyObject *kwargs)
6720 {
6721 return (pyhttp_client_request(client, HTTP_METHOD_GET, kwargs));
6722 }
6723
6724 static PyObject *
6725 pyhttp_client_put(struct pyhttp_client *client, PyObject *args,
6726 PyObject *kwargs)
6727 {
6728 return (pyhttp_client_request(client, HTTP_METHOD_PUT, kwargs));
6729 }
6730
6731 static PyObject *
6732 pyhttp_client_post(struct pyhttp_client *client, PyObject *args,
6733 PyObject *kwargs)
6734 {
6735 return (pyhttp_client_request(client, HTTP_METHOD_POST, kwargs));
6736 }
6737
6738 static PyObject *
6739 pyhttp_client_head(struct pyhttp_client *client, PyObject *args,
6740 PyObject *kwargs)
6741 {
6742 return (pyhttp_client_request(client, HTTP_METHOD_HEAD, kwargs));
6743 }
6744
6745 static PyObject *
6746 pyhttp_client_patch(struct pyhttp_client *client, PyObject *args,
6747 PyObject *kwargs)
6748 {
6749 return (pyhttp_client_request(client, HTTP_METHOD_PATCH, kwargs));
6750 }
6751
6752 static PyObject *
6753 pyhttp_client_delete(struct pyhttp_client *client, PyObject *args,
6754 PyObject *kwargs)
6755 {
6756 return (pyhttp_client_request(client, HTTP_METHOD_DELETE, kwargs));
6757 }
6758
6759 static PyObject *
6760 pyhttp_client_options(struct pyhttp_client *client, PyObject *args,
6761 PyObject *kwargs)
6762 {
6763 return (pyhttp_client_request(client, HTTP_METHOD_OPTIONS, kwargs));
6764 }
6765
6766 static PyObject *
6767 pyhttp_client_request(struct pyhttp_client *client, int m, PyObject *kwargs)
6768 {
6769 struct pyhttp_client_op *op;
6770 char *ptr;
6771 const char *k, *v;
6772 Py_ssize_t length, idx;
6773 PyObject *data, *headers, *key, *obj;
6774
6775 ptr = NULL;
6776 length = 0;
6777 headers = NULL;
6778
6779 if (kwargs != NULL &&
6780 ((headers = PyDict_GetItemString(kwargs, "headers")) != NULL)) {
6781 if (!PyDict_CheckExact(headers)) {
6782 PyErr_SetString(PyExc_RuntimeError,
6783 "headers keyword must be a dict");
6784 return (NULL);
6785 }
6786 }
6787
6788 switch (m) {
6789 case HTTP_METHOD_GET:
6790 case HTTP_METHOD_HEAD:
6791 case HTTP_METHOD_OPTIONS:
6792 break;
6793 case HTTP_METHOD_PUT:
6794 case HTTP_METHOD_POST:
6795 case HTTP_METHOD_PATCH:
6796 case HTTP_METHOD_DELETE:
6797 length = -1;
6798
6799 if (kwargs == NULL) {
6800 if (m == HTTP_METHOD_DELETE) {
6801 length = 0;
6802 break;
6803 }
6804
6805 PyErr_Format(PyExc_RuntimeError,
6806 "no keyword arguments given, but body expected ",
6807 http_method_text(m));
6808 return (NULL);
6809 }
6810
6811 if ((data = PyDict_GetItemString(kwargs, "body")) == NULL)
6812 return (NULL);
6813
6814 if (PyBytes_AsStringAndSize(data, &ptr, &length) == -1)
6815 return (NULL);
6816
6817 if (length < 0) {
6818 PyErr_SetString(PyExc_TypeError, "invalid length");
6819 return (NULL);
6820 }
6821 break;
6822 default:
6823 fatal("%s: unknown method %d", __func__, m);
6824 }
6825
6826 op = PyObject_New(struct pyhttp_client_op, &pyhttp_client_op_type);
6827 if (op == NULL)
6828 return (NULL);
6829
6830 if (!kore_curl_init(&op->data.curl, client->url, KORE_CURL_ASYNC)) {
6831 Py_DECREF((PyObject *)op);
6832 PyErr_SetString(PyExc_RuntimeError, "failed to setup call");
6833 return (NULL);
6834 }
6835
6836 op->headers = 0;
6837 op->coro = coro_running;
6838 op->state = CURL_CLIENT_OP_RUN;
6839 LIST_INIT(&op->data.slists);
6840
6841 Py_INCREF(client);
6842 op->client = client;
6843
6844 kore_curl_http_setup(&op->data.curl, m, ptr, length);
6845 kore_curl_bind_callback(&op->data.curl, python_curl_http_callback, op);
6846
6847 /* Go in with our own bare hands. */
6848 if (client->unix != NULL) {
6849 #if defined(__linux__)
6850 if (client->unix[0] == '@') {
6851 curl_easy_setopt(op->data.curl.handle,
6852 CURLOPT_ABSTRACT_UNIX_SOCKET, client->unix + 1);
6853 } else {
6854 curl_easy_setopt(op->data.curl.handle,
6855 CURLOPT_UNIX_SOCKET_PATH, client->unix);
6856 }
6857 #else
6858 curl_easy_setopt(op->data.curl.handle, CURLOPT_UNIX_SOCKET_PATH,
6859 client->unix);
6860 #endif
6861 }
6862
6863 if (client->tlskey != NULL && client->tlscert != NULL) {
6864 curl_easy_setopt(op->data.curl.handle, CURLOPT_SSLCERT,
6865 client->tlscert);
6866 curl_easy_setopt(op->data.curl.handle, CURLOPT_SSLKEY,
6867 client->tlskey);
6868 }
6869
6870 if (client->tlsverify == 0) {
6871 curl_easy_setopt(op->data.curl.handle,
6872 CURLOPT_SSL_VERIFYHOST, 0);
6873 curl_easy_setopt(op->data.curl.handle,
6874 CURLOPT_SSL_VERIFYPEER, 0);
6875 }
6876
6877 if (client->curlopt != NULL) {
6878 if (!python_curlopt_from_dict(&op->data, client->curlopt)) {
6879 Py_DECREF((PyObject *)op);
6880 return (NULL);
6881 }
6882 }
6883
6884 if (client->cabundle != NULL) {
6885 curl_easy_setopt(op->data.curl.handle, CURLOPT_CAINFO,
6886 client->cabundle);
6887 }
6888
6889 if (headers != NULL) {
6890 idx = 0;
6891 while (PyDict_Next(headers, &idx, &key, &obj)) {
6892 if ((k = PyUnicode_AsUTF8(key)) == NULL) {
6893 Py_DECREF((PyObject *)op);
6894 return (NULL);
6895 }
6896
6897 if ((v = PyUnicode_AsUTF8(obj)) == NULL) {
6898 Py_DECREF((PyObject *)op);
6899 return (NULL);
6900 }
6901
6902 kore_curl_http_set_header(&op->data.curl, k, v);
6903 }
6904 }
6905
6906 if (kwargs != NULL) {
6907 if ((obj = PyDict_GetItemString(kwargs, "curlopt")) != NULL) {
6908 if (!python_curlopt_from_dict(&op->data, obj)) {
6909 Py_DECREF((PyObject *)op);
6910 return (NULL);
6911 }
6912 }
6913
6914 python_bool_from_dict(kwargs, "return_headers", &op->headers);
6915 }
6916
6917 return ((PyObject *)op);
6918 }
6919
6920 static void
6921 pyhttp_client_op_dealloc(struct pyhttp_client_op *op)
6922 {
6923 struct pycurl_slist *psl;
6924
6925 while ((psl = LIST_FIRST(&op->data.slists))) {
6926 LIST_REMOVE(psl, list);
6927 curl_slist_free_all(psl->slist);
6928 kore_free(psl);
6929 }
6930
6931 Py_DECREF(op->client);
6932 kore_curl_cleanup(&op->data.curl);
6933 PyObject_Del((PyObject *)op);
6934 }
6935
6936 static PyObject *
6937 pyhttp_client_op_await(PyObject *op)
6938 {
6939 Py_INCREF(op);
6940 return (op);
6941 }
6942
6943 static PyObject *
6944 pyhttp_client_op_iternext(struct pyhttp_client_op *op)
6945 {
6946 size_t len;
6947 struct http_header *hdr;
6948 const u_int8_t *response;
6949 PyObject *result, *tuple, *dict, *value;
6950
6951 if (op->state == CURL_CLIENT_OP_RUN) {
6952 kore_curl_run(&op->data.curl);
6953 op->state = CURL_CLIENT_OP_RESULT;
6954 Py_RETURN_NONE;
6955 }
6956
6957 if (!kore_curl_success(&op->data.curl)) {
6958 PyErr_Format(PyExc_RuntimeError, "request to '%s' failed: %s",
6959 op->data.curl.url, kore_curl_strerror(&op->data.curl));
6960 return (NULL);
6961 }
6962
6963 kore_curl_response_as_bytes(&op->data.curl, &response, &len);
6964
6965 if (op->headers) {
6966 kore_curl_http_parse_headers(&op->data.curl);
6967
6968 if ((dict = PyDict_New()) == NULL)
6969 return (NULL);
6970
6971 TAILQ_FOREACH(hdr, &op->data.curl.http.resp_hdrs, list) {
6972 value = PyUnicode_FromString(hdr->value);
6973 if (value == NULL) {
6974 Py_DECREF(dict);
6975 return (NULL);
6976 }
6977
6978 if (PyDict_SetItemString(dict,
6979 hdr->header, value) == -1) {
6980 Py_DECREF(dict);
6981 Py_DECREF(value);
6982 return (NULL);
6983 }
6984
6985 Py_DECREF(value);
6986 }
6987
6988 if ((tuple = Py_BuildValue("(iOy#)", op->data.curl.http.status,
6989 dict, (const char *)response, len)) == NULL)
6990 return (NULL);
6991
6992 Py_DECREF(dict);
6993 } else {
6994 if ((tuple = Py_BuildValue("(iy#)", op->data.curl.http.status,
6995 (const char *)response, len)) == NULL)
6996 return (NULL);
6997 }
6998
6999 result = PyObject_CallFunctionObjArgs(PyExc_StopIteration, tuple, NULL);
7000 if (result == NULL) {
7001 Py_DECREF(tuple);
7002 return (NULL);
7003 }
7004
7005 Py_DECREF(tuple);
7006 PyErr_SetObject(PyExc_StopIteration, result);
7007 Py_DECREF(result);
7008
7009 return (NULL);
7010 }
7011
7012 static void
7013 python_curl_http_callback(struct kore_curl *curl, void *arg)
7014 {
7015 struct pyhttp_client_op *op = arg;
7016
7017 if (op->coro->request != NULL)
7018 http_request_wakeup(op->coro->request);
7019 else
7020 python_coro_wakeup(op->coro);
7021 }
7022
7023 static void
7024 python_curl_handle_callback(struct kore_curl *curl, void *arg)
7025 {
7026 struct pycurl_handle_op *op = arg;
7027
7028 if (op->coro->request != NULL)
7029 http_request_wakeup(op->coro->request);
7030 else
7031 python_coro_wakeup(op->coro);
7032 }
7033 #endif