File: symcall_plugin.c

package info (click to toggle)
uwsgi 2.0.31-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,564 kB
  • sloc: ansic: 87,066; python: 7,004; cpp: 1,133; java: 708; perl: 678; sh: 585; ruby: 555; makefile: 148; xml: 130; cs: 121; objc: 37; php: 28; erlang: 20; javascript: 11
file content (200 lines) | stat: -rw-r--r-- 6,471 bytes parent folder | download | duplicates (8)
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,
};