1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
|
#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,
};
|