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