kore

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

python_methods.h (33250B)



      1 /*
      2  * Copyright (c) 2017-2022 Joris Vink <joris@coders.se>
      3  *
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #define CORO_STATE_RUNNABLE		1
     18 #define CORO_STATE_SUSPENDED		2
     19 
     20 struct python_coro {
     21 	u_int64_t			id;
     22 	int				state;
     23 	int				killed;
     24 	PyObject			*obj;
     25 	char				*name;
     26 	PyObject			*result;
     27 	struct pylock_op		*lockop;
     28 	struct pysocket_op		*sockop;
     29 	struct pygather_op		*gatherop;
     30 	struct http_request		*request;
     31 	PyObject			*exception;
     32 	char				*exception_msg;
     33 	TAILQ_ENTRY(python_coro)	list;
     34 };
     35 
     36 TAILQ_HEAD(coro_list, python_coro);
     37 
     38 static PyObject		*python_kore_app(PyObject *, PyObject *);
     39 static PyObject		*python_kore_log(PyObject *, PyObject *);
     40 static PyObject		*python_kore_time(PyObject *, PyObject *);
     41 static PyObject		*python_kore_lock(PyObject *, PyObject *);
     42 static PyObject		*python_kore_fatal(PyObject *, PyObject *);
     43 static PyObject		*python_kore_queue(PyObject *, PyObject *);
     44 static PyObject		*python_kore_worker(PyObject *, PyObject *);
     45 static PyObject		*python_kore_tracer(PyObject *, PyObject *);
     46 static PyObject		*python_kore_fatalx(PyObject *, PyObject *);
     47 static PyObject		*python_kore_task_id(PyObject *, PyObject *);
     48 static PyObject		*python_kore_sigtrap(PyObject *, PyObject *);
     49 static PyObject		*python_kore_setname(PyObject *, PyObject *);
     50 static PyObject		*python_kore_suspend(PyObject *, PyObject *);
     51 static PyObject		*python_kore_shutdown(PyObject *, PyObject *);
     52 static PyObject		*python_kore_coroname(PyObject *, PyObject *);
     53 static PyObject		*python_kore_corotrace(PyObject *, PyObject *);
     54 static PyObject		*python_kore_task_kill(PyObject *, PyObject *);
     55 static PyObject		*python_kore_prerequest(PyObject *, PyObject *);
     56 static PyObject		*python_kore_task_create(PyObject *, PyObject *);
     57 static PyObject		*python_kore_socket_wrap(PyObject *, PyObject *);
     58 static PyObject		*python_kore_proc(PyObject *, PyObject *, PyObject *);
     59 static PyObject		*python_kore_route(PyObject *, PyObject *, PyObject *);
     60 static PyObject		*python_kore_timer(PyObject *, PyObject *, PyObject *);
     61 static PyObject		*python_kore_domain(PyObject *, PyObject *, PyObject *);
     62 static PyObject		*python_kore_gather(PyObject *, PyObject *, PyObject *);
     63 static PyObject		*python_kore_sendobj(PyObject *, PyObject *,
     64 			    PyObject *);
     65 static PyObject		*python_kore_server(PyObject *, PyObject *,
     66 			    PyObject *);
     67 static PyObject		*python_kore_privsep(PyObject *, PyObject *,
     68 			    PyObject *);
     69 
     70 
     71 #if defined(KORE_USE_PGSQL)
     72 static PyObject		*python_kore_pgsql_query(PyObject *, PyObject *,
     73 			    PyObject *);
     74 static PyObject		*python_kore_pgsql_register(PyObject *, PyObject *);
     75 #endif
     76 
     77 #if defined(KORE_USE_CURL)
     78 static PyObject		*python_kore_curl_handle(PyObject *, PyObject *);
     79 static PyObject		*python_kore_httpclient(PyObject *,
     80 			    PyObject *, PyObject *);
     81 #endif
     82 
     83 static PyObject		*python_websocket_broadcast(PyObject *, PyObject *);
     84 
     85 #define METHOD(n, c, a)		{ n, (PyCFunction)c, a, NULL }
     86 #define GETTER(n, g)		{ n, (getter)g, NULL, NULL, NULL }
     87 #define SETTER(n, s)		{ n, NULL, (setter)s, NULL, NULL }
     88 #define GETSET(n, g, s)		{ n, (getter)g, (setter)s, NULL, NULL }
     89 
     90 static struct PyMethodDef pykore_methods[] = {
     91 	METHOD("app", python_kore_app, METH_VARARGS),
     92 	METHOD("log", python_kore_log, METH_VARARGS),
     93 	METHOD("time", python_kore_time, METH_NOARGS),
     94 	METHOD("lock", python_kore_lock, METH_NOARGS),
     95 	METHOD("queue", python_kore_queue, METH_VARARGS),
     96 	METHOD("worker", python_kore_worker, METH_VARARGS),
     97 	METHOD("tracer", python_kore_tracer, METH_VARARGS),
     98 	METHOD("fatal", python_kore_fatal, METH_VARARGS),
     99 	METHOD("fatalx", python_kore_fatalx, METH_VARARGS),
    100 	METHOD("task_id", python_kore_task_id, METH_NOARGS),
    101 	METHOD("sigtrap", python_kore_sigtrap, METH_VARARGS),
    102 	METHOD("setname", python_kore_setname, METH_VARARGS),
    103 	METHOD("suspend", python_kore_suspend, METH_VARARGS),
    104 	METHOD("shutdown", python_kore_shutdown, METH_NOARGS),
    105 	METHOD("coroname", python_kore_coroname, METH_VARARGS),
    106 	METHOD("corotrace", python_kore_corotrace, METH_VARARGS),
    107 	METHOD("task_kill", python_kore_task_kill, METH_VARARGS),
    108 	METHOD("prerequest", python_kore_prerequest, METH_VARARGS),
    109 	METHOD("task_create", python_kore_task_create, METH_VARARGS),
    110 	METHOD("socket_wrap", python_kore_socket_wrap, METH_VARARGS),
    111 	METHOD("proc", python_kore_proc, METH_VARARGS | METH_KEYWORDS),
    112 	METHOD("route", python_kore_route, METH_VARARGS | METH_KEYWORDS),
    113 	METHOD("timer", python_kore_timer, METH_VARARGS | METH_KEYWORDS),
    114 	METHOD("domain", python_kore_domain, METH_VARARGS | METH_KEYWORDS),
    115 	METHOD("server", python_kore_server, METH_VARARGS | METH_KEYWORDS),
    116 	METHOD("gather", python_kore_gather, METH_VARARGS | METH_KEYWORDS),
    117 	METHOD("privsep", python_kore_privsep, METH_VARARGS | METH_KEYWORDS),
    118 	METHOD("sendobj", python_kore_sendobj, METH_VARARGS | METH_KEYWORDS),
    119 	METHOD("websocket_broadcast", python_websocket_broadcast, METH_VARARGS),
    120 #if defined(KORE_USE_PGSQL)
    121 	METHOD("dbsetup", python_kore_pgsql_register, METH_VARARGS),
    122 	METHOD("dbquery", python_kore_pgsql_query,
    123 	    METH_VARARGS | METH_KEYWORDS),
    124 #endif
    125 #if defined(KORE_USE_CURL)
    126 	METHOD("curl", python_kore_curl_handle, METH_VARARGS),
    127 	METHOD("httpclient", python_kore_httpclient,
    128 	    METH_VARARGS | METH_KEYWORDS),
    129 #endif
    130 	{ NULL, NULL, 0, NULL }
    131 };
    132 
    133 static struct PyModuleDef pykore_module = {
    134 	PyModuleDef_HEAD_INIT, "kore", NULL, -1, pykore_methods
    135 };
    136 
    137 struct pyconfig {
    138 	PyObject_HEAD
    139 };
    140 
    141 static int	pyconfig_setattr(PyObject *, PyObject *, PyObject *);
    142 
    143 static PyTypeObject pyconfig_type = {
    144 	PyVarObject_HEAD_INIT(NULL, 0)
    145 	.tp_name = "kore.config",
    146 	.tp_doc = "kore configuration",
    147 	.tp_setattro = pyconfig_setattr,
    148 	.tp_basicsize = sizeof(struct pyconfig),
    149 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    150 };
    151 
    152 #if defined(__linux__)
    153 struct pyseccomp {
    154 	PyObject_HEAD
    155 	size_t			elm;
    156 	u_int8_t		*filters;
    157 };
    158 
    159 static PyObject	*pyseccomp_allow(struct pyseccomp *, PyObject *);
    160 static PyObject	*pyseccomp_allow_arg(struct pyseccomp *, PyObject *);
    161 static PyObject	*pyseccomp_allow_flag(struct pyseccomp *, PyObject *);
    162 static PyObject	*pyseccomp_allow_mask(struct pyseccomp *, PyObject *);
    163 
    164 static PyObject	*pyseccomp_deny(struct pyseccomp *, PyObject *, PyObject *);
    165 static PyObject	*pyseccomp_deny_arg(struct pyseccomp *, PyObject *, PyObject *);
    166 static PyObject	*pyseccomp_deny_flag(struct pyseccomp *,
    167 		    PyObject *, PyObject *);
    168 static PyObject	*pyseccomp_deny_mask(struct pyseccomp *,
    169 		    PyObject *, PyObject *);
    170 
    171 static PyObject	*pyseccomp_bpf_stmt(struct pyseccomp *, PyObject *);
    172 
    173 static PyMethodDef pyseccomp_methods[] = {
    174 	METHOD("allow", pyseccomp_allow, METH_VARARGS),
    175 	METHOD("bpf_stmt", pyseccomp_bpf_stmt, METH_VARARGS),
    176 	METHOD("allow_arg", pyseccomp_allow_arg, METH_VARARGS),
    177 	METHOD("allow_flag", pyseccomp_allow_flag, METH_VARARGS),
    178 	METHOD("allow_mask", pyseccomp_allow_mask, METH_VARARGS),
    179 	METHOD("deny", pyseccomp_deny, METH_VARARGS | METH_KEYWORDS),
    180 	METHOD("deny_arg", pyseccomp_deny_arg, METH_VARARGS | METH_KEYWORDS),
    181 	METHOD("deny_flag", pyseccomp_deny_flag, METH_VARARGS | METH_KEYWORDS),
    182 	METHOD("deny_mask", pyseccomp_deny_mask, METH_VARARGS | METH_KEYWORDS),
    183 	METHOD(NULL, NULL, -1)
    184 };
    185 
    186 static void	pyseccomp_dealloc(struct pyseccomp *);
    187 
    188 static PyTypeObject pyseccomp_type = {
    189 	PyVarObject_HEAD_INIT(NULL, 0)
    190 	.tp_name = "kore.seccomp",
    191 	.tp_doc = "kore seccomp configuration",
    192 	.tp_methods = pyseccomp_methods,
    193 	.tp_basicsize = sizeof(struct pyseccomp),
    194 	.tp_dealloc = (destructor)pyseccomp_dealloc,
    195 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    196 };
    197 #endif
    198 
    199 struct pyroute {
    200 	PyObject_HEAD
    201 	char			*path;
    202 	PyObject		*func;
    203 	PyObject		*kwargs;
    204 	struct kore_domain	*domain;
    205 	TAILQ_ENTRY(pyroute)	list;
    206 };
    207 
    208 static PyObject	*pyroute_inner(struct pyroute *, PyObject *);
    209 static void	pyroute_dealloc(struct pyroute *);
    210 
    211 static PyMethodDef pyroute_methods[] = {
    212 	METHOD("inner", pyroute_inner, METH_VARARGS),
    213 	METHOD(NULL, NULL, -1)
    214 };
    215 
    216 static PyTypeObject pyroute_type = {
    217 	PyVarObject_HEAD_INIT(NULL, 0)
    218 	.tp_name = "kore.route",
    219 	.tp_doc = "kore route function",
    220 	.tp_methods = pyroute_methods,
    221 	.tp_basicsize = sizeof(struct pyroute),
    222 	.tp_dealloc = (destructor)pyroute_dealloc,
    223 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    224 };
    225 
    226 struct pydomain {
    227 	PyObject_HEAD
    228 	struct kore_domain		*config;
    229 	struct kore_module_handle	*next;
    230 	PyObject			*kwargs;
    231 };
    232 
    233 static PyObject	*pydomain_filemaps(struct pydomain *, PyObject *);
    234 static PyObject	*pydomain_redirect(struct pydomain *, PyObject *);
    235 static PyObject	*pydomain_route(struct pydomain *, PyObject *, PyObject *);
    236 
    237 static PyMethodDef pydomain_methods[] = {
    238 	METHOD("filemaps", pydomain_filemaps, METH_VARARGS),
    239 	METHOD("redirect", pydomain_redirect, METH_VARARGS),
    240 	METHOD("route", pydomain_route, METH_VARARGS | METH_KEYWORDS),
    241 	METHOD(NULL, NULL, -1)
    242 };
    243 
    244 static int	pydomain_set_accesslog(struct pydomain *, PyObject *, void *);
    245 
    246 static PyGetSetDef pydomain_getset[] = {
    247 	SETTER("accesslog", pydomain_set_accesslog),
    248 	SETTER(NULL, NULL),
    249 };
    250 
    251 static void	pydomain_dealloc(struct pydomain *);
    252 
    253 static PyTypeObject pydomain_type = {
    254 	PyVarObject_HEAD_INIT(NULL, 0)
    255 	.tp_name = "kore.domain",
    256 	.tp_doc = "kore domain configuration",
    257 	.tp_getset = pydomain_getset,
    258 	.tp_methods = pydomain_methods,
    259 	.tp_basicsize = sizeof(struct pydomain),
    260 	.tp_dealloc = (destructor)pydomain_dealloc,
    261 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    262 };
    263 
    264 #define PYSUSPEND_OP_INIT	1
    265 #define PYSUSPEND_OP_WAIT	2
    266 #define PYSUSPEND_OP_CONTINUE	3
    267 
    268 struct pysuspend_op {
    269 	PyObject_HEAD
    270 	int			state;
    271 	int			delay;
    272 	struct python_coro	*coro;
    273 	struct kore_timer	*timer;
    274 };
    275 
    276 static void	pysuspend_op_dealloc(struct pysuspend_op *);
    277 
    278 static PyObject	*pysuspend_op_await(PyObject *);
    279 static PyObject	*pysuspend_op_iternext(struct pysuspend_op *);
    280 
    281 static PyAsyncMethods pysuspend_op_async = {
    282 	(unaryfunc)pysuspend_op_await,
    283 	NULL,
    284 	NULL
    285 };
    286 
    287 static PyTypeObject pysuspend_op_type = {
    288 	PyVarObject_HEAD_INIT(NULL, 0)
    289 	.tp_name = "kore.suspend",
    290 	.tp_doc = "suspension operation",
    291 	.tp_as_async = &pysuspend_op_async,
    292 	.tp_iternext = (iternextfunc)pysuspend_op_iternext,
    293 	.tp_basicsize = sizeof(struct pysuspend_op),
    294 	.tp_dealloc = (destructor)pysuspend_op_dealloc,
    295 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    296 };
    297 
    298 struct pytimer {
    299 	PyObject_HEAD
    300 	int			flags;
    301 	struct kore_timer	*run;
    302 	PyObject		*callable;
    303 	PyObject		*udata;
    304 };
    305 
    306 static PyObject	*pytimer_close(struct pytimer *, PyObject *);
    307 
    308 static PyMethodDef pytimer_methods[] = {
    309 	METHOD("close", pytimer_close, METH_NOARGS),
    310 	METHOD(NULL, NULL, -1)
    311 };
    312 
    313 static void	pytimer_dealloc(struct pytimer *);
    314 
    315 static PyTypeObject pytimer_type = {
    316 	PyVarObject_HEAD_INIT(NULL, 0)
    317 	.tp_name = "kore.timer",
    318 	.tp_doc = "kore timer implementation",
    319 	.tp_methods = pytimer_methods,
    320 	.tp_basicsize = sizeof(struct pytimer),
    321 	.tp_dealloc = (destructor)pytimer_dealloc,
    322 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    323 };
    324 
    325 /* XXX */
    326 struct pysocket;
    327 struct pysocket_op;
    328 
    329 struct pysocket_event {
    330 	struct kore_event	evt;
    331 	struct pysocket		*s;
    332 };
    333 
    334 struct pysocket {
    335 	PyObject_HEAD
    336 	int			fd;
    337 	int			family;
    338 	int			protocol;
    339 	int			scheduled;
    340 	PyObject		*socket;
    341 	socklen_t		addr_len;
    342 
    343 	struct pysocket_event	event;
    344 	struct pysocket_op	*recvop;
    345 	struct pysocket_op	*sendop;
    346 
    347 	union {
    348 		struct sockaddr_in	ipv4;
    349 		struct sockaddr_un	sun;
    350 	} addr;
    351 };
    352 
    353 static PyObject *pysocket_send(struct pysocket *, PyObject *);
    354 static PyObject *pysocket_recv(struct pysocket *, PyObject *);
    355 static PyObject *pysocket_close(struct pysocket *, PyObject *);
    356 static PyObject *pysocket_accept(struct pysocket *, PyObject *);
    357 static PyObject *pysocket_sendto(struct pysocket *, PyObject *);
    358 static PyObject *pysocket_connect(struct pysocket *, PyObject *);
    359 static PyObject *pysocket_recvmsg(struct pysocket *, PyObject *);
    360 static PyObject *pysocket_recvfrom(struct pysocket *, PyObject *);
    361 
    362 static PyMethodDef pysocket_methods[] = {
    363 	METHOD("recv", pysocket_recv, METH_VARARGS),
    364 	METHOD("send", pysocket_send, METH_VARARGS),
    365 	METHOD("close", pysocket_close, METH_NOARGS),
    366 	METHOD("accept", pysocket_accept, METH_NOARGS),
    367 	METHOD("sendto", pysocket_sendto, METH_VARARGS),
    368 	METHOD("connect", pysocket_connect, METH_VARARGS),
    369 	METHOD("recvmsg", pysocket_recvmsg, METH_VARARGS),
    370 	METHOD("recvfrom", pysocket_recvfrom, METH_VARARGS),
    371 	METHOD(NULL, NULL, -1),
    372 };
    373 
    374 static void	pysocket_dealloc(struct pysocket *);
    375 
    376 static PyTypeObject pysocket_type = {
    377 	PyVarObject_HEAD_INIT(NULL, 0)
    378 	.tp_name = "kore.socket",
    379 	.tp_doc = "kore socket implementation",
    380 	.tp_methods = pysocket_methods,
    381 	.tp_basicsize = sizeof(struct pysocket),
    382 	.tp_dealloc = (destructor)pysocket_dealloc,
    383 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    384 };
    385 
    386 #define PYSOCKET_TYPE_ACCEPT	1
    387 #define PYSOCKET_TYPE_CONNECT	2
    388 #define PYSOCKET_TYPE_RECV	3
    389 #define PYSOCKET_TYPE_SEND	4
    390 #define PYSOCKET_TYPE_RECVFROM	5
    391 #define PYSOCKET_TYPE_SENDTO	6
    392 #define PYSOCKET_TYPE_RECVMSG	7
    393 
    394 struct pysocket_op {
    395 	PyObject_HEAD
    396 	int				eof;
    397 	int				type;
    398 	void				*self;
    399 	struct python_coro		*coro;
    400 	int				state;
    401 	size_t				length;
    402 	struct kore_buf			buffer;
    403 	struct pysocket			*socket;
    404 	struct kore_timer		*timer;
    405 
    406 	union {
    407 		struct sockaddr_in	ipv4;
    408 		struct sockaddr_un	sun;
    409 	} sendaddr;
    410 };
    411 
    412 static void	pysocket_op_dealloc(struct pysocket_op *);
    413 
    414 static PyObject	*pysocket_op_await(PyObject *);
    415 static PyObject	*pysocket_op_iternext(struct pysocket_op *);
    416 
    417 static PyAsyncMethods pysocket_op_async = {
    418 	(unaryfunc)pysocket_op_await,
    419 	NULL,
    420 	NULL
    421 };
    422 
    423 static PyTypeObject pysocket_op_type = {
    424 	PyVarObject_HEAD_INIT(NULL, 0)
    425 	.tp_name = "kore.socketop",
    426 	.tp_doc = "socket operation",
    427 	.tp_as_async = &pysocket_op_async,
    428 	.tp_iternext = (iternextfunc)pysocket_op_iternext,
    429 	.tp_basicsize = sizeof(struct pysocket_op),
    430 	.tp_dealloc = (destructor)pysocket_op_dealloc,
    431 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    432 };
    433 
    434 struct pyqueue_waiting {
    435 	struct python_coro		*coro;
    436 	struct pyqueue_op		*op;
    437 	TAILQ_ENTRY(pyqueue_waiting)	list;
    438 };
    439 
    440 struct pyqueue_object {
    441 	PyObject			*obj;
    442 	TAILQ_ENTRY(pyqueue_object)	list;
    443 };
    444 
    445 struct pyqueue {
    446 	PyObject_HEAD
    447 	TAILQ_HEAD(, pyqueue_object)	objects;
    448 	TAILQ_HEAD(, pyqueue_waiting)	waiting;
    449 };
    450 
    451 static PyObject *pyqueue_pop(struct pyqueue *, PyObject *);
    452 static PyObject *pyqueue_push(struct pyqueue *, PyObject *);
    453 static PyObject *pyqueue_popnow(struct pyqueue *, PyObject *);
    454 
    455 static PyMethodDef pyqueue_methods[] = {
    456 	METHOD("pop", pyqueue_pop, METH_NOARGS),
    457 	METHOD("push", pyqueue_push, METH_VARARGS),
    458 	METHOD("popnow", pyqueue_popnow, METH_NOARGS),
    459 	METHOD(NULL, NULL, -1)
    460 };
    461 
    462 static void	pyqueue_dealloc(struct pyqueue *);
    463 
    464 static PyTypeObject pyqueue_type = {
    465 	PyVarObject_HEAD_INIT(NULL, 0)
    466 	.tp_name = "kore.queue",
    467 	.tp_doc = "queue",
    468 	.tp_methods = pyqueue_methods,
    469 	.tp_basicsize = sizeof(struct pyqueue),
    470 	.tp_dealloc = (destructor)pyqueue_dealloc,
    471 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    472 };
    473 
    474 struct pyqueue_op {
    475 	PyObject_HEAD
    476 	struct pyqueue		*queue;
    477 	struct pyqueue_waiting	*waiting;
    478 };
    479 
    480 static void	pyqueue_op_dealloc(struct pyqueue_op *);
    481 
    482 static PyObject	*pyqueue_op_await(PyObject *);
    483 static PyObject	*pyqueue_op_iternext(struct pyqueue_op *);
    484 
    485 static PyAsyncMethods pyqueue_op_async = {
    486 	(unaryfunc)pyqueue_op_await,
    487 	NULL,
    488 	NULL
    489 };
    490 
    491 static PyTypeObject pyqueue_op_type = {
    492 	PyVarObject_HEAD_INIT(NULL, 0)
    493 	.tp_name = "kore.queueop",
    494 	.tp_doc = "queue waitable",
    495 	.tp_as_async = &pyqueue_op_async,
    496 	.tp_iternext = (iternextfunc)pyqueue_op_iternext,
    497 	.tp_basicsize = sizeof(struct pyqueue_op),
    498 	.tp_dealloc = (destructor)pyqueue_op_dealloc,
    499 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    500 };
    501 
    502 struct pylock {
    503 	PyObject_HEAD
    504 	struct python_coro		*owner;
    505 	TAILQ_HEAD(, pylock_op)		ops;
    506 };
    507 
    508 static PyObject *pylock_aexit(struct pylock *, PyObject *);
    509 static PyObject *pylock_aenter(struct pylock *, PyObject *);
    510 static PyObject *pylock_release(struct pylock *, PyObject *);
    511 static PyObject *pylock_trylock(struct pylock *, PyObject *);
    512 
    513 static PyMethodDef pylock_methods[] = {
    514 	METHOD("acquire", pylock_aenter, METH_NOARGS),
    515 	METHOD("release", pylock_release, METH_NOARGS),
    516 	METHOD("trylock", pylock_trylock, METH_NOARGS),
    517 	METHOD("__aexit__", pylock_aexit, METH_VARARGS),
    518 	METHOD("__aenter__", pylock_aenter, METH_NOARGS),
    519 	METHOD(NULL, NULL, -1)
    520 };
    521 
    522 static void	pylock_dealloc(struct pylock *);
    523 
    524 static PyTypeObject pylock_type = {
    525 	PyVarObject_HEAD_INIT(NULL, 0)
    526 	.tp_name = "kore.lock",
    527 	.tp_doc = "locking mechanism",
    528 	.tp_methods = pylock_methods,
    529 	.tp_basicsize = sizeof(struct pylock),
    530 	.tp_dealloc = (destructor)pylock_dealloc,
    531 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    532 };
    533 
    534 struct pylock_op {
    535 	PyObject_HEAD
    536 	int			locking;
    537 	int			active;
    538 	struct pylock		*lock;
    539 	struct python_coro	*coro;
    540 	TAILQ_ENTRY(pylock_op)	list;
    541 };
    542 
    543 static void	pylock_op_dealloc(struct pylock_op *);
    544 
    545 static PyObject	*pylock_op_await(PyObject *);
    546 static PyObject	*pylock_op_iternext(struct pylock_op *);
    547 
    548 static PyAsyncMethods pylock_op_async = {
    549 	(unaryfunc)pylock_op_await,
    550 	NULL,
    551 	NULL
    552 };
    553 
    554 static PyTypeObject pylock_op_type = {
    555 	PyVarObject_HEAD_INIT(NULL, 0)
    556 	.tp_name = "kore.lockop",
    557 	.tp_doc = "lock awaitable",
    558 	.tp_as_async = &pylock_op_async,
    559 	.tp_iternext = (iternextfunc)pylock_op_iternext,
    560 	.tp_basicsize = sizeof(struct pylock_op),
    561 	.tp_dealloc = (destructor)pylock_op_dealloc,
    562 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    563 };
    564 
    565 #define PYTHON_PROC_MAX_ENV	32
    566 
    567 struct pyproc {
    568 	PyObject_HEAD
    569 	pid_t			pid;
    570 	pid_t			apid;
    571 	int			reaped;
    572 	int			status;
    573 	struct pyproc_op	*op;
    574 	struct pysocket		*in;
    575 	struct pysocket		*out;
    576 	struct python_coro	*coro;
    577 	struct kore_timer	*timer;
    578 	TAILQ_ENTRY(pyproc)	list;
    579 };
    580 
    581 static void	pyproc_dealloc(struct pyproc *);
    582 
    583 static PyObject	*pyproc_kill(struct pyproc *, PyObject *);
    584 static PyObject	*pyproc_reap(struct pyproc *, PyObject *);
    585 static PyObject	*pyproc_recv(struct pyproc *, PyObject *);
    586 static PyObject	*pyproc_send(struct pyproc *, PyObject *);
    587 static PyObject	*pyproc_close_stdin(struct pyproc *, PyObject *);
    588 
    589 static PyMethodDef pyproc_methods[] = {
    590 	METHOD("kill", pyproc_kill, METH_NOARGS),
    591 	METHOD("reap", pyproc_reap, METH_NOARGS),
    592 	METHOD("recv", pyproc_recv, METH_VARARGS),
    593 	METHOD("send", pyproc_send, METH_VARARGS),
    594 	METHOD("close_stdin", pyproc_close_stdin, METH_NOARGS),
    595 	METHOD(NULL, NULL, -1),
    596 };
    597 
    598 static PyObject	*pyproc_get_pid(struct pyproc *, void *);
    599 
    600 static PyGetSetDef pyproc_getset[] = {
    601 	GETTER("pid", pyproc_get_pid),
    602 	GETTER(NULL, NULL),
    603 };
    604 
    605 static PyTypeObject pyproc_type = {
    606 	PyVarObject_HEAD_INIT(NULL, 0)
    607 	.tp_name = "kore.proc",
    608 	.tp_doc = "async process",
    609 	.tp_getset = pyproc_getset,
    610 	.tp_methods = pyproc_methods,
    611 	.tp_basicsize = sizeof(struct pyproc),
    612 	.tp_dealloc = (destructor)pyproc_dealloc,
    613 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    614 };
    615 
    616 struct pyproc_op {
    617 	PyObject_HEAD
    618 	struct pyproc		*proc;
    619 	struct python_coro	*coro;
    620 };
    621 
    622 static void	pyproc_op_dealloc(struct pyproc_op *);
    623 
    624 static PyObject	*pyproc_op_await(PyObject *);
    625 static PyObject	*pyproc_op_iternext(struct pyproc_op *);
    626 
    627 static PyAsyncMethods pyproc_op_async = {
    628 	(unaryfunc)pyproc_op_await,
    629 	NULL,
    630 	NULL
    631 };
    632 
    633 static PyTypeObject pyproc_op_type = {
    634 	PyVarObject_HEAD_INIT(NULL, 0)
    635 	.tp_name = "kore.proc_op",
    636 	.tp_doc = "proc reaper awaitable",
    637 	.tp_as_async = &pyproc_op_async,
    638 	.tp_iternext = (iternextfunc)pyproc_op_iternext,
    639 	.tp_basicsize = sizeof(struct pyproc_op),
    640 	.tp_dealloc = (destructor)pyproc_op_dealloc,
    641 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    642 };
    643 
    644 struct pygather_coro {
    645 	struct python_coro		*coro;
    646 	PyObject			*result;
    647 	TAILQ_ENTRY(pygather_coro)	list;
    648 };
    649 
    650 struct pygather_result {
    651 	PyObject			*obj;
    652 	TAILQ_ENTRY(pygather_result)	list;
    653 };
    654 
    655 struct pygather_op {
    656 	PyObject_HEAD
    657 	int				count;
    658 	int				running;
    659 	int				concurrency;
    660 	struct python_coro		*coro;
    661 	TAILQ_HEAD(, pygather_result)	results;
    662 	TAILQ_HEAD(, pygather_coro)	coroutines;
    663 };
    664 
    665 static void	pygather_op_dealloc(struct pygather_op *);
    666 
    667 static PyObject	*pygather_op_await(PyObject *);
    668 static PyObject	*pygather_op_iternext(struct pygather_op *);
    669 
    670 static PyAsyncMethods pygather_op_async = {
    671 	(unaryfunc)pygather_op_await,
    672 	NULL,
    673 	NULL
    674 };
    675 
    676 static PyTypeObject pygather_op_type = {
    677 	PyVarObject_HEAD_INIT(NULL, 0)
    678 	.tp_name = "kore.pygather_op",
    679 	.tp_doc = "coroutine gathering",
    680 	.tp_as_async = &pygather_op_async,
    681 	.tp_iternext = (iternextfunc)pygather_op_iternext,
    682 	.tp_basicsize = sizeof(struct pygather_op),
    683 	.tp_dealloc = (destructor)pygather_op_dealloc,
    684 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    685 };
    686 
    687 struct pyconnection {
    688 	PyObject_HEAD
    689 	struct connection	*c;
    690 };
    691 
    692 static PyObject *pyconnection_disconnect(struct pyconnection *, PyObject *);
    693 static PyObject *pyconnection_websocket_send(struct pyconnection *, PyObject *);
    694 
    695 static PyMethodDef pyconnection_methods[] = {
    696 	METHOD("disconnect", pyconnection_disconnect, METH_NOARGS),
    697 	METHOD("websocket_send", pyconnection_websocket_send, METH_VARARGS),
    698 	METHOD(NULL, NULL, -1),
    699 };
    700 
    701 static PyObject	*pyconnection_get_fd(struct pyconnection *, void *);
    702 static PyObject	*pyconnection_get_addr(struct pyconnection *, void *);
    703 
    704 static PyObject	*pyconnection_get_peer_x509(struct pyconnection *, void *);
    705 static PyObject	*pyconnection_get_peer_x509dict(struct pyconnection *, void *);
    706 
    707 static PyGetSetDef pyconnection_getset[] = {
    708 	GETTER("fd", pyconnection_get_fd),
    709 	GETTER("addr", pyconnection_get_addr),
    710 	GETTER("x509", pyconnection_get_peer_x509),
    711 	GETTER("x509dict", pyconnection_get_peer_x509dict),
    712 	GETTER(NULL, NULL),
    713 };
    714 
    715 static void	pyconnection_dealloc(struct pyconnection *);
    716 
    717 static PyTypeObject pyconnection_type = {
    718 	PyVarObject_HEAD_INIT(NULL, 0)
    719 	.tp_name = "kore.connection",
    720 	.tp_doc = "struct connection",
    721 	.tp_getset = pyconnection_getset,
    722 	.tp_methods = pyconnection_methods,
    723 	.tp_basicsize = sizeof(struct pyconnection),
    724 	.tp_dealloc = (destructor)pyconnection_dealloc,
    725 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    726 };
    727 
    728 #define PYHTTP_STATE_INIT		0
    729 #define PYHTTP_STATE_PREPROCESS		1
    730 #define PYHTTP_STATE_RUN		2
    731 
    732 struct pyhttp_request {
    733 	PyObject_HEAD
    734 	struct http_request	*req;
    735 	PyObject		*dict;
    736 	PyObject		*data;
    737 };
    738 
    739 struct pyhttp_iterobj {
    740 	int			remove;
    741 	PyObject		*iterator;
    742 	struct connection	*connection;
    743 	struct kore_buf		buf;
    744 };
    745 
    746 struct pyhttp_file {
    747 	PyObject_HEAD
    748 	struct http_file	*file;
    749 };
    750 
    751 static void	pyhttp_dealloc(struct pyhttp_request *);
    752 static void	pyhttp_file_dealloc(struct pyhttp_file *);
    753 
    754 static PyObject *pyhttp_cookie(struct pyhttp_request *, PyObject *);
    755 static PyObject *pyhttp_headers(struct pyhttp_request *, PyObject *);
    756 static PyObject	*pyhttp_response(struct pyhttp_request *, PyObject *);
    757 static PyObject *pyhttp_argument(struct pyhttp_request *, PyObject *);
    758 static PyObject	*pyhttp_body_read(struct pyhttp_request *, PyObject *);
    759 static PyObject	*pyhttp_file_lookup(struct pyhttp_request *, PyObject *);
    760 static PyObject	*pyhttp_populate_get(struct pyhttp_request *, PyObject *);
    761 static PyObject	*pyhttp_populate_post(struct pyhttp_request *, PyObject *);
    762 static PyObject	*pyhttp_populate_multi(struct pyhttp_request *, PyObject *);
    763 static PyObject	*pyhttp_populate_cookies(struct pyhttp_request *, PyObject *);
    764 static PyObject	*pyhttp_request_header(struct pyhttp_request *, PyObject *);
    765 static PyObject	*pyhttp_response_header(struct pyhttp_request *, PyObject *);
    766 static PyObject *pyhttp_websocket_handshake(struct pyhttp_request *,
    767 		    PyObject *);
    768 
    769 static PyMethodDef pyhttp_request_methods[] = {
    770 	METHOD("cookie", pyhttp_cookie, METH_VARARGS),
    771 	METHOD("headers", pyhttp_headers, METH_NOARGS),
    772 	METHOD("response", pyhttp_response, METH_VARARGS),
    773 	METHOD("argument", pyhttp_argument, METH_VARARGS),
    774 	METHOD("body_read", pyhttp_body_read, METH_VARARGS),
    775 	METHOD("file_lookup", pyhttp_file_lookup, METH_VARARGS),
    776 	METHOD("populate_get", pyhttp_populate_get, METH_NOARGS),
    777 	METHOD("populate_post", pyhttp_populate_post, METH_NOARGS),
    778 	METHOD("populate_multi", pyhttp_populate_multi, METH_NOARGS),
    779 	METHOD("populate_cookies", pyhttp_populate_cookies, METH_NOARGS),
    780 	METHOD("request_header", pyhttp_request_header, METH_VARARGS),
    781 	METHOD("response_header", pyhttp_response_header, METH_VARARGS),
    782 	METHOD("websocket_handshake", pyhttp_websocket_handshake, METH_VARARGS),
    783 	METHOD(NULL, NULL, -1)
    784 };
    785 
    786 static PyObject	*pyhttp_get_host(struct pyhttp_request *, void *);
    787 static PyObject	*pyhttp_get_path(struct pyhttp_request *, void *);
    788 static PyObject	*pyhttp_get_body(struct pyhttp_request *, void *);
    789 static PyObject	*pyhttp_get_agent(struct pyhttp_request *, void *);
    790 static PyObject	*pyhttp_get_method(struct pyhttp_request *, void *);
    791 static PyObject	*pyhttp_get_protocol(struct pyhttp_request *, void *);
    792 static PyObject	*pyhttp_get_body_path(struct pyhttp_request *, void *);
    793 static PyObject	*pyhttp_get_connection(struct pyhttp_request *, void *);
    794 static PyObject	*pyhttp_get_body_digest(struct pyhttp_request *, void *);
    795 
    796 static PyGetSetDef pyhttp_request_getset[] = {
    797 	GETTER("host", pyhttp_get_host),
    798 	GETTER("path", pyhttp_get_path),
    799 	GETTER("body", pyhttp_get_body),
    800 	GETTER("agent", pyhttp_get_agent),
    801 	GETTER("method", pyhttp_get_method),
    802 	GETTER("protocol", pyhttp_get_protocol),
    803 	GETTER("body_path", pyhttp_get_body_path),
    804 	GETTER("body_digest", pyhttp_get_body_digest),
    805 	GETTER("connection", pyhttp_get_connection),
    806 	GETTER(NULL, NULL)
    807 };
    808 
    809 static PyTypeObject pyhttp_request_type = {
    810 	PyVarObject_HEAD_INIT(NULL, 0)
    811 	.tp_name = "kore.http_request",
    812 	.tp_doc = "struct http_request",
    813 	.tp_setattro = PyObject_GenericSetAttr,
    814 	.tp_getattro = PyObject_GenericGetAttr,
    815 	.tp_getset = pyhttp_request_getset,
    816 	.tp_methods = pyhttp_request_methods,
    817 	.tp_dealloc = (destructor)pyhttp_dealloc,
    818 	.tp_basicsize = sizeof(struct pyhttp_request),
    819 	.tp_dictoffset = offsetof(struct pyhttp_request, dict),
    820 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    821 };
    822 
    823 static PyObject	*pyhttp_file_read(struct pyhttp_file *, PyObject *);
    824 
    825 static PyMethodDef pyhttp_file_methods[] = {
    826 	METHOD("read", pyhttp_file_read, METH_VARARGS),
    827 	METHOD(NULL, NULL, -1)
    828 };
    829 
    830 static PyObject	*pyhttp_file_get_name(struct pyhttp_file *, void *);
    831 static PyObject	*pyhttp_file_get_filename(struct pyhttp_file *, void *);
    832 
    833 static PyGetSetDef pyhttp_file_getset[] = {
    834 	GETTER("name", pyhttp_file_get_name),
    835 	GETTER("filename", pyhttp_file_get_filename),
    836 	GETTER(NULL, NULL)
    837 };
    838 
    839 static PyTypeObject pyhttp_file_type = {
    840 	PyVarObject_HEAD_INIT(NULL, 0)
    841 	.tp_name = "kore.http_file",
    842 	.tp_doc = "struct http_file",
    843 	.tp_getset = pyhttp_file_getset,
    844 	.tp_methods = pyhttp_file_methods,
    845 	.tp_dealloc = (destructor)pyhttp_file_dealloc,
    846 	.tp_basicsize = sizeof(struct pyhttp_file),
    847 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    848 };
    849 
    850 #if defined(KORE_USE_CURL)
    851 
    852 #define CURL_CLIENT_OP_RUN	1
    853 #define CURL_CLIENT_OP_RESULT	2
    854 
    855 struct pycurl_slist {
    856 	struct curl_slist		*slist;
    857 	LIST_ENTRY(pycurl_slist)	list;
    858 };
    859 
    860 struct pycurl_data {
    861 	struct kore_curl		curl;
    862 	LIST_HEAD(, pycurl_slist)	slists;
    863 };
    864 
    865 struct pycurl_handle {
    866 	PyObject_HEAD
    867 	char			*url;
    868 	struct kore_buf		*body;
    869 	struct pycurl_data	data;
    870 };
    871 
    872 struct pycurl_handle_op {
    873 	PyObject_HEAD
    874 	int			state;
    875 	struct python_coro	*coro;
    876 	struct pycurl_handle	*handle;
    877 };
    878 
    879 static PyObject	*pycurl_handle_op_await(PyObject *);
    880 static PyObject	*pycurl_handle_op_iternext(struct pycurl_handle_op *);
    881 
    882 static void	pycurl_handle_dealloc(struct pycurl_handle *);
    883 static void	pycurl_handle_op_dealloc(struct pycurl_handle_op *);
    884 
    885 static PyObject *pycurl_handle_run(struct pycurl_handle *, PyObject *);
    886 static PyObject *pycurl_handle_setopt(struct pycurl_handle *, PyObject *);
    887 static PyObject *pycurl_handle_setbody(struct pycurl_handle *, PyObject *);
    888 
    889 static PyObject *pycurl_handle_setopt_string(struct pycurl_data *,
    890 		    int, PyObject *);
    891 static PyObject *pycurl_handle_setopt_long(struct pycurl_data *,
    892 		    int, PyObject *);
    893 static PyObject *pycurl_handle_setopt_slist(struct pycurl_data *,
    894 		    int, PyObject *);
    895 
    896 static PyMethodDef pycurl_handle_methods[] = {
    897 	METHOD("run", pycurl_handle_run, METH_VARARGS),
    898 	METHOD("setopt", pycurl_handle_setopt, METH_VARARGS),
    899 	METHOD("setbody", pycurl_handle_setbody, METH_VARARGS),
    900 	METHOD(NULL, NULL, -1)
    901 };
    902 
    903 static PyTypeObject pycurl_handle_type = {
    904 	PyVarObject_HEAD_INIT(NULL, 0)
    905 	.tp_name = "kore.curl",
    906 	.tp_doc = "An asynchronous CURL handle",
    907 	.tp_methods = pycurl_handle_methods,
    908 	.tp_basicsize = sizeof(struct pycurl_handle),
    909 	.tp_dealloc = (destructor)pycurl_handle_dealloc,
    910 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    911 };
    912 
    913 static PyAsyncMethods pycurl_handle_op_async = {
    914 	(unaryfunc)pycurl_handle_op_await,
    915 	NULL,
    916 	NULL
    917 };
    918 
    919 static PyTypeObject pycurl_handle_op_type = {
    920 	PyVarObject_HEAD_INIT(NULL, 0)
    921 	.tp_name = "kore.curlop",
    922 	.tp_doc = "Asynchronous CURL operation",
    923 	.tp_as_async = &pycurl_handle_op_async,
    924 	.tp_iternext = (iternextfunc)pycurl_handle_op_iternext,
    925 	.tp_basicsize = sizeof(struct pycurl_handle_op),
    926 	.tp_dealloc = (destructor)pycurl_handle_op_dealloc,
    927 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    928 };
    929 
    930 struct pyhttp_client {
    931 	PyObject_HEAD
    932 	char			*url;
    933 	char			*unix;
    934 	char			*tlskey;
    935 	char			*tlscert;
    936 	char			*cabundle;
    937 	PyObject		*curlopt;
    938 	int			tlsverify;
    939 };
    940 
    941 struct pyhttp_client_op {
    942 	PyObject_HEAD
    943 	int			state;
    944 	int			headers;
    945 	struct python_coro	*coro;
    946 	struct pyhttp_client	*client;
    947 	struct pycurl_data	data;
    948 };
    949 
    950 
    951 static PyObject	*pyhttp_client_op_await(PyObject *);
    952 static PyObject	*pyhttp_client_op_iternext(struct pyhttp_client_op *);
    953 
    954 static void	pyhttp_client_dealloc(struct pyhttp_client *);
    955 static void	pyhttp_client_op_dealloc(struct pyhttp_client_op *);
    956 
    957 static PyObject *pyhttp_client_get(struct pyhttp_client *,
    958 		    PyObject *, PyObject *);
    959 static PyObject *pyhttp_client_put(struct pyhttp_client *,
    960 		    PyObject *, PyObject *);
    961 static PyObject *pyhttp_client_post(struct pyhttp_client *,
    962 		    PyObject *, PyObject *);
    963 static PyObject *pyhttp_client_head(struct pyhttp_client *,
    964 		    PyObject *, PyObject *);
    965 static PyObject *pyhttp_client_patch(struct pyhttp_client *,
    966 		    PyObject *, PyObject *);
    967 static PyObject *pyhttp_client_delete(struct pyhttp_client *,
    968 		    PyObject *, PyObject *);
    969 static PyObject *pyhttp_client_options(struct pyhttp_client *,
    970 		    PyObject *, PyObject *);
    971 
    972 static PyMethodDef pyhttp_client_methods[] = {
    973 	METHOD("get", pyhttp_client_get, METH_VARARGS | METH_KEYWORDS),
    974 	METHOD("put", pyhttp_client_put, METH_VARARGS | METH_KEYWORDS),
    975 	METHOD("post", pyhttp_client_post, METH_VARARGS | METH_KEYWORDS),
    976 	METHOD("head", pyhttp_client_head, METH_VARARGS | METH_KEYWORDS),
    977 	METHOD("patch", pyhttp_client_patch, METH_VARARGS | METH_KEYWORDS),
    978 	METHOD("delete", pyhttp_client_delete, METH_VARARGS | METH_KEYWORDS),
    979 	METHOD("options", pyhttp_client_options, METH_VARARGS | METH_KEYWORDS),
    980 	METHOD(NULL, NULL, -1)
    981 };
    982 
    983 static PyTypeObject pyhttp_client_type = {
    984 	PyVarObject_HEAD_INIT(NULL, 0)
    985 	.tp_name = "kore.httpclient",
    986 	.tp_doc = "An asynchronous HTTP client",
    987 	.tp_methods = pyhttp_client_methods,
    988 	.tp_basicsize = sizeof(struct pyhttp_client),
    989 	.tp_dealloc = (destructor)pyhttp_client_dealloc,
    990 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
    991 };
    992 
    993 static PyAsyncMethods pyhttp_client_op_async = {
    994 	(unaryfunc)pyhttp_client_op_await,
    995 	NULL,
    996 	NULL
    997 };
    998 
    999 static PyTypeObject pyhttp_client_op_type = {
   1000 	PyVarObject_HEAD_INIT(NULL, 0)
   1001 	.tp_name = "kore.httpclientop",
   1002 	.tp_doc = "Asynchronous HTTP client operation",
   1003 	.tp_as_async = &pyhttp_client_op_async,
   1004 	.tp_iternext = (iternextfunc)pyhttp_client_op_iternext,
   1005 	.tp_basicsize = sizeof(struct pyhttp_client_op),
   1006 	.tp_dealloc = (destructor)pyhttp_client_op_dealloc,
   1007 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
   1008 };
   1009 #endif
   1010 
   1011 #if defined(KORE_USE_PGSQL)
   1012 
   1013 #define PYKORE_PGSQL_PREINIT		1
   1014 #define PYKORE_PGSQL_INITIALIZE		2
   1015 #define PYKORE_PGSQL_QUERY		3
   1016 #define PYKORE_PGSQL_WAIT		4
   1017 
   1018 struct pykore_pgsql {
   1019 	PyObject_HEAD
   1020 	struct kore_pgsql	sql;
   1021 	int			state;
   1022 	int			binary;
   1023 
   1024 	char			*db;
   1025 	struct python_coro	*coro;
   1026 	char			*query;
   1027 	PyObject		*result;
   1028 
   1029 	struct {
   1030 		int		count;
   1031 		const char	**values;
   1032 		int		*lengths;
   1033 		int		*formats;
   1034 		PyObject	**objs;
   1035 	} param;
   1036 };
   1037 
   1038 static void	pykore_pgsql_dealloc(struct pykore_pgsql *);
   1039 
   1040 static PyObject	*pykore_pgsql_await(PyObject *);
   1041 static PyObject	*pykore_pgsql_iternext(struct pykore_pgsql *);
   1042 
   1043 static PyAsyncMethods pykore_pgsql_async = {
   1044 	(unaryfunc)pykore_pgsql_await,
   1045 	NULL,
   1046 	NULL
   1047 };
   1048 
   1049 static PyTypeObject pykore_pgsql_type = {
   1050 	PyVarObject_HEAD_INIT(NULL, 0)
   1051 	.tp_name = "kore.pgsql",
   1052 	.tp_doc = "struct kore_pgsql",
   1053 	.tp_as_async = &pykore_pgsql_async,
   1054 	.tp_iternext = (iternextfunc)pykore_pgsql_iternext,
   1055 	.tp_basicsize = sizeof(struct pykore_pgsql),
   1056 	.tp_dealloc = (destructor)pykore_pgsql_dealloc,
   1057 	.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
   1058 };
   1059 #endif