Repository URL to install this package:
|
Version:
2.0.17 ▾
|
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
struct uwsgi_symcall {
struct uwsgi_string_list *symcall_function_name;
int (*symcall_function)(struct wsgi_request *);
struct uwsgi_string_list *rpc;
struct uwsgi_string_list *post_fork;
int use_rtld_next;
void *dlsym_handle;
} usym;
struct uwsgi_plugin symcall_plugin;
static struct uwsgi_option uwsgi_symcall_options[] = {
{"symcall", required_argument, 0, "load the specified C symbol as the symcall request handler (supports <mountpoint=func> too)", uwsgi_opt_add_string_list, &usym.symcall_function_name, 0},
#ifdef RTLD_NEXT
{"symcall-use-next", no_argument, 0, "use RTLD_NEXT when searching for symbols", uwsgi_opt_true, &usym.use_rtld_next, 0},
#endif
{"symcall-register-rpc", required_argument, 0, "load the specified C symbol as an RPC function (syntax: name function)", uwsgi_opt_add_string_list, &usym.rpc, 0},
{"symcall-post-fork", required_argument, 0, "call the specified C symbol after each fork()", uwsgi_opt_add_string_list, &usym.post_fork, 0},
{0, 0, 0, 0},
};
static void uwsgi_symcall_init(){
#ifdef RTLD_NEXT
if (usym.use_rtld_next) {
usym.dlsym_handle = RTLD_NEXT;
}
#endif
struct uwsgi_string_list *usl = NULL;
int has_mountpoints = 0;
uwsgi_foreach(usl, usym.symcall_function_name) {
char *func = usl->value, *mountpoint = "";
char *equal = strchr(usl->value, '=');
if (equal) {
*equal = 0;
func = equal+1;
mountpoint = usl->value;
has_mountpoints = 1;
}
usl->custom_ptr = dlsym(usym.dlsym_handle, func);
if (!usl->custom_ptr) {
uwsgi_log("unable to find symbol \"%s\" in process address space\n", func);
exit(1);
}
int id = uwsgi_apps_cnt;
struct uwsgi_app *ua = uwsgi_add_app(id, symcall_plugin.modifier1, mountpoint, strlen(mountpoint), usl->custom_ptr, NULL);
uwsgi_log("symcall app %d (mountpoint: \"%.*s\") mapped to function ptr: %p\n", id, ua->mountpoint_len, ua->mountpoint, usl->custom_ptr);
if (equal) *equal = '=';
}
if (!has_mountpoints && usym.symcall_function_name) {
usym.symcall_function = usym.symcall_function_name->custom_ptr;
}
uwsgi_foreach(usl, usym.rpc) {
char *space = strchr(usl->value, ' ');
if (!space) {
uwsgi_log("invalid symcall RPC syntax, must be: rpcname symbol\n");
exit(1);
}
*space = 0;
void *func = dlsym(usym.dlsym_handle, space+1);
if (!func) {
uwsgi_log("unable to find symbol \"%s\" in process address space\n", space+1);
exit(1);
}
if (uwsgi_register_rpc(usl->value, &symcall_plugin, 0, func)) {
uwsgi_log("unable to register rpc function");
exit(1);
}
*space = ' ';
}
}
static int uwsgi_symcall_request(struct wsgi_request *wsgi_req) {
if (usym.symcall_function) {
return usym.symcall_function(wsgi_req);
}
if (uwsgi_parse_vars(wsgi_req)) return -1;
wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, symcall_plugin.modifier1);
if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) {
if (uwsgi_apps[uwsgi.default_app].modifier1 == symcall_plugin.modifier1) {
wsgi_req->app_id = uwsgi.default_app;
}
}
if (wsgi_req->app_id == -1) {
uwsgi_404(wsgi_req);
return UWSGI_OK;
}
struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id];
if (ua->interpreter) {
int (*func)(struct wsgi_request *) = (int (*)(struct wsgi_request *)) ua->interpreter;
return func(wsgi_req);
}
return UWSGI_OK;
}
static void uwsgi_symcall_after_request(struct wsgi_request *wsgi_req) {
log_request(wsgi_req);
}
static uint64_t uwsgi_symcall_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) {
uint64_t (*casted_func)(uint8_t, char **, uint16_t *, char **) = (uint64_t (*)(uint8_t, char **, uint16_t *, char **)) func;
return casted_func(argc, argv, argvs, buffer);
}
static void uwsgi_symcall_post_fork() {
void (*func)(void);
struct uwsgi_string_list *usl = usym.post_fork;
while(usl) {
func = dlsym(usym.dlsym_handle, usl->value);
if (!func) {
uwsgi_log("unable to find symbol \"%s\" in process address space\n", usl->value);
exit(1);
}
func();
usl = usl->next;
}
}
static int uwsgi_symcall_mule(char *opt) {
if (uwsgi_endswith(opt, "()")) {
char *func_name = uwsgi_concat2n(opt, strlen(opt)-2, "", 0);
void (*func)() = dlsym(usym.dlsym_handle, func_name);
if (!func) {
uwsgi_log("unable to find symbol \"%s\" in process address space\n", func_name);
exit(1);
}
free(func_name);
func();
return 1;
}
return 0;
}
#ifdef UWSGI_ROUTING
static int symcall_route(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
if (!ub) return UWSGI_ROUTE_BREAK;
int (*func)(struct wsgi_request *) = (int (*)(struct wsgi_request *)) dlsym(usym.dlsym_handle, ub->buf);
uwsgi_buffer_destroy(ub);
if (func) {
wsgi_req->async_status = func(wsgi_req);
}
else {
if (ur->custom) return UWSGI_ROUTE_NEXT;
uwsgi_404(wsgi_req);
}
return UWSGI_ROUTE_BREAK;
}
static int uwsgi_router_symcall(struct uwsgi_route *ur, char *args) {
ur->func = symcall_route;
ur->data = args;
ur->data_len = strlen(args);
return 0;
}
static int uwsgi_router_symcall_next(struct uwsgi_route *ur, char *args) {
ur->custom = 1;
return uwsgi_router_symcall(ur, args);
}
#endif
static void uwsgi_symcall_register() {
usym.dlsym_handle = RTLD_DEFAULT;
#ifdef UWSGI_ROUTING
uwsgi_register_router("symcall", uwsgi_router_symcall);
uwsgi_register_router("symcall-next", uwsgi_router_symcall_next);
#endif
}
struct uwsgi_plugin symcall_plugin = {
.name = "symcall",
.modifier1 = 18,
.options = uwsgi_symcall_options,
.init_apps = uwsgi_symcall_init,
.request = uwsgi_symcall_request,
.after_request = uwsgi_symcall_after_request,
.rpc = uwsgi_symcall_rpc,
.post_fork = uwsgi_symcall_post_fork,
.mule = uwsgi_symcall_mule,
.on_load = uwsgi_symcall_register,
};