kore

Kore is a web application platform for writing scalable, concurrent web based processes in C or Python.
Commits | Files | Refs | README | LICENSE | git clone https://git.kore.io/kore.git

python.c (156750B)



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