1 #include "uwsgi.h"
2 
3 extern struct uwsgi_server uwsgi;
4 
5 struct http_status_codes {
6         const char      key[3];
7         const char      *message;
8         int             message_size;
9 };
10 
11 /* statistically ordered */
12 struct http_status_codes hsc[] = {
13         {"200", "OK"},
14         {"302", "Found"},
15         {"404", "Not Found"},
16         {"500", "Internal Server Error"},
17         {"301", "Moved Permanently"},
18         {"304", "Not Modified"},
19         {"303", "See Other"},
20         {"403", "Forbidden"},
21         {"307", "Temporary Redirect"},
22         {"401", "Unauthorized"},
23         {"400", "Bad Request"},
24         {"405", "Method Not Allowed"},
25         {"408", "Request Timeout"},
26 
27         {"100", "Continue"},
28         {"101", "Switching Protocols"},
29         {"201", "Created"},
30         {"202", "Accepted"},
31         {"203", "Non-Authoritative Information"},
32         {"204", "No Content"},
33         {"205", "Reset Content"},
34         {"206", "Partial Content"},
35         {"300", "Multiple Choices"},
36         {"305", "Use Proxy"},
37         {"402", "Payment Required"},
38         {"406", "Not Acceptable"},
39         {"407", "Proxy Authentication Required"},
40         {"409", "Conflict"},
41         {"410", "Gone"},
42         {"411", "Length Required"},
43         {"412", "Precondition Failed"},
44         {"413", "Request Entity Too Large"},
45         {"414", "Request-URI Too Long"},
46         {"415", "Unsupported Media Type"},
47         {"416", "Requested Range Not Satisfiable"},
48         {"417", "Expectation Failed"},
49         {"418", "I'm a teapot"},
50         {"422", "Unprocessable Entity"},
51         {"425", "Too Early"},
52         {"426", "Upgrade Required"},
53         {"428", "Precondition Required"},
54         {"429", "Too Many Requests"},
55         {"431", "Request Header Fields Too Large"},
56         {"451", "Unavailable For Legal Reasons"},
57         {"501", "Not Implemented"},
58         {"502", "Bad Gateway"},
59         {"503", "Service Unavailable"},
60         {"504", "Gateway Timeout"},
61         {"505", "HTTP Version Not Supported"},
62         {"509", "Bandwidth Limit Exceeded"},
63         {"511", "Network Authentication Required"},
64         {"", NULL},
65 };
66 
67 
68 
69 
uwsgi_init_default()70 void uwsgi_init_default() {
71 
72 	uwsgi.cpus = 1;
73 	uwsgi.new_argc = -1;
74 
75 	uwsgi.backtrace_depth = 64;
76 	uwsgi.max_apps = 64;
77 
78 	uwsgi.master_queue = -1;
79 
80 	uwsgi.signal_socket = -1;
81 	uwsgi.my_signal_socket = -1;
82 	uwsgi.stats_fd = -1;
83 
84 	uwsgi.stats_pusher_default_freq = 3;
85 
86 	uwsgi.original_log_fd = 2;
87 
88 	uwsgi.emperor_fd_config = -1;
89 	uwsgi.emperor_fd_proxy = -1;
90 	// default emperor scan frequency
91 	uwsgi.emperor_freq = 3;
92 	uwsgi.emperor_throttle = 1000;
93 	uwsgi.emperor_heartbeat = 30;
94 	uwsgi.emperor_curse_tolerance = 30;
95 	// max 3 minutes throttling
96 	uwsgi.emperor_max_throttle = 1000 * 180;
97 	uwsgi.emperor_pid = -1;
98 
99 	uwsgi.subscribe_freq = 10;
100 	uwsgi.subscription_tolerance = 17;
101 
102 	uwsgi.cores = 1;
103 	uwsgi.threads = 1;
104 
105 	// default max number of rpc slot
106 	uwsgi.rpc_max = 64;
107 
108 	uwsgi.offload_threads_events = 64;
109 
110 	uwsgi.default_app = -1;
111 
112 	uwsgi.buffer_size = 4096;
113 	uwsgi.body_read_warning = 8;
114 	uwsgi.numproc = 1;
115 
116 	uwsgi.forkbomb_delay = 2;
117 
118 	uwsgi.async = 1;
119 	uwsgi.listen_queue = 100;
120 
121 	uwsgi.cheaper_overload = 3;
122 
123 	uwsgi.log_master_bufsize = 8192;
124 
125 	uwsgi.worker_reload_mercy = 60;
126 	uwsgi.mule_reload_mercy = 60;
127 
128 	uwsgi.max_vars = MAX_VARS;
129 	uwsgi.vec_size = 4 + 1 + (4 * MAX_VARS);
130 
131 	uwsgi.socket_timeout = 4;
132 	uwsgi.logging_options.enabled = 1;
133 
134 	// a workers hould be running for at least 10 seconds
135 	uwsgi.min_worker_lifetime = 10;
136 
137 	uwsgi.spooler_frequency = 30;
138 
139 	uwsgi.shared->spooler_signal_pipe[0] = -1;
140 	uwsgi.shared->spooler_signal_pipe[1] = -1;
141 
142 	uwsgi.shared->mule_signal_pipe[0] = -1;
143 	uwsgi.shared->mule_signal_pipe[1] = -1;
144 
145 	uwsgi.shared->mule_queue_pipe[0] = -1;
146 	uwsgi.shared->mule_queue_pipe[1] = -1;
147 
148 	uwsgi.shared->worker_log_pipe[0] = -1;
149 	uwsgi.shared->worker_log_pipe[1] = -1;
150 
151 	uwsgi.shared->worker_req_log_pipe[0] = -1;
152 	uwsgi.shared->worker_req_log_pipe[1] = -1;
153 
154 	uwsgi.req_log_fd = 2;
155 
156 #ifdef UWSGI_SSL
157 	// 1 day of tolerance
158 	uwsgi.subscriptions_sign_check_tolerance = 3600 * 24;
159 	uwsgi.ssl_sessions_timeout = 300;
160 	uwsgi.ssl_verify_depth = 1;
161 #endif
162 
163 	uwsgi.alarm_freq = 3;
164 	uwsgi.alarm_msg_size = 8192;
165 
166 	uwsgi.exception_handler_msg_size = 65536;
167 
168 	uwsgi.multicast_ttl = 1;
169 	uwsgi.multicast_loop = 1;
170 
171 	// filling http status codes
172 	struct http_status_codes *http_sc;
173         for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
174                 http_sc->message_size = strlen(http_sc->message);
175         }
176 
177 	uwsgi.empty = "";
178 
179 #ifdef __linux__
180 	uwsgi.cgroup_dir_mode = "0700";
181 #endif
182 
183 	uwsgi.wait_read_hook = uwsgi_simple_wait_read_hook;
184 	uwsgi.wait_write_hook = uwsgi_simple_wait_write_hook;
185 	uwsgi.wait_milliseconds_hook = uwsgi_simple_wait_milliseconds_hook;
186 	uwsgi.wait_read2_hook = uwsgi_simple_wait_read2_hook;
187 
188 	uwsgi_websockets_init();
189 
190 	// 1 MB default limit
191 	uwsgi.chunked_input_limit = 1024*1024;
192 
193 	// clear reforked status
194 	uwsgi.master_is_reforked = 0;
195 
196 	uwsgi.master_fifo_fd = -1;
197 	uwsgi_master_fifo_prepare();
198 
199 	uwsgi.notify_socket_fd = -1;
200 }
201 
uwsgi_setup_reload()202 void uwsgi_setup_reload() {
203 
204 	char env_reload_buf[11];
205 
206 	char *env_reloads = getenv("UWSGI_RELOADS");
207 	if (env_reloads) {
208 		//convert env value to int
209 		uwsgi.reloads = atoi(env_reloads);
210 		uwsgi.reloads++;
211 		//convert reloads to string
212 		int rlen = snprintf(env_reload_buf, 10, "%u", uwsgi.reloads);
213 		if (rlen > 0 && rlen < 10) {
214 			env_reload_buf[rlen] = 0;
215 			if (setenv("UWSGI_RELOADS", env_reload_buf, 1)) {
216 				uwsgi_error("setenv()");
217 			}
218 		}
219 		uwsgi.is_a_reload = 1;
220 	}
221 	else {
222 		if (setenv("UWSGI_RELOADS", "0", 1)) {
223 			uwsgi_error("setenv()");
224 		}
225 	}
226 
227 }
228 
uwsgi_autoload_plugins_by_name(char * argv_zero)229 void uwsgi_autoload_plugins_by_name(char *argv_zero) {
230 
231 	char *plugins_requested = NULL;
232 
233 	char *original_proc_name = getenv("UWSGI_ORIGINAL_PROC_NAME");
234 	if (!original_proc_name) {
235 		// here we use argv[0];
236 		original_proc_name = argv_zero;
237 		setenv("UWSGI_ORIGINAL_PROC_NAME", original_proc_name, 1);
238 	}
239 	char *p = strrchr(original_proc_name, '/');
240 	if (p == NULL)
241 		p = original_proc_name;
242 	p = strstr(p, "uwsgi_");
243 	if (p != NULL) {
244 		char *ctx = NULL;
245 		uwsgi_foreach_token(uwsgi_str(p + 6), "_", plugins_requested, ctx) {
246 			uwsgi_log("[uwsgi] implicit plugin requested %s\n", plugins_requested);
247 			uwsgi_load_plugin(-1, plugins_requested, NULL);
248 		}
249 	}
250 
251 	plugins_requested = getenv("UWSGI_PLUGINS");
252 	if (plugins_requested) {
253 		plugins_requested = uwsgi_concat2(plugins_requested, "");
254 		char *p, *ctx = NULL;
255 		uwsgi_foreach_token(plugins_requested, ",", p, ctx) {
256 			uwsgi_load_plugin(-1, p, NULL);
257 		}
258 	}
259 
260 }
261 
uwsgi_commandline_config()262 void uwsgi_commandline_config() {
263 	int i;
264 
265 	uwsgi.option_index = -1;
266 
267 	int argc = uwsgi.argc;
268 	char **argv = uwsgi.argv;
269 
270 	if (uwsgi.new_argc > -1 && uwsgi.new_argv) {
271 		argc = uwsgi.new_argc;
272 		argv = uwsgi.new_argv;
273 	}
274 
275 	char *optname;
276 	while ((i = getopt_long(argc, argv, uwsgi.short_options, uwsgi.long_options, &uwsgi.option_index)) != -1) {
277 
278 		if (i == '?') {
279 			uwsgi_log("getopt_long() error\n");
280 			exit(1);
281 		}
282 
283 		if (uwsgi.option_index > -1) {
284 			optname = (char *) uwsgi.long_options[uwsgi.option_index].name;
285 		}
286 		else {
287 			optname = uwsgi_get_optname_by_index(i);
288 		}
289 		if (!optname) {
290 			uwsgi_log("unable to parse command line options\n");
291 			exit(1);
292 		}
293 		uwsgi.option_index = -1;
294 		add_exported_option(optname, optarg, 0);
295 	}
296 
297 
298 #ifdef UWSGI_DEBUG
299 	uwsgi_log("optind:%d argc:%d\n", optind, uwsgi.argc);
300 #endif
301 
302 	if (optind < argc) {
303 		for (i = optind; i < argc; i++) {
304 			char *lazy = argv[i];
305 			if (lazy[0] != '[') {
306 				uwsgi_opt_load(NULL, lazy, NULL);
307 				// manage magic mountpoint
308 				int magic = 0;
309 				int j;
310 				for (j = 0; j < uwsgi.gp_cnt; j++) {
311 					if (uwsgi.gp[j]->magic) {
312 						if (uwsgi.gp[j]->magic(NULL, lazy)) {
313 							magic = 1;
314 							break;
315 						}
316 					}
317 				}
318 				if (!magic) {
319 					for (j = 0; j < 256; j++) {
320 						if (uwsgi.p[j]->magic) {
321 							if (uwsgi.p[j]->magic(NULL, lazy)) {
322 								magic = 1;
323 								break;
324 							}
325 						}
326 					}
327 				}
328 			}
329 		}
330 	}
331 
332 }
333 
uwsgi_setup_workers()334 void uwsgi_setup_workers() {
335 	int i, j;
336 	// allocate shared memory for workers + master
337 	uwsgi.workers = (struct uwsgi_worker *) uwsgi_calloc_shared(sizeof(struct uwsgi_worker) * (uwsgi.numproc + 1));
338 
339 	for (i = 0; i <= uwsgi.numproc; i++) {
340 		// allocate memory for apps
341 		uwsgi.workers[i].apps = (struct uwsgi_app *) uwsgi_calloc_shared(sizeof(struct uwsgi_app) * uwsgi.max_apps);
342 
343 		// allocate memory for cores
344 		uwsgi.workers[i].cores = (struct uwsgi_core *) uwsgi_calloc_shared(sizeof(struct uwsgi_core) * uwsgi.cores);
345 
346 		// this is a trick for avoiding too much memory areas
347 		void *ts = uwsgi_calloc_shared(sizeof(void *) * uwsgi.max_apps * uwsgi.cores);
348 		// add 4 bytes for uwsgi header
349 		void *buffers = uwsgi_malloc_shared((uwsgi.buffer_size+4) * uwsgi.cores);
350 		void *hvec = uwsgi_malloc_shared(sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores);
351 		void *post_buf = NULL;
352 		if (uwsgi.post_buffering > 0)
353 			post_buf = uwsgi_malloc_shared(uwsgi.post_buffering_bufsize * uwsgi.cores);
354 
355 
356 		for (j = 0; j < uwsgi.cores; j++) {
357 			// allocate shared memory for thread states (required for some language, like python)
358 			uwsgi.workers[i].cores[j].ts = ts + ((sizeof(void *) * uwsgi.max_apps) * j);
359 			// raw per-request buffer (+4 bytes for uwsgi header)
360 			uwsgi.workers[i].cores[j].buffer = buffers + ((uwsgi.buffer_size+4) * j);
361 			// iovec for uwsgi vars
362 			uwsgi.workers[i].cores[j].hvec = hvec + ((sizeof(struct iovec) * uwsgi.vec_size) * j);
363 			if (post_buf)
364 				uwsgi.workers[i].cores[j].post_buf = post_buf + (uwsgi.post_buffering_bufsize * j);
365 		}
366 
367 		// master does not need to following steps...
368 		if (i == 0)
369 			continue;
370 		uwsgi.workers[i].signal_pipe[0] = -1;
371 		uwsgi.workers[i].signal_pipe[1] = -1;
372 		snprintf(uwsgi.workers[i].name, 0xff, "uWSGI worker %d", i);
373 	}
374 
375 	uint64_t total_memory = (sizeof(struct uwsgi_app) * uwsgi.max_apps) + (sizeof(struct uwsgi_core) * uwsgi.cores) + (sizeof(void *) * uwsgi.max_apps * uwsgi.cores) + (uwsgi.buffer_size * uwsgi.cores) + (sizeof(struct iovec) * uwsgi.vec_size * uwsgi.cores);
376 	if (uwsgi.post_buffering > 0) {
377 		total_memory += (uwsgi.post_buffering_bufsize * uwsgi.cores);
378 	}
379 
380 	total_memory *= (uwsgi.numproc + uwsgi.master_process);
381 	if (uwsgi.numproc > 0)
382 		uwsgi_log("mapped %llu bytes (%llu KB) for %d cores\n", (unsigned long long) total_memory, (unsigned long long) (total_memory / 1024), uwsgi.cores * uwsgi.numproc);
383 
384 	// allocate signal table
385         uwsgi.shared->signal_table = uwsgi_calloc_shared(sizeof(struct uwsgi_signal_entry) * 256 * (uwsgi.numproc + 1));
386 
387 #ifdef UWSGI_ROUTING
388 	uwsgi_fixup_routes(uwsgi.routes);
389 	uwsgi_fixup_routes(uwsgi.error_routes);
390 	uwsgi_fixup_routes(uwsgi.response_routes);
391 	uwsgi_fixup_routes(uwsgi.final_routes);
392 #endif
393 
394 }
395 
uwsgi_daemonize2()396 pid_t uwsgi_daemonize2() {
397 	if (uwsgi.has_emperor) {
398 		logto(uwsgi.daemonize2);
399 	}
400 	else {
401 		if (!uwsgi.is_a_reload) {
402 			uwsgi_log("*** daemonizing uWSGI ***\n");
403 			daemonize(uwsgi.daemonize2);
404 		}
405 		else if (uwsgi.log_reopen) {
406 			logto(uwsgi.daemonize2);
407 		}
408 	}
409 	uwsgi.mypid = getpid();
410 
411 	uwsgi.workers[0].pid = uwsgi.mypid;
412 
413 	if (uwsgi.pidfile && !uwsgi.is_a_reload) {
414 		uwsgi_write_pidfile(uwsgi.pidfile);
415 	}
416 
417 	if (uwsgi.pidfile2 && !uwsgi.is_a_reload) {
418 		uwsgi_write_pidfile(uwsgi.pidfile2);
419 	}
420 
421 	if (uwsgi.log_master) uwsgi_setup_log_master();
422 
423 	return uwsgi.mypid;
424 }
425 
426 // fix/check related options
sanitize_args()427 void sanitize_args() {
428 
429         if (uwsgi.async > 1) {
430                 uwsgi.cores = uwsgi.async;
431         }
432 
433         if (uwsgi.threads > 1) {
434                 uwsgi.has_threads = 1;
435                 uwsgi.cores = uwsgi.threads;
436         }
437 
438         if (uwsgi.harakiri_options.workers > 0) {
439                 if (!uwsgi.post_buffering) {
440                         uwsgi_log(" *** WARNING: you have enabled harakiri without post buffering. Slow upload could be rejected on post-unbuffered webservers *** \n");
441                 }
442         }
443 
444         if (uwsgi.write_errors_exception_only) {
445                 uwsgi.ignore_sigpipe = 1;
446                 uwsgi.ignore_write_errors = 1;
447         }
448 
449         if (uwsgi.cheaper_count == 0) uwsgi.cheaper = 0;
450 
451         if (uwsgi.cheaper_count > 0 && uwsgi.cheaper_count >= uwsgi.numproc) {
452                 uwsgi_log("invalid cheaper value: must be lower than processes\n");
453                 exit(1);
454         }
455 
456         if (uwsgi.cheaper && uwsgi.cheaper_count) {
457 		if (uwsgi.cheaper_initial) {
458                 	if (uwsgi.cheaper_initial < uwsgi.cheaper_count) {
459                         	uwsgi_log("warning: invalid cheaper-initial value (%d), must be equal or higher than cheaper (%d), using %d as initial number of workers\n",
460                                 	uwsgi.cheaper_initial, uwsgi.cheaper_count, uwsgi.cheaper_count);
461                         	uwsgi.cheaper_initial = uwsgi.cheaper_count;
462                 	}
463                 	else if (uwsgi.cheaper_initial > uwsgi.numproc) {
464                         	uwsgi_log("warning: invalid cheaper-initial value (%d), must be lower or equal than worker count (%d), using %d as initial number of workers\n",
465                                 	uwsgi.cheaper_initial, uwsgi.numproc, uwsgi.numproc);
466                         	uwsgi.cheaper_initial = uwsgi.numproc;
467                 	}
468 		}
469 		else {
470                         uwsgi.cheaper_initial = uwsgi.cheaper_count;
471 		}
472         }
473 
474 	if (uwsgi.max_worker_lifetime > 0 && uwsgi.min_worker_lifetime >= uwsgi.max_worker_lifetime) {
475 		uwsgi_log("invalid min-worker-lifetime value (%d), must be lower than max-worker-lifetime (%d)\n",
476 			uwsgi.min_worker_lifetime, uwsgi.max_worker_lifetime);
477 		exit(1);
478 	}
479 
480 	if (uwsgi.cheaper_rss_limit_soft && uwsgi.logging_options.memory_report != 1 && uwsgi.force_get_memusage != 1) {
481 		uwsgi_log("enabling cheaper-rss-limit-soft requires enabling also memory-report\n");
482 		exit(1);
483 	}
484 	if (uwsgi.cheaper_rss_limit_hard && !uwsgi.cheaper_rss_limit_soft) {
485 		uwsgi_log("enabling cheaper-rss-limit-hard requires setting also cheaper-rss-limit-soft\n");
486 		exit(1);
487 	}
488 	if ( uwsgi.cheaper_rss_limit_hard && uwsgi.cheaper_rss_limit_hard <= uwsgi.cheaper_rss_limit_soft) {
489 		uwsgi_log("cheaper-rss-limit-hard value must be higher than cheaper-rss-limit-soft value\n");
490 		exit(1);
491 	}
492 
493 	if (uwsgi.evil_reload_on_rss || uwsgi.evil_reload_on_as) {
494 		if (!uwsgi.mem_collector_freq) uwsgi.mem_collector_freq = 3;
495 	}
496 
497 	/* here we try to choose if thunder lock is a good thing */
498 #ifdef UNBIT
499 	if (uwsgi.numproc > 1 && !uwsgi.map_socket) {
500 		uwsgi.use_thunder_lock = 1;
501 	}
502 #endif
503 }
504 
uwsgi_http_status_msg(char * status,uint16_t * len)505 const char *uwsgi_http_status_msg(char *status, uint16_t *len) {
506 	struct http_status_codes *http_sc;
507 	for (http_sc = hsc; http_sc->message != NULL; http_sc++) {
508                 if (!strncmp(http_sc->key, status, 3)) {
509                         *len = http_sc->message_size;
510 			return http_sc->message;
511                 }
512         }
513 	return NULL;
514 }
515