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