1 #include <uwsgi.h>
2
3 extern struct uwsgi_server uwsgi;
4
5 struct uwsgi_symcall {
6 struct uwsgi_string_list *symcall_function_name;
7 int (*symcall_function)(struct wsgi_request *);
8 struct uwsgi_string_list *rpc;
9 struct uwsgi_string_list *post_fork;
10 int use_rtld_next;
11 void *dlsym_handle;
12 } usym;
13
14 struct uwsgi_plugin symcall_plugin;
15
16 static struct uwsgi_option uwsgi_symcall_options[] = {
17 {"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},
18 #ifdef RTLD_NEXT
19 {"symcall-use-next", no_argument, 0, "use RTLD_NEXT when searching for symbols", uwsgi_opt_true, &usym.use_rtld_next, 0},
20 #endif
21 {"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},
22 {"symcall-post-fork", required_argument, 0, "call the specified C symbol after each fork()", uwsgi_opt_add_string_list, &usym.post_fork, 0},
23 {0, 0, 0, 0},
24 };
25
uwsgi_symcall_init()26 static void uwsgi_symcall_init(){
27 #ifdef RTLD_NEXT
28 if (usym.use_rtld_next) {
29 usym.dlsym_handle = RTLD_NEXT;
30 }
31 #endif
32 struct uwsgi_string_list *usl = NULL;
33 int has_mountpoints = 0;
34 uwsgi_foreach(usl, usym.symcall_function_name) {
35 char *func = usl->value, *mountpoint = "";
36 char *equal = strchr(usl->value, '=');
37 if (equal) {
38 *equal = 0;
39 func = equal+1;
40 mountpoint = usl->value;
41 has_mountpoints = 1;
42 }
43 usl->custom_ptr = dlsym(usym.dlsym_handle, func);
44 if (!usl->custom_ptr) {
45 uwsgi_log("unable to find symbol \"%s\" in process address space\n", func);
46 exit(1);
47 }
48 int id = uwsgi_apps_cnt;
49 struct uwsgi_app *ua = uwsgi_add_app(id, symcall_plugin.modifier1, mountpoint, strlen(mountpoint), usl->custom_ptr, NULL);
50 uwsgi_log("symcall app %d (mountpoint: \"%.*s\") mapped to function ptr: %p\n", id, ua->mountpoint_len, ua->mountpoint, usl->custom_ptr);
51 if (equal) *equal = '=';
52 }
53
54 if (!has_mountpoints && usym.symcall_function_name) {
55 usym.symcall_function = usym.symcall_function_name->custom_ptr;
56 }
57
58 uwsgi_foreach(usl, usym.rpc) {
59 char *space = strchr(usl->value, ' ');
60 if (!space) {
61 uwsgi_log("invalid symcall RPC syntax, must be: rpcname symbol\n");
62 exit(1);
63 }
64 *space = 0;
65 void *func = dlsym(usym.dlsym_handle, space+1);
66 if (!func) {
67 uwsgi_log("unable to find symbol \"%s\" in process address space\n", space+1);
68 exit(1);
69 }
70 if (uwsgi_register_rpc(usl->value, &symcall_plugin, 0, func)) {
71 uwsgi_log("unable to register rpc function");
72 exit(1);
73 }
74 *space = ' ';
75 }
76 }
77
uwsgi_symcall_request(struct wsgi_request * wsgi_req)78 static int uwsgi_symcall_request(struct wsgi_request *wsgi_req) {
79 if (usym.symcall_function) {
80 return usym.symcall_function(wsgi_req);
81 }
82
83 if (uwsgi_parse_vars(wsgi_req)) return -1;
84
85 wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, symcall_plugin.modifier1);
86 if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) {
87 if (uwsgi_apps[uwsgi.default_app].modifier1 == symcall_plugin.modifier1) {
88 wsgi_req->app_id = uwsgi.default_app;
89 }
90 }
91
92 if (wsgi_req->app_id == -1) {
93 uwsgi_404(wsgi_req);
94 return UWSGI_OK;
95 }
96
97 struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id];
98 if (ua->interpreter) {
99 int (*func)(struct wsgi_request *) = (int (*)(struct wsgi_request *)) ua->interpreter;
100 return func(wsgi_req);
101 }
102 return UWSGI_OK;
103 }
104
105
uwsgi_symcall_after_request(struct wsgi_request * wsgi_req)106 static void uwsgi_symcall_after_request(struct wsgi_request *wsgi_req) {
107 log_request(wsgi_req);
108 }
109
uwsgi_symcall_rpc(void * func,uint8_t argc,char ** argv,uint16_t argvs[],char ** buffer)110 static uint64_t uwsgi_symcall_rpc(void *func, uint8_t argc, char **argv, uint16_t argvs[], char **buffer) {
111 uint64_t (*casted_func)(uint8_t, char **, uint16_t *, char **) = (uint64_t (*)(uint8_t, char **, uint16_t *, char **)) func;
112 return casted_func(argc, argv, argvs, buffer);
113 }
114
uwsgi_symcall_post_fork()115 static void uwsgi_symcall_post_fork() {
116 void (*func)(void);
117 struct uwsgi_string_list *usl = usym.post_fork;
118 while(usl) {
119 func = dlsym(usym.dlsym_handle, usl->value);
120 if (!func) {
121 uwsgi_log("unable to find symbol \"%s\" in process address space\n", usl->value);
122 exit(1);
123 }
124 func();
125 usl = usl->next;
126 }
127 }
128
uwsgi_symcall_mule(char * opt)129 static int uwsgi_symcall_mule(char *opt) {
130 if (uwsgi_endswith(opt, "()")) {
131 char *func_name = uwsgi_concat2n(opt, strlen(opt)-2, "", 0);
132 void (*func)() = dlsym(usym.dlsym_handle, func_name);
133 if (!func) {
134 uwsgi_log("unable to find symbol \"%s\" in process address space\n", func_name);
135 exit(1);
136 }
137 free(func_name);
138 func();
139 return 1;
140 }
141 return 0;
142 }
143
144 #ifdef UWSGI_ROUTING
symcall_route(struct wsgi_request * wsgi_req,struct uwsgi_route * ur)145 static int symcall_route(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) {
146 char **subject = (char **) (((char *)(wsgi_req))+ur->subject);
147 uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len);
148
149 struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len);
150 if (!ub) return UWSGI_ROUTE_BREAK;
151
152 int (*func)(struct wsgi_request *) = (int (*)(struct wsgi_request *)) dlsym(usym.dlsym_handle, ub->buf);
153 uwsgi_buffer_destroy(ub);
154
155 if (func) {
156 wsgi_req->async_status = func(wsgi_req);
157 }
158 else {
159 if (ur->custom) return UWSGI_ROUTE_NEXT;
160 uwsgi_404(wsgi_req);
161 }
162
163 return UWSGI_ROUTE_BREAK;
164 }
165
uwsgi_router_symcall(struct uwsgi_route * ur,char * args)166 static int uwsgi_router_symcall(struct uwsgi_route *ur, char *args) {
167 ur->func = symcall_route;
168 ur->data = args;
169 ur->data_len = strlen(args);
170 return 0;
171 }
172
uwsgi_router_symcall_next(struct uwsgi_route * ur,char * args)173 static int uwsgi_router_symcall_next(struct uwsgi_route *ur, char *args) {
174 ur->custom = 1;
175 return uwsgi_router_symcall(ur, args);
176 }
177 #endif
178
uwsgi_symcall_register()179 static void uwsgi_symcall_register() {
180 usym.dlsym_handle = RTLD_DEFAULT;
181 #ifdef UWSGI_ROUTING
182 uwsgi_register_router("symcall", uwsgi_router_symcall);
183 uwsgi_register_router("symcall-next", uwsgi_router_symcall_next);
184 #endif
185 }
186
187 struct uwsgi_plugin symcall_plugin = {
188
189 .name = "symcall",
190 .modifier1 = 18,
191 .options = uwsgi_symcall_options,
192 .init_apps = uwsgi_symcall_init,
193 .request = uwsgi_symcall_request,
194 .after_request = uwsgi_symcall_after_request,
195 .rpc = uwsgi_symcall_rpc,
196 .post_fork = uwsgi_symcall_post_fork,
197 .mule = uwsgi_symcall_mule,
198 .on_load = uwsgi_symcall_register,
199 };
200
201