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