mirror of
https://git.kore.io/kore.git
synced 2024-11-06 02:21:58 +01:00
Add initial python support.
Based on work done by Stanislav Yudin.
This commit is contained in:
parent
57840a8366
commit
bbcdec82fc
9
Makefile
9
Makefile
@ -9,7 +9,8 @@ INCLUDE_DIR=$(PREFIX)/include/kore
|
||||
|
||||
S_SRC= src/kore.c src/buf.c src/cli.c src/config.c src/connection.c \
|
||||
src/domain.c src/mem.c src/msg.c src/module.c src/net.c \
|
||||
src/pool.c src/timer.c src/utils.c src/worker.c src/keymgr.c
|
||||
src/pool.c src/runtime.c src/timer.c src/utils.c src/worker.c \
|
||||
src/keymgr.c
|
||||
|
||||
CFLAGS+=-Wall -Werror -Wstrict-prototypes -Wmissing-prototypes
|
||||
CFLAGS+=-Wmissing-declarations -Wshadow -Wpointer-arith -Wcast-qual
|
||||
@ -63,6 +64,12 @@ ifneq ("$(JSONRPC)", "")
|
||||
CFLAGS+=-DKORE_USE_JSONRPC
|
||||
endif
|
||||
|
||||
ifneq ("$(PYTHON)", "")
|
||||
S_SRC+=src/python.c
|
||||
LDFLAGS+=$(shell python3-config --ldflags)
|
||||
CFLAGS+=$(shell python3-config --includes) -DKORE_USE_PYTHON
|
||||
endif
|
||||
|
||||
OSNAME=$(shell uname -s | sed -e 's/[-_].*//g' | tr A-Z a-z)
|
||||
ifeq ("$(OSNAME)", "darwin")
|
||||
CFLAGS+=-I/opt/local/include/ -I/usr/local/opt/openssl/include
|
||||
|
@ -186,6 +186,10 @@ struct http_request {
|
||||
char *query_string;
|
||||
struct kore_module_handle *hdlr;
|
||||
|
||||
#if defined(KORE_USE_PYTHON)
|
||||
void *py_object;
|
||||
#endif
|
||||
|
||||
LIST_HEAD(, kore_task) tasks;
|
||||
LIST_HEAD(, kore_pgsql) pgsqls;
|
||||
|
||||
|
102
includes/kore.h
102
includes/kore.h
@ -207,11 +207,32 @@ TAILQ_HEAD(connection_list, connection);
|
||||
extern struct connection_list connections;
|
||||
extern struct connection_list disconnected;
|
||||
|
||||
#define KORE_RUNTIME_NATIVE 0
|
||||
#define KORE_RUNTIME_PYTHON 1
|
||||
|
||||
struct kore_runtime {
|
||||
int type;
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
int (*http_request)(void *, struct http_request *);
|
||||
int (*validator)(void *, struct http_request *, void *);
|
||||
#endif
|
||||
int (*execute)(void *, void *);
|
||||
int (*onload)(void *, int);
|
||||
void (*connect)(void *, struct connection *);
|
||||
};
|
||||
|
||||
struct kore_runtime_call {
|
||||
void *addr;
|
||||
struct kore_runtime *runtime;
|
||||
};
|
||||
|
||||
extern struct kore_runtime kore_native_runtime;
|
||||
|
||||
struct listener {
|
||||
u_int8_t type;
|
||||
u_int8_t addrtype;
|
||||
int fd;
|
||||
void (*connect)(struct connection *);
|
||||
u_int8_t type;
|
||||
u_int8_t addrtype;
|
||||
int fd;
|
||||
struct kore_runtime_call *connect;
|
||||
|
||||
union {
|
||||
struct sockaddr_in ipv4;
|
||||
@ -250,32 +271,48 @@ struct kore_auth {
|
||||
#define HANDLER_TYPE_STATIC 1
|
||||
#define HANDLER_TYPE_DYNAMIC 2
|
||||
|
||||
#endif
|
||||
#endif /* !KORE_NO_HTTP */
|
||||
|
||||
#define KORE_MODULE_LOAD 1
|
||||
#define KORE_MODULE_UNLOAD 2
|
||||
|
||||
struct kore_module {
|
||||
void *handle;
|
||||
char *path;
|
||||
char *onload;
|
||||
int (*ocb)(int);
|
||||
#define KORE_MODULE_NATIVE 0
|
||||
#define KORE_MODULE_PYTHON 1
|
||||
|
||||
time_t mtime;
|
||||
struct kore_module;
|
||||
|
||||
struct kore_module_functions {
|
||||
void (*free)(struct kore_module *);
|
||||
void (*reload)(struct kore_module *);
|
||||
int (*callback)(struct kore_module *, int);
|
||||
void (*load)(struct kore_module *, const char *);
|
||||
void *(*getsym)(struct kore_module *, const char *);
|
||||
};
|
||||
|
||||
struct kore_module {
|
||||
void *handle;
|
||||
char *path;
|
||||
char *onload;
|
||||
int type;
|
||||
time_t mtime;
|
||||
struct kore_runtime_call *ocb;
|
||||
|
||||
struct kore_module_functions *fun;
|
||||
struct kore_runtime *runtime;
|
||||
|
||||
TAILQ_ENTRY(kore_module) list;
|
||||
};
|
||||
|
||||
struct kore_module_handle {
|
||||
char *path;
|
||||
char *func;
|
||||
void *addr;
|
||||
int type;
|
||||
int errors;
|
||||
regex_t rctx;
|
||||
struct kore_domain *dom;
|
||||
char *path;
|
||||
char *func;
|
||||
int type;
|
||||
int errors;
|
||||
regex_t rctx;
|
||||
struct kore_domain *dom;
|
||||
struct kore_runtime_call *rcall;
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
struct kore_auth *auth;
|
||||
struct kore_auth *auth;
|
||||
TAILQ_HEAD(, kore_handler_params) params;
|
||||
#endif
|
||||
TAILQ_ENTRY(kore_module_handle) list;
|
||||
@ -313,15 +350,15 @@ TAILQ_HEAD(kore_domain_h, kore_domain);
|
||||
#define KORE_VALIDATOR_TYPE_FUNCTION 2
|
||||
|
||||
struct kore_validator {
|
||||
u_int8_t type;
|
||||
char *name;
|
||||
char *arg;
|
||||
regex_t rctx;
|
||||
int (*func)(struct http_request *, char *);
|
||||
u_int8_t type;
|
||||
char *name;
|
||||
char *arg;
|
||||
regex_t rctx;
|
||||
struct kore_runtime_call *rcall;
|
||||
|
||||
TAILQ_ENTRY(kore_validator) list;
|
||||
};
|
||||
#endif
|
||||
#endif /* !KORE_NO_HTTP */
|
||||
|
||||
#define KORE_BUF_OWNER_API 0x0001
|
||||
|
||||
@ -568,16 +605,27 @@ void kore_module_reload(int);
|
||||
void kore_module_onload(void);
|
||||
int kore_module_loaded(void);
|
||||
void kore_domain_closelogs(void);
|
||||
void *kore_module_getsym(const char *);
|
||||
void *kore_module_getsym(const char *, struct kore_runtime **);
|
||||
void kore_domain_load_crl(void);
|
||||
void kore_domain_keymgr_init(void);
|
||||
void kore_module_load(const char *, const char *);
|
||||
void kore_domain_sslstart(struct kore_domain *);
|
||||
void kore_module_load(const char *, const char *, int);
|
||||
void kore_domain_callback(void (*cb)(struct kore_domain *));
|
||||
int kore_module_handler_new(const char *, const char *,
|
||||
const char *, const char *, int);
|
||||
void kore_module_handler_free(struct kore_module_handle *);
|
||||
|
||||
struct kore_runtime_call *kore_runtime_getcall(const char *);
|
||||
|
||||
int kore_runtime_onload(struct kore_runtime_call *, int);
|
||||
void kore_runtime_connect(struct kore_runtime_call *, struct connection *);
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
int kore_runtime_http_request(struct kore_runtime_call *,
|
||||
struct http_request *);
|
||||
int kore_runtime_validator(struct kore_runtime_call *,
|
||||
struct http_request *, void *);
|
||||
#endif
|
||||
|
||||
struct kore_domain *kore_domain_lookup(const char *);
|
||||
struct kore_module_handle *kore_module_handler_find(const char *,
|
||||
const char *);
|
||||
|
32
includes/python_api.h
Normal file
32
includes/python_api.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Stanislav Yudin <stan@endlessinsomnia.com>
|
||||
* Copyright (c) 2017 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __H_PYTHON_H
|
||||
#define __H_PYTHON_H
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
void kore_python_init(void);
|
||||
void kore_python_cleanup(void);
|
||||
void kore_python_path(const char *);
|
||||
|
||||
PyObject *kore_python_callable(PyObject *, const char *);
|
||||
|
||||
extern struct kore_module_functions kore_python_module;
|
||||
extern struct kore_runtime kore_python_runtime;
|
||||
|
||||
#endif
|
115
includes/python_methods.h
Normal file
115
includes/python_methods.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
static PyObject *python_exported_log(PyObject *, PyObject *);
|
||||
|
||||
#define METHOD(n, c, a) { n, (PyCFunction)c, a, NULL }
|
||||
#define GETTER(n, g) { n, (getter)g, NULL, NULL, NULL }
|
||||
#define SETTER(n, s) { n, NULL, (setter)g, NULL, NULL }
|
||||
#define GETSET(n, g, s) { n, (getter)g, (setter)s, NULL, NULL }
|
||||
|
||||
static struct PyMethodDef pykore_methods[] = {
|
||||
METHOD("log", python_exported_log, METH_VARARGS),
|
||||
{ NULL, NULL, 0, NULL }
|
||||
};
|
||||
|
||||
static struct PyModuleDef pykore_module = {
|
||||
PyModuleDef_HEAD_INIT, "kore", NULL, -1, pykore_methods
|
||||
};
|
||||
|
||||
struct pyconnection {
|
||||
PyObject_HEAD
|
||||
struct connection *c;
|
||||
};
|
||||
|
||||
static PyMethodDef pyconnection_methods[] = {
|
||||
METHOD(NULL, NULL, -1),
|
||||
};
|
||||
|
||||
static PyGetSetDef pyconnection_getset[] = {
|
||||
GETTER(NULL, NULL),
|
||||
};
|
||||
|
||||
static void pyconnection_dealloc(struct pyconnection *);
|
||||
|
||||
static PyTypeObject pyconnection_type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "kore.connection",
|
||||
.tp_doc = "struct connection",
|
||||
.tp_getset = pyconnection_getset,
|
||||
.tp_methods = pyconnection_methods,
|
||||
.tp_basicsize = sizeof(struct pyconnection),
|
||||
.tp_dealloc = (destructor)pyconnection_dealloc,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
};
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
struct pyhttp_request {
|
||||
PyObject_HEAD
|
||||
struct http_request *req;
|
||||
};
|
||||
|
||||
static void pyhttp_dealloc(struct pyhttp_request *);
|
||||
|
||||
static PyObject *pyhttp_response(struct pyhttp_request *, PyObject *);
|
||||
static PyObject *pyhttp_body_read(struct pyhttp_request *, PyObject *);
|
||||
static PyObject *pyhttp_populate_get(struct pyhttp_request *, PyObject *);
|
||||
static PyObject *pyhttp_populate_post(struct pyhttp_request *, PyObject *);
|
||||
static PyObject *pyhttp_request_header(struct pyhttp_request *, PyObject *);
|
||||
static PyObject *pyhttp_response_header(struct pyhttp_request *, PyObject *);
|
||||
|
||||
static PyMethodDef pyhttp_request_methods[] = {
|
||||
METHOD("response", pyhttp_response, METH_VARARGS),
|
||||
METHOD("body_read", pyhttp_body_read, METH_VARARGS),
|
||||
METHOD("populate_get", pyhttp_populate_get, METH_NOARGS),
|
||||
METHOD("populate_post", pyhttp_populate_post, METH_NOARGS),
|
||||
METHOD("request_header", pyhttp_request_header, METH_VARARGS),
|
||||
METHOD("response_header", pyhttp_response_header, METH_VARARGS),
|
||||
METHOD(NULL, NULL, -1)
|
||||
};
|
||||
|
||||
static int pyhttp_set_state(struct pyhttp_request *, PyObject *, void *);
|
||||
|
||||
static PyObject *pyhttp_get_host(struct pyhttp_request *, void *);
|
||||
static PyObject *pyhttp_get_path(struct pyhttp_request *, void *);
|
||||
static PyObject *pyhttp_get_body(struct pyhttp_request *, void *);
|
||||
static PyObject *pyhttp_get_agent(struct pyhttp_request *, void *);
|
||||
static PyObject *pyhttp_get_state(struct pyhttp_request *, void *);
|
||||
static PyObject *pyhttp_get_method(struct pyhttp_request *, void *);
|
||||
static PyObject *pyhttp_get_connection(struct pyhttp_request *, void *);
|
||||
|
||||
static PyGetSetDef pyhttp_request_getset[] = {
|
||||
GETTER("host", pyhttp_get_host),
|
||||
GETTER("path", pyhttp_get_path),
|
||||
GETTER("body", pyhttp_get_body),
|
||||
GETTER("agent", pyhttp_get_agent),
|
||||
GETTER("method", pyhttp_get_method),
|
||||
GETTER("connection", pyhttp_get_connection),
|
||||
GETSET("state", pyhttp_get_state, pyhttp_set_state),
|
||||
GETTER(NULL, NULL)
|
||||
};
|
||||
|
||||
static PyTypeObject pyhttp_request_type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
.tp_name = "kore.http_request",
|
||||
.tp_doc = "struct http_request",
|
||||
.tp_getset = pyhttp_request_getset,
|
||||
.tp_methods = pyhttp_request_methods,
|
||||
.tp_dealloc = (destructor)pyhttp_dealloc,
|
||||
.tp_basicsize = sizeof(struct pyhttp_request),
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
};
|
||||
#endif
|
28
src/config.c
28
src/config.c
@ -35,6 +35,10 @@
|
||||
#include "tasks.h"
|
||||
#endif
|
||||
|
||||
#if defined(KORE_USE_PYTHON)
|
||||
#include "python_api.h"
|
||||
#endif
|
||||
|
||||
/* XXX - This is becoming a clusterfuck. Fix it. */
|
||||
|
||||
#if !defined(KORE_SINGLE_BINARY)
|
||||
@ -99,6 +103,10 @@ static int configure_pgsql_conn_max(char *);
|
||||
static int configure_task_threads(char *);
|
||||
#endif
|
||||
|
||||
#if defined(KORE_USE_PYTHON)
|
||||
static int configure_python_import(char *);
|
||||
#endif
|
||||
|
||||
static void domain_sslstart(void);
|
||||
static void kore_parse_config_file(const char *);
|
||||
|
||||
@ -110,6 +118,9 @@ static struct {
|
||||
{ "bind", configure_bind },
|
||||
#if !defined(KORE_SINGLE_BINARY)
|
||||
{ "load", configure_load },
|
||||
#endif
|
||||
#if defined(KORE_USE_PYTHON)
|
||||
{ "python_import", configure_python_import },
|
||||
#endif
|
||||
{ "domain", configure_domain },
|
||||
{ "chroot", configure_chroot },
|
||||
@ -313,7 +324,7 @@ configure_load(char *options)
|
||||
if (argv[0] == NULL)
|
||||
return (KORE_RESULT_ERROR);
|
||||
|
||||
kore_module_load(argv[0], argv[1]);
|
||||
kore_module_load(argv[0], argv[1], KORE_MODULE_NATIVE);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
#else
|
||||
@ -1073,3 +1084,18 @@ configure_task_threads(char *option)
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(KORE_USE_PYTHON)
|
||||
static int
|
||||
configure_python_import(char *module)
|
||||
{
|
||||
char *argv[3];
|
||||
|
||||
kore_split_string(module, " ", argv, 3);
|
||||
if (argv[0] == NULL)
|
||||
return (KORE_RESULT_ERROR);
|
||||
|
||||
kore_module_load(argv[0], argv[1], KORE_MODULE_PYTHON);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
#endif
|
||||
|
@ -128,7 +128,7 @@ kore_connection_accept(struct listener *listener, struct connection **out)
|
||||
c->read = net_read;
|
||||
|
||||
if (listener->connect != NULL) {
|
||||
listener->connect(c);
|
||||
kore_runtime_connect(listener->connect, c);
|
||||
} else {
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
c->proto = CONN_PROTO_HTTP;
|
||||
@ -265,7 +265,7 @@ kore_connection_handle(struct connection *c)
|
||||
if (c->owner != NULL) {
|
||||
listener = (struct listener *)c->owner;
|
||||
if (listener->connect != NULL) {
|
||||
listener->connect(c);
|
||||
kore_runtime_connect(listener->connect, c);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
}
|
||||
|
11
src/http.c
11
src/http.c
@ -204,6 +204,10 @@ http_request_new(struct connection *c, const char *host,
|
||||
req->http_body_offset = 0;
|
||||
req->http_body_path = NULL;
|
||||
|
||||
#if defined(KORE_USE_PYTHON)
|
||||
req->py_object = NULL;
|
||||
#endif
|
||||
|
||||
req->host = kore_pool_get(&http_host_pool);
|
||||
memcpy(req->host, host, hostlen);
|
||||
req->host[hostlen] = '\0';
|
||||
@ -298,7 +302,7 @@ http_process(void)
|
||||
void
|
||||
http_process_request(struct http_request *req)
|
||||
{
|
||||
int r, (*cb)(struct http_request *);
|
||||
int r;
|
||||
|
||||
kore_debug("http_process_request: %p->%p (%s)",
|
||||
req->owner, req, req->path);
|
||||
@ -314,10 +318,7 @@ http_process_request(struct http_request *req)
|
||||
|
||||
switch (r) {
|
||||
case KORE_RESULT_OK:
|
||||
*(void **)&(cb) = req->hdlr->addr;
|
||||
worker->active_hdlr = req->hdlr;
|
||||
r = cb(req);
|
||||
worker->active_hdlr = NULL;
|
||||
r = kore_runtime_http_request(req->hdlr->rcall, req);
|
||||
break;
|
||||
case KORE_RESULT_RETRY:
|
||||
break;
|
||||
|
26
src/kore.c
26
src/kore.c
@ -30,6 +30,10 @@
|
||||
#include "http.h"
|
||||
#endif
|
||||
|
||||
#if defined(KORE_USE_PYTHON)
|
||||
#include "python_api.h"
|
||||
#endif
|
||||
|
||||
volatile sig_atomic_t sig_recv;
|
||||
|
||||
struct listener_head listeners;
|
||||
@ -175,6 +179,9 @@ main(int argc, char *argv[])
|
||||
LIST_INIT(&listeners);
|
||||
|
||||
kore_log_init();
|
||||
#if defined(KORE_USE_PYTHON)
|
||||
kore_python_init();
|
||||
#endif
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
kore_auth_init();
|
||||
kore_validator_init();
|
||||
@ -187,7 +194,7 @@ main(int argc, char *argv[])
|
||||
if (config_file == NULL)
|
||||
usage();
|
||||
#else
|
||||
kore_module_load(NULL, NULL);
|
||||
kore_module_load(NULL, NULL, KORE_MODULE_NATIVE);
|
||||
#endif
|
||||
|
||||
kore_parse_config();
|
||||
@ -340,8 +347,7 @@ kore_server_bind(const char *ip, const char *port, const char *ccb)
|
||||
}
|
||||
|
||||
if (ccb != NULL) {
|
||||
*(void **)&(l->connect) = kore_module_getsym(ccb);
|
||||
if (l->connect == NULL) {
|
||||
if ((l->connect = kore_runtime_getcall(ccb)) == NULL) {
|
||||
printf("no such callback: '%s'\n", ccb);
|
||||
close(l->fd);
|
||||
kore_free(l);
|
||||
@ -398,10 +404,10 @@ kore_server_sslstart(void)
|
||||
static void
|
||||
kore_server_start(void)
|
||||
{
|
||||
u_int32_t tmp;
|
||||
int quit;
|
||||
u_int32_t tmp;
|
||||
int quit;
|
||||
#if defined(KORE_SINGLE_BINARY)
|
||||
void (*preload)(void);
|
||||
struct kore_runtime_call *rcall;
|
||||
#endif
|
||||
|
||||
if (foreground == 0 && daemon(1, 1) == -1)
|
||||
@ -422,9 +428,11 @@ kore_server_start(void)
|
||||
kore_log(LOG_NOTICE, "jsonrpc built-in enabled");
|
||||
#endif
|
||||
#if defined(KORE_SINGLE_BINARY)
|
||||
*(void **)&(preload) = kore_module_getsym("kore_preload");
|
||||
if (preload != NULL)
|
||||
preload();
|
||||
rcall = kore_runtime_getcall("kore_preload");
|
||||
if (rcall != NULL) {
|
||||
rcall->runtime->execute(rcall->addr, NULL);
|
||||
kore_free(rcall);
|
||||
}
|
||||
#endif
|
||||
|
||||
kore_platform_proctitle("kore [parent]");
|
||||
|
165
src/module.c
165
src/module.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2016 Joris Vink <joris@coders.se>
|
||||
* Copyright (c) 2013-2017 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@ -20,8 +20,28 @@
|
||||
|
||||
#include "kore.h"
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
#include "http.h"
|
||||
#endif
|
||||
|
||||
#if defined(KORE_USE_PYTHON)
|
||||
#include "python_api.h"
|
||||
#endif
|
||||
|
||||
static TAILQ_HEAD(, kore_module) modules;
|
||||
|
||||
static void native_free(struct kore_module *);
|
||||
static void native_reload(struct kore_module *);
|
||||
static void native_load(struct kore_module *, const char *);
|
||||
static void *native_getsym(struct kore_module *, const char *);
|
||||
|
||||
struct kore_module_functions kore_native_module = {
|
||||
.free = native_free,
|
||||
.load = native_load,
|
||||
.getsym = native_getsym,
|
||||
.reload = native_reload,
|
||||
};
|
||||
|
||||
void
|
||||
kore_module_init(void)
|
||||
{
|
||||
@ -36,15 +56,12 @@ kore_module_cleanup(void)
|
||||
for (module = TAILQ_FIRST(&modules); module != NULL; module = next) {
|
||||
next = TAILQ_NEXT(module, list);
|
||||
TAILQ_REMOVE(&modules, module, list);
|
||||
|
||||
kore_free(module->path);
|
||||
(void)dlclose(module->handle);
|
||||
kore_free(module);
|
||||
module->fun->free(module);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
kore_module_load(const char *path, const char *onload)
|
||||
kore_module_load(const char *path, const char *onload, int type)
|
||||
{
|
||||
#if !defined(KORE_SINGLE_BINARY)
|
||||
struct stat st;
|
||||
@ -54,8 +71,10 @@ kore_module_load(const char *path, const char *onload)
|
||||
kore_debug("kore_module_load(%s, %s)", path, onload);
|
||||
|
||||
module = kore_malloc(sizeof(struct kore_module));
|
||||
module->onload = NULL;
|
||||
module->ocb = NULL;
|
||||
module->type = type;
|
||||
module->onload = NULL;
|
||||
module->handle = NULL;
|
||||
|
||||
#if !defined(KORE_SINGLE_BINARY)
|
||||
if (stat(path, &st) == -1)
|
||||
@ -68,18 +87,34 @@ kore_module_load(const char *path, const char *onload)
|
||||
module->mtime = 0;
|
||||
#endif
|
||||
|
||||
module->handle = dlopen(module->path, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (module->handle == NULL)
|
||||
fatal("%s: %s", path, dlerror());
|
||||
|
||||
if (onload != NULL) {
|
||||
module->onload = kore_strdup(onload);
|
||||
*(void **)&(module->ocb) = dlsym(module->handle, onload);
|
||||
if (module->ocb == NULL)
|
||||
fatal("%s: onload '%s' not present", path, onload);
|
||||
switch (module->type) {
|
||||
case KORE_MODULE_NATIVE:
|
||||
module->fun = &kore_native_module;
|
||||
module->runtime = &kore_native_runtime;
|
||||
break;
|
||||
#if defined(KORE_USE_PYTHON)
|
||||
case KORE_MODULE_PYTHON:
|
||||
module->fun = &kore_python_module;
|
||||
module->runtime = &kore_python_runtime;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
fatal("kore_module_load: unknown type %d", type);
|
||||
}
|
||||
|
||||
module->fun->load(module, onload);
|
||||
TAILQ_INSERT_TAIL(&modules, module, list);
|
||||
|
||||
if (onload != NULL) {
|
||||
module->ocb = kore_malloc(sizeof(*module->ocb));
|
||||
module->ocb->runtime = module->runtime;
|
||||
module->ocb->addr = module->fun->getsym(module, onload);
|
||||
|
||||
if (module->ocb->addr == NULL) {
|
||||
fatal("%s: onload '%s' not present",
|
||||
module->path, onload);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -92,7 +127,7 @@ kore_module_onload(void)
|
||||
if (module->ocb == NULL)
|
||||
continue;
|
||||
|
||||
(void)module->ocb(KORE_MODULE_LOAD);
|
||||
kore_runtime_onload(module->ocb, KORE_MODULE_LOAD);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@ -102,6 +137,7 @@ kore_module_reload(int cbs)
|
||||
{
|
||||
#if !defined(KORE_SINGLE_BINARY)
|
||||
struct stat st;
|
||||
int ret;
|
||||
struct kore_domain *dom;
|
||||
struct kore_module_handle *hdlr;
|
||||
struct kore_module *module;
|
||||
@ -113,11 +149,15 @@ kore_module_reload(int cbs)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (module->mtime == st.st_mtime)
|
||||
if (module->mtime == st.st_mtime) {
|
||||
kore_log(LOG_NOTICE, "not reloading %s", module->path);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (module->ocb != NULL && cbs == 1) {
|
||||
if (!module->ocb(KORE_MODULE_UNLOAD)) {
|
||||
ret = kore_runtime_onload(module->ocb,
|
||||
KORE_MODULE_UNLOAD);
|
||||
if (ret == KORE_RESULT_ERROR) {
|
||||
kore_log(LOG_NOTICE,
|
||||
"not reloading %s", module->path);
|
||||
continue;
|
||||
@ -125,32 +165,31 @@ kore_module_reload(int cbs)
|
||||
}
|
||||
|
||||
module->mtime = st.st_mtime;
|
||||
if (dlclose(module->handle))
|
||||
fatal("cannot close existing module: %s", dlerror());
|
||||
|
||||
module->handle = dlopen(module->path, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (module->handle == NULL)
|
||||
fatal("kore_module_reload(): %s", dlerror());
|
||||
module->fun->reload(module);
|
||||
|
||||
if (module->onload != NULL) {
|
||||
*(void **)&(module->ocb) =
|
||||
dlsym(module->handle, module->onload);
|
||||
if (module->ocb == NULL) {
|
||||
kore_free(module->ocb);
|
||||
module->ocb = kore_malloc(sizeof(*module->ocb));
|
||||
module->ocb->runtime = module->runtime;
|
||||
module->ocb->addr =
|
||||
module->fun->getsym(module, module->onload);
|
||||
if (module->ocb->addr == NULL) {
|
||||
fatal("%s: onload '%s' not present",
|
||||
module->path, module->onload);
|
||||
}
|
||||
|
||||
if (cbs)
|
||||
(void)module->ocb(KORE_MODULE_LOAD);
|
||||
}
|
||||
|
||||
if (module->ocb != NULL && cbs == 1)
|
||||
kore_runtime_onload(module->ocb, KORE_MODULE_LOAD);
|
||||
|
||||
kore_log(LOG_NOTICE, "reloaded '%s' module", module->path);
|
||||
}
|
||||
|
||||
TAILQ_FOREACH(dom, &domains, list) {
|
||||
TAILQ_FOREACH(hdlr, &(dom->handlers), list) {
|
||||
hdlr->addr = kore_module_getsym(hdlr->func);
|
||||
if (hdlr->func == NULL)
|
||||
kore_free(hdlr->rcall);
|
||||
hdlr->rcall = kore_runtime_getcall(hdlr->func);
|
||||
if (hdlr->rcall == NULL)
|
||||
fatal("no function '%s' found", hdlr->func);
|
||||
hdlr->errors = 0;
|
||||
}
|
||||
@ -177,19 +216,12 @@ kore_module_handler_new(const char *path, const char *domain,
|
||||
const char *func, const char *auth, int type)
|
||||
{
|
||||
struct kore_auth *ap;
|
||||
void *addr;
|
||||
struct kore_domain *dom;
|
||||
struct kore_module_handle *hdlr;
|
||||
|
||||
kore_debug("kore_module_handler_new(%s, %s, %s, %s, %d)", path,
|
||||
domain, func, auth, type);
|
||||
|
||||
addr = kore_module_getsym(func);
|
||||
if (addr == NULL) {
|
||||
kore_debug("function '%s' not found", func);
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
if ((dom = kore_domain_lookup(domain)) == NULL)
|
||||
return (KORE_RESULT_ERROR);
|
||||
|
||||
@ -204,12 +236,18 @@ kore_module_handler_new(const char *path, const char *domain,
|
||||
hdlr->auth = ap;
|
||||
hdlr->dom = dom;
|
||||
hdlr->errors = 0;
|
||||
hdlr->addr = addr;
|
||||
hdlr->type = type;
|
||||
TAILQ_INIT(&(hdlr->params));
|
||||
hdlr->path = kore_strdup(path);
|
||||
hdlr->func = kore_strdup(func);
|
||||
|
||||
TAILQ_INIT(&(hdlr->params));
|
||||
|
||||
if ((hdlr->rcall = kore_runtime_getcall(func)) == NULL) {
|
||||
kore_module_handler_free(hdlr);
|
||||
kore_log(LOG_ERR, "function '%s' not found", func);
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
if (hdlr->type == HANDLER_TYPE_DYNAMIC) {
|
||||
if (regcomp(&(hdlr->rctx), hdlr->path,
|
||||
REG_EXTENDED | REG_NOSUB)) {
|
||||
@ -270,20 +308,55 @@ kore_module_handler_find(const char *domain, const char *path)
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
#endif /* !KORE_NO_HTTP */
|
||||
|
||||
void *
|
||||
kore_module_getsym(const char *symbol)
|
||||
kore_module_getsym(const char *symbol, struct kore_runtime **runtime)
|
||||
{
|
||||
void *ptr;
|
||||
struct kore_module *module;
|
||||
|
||||
if (runtime != NULL)
|
||||
*runtime = NULL;
|
||||
|
||||
TAILQ_FOREACH(module, &modules, list) {
|
||||
ptr = dlsym(module->handle, symbol);
|
||||
if (ptr != NULL)
|
||||
ptr = module->fun->getsym(module, symbol);
|
||||
if (ptr != NULL) {
|
||||
if (runtime != NULL)
|
||||
*runtime = module->runtime;
|
||||
return (ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static void *
|
||||
native_getsym(struct kore_module *module, const char *symbol)
|
||||
{
|
||||
return (dlsym(module->handle, symbol));
|
||||
}
|
||||
|
||||
static void
|
||||
native_free(struct kore_module *module)
|
||||
{
|
||||
kore_free(module->path);
|
||||
(void)dlclose(module->handle);
|
||||
kore_free(module);
|
||||
}
|
||||
|
||||
static void
|
||||
native_reload(struct kore_module *module)
|
||||
{
|
||||
if (dlclose(module->handle))
|
||||
fatal("cannot close existing module: %s", dlerror());
|
||||
module->fun->load(module, module->onload);
|
||||
}
|
||||
|
||||
static void
|
||||
native_load(struct kore_module *module, const char *onload)
|
||||
{
|
||||
module->handle = dlopen(module->path, RTLD_NOW | RTLD_GLOBAL);
|
||||
if (module->handle == NULL)
|
||||
fatal("%s: %s", module->path, dlerror());
|
||||
}
|
||||
|
667
src/python.c
Normal file
667
src/python.c
Normal file
@ -0,0 +1,667 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Stanislav Yudin <stan@endlessinsomnia.com>
|
||||
* Copyright (c) 2017 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <libgen.h>
|
||||
|
||||
#include "kore.h"
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
#include "http.h"
|
||||
#endif
|
||||
|
||||
#include "python_api.h"
|
||||
#include "python_methods.h"
|
||||
|
||||
static PyMODINIT_FUNC python_module_init(void);
|
||||
static PyObject *python_import(const char *);
|
||||
static void python_log_error(const char *);
|
||||
static PyObject *pyconnection_alloc(struct connection *);
|
||||
static PyObject *python_callable(PyObject *, const char *);
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
static PyObject *pyhttp_request_alloc(struct http_request *);
|
||||
#endif
|
||||
|
||||
static void python_append_path(const char *);
|
||||
static void python_push_integer(PyObject *, const char *, long);
|
||||
static void python_push_type(const char *, PyObject *, PyTypeObject *);
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
static int python_runtime_http_request(void *, struct http_request *);
|
||||
static int python_runtime_validator(void *, struct http_request *, void *);
|
||||
#endif
|
||||
static int python_runtime_onload(void *, int);
|
||||
static void python_runtime_connect(void *, struct connection *);
|
||||
|
||||
static void python_module_free(struct kore_module *);
|
||||
static void python_module_reload(struct kore_module *);
|
||||
static void python_module_load(struct kore_module *, const char *);
|
||||
static void *python_module_getsym(struct kore_module *, const char *);
|
||||
|
||||
struct kore_module_functions kore_python_module = {
|
||||
.free = python_module_free,
|
||||
.load = python_module_load,
|
||||
.getsym = python_module_getsym,
|
||||
.reload = python_module_reload
|
||||
};
|
||||
|
||||
struct kore_runtime kore_python_runtime = {
|
||||
KORE_RUNTIME_PYTHON,
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
.http_request = python_runtime_http_request,
|
||||
.validator = python_runtime_validator,
|
||||
#endif
|
||||
.onload = python_runtime_onload,
|
||||
.connect = python_runtime_connect
|
||||
};
|
||||
|
||||
void
|
||||
kore_python_init(void)
|
||||
{
|
||||
if (PyImport_AppendInittab("kore", &python_module_init) == -1)
|
||||
fatal("kore_python_init: failed to add new module");
|
||||
|
||||
Py_Initialize();
|
||||
}
|
||||
|
||||
void
|
||||
kore_python_cleanup(void)
|
||||
{
|
||||
if (Py_IsInitialized())
|
||||
Py_Finalize();
|
||||
}
|
||||
|
||||
static void
|
||||
python_log_error(const char *function)
|
||||
{
|
||||
PyObject *type, *value, *traceback;
|
||||
|
||||
if (!PyErr_Occurred())
|
||||
return;
|
||||
|
||||
PyErr_Fetch(&type, &value, &traceback);
|
||||
|
||||
if (type == NULL || value == NULL || traceback == NULL)
|
||||
fatal("python_log_error(): exception but no error trace?");
|
||||
|
||||
kore_log(LOG_ERR,
|
||||
"python exception in '%s' - type:%s - value:%s - trace:%s",
|
||||
function,
|
||||
PyUnicode_AsUTF8AndSize(type, NULL),
|
||||
PyUnicode_AsUTF8AndSize(value, NULL),
|
||||
PyUnicode_AsUTF8AndSize(traceback, NULL));
|
||||
|
||||
Py_DECREF(type);
|
||||
Py_DECREF(value);
|
||||
Py_DECREF(traceback);
|
||||
}
|
||||
|
||||
static void
|
||||
python_module_free(struct kore_module *module)
|
||||
{
|
||||
kore_free(module->path);
|
||||
Py_DECREF(module->handle);
|
||||
kore_free(module);
|
||||
}
|
||||
|
||||
static void
|
||||
python_module_reload(struct kore_module *module)
|
||||
{
|
||||
/* Calls through to kore_python_module_load() below. */
|
||||
module->fun->load(module, module->onload);
|
||||
}
|
||||
|
||||
static void
|
||||
python_module_load(struct kore_module *module, const char *onload)
|
||||
{
|
||||
if (module->handle != NULL)
|
||||
Py_DECREF(module->handle);
|
||||
|
||||
kore_python_cleanup();
|
||||
kore_python_init();
|
||||
|
||||
module->handle = python_import(module->path);
|
||||
if (module->handle == NULL)
|
||||
fatal("%s: failed to import module", module->path);
|
||||
}
|
||||
|
||||
static void *
|
||||
python_module_getsym(struct kore_module *module, const char *symbol)
|
||||
{
|
||||
return (python_callable(module->handle, symbol));
|
||||
}
|
||||
|
||||
static void pyhttp_dealloc(struct pyhttp_request *pyreq)
|
||||
{
|
||||
printf("pyreq %p goes byebye\n", (void *)pyreq);
|
||||
PyObject_Del((PyObject *)pyreq);
|
||||
}
|
||||
|
||||
static void pyconnection_dealloc(struct pyconnection *pyc)
|
||||
{
|
||||
printf("pyc %p goes byebye\n", (void *)pyc);
|
||||
PyObject_Del((PyObject *)pyc);
|
||||
}
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
static int
|
||||
python_runtime_http_request(void *addr, struct http_request *req)
|
||||
{
|
||||
int ret;
|
||||
PyObject *pyret, *pyreq, *args, *callable;
|
||||
|
||||
callable = (PyObject *)addr;
|
||||
|
||||
pyreq = pyhttp_request_alloc(req);
|
||||
if (pyreq == NULL) {
|
||||
kore_log(LOG_ERR, "cannot create new pyhttp_request");
|
||||
http_response(req, HTTP_STATUS_INTERNAL_ERROR, NULL, 0);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
if ((args = PyTuple_New(1)) == NULL)
|
||||
fatal("python_runtime_http_request: PyTuple_New failed");
|
||||
|
||||
printf(" args tuple: %p\n", (void *)args);
|
||||
|
||||
if (PyTuple_SetItem(args, 0, pyreq) != 0)
|
||||
fatal("python_runtime_http_request: PyTuple_SetItem failed");
|
||||
|
||||
PyErr_Clear();
|
||||
pyret = PyObject_Call(callable, args, NULL);
|
||||
Py_DECREF(args);
|
||||
|
||||
if (pyret == NULL) {
|
||||
Py_XDECREF(req->py_object);
|
||||
python_log_error("python_runtime_http_request");
|
||||
http_response(req, HTTP_STATUS_INTERNAL_ERROR, NULL, 0);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
|
||||
if (!PyLong_Check(pyret))
|
||||
fatal("python_runtime_http_request: unexpected return type");
|
||||
|
||||
ret = (int)PyLong_AsLong(pyret);
|
||||
if (ret != KORE_RESULT_RETRY)
|
||||
Py_XDECREF(req->py_object);
|
||||
|
||||
Py_DECREF(pyret);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
python_runtime_validator(void *addr, struct http_request *req, void *data)
|
||||
{
|
||||
printf("python_runtime_validator: XXX %s\n", req->path);
|
||||
return (KORE_RESULT_OK);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
python_runtime_onload(void *addr, int action)
|
||||
{
|
||||
int ret;
|
||||
PyObject *pyret, *args, *pyact, *callable;
|
||||
|
||||
callable = (PyObject *)addr;
|
||||
|
||||
if ((pyact = PyLong_FromLong(action)) == NULL)
|
||||
fatal("python_runtime_onload: PyLong_FromLong failed");
|
||||
|
||||
if ((args = PyTuple_New(1)) == NULL)
|
||||
fatal("python_runtime_onload: PyTuple_New failed");
|
||||
|
||||
if (PyTuple_SetItem(args, 0, pyact) != 0)
|
||||
fatal("python_runtime_onload: PyTuple_SetItem failed");
|
||||
|
||||
pyret = PyObject_Call(callable, args, NULL);
|
||||
Py_DECREF(args);
|
||||
|
||||
if (pyret == NULL) {
|
||||
python_log_error("python_runtime_onload");
|
||||
return (KORE_RESULT_ERROR);
|
||||
}
|
||||
|
||||
if (!PyLong_Check(pyret))
|
||||
fatal("python_runtime_onload: unexpected return type");
|
||||
|
||||
ret = (int)PyLong_AsLong(pyret);
|
||||
Py_DECREF(pyret);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static void
|
||||
python_runtime_connect(void *addr, struct connection *c)
|
||||
{
|
||||
PyObject *pyc, *pyret, *args, *callable;
|
||||
|
||||
callable = (PyObject *)addr;
|
||||
|
||||
if ((pyc = pyconnection_alloc(c)) == NULL) {
|
||||
kore_log(LOG_ERR, "cannot create new pyconnection");
|
||||
kore_connection_disconnect(c);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((args = PyTuple_New(1)) == NULL)
|
||||
fatal("python_runtime_connect: PyTuple_New failed");
|
||||
|
||||
if (PyTuple_SetItem(args, 0, pyc) != 0)
|
||||
fatal("python_runtime_connect: PyTuple_SetItem failed");
|
||||
|
||||
pyret = PyObject_Call(callable, args, NULL);
|
||||
Py_DECREF(args);
|
||||
|
||||
if (pyret == NULL) {
|
||||
python_log_error("python_runtime_connect");
|
||||
kore_connection_disconnect(c);
|
||||
}
|
||||
|
||||
Py_DECREF(pyret);
|
||||
}
|
||||
|
||||
static PyMODINIT_FUNC
|
||||
python_module_init(void)
|
||||
{
|
||||
PyObject *pykore;
|
||||
|
||||
if ((pykore = PyModule_Create(&pykore_module)) == NULL)
|
||||
fatal("python_module_init: failed to setup pykore module");
|
||||
|
||||
python_push_type("pyconnection", pykore, &pyconnection_type);
|
||||
|
||||
python_push_integer(pykore, "RESULT_OK", KORE_RESULT_OK);
|
||||
python_push_integer(pykore, "RESULT_RETRY", KORE_RESULT_RETRY);
|
||||
python_push_integer(pykore, "RESULT_ERROR", KORE_RESULT_ERROR);
|
||||
python_push_integer(pykore, "MODULE_LOAD", KORE_MODULE_LOAD);
|
||||
python_push_integer(pykore, "MODULE_UNLOAD", KORE_MODULE_UNLOAD);
|
||||
|
||||
python_push_integer(pykore, "LOG_ERR", LOG_ERR);
|
||||
python_push_integer(pykore, "LOG_INFO", LOG_INFO);
|
||||
python_push_integer(pykore, "LOG_NOTICE", LOG_NOTICE);
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
python_push_type("pyhttp_request", pykore, &pyhttp_request_type);
|
||||
|
||||
python_push_integer(pykore, "METHOD_GET", HTTP_METHOD_GET);
|
||||
python_push_integer(pykore, "METHOD_PUT", HTTP_METHOD_PUT);
|
||||
python_push_integer(pykore, "METHOD_HEAD", HTTP_METHOD_HEAD);
|
||||
python_push_integer(pykore, "METHOD_POST", HTTP_METHOD_POST);
|
||||
python_push_integer(pykore, "METHOD_DELETE", HTTP_METHOD_DELETE);
|
||||
python_push_integer(pykore,
|
||||
"WEBSOCKET_BROADCAST_LOCAL", WEBSOCKET_BROADCAST_LOCAL);
|
||||
python_push_integer(pykore,
|
||||
"WEBSOCKET_BROADCAST_GLOBAL", WEBSOCKET_BROADCAST_GLOBAL);
|
||||
#endif
|
||||
|
||||
return (pykore);
|
||||
}
|
||||
|
||||
static void
|
||||
python_append_path(const char *path)
|
||||
{
|
||||
PyObject *mpath, *spath;
|
||||
|
||||
if ((mpath = PyUnicode_FromString(path)) == NULL)
|
||||
fatal("python_append_path: PyUnicode_FromString failed");
|
||||
|
||||
if ((spath = PySys_GetObject("path")) == NULL)
|
||||
fatal("python_append_path: PySys_GetObject failed");
|
||||
|
||||
PyList_Append(spath, mpath);
|
||||
Py_DECREF(mpath);
|
||||
}
|
||||
|
||||
static void
|
||||
python_push_type(const char *name, PyObject *module, PyTypeObject *type)
|
||||
{
|
||||
if (PyType_Ready(type) == -1)
|
||||
fatal("python_push_type: failed to ready %s", name);
|
||||
|
||||
Py_INCREF(type);
|
||||
|
||||
if (PyModule_AddObject(module, name, (PyObject *)type) == -1)
|
||||
fatal("python_push_type: failed to push %s", name);
|
||||
}
|
||||
|
||||
static void
|
||||
python_push_integer(PyObject *module, const char *name, long value)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = PyModule_AddIntConstant(module, name, value)) == -1)
|
||||
fatal("python_push_integer: failed to add %s", name);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
python_exported_log(PyObject *self, PyObject *args)
|
||||
{
|
||||
int prio;
|
||||
const char *message;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "is", &prio, &message)) {
|
||||
PyErr_SetString(PyExc_TypeError, "invalid parameters");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
kore_log(prio, "%s", message);
|
||||
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
python_import(const char *path)
|
||||
{
|
||||
PyObject *module;
|
||||
char *dir, *file, *copy, *p;
|
||||
|
||||
copy = kore_strdup(path);
|
||||
|
||||
if ((file = basename(copy)) == NULL)
|
||||
fatal("basename: %s: %s", path, errno_s);
|
||||
if ((dir = dirname(copy)) == NULL)
|
||||
fatal("dirname: %s: %s", path, errno_s);
|
||||
|
||||
if ((p = strrchr(file, '.')) != NULL)
|
||||
*p = '\0';
|
||||
|
||||
python_append_path(dir);
|
||||
module = PyImport_ImportModule(file);
|
||||
if (module == NULL)
|
||||
PyErr_Print();
|
||||
|
||||
kore_free(copy);
|
||||
|
||||
return (module);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
python_callable(PyObject *module, const char *symbol)
|
||||
{
|
||||
PyObject *obj;
|
||||
|
||||
if ((obj = PyObject_GetAttrString(module, symbol)) == NULL)
|
||||
return (NULL);
|
||||
|
||||
if (!PyCallable_Check(obj)) {
|
||||
Py_DECREF(obj);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (obj);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyconnection_alloc(struct connection *c)
|
||||
{
|
||||
struct pyconnection *pyc;
|
||||
|
||||
pyc = PyObject_New(struct pyconnection, &pyconnection_type);
|
||||
if (pyc == NULL)
|
||||
return (NULL);
|
||||
|
||||
printf(" pyc: %p\n", (void *)pyc);
|
||||
pyc->c = c;
|
||||
|
||||
return ((PyObject *)pyc);
|
||||
}
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
static PyObject *
|
||||
pyhttp_request_alloc(struct http_request *req)
|
||||
{
|
||||
struct pyhttp_request *pyreq;
|
||||
|
||||
pyreq = PyObject_New(struct pyhttp_request, &pyhttp_request_type);
|
||||
if (pyreq == NULL)
|
||||
return (NULL);
|
||||
|
||||
pyreq->req = req;
|
||||
|
||||
return ((PyObject *)pyreq);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyhttp_response(struct pyhttp_request *pyreq, PyObject *args)
|
||||
{
|
||||
Py_buffer body;
|
||||
int status;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iy*", &status, &body)) {
|
||||
PyErr_SetString(PyExc_TypeError, "invalid parameters");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
http_response(pyreq->req, status, body.buf, body.len);
|
||||
PyBuffer_Release(&body);
|
||||
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyhttp_response_header(struct pyhttp_request *pyreq, PyObject *args)
|
||||
{
|
||||
const char *header, *value;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ss", &header, &value)) {
|
||||
PyErr_SetString(PyExc_TypeError, "invalid parameters");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
http_response_header(pyreq->req, header, value);
|
||||
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyhttp_request_header(struct pyhttp_request *pyreq, PyObject *args)
|
||||
{
|
||||
char *value;
|
||||
const char *header;
|
||||
PyObject *result;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &header)) {
|
||||
PyErr_SetString(PyExc_TypeError, "invalid parameters");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (!http_request_header(pyreq->req, header, &value)) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
if ((result = PyUnicode_FromString(value)) == NULL)
|
||||
return (PyErr_NoMemory());
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyhttp_body_read(struct pyhttp_request *pyreq, PyObject *args)
|
||||
{
|
||||
ssize_t ret;
|
||||
size_t len;
|
||||
Py_ssize_t pylen;
|
||||
PyObject *result;
|
||||
u_int8_t buf[1024];
|
||||
|
||||
if (!PyArg_ParseTuple(args, "n", &pylen) || pylen < 0) {
|
||||
PyErr_SetString(PyExc_TypeError, "invalid parameters");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
len = (size_t)pylen;
|
||||
if (len > sizeof(buf)) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "len > sizeof(buf)");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
ret = http_body_read(pyreq->req, buf, len);
|
||||
if (ret == -1) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "http_body_read() failed");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (ret > INT_MAX) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "ret > INT_MAX");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
result = Py_BuildValue("ny#", ret, buf, (int)ret);
|
||||
if (result == NULL)
|
||||
return (PyErr_NoMemory());
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyhttp_populate_get(struct pyhttp_request *pyreq, PyObject *args)
|
||||
{
|
||||
http_populate_get(pyreq->req);
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyhttp_populate_post(struct pyhttp_request *pyreq, PyObject *args)
|
||||
{
|
||||
http_populate_post(pyreq->req);
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyhttp_get_host(struct pyhttp_request *pyreq, void *closure)
|
||||
{
|
||||
PyObject *host;
|
||||
|
||||
if ((host = PyUnicode_FromString(pyreq->req->host)) == NULL)
|
||||
return (PyErr_NoMemory());
|
||||
|
||||
return (host);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyhttp_get_path(struct pyhttp_request *pyreq, void *closure)
|
||||
{
|
||||
PyObject *path;
|
||||
|
||||
if ((path = PyUnicode_FromString(pyreq->req->path)) == NULL)
|
||||
return (PyErr_NoMemory());
|
||||
|
||||
return (path);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyhttp_get_body(struct pyhttp_request *pyreq, void *closure)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct kore_buf buf;
|
||||
PyObject *body;
|
||||
u_int8_t data[BUFSIZ];
|
||||
|
||||
kore_buf_init(&buf, 1024);
|
||||
|
||||
for (;;) {
|
||||
ret = http_body_read(pyreq->req, data, sizeof(data));
|
||||
if (ret == -1) {
|
||||
kore_buf_cleanup(&buf);
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"http_body_read() failed");
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (ret == 0)
|
||||
break;
|
||||
|
||||
kore_buf_append(&buf, data, (size_t)ret);
|
||||
}
|
||||
|
||||
body = PyBytes_FromStringAndSize((char *)buf.data, buf.offset);
|
||||
kore_buf_free(&buf);
|
||||
|
||||
if (body == NULL)
|
||||
return (PyErr_NoMemory());
|
||||
|
||||
return (body);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyhttp_get_agent(struct pyhttp_request *pyreq, void *closure)
|
||||
{
|
||||
PyObject *agent;
|
||||
|
||||
if (pyreq->req->agent == NULL) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
if ((agent = PyUnicode_FromString(pyreq->req->path)) == NULL)
|
||||
return (PyErr_NoMemory());
|
||||
|
||||
return (agent);
|
||||
}
|
||||
|
||||
static int
|
||||
pyhttp_set_state(struct pyhttp_request *pyreq, PyObject *value, void *closure)
|
||||
{
|
||||
if (value == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"pyhttp_set_state: value is NULL");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
Py_XDECREF(pyreq->req->py_object);
|
||||
pyreq->req->py_object = value;
|
||||
Py_INCREF(pyreq->req->py_object);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyhttp_get_state(struct pyhttp_request *pyreq, void *closure)
|
||||
{
|
||||
if (pyreq->req->py_object == NULL)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
Py_INCREF(pyreq->req->py_object);
|
||||
|
||||
return (pyreq->req->py_object);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyhttp_get_method(struct pyhttp_request *pyreq, void *closure)
|
||||
{
|
||||
PyObject *method;
|
||||
|
||||
if ((method = PyLong_FromUnsignedLong(pyreq->req->method)) == NULL)
|
||||
return (PyErr_NoMemory());
|
||||
|
||||
return (method);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
pyhttp_get_connection(struct pyhttp_request *pyreq, void *closure)
|
||||
{
|
||||
PyObject *pyc;
|
||||
|
||||
if ((pyc = pyconnection_alloc(pyreq->req->owner)) == NULL)
|
||||
return (PyErr_NoMemory());
|
||||
|
||||
return (pyc);
|
||||
}
|
||||
#endif
|
128
src/runtime.c
Normal file
128
src/runtime.c
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) 2017 Joris Vink <joris@coders.se>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include "kore.h"
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
#include "http.h"
|
||||
#endif
|
||||
|
||||
#if defined(KORE_USE_PYTHON)
|
||||
#include "python_api.h"
|
||||
#endif
|
||||
|
||||
static int native_runtime_onload(void *, int);
|
||||
static void native_runtime_connect(void *, struct connection *);
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
static int native_runtime_http_request(void *, struct http_request *);
|
||||
static int native_runtime_validator(void *, struct http_request *, void *);
|
||||
#endif
|
||||
|
||||
struct kore_runtime kore_native_runtime = {
|
||||
KORE_RUNTIME_NATIVE,
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
.http_request = native_runtime_http_request,
|
||||
.validator = native_runtime_validator,
|
||||
#endif
|
||||
.onload = native_runtime_onload,
|
||||
.connect = native_runtime_connect
|
||||
};
|
||||
|
||||
struct kore_runtime_call *
|
||||
kore_runtime_getcall(const char *symbol)
|
||||
{
|
||||
void *ptr;
|
||||
struct kore_runtime_call *rcall;
|
||||
struct kore_runtime *runtime;
|
||||
|
||||
ptr = kore_module_getsym(symbol, &runtime);
|
||||
if (ptr == NULL)
|
||||
return (NULL);
|
||||
|
||||
rcall = kore_malloc(sizeof(*rcall));
|
||||
rcall->addr = ptr;
|
||||
rcall->runtime = runtime;
|
||||
|
||||
return (rcall);
|
||||
}
|
||||
|
||||
int
|
||||
kore_runtime_onload(struct kore_runtime_call *rcall, int action)
|
||||
{
|
||||
return (rcall->runtime->onload(rcall->addr, action));
|
||||
}
|
||||
|
||||
void
|
||||
kore_runtime_connect(struct kore_runtime_call *rcall, struct connection *c)
|
||||
{
|
||||
rcall->runtime->connect(rcall->addr, c);
|
||||
}
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
int
|
||||
kore_runtime_http_request(struct kore_runtime_call *rcall,
|
||||
struct http_request *req)
|
||||
{
|
||||
return (rcall->runtime->http_request(rcall->addr, req));
|
||||
}
|
||||
|
||||
int
|
||||
kore_runtime_validator(struct kore_runtime_call *rcall,
|
||||
struct http_request *req, void *data)
|
||||
{
|
||||
return (rcall->runtime->validator(rcall->addr, req, data));
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
native_runtime_connect(void *addr, struct connection *c)
|
||||
{
|
||||
void (*cb)(struct connection *);
|
||||
|
||||
*(void **)&(cb) = addr;
|
||||
cb(c);
|
||||
}
|
||||
|
||||
static int
|
||||
native_runtime_onload(void *addr, int action)
|
||||
{
|
||||
int (*cb)(int);
|
||||
|
||||
*(void **)&(cb) = addr;
|
||||
return (cb(action));
|
||||
}
|
||||
|
||||
#if !defined(KORE_NO_HTTP)
|
||||
static int
|
||||
native_runtime_http_request(void *addr, struct http_request *req)
|
||||
{
|
||||
int (*cb)(struct http_request *);
|
||||
|
||||
*(void **)&(cb) = addr;
|
||||
return (cb(req));
|
||||
}
|
||||
|
||||
static int
|
||||
native_runtime_validator(void *addr, struct http_request *req, void *data)
|
||||
{
|
||||
int (*cb)(struct http_request *, void *);
|
||||
|
||||
*(void **)&(cb) = addr;
|
||||
return (cb(req, data));
|
||||
}
|
||||
#endif
|
@ -42,8 +42,8 @@ kore_validator_add(const char *name, u_int8_t type, const char *arg)
|
||||
}
|
||||
break;
|
||||
case KORE_VALIDATOR_TYPE_FUNCTION:
|
||||
*(void **)(&val->func) = kore_module_getsym(arg);
|
||||
if (val->func == NULL) {
|
||||
val->rcall = kore_runtime_getcall(arg);
|
||||
if (val->rcall == NULL) {
|
||||
kore_free(val);
|
||||
kore_log(LOG_NOTICE,
|
||||
"validator %s has undefined callback %s",
|
||||
@ -92,7 +92,7 @@ kore_validator_check(struct http_request *req, struct kore_validator *val,
|
||||
r = KORE_RESULT_ERROR;
|
||||
break;
|
||||
case KORE_VALIDATOR_TYPE_FUNCTION:
|
||||
r = val->func(req, data);
|
||||
r = kore_runtime_validator(val->rcall, req, data);
|
||||
break;
|
||||
default:
|
||||
r = KORE_RESULT_ERROR;
|
||||
@ -113,9 +113,10 @@ kore_validator_reload(void)
|
||||
if (val->type != KORE_VALIDATOR_TYPE_FUNCTION)
|
||||
continue;
|
||||
|
||||
*(void **)&(val->func) = kore_module_getsym(val->arg);
|
||||
if (val->func == NULL)
|
||||
fatal("no function for validator %s found", val->name);
|
||||
kore_free(val->rcall);
|
||||
val->rcall = kore_runtime_getcall(val->arg);
|
||||
if (val->rcall == NULL)
|
||||
fatal("no function for validator %s found", val->arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
24
src/worker.c
24
src/worker.c
@ -40,6 +40,10 @@
|
||||
#include "tasks.h"
|
||||
#endif
|
||||
|
||||
#if defined(KORE_USE_PYTHON)
|
||||
#include "python_api.h"
|
||||
#endif
|
||||
|
||||
#if defined(WORKER_DEBUG)
|
||||
#define worker_debug(fmt, ...) printf(fmt, ##__VA_ARGS__)
|
||||
#else
|
||||
@ -262,11 +266,11 @@ kore_worker_privdrop(void)
|
||||
void
|
||||
kore_worker_entry(struct kore_worker *kw)
|
||||
{
|
||||
char buf[16];
|
||||
int quit, had_lock, r;
|
||||
u_int64_t now, next_lock, netwait;
|
||||
char buf[16];
|
||||
int quit, had_lock, r;
|
||||
u_int64_t now, next_lock, netwait;
|
||||
#if defined(KORE_SINGLE_BINARY)
|
||||
void (*onload)(void);
|
||||
struct kore_runtime_call *rcall;
|
||||
#endif
|
||||
|
||||
worker = kw;
|
||||
@ -332,9 +336,11 @@ kore_worker_entry(struct kore_worker *kw)
|
||||
kore_log(LOG_NOTICE, "worker %d started (cpu#%d)", kw->id, kw->cpu);
|
||||
|
||||
#if defined(KORE_SINGLE_BINARY)
|
||||
*(void **)&(onload) = kore_module_getsym("kore_onload");
|
||||
if (onload != NULL)
|
||||
onload();
|
||||
rcall = kore_runtime_getcall("kore_onload");
|
||||
if (rcall != NULL) {
|
||||
rcall->runtime->execute(rcall->addr, NULL);
|
||||
kore_free(rcall);
|
||||
}
|
||||
#else
|
||||
kore_module_onload();
|
||||
#endif
|
||||
@ -406,6 +412,10 @@ kore_worker_entry(struct kore_worker *kw)
|
||||
#endif
|
||||
net_cleanup();
|
||||
|
||||
#if defined(KORE_USE_PYTHON)
|
||||
kore_python_cleanup();
|
||||
#endif
|
||||
|
||||
kore_debug("worker %d shutting down", kw->id);
|
||||
exit(0);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user