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