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