From 8b8b57769e42c7fdb447fa9553aedb91ed728576 Mon Sep 17 00:00:00 2001 From: Unbit Date: Sat, 3 May 2014 10:17:27 +0200 Subject: [PATCH 01/54] first prototype of a fork server --- core/fork_server.c | 69 ++++++++++++++++++++++++++++++++++++++ core/init.c | 2 ++ core/uwsgi.c | 11 ++++++ plugins/psgi/psgi.h | 2 ++ plugins/psgi/psgi_loader.c | 6 ++++ plugins/psgi/psgi_plugin.c | 10 ++++++ uwsgi.h | 4 +++ uwsgiconfig.py | 2 +- 8 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 core/fork_server.c diff --git a/core/fork_server.c b/core/fork_server.c new file mode 100644 index 00000000..4dd4137f --- /dev/null +++ b/core/fork_server.c @@ -0,0 +1,69 @@ +#include + +extern struct uwsgi_server uwsgi; + +void uwsgi_fork_server(char *socket) { + int fd = bind_to_unix(socket, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); + if (fd < 0) exit(1); + + if (uwsgi_socket_passcred(fd)) exit(1); + + for(;;) { + struct sockaddr_un client_src; + socklen_t client_src_len = 0; + int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len); + if (client_fd < 0) { + uwsgi_error("uwsgi_fork_server()/accept()"); + continue; + } + char buf[4096]; + pid_t ppid = -1; + uid_t uid = -1; + gid_t gid = -1; + ssize_t len = uwsgi_recv_cred2(client_fd, buf, 4096, &ppid, &uid, &gid); + uwsgi_log("RET = %d %d %d %d\n", len, ppid, uid, gid); + + pid_t pid = fork(); + if (pid < 0) { + uwsgi_error("uwsgi_fork_server()/fork()"); + goto end; + } + else if (pid > 0) { + goto end; + } + else { + // reparent the process +#ifdef __linux__ + if (prctl(PR_SET_CHILD_SUBREAPER, ppid, 0, 0, 0)) { + uwsgi_error("uwsgi_fork_server()/fork()"); + exit(1); + } +#endif + // now fork again and kill + pid_t new_pid = fork(); + if (new_pid < 0) { + uwsgi_error("uwsgi_fork_server()/fork()"); + exit(1); + } + else if (new_pid > 0) { + exit(0); + } + else { + uwsgi_log("double fork() and reparenting successfull (new pid: %d)\n", getpid()); + uwsgi.argc = 3; + uwsgi.argv = uwsgi_malloc(sizeof(char *) * (uwsgi.argc+1)); + uwsgi.argv[0] = uwsgi.binary_path; + uwsgi.argv[1] = uwsgi_str("--socket"); + uwsgi.argv[2] = uwsgi_str(":1717"); + uwsgi.argv[3] = NULL; + // this is the only step required to have a consistent environment + uwsgi.fork_socket = NULL; + return; + } + } + +end: + close(client_fd); + + } +} diff --git a/core/init.c b/core/init.c index c4ce7147..587a7666 100644 --- a/core/init.c +++ b/core/init.c @@ -252,6 +252,8 @@ void uwsgi_commandline_config() { int i; uwsgi.option_index = -1; + // required in case we want to call getopt_long from the beginning + optind = 0; char *optname; while ((i = getopt_long(uwsgi.argc, uwsgi.argv, uwsgi.short_options, uwsgi.long_options, &uwsgi.option_index)) != -1) { diff --git a/core/uwsgi.c b/core/uwsgi.c index b1145ebb..c660c3dd 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -356,6 +356,7 @@ static struct uwsgi_option uwsgi_base_options[] = { {"setns-skip", required_argument, 0, "skip the specified entry when sending setns file descriptors", uwsgi_opt_add_string_list, &uwsgi.setns_socket_skip, 0}, {"setns", required_argument, 0, "join a namespace created by an external uWSGI instance", uwsgi_opt_set_str, &uwsgi.setns, 0}, {"setns-preopen", no_argument, 0, "open /proc/self/ns as soon as possible and cache fds", uwsgi_opt_true, &uwsgi.setns_preopen, 0}, + {"fork-socket", required_argument, 0, "suspend the execution after early initialization and fork() at every unix socket connection", uwsgi_opt_set_str, &uwsgi.fork_socket, 0}, #endif {"jailed", no_argument, 0, "mark the instance as jailed (force the execution of post_jail hooks)", uwsgi_opt_true, &uwsgi.jailed, 0}, #if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) @@ -2131,6 +2132,8 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) { struct group *gr = getgrgid(getgid()); uwsgi.magic_table['G'] = gr ? gr->gr_name : uwsgi.magic_table['g']; +configure: + // you can embed a ini file in the uWSGi binary with default options #ifdef UWSGI_EMBED_CONFIG uwsgi_ini_config("", uwsgi.magic_table); @@ -2155,6 +2158,14 @@ void uwsgi_setup(int argc, char *argv[], char *envp[]) { // ok, the options dictionary is available, lets manage it uwsgi_configure(); + // stop the execution until a connection arrives on the fork socket + if (uwsgi.fork_socket) { + uwsgi_log_verbose("waiting for fork-socket connections...\n"); + uwsgi_fork_server(uwsgi.fork_socket); + // if we are here a new process has been spawned + goto configure; + } + // fixup cwd if (uwsgi.force_cwd) uwsgi.cwd = uwsgi.force_cwd; diff --git a/plugins/psgi/psgi.h b/plugins/psgi/psgi.h index 92e6b588..e7c386b9 100644 --- a/plugins/psgi/psgi.h +++ b/plugins/psgi/psgi.h @@ -67,6 +67,8 @@ struct uwsgi_perl { CV *spooler; int no_plack; + + void *early_psgi_callable; }; void init_perl_embedded_module(void); diff --git a/plugins/psgi/psgi_loader.c b/plugins/psgi/psgi_loader.c index c798408e..5e0255df 100644 --- a/plugins/psgi/psgi_loader.c +++ b/plugins/psgi/psgi_loader.c @@ -453,6 +453,12 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe PERL_SET_CONTEXT(interpreters[0]); } + // is it an early loading ? + if (!uwsgi.workers) { + uperl.early_psgi_callable = callables[0]; + return 0; + } + if (uwsgi_apps_cnt >= uwsgi.max_apps) { uwsgi_log("ERROR: you cannot load more than %d apps in a worker\n", uwsgi.max_apps); goto clear; diff --git a/plugins/psgi/psgi_plugin.c b/plugins/psgi/psgi_plugin.c index a764cb2c..a177d709 100644 --- a/plugins/psgi/psgi_plugin.c +++ b/plugins/psgi/psgi_plugin.c @@ -26,6 +26,12 @@ static void uwsgi_opt_plshell(char *opt, char *value, void *foobar) { } } +int uwsgi_perl_init(void); +static void uwsgi_opt_early_psgi(char *opt, char *value, void *foobar) { + uwsgi_perl_init(); + init_psgi_app(NULL, value, strlen(value), uperl.main); +} + struct uwsgi_option uwsgi_perl_options[] = { {"psgi", required_argument, 0, "load a psgi app", uwsgi_opt_set_str, &uperl.psgi, 0}, @@ -46,6 +52,7 @@ struct uwsgi_option uwsgi_perl_options[] = { {"plshell-oneshot", no_argument, 0, "run a perl interactive shell (one shot)", uwsgi_opt_plshell, NULL, 0}, {"perl-no-plack", no_argument, 0, "force the use of do instead of Plack::Util::load_psgi", uwsgi_opt_true, &uperl.no_plack, 0}, + {"early-psgi", required_argument, 0, "load a psgi app soon after perl initialization", uwsgi_opt_early_psgi, NULL, UWSGI_OPT_IMMEDIATE}, {0, 0, 0, 0, 0, 0, 0}, }; @@ -437,6 +444,9 @@ int uwsgi_perl_init(){ int argc; int i; + // the perl interpreter could be already initialized + if (uperl.main) return 0; + uperl.embedding[0] = ""; uperl.embedding[1] = "-e"; uperl.embedding[2] = "0"; diff --git a/uwsgi.h b/uwsgi.h index 0dc855b6..6924b02d 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -2709,6 +2709,8 @@ struct uwsgi_server { int mule_reload_mercy; int alarm_cheap; + + char *fork_socket; }; struct uwsgi_rpc { @@ -4761,6 +4763,8 @@ mode_t uwsgi_mode_t(char *, int *); int uwsgi_notify_socket_manage(int); int uwsgi_notify_msg(char *, char *, size_t); +void uwsgi_fork_server(char *); + #ifdef __cplusplus } #endif diff --git a/uwsgiconfig.py b/uwsgiconfig.py index 78a464d1..b6796db1 100644 --- a/uwsgiconfig.py +++ b/uwsgiconfig.py @@ -602,7 +602,7 @@ class uConf(object): 'core/setup_utils', 'core/clock', 'core/init', 'core/buffer', 'core/reader', 'core/writer', 'core/alarm', 'core/cron', 'core/hooks', 'core/plugins', 'core/lock', 'core/cache', 'core/daemons', 'core/errors', 'core/hash', 'core/master_events', 'core/chunked', 'core/queue', 'core/event', 'core/signal', 'core/strings', 'core/progress', 'core/timebomb', 'core/ini', 'core/fsmon', 'core/mount', - 'core/metrics', 'core/plugins_builder', 'core/sharedarea', + 'core/metrics', 'core/plugins_builder', 'core/sharedarea', 'core/fork_server', 'core/rpc', 'core/gateway', 'core/loop', 'core/cookie', 'core/querystring', 'core/rb_timers', 'core/transformations', 'core/uwsgi'] # add protocols self.gcc_list.append('proto/base') From fa269b88384d779e36a4b20f2c79df6717f0f517 Mon Sep 17 00:00:00 2001 From: Unbit Date: Sat, 3 May 2014 11:44:24 +0200 Subject: [PATCH 02/54] start investigating argc/argv implications --- core/fork_server.c | 23 ++++++++--- core/init.c | 12 +++++- core/master_utils.c | 2 + core/utils.c | 2 + plugins/psgi/psgi.h | 5 ++- plugins/psgi/psgi_loader.c | 81 +++++++++++++++++++++----------------- plugins/psgi/psgi_plugin.c | 6 ++- uwsgi.h | 2 + 8 files changed, 87 insertions(+), 46 deletions(-) diff --git a/core/fork_server.c b/core/fork_server.c index 4dd4137f..2ba5b908 100644 --- a/core/fork_server.c +++ b/core/fork_server.c @@ -29,6 +29,7 @@ void uwsgi_fork_server(char *socket) { goto end; } else if (pid > 0) { + waitpid(pid, NULL, 0); goto end; } else { @@ -50,12 +51,22 @@ void uwsgi_fork_server(char *socket) { } else { uwsgi_log("double fork() and reparenting successfull (new pid: %d)\n", getpid()); - uwsgi.argc = 3; - uwsgi.argv = uwsgi_malloc(sizeof(char *) * (uwsgi.argc+1)); - uwsgi.argv[0] = uwsgi.binary_path; - uwsgi.argv[1] = uwsgi_str("--socket"); - uwsgi.argv[2] = uwsgi_str(":1717"); - uwsgi.argv[3] = NULL; + uwsgi.new_argc = 6; + // we do not free old uwsgi.argv as it could contains still used pointers + uwsgi_log("%s\n", uwsgi.binary_path); + uwsgi.new_argv = uwsgi_malloc(sizeof(char *) * (uwsgi.argc+1)); + uwsgi.new_argv[0] = uwsgi.binary_path; + uwsgi.new_argv[1] = uwsgi_str("--http-socket"); + uwsgi.new_argv[2] = uwsgi_str(":1717"); + uwsgi.new_argv[3] = uwsgi_str("--master"); + uwsgi.new_argv[4] = uwsgi_str("--processes"); + uwsgi.new_argv[5] = uwsgi_str("8"); + uwsgi.new_argv[6] = NULL; +// on linux and sun we need to fix orig_argv +#if defined(__linux__) || defined(__sun__) +#endif + + // this is the only step required to have a consistent environment uwsgi.fork_socket = NULL; return; diff --git a/core/init.c b/core/init.c index 587a7666..fa5eecc0 100644 --- a/core/init.c +++ b/core/init.c @@ -61,6 +61,7 @@ struct http_status_codes hsc[] = { void uwsgi_init_default() { uwsgi.cpus = 1; + uwsgi.new_argc = -1; uwsgi.backtrace_depth = 64; uwsgi.max_apps = 64; @@ -255,8 +256,17 @@ void uwsgi_commandline_config() { // required in case we want to call getopt_long from the beginning optind = 0; + int argc = uwsgi.argc; + char **argv = uwsgi.argv; + + if (uwsgi.new_argc > -1 && uwsgi.new_argv) { + argc = uwsgi.new_argc; + argv = uwsgi.new_argv; + } + + char *optname; - while ((i = getopt_long(uwsgi.argc, uwsgi.argv, uwsgi.short_options, uwsgi.long_options, &uwsgi.option_index)) != -1) { + while ((i = getopt_long(argc, argv, uwsgi.short_options, uwsgi.long_options, &uwsgi.option_index)) != -1) { if (i == '?') { uwsgi_log("getopt_long() error\n"); diff --git a/core/master_utils.c b/core/master_utils.c index f09724b4..bcbbf829 100644 --- a/core/master_utils.c +++ b/core/master_utils.c @@ -388,6 +388,8 @@ void uwsgi_reload(char **argv) { int i; int waitpid_status; + if (uwsgi.new_argv) argv = uwsgi.new_argv; + if (!uwsgi.master_is_reforked) { // call a series of waitpid to ensure all processes (gateways, mules and daemons) are dead diff --git a/core/utils.c b/core/utils.c index cce2e576..ce2a0894 100644 --- a/core/utils.c +++ b/core/utils.c @@ -3101,6 +3101,8 @@ pid_t uwsgi_fork(char *name) { #if defined(__linux__) || defined(__sun__) int i; for (i = 0; i < uwsgi.argc; i++) { + // stop fixing original argv if the new one is bigger + if (!uwsgi.orig_argv[i]) break; strcpy(uwsgi.orig_argv[i], uwsgi.argv[i]); } #endif diff --git a/plugins/psgi/psgi.h b/plugins/psgi/psgi.h index e7c386b9..765534c1 100644 --- a/plugins/psgi/psgi.h +++ b/plugins/psgi/psgi.h @@ -68,7 +68,8 @@ struct uwsgi_perl { int no_plack; - void *early_psgi_callable; + SV **early_psgi_callable; + char *early_psgi_app_name; }; void init_perl_embedded_module(void); @@ -89,3 +90,5 @@ void uwsgi_perl_exec(char *); void uwsgi_perl_check_auto_reload(void); void uwsgi_psgi_preinit_apps(void); + +int uwsgi_perl_add_app(struct wsgi_request *, char *, PerlInterpreter **, SV **, time_t); diff --git a/plugins/psgi/psgi_loader.c b/plugins/psgi/psgi_loader.c index 5e0255df..5d487b55 100644 --- a/plugins/psgi/psgi_loader.c +++ b/plugins/psgi/psgi_loader.c @@ -455,7 +455,8 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe // is it an early loading ? if (!uwsgi.workers) { - uperl.early_psgi_callable = callables[0]; + uperl.early_psgi_app_name = app_name; + uperl.early_psgi_callable = callables; return 0; } @@ -464,41 +465,7 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe goto clear; } - int id = uwsgi_apps_cnt; - struct uwsgi_app *wi = NULL; - - if (wsgi_req) { - // we need a copy of app_id - wi = uwsgi_add_app(id, psgi_plugin.modifier1, uwsgi_concat2n(wsgi_req->appid, wsgi_req->appid_len, "", 0), wsgi_req->appid_len, interpreters, callables); - } - else { - wi = uwsgi_add_app(id, psgi_plugin.modifier1, "", 0, interpreters, callables); - } - - wi->started_at = now; - wi->startup_time = uwsgi_now() - now; - - uwsgi_log("PSGI app %d (%s) loaded in %d seconds at %p (interpreter %p)\n", id, app_name, (int) wi->startup_time, callables[0], interpreters[0]); - free(app_name); - - // copy global data to app-specific areas - wi->stream = uperl.tmp_streaming_stash; - wi->input = uperl.tmp_input_stash; - wi->error = uperl.tmp_error_stash; - wi->responder0 = uperl.tmp_stream_responder; - wi->responder1 = uperl.tmp_psgix_logger; - - uwsgi_emulate_cow_for_apps(id); - - - // restore context if required - if (interpreters != uperl.main) { - PERL_SET_CONTEXT(uperl.main[0]); - } - - uperl.loaded = 1; - - return id; + return uwsgi_perl_add_app(wsgi_req, app_name, interpreters, callables, now); clear: if (interpreters != uperl.main) { @@ -515,6 +482,44 @@ clear2: return -1; } +int uwsgi_perl_add_app(struct wsgi_request *wsgi_req, char *app_name, PerlInterpreter **interpreters, SV **callables, time_t now) { + int id = uwsgi_apps_cnt; + struct uwsgi_app *wi = NULL; + + if (wsgi_req) { + // we need a copy of app_id + wi = uwsgi_add_app(id, psgi_plugin.modifier1, uwsgi_concat2n(wsgi_req->appid, wsgi_req->appid_len, "", 0), wsgi_req->appid_len, interpreters, callables); + } + else { + wi = uwsgi_add_app(id, psgi_plugin.modifier1, "", 0, interpreters, callables); + } + + wi->started_at = now; + wi->startup_time = uwsgi_now() - now; + + uwsgi_log("PSGI app %d (%s) loaded in %d seconds at %p (interpreter %p)\n", id, app_name, (int) wi->startup_time, callables[0], interpreters[0]); + free(app_name); + + // copy global data to app-specific areas + wi->stream = uperl.tmp_streaming_stash; + wi->input = uperl.tmp_input_stash; + wi->error = uperl.tmp_error_stash; + wi->responder0 = uperl.tmp_stream_responder; + wi->responder1 = uperl.tmp_psgix_logger; + + uwsgi_emulate_cow_for_apps(id); + + + // restore context if required + if (interpreters != uperl.main) { + PERL_SET_CONTEXT(uperl.main[0]); + } + + uperl.loaded = 1; + + return id; +} + void uwsgi_psgi_preinit_apps() { if (uperl.exec) { PERL_SET_CONTEXT(uperl.main[0]); @@ -530,6 +535,10 @@ void uwsgi_psgi_preinit_apps() { void uwsgi_psgi_app() { + if (uperl.early_psgi_callable) { + uwsgi_perl_add_app(NULL, uperl.early_psgi_app_name, uperl.main, uperl.early_psgi_callable, uwsgi_now()); + } + if (uperl.psgi) { //load app in the main interpreter list init_psgi_app(NULL, uperl.psgi, strlen(uperl.psgi), uperl.main); diff --git a/plugins/psgi/psgi_plugin.c b/plugins/psgi/psgi_plugin.c index a177d709..a9ab9dee 100644 --- a/plugins/psgi/psgi_plugin.c +++ b/plugins/psgi/psgi_plugin.c @@ -444,8 +444,9 @@ int uwsgi_perl_init(){ int argc; int i; - // the perl interpreter could be already initialized - if (uperl.main) return 0; + if (uperl.main) { + goto already_initialized; + } uperl.embedding[0] = ""; uperl.embedding[1] = "-e"; @@ -487,6 +488,7 @@ int uwsgi_perl_init(){ PERL_SET_CONTEXT(uperl.main[0]); +already_initialized: #ifdef PERL_VERSION_STRING uwsgi_log_initial("initialized Perl %s main interpreter at %p\n", PERL_VERSION_STRING, uperl.main[0]); #else diff --git a/uwsgi.h b/uwsgi.h index 6924b02d..a6ec0740 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -2711,6 +2711,8 @@ struct uwsgi_server { int alarm_cheap; char *fork_socket; + int new_argc; + char **new_argv; }; struct uwsgi_rpc { From be2dea3c51c0622f50bb41a0e660e27afbb791c0 Mon Sep 17 00:00:00 2001 From: Unbit Date: Sat, 3 May 2014 12:53:04 +0200 Subject: [PATCH 03/54] preparing for fork server connection --- core/emperor.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++--- core/uwsgi.c | 1 + uwsgi.h | 2 ++ 3 files changed, 84 insertions(+), 5 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 9c7ac340..73f01cec 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -929,6 +929,68 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *); +/* + there are max 3 file descriptors we need to pass to the fork server: + + n_ui->pipe[1] + n_ui->pipe_config[1] + n_ui->on_demand_fd[1] + +*/ +static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance *n_ui) { + int fd = uwsgi_connect(socket, uwsgi.socket_timeout, 0); + + int num_fds = 1; + if (n_ui->use_config) num_fds ++; + if (n_ui->on_demand_fd > -1) num_fds++; + + struct msghdr ep_msg; + void *ep_msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * num_fds)); + struct iovec ep_iov[2]; + struct cmsghdr *cmsg; + + // build the parameters (passed as a uwsgi array) + + ep_iov[0].iov_base = "uwsgi-emperor"; + ep_iov[0].iov_len = 13; + ep_iov[1].iov_base = &num_fds; + ep_iov[1].iov_len = sizeof(int); + + ep_msg.msg_name = NULL; + ep_msg.msg_namelen = 0; + + ep_msg.msg_iov = ep_iov; + ep_msg.msg_iovlen = 2; + + ep_msg.msg_flags = 0; + ep_msg.msg_control = ep_msg_control; + ep_msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds); + + cmsg = CMSG_FIRSTHDR(&ep_msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + unsigned char *ep_fd_ptr = CMSG_DATA(cmsg); + + memcpy(ep_fd_ptr, &uwsgi.emperor_fd, sizeof(int)); + if (num_fds > 1) { + memcpy(ep_fd_ptr + sizeof(int), &uwsgi.emperor_fd_config, sizeof(int)); + } + + if (sendmsg(fd, &ep_msg, 0) < 0) { + uwsgi_error("emperor_connect_to_fork_server()/sendmsg()"); + } + + free(ep_msg_control); + + // now wait for the response (the pid number) + + close(fd); + + return -1; +} + int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { pid_t pid; @@ -956,17 +1018,20 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { // TODO pre-start hook // a new uWSGI instance will start + if (uwsgi.emperor_use_fork_server) { + // pid can only be > 0 or -1 + pid = emperor_connect_to_fork_server(uwsgi.emperor_use_fork_server, n_ui); + } #if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && !defined(__ia64__) - if (uwsgi.emperor_clone) { + else if (uwsgi.emperor_clone) { char stack[PTHREAD_STACK_MIN]; pid = clone((int (*)(void *))uwsgi_emperor_spawn_vassal, stack + PTHREAD_STACK_MIN, SIGCHLD | uwsgi.emperor_clone, (void *) n_ui); } +#endif else { -#endif - pid = fork(); -#if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && !defined(__ia64__) + pid = fork(); } -#endif + if (pid < 0) { uwsgi_error("uwsgi_emperor_spawn_vassal()/fork()") } @@ -1854,6 +1919,10 @@ recheck: uwsgi_error("waitpid()"); } } + + if (diedpid > 0) { + uwsgi_log("DIEDPID = %d\n", diedpid); + } ui_current = ui; while (ui_current->ui_next) { ui_current = ui_current->ui_next; @@ -2133,6 +2202,13 @@ end: void uwsgi_emperor_start() { +#ifdef __linux__ + if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)) { + uwsgi_error("uwsgi_fork_server()/fork()"); + exit(1); + } +#endif + if (!uwsgi.sockets && !ushared->gateways_cnt && !uwsgi.master_process) { if (uwsgi.emperor_procname) { uwsgi_set_processname(uwsgi.emperor_procname); diff --git a/core/uwsgi.c b/core/uwsgi.c index c660c3dd..e7866609 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -1952,6 +1952,7 @@ static char *uwsgi_at_file_read(char *filename) { } void uwsgi_setup(int argc, char *argv[], char *envp[]) { + #ifdef UWSGI_AS_SHARED_LIBRARY #ifdef __APPLE__ char ***envPtr = _NSGetEnviron(); diff --git a/uwsgi.h b/uwsgi.h index a6ec0740..ec2c1047 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -2710,9 +2710,11 @@ struct uwsgi_server { int mule_reload_mercy; int alarm_cheap; + // uWSGI 2.0.5 char *fork_socket; int new_argc; char **new_argv; + char *emperor_use_fork_server; }; struct uwsgi_rpc { From 9d98b3b4ef91457b63732ad065a128f10255616e Mon Sep 17 00:00:00 2001 From: Unbit Date: Mon, 5 May 2014 15:58:36 +0200 Subject: [PATCH 04/54] better to mark it as 2.1, we can merge to master later --- core/uwsgi.c | 1 + plugins/psgi/psgi_plugin.c | 1 + uwsgiconfig.py | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/core/uwsgi.c b/core/uwsgi.c index 14ce1e28..ffc28442 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -358,6 +358,7 @@ static struct uwsgi_option uwsgi_base_options[] = { {"setns", required_argument, 0, "join a namespace created by an external uWSGI instance", uwsgi_opt_set_str, &uwsgi.setns, 0}, {"setns-preopen", no_argument, 0, "open /proc/self/ns as soon as possible and cache fds", uwsgi_opt_true, &uwsgi.setns_preopen, 0}, {"fork-socket", required_argument, 0, "suspend the execution after early initialization and fork() at every unix socket connection", uwsgi_opt_set_str, &uwsgi.fork_socket, 0}, + {"fork-server", required_argument, 0, "suspend the execution after early initialization and fork() at every unix socket connection", uwsgi_opt_set_str, &uwsgi.fork_socket, 0}, #endif {"jailed", no_argument, 0, "mark the instance as jailed (force the execution of post_jail hooks)", uwsgi_opt_true, &uwsgi.jailed, 0}, #if defined(__FreeBSD__) || defined(__GNU_kFreeBSD__) diff --git a/plugins/psgi/psgi_plugin.c b/plugins/psgi/psgi_plugin.c index a9ab9dee..10cb902b 100644 --- a/plugins/psgi/psgi_plugin.c +++ b/plugins/psgi/psgi_plugin.c @@ -30,6 +30,7 @@ int uwsgi_perl_init(void); static void uwsgi_opt_early_psgi(char *opt, char *value, void *foobar) { uwsgi_perl_init(); init_psgi_app(NULL, value, strlen(value), uperl.main); + if (!uperl.early_psgi_callable) exit(1); } struct uwsgi_option uwsgi_perl_options[] = { diff --git a/uwsgiconfig.py b/uwsgiconfig.py index 57d58e54..f0792d44 100644 --- a/uwsgiconfig.py +++ b/uwsgiconfig.py @@ -1,6 +1,6 @@ # uWSGI build system -uwsgi_version = '2.0.5' +uwsgi_version = '2.1' import os import re From fe82772c377e1c0bdb1ce724f8bbe8ceb6294ee1 Mon Sep 17 00:00:00 2001 From: Unbit Date: Mon, 5 May 2014 16:30:13 +0200 Subject: [PATCH 05/54] add some comment to the fork server system --- core/fork_server.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/fork_server.c b/core/fork_server.c index 2ba5b908..c6547ead 100644 --- a/core/fork_server.c +++ b/core/fork_server.c @@ -2,6 +2,18 @@ extern struct uwsgi_server uwsgi; +/* + +on connection retrieve the uid,gid and pid of the connecting process, in addition to up to 3 +file descriptors (emperor pipe, emperor pipe_config, on_demand socket dup()'ed to 0) + +if authorized, double fork, get the pid of the second child and exit() +its parent (this will force the Emperor to became its subreaper). + +from now on, we can consider the new child as a full-featured vassal + +*/ + void uwsgi_fork_server(char *socket) { int fd = bind_to_unix(socket, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); if (fd < 0) exit(1); From f2bd61991f8267e8f3e4bbd68dab17163955943a Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 6 May 2014 07:51:14 +0200 Subject: [PATCH 06/54] try with a frequency of 1 seconds for vassals fast restart --- core/emperor.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 8bb93516..ff18dbbb 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -1938,8 +1938,8 @@ recheck: // UNSAFE emperor_add(ui_current->scanner, ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len, ui_current->uid, ui_current->gid, ui_current->socket_name); emperor_del(ui_current); - // temporarily set frequency to 0, so we can eventually fast-restart the instance - freq = 0; + // temporarily set frequency to 1, so we can eventually fast-restart the instance + freq = 1; } break; } @@ -1949,8 +1949,8 @@ recheck: free(ui_current->config); // SAFE emperor_del(ui_current); - // temporarily set frequency to 0, so we can eventually fast-restart the instance - freq = 0; + // temporarily set frequency to 1, so we can eventually fast-restart the instance + freq = 1; break; } // back to on_demand mode ... @@ -1970,8 +1970,8 @@ recheck: else if (ui_current->cursed_at > 0) { if (ui_current->pid == -1) { emperor_del(ui_current); - // temporarily set frequency to 0, so we can eventually fast-restart the instance - freq = 0; + // temporarily set frequency to 1, so we can eventually fast-restart the instance + freq = 1; break; } else if (now - ui_current->cursed_at >= uwsgi.emperor_curse_tolerance) { From 8b8e3dbd89508cc741e94194bc4076b81b994012 Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 6 May 2014 12:17:51 +0200 Subject: [PATCH 07/54] fork server (step1) --- core/emperor.c | 273 ++++++++++++++++++++++----------------------- core/fork_server.c | 31 +++-- core/io.c | 63 +++++++++++ 3 files changed, 214 insertions(+), 153 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index ff18dbbb..dbd47d67 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -2,10 +2,9 @@ The uWSGI Emperor -a supervisor for multiple uWSGI instances - */ -#include "uwsgi.h" + +#include extern struct uwsgi_server uwsgi; @@ -39,6 +38,111 @@ struct uwsgi_emperor_blacklist_item { struct uwsgi_emperor_blacklist_item *emperor_blacklist; +// this generates the argv for the new vassal +static char **vassal_new_argv(struct uwsgi_instance *n_ui, int *slot_to_free) { + + int counter = 4; + struct uwsgi_string_list *uct; + uwsgi_foreach(uct, uwsgi.vassals_templates_before) counter += 2; + uwsgi_foreach(uct, uwsgi.vassals_includes_before) counter += 2; + uwsgi_foreach(uct, uwsgi.vassals_set) counter += 2; + uwsgi_foreach(uct, uwsgi.vassals_templates) counter += 2; + uwsgi_foreach(uct, uwsgi.vassals_includes) counter += 2; + + char **vassal_argv = uwsgi_malloc(sizeof(char *) * counter); + // set args + vassal_argv[0] = uwsgi.emperor_wrapper ? uwsgi.emperor_wrapper: uwsgi.binary_path; + + // reset counter + counter = 1; + + uwsgi_foreach(uct, uwsgi.vassals_templates_before) { + vassal_argv[counter] = "--inherit"; + vassal_argv[counter + 1] = uct->value; + counter += 2; + } + + uwsgi_foreach (uct, uwsgi.vassals_includes_before) { + vassal_argv[counter] = "--include"; + vassal_argv[counter + 1] = uct->value; + counter += 2; + } + + uwsgi_foreach (uct, uwsgi.vassals_set) { + vassal_argv[counter] = "--set"; + vassal_argv[counter + 1] = uct->value; + counter += 2; + } + + char *colon = NULL; + if (uwsgi.emperor_broodlord) { + colon = strchr(n_ui->name, ':'); + if (colon) { + colon[0] = 0; + } + } + // initialize to a default value + vassal_argv[counter] = "--inherit"; + + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".xml")) + vassal_argv[counter] = "--xml"; + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".ini")) + vassal_argv[counter] = "--ini"; + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".yml")) + vassal_argv[counter] = "--yaml"; + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".yaml")) + vassal_argv[counter] = "--yaml"; + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 3), ".js")) + vassal_argv[counter] = "--json"; + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".json")) + vassal_argv[counter] = "--json"; + struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension; + while(usl) { + if (uwsgi_endswith(n_ui->name, usl->value)) { + vassal_argv[counter] = "--config"; + break; + } + usl = usl->next; + } + if (colon) colon[0] = ':'; + + // start config filename... + counter++; + + vassal_argv[counter] = n_ui->name; + if (uwsgi.emperor_magic_exec) { + if (!access(n_ui->name, R_OK | X_OK)) { + vassal_argv[counter] = uwsgi_concat2("exec://", n_ui->name); + if (*slot_to_free) *slot_to_free = counter; + } + + } + else if (n_ui->use_config) { + vassal_argv[counter] = uwsgi_concat2("emperor://", n_ui->name); + if (*slot_to_free) *slot_to_free = counter; + } + + // start templates,includes,inherit... + counter++; + + uwsgi_foreach(uct, uwsgi.vassals_templates) { + vassal_argv[counter] = "--inherit"; + vassal_argv[counter + 1] = uct->value; + counter += 2; + } + + uwsgi_foreach (uct, uwsgi.vassals_includes) { + vassal_argv[counter] = "--include"; + vassal_argv[counter + 1] = uct->value; + counter += 2; + } + + vassal_argv[counter] = NULL; + + return vassal_argv; +} + + /* this should be placed in core/socket.c but we realized it was needed only after 2.0 so we cannot change uwsgi.h @@ -939,55 +1043,36 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *); */ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance *n_ui) { int fd = uwsgi_connect(socket, uwsgi.socket_timeout, 0); + if (fd < 0) return -1; + + int slot_to_free = -1; + char **vassal_argv = vassal_new_argv(n_ui, &slot_to_free); - int num_fds = 1; - if (n_ui->use_config) num_fds ++; - if (n_ui->on_demand_fd > -1) num_fds++; + struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); + // leave space for uwsgi header + ub->pos = 4; + int error=0,counter=0; + while(vassal_argv[counter]) { + if (!error && uwsgi_buffer_u16le(ub, strlen(vassal_argv[counter])) error = 1; + if (!error && uwsgi_buffer_append(ub, vassal_argv[counter], strlen(vassal_argv[counter])) error = 1; + if (counter == slot_to_free) free(vassal_argv[counter]); + counter++; + } - struct msghdr ep_msg; - void *ep_msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * num_fds)); - struct iovec ep_iov[2]; - struct cmsghdr *cmsg; + free(vassal_argv); - // build the parameters (passed as a uwsgi array) - - ep_iov[0].iov_base = "uwsgi-emperor"; - ep_iov[0].iov_len = 13; - ep_iov[1].iov_base = &num_fds; - ep_iov[1].iov_len = sizeof(int); - - ep_msg.msg_name = NULL; - ep_msg.msg_namelen = 0; - - ep_msg.msg_iov = ep_iov; - ep_msg.msg_iovlen = 2; - - ep_msg.msg_flags = 0; - ep_msg.msg_control = ep_msg_control; - ep_msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds); - - cmsg = CMSG_FIRSTHDR(&ep_msg); - cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - - unsigned char *ep_fd_ptr = CMSG_DATA(cmsg); - - memcpy(ep_fd_ptr, &uwsgi.emperor_fd, sizeof(int)); - if (num_fds > 1) { - memcpy(ep_fd_ptr + sizeof(int), &uwsgi.emperor_fd_config, sizeof(int)); - } - - if (sendmsg(fd, &ep_msg, 0) < 0) { - uwsgi_error("emperor_connect_to_fork_server()/sendmsg()"); - } - - free(ep_msg_control); + uwsgi_send_fds_and_body(fd, *fds, *fds_count, ub->buf, ub->pos); // now wait for the response (the pid number) + // the response could contain various info, currently we only need the "pid" attribute + // close the connection close(fd); + // return the pid to the Emperor + return pid; + + uwsgi_buffer_destroy(ub); return -1; } @@ -1039,7 +1124,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { n_ui->pid = pid; // close the right side of the pipe close(n_ui->pipe[1]); - /* THE ON-DEMAND file descriptir is left mapped to the emperor to allow fast-respawn + /* THE ON-DEMAND file descriptor is left mapped to the emperor to allow fast-respawn // TODO add an option to force closing it // close the "on demand" socket if (n_ui->on_demand_fd > -1) { @@ -1286,102 +1371,7 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) { close(n_ui->pipe_config[0]); } - int counter = 4; - struct uwsgi_string_list *uct; - uwsgi_foreach(uct, uwsgi.vassals_templates_before) counter += 2; - uwsgi_foreach(uct, uwsgi.vassals_includes_before) counter += 2; - uwsgi_foreach(uct, uwsgi.vassals_set) counter += 2; - uwsgi_foreach(uct, uwsgi.vassals_templates) counter += 2; - uwsgi_foreach(uct, uwsgi.vassals_includes) counter += 2; - - char **vassal_argv = uwsgi_malloc(sizeof(char *) * counter); - // set args - vassal_argv[0] = uwsgi.emperor_wrapper ? uwsgi.emperor_wrapper: uwsgi.binary_path; - - // reset counter - counter = 1; - - uwsgi_foreach(uct, uwsgi.vassals_templates_before) { - vassal_argv[counter] = "--inherit"; - vassal_argv[counter + 1] = uct->value; - counter += 2; - } - - uwsgi_foreach (uct, uwsgi.vassals_includes_before) { - vassal_argv[counter] = "--include"; - vassal_argv[counter + 1] = uct->value; - counter += 2; - } - - uwsgi_foreach (uct, uwsgi.vassals_set) { - vassal_argv[counter] = "--set"; - vassal_argv[counter + 1] = uct->value; - counter += 2; - } - - char *colon = NULL; - if (uwsgi.emperor_broodlord) { - colon = strchr(n_ui->name, ':'); - if (colon) { - colon[0] = 0; - } - } - // initialize to a default value - vassal_argv[counter] = "--inherit"; - - if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".xml")) - vassal_argv[counter] = "--xml"; - if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".ini")) - vassal_argv[counter] = "--ini"; - if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".yml")) - vassal_argv[counter] = "--yaml"; - if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".yaml")) - vassal_argv[counter] = "--yaml"; - if (!strcmp(n_ui->name + (strlen(n_ui->name) - 3), ".js")) - vassal_argv[counter] = "--json"; - if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".json")) - vassal_argv[counter] = "--json"; - struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension; - while(usl) { - if (uwsgi_endswith(n_ui->name, usl->value)) { - vassal_argv[counter] = "--config"; - break; - } - usl = usl->next; - } - if (colon) colon[0] = ':'; - - // start config filename... - counter++; - - vassal_argv[counter] = n_ui->name; - if (uwsgi.emperor_magic_exec) { - if (!access(n_ui->name, R_OK | X_OK)) { - vassal_argv[counter] = uwsgi_concat2("exec://", n_ui->name); - } - - } - - if (n_ui->use_config) { - vassal_argv[counter] = uwsgi_concat2("emperor://", n_ui->name); - } - - // start templates,includes,inherit... - counter++; - - uwsgi_foreach(uct, uwsgi.vassals_templates) { - vassal_argv[counter] = "--inherit"; - vassal_argv[counter + 1] = uct->value; - counter += 2; - } - - uwsgi_foreach (uct, uwsgi.vassals_includes) { - vassal_argv[counter] = "--include"; - vassal_argv[counter + 1] = uct->value; - counter += 2; - } - - vassal_argv[counter] = NULL; + char **vassal_argv = vassal_new_argv(n_ui, NULL); // disable stdin OR map it to the "on demand" socket if (n_ui->on_demand_fd > -1) { @@ -1424,6 +1414,7 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) { uwsgi_hooks_run(uwsgi.hook_as_vassal, "as-vassal", 1); + struct uwsgi_string_list *usl = NULL; uwsgi_foreach(usl, uwsgi.mount_as_vassal) { uwsgi_log("mounting \"%s\" (as-vassal)...\n", usl->value); if (uwsgi_mount_hook(usl->value)) { diff --git a/core/fork_server.c b/core/fork_server.c index c6547ead..1eedd2fe 100644 --- a/core/fork_server.c +++ b/core/fork_server.c @@ -15,11 +15,16 @@ from now on, we can consider the new child as a full-featured vassal */ void uwsgi_fork_server(char *socket) { + // map fd 0 to /dev/null to avoid mess + uwsgi_remap_fd(0, "/dev/null"); + int fd = bind_to_unix(socket, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); if (fd < 0) exit(1); + // automatically receive credentials (TODO make something useful with them, like checking the pid is from the Emperor) if (uwsgi_socket_passcred(fd)) exit(1); + // now start waiting for connections for(;;) { struct sockaddr_un client_src; socklen_t client_src_len = 0; @@ -37,22 +42,21 @@ void uwsgi_fork_server(char *socket) { pid_t pid = fork(); if (pid < 0) { + // error on fork() uwsgi_error("uwsgi_fork_server()/fork()"); goto end; } else if (pid > 0) { + // wait for child death... waitpid(pid, NULL, 0); goto end; } else { - // reparent the process -#ifdef __linux__ - if (prctl(PR_SET_CHILD_SUBREAPER, ppid, 0, 0, 0)) { - uwsgi_error("uwsgi_fork_server()/fork()"); - exit(1); - } -#endif - // now fork again and kill + // close everything excluded the passed fds and client_fd + // set EMPEROR_FD and FD_CONFIG env vars + // dup the on_demand socket to 0 and close it + + // now fork again and die pid_t new_pid = fork(); if (new_pid < 0) { uwsgi_error("uwsgi_fork_server()/fork()"); @@ -62,7 +66,13 @@ void uwsgi_fork_server(char *socket) { exit(0); } else { + // send the pid to the client_fd and close it + // send_pid() + close(client_fd); uwsgi_log("double fork() and reparenting successfull (new pid: %d)\n", getpid()); + + + // now parse the uwsgi packet array and build the argv uwsgi.new_argc = 6; // we do not free old uwsgi.argv as it could contains still used pointers uwsgi_log("%s\n", uwsgi.binary_path); @@ -74,13 +84,10 @@ void uwsgi_fork_server(char *socket) { uwsgi.new_argv[4] = uwsgi_str("--processes"); uwsgi.new_argv[5] = uwsgi_str("8"); uwsgi.new_argv[6] = NULL; -// on linux and sun we need to fix orig_argv -#if defined(__linux__) || defined(__sun__) -#endif - // this is the only step required to have a consistent environment uwsgi.fork_socket = NULL; + // continue with uWSGI startup return; } } diff --git a/core/io.c b/core/io.c index 30334dce..f91e0976 100644 --- a/core/io.c +++ b/core/io.c @@ -1481,3 +1481,66 @@ clear: #endif } +ssize_t uwsgi_recv_cred_and_fds(int fd, char *buf, size_t buf_len, pid_t *pid, uid_t *uid, gid_t *gid, int *fds, int *fds_count) { +#if defined(SCM_CREDENTIALS) && defined(SCM_RIGHTS) + ssize_t ret = -1; + + size_t msg_len = CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int) * (*fds_count)); + + // allocate space for credentials and file descriptors + void *msg_control = uwsgi_calloc(msg_len); + + // read into buf + struct iovec iov; + iov.iov_base = buf; + iov.iov_len = buf_len; + + struct msghdr msg; + memset(&msg, 0, sizeof(msg)); + + msg.msg_name = NULL; + msg.msg_namelen = 0; + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + // set cmsg + msg.msg_control = msg_control; + msg.msg_controllen = msg_len; + + ssize_t len = recvmsg(fd, &msg, 0); + if (len <= 0) { + uwsgi_error("uwsgi_recv_cred_and_fds()/recvmsg()"); + goto clear; + } + + // reset the number of fds + *fds_count = 0; + + struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); + while(cmsg) { + if (cmsg->cmsg_level != SOL_SOCKET) goto next; + if (cmsg->cmsg_type == SCM_RIGHTS) { + size_t fds_len = cmsg->cmsg_len - ((char *) CMSG_DATA(cmsg) - (char *) cmsg); + memcpy(fds, CMSG_DATA(cmsg), fds_len); + *fds_count = fds_len/sizeof(int); + } + else if (cmsg->cmsg_type == SCM_CREDENTIALS) { + struct ucred *u = (struct ucred *) CMSG_DATA(cmsg); + *pid = u->pid; + *uid = u->uid; + *gid = u->gid; + } +next: + cmsg=CMSG_NXTHDR(&msg,cmsg); + } + + ret = len; + +clear: + free(msg_control); + return ret; +#else + return -1; +#endif +} From 7ff5083e0946a7783f58f247c2cc336185077411 Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 6 May 2014 12:43:50 +0200 Subject: [PATCH 08/54] fork server (step2) --- core/emperor.c | 7 +++--- core/io.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ uwsgi.h | 1 + 3 files changed, 68 insertions(+), 3 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index dbd47d67..2b289a1b 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -1053,15 +1053,15 @@ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance ub->pos = 4; int error=0,counter=0; while(vassal_argv[counter]) { - if (!error && uwsgi_buffer_u16le(ub, strlen(vassal_argv[counter])) error = 1; - if (!error && uwsgi_buffer_append(ub, vassal_argv[counter], strlen(vassal_argv[counter])) error = 1; + if (!error && uwsgi_buffer_u16le(ub, strlen(vassal_argv[counter]))) error = 1; + if (!error && uwsgi_buffer_append(ub, vassal_argv[counter], strlen(vassal_argv[counter]))) error = 1; if (counter == slot_to_free) free(vassal_argv[counter]); counter++; } free(vassal_argv); - uwsgi_send_fds_and_body(fd, *fds, *fds_count, ub->buf, ub->pos); + //uwsgi_send_fds_and_body(fd, *fds, *fds_count, ub->buf, ub->pos); // now wait for the response (the pid number) // the response could contain various info, currently we only need the "pid" attribute @@ -1070,6 +1070,7 @@ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance close(fd); // return the pid to the Emperor + pid_t pid = -1; return pid; uwsgi_buffer_destroy(ub); diff --git a/core/io.c b/core/io.c index f91e0976..bbe59c39 100644 --- a/core/io.c +++ b/core/io.c @@ -1544,3 +1544,66 @@ clear: return -1; #endif } + + +int uwsgi_send_fds_and_body(int fd, int *fds, int fds_count, char *body, size_t len) { + + int ret = -1; + + struct msghdr msg; + void *msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * fds_count)); + struct iovec iov; + struct cmsghdr *cmsg; + + iov.iov_base = body; + iov.iov_len = len; + + msg.msg_name = NULL; + msg.msg_namelen = 0; + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + msg.msg_flags = 0; + msg.msg_control = msg_control; + msg.msg_controllen = CMSG_SPACE(sizeof(int) * fds_count); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int) * fds_count); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + unsigned char *fd_ptr = CMSG_DATA(cmsg); + + memcpy(fd_ptr, fds, sizeof(int) * fds_count); + + ssize_t rlen = sendmsg(fd, &msg, 0); + if (rlen <= 0) { + uwsgi_error("uwsgi_send_fds_and_body()/sendmsg()"); + goto end; + } + else { + size_t remains = len - rlen; + while(remains > 0) { + char *buf = body + rlen; + ssize_t wlen = write(fd, buf, remains); + if (wlen == 0) goto end; + if (wlen < 0) { + if (uwsgi_is_again()) { + // wait for write + continue; + } + uwsgi_error("uwsgi_send_fds_and_body()/write()"); + goto end; + } + rlen += wlen; + remains -= wlen; + } + } + ret = 0; + +end: + free(msg_control); + return ret; +} + diff --git a/uwsgi.h b/uwsgi.h index 9fadc4bb..c1fd1541 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -4778,6 +4778,7 @@ mode_t uwsgi_mode_t(char *, int *); int uwsgi_notify_socket_manage(int); int uwsgi_notify_msg(char *, char *, size_t); +int uwsgi_send_fds_and_body(int, int *, int, char *, size_t); void uwsgi_fork_server(char *); #ifdef __cplusplus From 119889584a71e0a91a39d6ce6dac70b603a300e1 Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 6 May 2014 13:59:23 +0200 Subject: [PATCH 09/54] fork server (step3) --- core/emperor.c | 21 ++++++++++++++++++++- core/fork_server.c | 5 ++++- uwsgi.h | 1 + 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 2b289a1b..09bc4b40 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -1061,10 +1061,28 @@ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance free(vassal_argv); - //uwsgi_send_fds_and_body(fd, *fds, *fds_count, ub->buf, ub->pos); + int fds[8]; + int fds_count = 1; + + if (uwsgi_send_fds_and_body(fd, fds, fds_count, ub->buf, ub->pos)) { + uwsgi_log_verbose("[uwsgi-emperor] %s: unable to complete fork-server session\n",n_ui->name); + goto end; + } // now wait for the response (the pid number) // the response could contain various info, currently we only need the "pid" attribute + size_t buf_len = uwsgi.page_size; + char *buf = uwsgi_malloc(buf_len); + uint8_t modifier1 = 0; + uint8_t modifier2 = 0; + int ret = uwsgi_read_with_realloc(fd, &buf, &buf_len, uwsgi.socket_timeout, &modifier1, &modifier2); + if (ret) { + free(buf); + uwsgi_log_verbose("[uwsgi-emperor] %s: unable to complete fork-server session\n",n_ui->name); + goto end; + } + + free(buf); // close the connection close(fd); @@ -1073,6 +1091,7 @@ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance pid_t pid = -1; return pid; +end: uwsgi_buffer_destroy(ub); return -1; } diff --git a/core/fork_server.c b/core/fork_server.c index 1eedd2fe..ab4852ef 100644 --- a/core/fork_server.c +++ b/core/fork_server.c @@ -37,7 +37,10 @@ void uwsgi_fork_server(char *socket) { pid_t ppid = -1; uid_t uid = -1; gid_t gid = -1; - ssize_t len = uwsgi_recv_cred2(client_fd, buf, 4096, &ppid, &uid, &gid); + int fds_count = 0; + // we can receive upto 8 fds (generally from 1 to 3) + int fds[8]; + ssize_t len = uwsgi_recv_cred_and_fds(client_fd, buf, 4096, &ppid, &uid, &gid, fds, &fds_count); uwsgi_log("RET = %d %d %d %d\n", len, ppid, uid, gid); pid_t pid = fork(); diff --git a/uwsgi.h b/uwsgi.h index c1fd1541..006663f4 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -4779,6 +4779,7 @@ int uwsgi_notify_socket_manage(int); int uwsgi_notify_msg(char *, char *, size_t); int uwsgi_send_fds_and_body(int, int *, int, char *, size_t); +ssize_t uwsgi_recv_cred_and_fds(int, char *, size_t buf_len, pid_t *, uid_t *, gid_t *, int *, int *); void uwsgi_fork_server(char *); #ifdef __cplusplus From c63bb224fb2fb7f5162832bf3f2655124fb5f5e2 Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 6 May 2014 14:06:06 +0200 Subject: [PATCH 10/54] reindented emperor --- core/emperor.c | 1194 +++++++++++++++++++++++++----------------------- 1 file changed, 618 insertions(+), 576 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 09bc4b40..3a10ab7f 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -41,103 +41,106 @@ struct uwsgi_emperor_blacklist_item *emperor_blacklist; // this generates the argv for the new vassal static char **vassal_new_argv(struct uwsgi_instance *n_ui, int *slot_to_free) { - int counter = 4; - struct uwsgi_string_list *uct; - uwsgi_foreach(uct, uwsgi.vassals_templates_before) counter += 2; - uwsgi_foreach(uct, uwsgi.vassals_includes_before) counter += 2; - uwsgi_foreach(uct, uwsgi.vassals_set) counter += 2; - uwsgi_foreach(uct, uwsgi.vassals_templates) counter += 2; - uwsgi_foreach(uct, uwsgi.vassals_includes) counter += 2; + int counter = 4; + struct uwsgi_string_list *uct; + uwsgi_foreach(uct, uwsgi.vassals_templates_before) counter += 2; + uwsgi_foreach(uct, uwsgi.vassals_includes_before) counter += 2; + uwsgi_foreach(uct, uwsgi.vassals_set) counter += 2; + uwsgi_foreach(uct, uwsgi.vassals_templates) counter += 2; + uwsgi_foreach(uct, uwsgi.vassals_includes) counter += 2; - char **vassal_argv = uwsgi_malloc(sizeof(char *) * counter); - // set args - vassal_argv[0] = uwsgi.emperor_wrapper ? uwsgi.emperor_wrapper: uwsgi.binary_path; + char **vassal_argv = uwsgi_malloc(sizeof(char *) * counter); + // set args + vassal_argv[0] = uwsgi.emperor_wrapper ? uwsgi.emperor_wrapper : uwsgi.binary_path; - // reset counter - counter = 1; + // reset counter + counter = 1; - uwsgi_foreach(uct, uwsgi.vassals_templates_before) { - vassal_argv[counter] = "--inherit"; - vassal_argv[counter + 1] = uct->value; - counter += 2; - } - - uwsgi_foreach (uct, uwsgi.vassals_includes_before) { - vassal_argv[counter] = "--include"; - vassal_argv[counter + 1] = uct->value; - counter += 2; - } - - uwsgi_foreach (uct, uwsgi.vassals_set) { - vassal_argv[counter] = "--set"; - vassal_argv[counter + 1] = uct->value; - counter += 2; - } - - char *colon = NULL; - if (uwsgi.emperor_broodlord) { - colon = strchr(n_ui->name, ':'); - if (colon) { - colon[0] = 0; - } - } - // initialize to a default value + uwsgi_foreach(uct, uwsgi.vassals_templates_before) { vassal_argv[counter] = "--inherit"; - - if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".xml")) - vassal_argv[counter] = "--xml"; - if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".ini")) - vassal_argv[counter] = "--ini"; - if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".yml")) + vassal_argv[counter + 1] = uct->value; + counter += 2; + } + + uwsgi_foreach(uct, uwsgi.vassals_includes_before) { + vassal_argv[counter] = "--include"; + vassal_argv[counter + 1] = uct->value; + counter += 2; + } + + uwsgi_foreach(uct, uwsgi.vassals_set) { + vassal_argv[counter] = "--set"; + vassal_argv[counter + 1] = uct->value; + counter += 2; + } + + char *colon = NULL; + if (uwsgi.emperor_broodlord) { + colon = strchr(n_ui->name, ':'); + if (colon) { + colon[0] = 0; + } + } + // initialize to a default value + vassal_argv[counter] = "--inherit"; + + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".xml")) + vassal_argv[counter] = "--xml"; + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".ini")) + vassal_argv[counter] = "--ini"; + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".yml")) vassal_argv[counter] = "--yaml"; - if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".yaml")) - vassal_argv[counter] = "--yaml"; - if (!strcmp(n_ui->name + (strlen(n_ui->name) - 3), ".js")) - vassal_argv[counter] = "--json"; - if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".json")) - vassal_argv[counter] = "--json"; - struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension; - while(usl) { - if (uwsgi_endswith(n_ui->name, usl->value)) { - vassal_argv[counter] = "--config"; - break; - } - usl = usl->next; + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".yaml")) + vassal_argv[counter] = "--yaml"; + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 3), ".js")) + vassal_argv[counter] = "--json"; + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".json")) + vassal_argv[counter] = "--json"; + struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension; + while (usl) { + if (uwsgi_endswith(n_ui->name, usl->value)) { + vassal_argv[counter] = "--config"; + break; } - if (colon) colon[0] = ':'; + usl = usl->next; + } + if (colon) + colon[0] = ':'; - // start config filename... - counter++; + // start config filename... + counter++; - vassal_argv[counter] = n_ui->name; - if (uwsgi.emperor_magic_exec) { - if (!access(n_ui->name, R_OK | X_OK)) { - vassal_argv[counter] = uwsgi_concat2("exec://", n_ui->name); - if (*slot_to_free) *slot_to_free = counter; - } - - } - else if (n_ui->use_config) { - vassal_argv[counter] = uwsgi_concat2("emperor://", n_ui->name); - if (*slot_to_free) *slot_to_free = counter; + vassal_argv[counter] = n_ui->name; + if (uwsgi.emperor_magic_exec) { + if (!access(n_ui->name, R_OK | X_OK)) { + vassal_argv[counter] = uwsgi_concat2("exec://", n_ui->name); + if (*slot_to_free) + *slot_to_free = counter; } - // start templates,includes,inherit... - counter++; + } + else if (n_ui->use_config) { + vassal_argv[counter] = uwsgi_concat2("emperor://", n_ui->name); + if (*slot_to_free) + *slot_to_free = counter; + } - uwsgi_foreach(uct, uwsgi.vassals_templates) { - vassal_argv[counter] = "--inherit"; - vassal_argv[counter + 1] = uct->value; - counter += 2; - } + // start templates,includes,inherit... + counter++; - uwsgi_foreach (uct, uwsgi.vassals_includes) { - vassal_argv[counter] = "--include"; - vassal_argv[counter + 1] = uct->value; - counter += 2; - } + uwsgi_foreach(uct, uwsgi.vassals_templates) { + vassal_argv[counter] = "--inherit"; + vassal_argv[counter + 1] = uct->value; + counter += 2; + } - vassal_argv[counter] = NULL; + uwsgi_foreach(uct, uwsgi.vassals_includes) { + vassal_argv[counter] = "--include"; + vassal_argv[counter + 1] = uct->value; + counter += 2; + } + + vassal_argv[counter] = NULL; return vassal_argv; } @@ -155,17 +158,18 @@ static int on_demand_bind(char *socket_name) { char *is_tcp = strchr(socket_name, ':'); int af_family = is_tcp ? AF_INET : AF_UNIX; int fd = socket(af_family, SOCK_STREAM, 0); - if (fd < 0) return -1; + if (fd < 0) + return -1; memset(&us, 0, sizeof(union uwsgi_sockaddr)); if (is_tcp) { int reuse = 1; - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) { + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *) &reuse, sizeof(int)) < 0) { goto error; - } + } us.sa_in.sin_family = AF_INET; - us.sa_in.sin_port = htons(atoi(is_tcp+1)); + us.sa_in.sin_port = htons(atoi(is_tcp + 1)); *is_tcp = 0; if (socket_name[0] != 0) { us.sa_in.sin_addr.s_addr = inet_addr(socket_name); @@ -201,7 +205,7 @@ static int on_demand_bind(char *socket_name) { } return fd; - + error: close(fd); return -1; @@ -294,11 +298,11 @@ struct uwsgi_emperor_scanner *emperor_scanners; static int has_extra_extension(char *name) { struct uwsgi_string_list *usl = uwsgi.emperor_extra_extension; - while(usl) { + while (usl) { if (uwsgi_endswith(name, usl->value)) { return 1; } - usl = usl->next; + usl = usl->next; } return 0; } @@ -322,12 +326,13 @@ static char *emperor_check_on_demand_socket(char *filename) { char *tmp = uwsgi_concat2(filename, uwsgi.emperor_on_demand_extension); int fd = open(tmp, O_RDONLY); free(tmp); - if (fd < 0) return NULL; + if (fd < 0) + return NULL; char *ret = uwsgi_read_fd(fd, &len, 1); close(fd); // change the first non printable character to 0 size_t i; - for(i=0;id_name); emperor_add(ues, de->d_name, st.st_mtime, NULL, 0, t_uid, t_gid, socket_name); - if (socket_name) free(socket_name); + if (socket_name) + free(socket_name); } } closedir(dir); @@ -486,14 +493,14 @@ void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) { } else { if (uwsgi.emperor_nofollow) { - if (lstat(c_ui->name, &st)) { - emperor_stop(c_ui); - } + if (lstat(c_ui->name, &st)) { + emperor_stop(c_ui); + } } else { - if (stat(c_ui->name, &st)) { - emperor_stop(c_ui); - } + if (stat(c_ui->name, &st)) { + emperor_stop(c_ui); + } } } } @@ -540,21 +547,21 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) { ui_current = emperor_get(g.gl_pathv[i]); uid_t t_uid = st.st_uid; - gid_t t_gid = st.st_gid; + gid_t t_gid = st.st_gid; - if (uwsgi.emperor_tyrant && uwsgi.emperor_tyrant_nofollow) { - struct stat lst; - if (lstat(g.gl_pathv[i], &lst)) { - uwsgi_error("[emperor-tyrant]/lstat()"); - if (ui_current) { - uwsgi_log("!!! availability of file %s changed. stopping the instance... !!!\n", g.gl_pathv[i]); - emperor_stop(ui_current); - } - continue; - } - t_uid = lst.st_uid; - t_gid = lst.st_gid; - } + if (uwsgi.emperor_tyrant && uwsgi.emperor_tyrant_nofollow) { + struct stat lst; + if (lstat(g.gl_pathv[i], &lst)) { + uwsgi_error("[emperor-tyrant]/lstat()"); + if (ui_current) { + uwsgi_log("!!! availability of file %s changed. stopping the instance... !!!\n", g.gl_pathv[i]); + emperor_stop(ui_current); + } + continue; + } + t_uid = lst.st_uid; + t_gid = lst.st_gid; + } if (ui_current) { // check if uid or gid are changed, in such case, stop the instance @@ -573,7 +580,8 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) { else { char *socket_name = emperor_check_on_demand_socket(g.gl_pathv[i]); emperor_add(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, t_uid, t_gid, socket_name); - if (socket_name) free(socket_name); + if (socket_name) + free(socket_name); } } @@ -585,38 +593,38 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) { while (c_ui) { if (c_ui->scanner == ues) { if (c_ui->zerg) { - char *colon = strrchr(c_ui->name, ':'); - if (!colon) { - emperor_stop(c_ui); - } - else { - char *filename = uwsgi_calloc(0xff); - memcpy(filename, c_ui->name, colon - c_ui->name); - if (uwsgi.emperor_nofollow) { - if (lstat(filename, &st)) { - emperor_stop(c_ui); - } - } - else { - if (stat(filename, &st)) { - emperor_stop(c_ui); - } - } - free(filename); - } - } - else { - if (uwsgi.emperor_nofollow) { - if (lstat(c_ui->name, &st)) { - emperor_stop(c_ui); - } + char *colon = strrchr(c_ui->name, ':'); + if (!colon) { + emperor_stop(c_ui); } else { - if (stat(c_ui->name, &st)) { - emperor_stop(c_ui); - } + char *filename = uwsgi_calloc(0xff); + memcpy(filename, c_ui->name, colon - c_ui->name); + if (uwsgi.emperor_nofollow) { + if (lstat(filename, &st)) { + emperor_stop(c_ui); + } + } + else { + if (stat(filename, &st)) { + emperor_stop(c_ui); + } + } + free(filename); } - } + } + else { + if (uwsgi.emperor_nofollow) { + if (lstat(c_ui->name, &st)) { + emperor_stop(c_ui); + } + } + else { + if (stat(c_ui->name, &st)) { + emperor_stop(c_ui); + } + } + } } c_ui = c_ui->ui_next; } @@ -678,11 +686,12 @@ static void royal_death(int signum) { uwsgi_log("[emperor] *** RAGNAROK EVOKED ***\n"); while (c_ui) { - emperor_stop(c_ui); - c_ui = c_ui->ui_next; - } + emperor_stop(c_ui); + c_ui = c_ui->ui_next; + } - if (!uwsgi.reload_mercy) uwsgi.reload_mercy = 30; + if (!uwsgi.reload_mercy) + uwsgi.reload_mercy = 30; on_royal_death = uwsgi_now(); } @@ -726,17 +735,17 @@ struct uwsgi_instance *emperor_get_by_fd(int fd) { struct uwsgi_instance *emperor_get_by_socket_fd(int fd) { - struct uwsgi_instance *c_ui = ui; + struct uwsgi_instance *c_ui = ui; - while (c_ui->ui_next) { - c_ui = c_ui->ui_next; + while (c_ui->ui_next) { + c_ui = c_ui->ui_next; // over engineering... - if (c_ui->on_demand_fd != -1 && c_ui->on_demand_fd == fd) { - return c_ui; - } - } - return NULL; + if (c_ui->on_demand_fd != -1 && c_ui->on_demand_fd == fd) { + return c_ui; + } + } + return NULL; } @@ -806,24 +815,26 @@ void emperor_del(struct uwsgi_instance *c_ui) { } void emperor_back_to_ondemand(struct uwsgi_instance *c_ui) { - if (c_ui->status > 0) return; + if (c_ui->status > 0) + return; // remove uWSGI instance - if (c_ui->pid != -1) { - if (write(c_ui->pipe[0], "\0", 1) != 1) { - uwsgi_error("emperor_stop()/write()"); - } - } + if (c_ui->pid != -1) { + if (write(c_ui->pipe[0], "\0", 1) != 1) { + uwsgi_error("emperor_stop()/write()"); + } + } c_ui->status = 2; - c_ui->cursed_at = uwsgi_now(); + c_ui->cursed_at = uwsgi_now(); - uwsgi_log_verbose("[emperor] bringing back instance %s to on-demand mode\n", c_ui->name); + uwsgi_log_verbose("[emperor] bringing back instance %s to on-demand mode\n", c_ui->name); } void emperor_stop(struct uwsgi_instance *c_ui) { - if (c_ui->status == 1) return; + if (c_ui->status == 1) + return; // remove uWSGI instance if (c_ui->pid != -1) { @@ -839,14 +850,16 @@ void emperor_stop(struct uwsgi_instance *c_ui) { } void emperor_curse(struct uwsgi_instance *c_ui) { - if (c_ui->status == 1) return; - // curse uWSGI instance + if (c_ui->status == 1) + return; + // curse uWSGI instance // take in account on-demand mode - if (c_ui->status == 0) c_ui->status = 1; - c_ui->cursed_at = uwsgi_now(); + if (c_ui->status == 0) + c_ui->status = 1; + c_ui->cursed_at = uwsgi_now(); - uwsgi_log_verbose("[emperor] curse the uwsgi instance %s (pid: %d)\n", c_ui->name, (int) c_ui->pid); + uwsgi_log_verbose("[emperor] curse the uwsgi instance %s (pid: %d)\n", c_ui->name, (int) c_ui->pid); } @@ -855,24 +868,25 @@ static void emperor_push_config(struct uwsgi_instance *c_ui) { struct uwsgi_header uh; if (c_ui->use_config) { - uh.modifier1 = 115; - uh.pktsize = c_ui->config_len; - uh.modifier2 = 0; - if (write(c_ui->pipe_config[0], &uh, 4) != 4) { - uwsgi_error("[uwsgi-emperor] write() header config"); - } - else { - if (write(c_ui->pipe_config[0], c_ui->config, c_ui->config_len) != (long) c_ui->config_len) { - uwsgi_error("[uwsgi-emperor] write() config"); - } - } - } + uh.modifier1 = 115; + uh.pktsize = c_ui->config_len; + uh.modifier2 = 0; + if (write(c_ui->pipe_config[0], &uh, 4) != 4) { + uwsgi_error("[uwsgi-emperor] write() header config"); + } + else { + if (write(c_ui->pipe_config[0], c_ui->config, c_ui->config_len) != (long) c_ui->config_len) { + uwsgi_error("[uwsgi-emperor] write() config"); + } + } + } } void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) { // if the vassal is being destroyed, do not honour respawns - if (c_ui->status > 0) return; + if (c_ui->status > 0) + return; // check if we are in on_demand mode (the respawn will be ignored) if (c_ui->pid == -1 && c_ui->on_demand_fd > -1) { @@ -993,7 +1007,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha n_ui->last_mod = born; // start non-ready n_ui->last_ready = 0; - n_ui->ready = 0; + n_ui->ready = 0; // start without loyalty n_ui->last_loyal = 0; n_ui->loyal = 0; @@ -1019,11 +1033,11 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha return; } - event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->on_demand_fd); + event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->on_demand_fd); uwsgi_log("[uwsgi-emperor] %s -> \"on demand\" instance detected, waiting for connections on socket \"%s\" ...\n", name, socket_name); return; } - + if (uwsgi_emperor_vassal_start(n_ui)) { // clear the vassal free(n_ui); @@ -1043,19 +1057,23 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *); */ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance *n_ui) { int fd = uwsgi_connect(socket, uwsgi.socket_timeout, 0); - if (fd < 0) return -1; - + if (fd < 0) + return -1; + int slot_to_free = -1; char **vassal_argv = vassal_new_argv(n_ui, &slot_to_free); struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); // leave space for uwsgi header ub->pos = 4; - int error=0,counter=0; - while(vassal_argv[counter]) { - if (!error && uwsgi_buffer_u16le(ub, strlen(vassal_argv[counter]))) error = 1; - if (!error && uwsgi_buffer_append(ub, vassal_argv[counter], strlen(vassal_argv[counter]))) error = 1; - if (counter == slot_to_free) free(vassal_argv[counter]); + int error = 0, counter = 0; + while (vassal_argv[counter]) { + if (!error && uwsgi_buffer_u16le(ub, strlen(vassal_argv[counter]))) + error = 1; + if (!error && uwsgi_buffer_append(ub, vassal_argv[counter], strlen(vassal_argv[counter]))) + error = 1; + if (counter == slot_to_free) + free(vassal_argv[counter]); counter++; } @@ -1065,7 +1083,7 @@ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance int fds_count = 1; if (uwsgi_send_fds_and_body(fd, fds, fds_count, ub->buf, ub->pos)) { - uwsgi_log_verbose("[uwsgi-emperor] %s: unable to complete fork-server session\n",n_ui->name); + uwsgi_log_verbose("[uwsgi-emperor] %s: unable to complete fork-server session\n", n_ui->name); goto end; } @@ -1078,14 +1096,14 @@ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance int ret = uwsgi_read_with_realloc(fd, &buf, &buf_len, uwsgi.socket_timeout, &modifier1, &modifier2); if (ret) { free(buf); - uwsgi_log_verbose("[uwsgi-emperor] %s: unable to complete fork-server session\n",n_ui->name); + uwsgi_log_verbose("[uwsgi-emperor] %s: unable to complete fork-server session\n", n_ui->name); goto end; } free(buf); // close the connection - close(fd); + close(fd); // return the pid to the Emperor pid_t pid = -1; @@ -1130,7 +1148,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { #if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && !defined(__ia64__) else if (uwsgi.emperor_clone) { char stack[PTHREAD_STACK_MIN]; - pid = clone((int (*)(void *))uwsgi_emperor_spawn_vassal, stack + PTHREAD_STACK_MIN, SIGCHLD | uwsgi.emperor_clone, (void *) n_ui); + pid = clone((int (*)(void *)) uwsgi_emperor_spawn_vassal, stack + PTHREAD_STACK_MIN, SIGCHLD | uwsgi.emperor_clone, (void *) n_ui); } #endif else { @@ -1145,13 +1163,13 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { // close the right side of the pipe close(n_ui->pipe[1]); /* THE ON-DEMAND file descriptor is left mapped to the emperor to allow fast-respawn - // TODO add an option to force closing it - // close the "on demand" socket - if (n_ui->on_demand_fd > -1) { - close(n_ui->on_demand_fd); - n_ui->on_demand_fd = -1; - } - */ + // TODO add an option to force closing it + // close the "on demand" socket + if (n_ui->on_demand_fd > -1) { + close(n_ui->on_demand_fd); + n_ui->on_demand_fd = -1; + } + */ if (n_ui->use_config) { close(n_ui->pipe_config[1]); } @@ -1159,16 +1177,16 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { if (n_ui->use_config) { struct uwsgi_header uh; uh.modifier1 = 115; - uh.pktsize = n_ui->config_len; - uh.modifier2 = 0; - if (write(n_ui->pipe_config[0], &uh, 4) != 4) { - uwsgi_error("[uwsgi-emperor] write() header config"); - } - else { - if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) != (long) n_ui->config_len) { - uwsgi_error("[uwsgi-emperor] write() config"); - } - } + uh.pktsize = n_ui->config_len; + uh.modifier2 = 0; + if (write(n_ui->pipe_config[0], &uh, 4) != 4) { + uwsgi_error("[uwsgi-emperor] write() header config"); + } + else { + if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) != (long) n_ui->config_len) { + uwsgi_error("[uwsgi-emperor] write() config"); + } + } } @@ -1177,71 +1195,77 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { uwsgi_hooks_run(uwsgi.hook_as_emperor, "as-emperor", 0); struct uwsgi_string_list *usl; uwsgi_foreach(usl, uwsgi.mount_as_emperor) { - uwsgi_log("mounting \"%s\" (as-emperor for vassal \"%s\" pid: %d uid: %d gid: %d)...\n", usl->value, n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid); - if (uwsgi_mount_hook(usl->value)) { - exit(1); - } - } + uwsgi_log("mounting \"%s\" (as-emperor for vassal \"%s\" pid: %d uid: %d gid: %d)...\n", usl->value, n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid); + if (uwsgi_mount_hook(usl->value)) { + exit(1); + } + } - uwsgi_foreach(usl, uwsgi.umount_as_emperor) { - uwsgi_log("un-mounting \"%s\" (as-emperor for vassal \"%s\" pid: %d uid: %d gid: %d)...\n", usl->value, n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid); - if (uwsgi_umount_hook(usl->value)) { - exit(1); - } - } + uwsgi_foreach(usl, uwsgi.umount_as_emperor) { + uwsgi_log("un-mounting \"%s\" (as-emperor for vassal \"%s\" pid: %d uid: %d gid: %d)...\n", usl->value, n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid); + if (uwsgi_umount_hook(usl->value)) { + exit(1); + } + } uwsgi_foreach(usl, uwsgi.exec_as_emperor) { uwsgi_log("running \"%s\" (as-emperor for vassal \"%s\" pid: %d uid: %d gid: %d)...\n", usl->value, n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid); char *argv[4]; argv[0] = uwsgi_concat2("UWSGI_VASSAL_CONFIG=", n_ui->name); - char argv_pid[17+11]; snprintf(argv_pid, 17 + 11, "UWSGI_VASSAL_PID=%d", (int) n_ui->pid); argv[1] = argv_pid; - char argv_uid[17+11]; snprintf(argv_uid, 17 + 11, "UWSGI_VASSAL_UID=%d", (int) n_ui->uid); argv[2] = argv_uid; - char argv_gid[17+11]; snprintf(argv_gid, 17 + 11, "UWSGI_VASSAL_GID=%d", (int) n_ui->gid); argv[3] = argv_gid; - int ret = uwsgi_run_command_putenv_and_wait(NULL, usl->value, argv, 4); - uwsgi_log("command \"%s\" exited with code: %d\n", usl->value, ret); + char argv_pid[17 + 11]; + snprintf(argv_pid, 17 + 11, "UWSGI_VASSAL_PID=%d", (int) n_ui->pid); + argv[1] = argv_pid; + char argv_uid[17 + 11]; + snprintf(argv_uid, 17 + 11, "UWSGI_VASSAL_UID=%d", (int) n_ui->uid); + argv[2] = argv_uid; + char argv_gid[17 + 11]; + snprintf(argv_gid, 17 + 11, "UWSGI_VASSAL_GID=%d", (int) n_ui->gid); + argv[3] = argv_gid; + int ret = uwsgi_run_command_putenv_and_wait(NULL, usl->value, argv, 4); + uwsgi_log("command \"%s\" exited with code: %d\n", usl->value, ret); free(argv[0]); } // 4 call hooks // config / config + pid / config + pid + uid + gid // call uwsgi_foreach(usl, uwsgi.call_as_emperor) { - void (*func)(void) = dlsym(RTLD_DEFAULT, usl->value); + void (*func) (void) = dlsym(RTLD_DEFAULT, usl->value); if (!func) { - uwsgi_log("unable to call function \"%s\"\n", usl->value); - } + uwsgi_log("unable to call function \"%s\"\n", usl->value); + } else { func(); } - } + } uwsgi_foreach(usl, uwsgi.call_as_emperor1) { - void (*func)(char *) = dlsym(RTLD_DEFAULT, usl->value); - if (!func) { - uwsgi_log("unable to call function \"%s\"\n", usl->value); - } - else { - func(n_ui->name); - } - } + void (*func) (char *) = dlsym(RTLD_DEFAULT, usl->value); + if (!func) { + uwsgi_log("unable to call function \"%s\"\n", usl->value); + } + else { + func(n_ui->name); + } + } uwsgi_foreach(usl, uwsgi.call_as_emperor2) { - void (*func)(char *, pid_t) = dlsym(RTLD_DEFAULT, usl->value); - if (!func) { - uwsgi_log("unable to call function \"%s\"\n", usl->value); - } - else { - func(n_ui->name, n_ui->pid); - } - } + void (*func) (char *, pid_t) = dlsym(RTLD_DEFAULT, usl->value); + if (!func) { + uwsgi_log("unable to call function \"%s\"\n", usl->value); + } + else { + func(n_ui->name, n_ui->pid); + } + } uwsgi_foreach(usl, uwsgi.call_as_emperor4) { - void (*func)(char *, pid_t, uid_t, gid_t) = dlsym(RTLD_DEFAULT, usl->value); - if (!func) { - uwsgi_log("unable to call function \"%s\"\n", usl->value); - } - else { - func(n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid); - } - } + void (*func) (char *, pid_t, uid_t, gid_t) = dlsym(RTLD_DEFAULT, usl->value); + if (!func) { + uwsgi_log("unable to call function \"%s\"\n", usl->value); + } + else { + func(n_ui->name, n_ui->pid, n_ui->uid, n_ui->gid); + } + } return 0; } else { @@ -1254,9 +1278,9 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) { #ifdef __linux__ - if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { - uwsgi_error("prctl()"); - } + if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { + uwsgi_error("prctl()"); + } #ifdef CLONE_NEWUSER if (uwsgi.emperor_clone & CLONE_NEWUSER) { if (setuid(0)) { @@ -1268,20 +1292,24 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) { #ifdef UWSGI_CAP #if defined(CAP_LAST_CAP) && defined(PR_CAPBSET_READ) && defined(PR_CAPBSET_DROP) - if (uwsgi.emperor_cap && uwsgi.emperor_cap_count > 0) { + if (uwsgi.emperor_cap && uwsgi.emperor_cap_count > 0) { int i; - for(i=0;i<=CAP_LAST_CAP;i++) { - + for (i = 0; i <= CAP_LAST_CAP; i++) { + int has_cap = prctl(PR_CAPBSET_READ, i, 0, 0, 0); if (has_cap == 1) { - if (i == CAP_SETPCAP) continue; - int j;int found = 0; - for(j=0;jname, (int) getpid()); - } + } #endif #endif #endif - if (uwsgi.emperor_tyrant) { - uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) n_ui->uid, (int) n_ui->gid, n_ui->name); - if (setgid(n_ui->gid)) { - uwsgi_error("setgid()"); - exit(1); - } - if (setgroups(0, NULL)) { - uwsgi_error("setgroups()"); - exit(1); - } - - if (setuid(n_ui->uid)) { - uwsgi_error("setuid()"); - exit(1); - } - + if (uwsgi.emperor_tyrant) { + uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) n_ui->uid, (int) n_ui->gid, n_ui->name); + if (setgid(n_ui->gid)) { + uwsgi_error("setgid()"); + exit(1); + } + if (setgroups(0, NULL)) { + uwsgi_error("setgroups()"); + exit(1); } - unsetenv("UWSGI_RELOADS"); - unsetenv("NOTIFY_SOCKET"); + if (setuid(n_ui->uid)) { + uwsgi_error("setuid()"); + exit(1); + } - char *uef = uwsgi_num2str(n_ui->pipe[1]); - if (setenv("UWSGI_EMPEROR_FD", uef, 1)) { + } + + unsetenv("UWSGI_RELOADS"); + unsetenv("NOTIFY_SOCKET"); + + char *uef = uwsgi_num2str(n_ui->pipe[1]); + if (setenv("UWSGI_EMPEROR_FD", uef, 1)) { + uwsgi_error("setenv()"); + exit(1); + } + free(uef); + + // add UWSGI_BROODLORD_NUM + if (n_ui->zerg) { + uef = uwsgi_num2str(uwsgi.emperor_broodlord_num); + if (setenv("UWSGI_BROODLORD_NUM", uef, 1)) { uwsgi_error("setenv()"); exit(1); } free(uef); + } - // add UWSGI_BROODLORD_NUM - if (n_ui->zerg) { - uef = uwsgi_num2str(uwsgi.emperor_broodlord_num); - if (setenv("UWSGI_BROODLORD_NUM", uef, 1)) { - uwsgi_error("setenv()"); - exit(1); - } - free(uef); + if (n_ui->use_config) { + uef = uwsgi_num2str(n_ui->pipe_config[1]); + if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) { + uwsgi_error("setenv()"); + exit(1); } + free(uef); + } - if (n_ui->use_config) { - uef = uwsgi_num2str(n_ui->pipe_config[1]); - if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) { - uwsgi_error("setenv()"); - exit(1); - } - free(uef); - } - - char **uenvs = environ; - while (*uenvs) { - if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13) && strchr(*uenvs, '=')) { - char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0), *ne; + char **uenvs = environ; + while (*uenvs) { + if (!strncmp(*uenvs, "UWSGI_VASSAL_", 13) && strchr(*uenvs, '=')) { + char *oe = uwsgi_concat2n(*uenvs, strchr(*uenvs, '=') - *uenvs, "", 0), *ne; #ifdef UNSETENV_VOID - unsetenv(oe); + unsetenv(oe); #else - if (unsetenv(oe)) { - uwsgi_error("unsetenv()"); - free(oe); - break; - } -#endif + if (unsetenv(oe)) { + uwsgi_error("unsetenv()"); free(oe); + break; + } +#endif + free(oe); - ne = uwsgi_concat2("UWSGI_", *uenvs + 13); + ne = uwsgi_concat2("UWSGI_", *uenvs + 13); #ifdef UWSGI_DEBUG - uwsgi_log("putenv %s\n", ne); + uwsgi_log("putenv %s\n", ne); #endif - if (putenv(ne)) { - uwsgi_error("putenv()"); - } - // do not free ne as putenv will add it to the environ - uenvs = environ; - continue; + if (putenv(ne)) { + uwsgi_error("putenv()"); } - uenvs++; + // do not free ne as putenv will add it to the environ + uenvs = environ; + continue; } + uenvs++; + } - // close the left side of the pipe - close(n_ui->pipe[0]); + // close the left side of the pipe + close(n_ui->pipe[0]); - if (n_ui->use_config) { - close(n_ui->pipe_config[0]); - } + if (n_ui->use_config) { + close(n_ui->pipe_config[0]); + } - char **vassal_argv = vassal_new_argv(n_ui, NULL); + char **vassal_argv = vassal_new_argv(n_ui, NULL); - // disable stdin OR map it to the "on demand" socket - if (n_ui->on_demand_fd > -1) { - if (n_ui->on_demand_fd != 0) { - if (dup2(n_ui->on_demand_fd, 0) < 0) { - uwsgi_error("dup2()"); - exit(1); - } - close(n_ui->on_demand_fd); - } - } - else { - uwsgi_remap_fd(0, "/dev/null"); - } - - // close all of the unneded fd - int i; - for (i = 3; i < (int) uwsgi.max_fd; i++) { - if (uwsgi_fd_is_safe(i)) continue; - if (n_ui->use_config) { - if (i == n_ui->pipe_config[1]) - continue; - } - if (i != n_ui->pipe[1]) { - close(i); - } - } - - // run start hook (can fail) - if (uwsgi.vassals_start_hook) { - uwsgi_log("[emperor] running vassal start-hook: %s %s\n", uwsgi.vassals_start_hook, n_ui->name); - if (uwsgi.emperor_absolute_dir) { - if (setenv("UWSGI_VASSALS_DIR", uwsgi.emperor_absolute_dir, 1)) { - uwsgi_error("setenv()"); - } - } - int start_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_start_hook, n_ui->name); - uwsgi_log("[emperor] %s start-hook returned %d\n", n_ui->name, start_hook_ret); - } - - uwsgi_hooks_run(uwsgi.hook_as_vassal, "as-vassal", 1); - - struct uwsgi_string_list *usl = NULL; - uwsgi_foreach(usl, uwsgi.mount_as_vassal) { - uwsgi_log("mounting \"%s\" (as-vassal)...\n", usl->value); - if (uwsgi_mount_hook(usl->value)) { - exit(1); - } - } - - uwsgi_foreach(usl, uwsgi.umount_as_vassal) { - uwsgi_log("un-mounting \"%s\" (as-vassal)...\n", usl->value); - if (uwsgi_umount_hook(usl->value)) { - exit(1); - } - } - - // run exec hooks (cannot fail) - uwsgi_foreach(usl, uwsgi.exec_as_vassal) { - uwsgi_log("running \"%s\" (as-vassal)...\n", usl->value); - int ret = uwsgi_run_command_and_wait(NULL, usl->value); - if (ret != 0) { - uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret); - exit(1); - } - } - - // run low-level hooks - uwsgi_foreach(usl, uwsgi.call_as_vassal) { - void (*func)(void) = dlsym(RTLD_DEFAULT, usl->value); - if (!func) { - uwsgi_log("unable to call function \"%s\"\n", usl->value); + // disable stdin OR map it to the "on demand" socket + if (n_ui->on_demand_fd > -1) { + if (n_ui->on_demand_fd != 0) { + if (dup2(n_ui->on_demand_fd, 0) < 0) { + uwsgi_error("dup2()"); exit(1); - } - func(); - } - - uwsgi_foreach(usl, uwsgi.call_as_vassal1) { - void (*func)(char *) = dlsym(RTLD_DEFAULT, usl->value); - if (!func) { - uwsgi_log("unable to call function \"%s\"\n", usl->value); - exit(1); - } - func(n_ui->name); - } - - uwsgi_foreach(usl, uwsgi.call_as_vassal3) { - void (*func)(char *, uid_t, gid_t) = dlsym(RTLD_DEFAULT, usl->value); - if (!func) { - uwsgi_log("unable to call function \"%s\"\n", usl->value); - exit(1); - } - func(n_ui->name, n_ui->uid, n_ui->gid); - } - - // start !!! - if (execvp(vassal_argv[0], vassal_argv)) { - uwsgi_error("execvp()"); + } + close(n_ui->on_demand_fd); } - uwsgi_log("[emperor] is the uwsgi binary in your system PATH ?\n"); - // never here - exit(UWSGI_EXILE_CODE); + } + else { + uwsgi_remap_fd(0, "/dev/null"); + } + + // close all of the unneded fd + int i; + for (i = 3; i < (int) uwsgi.max_fd; i++) { + if (uwsgi_fd_is_safe(i)) + continue; + if (n_ui->use_config) { + if (i == n_ui->pipe_config[1]) + continue; + } + if (i != n_ui->pipe[1]) { + close(i); + } + } + + // run start hook (can fail) + if (uwsgi.vassals_start_hook) { + uwsgi_log("[emperor] running vassal start-hook: %s %s\n", uwsgi.vassals_start_hook, n_ui->name); + if (uwsgi.emperor_absolute_dir) { + if (setenv("UWSGI_VASSALS_DIR", uwsgi.emperor_absolute_dir, 1)) { + uwsgi_error("setenv()"); + } + } + int start_hook_ret = uwsgi_run_command_and_wait(uwsgi.vassals_start_hook, n_ui->name); + uwsgi_log("[emperor] %s start-hook returned %d\n", n_ui->name, start_hook_ret); + } + + uwsgi_hooks_run(uwsgi.hook_as_vassal, "as-vassal", 1); + + struct uwsgi_string_list *usl = NULL; + uwsgi_foreach(usl, uwsgi.mount_as_vassal) { + uwsgi_log("mounting \"%s\" (as-vassal)...\n", usl->value); + if (uwsgi_mount_hook(usl->value)) { + exit(1); + } + } + + uwsgi_foreach(usl, uwsgi.umount_as_vassal) { + uwsgi_log("un-mounting \"%s\" (as-vassal)...\n", usl->value); + if (uwsgi_umount_hook(usl->value)) { + exit(1); + } + } + + // run exec hooks (cannot fail) + uwsgi_foreach(usl, uwsgi.exec_as_vassal) { + uwsgi_log("running \"%s\" (as-vassal)...\n", usl->value); + int ret = uwsgi_run_command_and_wait(NULL, usl->value); + if (ret != 0) { + uwsgi_log("command \"%s\" exited with non-zero code: %d\n", usl->value, ret); + exit(1); + } + } + + // run low-level hooks + uwsgi_foreach(usl, uwsgi.call_as_vassal) { + void (*func) (void) = dlsym(RTLD_DEFAULT, usl->value); + if (!func) { + uwsgi_log("unable to call function \"%s\"\n", usl->value); + exit(1); + } + func(); + } + + uwsgi_foreach(usl, uwsgi.call_as_vassal1) { + void (*func) (char *) = dlsym(RTLD_DEFAULT, usl->value); + if (!func) { + uwsgi_log("unable to call function \"%s\"\n", usl->value); + exit(1); + } + func(n_ui->name); + } + + uwsgi_foreach(usl, uwsgi.call_as_vassal3) { + void (*func) (char *, uid_t, gid_t) = dlsym(RTLD_DEFAULT, usl->value); + if (!func) { + uwsgi_log("unable to call function \"%s\"\n", usl->value); + exit(1); + } + func(n_ui->name, n_ui->uid, n_ui->gid); + } + + // start !!! + if (execvp(vassal_argv[0], vassal_argv)) { + uwsgi_error("execvp()"); + } + uwsgi_log("[emperor] is the uwsgi binary in your system PATH ?\n"); + // never here + exit(UWSGI_EXILE_CODE); } void uwsgi_imperial_monitor_glob_init(struct uwsgi_emperor_scanner *ues) { @@ -1632,14 +1661,15 @@ int uwsgi_emperor_scanner_event(int fd) { } -static void emperor_wakeup(int sn) {} +static void emperor_wakeup(int sn) { +} static void emperor_cleanup() { uwsgi_log_verbose("[uwsgi-emperor] cleaning up blacklist ...\n"); struct uwsgi_instance *ui_current = ui; - while (ui_current->ui_next) { + while (ui_current->ui_next) { uwsgi_emperor_blacklist_remove(ui_current->name); - ui_current = ui_current->ui_next; + ui_current = ui_current->ui_next; } } @@ -1728,26 +1758,27 @@ void emperor_loop() { uwsgi_hooks_run(uwsgi.hook_emperor_start, "emperor-start", 1); // signal parent-Emperor about my loyalty - if (uwsgi.has_emperor && !uwsgi.loyal) { - uwsgi_log("announcing my loyalty to the Emperor...\n"); - char byte = 17; - if (write(uwsgi.emperor_fd, &byte, 1) != 1) { - uwsgi_error("write()"); - } - uwsgi.loyal = 1; - } + if (uwsgi.has_emperor && !uwsgi.loyal) { + uwsgi_log("announcing my loyalty to the Emperor...\n"); + char byte = 17; + if (write(uwsgi.emperor_fd, &byte, 1) != 1) { + uwsgi_error("write()"); + } + uwsgi.loyal = 1; + } for (;;) { if (on_royal_death) { - if (!ui->ui_next) break; + if (!ui->ui_next) + break; if (uwsgi_now() - on_royal_death >= uwsgi.reload_mercy) { ui_current = ui->ui_next; while (ui_current) { uwsgi_log_verbose("[emperor] NO MERCY for vassal %s !!!\n", ui_current->name); if (kill(ui_current->pid, SIGKILL) < 0) { uwsgi_error("[emperor] kill()"); - emperor_del(ui_current); + emperor_del(ui_current); break; } ui_current = ui_current->ui_next; @@ -1757,15 +1788,15 @@ void emperor_loop() { ui_current = ui->ui_next; while (ui_current) { struct uwsgi_instance *dead_vassal = ui_current; - ui_current = ui_current->ui_next; - pid_t dead_pid = waitpid(dead_vassal->pid, &waitpid_status, WNOHANG); + ui_current = ui_current->ui_next; + pid_t dead_pid = waitpid(dead_vassal->pid, &waitpid_status, WNOHANG); if (dead_pid > 0 || dead_pid < 0) { - emperor_del(dead_vassal); + emperor_del(dead_vassal); } } sleep(1); continue; - } + } if (!i_am_alone) { diedpid = waitpid(uwsgi.emperor_pid, &waitpid_status, WNOHANG); @@ -1817,7 +1848,7 @@ void emperor_loop() { ui_current->last_heartbeat = uwsgi_now(); } else if (byte == 22) { - // command 22 changes meaning when in "on_demand" mode + // command 22 changes meaning when in "on_demand" mode if (ui_current->on_demand_fd != -1) { emperor_back_to_ondemand(ui_current); } @@ -1870,7 +1901,7 @@ void emperor_loop() { while (ui_current) { if (ui_current->last_heartbeat > 0) { #ifdef UWSGI_DEBUG - uwsgi_log("%d %d %d %d\n", ui_current->last_heartbeat, uwsgi.emperor_heartbeat, ui_current->last_heartbeat + uwsgi.emperor_heartbeat, uwsgi_now()); + uwsgi_log("%d %d %d %d\n", ui_current->last_heartbeat, uwsgi.emperor_heartbeat, ui_current->last_heartbeat + uwsgi.emperor_heartbeat, uwsgi_now()); #endif if ((ui_current->last_heartbeat + uwsgi.emperor_heartbeat) < uwsgi_now()) { uwsgi_log("[emperor] vassal %s sent no heartbeat in last %d seconds, brutally respawning it...\n", ui_current->name, uwsgi.emperor_heartbeat); @@ -1968,13 +1999,14 @@ recheck: else if (ui_current->status == 2) { event_queue_add_fd_read(uwsgi.emperor_queue, ui_current->on_demand_fd); close(ui_current->pipe[0]); - if (ui_current->use_config) close(ui_current->pipe_config[0]); + if (ui_current->use_config) + close(ui_current->pipe_config[0]); ui_current->pid = -1; ui_current->status = 0; ui_current->cursed_at = 0; ui_current->ready = 0; ui_current->accepting = 0; - uwsgi_log("[uwsgi-emperor] %s -> back to \"on demand\" mode, waiting for connections on socket \"%s\" ...\n", ui_current->name, ui_current->socket_name); + uwsgi_log("[uwsgi-emperor] %s -> back to \"on demand\" mode, waiting for connections on socket \"%s\" ...\n", ui_current->name, ui_current->socket_name); break; } } @@ -1983,7 +2015,7 @@ recheck: emperor_del(ui_current); // temporarily set frequency to 1, so we can eventually fast-restart the instance freq = 1; - break; + break; } else if (now - ui_current->cursed_at >= uwsgi.emperor_curse_tolerance) { ui_current->cursed_at = now; @@ -1998,14 +2030,15 @@ recheck: } // if waitpid returned an item, let's check for another (potential) one - if (diedpid > 0) goto recheck; + if (diedpid > 0) + goto recheck; } uwsgi_log_verbose("The Emperor is buried.\n"); uwsgi_notify("The Emperor is buried."); - exit(0); + exit(0); } @@ -2218,10 +2251,10 @@ end: void uwsgi_emperor_start() { #ifdef __linux__ - if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)) { - uwsgi_error("uwsgi_fork_server()/fork()"); - exit(1); - } + if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)) { + uwsgi_error("uwsgi_fork_server()/fork()"); + exit(1); + } #endif if (!uwsgi.sockets && !ushared->gateways_cnt && !uwsgi.master_process) { @@ -2261,7 +2294,7 @@ void uwsgi_emperor_start() { void uwsgi_check_emperor() { char *emperor_fd_pass = getenv("UWSGI_EMPEROR_PROXY"); if (emperor_fd_pass) { - for(;;) { + for (;;) { int proxy_fd = uwsgi_connect(emperor_fd_pass, 30, 0); if (proxy_fd < 0) { uwsgi_error("uwsgi_check_emperor()/uwsgi_connect()"); @@ -2275,8 +2308,10 @@ void uwsgi_check_emperor() { if (setenv("UWSGI_EMPEROR_FD", env_emperor_fd, 1)) { uwsgi_error("uwsgi_check_emperor()/setenv(UWSGI_EMPEROR_FD)"); free(env_emperor_fd); - int i; for(i=0;i 1) { @@ -2284,15 +2319,18 @@ void uwsgi_check_emperor() { if (setenv("UWSGI_EMPEROR_FD_CONFIG", env_emperor_fd_config, 1)) { uwsgi_error("uwsgi_check_emperor()/setenv(UWSGI_EMPEROR_FD_CONFIG)"); free(env_emperor_fd_config); - int i; for(i=0;istatus > 0) return; + if (ui_current->status > 0) + return; // check if uid or gid are changed, in such case, stop the instance if (uwsgi.emperor_tyrant) { @@ -2340,12 +2379,12 @@ void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char if ((!ui_current->socket_name && ui_current->on_demand_fd == -1) && socket_name) { uwsgi_log("[uwsgi-emperor] %s -> requested move to \"on demand\" mode for socket \"%s\" ...\n", name, socket_name); emperor_stop(ui_current); - return; + return; } else if ((ui_current->socket_name && ui_current->on_demand_fd > -1) && !socket_name) { uwsgi_log("[uwsgi-emperor] %s -> asked for leaving \"on demand\" mode for socket \"%s\" ...\n", name, ui_current->socket_name); emperor_stop(ui_current); - return; + return; } // make a new config (free the old one) if needed @@ -2372,104 +2411,107 @@ void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char } void uwsgi_master_manage_emperor() { - char byte; - ssize_t rlen = read(uwsgi.emperor_fd, &byte, 1); - if (rlen > 0) { - uwsgi_log_verbose("received message %d from emperor\n", byte); - // remove me - if (byte == 0) { + char byte; + ssize_t rlen = read(uwsgi.emperor_fd, &byte, 1); + if (rlen > 0) { + uwsgi_log_verbose("received message %d from emperor\n", byte); + // remove me + if (byte == 0) { uwsgi_hooks_run(uwsgi.hook_emperor_stop, "emperor-stop", 0); - close(uwsgi.emperor_fd); - if (!uwsgi.status.brutally_reloading) - kill_them_all(0); - } - // reload me - else if (byte == 1) { + close(uwsgi.emperor_fd); + if (!uwsgi.status.brutally_reloading) + kill_them_all(0); + } + // reload me + else if (byte == 1) { uwsgi_hooks_run(uwsgi.hook_emperor_reload, "emperor-reload", 0); - // un-lazy the stack to trigger a real reload - uwsgi.lazy = 0; - uwsgi_block_signal(SIGHUP); - grace_them_all(0); - uwsgi_unblock_signal(SIGHUP); - } - } - else { + // un-lazy the stack to trigger a real reload + uwsgi.lazy = 0; + uwsgi_block_signal(SIGHUP); + grace_them_all(0); + uwsgi_unblock_signal(SIGHUP); + } + } + else { uwsgi_error("uwsgi_master_manage_emperor()/read()"); - uwsgi_log("lost connection with my emperor !!!\n"); + uwsgi_log("lost connection with my emperor !!!\n"); uwsgi_hooks_run(uwsgi.hook_emperor_lost, "emperor-lost", 0); - close(uwsgi.emperor_fd); - if (!uwsgi.status.brutally_reloading) - kill_them_all(0); - sleep(2); - exit(1); - } + close(uwsgi.emperor_fd); + if (!uwsgi.status.brutally_reloading) + kill_them_all(0); + sleep(2); + exit(1); + } } void uwsgi_master_manage_emperor_proxy() { struct sockaddr_un epsun; - socklen_t epsun_len = sizeof(struct sockaddr_un); + socklen_t epsun_len = sizeof(struct sockaddr_un); - int ep_client = accept(uwsgi.emperor_fd_proxy, (struct sockaddr *) &epsun, &epsun_len); - if (ep_client < 0) { - uwsgi_error("uwsgi_master_manage_emperor_proxy()/accept()"); - return; - } - - int num_fds = 1; - if (uwsgi.emperor_fd_config > -1) num_fds++; - - struct msghdr ep_msg; - void *ep_msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * num_fds)); - struct iovec ep_iov[2]; - struct cmsghdr *cmsg; - - ep_iov[0].iov_base = "uwsgi-emperor"; - ep_iov[0].iov_len = 13; - ep_iov[1].iov_base = &num_fds; - ep_iov[1].iov_len = sizeof(int); - - ep_msg.msg_name = NULL; - ep_msg.msg_namelen = 0; - - ep_msg.msg_iov = ep_iov; - ep_msg.msg_iovlen = 2; - - ep_msg.msg_flags = 0; - ep_msg.msg_control = ep_msg_control; - ep_msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds); - - cmsg = CMSG_FIRSTHDR(&ep_msg); - cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - - unsigned char *ep_fd_ptr = CMSG_DATA(cmsg); - - memcpy(ep_fd_ptr, &uwsgi.emperor_fd, sizeof(int)); - if (num_fds > 1) { - memcpy(ep_fd_ptr + sizeof(int), &uwsgi.emperor_fd_config, sizeof(int)); + int ep_client = accept(uwsgi.emperor_fd_proxy, (struct sockaddr *) &epsun, &epsun_len); + if (ep_client < 0) { + uwsgi_error("uwsgi_master_manage_emperor_proxy()/accept()"); + return; } - if (sendmsg(ep_client, &ep_msg, 0) < 0) { - uwsgi_error("uwsgi_master_manage_emperor_proxy()/sendmsg()"); - } + int num_fds = 1; + if (uwsgi.emperor_fd_config > -1) + num_fds++; - free(ep_msg_control); + struct msghdr ep_msg; + void *ep_msg_control = uwsgi_malloc(CMSG_SPACE(sizeof(int) * num_fds)); + struct iovec ep_iov[2]; + struct cmsghdr *cmsg; - close(ep_client); + ep_iov[0].iov_base = "uwsgi-emperor"; + ep_iov[0].iov_len = 13; + ep_iov[1].iov_base = &num_fds; + ep_iov[1].iov_len = sizeof(int); + + ep_msg.msg_name = NULL; + ep_msg.msg_namelen = 0; + + ep_msg.msg_iov = ep_iov; + ep_msg.msg_iovlen = 2; + + ep_msg.msg_flags = 0; + ep_msg.msg_control = ep_msg_control; + ep_msg.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds); + + cmsg = CMSG_FIRSTHDR(&ep_msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + + unsigned char *ep_fd_ptr = CMSG_DATA(cmsg); + + memcpy(ep_fd_ptr, &uwsgi.emperor_fd, sizeof(int)); + if (num_fds > 1) { + memcpy(ep_fd_ptr + sizeof(int), &uwsgi.emperor_fd_config, sizeof(int)); + } + + if (sendmsg(ep_client, &ep_msg, 0) < 0) { + uwsgi_error("uwsgi_master_manage_emperor_proxy()/sendmsg()"); + } + + free(ep_msg_control); + + close(ep_client); } static void emperor_notify_ready() { - if (!uwsgi.has_emperor) return; - char byte = 1; - if (write(uwsgi.emperor_fd, &byte, 1) != 1) { - uwsgi_error("emperor_notify_ready()/write()"); - } + if (!uwsgi.has_emperor) + return; + char byte = 1; + if (write(uwsgi.emperor_fd, &byte, 1) != 1) { + uwsgi_error("emperor_notify_ready()/write()"); + } } void uwsgi_setup_emperor() { - if (!uwsgi.has_emperor) return; + if (!uwsgi.has_emperor) + return; uwsgi.notify_ready = emperor_notify_ready; } From 338700e95021a8c4f706ff1beeb5426f3f128c15 Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 6 May 2014 14:22:02 +0200 Subject: [PATCH 11/54] completed prototype for Emperor fork-client --- core/emperor.c | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 3a10ab7f..6e184c43 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -1047,12 +1047,23 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *); +static void vassal_fork_server_parser_hook(char *key, uint16_t key_len, char *value, uint16_t value_len, void *data) { + pid_t *pid = (pid_t *) data; + + if (!uwsgi_strncmp(key, key_len, "pid", 3)) { + // ignore negative values + if (value_len > 0 && value[0] == '-') return; + *pid = uwsgi_str_num(value, value_len); + } +} + + /* there are max 3 file descriptors we need to pass to the fork server: n_ui->pipe[1] n_ui->pipe_config[1] - n_ui->on_demand_fd[1] + n_ui->on_demand_fd */ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance *n_ui) { @@ -1078,15 +1089,43 @@ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance } free(vassal_argv); + if (error) { + uwsgi_log_verbose("[uwsgi-emperor] %s: unable to complete fork-server session\n", n_ui->name); + goto end; + } + // bit 0 -> pipe (0x01) + // bit 1 -> config_pipe (0x02) + // bit 2 -> on_demand (0x04) + uint8_t modifier2_mask = 0x01; int fds[8]; int fds_count = 1; + fds[0] = n_ui->pipe[1]; + + // add pipe config ? + if (n_ui->use_config) { + modifier2_mask |= 0x02; + fds[fds_count] = n_ui->pipe_config[1]; + fds_count++; + } + + // add ondemand ? + if (n_ui->on_demand_fd > -1) { + modifier2_mask |= 0x04; + fds[fds_count] = n_ui->on_demand_fd; + fds_count++; + } + + // fix uwsgi header + if (uwsgi_buffer_set_uh(ub, 35, modifier2_mask)) goto end; if (uwsgi_send_fds_and_body(fd, fds, fds_count, ub->buf, ub->pos)) { uwsgi_log_verbose("[uwsgi-emperor] %s: unable to complete fork-server session\n", n_ui->name); goto end; } + uwsgi_buffer_destroy(ub); + // now wait for the response (the pid number) // the response could contain various info, currently we only need the "pid" attribute size_t buf_len = uwsgi.page_size; @@ -1100,17 +1139,19 @@ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance goto end; } + pid_t pid = -1; + uwsgi_hooked_parse(buf, buf_len, vassal_fork_server_parser_hook, &pid); free(buf); // close the connection close(fd); // return the pid to the Emperor - pid_t pid = -1; return pid; end: uwsgi_buffer_destroy(ub); + close(fd); return -1; } From 1219f6fc302193179d63551ae22c2300f323b4f0 Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 6 May 2014 17:28:39 +0200 Subject: [PATCH 12/54] added adopted-vassals concept --- core/emperor.c | 38 ++++++++++++++------- core/fork_server.c | 83 +++++++++++++++++++++++++++++++++++++--------- core/init.c | 6 ++-- core/io.c | 2 ++ core/uwsgi.c | 1 + uwsgi.h | 2 ++ 6 files changed, 102 insertions(+), 30 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 6e184c43..195cae99 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -775,10 +775,12 @@ void emperor_del(struct uwsgi_instance *c_ui) { } // this will destroy the whole uWSGI instance (and workers) - close(c_ui->pipe[0]); + if (c_ui->pipe[0] != -1) close(c_ui->pipe[0]); + if (c_ui->pipe[1] != -1) close(c_ui->pipe[1]); if (c_ui->use_config) { - close(c_ui->pipe_config[0]); + if (c_ui->pipe_config[0] != -1) close(c_ui->pipe_config[0]); + if (c_ui->pipe_config[1] != -1) close(c_ui->pipe_config[1]); } if (uwsgi.vassals_stop_hook) { @@ -810,8 +812,9 @@ void emperor_del(struct uwsgi_instance *c_ui) { close(c_ui->on_demand_fd); } - free(c_ui); + if (c_ui->use_config) free(c_ui->config); + free(c_ui); } void emperor_back_to_ondemand(struct uwsgi_instance *c_ui) { @@ -1023,13 +1026,15 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha n_ui->pipe[0] = -1; n_ui->pipe[1] = -1; + n_ui->pipe_config[0] = -1; + n_ui->pipe_config[1] = -1; + // ok here we check if we need to bind to the specified socket or continue with the activation if (socket_name) { n_ui->on_demand_fd = on_demand_bind(socket_name); if (n_ui->on_demand_fd < 0) { uwsgi_error("emperor_add()/bind()"); - free(n_ui); - c_ui->ui_next = NULL; + emperor_del(n_ui); return; } @@ -1040,8 +1045,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha if (uwsgi_emperor_vassal_start(n_ui)) { // clear the vassal - free(n_ui); - c_ui->ui_next = NULL; + emperor_del(n_ui); } } @@ -1136,7 +1140,7 @@ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance if (ret) { free(buf); uwsgi_log_verbose("[uwsgi-emperor] %s: unable to complete fork-server session\n", n_ui->name); - goto end; + goto end2; } pid_t pid = -1; @@ -1151,6 +1155,7 @@ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance end: uwsgi_buffer_destroy(ub); +end2: close(fd); return -1; } @@ -1184,6 +1189,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { // a new uWSGI instance will start if (uwsgi.emperor_use_fork_server) { // pid can only be > 0 or -1 + n_ui->adopted = 1; pid = emperor_connect_to_fork_server(uwsgi.emperor_use_fork_server, n_ui); } #if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && !defined(__ia64__) @@ -1203,6 +1209,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { n_ui->pid = pid; // close the right side of the pipe close(n_ui->pipe[1]); + n_ui->pipe[1] = -1; /* THE ON-DEMAND file descriptor is left mapped to the emperor to allow fast-respawn // TODO add an option to force closing it // close the "on demand" socket @@ -1213,6 +1220,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { */ if (n_ui->use_config) { close(n_ui->pipe_config[1]); + n_ui->pipe_config[1] = -1; } if (n_ui->use_config) { @@ -1967,7 +1975,7 @@ recheck: has_children = 0; while (ui_current->ui_next) { ui_current = ui_current->ui_next; - if (ui_current->pid > -1) { + if (ui_current->pid > -1 && !ui_current->adopted) { has_children++; } } @@ -2189,6 +2197,9 @@ void emperor_send_stats(int fd) { if (uwsgi_stats_keyval_comma(us, "on_demand", c_ui->socket_name ? c_ui->socket_name : "")) goto end0; + if (uwsgi_stats_keylong_comma(us, "adopted", (unsigned long long) c_ui->adopted)) + goto end0; + if (uwsgi_stats_keylong_comma(us, "uid", (unsigned long long) c_ui->uid)) goto end0; if (uwsgi_stats_keylong_comma(us, "gid", (unsigned long long) c_ui->gid)) @@ -2292,9 +2303,11 @@ end: void uwsgi_emperor_start() { #ifdef __linux__ - if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)) { - uwsgi_error("uwsgi_fork_server()/fork()"); - exit(1); + if (uwsgi.emperor_use_fork_server) { + if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)) { + uwsgi_error("uwsgi_fork_server()/fork()"); + exit(1); + } } #endif @@ -2548,6 +2561,7 @@ static void emperor_notify_ready() { char byte = 1; if (write(uwsgi.emperor_fd, &byte, 1) != 1) { uwsgi_error("emperor_notify_ready()/write()"); + exit(1); } } diff --git a/core/fork_server.c b/core/fork_server.c index ab4852ef..1c452f1e 100644 --- a/core/fork_server.c +++ b/core/fork_server.c @@ -14,6 +14,11 @@ from now on, we can consider the new child as a full-featured vassal */ +static void parse_argv_hook(uint16_t item, char *value, uint16_t vlen, void *data) { + struct uwsgi_string_list **usl = (struct uwsgi_string_list **) data; + uwsgi_string_new_list(usl, uwsgi_concat2n(value, vlen, "", 0)); +} + void uwsgi_fork_server(char *socket) { // map fd 0 to /dev/null to avoid mess uwsgi_remap_fd(0, "/dev/null"); @@ -33,23 +38,52 @@ void uwsgi_fork_server(char *socket) { uwsgi_error("uwsgi_fork_server()/accept()"); continue; } - char buf[4096]; + char hbuf[4]; pid_t ppid = -1; uid_t uid = -1; gid_t gid = -1; - int fds_count = 0; + int fds_count = 8; + size_t remains = 4; // we can receive upto 8 fds (generally from 1 to 3) int fds[8]; - ssize_t len = uwsgi_recv_cred_and_fds(client_fd, buf, 4096, &ppid, &uid, &gid, fds, &fds_count); - uwsgi_log("RET = %d %d %d %d\n", len, ppid, uid, gid); + // we only read 4 bytes header + ssize_t len = uwsgi_recv_cred_and_fds(client_fd, hbuf, remains, &ppid, &uid, &gid, fds, &fds_count); + uwsgi_log("RET = %d %d %d %d fds:%d\n", len, ppid, uid, gid, fds_count); + if (len <= 0) { + uwsgi_error("uwsgi_fork_server()/recvmsg()"); + goto end; + } + remains -= len; + + if (uwsgi_read_nb(client_fd, hbuf + (4-remains), remains, uwsgi.socket_timeout)) { + uwsgi_error("uwsgi_fork_server()/uwsgi_read_nb()"); + goto end; + } + + struct uwsgi_header *uh = (struct uwsgi_header *) hbuf; + // this memory area must be freed in the right place !!! + char *body_argv = uwsgi_malloc(uh->pktsize); + if (uwsgi_read_nb(client_fd, body_argv, uh->pktsize, uwsgi.socket_timeout)) { + free(body_argv); + uwsgi_error("uwsgi_fork_server()/uwsgi_read_nb()"); + goto end; + } pid_t pid = fork(); if (pid < 0) { + free(body_argv); + // close inherited decriptors excluded the passed fds and client_fd + int i; + for(i=0;i 0) { + free(body_argv); + // close inherited decriptors excluded the passed fds and client_fd + int i; + for(i=0;ipos = 4; + if (uwsgi_buffer_append_keynum(ub, "pid", 3, getppid())) exit(1); + // fix uwsgi header + if (uwsgi_buffer_set_uh(ub, 35, 0)) goto end; // send_pid() + if (uwsgi_write_nb(client_fd, ub->buf, ub->pos, uwsgi.socket_timeout)) exit(1); close(client_fd); uwsgi_log("double fork() and reparenting successfull (new pid: %d)\n", getpid()); // now parse the uwsgi packet array and build the argv - uwsgi.new_argc = 6; - // we do not free old uwsgi.argv as it could contains still used pointers - uwsgi_log("%s\n", uwsgi.binary_path); - uwsgi.new_argv = uwsgi_malloc(sizeof(char *) * (uwsgi.argc+1)); - uwsgi.new_argv[0] = uwsgi.binary_path; - uwsgi.new_argv[1] = uwsgi_str("--http-socket"); - uwsgi.new_argv[2] = uwsgi_str(":1717"); - uwsgi.new_argv[3] = uwsgi_str("--master"); - uwsgi.new_argv[4] = uwsgi_str("--processes"); - uwsgi.new_argv[5] = uwsgi_str("8"); - uwsgi.new_argv[6] = NULL; + struct uwsgi_string_list *usl = NULL, *usl_argv = NULL; + uwsgi_hooked_parse_array(body_argv, uh->pktsize, parse_argv_hook, &usl_argv); + free(body_argv); + // build new argc/argv + uwsgi.new_argc = 0; + uwsgi_foreach(usl, usl_argv) { + uwsgi.new_argc++; + } + + uwsgi.new_argv = uwsgi_calloc(sizeof(char *) * (uwsgi.new_argc + 1)); + int counter = 0; + uwsgi_foreach(usl, usl_argv) { + uwsgi.new_argv[counter] = usl->value; + counter++; + } // this is the only step required to have a consistent environment uwsgi.fork_socket = NULL; + // fixup the Emperor communication + uwsgi_check_emperor(); // continue with uWSGI startup return; } diff --git a/core/init.c b/core/init.c index fa5eecc0..48532b28 100644 --- a/core/init.c +++ b/core/init.c @@ -292,9 +292,9 @@ void uwsgi_commandline_config() { uwsgi_log("optind:%d argc:%d\n", optind, uwsgi.argc); #endif - if (optind < uwsgi.argc) { - for (i = optind; i < uwsgi.argc; i++) { - char *lazy = uwsgi.argv[i]; + if (optind < argc) { + for (i = optind; i < argc; i++) { + char *lazy = argv[i]; if (lazy[0] != '[') { uwsgi_opt_load(NULL, lazy, NULL); // manage magic mountpoint diff --git a/core/io.c b/core/io.c index bbe59c39..b123f297 100644 --- a/core/io.c +++ b/core/io.c @@ -1519,9 +1519,11 @@ ssize_t uwsgi_recv_cred_and_fds(int fd, char *buf, size_t buf_len, pid_t *pid, u struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); while(cmsg) { + uwsgi_log("ROUND ROUND\n"); if (cmsg->cmsg_level != SOL_SOCKET) goto next; if (cmsg->cmsg_type == SCM_RIGHTS) { size_t fds_len = cmsg->cmsg_len - ((char *) CMSG_DATA(cmsg) - (char *) cmsg); + uwsgi_log("FDS_LEN = %d\n", fds_len); memcpy(fds, CMSG_DATA(cmsg), fds_len); *fds_count = fds_len/sizeof(int); } diff --git a/core/uwsgi.c b/core/uwsgi.c index 9a2c592e..3d2a3576 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -223,6 +223,7 @@ static struct uwsgi_option uwsgi_base_options[] = { #if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) {"emperor-use-clone", required_argument, 0, "use clone() instead of fork() passing the specified unshare() flags", uwsgi_opt_set_unshare, &uwsgi.emperor_clone, 0}, #endif + {"emperor-use-fork-server", required_argument, 0, "connect to the specified fork server instead of using plain fork() for new vassals", uwsgi_opt_set_str, &uwsgi.emperor_use_fork_server, 0}, #ifdef UWSGI_CAP {"emperor-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0}, {"vassals-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0}, diff --git a/uwsgi.h b/uwsgi.h index 006663f4..b44bac8c 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -4071,6 +4071,8 @@ struct uwsgi_instance { int on_demand_fd; char *socket_name; time_t cursed_at; + + int adopted; }; struct uwsgi_instance *emperor_get_by_fd(int); From e983fae9a40f966dbdeb9392db55bab118460dad Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 6 May 2014 17:46:44 +0200 Subject: [PATCH 13/54] it looks like SUBREAPER works great --- core/emperor.c | 4 ++-- core/fork_server.c | 2 +- core/uwsgi.c | 1 + plugins/http/http.c | 4 ++++ uwsgi.h | 1 + 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 195cae99..29220574 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -1187,7 +1187,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { // TODO pre-start hook // a new uWSGI instance will start - if (uwsgi.emperor_use_fork_server) { + if (uwsgi.emperor_use_fork_server && !uwsgi_string_list_has_item(uwsgi.vassal_fork_base, n_ui->name, strlen(n_ui->name))) { // pid can only be > 0 or -1 n_ui->adopted = 1; pid = emperor_connect_to_fork_server(uwsgi.emperor_use_fork_server, n_ui); @@ -1975,7 +1975,7 @@ recheck: has_children = 0; while (ui_current->ui_next) { ui_current = ui_current->ui_next; - if (ui_current->pid > -1 && !ui_current->adopted) { + if (ui_current->pid > -1) { has_children++; } } diff --git a/core/fork_server.c b/core/fork_server.c index 1c452f1e..d08a1e4e 100644 --- a/core/fork_server.c +++ b/core/fork_server.c @@ -113,7 +113,7 @@ void uwsgi_fork_server(char *socket) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); // leave space for header ub->pos = 4; - if (uwsgi_buffer_append_keynum(ub, "pid", 3, getppid())) exit(1); + if (uwsgi_buffer_append_keynum(ub, "pid", 3, getpid())) exit(1); // fix uwsgi header if (uwsgi_buffer_set_uh(ub, 35, 0)) goto end; // send_pid() diff --git a/core/uwsgi.c b/core/uwsgi.c index 3d2a3576..fba102a9 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -224,6 +224,7 @@ static struct uwsgi_option uwsgi_base_options[] = { {"emperor-use-clone", required_argument, 0, "use clone() instead of fork() passing the specified unshare() flags", uwsgi_opt_set_unshare, &uwsgi.emperor_clone, 0}, #endif {"emperor-use-fork-server", required_argument, 0, "connect to the specified fork server instead of using plain fork() for new vassals", uwsgi_opt_set_str, &uwsgi.emperor_use_fork_server, 0}, + {"vassal-fork-base", required_argument, 0, "use plain fork() for the specified vassal (instead of a fork-server)", uwsgi_opt_add_string_list, &uwsgi.vassal_fork_base, 0}, #ifdef UWSGI_CAP {"emperor-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0}, {"vassals-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0}, diff --git a/plugins/http/http.c b/plugins/http/http.c index a960e1bc..6da2cd85 100644 --- a/plugins/http/http.c +++ b/plugins/http/http.c @@ -205,6 +205,10 @@ int http_headers_parse(struct corerouter_peer *peer) { while (ptr < watermark) { if (*ptr == ' ') { if (uwsgi_buffer_append_keyval(out, "REQUEST_METHOD", 14, base, ptr - base)) return -1; + // on SOURCE METHOD, force raw body + if (!uwsgi_strncmp(base, ptr - base, "SOURCE", 6)) { + hr->raw_body = 1; + } ptr++; found = 1; break; diff --git a/uwsgi.h b/uwsgi.h index b44bac8c..eb9b6ca5 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -2726,6 +2726,7 @@ struct uwsgi_server { int new_argc; char **new_argv; char *emperor_use_fork_server; + struct uwsgi_string_list *vassal_fork_base; }; struct uwsgi_rpc { From 246e106d8551ca95c2f1850695d432b78e892d8b Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 6 May 2014 17:57:37 +0200 Subject: [PATCH 14/54] added support for on_demand and config pipe in fork-server mode --- core/fork_server.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/core/fork_server.c b/core/fork_server.c index d08a1e4e..e88b1284 100644 --- a/core/fork_server.c +++ b/core/fork_server.c @@ -14,11 +14,15 @@ from now on, we can consider the new child as a full-featured vassal */ +#define VASSAL_HAS_CONFIG 0x02 +#define VASSAL_HAS_ON_DEMAND 0x04 + static void parse_argv_hook(uint16_t item, char *value, uint16_t vlen, void *data) { struct uwsgi_string_list **usl = (struct uwsgi_string_list **) data; uwsgi_string_new_list(usl, uwsgi_concat2n(value, vlen, "", 0)); } + void uwsgi_fork_server(char *socket) { // map fd 0 to /dev/null to avoid mess uwsgi_remap_fd(0, "/dev/null"); @@ -49,7 +53,7 @@ void uwsgi_fork_server(char *socket) { // we only read 4 bytes header ssize_t len = uwsgi_recv_cred_and_fds(client_fd, hbuf, remains, &ppid, &uid, &gid, fds, &fds_count); uwsgi_log("RET = %d %d %d %d fds:%d\n", len, ppid, uid, gid, fds_count); - if (len <= 0) { + if (len <= 0 || fds_count < 1) { uwsgi_error("uwsgi_fork_server()/recvmsg()"); goto end; } @@ -89,15 +93,46 @@ void uwsgi_fork_server(char *socket) { goto end; } else { - // close everything excluded the passed fds and client_fd + // close everything excluded 0,1,2, the passed fds and client_fd // set EMPEROR_FD and FD_CONFIG env vars char *uef = uwsgi_num2str(fds[0]); if (setenv("UWSGI_EMPEROR_FD", uef, 1)) { - uwsgi_error("setenv()"); + uwsgi_error("uwsgi_fork_server()/setenv()"); exit(1); } free(uef); + + int pipe_config = -1; + int on_demand = -1; + + if (uh->modifier2 & VASSAL_HAS_CONFIG && fds_count > 1) { + pipe_config = fds[1]; + char *uef = uwsgi_num2str(pipe_config); + if (setenv("UWSGI_EMPEROR_FD_CONFIG", uef, 1)) { + uwsgi_error("uwsgi_fork_server()/setenv()"); + exit(1); + } + free(uef); + } + + if (uh->modifier2 & VASSAL_HAS_ON_DEMAND && fds_count > 1) { + if (pipe_config > -1) { + if (fds_count > 2) { + on_demand = fds[2]; + } + } + else { + on_demand = fds[1]; + } + } // dup the on_demand socket to 0 and close it + if (on_demand > -1) { + if (dup2(on_demand, 0) < 0) { + uwsgi_error("uwsgi_fork_server()/dup2()"); + exit(1); + } + close(on_demand); + } // now fork again and die pid_t new_pid = fork(); From 472ac2dd9dd05dbc0d6631ecc8e2fc8dfd977ddc Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 6 May 2014 18:28:40 +0200 Subject: [PATCH 15/54] fixed double-free --- core/emperor.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 29220574..4503698a 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -804,15 +804,16 @@ void emperor_del(struct uwsgi_instance *c_ui) { uwsgi.emperor_broodlord_count--; } + uwsgi_log("%s socket_name\n", c_ui->socket_name); if (c_ui->socket_name) { free(c_ui->socket_name); } - if (c_ui->on_demand_fd != -1) { + if (c_ui->on_demand_fd > -1) { close(c_ui->on_demand_fd); } - - if (c_ui->use_config) free(c_ui->config); + uwsgi_log("%s %p\n", c_ui->config, c_ui->config); + if (c_ui->config) free(c_ui->config); free(c_ui); } @@ -2020,6 +2021,7 @@ recheck: time_t now = uwsgi_now(); if (diedpid > 0 && ui_current->pid == diedpid) { if (ui_current->status == 0) { + uwsgi_log("OOOOPS\n"); // respawn an accidentally dead instance if its exit code is not UWSGI_EXILE_CODE if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXILE_CODE) { // SAFE @@ -2027,7 +2029,15 @@ recheck: } else { // UNSAFE - emperor_add(ui_current->scanner, ui_current->name, ui_current->last_mod, ui_current->config, ui_current->config_len, ui_current->uid, ui_current->gid, ui_current->socket_name); + char *config = NULL; + if (ui_current->config) { + config = uwsgi_str(ui_current->config); + } + char *socket_name = NULL; + if (ui_current->socket_name) { + socket_name = uwsgi_str(ui_current->socket_name); + } + emperor_add(ui_current->scanner, ui_current->name, ui_current->last_mod, config, ui_current->config_len, ui_current->uid, ui_current->gid, socket_name); emperor_del(ui_current); // temporarily set frequency to 1, so we can eventually fast-restart the instance freq = 1; @@ -2036,9 +2046,6 @@ recheck: } else if (ui_current->status == 1) { // remove 'marked for dead' instance - if (ui_current->config) - free(ui_current->config); - // SAFE emperor_del(ui_current); // temporarily set frequency to 1, so we can eventually fast-restart the instance freq = 1; From cf8580775a66daf331e3b569b6f546d0d677c5a8 Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 6 May 2014 18:32:01 +0200 Subject: [PATCH 16/54] exit_on_reload on by default in fork-server mode --- core/fork_server.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/fork_server.c b/core/fork_server.c index e88b1284..266ffa9f 100644 --- a/core/fork_server.c +++ b/core/fork_server.c @@ -176,6 +176,8 @@ void uwsgi_fork_server(char *socket) { } // this is the only step required to have a consistent environment uwsgi.fork_socket = NULL; + // this avoids the process to re-exec itself + uwsgi.exit_on_reload = 1; // fixup the Emperor communication uwsgi_check_emperor(); // continue with uWSGI startup From da335692a0f58cd134e8be54a200873e4cbf3672 Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 7 May 2014 06:08:49 +0200 Subject: [PATCH 17/54] ported SOURCE management from 2.0.5 --- plugins/http/common.h | 1 + plugins/http/http.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/http/common.h b/plugins/http/common.h index 11667d84..3281b059 100644 --- a/plugins/http/common.h +++ b/plugins/http/common.h @@ -44,6 +44,7 @@ struct uwsgi_http { int headers_timeout; int connect_timeout; + int manage_source; }; struct http_session { diff --git a/plugins/http/http.c b/plugins/http/http.c index 6da2cd85..c7862dce 100644 --- a/plugins/http/http.c +++ b/plugins/http/http.c @@ -62,6 +62,8 @@ struct uwsgi_option http_options[] = { {"http-server-name-as-http-host", required_argument, 0, "force SERVER_NAME to HTTP_HOST", uwsgi_opt_true, &uhttp.server_name_as_http_host, 0}, {"http-headers-timeout", required_argument, 0, "set internal http socket timeout for headers", uwsgi_opt_set_int, &uhttp.headers_timeout, 0}, {"http-connect-timeout", required_argument, 0, "set internal http socket timeout for backend connections", uwsgi_opt_set_int, &uhttp.connect_timeout, 0}, + + {"http-manage-source", optional_argument, 0, "manage the SOURCE HTTP method placing the session in raw mode", uwsgi_opt_true, &uhttp.manage_source, 0}, {0, 0, 0, 0, 0, 0, 0}, }; @@ -206,7 +208,7 @@ int http_headers_parse(struct corerouter_peer *peer) { if (*ptr == ' ') { if (uwsgi_buffer_append_keyval(out, "REQUEST_METHOD", 14, base, ptr - base)) return -1; // on SOURCE METHOD, force raw body - if (!uwsgi_strncmp(base, ptr - base, "SOURCE", 6)) { + if (uhttp.manage_source && !uwsgi_strncmp(base, ptr - base, "SOURCE", 6)) { hr->raw_body = 1; } ptr++; From d3de54ac3fbf183a87869942c9fbc43eb44a0f8a Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 7 May 2014 06:12:58 +0200 Subject: [PATCH 18/54] correctly set pipes to -1 in emperor mode 2 --- core/emperor.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/emperor.c b/core/emperor.c index 4503698a..df3edd67 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -2055,8 +2055,11 @@ recheck: else if (ui_current->status == 2) { event_queue_add_fd_read(uwsgi.emperor_queue, ui_current->on_demand_fd); close(ui_current->pipe[0]); - if (ui_current->use_config) + ui_current->pipe[0] = -1; + if (ui_current->use_config) { close(ui_current->pipe_config[0]); + ui_current->pipe_config[0] = -1; + } ui_current->pid = -1; ui_current->status = 0; ui_current->cursed_at = 0; From 50cbb016b5de9d31078bb6a122f8b87d934df1a0 Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 7 May 2014 06:17:05 +0200 Subject: [PATCH 19/54] refactored push pipe config --- core/emperor.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index df3edd67..b038aec9 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -1222,22 +1222,7 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { if (n_ui->use_config) { close(n_ui->pipe_config[1]); n_ui->pipe_config[1] = -1; - } - - if (n_ui->use_config) { - struct uwsgi_header uh; - uh.modifier1 = 115; - uh.pktsize = n_ui->config_len; - uh.modifier2 = 0; - if (write(n_ui->pipe_config[0], &uh, 4) != 4) { - uwsgi_error("[uwsgi-emperor] write() header config"); - } - else { - if (write(n_ui->pipe_config[0], n_ui->config, n_ui->config_len) != (long) n_ui->config_len) { - uwsgi_error("[uwsgi-emperor] write() config"); - } - } - + emperor_push_config(n_ui); } // once the config is sent we can run hooks (they can fail) From 3a1c5b4ad56ba8140e156f2bd18a16cd1fba3f30 Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 7 May 2014 06:22:41 +0200 Subject: [PATCH 20/54] another refactor for on_demand socket management --- core/emperor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/emperor.c b/core/emperor.c index b038aec9..b06bda60 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -741,7 +741,7 @@ struct uwsgi_instance *emperor_get_by_socket_fd(int fd) { c_ui = c_ui->ui_next; // over engineering... - if (c_ui->on_demand_fd != -1 && c_ui->on_demand_fd == fd) { + if (c_ui->on_demand_fd > -1 && c_ui->on_demand_fd == fd) { return c_ui; } } From a7297782abef24450337e24f39f838ef14dc9caa Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 7 May 2014 06:47:45 +0200 Subject: [PATCH 21/54] implement a form of virtualhosting for http/1.0 icecast2 source requests --- plugins/http/http.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/http/http.c b/plugins/http/http.c index c7862dce..10d399eb 100644 --- a/plugins/http/http.c +++ b/plugins/http/http.c @@ -156,6 +156,10 @@ static int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, size_t hr->session.can_keepalive = 0; } } + else if (peer->key_len == 0 && hr->raw_body && !uwsgi_strncmp("ICE_URL", 7, hh, keylen)) { + peer->key = val; + peer->key_len = vallen; + } #ifdef UWSGI_ZLIB else if (uhttp.auto_gzip && !uwsgi_strncmp("ACCEPT_ENCODING", 15, hh, keylen)) { From e43a8fe8c5f2c4cab32c70bd6616aaf5f0e28955 Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 7 May 2014 06:53:30 +0200 Subject: [PATCH 22/54] improved icecast2 management --- plugins/http/http.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/http/http.c b/plugins/http/http.c index 10d399eb..0a77a942 100644 --- a/plugins/http/http.c +++ b/plugins/http/http.c @@ -156,7 +156,7 @@ static int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, size_t hr->session.can_keepalive = 0; } } - else if (peer->key_len == 0 && hr->raw_body && !uwsgi_strncmp("ICE_URL", 7, hh, keylen)) { + else if (peer->key == uwsgi.hostname && hr->raw_body && !uwsgi_strncmp("ICE_URL", 7, hh, keylen)) { peer->key = val; peer->key_len = vallen; } From 066ef55766db47e7d082904542e8317f78075e14 Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 7 May 2014 11:30:43 +0200 Subject: [PATCH 23/54] allow variables in uwsgi router --- plugins/router_uwsgi/router_uwsgi.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/plugins/router_uwsgi/router_uwsgi.c b/plugins/router_uwsgi/router_uwsgi.c index d4fc556f..9fca0311 100644 --- a/plugins/router_uwsgi/router_uwsgi.c +++ b/plugins/router_uwsgi/router_uwsgi.c @@ -35,7 +35,13 @@ static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct struct uwsgi_header *uh = (struct uwsgi_header *) ur->data; char *addr = ur->data + sizeof(struct uwsgi_header); - + + char **subject = (char **) (((char *)(wsgi_req))+ur->subject); + uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); + + struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, addr, strlen(addr)); + if (!ub_addr) return UWSGI_ROUTE_BREAK; + // mark a route request wsgi_req->via = UWSGI_VIA_ROUTE; @@ -66,18 +72,20 @@ static int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct goto end; } } - if (!uwsgi_offload_request_net_do(wsgi_req, addr, ub)) { + if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) { wsgi_req->via = UWSGI_VIA_OFFLOAD; wsgi_req->status = 202; + uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_BREAK; } } - if (uwsgi_proxy_nb(wsgi_req, addr, ub, remains, uwsgi.socket_timeout)) { - uwsgi_log("error routing request to uwsgi server %s\n", addr); + if (uwsgi_proxy_nb(wsgi_req, ub_addr->buf, ub, remains, uwsgi.socket_timeout)) { + uwsgi_log("error routing request to uwsgi server %s\n", ub_addr->buf); } end: uwsgi_buffer_destroy(ub); + uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_BREAK; } From 7c1bd05dd23d6af7df7b97f735a594855b6a6417 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Thu, 8 May 2014 06:48:30 +0200 Subject: [PATCH 24/54] fixed #620 --- plugins/http/http.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/plugins/http/http.c b/plugins/http/http.c index 0a77a942..9532166f 100644 --- a/plugins/http/http.c +++ b/plugins/http/http.c @@ -152,7 +152,7 @@ static int http_add_uwsgi_header(struct corerouter_peer *peer, char *hh, size_t } else if (!uwsgi_strncmp("CONNECTION", 10, hh, keylen)) { - if (!uwsgi_strnicmp(val, vallen, "close", 5)) { + if (!uwsgi_strnicmp(val, vallen, "close", 5) || !uwsgi_strnicmp(val, vallen, "upgrade", 7)) { hr->session.can_keepalive = 0; } } @@ -806,6 +806,13 @@ ssize_t http_parse(struct corerouter_peer *main_peer) { if (uwsgi_buffer_append(new_peer->out, main_peer->in->buf + hr->headers_size + 1, hr->remains)) return -1; } + if (hr->websockets > 2 && hr->websocket_key_len > 0) { + hr->raw_body = 1; + } + + // on raw body, ensure keepalive is disabled + if (hr->raw_body) hr->session.can_keepalive = 0; + if (hr->session.can_keepalive && hr->content_length == 0) { main_peer->disabled = 1; // stop reading from the client @@ -817,9 +824,7 @@ ssize_t http_parse(struct corerouter_peer *main_peer) { break; } - if (hr->websockets > 2 && hr->websocket_key_len > 0) { - hr->raw_body = 1; - } + new_peer->can_retry = 1; // reset main timeout http_set_timeout(main_peer, uhttp.cr.socket_timeout); From 5ffd5f9bb98c946c15e34ccddebeb78650170bb1 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Thu, 8 May 2014 07:26:31 +0200 Subject: [PATCH 25/54] preapre for psgi early-exec --- plugins/psgi/psgi_plugin.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/plugins/psgi/psgi_plugin.c b/plugins/psgi/psgi_plugin.c index 10cb902b..599ebe98 100644 --- a/plugins/psgi/psgi_plugin.c +++ b/plugins/psgi/psgi_plugin.c @@ -33,6 +33,16 @@ static void uwsgi_opt_early_psgi(char *opt, char *value, void *foobar) { if (!uperl.early_psgi_callable) exit(1); } +EXTERN_C void xs_init (pTHX); +static void uwsgi_opt_early_exec(char *opt, char *value, void *foobar) { + uwsgi_perl_init(); + perl_parse(uperl.main[0], xs_init, 3, uperl.embedding, NULL); + SV *dollar_zero = get_sv("0", GV_ADD); + sv_setsv(dollar_zero, newSVpv(value, strlen(value))); + uwsgi_perl_exec(value); +} + + struct uwsgi_option uwsgi_perl_options[] = { {"psgi", required_argument, 0, "load a psgi app", uwsgi_opt_set_str, &uperl.psgi, 0}, @@ -53,7 +63,8 @@ struct uwsgi_option uwsgi_perl_options[] = { {"plshell-oneshot", no_argument, 0, "run a perl interactive shell (one shot)", uwsgi_opt_plshell, NULL, 0}, {"perl-no-plack", no_argument, 0, "force the use of do instead of Plack::Util::load_psgi", uwsgi_opt_true, &uperl.no_plack, 0}, - {"early-psgi", required_argument, 0, "load a psgi app soon after perl initialization", uwsgi_opt_early_psgi, NULL, UWSGI_OPT_IMMEDIATE}, + {"early-psgi", required_argument, 0, "load a psgi app soon after uWSGI initialization", uwsgi_opt_early_psgi, NULL, UWSGI_OPT_IMMEDIATE}, + {"early-perl-exec", required_argument, 0, "load a perl script soon after uWSGI initialization", uwsgi_opt_early_exec, NULL, UWSGI_OPT_IMMEDIATE}, {0, 0, 0, 0, 0, 0, 0}, }; From eac016a416de19a765bc848fad3817316cdd0d31 Mon Sep 17 00:00:00 2001 From: Unbit Date: Thu, 8 May 2014 09:06:30 +0200 Subject: [PATCH 26/54] force processname in fork-server mode --- core/fork_server.c | 9 +++++++++ core/uwsgi.c | 1 + 2 files changed, 10 insertions(+) diff --git a/core/fork_server.c b/core/fork_server.c index 266ffa9f..232678c4 100644 --- a/core/fork_server.c +++ b/core/fork_server.c @@ -164,16 +164,25 @@ void uwsgi_fork_server(char *socket) { // build new argc/argv uwsgi.new_argc = 0; + size_t procname_len = 1; uwsgi_foreach(usl, usl_argv) { uwsgi.new_argc++; + procname_len += usl->len + 1; } + + char *new_procname = uwsgi_calloc(procname_len); uwsgi.new_argv = uwsgi_calloc(sizeof(char *) * (uwsgi.new_argc + 1)); int counter = 0; uwsgi_foreach(usl, usl_argv) { uwsgi.new_argv[counter] = usl->value; + strcat(new_procname, usl->value); + strcat(new_procname, " "); counter++; } + // fix process name + uwsgi_set_processname(new_procname); + free(new_procname); // this is the only step required to have a consistent environment uwsgi.fork_socket = NULL; // this avoids the process to re-exec itself diff --git a/core/uwsgi.c b/core/uwsgi.c index fba102a9..8151e8f6 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -901,6 +901,7 @@ static struct uwsgi_option uwsgi_base_options[] = { {"close-on-exec2", no_argument, 0, "set close-on-exec on server sockets (could be required for spawning processes in requests)", uwsgi_opt_true, &uwsgi.close_on_exec2, 0}, {"mode", required_argument, 0, "set uWSGI custom mode", uwsgi_opt_set_str, &uwsgi.mode, 0}, {"env", required_argument, 0, "set environment variable", uwsgi_opt_set_env, NULL, 0}, + {"ienv", required_argument, 0, "set environment variable (IMMEDIATE version)", uwsgi_opt_set_env, NULL, UWSGI_OPT_IMMEDIATE}, {"envdir", required_argument, 0, "load a daemontools compatible envdir", uwsgi_opt_add_string_list, &uwsgi.envdirs, 0}, {"early-envdir", required_argument, 0, "load a daemontools compatible envdir ASAP", uwsgi_opt_envdir, NULL, UWSGI_OPT_IMMEDIATE}, {"unenv", required_argument, 0, "unset environment variable", uwsgi_opt_unset_env, NULL, 0}, From c01d6242adbe03742bd4920663cef2bf69aefcbe Mon Sep 17 00:00:00 2001 From: Unbit Date: Thu, 8 May 2014 09:10:31 +0200 Subject: [PATCH 27/54] ansure stdc++ is linked for emperor_mongodb --- plugins/emperor_mongodb/uwsgiplugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/emperor_mongodb/uwsgiplugin.py b/plugins/emperor_mongodb/uwsgiplugin.py index 5d7810de..58b56757 100644 --- a/plugins/emperor_mongodb/uwsgiplugin.py +++ b/plugins/emperor_mongodb/uwsgiplugin.py @@ -5,7 +5,7 @@ NAME='emperor_mongodb' CFLAGS = ['-I/usr/include/mongo','-I/usr/local/include/mongo'] LDFLAGS = [] -LIBS = [] +LIBS = ['-lstdc++'] if not 'UWSGI_MONGODB_NOLIB' in os.environ: LIBS.append('-lmongoclient') LIBS.append('-lboost_thread') From c94aa42a021b1935122e4b37c5042a09d1bb9ef7 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Mon, 12 May 2014 02:33:41 +0200 Subject: [PATCH 28/54] added support for emperor protocol in the fork server --- core/fork_server.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/core/fork_server.c b/core/fork_server.c index 232678c4..18beb88c 100644 --- a/core/fork_server.c +++ b/core/fork_server.c @@ -33,8 +33,27 @@ void uwsgi_fork_server(char *socket) { // automatically receive credentials (TODO make something useful with them, like checking the pid is from the Emperor) if (uwsgi_socket_passcred(fd)) exit(1); + // initialize the event queue + int eq = event_queue_init(); + if (uwsgi.has_emperor) { + event_queue_add_fd_read(eq, uwsgi.emperor_fd); + } + event_queue_add_fd_read(eq, fd); + // now start waiting for connections for(;;) { + int interesting_fd = -1; + int rlen = event_queue_wait(eq, -1, &interesting_fd); + if (rlen <= 0) continue; + if (uwsgi.has_emperor && interesting_fd == uwsgi.emperor_fd) { + char byte; + ssize_t rlen = read(uwsgi.emperor_fd, &byte, 1); + if (rlen > 0) { + uwsgi_log_verbose("received message %d from emperor\n", byte); + } + exit(0); + } + if (interesting_fd != fd) continue; struct sockaddr_un client_src; socklen_t client_src_len = 0; int client_fd = accept(fd, (struct sockaddr *) &client_src, &client_src_len); From 9e7ba112285c39ff8c7c3eb0a6f4975e1e7b2da4 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Mon, 12 May 2014 02:38:36 +0200 Subject: [PATCH 29/54] avoid registering rpc functions too early --- core/rpc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/rpc.c b/core/rpc.c index 8f51b0f6..26e1773c 100644 --- a/core/rpc.c +++ b/core/rpc.c @@ -7,6 +7,11 @@ int uwsgi_register_rpc(char *name, struct uwsgi_plugin *plugin, uint8_t args, vo struct uwsgi_rpc *urpc; int ret = -1; + if (!uwsgi.workers || !uwsgi.shared || !uwsgi.rpc_table_lock) { + uwsgi_log("RPC subsystem still not initialized\n"); + return -1; + } + if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) { uwsgi_log("only the master and the workers can register RPC functions\n"); return -1; From 9e618ee105c177a5cf018d0fdb097dc3986353fe Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Mon, 12 May 2014 03:05:33 +0200 Subject: [PATCH 30/54] implemented (early) shared per interpreter --- plugins/psgi/psgi.h | 2 ++ plugins/psgi/psgi_loader.c | 14 ++++++++------ plugins/psgi/psgi_plugin.c | 27 +++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/plugins/psgi/psgi.h b/plugins/psgi/psgi.h index 765534c1..f204b80a 100644 --- a/plugins/psgi/psgi.h +++ b/plugins/psgi/psgi.h @@ -70,6 +70,8 @@ struct uwsgi_perl { SV **early_psgi_callable; char *early_psgi_app_name; + + PerlInterpreter *early_interpreter; }; void init_perl_embedded_module(void); diff --git a/plugins/psgi/psgi_loader.c b/plugins/psgi/psgi_loader.c index 5d487b55..27b0280e 100644 --- a/plugins/psgi/psgi_loader.c +++ b/plugins/psgi/psgi_loader.c @@ -337,11 +337,13 @@ int init_psgi_app(struct wsgi_request *wsgi_req, char *app, uint16_t app_len, Pe if (!interpreters) goto clear2; callables = uwsgi_calloc(sizeof(SV *) * uwsgi.threads); - uperl.tmp_streaming_stash = uwsgi_calloc(sizeof(HV *) * uwsgi.threads); - uperl.tmp_input_stash = uwsgi_calloc(sizeof(HV *) * uwsgi.threads); - uperl.tmp_error_stash = uwsgi_calloc(sizeof(HV *) * uwsgi.threads); - uperl.tmp_stream_responder = uwsgi_calloc(sizeof(CV *) * uwsgi.threads); - uperl.tmp_psgix_logger = uwsgi_calloc(sizeof(CV *) * uwsgi.threads); + if (!uperl.early_interpreter) { + uperl.tmp_streaming_stash = uwsgi_calloc(sizeof(HV *) * uwsgi.threads); + uperl.tmp_input_stash = uwsgi_calloc(sizeof(HV *) * uwsgi.threads); + uperl.tmp_error_stash = uwsgi_calloc(sizeof(HV *) * uwsgi.threads); + uperl.tmp_stream_responder = uwsgi_calloc(sizeof(CV *) * uwsgi.threads); + uperl.tmp_psgix_logger = uwsgi_calloc(sizeof(CV *) * uwsgi.threads); + } for(i=0;i Date: Mon, 12 May 2014 03:13:21 +0200 Subject: [PATCH 31/54] added anot for TODO impkementations in the fork server --- core/fork_server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/fork_server.c b/core/fork_server.c index 18beb88c..4cd35cfb 100644 --- a/core/fork_server.c +++ b/core/fork_server.c @@ -112,7 +112,7 @@ void uwsgi_fork_server(char *socket) { goto end; } else { - // close everything excluded 0,1,2, the passed fds and client_fd + // TODO close everything excluded 0,1,2, the passed fds and client_fd // set EMPEROR_FD and FD_CONFIG env vars char *uef = uwsgi_num2str(fds[0]); if (setenv("UWSGI_EMPEROR_FD", uef, 1)) { From 587114651912e2af746528fc3048919eaa2f4e9d Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 13 May 2014 12:49:58 +0200 Subject: [PATCH 32/54] ensure SIGPIPE is ignored in gevent mode --- plugins/gevent/gevent.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/gevent/gevent.c b/plugins/gevent/gevent.c index 0debbdaf..15782fcf 100644 --- a/plugins/gevent/gevent.c +++ b/plugins/gevent/gevent.c @@ -345,6 +345,9 @@ static void gil_gevent_release() { static void gevent_loop() { + // ensure SIGPIPE is ignored + signal(SIGPIPE, SIG_IGN); + if (!uwsgi.has_threads && uwsgi.mywid == 1) { uwsgi_log("!!! Running gevent without threads IS NOT recommended, enable them with --enable-threads !!!\n"); } From cfbb213e6d12d302fabcec7b3ce2b952dc1a9203 Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 13 May 2014 13:26:00 +0200 Subject: [PATCH 33/54] fixed #623 --- plugins/http/common.h | 2 +- plugins/http/http.c | 2 +- plugins/http/https.c | 9 ++++++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/plugins/http/common.h b/plugins/http/common.h index 3281b059..d5052b95 100644 --- a/plugins/http/common.h +++ b/plugins/http/common.h @@ -157,7 +157,7 @@ void hr_session_ssl_close(struct corerouter_session *); ssize_t hr_ssl_read(struct corerouter_peer *); ssize_t hr_ssl_write(struct corerouter_peer *); -int hr_https_add_vars(struct http_session *, struct uwsgi_buffer *); +int hr_https_add_vars(struct http_session *, struct corerouter_peer *, struct uwsgi_buffer *); void hr_setup_ssl(struct http_session *, struct uwsgi_gateway_socket *); #endif diff --git a/plugins/http/http.c b/plugins/http/http.c index 9532166f..84be5c2e 100644 --- a/plugins/http/http.c +++ b/plugins/http/http.c @@ -334,7 +334,7 @@ int http_headers_parse(struct corerouter_peer *peer) { } #ifdef UWSGI_SSL - if (hr_https_add_vars(hr, out)) return -1; + if (hr_https_add_vars(hr, peer, out)) return -1; #endif // REMOTE_ADDR diff --git a/plugins/http/https.c b/plugins/http/https.c index 8021728f..4ea29680 100644 --- a/plugins/http/https.c +++ b/plugins/http/https.c @@ -166,10 +166,17 @@ void uwsgi_opt_http_to_https(char *opt, char *value, void *cr) { ucr->has_sockets++; } -int hr_https_add_vars(struct http_session *hr, struct uwsgi_buffer *out) { +int hr_https_add_vars(struct http_session *hr, struct corerouter_peer *peer, struct uwsgi_buffer *out) { // HTTPS (adapted from nginx) if (hr->session.ugs->mode == UWSGI_HTTP_SSL) { if (uwsgi_buffer_append_keyval(out, "HTTPS", 5, "on", 2)) return -1; +#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME + const char *servername = SSL_get_servername(hr->ssl, TLSEXT_NAMETYPE_host_name); + if (servername) { + peer->key = (char *) servername; + peer->key_len = strlen(servername); + } +#endif hr->ssl_client_cert = SSL_get_peer_certificate(hr->ssl); if (hr->ssl_client_cert) { X509_NAME *name = X509_get_subject_name(hr->ssl_client_cert); From 7681a40d882ad6b5a15072b6416472b14ec77fa9 Mon Sep 17 00:00:00 2001 From: Unbit Date: Tue, 13 May 2014 19:37:10 +0200 Subject: [PATCH 34/54] fixed #622 --- core/master.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/master.c b/core/master.c index b5a81dd8..0bdcaa17 100644 --- a/core/master.c +++ b/core/master.c @@ -964,6 +964,11 @@ next: if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_FAILED_APP_CODE) { uwsgi_log("OOPS ! failed loading app in worker %d (pid %d) :( trying again...\n", thewid, (int) diedpid); + if (uwsgi.lazy_apps && uwsgi.need_app) { + uwsgi_log_verbose("need-app requested, destroying the instance...\n"); + kill_them_all(0); + continue; + } } else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_DE_HIJACKED_CODE) { uwsgi_log("...restoring worker %d (pid: %d)...\n", thewid, (int) diedpid); From 0dffa344b4ddf609b68d5f0ec77766fa722d8a74 Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 14 May 2014 10:45:49 +0000 Subject: [PATCH 35/54] various sharedarea improvements --- core/sharedarea.c | 62 +++++++++++++++++-- plugins/python/uwsgi_pymodule.c | 105 +++++++++++++++++++++++++++++--- uwsgi.h | 1 + 3 files changed, 157 insertions(+), 11 deletions(-) diff --git a/core/sharedarea.c b/core/sharedarea.c index fcb94ce8..cfbbba93 100644 --- a/core/sharedarea.c +++ b/core/sharedarea.c @@ -269,6 +269,27 @@ static struct uwsgi_sharedarea *announce_sa(struct uwsgi_sharedarea *sa) { return sa; } + +struct uwsgi_sharedarea *uwsgi_sharedarea_init_fd(int fd, uint64_t len, off_t offset) { + int id = uwsgi_sharedarea_new_id(); + uwsgi.sharedareas[id] = uwsgi_calloc_shared(sizeof(struct uwsgi_sharedarea)); + uwsgi.sharedareas[id]->area = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset); + if (uwsgi.sharedareas[id]->area == MAP_FAILED) { + uwsgi_error("uwsgi_sharedarea_init_fd()/mmap()"); + exit(1); + } + uwsgi.sharedareas[id]->id = id; + uwsgi.sharedareas[id]->fd = fd; + uwsgi.sharedareas[id]->pages = len / uwsgi.page_size; + if (len % uwsgi.page_size != 0) uwsgi.sharedareas[id]->pages++; + uwsgi.sharedareas[id]->max_pos = len-1; + char *id_str = uwsgi_num2str(id); + uwsgi.sharedareas[id]->lock = uwsgi_rwlock_init(uwsgi_concat2("sharedarea", id_str)); + free(id_str); + return announce_sa(uwsgi.sharedareas[id]); +} + + struct uwsgi_sharedarea *uwsgi_sharedarea_init(int pages) { int id = uwsgi_sharedarea_new_id(); uwsgi.sharedareas[id] = uwsgi_calloc_shared(uwsgi.page_size * (pages + 1)); @@ -304,24 +325,41 @@ struct uwsgi_sharedarea *uwsgi_sharedarea_init_keyval(char *arg) { char *s_fd = NULL; char *s_ptr = NULL; char *s_size = NULL; + char *s_offset = NULL; if (uwsgi_kvlist_parse(arg, strlen(arg), ',', '=', "pages", &s_pages, "file", &s_file, "fd", &s_fd, "ptr", &s_ptr, "size", &s_size, + "offset", &s_offset, NULL)) { uwsgi_log("invalid sharedarea keyval syntax\n"); exit(1); } uint64_t len = 0; + off_t offset = 0; int pages = 0; if (s_size) { - len = uwsgi_n64(s_size); + if (strlen(s_size) > 2 && s_size[0] == '0' && s_size[1] == 'x') { + len = strtoul(s_size+2, NULL, 16); + } + else { + len = uwsgi_n64(s_size); + } pages = len / uwsgi.page_size; if (len % uwsgi.page_size != 0) pages++; } + + if (s_offset) { + if (strlen(s_offset) > 2 && s_offset[0] == '0' && s_offset[1] == 'x') { + offset = strtoul(s_offset+2, NULL, 16); + } + else { + offset = uwsgi_n64(s_offset); + } + } if (s_pages) { pages = atoi(s_pages); @@ -329,27 +367,43 @@ struct uwsgi_sharedarea *uwsgi_sharedarea_init_keyval(char *arg) { char *area = NULL; struct uwsgi_sharedarea *sa = NULL; + + int fd = -1; if (s_file) { + fd = open(s_file, O_RDWR|O_SYNC); + if (fd < 0) { + uwsgi_error_open(s_file); + exit(1); + } } else if (s_fd) { + fd = atoi(s_fd); } else if (s_ptr) { } if (pages) { - if (!area) { - sa = uwsgi_sharedarea_init(pages); + if (fd > -1) { + sa = uwsgi_sharedarea_init_fd(fd, len, offset); + } + else if (area) { + sa = uwsgi_sharedarea_init_ptr(area, len); } else { - uwsgi_sharedarea_init_ptr(area, len); + sa = uwsgi_sharedarea_init(pages); } } + else { + uwsgi_log("you need to set a size for a sharedarea !!! [%s]\n", arg); + exit(1); + } if (s_pages) free(s_pages); if (s_file) free(s_file); if (s_fd) free(s_fd); if (s_ptr) free(s_ptr); if (s_size) free(s_size); + if (s_offset) free(s_offset); return sa; } diff --git a/plugins/python/uwsgi_pymodule.c b/plugins/python/uwsgi_pymodule.c index 08e69678..fb0bfd6d 100644 --- a/plugins/python/uwsgi_pymodule.c +++ b/plugins/python/uwsgi_pymodule.c @@ -1426,7 +1426,7 @@ PyObject *py_uwsgi_sharedarea_inc64(PyObject * self, PyObject * args) { uint64_t pos = 0; int64_t value = 1; - if (!PyArg_ParseTuple(args, "il|l:sharedarea_inc64", &id, &pos, &value)) { + if (!PyArg_ParseTuple(args, "iL|l:sharedarea_inc64", &id, &pos, &value)) { return NULL; } @@ -1443,12 +1443,56 @@ PyObject *py_uwsgi_sharedarea_inc64(PyObject * self, PyObject * args) { } +PyObject *py_uwsgi_sharedarea_write32(PyObject * self, PyObject * args) { + int id; + uint64_t pos = 0; + int32_t value = 0; + + if (!PyArg_ParseTuple(args, "iLI:sharedarea_write32", &id, &pos, &value)) { + return NULL; + } + + UWSGI_RELEASE_GIL + int ret = uwsgi_sharedarea_write32(id, pos, &value); + UWSGI_GET_GIL + + if (ret) { + return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_write32()"); + } + + Py_INCREF(Py_None); + return Py_None; +} + +PyObject *py_uwsgi_sharedarea_write16(PyObject * self, PyObject * args) { + int id; + uint64_t pos = 0; + int16_t value = 0; + + if (!PyArg_ParseTuple(args, "iLI:sharedarea_write16", &id, &pos, &value)) { + return NULL; + } + + UWSGI_RELEASE_GIL + int ret = uwsgi_sharedarea_write16(id, pos, &value); + UWSGI_GET_GIL + + if (ret) { + return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_write16()"); + } + + Py_INCREF(Py_None); + return Py_None; +} + + + PyObject *py_uwsgi_sharedarea_write64(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int64_t value = 0; - if (!PyArg_ParseTuple(args, "ill:sharedarea_write64", &id, &pos, &value)) { + if (!PyArg_ParseTuple(args, "iLL:sharedarea_write64", &id, &pos, &value)) { return NULL; } @@ -1470,7 +1514,7 @@ PyObject *py_uwsgi_sharedarea_write(PyObject * self, PyObject * args) { char *value; Py_ssize_t value_len = 0; - if (!PyArg_ParseTuple(args, "ils#:sharedarea_write", &id, &pos, &value, &value_len)) { + if (!PyArg_ParseTuple(args, "iLs#:sharedarea_write", &id, &pos, &value, &value_len)) { return NULL; } @@ -1570,7 +1614,7 @@ PyObject *py_uwsgi_sharedarea_write8(PyObject * self, PyObject * args) { uint64_t pos = 0; int8_t value; - if (!PyArg_ParseTuple(args, "ilb:sharedarea_write8", &id, &pos, &value)) { + if (!PyArg_ParseTuple(args, "iLb:sharedarea_write8", &id, &pos, &value)) { return NULL; } @@ -1592,7 +1636,7 @@ PyObject *py_uwsgi_sharedarea_read64(PyObject * self, PyObject * args) { uint64_t pos = 0; int64_t value; - if (!PyArg_ParseTuple(args, "il:sharedarea_read64", &id, &pos)) { + if (!PyArg_ParseTuple(args, "iL:sharedarea_read64", &id, &pos)) { return NULL; } @@ -1608,12 +1652,55 @@ PyObject *py_uwsgi_sharedarea_read64(PyObject * self, PyObject * args) { } +PyObject *py_uwsgi_sharedarea_read32(PyObject * self, PyObject * args) { + int id; + uint64_t pos = 0; + int32_t value; + + if (!PyArg_ParseTuple(args, "iL:sharedarea_read32", &id, &pos)) { + return NULL; + } + + UWSGI_RELEASE_GIL + int ret = uwsgi_sharedarea_read32(id, pos, &value); + UWSGI_GET_GIL + + if (ret) { + return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read32()"); + } + + return PyInt_FromLong(value); + +} + +PyObject *py_uwsgi_sharedarea_read16(PyObject * self, PyObject * args) { + int id; + uint64_t pos = 0; + int16_t value; + + if (!PyArg_ParseTuple(args, "iL:sharedarea_read16", &id, &pos)) { + return NULL; + } + + UWSGI_RELEASE_GIL + int ret = uwsgi_sharedarea_read16(id, pos, &value); + UWSGI_GET_GIL + + if (ret) { + return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read16()"); + } + + return PyInt_FromLong(value); + +} + + PyObject *py_uwsgi_sharedarea_read8(PyObject * self, PyObject * args) { int id; uint64_t pos = 0; int8_t byte; - if (!PyArg_ParseTuple(args, "il:sharedarea_read8", &id, &pos)) { + if (!PyArg_ParseTuple(args, "iL:sharedarea_read8", &id, &pos)) { return NULL; } @@ -1633,7 +1720,7 @@ PyObject *py_uwsgi_sharedarea_read(PyObject * self, PyObject * args) { uint64_t pos = 0; uint64_t len = 0; - if (!PyArg_ParseTuple(args, "il|l:sharedarea_read", &id, &pos, &len)) { + if (!PyArg_ParseTuple(args, "iL|L:sharedarea_read", &id, &pos, &len)) { return NULL; } @@ -2459,6 +2546,10 @@ static PyMethodDef uwsgi_sa_methods[] = { {"sharedarea_writelong", py_uwsgi_sharedarea_write64, METH_VARARGS, ""}, {"sharedarea_read64", py_uwsgi_sharedarea_read64, METH_VARARGS, ""}, {"sharedarea_write64", py_uwsgi_sharedarea_write64, METH_VARARGS, ""}, + {"sharedarea_read32", py_uwsgi_sharedarea_read32, METH_VARARGS, ""}, + {"sharedarea_write32", py_uwsgi_sharedarea_write32, METH_VARARGS, ""}, + {"sharedarea_read16", py_uwsgi_sharedarea_read16, METH_VARARGS, ""}, + {"sharedarea_write16", py_uwsgi_sharedarea_write16, METH_VARARGS, ""}, {"sharedarea_inclong", py_uwsgi_sharedarea_inc64, METH_VARARGS, ""}, {"sharedarea_inc64", py_uwsgi_sharedarea_inc64, METH_VARARGS, ""}, {"sharedarea_rlock", py_uwsgi_sharedarea_rlock, METH_VARARGS, ""}, diff --git a/uwsgi.h b/uwsgi.h index eb9b6ca5..30f80640 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -4734,6 +4734,7 @@ void uwsgi_sharedareas_init(); struct uwsgi_sharedarea *uwsgi_sharedarea_init(int); struct uwsgi_sharedarea *uwsgi_sharedarea_init_ptr(char *, uint64_t); +struct uwsgi_sharedarea *uwsgi_sharedarea_init_fd(int, uint64_t, off_t); int64_t uwsgi_sharedarea_read(int, uint64_t, char *, uint64_t); int uwsgi_sharedarea_write(int, uint64_t, char *, uint64_t); From 154d17ec2bd67ccf2e008a0731747a0ed09cc057 Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 14 May 2014 11:33:18 +0000 Subject: [PATCH 36/54] correctly manage 64bit sharedarea numbers on 32bit systems --- plugins/python/uwsgi_pymodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/python/uwsgi_pymodule.c b/plugins/python/uwsgi_pymodule.c index fb0bfd6d..ecb6aad2 100644 --- a/plugins/python/uwsgi_pymodule.c +++ b/plugins/python/uwsgi_pymodule.c @@ -1648,7 +1648,7 @@ PyObject *py_uwsgi_sharedarea_read64(PyObject * self, PyObject * args) { return PyErr_Format(PyExc_ValueError, "error calling uwsgi_sharedarea_read64()"); } - return PyLong_FromLong(value); + return PyLong_FromLongLong(value); } From 34349c39feb2b6b47bb05e0c32a24918a5ef8469 Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 14 May 2014 15:24:37 +0200 Subject: [PATCH 37/54] added UWSGI_GO_CHEAP --- core/master.c | 3 +++ uwsgi.h | 1 + 2 files changed, 4 insertions(+) diff --git a/core/master.c b/core/master.c index 0bdcaa17..bf079203 100644 --- a/core/master.c +++ b/core/master.c @@ -984,6 +984,9 @@ next: reap_them_all(0); continue; } + else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_GO_CHEAP) { + uwsgi.workers[thewid].cheaped = 1; + } else if (uwsgi.workers[thewid].manage_next_request) { if (WIFSIGNALED(waitpid_status)) { uwsgi_log("DAMN ! worker %d (pid: %d) died, killed by signal %d :( trying respawn ...\n", thewid, (int) diedpid, (int) WTERMSIG(waitpid_status)); diff --git a/uwsgi.h b/uwsgi.h index 30f80640..925c3435 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -897,6 +897,7 @@ struct uwsgi_opt { #define UWSGI_EXCEPTION_CODE 5 #define UWSGI_QUIET_CODE 29 #define UWSGI_BRUTAL_RELOAD_CODE 31 +#define UWSGI_GO_CHEAP 15 #define MAX_VARS 64 From 1bb0f8fcb8a031460620f3a91e57e38be46a9757 Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 14 May 2014 15:34:08 +0200 Subject: [PATCH 38/54] inform user about UWSGI_GO_CHEAP --- core/master.c | 1 + 1 file changed, 1 insertion(+) diff --git a/core/master.c b/core/master.c index bf079203..4573a404 100644 --- a/core/master.c +++ b/core/master.c @@ -985,6 +985,7 @@ next: continue; } else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_GO_CHEAP) { + uwsgi_log("worker %d asked for cheap mode (pid: %d)...\n", thewid, (int) diedpid); uwsgi.workers[thewid].cheaped = 1; } else if (uwsgi.workers[thewid].manage_next_request) { From cb110260c3e764e46937fcfcbb10d630426f0acc Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 14 May 2014 15:35:06 +0200 Subject: [PATCH 39/54] inform user about UWSGI_GO_CHEAP_CODE --- core/master.c | 2 +- uwsgi.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/master.c b/core/master.c index 4573a404..ba192db5 100644 --- a/core/master.c +++ b/core/master.c @@ -984,7 +984,7 @@ next: reap_them_all(0); continue; } - else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_GO_CHEAP) { + else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_GO_CHEAP_CODE) { uwsgi_log("worker %d asked for cheap mode (pid: %d)...\n", thewid, (int) diedpid); uwsgi.workers[thewid].cheaped = 1; } diff --git a/uwsgi.h b/uwsgi.h index 925c3435..4dca192c 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -897,7 +897,7 @@ struct uwsgi_opt { #define UWSGI_EXCEPTION_CODE 5 #define UWSGI_QUIET_CODE 29 #define UWSGI_BRUTAL_RELOAD_CODE 31 -#define UWSGI_GO_CHEAP 15 +#define UWSGI_GO_CHEAP_CODE 15 #define MAX_VARS 64 From f56f16788b2f45709b452a8fcb0bf2ea0ab05203 Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 14 May 2014 18:39:10 +0200 Subject: [PATCH 40/54] prepare for vassal's attributes --- uwsgi.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/uwsgi.h b/uwsgi.h index 4dca192c..671ede2e 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -4075,6 +4075,9 @@ struct uwsgi_instance { time_t cursed_at; int adopted; + + // uWSGI 2.1 (vassal's attributes) + struct uwsgi_dyn_dict *attrs; }; struct uwsgi_instance *emperor_get_by_fd(int); From e61c2699f6a7974dffc11b6b4ed2b65bfa241f9c Mon Sep 17 00:00:00 2001 From: Unbit Date: Fri, 16 May 2014 05:11:04 +0200 Subject: [PATCH 41/54] generic vassal's attributes logic --- core/emperor.c | 25 +++++++++++++++++++++++++ core/uwsgi.c | 2 ++ uwsgi.h | 1 + 3 files changed, 28 insertions(+) diff --git a/core/emperor.c b/core/emperor.c index b06bda60..78ae70c2 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -815,6 +815,13 @@ void emperor_del(struct uwsgi_instance *c_ui) { uwsgi_log("%s %p\n", c_ui->config, c_ui->config); if (c_ui->config) free(c_ui->config); + struct uwsgi_dyn_dict *attr = c_ui->attrs; + while(attr) { + struct uwsgi_dyn_dict *tmp = attr; + attr = attr->next; + free(tmp); + } + free(c_ui); } @@ -2400,6 +2407,24 @@ next: } +int uwsgi_emperor_simple_do_with_attrs(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid, char *socket_name, struct uwsgi_dyn_dict *attrs) { + uwsgi_emperor_simple_do(ues, name, config, ts, uid, gid, socket_name); + struct uwsgi_instance *ui_current = emperor_get(name); + if (!ui_current) return -1; + + // if the instance has attrs mapped, let's free them + if (ui_current->attrs) { + struct uwsgi_dyn_dict *attr = ui_current->attrs; + while(attr) { + struct uwsgi_dyn_dict *tmp = attr; + attr = attr->next; + free(tmp); + } + } + ui_current->attrs = attrs; + return 0; +} + void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid, char *socket_name) { if (!uwsgi_emperor_is_valid(name)) diff --git a/core/uwsgi.c b/core/uwsgi.c index 8151e8f6..6523f790 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -230,6 +230,8 @@ static struct uwsgi_option uwsgi_base_options[] = { {"vassals-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0}, {"vassal-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0}, #endif + {"emperor-collect-attribute", no_argument, 0, "collect the specified vassal attribute from imperial monitors", uwsgi_opt_add_string_list, &uwsgi.emperor_collect_attributes, 0}, + {"emperor-collect-attr", no_argument, 0, "collect the specified vassal attribute from imperial monitors", uwsgi_opt_add_string_list, &uwsgi.emperor_collect_attributes, 0}, {"imperial-monitor-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0}, {"imperial-monitors-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0}, {"vassals-inherit", required_argument, 0, "add config templates to vassals config (uses --inherit)", uwsgi_opt_add_string_list, &uwsgi.vassals_templates, 0}, diff --git a/uwsgi.h b/uwsgi.h index 671ede2e..78524968 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -2728,6 +2728,7 @@ struct uwsgi_server { char **new_argv; char *emperor_use_fork_server; struct uwsgi_string_list *vassal_fork_base; + struct uwsgi_string_list *emperor_collect_attributes; }; struct uwsgi_rpc { From ef8d9d6145d9d695f34ef789a96596bd27ff893b Mon Sep 17 00:00:00 2001 From: Unbit Date: Fri, 16 May 2014 05:27:52 +0200 Subject: [PATCH 42/54] added api for emperor attributes --- core/emperor.c | 51 ++++++++++++++++++---- plugins/emperor_mongodb/emperor_mongodb.cc | 12 ++++- uwsgi.h | 1 + 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 78ae70c2..8a1dc2aa 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -804,7 +804,6 @@ void emperor_del(struct uwsgi_instance *c_ui) { uwsgi.emperor_broodlord_count--; } - uwsgi_log("%s socket_name\n", c_ui->socket_name); if (c_ui->socket_name) { free(c_ui->socket_name); } @@ -812,13 +811,14 @@ void emperor_del(struct uwsgi_instance *c_ui) { if (c_ui->on_demand_fd > -1) { close(c_ui->on_demand_fd); } - uwsgi_log("%s %p\n", c_ui->config, c_ui->config); if (c_ui->config) free(c_ui->config); struct uwsgi_dyn_dict *attr = c_ui->attrs; while(attr) { struct uwsgi_dyn_dict *tmp = attr; attr = attr->next; + if (tmp->key) free(tmp->key); + if (tmp->value) free(tmp->value); free(tmp); } @@ -2004,16 +2004,12 @@ recheck: } } - if (diedpid > 0) { - uwsgi_log("DIEDPID = %d\n", diedpid); - } ui_current = ui; while (ui_current->ui_next) { ui_current = ui_current->ui_next; time_t now = uwsgi_now(); if (diedpid > 0 && ui_current->pid == diedpid) { if (ui_current->status == 0) { - uwsgi_log("OOOOPS\n"); // respawn an accidentally dead instance if its exit code is not UWSGI_EXILE_CODE if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXILE_CODE) { // SAFE @@ -2210,6 +2206,31 @@ void emperor_send_stats(int fd) { if (uwsgi_stats_keyval_comma(us, "monitor", c_ui->scanner->arg)) goto end0; + if (uwsgi_stats_key(us, "attrs")) + goto end0; + + if (uwsgi_stats_list_open(us)) + goto end0; + + struct uwsgi_dyn_dict *attrs = c_ui->attrs; + while(attrs) { + if (attrs->next) { + if (uwsgi_stats_keyval_comma(us, attrs->key, attrs->value)) + goto end0; + } + else { + if (uwsgi_stats_keyval(us, attrs->key, attrs->value)) + goto end0; + } + attrs = attrs->next; + } + + if (uwsgi_stats_list_close(us)) + goto end0; + + if (uwsgi_stats_comma(us)) + goto end0; + if (uwsgi_stats_keylong(us, "respawns", (unsigned long long) c_ui->respawns)) goto end0; @@ -2407,10 +2428,21 @@ next: } -int uwsgi_emperor_simple_do_with_attrs(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid, char *socket_name, struct uwsgi_dyn_dict *attrs) { +void uwsgi_emperor_simple_do_with_attrs(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid, char *socket_name, struct uwsgi_dyn_dict *attrs) { uwsgi_emperor_simple_do(ues, name, config, ts, uid, gid, socket_name); struct uwsgi_instance *ui_current = emperor_get(name); - if (!ui_current) return -1; + // free attrs ? + if (!ui_current) { + struct uwsgi_dyn_dict *attr = attrs; + while(attr) { + struct uwsgi_dyn_dict *tmp = attr; + attr = attr->next; + if (tmp->key) free(tmp->key); + if (tmp->value) free(tmp->value); + free(tmp); + } + return; + } // if the instance has attrs mapped, let's free them if (ui_current->attrs) { @@ -2418,11 +2450,12 @@ int uwsgi_emperor_simple_do_with_attrs(struct uwsgi_emperor_scanner *ues, char * while(attr) { struct uwsgi_dyn_dict *tmp = attr; attr = attr->next; + if (tmp->key) free(tmp->key); + if (tmp->value) free(tmp->value); free(tmp); } } ui_current->attrs = attrs; - return 0; } void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid, char *socket_name) { diff --git a/plugins/emperor_mongodb/emperor_mongodb.cc b/plugins/emperor_mongodb/emperor_mongodb.cc index 449f5d34..f6ef1ccb 100644 --- a/plugins/emperor_mongodb/emperor_mongodb.cc +++ b/plugins/emperor_mongodb/emperor_mongodb.cc @@ -76,7 +76,17 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues const char *socket_name = p.getStringField("socket"); if (strlen(socket_name) == 0) socket_name = NULL; - uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name); + struct uwsgi_dyn_dict *attrs = NULL; + char *attr_key = NULL; + char *attr_value = NULL; + + if (attrs) { + // attrs will be freed in case of error + uwsgi_emperor_simple_do_with_attrs(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name, attrs); + } + else { + uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name); + } } diff --git a/uwsgi.h b/uwsgi.h index 78524968..33f1e9b5 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -4167,6 +4167,7 @@ void uwsgi_master_cleanup_hooks(void); pid_t uwsgi_daemonize2(); void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *, char *, char *, time_t, uid_t, gid_t, char *); +void uwsgi_emperor_simple_do_with_attrs(struct uwsgi_emperor_scanner *, char *, char *, time_t, uid_t, gid_t, char *, struct uwsgi_dyn_dict *); #if defined(__linux__) #define UWSGI_ELF From 4d6daded292585fa398ed2a8ab705ef50f39dbdc Mon Sep 17 00:00:00 2001 From: Unbit Date: Fri, 16 May 2014 05:35:15 +0200 Subject: [PATCH 43/54] implemented attributes in mongodb imperial monitor --- core/emperor.c | 3 --- plugins/emperor_mongodb/emperor_mongodb.cc | 13 +++++++++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 8a1dc2aa..5aae6ef1 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -817,7 +817,6 @@ void emperor_del(struct uwsgi_instance *c_ui) { while(attr) { struct uwsgi_dyn_dict *tmp = attr; attr = attr->next; - if (tmp->key) free(tmp->key); if (tmp->value) free(tmp->value); free(tmp); } @@ -2437,7 +2436,6 @@ void uwsgi_emperor_simple_do_with_attrs(struct uwsgi_emperor_scanner *ues, char while(attr) { struct uwsgi_dyn_dict *tmp = attr; attr = attr->next; - if (tmp->key) free(tmp->key); if (tmp->value) free(tmp->value); free(tmp); } @@ -2450,7 +2448,6 @@ void uwsgi_emperor_simple_do_with_attrs(struct uwsgi_emperor_scanner *ues, char while(attr) { struct uwsgi_dyn_dict *tmp = attr; attr = attr->next; - if (tmp->key) free(tmp->key); if (tmp->value) free(tmp->value); free(tmp); } diff --git a/plugins/emperor_mongodb/emperor_mongodb.cc b/plugins/emperor_mongodb/emperor_mongodb.cc index f6ef1ccb..865a8cf2 100644 --- a/plugins/emperor_mongodb/emperor_mongodb.cc +++ b/plugins/emperor_mongodb/emperor_mongodb.cc @@ -77,8 +77,17 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues if (strlen(socket_name) == 0) socket_name = NULL; struct uwsgi_dyn_dict *attrs = NULL; - char *attr_key = NULL; - char *attr_value = NULL; + struct uwsgi_string_list *e_attrs = uwsgi.emperor_collect_attributes; + while(e_attrs) { + const char *attr_value = p.getStringField(e_attrs->value); + if (strlen(attr_value) == 0) attr_value = NULL; + if (attr_value) { + // the value memory is always reallocated + char *value = uwsgi_str((char *)attr_value); + uwsgi_dyn_dict_new(&attrs, e_attrs->value, e_attrs->len, value, strlen(value)); + } + e_attrs = NULL; + } if (attrs) { // attrs will be freed in case of error From 1cf169ebe007887d1c7ec7221dce06612ef0a3c6 Mon Sep 17 00:00:00 2001 From: Unbit Date: Fri, 16 May 2014 05:50:23 +0200 Subject: [PATCH 44/54] implemented fork-server and wrapper vassal's attributes --- core/emperor.c | 23 +++++++++++++++++++++-- core/uwsgi.c | 2 ++ uwsgi.h | 2 ++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 5aae6ef1..9c532a7b 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -38,6 +38,18 @@ struct uwsgi_emperor_blacklist_item { struct uwsgi_emperor_blacklist_item *emperor_blacklist; +static char *vassal_attr_get(struct uwsgi_instance *c_ui, char *attr) { + if (!attr) return NULL; + struct uwsgi_dyn_dict *attrs = c_ui->attrs; + while(attrs) { + if (!strcmp(attrs->key, attr)) { + return attrs->value; + } + attrs = attrs->next; + } + return NULL; +} + // this generates the argv for the new vassal static char **vassal_new_argv(struct uwsgi_instance *n_ui, int *slot_to_free) { @@ -52,6 +64,8 @@ static char **vassal_new_argv(struct uwsgi_instance *n_ui, int *slot_to_free) { char **vassal_argv = uwsgi_malloc(sizeof(char *) * counter); // set args vassal_argv[0] = uwsgi.emperor_wrapper ? uwsgi.emperor_wrapper : uwsgi.binary_path; + char *wrapper_attr = vassal_attr_get(n_ui, uwsgi.emperor_wrapper_attr); + if (wrapper_attr) vassal_argv[0] = wrapper_attr; // reset counter counter = 1; @@ -1193,11 +1207,16 @@ int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { // TODO pre-start hook + + // check for fork server + char *fork_server = uwsgi.emperor_use_fork_server; + char *fork_server_attr = vassal_attr_get(n_ui, uwsgi.emperor_fork_server_attr); + if (fork_server_attr) fork_server = fork_server_attr; // a new uWSGI instance will start - if (uwsgi.emperor_use_fork_server && !uwsgi_string_list_has_item(uwsgi.vassal_fork_base, n_ui->name, strlen(n_ui->name))) { + if (fork_server && !uwsgi_string_list_has_item(uwsgi.vassal_fork_base, n_ui->name, strlen(n_ui->name))) { // pid can only be > 0 or -1 n_ui->adopted = 1; - pid = emperor_connect_to_fork_server(uwsgi.emperor_use_fork_server, n_ui); + pid = emperor_connect_to_fork_server(fork_server, n_ui); } #if defined(__linux__) && !defined(OBSOLETE_LINUX_KERNEL) && !defined(__ia64__) else if (uwsgi.emperor_clone) { diff --git a/core/uwsgi.c b/core/uwsgi.c index 6523f790..a70c1c18 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -232,6 +232,8 @@ static struct uwsgi_option uwsgi_base_options[] = { #endif {"emperor-collect-attribute", no_argument, 0, "collect the specified vassal attribute from imperial monitors", uwsgi_opt_add_string_list, &uwsgi.emperor_collect_attributes, 0}, {"emperor-collect-attr", no_argument, 0, "collect the specified vassal attribute from imperial monitors", uwsgi_opt_add_string_list, &uwsgi.emperor_collect_attributes, 0}, + {"emperor-fork-server-attr", no_argument, 0, "set teh vassal's attribute to get when checking for fork-server", uwsgi_opt_set_str, &uwsgi.emperor_fork_server_attr, 0}, + {"emperor-wrapper-attr", no_argument, 0, "set teh vassal's attribute to get when checking for fork-wrapper", uwsgi_opt_set_str, &uwsgi.emperor_wrapper_attr, 0}, {"imperial-monitor-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0}, {"imperial-monitors-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0}, {"vassals-inherit", required_argument, 0, "add config templates to vassals config (uses --inherit)", uwsgi_opt_add_string_list, &uwsgi.vassals_templates, 0}, diff --git a/uwsgi.h b/uwsgi.h index 33f1e9b5..1ed7c5d9 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -2729,6 +2729,8 @@ struct uwsgi_server { char *emperor_use_fork_server; struct uwsgi_string_list *vassal_fork_base; struct uwsgi_string_list *emperor_collect_attributes; + char *emperor_fork_server_attr; + char *emperor_wrapper_attr; }; struct uwsgi_rpc { From ec28cca229b4563381a1da5d2e457940ef8a3245 Mon Sep 17 00:00:00 2001 From: Unbit Date: Fri, 16 May 2014 07:13:48 +0200 Subject: [PATCH 45/54] completed support for attributes in mongodb imperial monitor --- core/emperor.c | 4 +++- core/uwsgi.c | 8 ++++---- plugins/emperor_mongodb/emperor_mongodb.cc | 11 +++++++++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 9c532a7b..aa8ed0f3 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -1093,8 +1093,10 @@ static void vassal_fork_server_parser_hook(char *key, uint16_t key_len, char *va */ static pid_t emperor_connect_to_fork_server(char *socket, struct uwsgi_instance *n_ui) { int fd = uwsgi_connect(socket, uwsgi.socket_timeout, 0); - if (fd < 0) + if (fd < 0) { + uwsgi_error("emperor_connect_to_fork_server()/uwsgi_connect()"); return -1; + } int slot_to_free = -1; char **vassal_argv = vassal_new_argv(n_ui, &slot_to_free); diff --git a/core/uwsgi.c b/core/uwsgi.c index a70c1c18..001ca1e9 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -230,10 +230,10 @@ static struct uwsgi_option uwsgi_base_options[] = { {"vassals-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0}, {"vassal-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0}, #endif - {"emperor-collect-attribute", no_argument, 0, "collect the specified vassal attribute from imperial monitors", uwsgi_opt_add_string_list, &uwsgi.emperor_collect_attributes, 0}, - {"emperor-collect-attr", no_argument, 0, "collect the specified vassal attribute from imperial monitors", uwsgi_opt_add_string_list, &uwsgi.emperor_collect_attributes, 0}, - {"emperor-fork-server-attr", no_argument, 0, "set teh vassal's attribute to get when checking for fork-server", uwsgi_opt_set_str, &uwsgi.emperor_fork_server_attr, 0}, - {"emperor-wrapper-attr", no_argument, 0, "set teh vassal's attribute to get when checking for fork-wrapper", uwsgi_opt_set_str, &uwsgi.emperor_wrapper_attr, 0}, + {"emperor-collect-attribute", required_argument, 0, "collect the specified vassal attribute from imperial monitors", uwsgi_opt_add_string_list, &uwsgi.emperor_collect_attributes, 0}, + {"emperor-collect-attr", required_argument, 0, "collect the specified vassal attribute from imperial monitors", uwsgi_opt_add_string_list, &uwsgi.emperor_collect_attributes, 0}, + {"emperor-fork-server-attr", required_argument, 0, "set teh vassal's attribute to get when checking for fork-server", uwsgi_opt_set_str, &uwsgi.emperor_fork_server_attr, 0}, + {"emperor-wrapper-attr", required_argument, 0, "set teh vassal's attribute to get when checking for fork-wrapper", uwsgi_opt_set_str, &uwsgi.emperor_wrapper_attr, 0}, {"imperial-monitor-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0}, {"imperial-monitors-list", no_argument, 0, "list enabled imperial monitors", uwsgi_opt_true, &uwsgi.imperial_monitor_list, 0}, {"vassals-inherit", required_argument, 0, "add config templates to vassals config (uses --inherit)", uwsgi_opt_add_string_list, &uwsgi.vassals_templates, 0}, diff --git a/plugins/emperor_mongodb/emperor_mongodb.cc b/plugins/emperor_mongodb/emperor_mongodb.cc index 865a8cf2..bb41fc36 100644 --- a/plugins/emperor_mongodb/emperor_mongodb.cc +++ b/plugins/emperor_mongodb/emperor_mongodb.cc @@ -24,7 +24,14 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues try { // requested fields - mongo::BSONObj p = BSON( "name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 << "socket" << 1 ); + mongo::BSONObjBuilder builder; + builder.appendElements(BSON("name" << 1 << "config" << 1 << "ts" << 1 << "uid" << 1 << "gid" << 1 << "socket" << 1 )); + struct uwsgi_string_list *e_attrs = uwsgi.emperor_collect_attributes; + while(e_attrs) { + builder.appendElements(BSON(e_attrs->value << 1)); + e_attrs = e_attrs->next; + } + mongo::BSONObj p = builder.obj(); mongo::BSONObj q = mongo::fromjson(uems->json); // the connection object (will be automatically destroyed at each cycle) mongo::DBClientConnection c; @@ -86,7 +93,7 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues char *value = uwsgi_str((char *)attr_value); uwsgi_dyn_dict_new(&attrs, e_attrs->value, e_attrs->len, value, strlen(value)); } - e_attrs = NULL; + e_attrs = e_attrs->next; } if (attrs) { From 567395f6c43bdb641c654677cc72cf6913784513 Mon Sep 17 00:00:00 2001 From: Unbit Date: Fri, 16 May 2014 09:58:50 +0200 Subject: [PATCH 46/54] ready for fork-server heavy tests --- core/emperor.c | 5 +++-- core/fork_server.c | 14 ++++++++++---- core/io.c | 2 -- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index aa8ed0f3..7f98ae47 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -128,14 +128,14 @@ static char **vassal_new_argv(struct uwsgi_instance *n_ui, int *slot_to_free) { if (uwsgi.emperor_magic_exec) { if (!access(n_ui->name, R_OK | X_OK)) { vassal_argv[counter] = uwsgi_concat2("exec://", n_ui->name); - if (*slot_to_free) + if (slot_to_free) *slot_to_free = counter; } } else if (n_ui->use_config) { vassal_argv[counter] = uwsgi_concat2("emperor://", n_ui->name); - if (*slot_to_free) + if (slot_to_free) *slot_to_free = counter; } @@ -1483,6 +1483,7 @@ static void uwsgi_emperor_spawn_vassal(struct uwsgi_instance *n_ui) { char **vassal_argv = vassal_new_argv(n_ui, NULL); + // disable stdin OR map it to the "on demand" socket if (n_ui->on_demand_fd > -1) { if (n_ui->on_demand_fd != 0) { diff --git a/core/fork_server.c b/core/fork_server.c index 4cd35cfb..03caec58 100644 --- a/core/fork_server.c +++ b/core/fork_server.c @@ -71,7 +71,7 @@ void uwsgi_fork_server(char *socket) { int fds[8]; // we only read 4 bytes header ssize_t len = uwsgi_recv_cred_and_fds(client_fd, hbuf, remains, &ppid, &uid, &gid, fds, &fds_count); - uwsgi_log("RET = %d %d %d %d fds:%d\n", len, ppid, uid, gid, fds_count); + uwsgi_log_verbose("[uwsgi-fork-server] connection from pid: %d uid: %d gid:%d fds:%d\n", ppid, uid, gid, fds_count); if (len <= 0 || fds_count < 1) { uwsgi_error("uwsgi_fork_server()/recvmsg()"); goto end; @@ -95,7 +95,6 @@ void uwsgi_fork_server(char *socket) { pid_t pid = fork(); if (pid < 0) { free(body_argv); - // close inherited decriptors excluded the passed fds and client_fd int i; for(i=0;i 0) { free(body_argv); - // close inherited decriptors excluded the passed fds and client_fd + // close inherited decriptors int i; for(i=0;i -1) close(uwsgi.emperor_fd_config); + } + // set EMPEROR_FD and FD_CONFIG env vars char *uef = uwsgi_num2str(fds[0]); if (setenv("UWSGI_EMPEROR_FD", uef, 1)) { diff --git a/core/io.c b/core/io.c index b123f297..bbe59c39 100644 --- a/core/io.c +++ b/core/io.c @@ -1519,11 +1519,9 @@ ssize_t uwsgi_recv_cred_and_fds(int fd, char *buf, size_t buf_len, pid_t *pid, u struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); while(cmsg) { - uwsgi_log("ROUND ROUND\n"); if (cmsg->cmsg_level != SOL_SOCKET) goto next; if (cmsg->cmsg_type == SCM_RIGHTS) { size_t fds_len = cmsg->cmsg_len - ((char *) CMSG_DATA(cmsg) - (char *) cmsg); - uwsgi_log("FDS_LEN = %d\n", fds_len); memcpy(fds, CMSG_DATA(cmsg), fds_len); *fds_count = fds_len/sizeof(int); } From 7b1138e5ef13ad80104f14aa1d33cb9dcd514e1f Mon Sep 17 00:00:00 2001 From: Unbit Date: Mon, 26 May 2014 14:59:33 +0200 Subject: [PATCH 47/54] added perl low-level hook --- plugins/psgi/psgi_plugin.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/plugins/psgi/psgi_plugin.c b/plugins/psgi/psgi_plugin.c index ab50ed2f..a7c46026 100644 --- a/plugins/psgi/psgi_plugin.c +++ b/plugins/psgi/psgi_plugin.c @@ -992,7 +992,15 @@ static int uwsgi_perl_spooler(char *filename, char *buf, uint16_t len, char *bod return ret; } +static int uwsgi_perl_hook_perl(char *arg) { + SV *ret = perl_eval_pv(arg, 0); + if (!ret) return -1; + return 0; +} +static void uwsgi_perl_register_features() { + uwsgi_register_hook("perl", uwsgi_perl_hook_perl); +} struct uwsgi_plugin psgi_plugin = { @@ -1023,4 +1031,5 @@ struct uwsgi_plugin psgi_plugin = { .magic = uwsgi_perl_magic, .spooler = uwsgi_perl_spooler, + .on_load = uwsgi_perl_register_features, }; From 657bc57885607e235b0595f276f16edf0c38d859 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 28 May 2014 06:45:30 +0200 Subject: [PATCH 48/54] added emperor-subreaper option and hook-as-on-demand-vassal --- core/emperor.c | 25 ++++++++----- core/hooks.c | 100 +++++++++++++++++++++++++++---------------------- core/uwsgi.c | 3 ++ uwsgi.h | 3 ++ 4 files changed, 78 insertions(+), 53 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 7f98ae47..af33c48c 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -1061,6 +1061,9 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->on_demand_fd); uwsgi_log("[uwsgi-emperor] %s -> \"on demand\" instance detected, waiting for connections on socket \"%s\" ...\n", name, socket_name); + if (uwsgi_hooks_run_and_return(uwsgi.hook_as_on_demand_vassal, "as-on-demand-vassal", 0)) { + emperor_del(n_ui); + } return; } @@ -1738,6 +1741,15 @@ static void emperor_cleanup() { void emperor_loop() { +#ifdef __linux__ + if (uwsgi.emperor_use_fork_server || uwsgi.emperor_subreaper) { + if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)) { + uwsgi_error("uwsgi_fork_server()/fork()"); + exit(1); + } + } +#endif + // monitor a directory struct uwsgi_instance ui_base; @@ -2075,6 +2087,10 @@ recheck: ui_current->ready = 0; ui_current->accepting = 0; uwsgi_log("[uwsgi-emperor] %s -> back to \"on demand\" mode, waiting for connections on socket \"%s\" ...\n", ui_current->name, ui_current->socket_name); + if (uwsgi_hooks_run_and_return(uwsgi.hook_as_on_demand_vassal, "as-on-demand-vassal", 0)) { + emperor_del(ui_current); + freq = 1; + } break; } } @@ -2346,15 +2362,6 @@ end: void uwsgi_emperor_start() { -#ifdef __linux__ - if (uwsgi.emperor_use_fork_server) { - if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)) { - uwsgi_error("uwsgi_fork_server()/fork()"); - exit(1); - } - } -#endif - if (!uwsgi.sockets && !ushared->gateways_cnt && !uwsgi.master_process) { if (uwsgi.emperor_procname) { uwsgi_set_processname(uwsgi.emperor_procname); diff --git a/core/hooks.c b/core/hooks.c index 4f79fab0..773dbb40 100644 --- a/core/hooks.c +++ b/core/hooks.c @@ -586,55 +586,67 @@ void uwsgi_register_base_hooks() { uwsgi_register_hook("log", uwsgi_hook_print); } -void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) { +int uwsgi_hooks_run_and_return(struct uwsgi_string_list *l, char *phase, int fatal) { + int final_ret = 0; struct uwsgi_string_list *usl = NULL; - uwsgi_foreach(usl, l) { - char *colon = strchr(usl->value, ':'); - if (!colon) { - uwsgi_log("invalid hook syntax, must be hook:args\n"); - exit(1); - } - *colon = 0; - int private = 0; - char *action = usl->value; - // private hook ? - if (action[0] == '!') { - action++; - private = 1; - } - struct uwsgi_hook *uh = uwsgi_hook_by_name(action); - if (!uh) { - uwsgi_log("hook action not found: %s\n", action); - exit(1); - } - *colon = ':'; + uwsgi_foreach(usl, l) { + char *colon = strchr(usl->value, ':'); + if (!colon) { + uwsgi_log("invalid hook syntax, must be hook:args\n"); + exit(1); + } + *colon = 0; + int private = 0; + char *action = usl->value; + // private hook ? + if (action[0] == '!') { + action++; + private = 1; + } + struct uwsgi_hook *uh = uwsgi_hook_by_name(action); + if (!uh) { + uwsgi_log("hook action not found: %s\n", action); + exit(1); + } + *colon = ':'; - if (private) { - uwsgi_log("running --- PRIVATE HOOK --- (%s)...\n", phase); + if (private) { + uwsgi_log("running --- PRIVATE HOOK --- (%s)...\n", phase); + } + else { + uwsgi_log("running \"%s\" (%s)...\n", usl->value, phase); + } + + int ret = uh->func(colon+1); + if (ret != 0) { + if (fatal) return ret; + final_ret = ret; } - else { - uwsgi_log("running \"%s\" (%s)...\n", usl->value, phase); - } - - int ret = uh->func(colon+1); - if (fatal && ret != 0) { - uwsgi_log_verbose("FATAL hook failed, destroying instance\n"); - if (uwsgi.master_process) { - if (uwsgi.workers) { - if (uwsgi.workers[0].pid == getpid()) { - kill_them_all(0); - return; - } - else { - if (kill(uwsgi.workers[0].pid, SIGINT)) { - uwsgi_error("uwsgi_hooks_run()/kill()"); - exit(1); - } - return; - } + } + + return final_ret; +} + +void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) { + int ret = uwsgi_hooks_run_and_return(l, phase, fatal); + if (fatal && ret != 0) { + uwsgi_log_verbose("FATAL hook failed, destroying instance\n"); + if (uwsgi.master_process) { + if (uwsgi.workers) { + if (uwsgi.workers[0].pid == getpid()) { + kill_them_all(0); + return; } + else { + if (kill(uwsgi.workers[0].pid, SIGINT)) { + uwsgi_error("uwsgi_hooks_run()/kill()"); + exit(1); + } + return; + } } - exit(1); } + exit(1); } } + diff --git a/core/uwsgi.c b/core/uwsgi.c index 001ca1e9..6840f488 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -225,6 +225,7 @@ static struct uwsgi_option uwsgi_base_options[] = { #endif {"emperor-use-fork-server", required_argument, 0, "connect to the specified fork server instead of using plain fork() for new vassals", uwsgi_opt_set_str, &uwsgi.emperor_use_fork_server, 0}, {"vassal-fork-base", required_argument, 0, "use plain fork() for the specified vassal (instead of a fork-server)", uwsgi_opt_add_string_list, &uwsgi.vassal_fork_base, 0}, + {"emperor-subreaper", no_argument, 0, "force the Emperor to be a sub-reaper (if supported)", uwsgi_opt_true, &uwsgi.emperor_subreaper, 0}, #ifdef UWSGI_CAP {"emperor-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0}, {"vassals-cap", required_argument, 0, "set vassals capability", uwsgi_opt_set_emperor_cap, NULL, 0}, @@ -412,6 +413,8 @@ static struct uwsgi_option uwsgi_base_options[] = { {"hook-as-vassal", required_argument, 0, "run the specified hook before exec()ing the vassal", uwsgi_opt_add_string_list, &uwsgi.hook_as_vassal, 0}, {"hook-as-emperor", required_argument, 0, "run the specified hook in the emperor after the vassal has been started", uwsgi_opt_add_string_list, &uwsgi.hook_as_emperor, 0}, + {"hook-as-on-demand-vassal", required_argument, 0, "run the specified hook whenever a vassal enters on-demand mode", uwsgi_opt_add_string_list, &uwsgi.hook_as_on_demand_vassal, 0}, + {"hook-as-mule", required_argument, 0, "run the specified hook in each mule", uwsgi_opt_add_string_list, &uwsgi.hook_as_mule, 0}, {"hook-as-gateway", required_argument, 0, "run the specified hook in each gateway", uwsgi_opt_add_string_list, &uwsgi.hook_as_gateway, 0}, diff --git a/uwsgi.h b/uwsgi.h index 1ed7c5d9..8b470b94 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -2731,6 +2731,8 @@ struct uwsgi_server { struct uwsgi_string_list *emperor_collect_attributes; char *emperor_fork_server_attr; char *emperor_wrapper_attr; + int emperor_subreaper; + struct uwsgi_string_list *hook_as_on_demand_vassal; }; struct uwsgi_rpc { @@ -4579,6 +4581,7 @@ int uwsgi_umount(char *, char *); int uwsgi_mount_hook(char *); int uwsgi_umount_hook(char *); +int uwsgi_hooks_run_and_return(struct uwsgi_string_list *, char *, int); void uwsgi_hooks_run(struct uwsgi_string_list *, char *, int); void uwsgi_register_hook(char *, int (*)(char *)); struct uwsgi_hook *uwsgi_hook_by_name(char *); From 8d3e6cd3f36f1ad2848bcbfb40f00ef7ce94b5f2 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Wed, 28 May 2014 06:55:53 +0200 Subject: [PATCH 49/54] added fix for older linux systems --- core/emperor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/emperor.c b/core/emperor.c index af33c48c..a63bd57b 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -1741,7 +1741,7 @@ static void emperor_cleanup() { void emperor_loop() { -#ifdef __linux__ +#if defined(__linux__) && defined(PR_SET_CHILD_SUBREAPER) if (uwsgi.emperor_use_fork_server || uwsgi.emperor_subreaper) { if (prctl(PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0)) { uwsgi_error("uwsgi_fork_server()/fork()"); From 65d25a0fc224f0694ebfd1434524eed1efb45ae8 Mon Sep 17 00:00:00 2001 From: C Anthony Risinger Date: Wed, 28 May 2014 12:51:58 -0500 Subject: [PATCH 50/54] add build products to .gitignore --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index d021ce9b..df2b62e4 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,7 @@ /t/ring/target core/dot_h.c + +/build/ +/dist/ +/uWSGI.egg-info/ From c5e1ead0658334388a41b5ce685333334d8ec55b Mon Sep 17 00:00:00 2001 From: C Anthony Risinger Date: Wed, 28 May 2014 12:52:41 -0500 Subject: [PATCH 51/54] add alternate setup.py impl --- setup.cpyext.py | 131 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 setup.cpyext.py diff --git a/setup.cpyext.py b/setup.cpyext.py new file mode 100644 index 00000000..ee89dbc5 --- /dev/null +++ b/setup.cpyext.py @@ -0,0 +1,131 @@ +# encoding: utf-8 + +""" +This is a hack allowing you installing +uWSGI and uwsgidecorators via pip and easy_install +since 1.9.11 it automatically detects pypy +""" + +import os +import sys +import errno +import shlex +import shutil +import uwsgiconfig + +from setuptools import setup +from setuptools.dist import Distribution +from setuptools.command.install import install +from setuptools.command.install_lib import install_lib +from setuptools.command.build_ext import build_ext +from distutils.core import Extension + + +class uWSGIBuildExt(build_ext): + + UWSGI_NAME = 'uwsgi' + UWSGI_PLUGIN = 'pyuwsgi' + + def build_extensions(self): + self.uwsgi_setup() + #XXX: needs uwsgiconfig fix + self.uwsgi_build() + if 'UWSGI_USE_DISTUTILS' not in os.environ: + #XXX: needs uwsgiconfig fix + #uwsgiconfig.build_uwsgi(self.uwsgi_config) + return + + else: + #XXX: needs uwsgiconfig fix + os.unlink(self.uwsgi_config.get('bin_name')) + + #FIXME: else build fails :( + for baddie in set(self.compiler.compiler_so) & set(( + '-Wstrict-prototypes', + )): + self.compiler.compiler_so.remove(baddie) + + build_ext.build_extensions(self) + + def uwsgi_setup(self): + default = ( + '__pypy__' in sys.builtin_module_names + and 'pypy' + or 'default' + ) + profile = ( + os.environ.get('UWSGI_PROFILE') + or 'buildconf/%s.ini' % default + ) + + if not profile.endswith('.ini'): + profile = profile + '.ini' + if not '/' in profile: + profile = 'buildconf/' + profile + + #FIXME: update uwsgiconfig to properly set _EVERYTHING_! + config = uwsgiconfig.uConf(profile) + # insert in the beginning so UWSGI_PYTHON_NOLIB is exported + # before the python plugin compiles + ep = config.get('embedded_plugins').split(',') + if self.UWSGI_PLUGIN in ep: + ep.remove(self.UWSGI_PLUGIN) + ep.insert(0, self.UWSGI_PLUGIN) + config.set('embedded_plugins', ','.join(ep)) + config.set('as_shared_library', 'true') + config.set('bin_name', self.get_ext_fullpath(self.UWSGI_NAME)) + try: + os.makedirs(os.path.dirname(config.get('bin_name'))) + except OSError as e: + if e.errno != errno.EEXIST: + raise + + self.uwsgi_profile = profile + self.uwsgi_config = config + + def uwsgi_build(self): + uwsgiconfig.build_uwsgi(self.uwsgi_config) + + #XXX: merge uwsgi_setup (see other comments) + for ext in self.extensions: + if ext.name == self.UWSGI_NAME: + ext.sources = [s + '.c' for s in self.uwsgi_config.gcc_list] + ext.library_dirs = self.uwsgi_config.include_path[:] + ext.libraries = list() + ext.extra_compile_args = list() + + for x in uwsgiconfig.uniq_warnings( + self.uwsgi_config.ldflags + self.uwsgi_config.libs, + ): + for y in shlex.split(x): + if y.startswith('-l'): + ext.libraries.append(y[2:]) + elif y.startswith('-L'): + ext.library_dirs.append(y[2:]) + + for x in self.uwsgi_config.cflags: + for y in shlex.split(x): + if y: + ext.extra_compile_args.append(y) + + +setup( + name='uWSGI', + license='GPL2', + version=uwsgiconfig.uwsgi_version, + author='Unbit', + author_email='info@unbit.it', + description='The uWSGI server', + cmdclass={ + 'build_ext': uWSGIBuildExt, + }, + py_modules=[ + 'uwsgidecorators', + ], + ext_modules=[ + Extension(uWSGIBuildExt.UWSGI_NAME, sources=[]), + ], + entry_points={ + 'console_scripts': ['uwsgi=%s:run' % uWSGIBuildExt.UWSGI_NAME], + }, + ) From 5a17557954fd622038a49340a5353ee1da791f18 Mon Sep 17 00:00:00 2001 From: C Anthony Risinger Date: Tue, 27 May 2014 05:51:13 -0500 Subject: [PATCH 52/54] Support alternate build as proper CPython extension, and/or by distutils uWSGI will instruct setuptools to generate a console_scripts entry_point as bin/uwsgi, and will in general behave more like a normal extension. Also exports uwsgi.ORIG_ARGV and uwsgi.NEW_ARGV... ex. usage: # python -i -c \ 'import uwsgi as u; u.setup().worker_id()==1 or u.run()' \ --master --workers=1 --enable-threads --honour-stdin \ --auto-procname --http :8000 Relies on new_argc/new_argv support in 2.1 --- plugins/pyuwsgi/pyuwsgi.c | 332 +++++++++++++++++++++++++++++++++----- 1 file changed, 291 insertions(+), 41 deletions(-) diff --git a/plugins/pyuwsgi/pyuwsgi.c b/plugins/pyuwsgi/pyuwsgi.c index 02a03329..2f248f4a 100644 --- a/plugins/pyuwsgi/pyuwsgi.c +++ b/plugins/pyuwsgi/pyuwsgi.c @@ -1,75 +1,325 @@ #include "../python/uwsgi_python.h" +//FIXME: [upstream:python] needs PyAPI_FUNC(void) +extern void Py_GetArgcArgv(int *, char ***); + extern struct uwsgi_server uwsgi; extern struct uwsgi_python up; extern char **environ; -PyObject *u_run(PyObject *self, PyObject *args) { +static int new_argc = -1; +static int orig_argc = -1; +static char **new_argv = NULL; +static char **orig_argv = NULL; +static char *new_argv_buf = NULL; - char **argv; - size_t size = 2; - int i; - if (PyTuple_Size(args) < 1) { - return PyErr_Format(PyExc_ValueError, "you have to specify at least one uWSGI option to run() it"); - } +PyObject * +pyuwsgi_setup(PyObject *self, PyObject *args, PyObject *kwds) +{ + if (new_argv) { + PyErr_SetString( + PyExc_RuntimeError, + "uWSGI already setup" + ); + return NULL; + } - PyObject *the_arg = PyTuple_GetItem(args, 0); + if (uwsgi.mywid) { + PyErr_SetString( + PyExc_RuntimeError, + "uWSGI must be setup by master" + ); + return NULL; + } - if (PyList_Check(the_arg)) { - size = PyList_Size(the_arg) + 2; - } - else if (PyTuple_Check(the_arg)) { - size = PyTuple_Size(the_arg) + 2; - } - else if (PyString_Check(the_arg)) { - size = 3; - } + PyObject *iterator; - argv = uwsgi_malloc(sizeof(char *) * size); - memset(argv, 0, sizeof(char *) * size); + if (args == NULL || PyObject_Size(args) == 0) { + PyObject *argv = PySys_GetObject("argv"); + if (argv == NULL) + return NULL; - // will be overwritten - argv[0] = "uwsgi"; + // during site.py maybe + if (argv == Py_None) { + argv = PyTuple_New(0); + iterator = PyObject_GetIter(argv); + Py_DECREF(argv); + } + else { + iterator = PyObject_GetIter(argv); + if (PyObject_Size(argv) > 0) { + // forward past argv0 + PyObject *item = PyIter_Next(iterator); + Py_DECREF(item); + } + } + } + else if ( + PyObject_Size(args) == 1 + && !PyString_Check(PyTuple_GetItem(args, 0)) + ) { + iterator = PyObject_GetIter(PyTuple_GetItem(args, 0)); + } + else { + iterator = PyObject_GetIter(args); + } - if (PyList_Check(the_arg)) { - for(i=0;i>> 0" + "\n" + "\n * Call setup(...) if not configured" + "\n * Begin uWSGI mainloop" + "\n NOTE: will not return" + "\n" + }, + {"init", + (PyCFunction) pyuwsgi_init, + METH_VARARGS | METH_KEYWORDS, + "init(...)" + "\n>>> 0" + "\n" + "\n * Call setup(...)" + "\n * Begin uWSGI mainloop" + "\n NOTE: will not return" + "\n" + }, + {"setup", + (PyCFunction) pyuwsgi_setup, + METH_VARARGS | METH_KEYWORDS, + "setup('--master', ...)" + "\n>>> " + "\n" + "\n * Initialize uWSGI core with (...)" + "\n MUST only call once [RuntimeException]" + "\n MUST only call from master [RuntimeException]" + "\n" + }, {NULL, NULL, 0, NULL} }; + +static void +pyuwsgi_set_orig_argv(PyObject *self) +{ + + // ask python for the original argc/argv saved in Py_Main() + Py_GetArgcArgv(&orig_argc, &orig_argv); + + // [re?]export to uwsgi.orig_argv + PyObject *m_orig_argv; + m_orig_argv = PyTuple_New(orig_argc); + + int i = 0; + int i_cm = -1; + + for(i=0; i < orig_argc; i++) { + char *arg = orig_argv[i]; + //XXX: _PyOS_optarg != 0 also indicates python quit early... + //FIXME: [upstream:python] orig_argv could be mangled; reset + // rel: http://bugs.python.org/issue8202 + orig_argv[i + 1] = arg + strlen(arg) + 1; + + // look for -c or -m and record the offset + if (i_cm < 0) { + if (strcmp(arg, "-c") || strcmp(arg, "-m")) { + // python's getopt would've failed had + 1 not exist + i_cm = i + 1; + } + else if (!uwsgi_startswith(arg, "-c", 2) || + !uwsgi_startswith(arg, "-m", 2)) { + //FIXME: ARGS prior to and including -c/-m are REQUIRED, + // but NOT a part of the uWSGI argv! Needed to make + // exec*() self-referential: exec*(...) -> uwsgi + // + // want: uwsgi.binary_argv[:] + uwsgi.argv[:]! + // binary_argv = [binary_path] + args + i_cm = i; + } + } + + PyTuple_SetItem(m_orig_argv, i, PyString_FromString(arg)); + } + + //TODO: howto properly detect uwsgi already running... + // orig_argv == uwsgi.orig_argv (?) + // ^^^ but if Py_Main not called, python/main.c:orig_argv unset + // howto interact/detect things in general + PyObject *m_new_argv = PyTuple_New(0); + PyObject_SetAttrString(self, "NEW_ARGV", m_new_argv); + PyObject_SetAttrString(self, "ORIG_ARGV", m_orig_argv); + Py_DECREF(m_new_argv); + Py_DECREF(m_orig_argv); +} + + +static PyObject * +pyuwsgi_init_as(char *mod_name) +{ + + PyObject *m; + + m = PyImport_GetModuleDict(); + if (m == NULL) { + return NULL; + } + + m = PyDict_GetItemString(m, mod_name); + if (!m) { + m = Py_InitModule(mod_name, NULL); + } + + if (orig_argc < 0) { + pyuwsgi_set_orig_argv(m); + } + + int i; + for (i=0; methods[i].ml_name != NULL; i++) { + PyObject *fun = PyObject_GetAttrString(m, methods[i].ml_name); + if (fun != NULL) { + // already exists + Py_DECREF(fun); + continue; + } + + PyErr_Clear(); + + // rel: Python/modsupport.c:Py_InitModule4 + PyObject* name = PyString_FromString(methods[i].ml_name); + // fun(self, ...) + fun = PyCFunction_NewEx(&methods[i], m, name); + Py_DECREF(name); + // module.fun + PyObject_SetAttrString(m, methods[i].ml_name, fun); + Py_DECREF(fun); + } + + return m; +} + + PyMODINIT_FUNC initpyuwsgi() { - (void) Py_InitModule("pyuwsgi", methods); + (void) pyuwsgi_init_as("pyuwsgi"); } -int pyuwsgi_init() { return 0; } +// allow the module to be called `uwsgi` +PyMODINIT_FUNC +inituwsgi() +{ + (void) pyuwsgi_init_as("uwsgi"); +} + + +void pyuwsgi_load() +{ + if (new_argc > -1) { + uwsgi.new_argc = new_argc; + uwsgi.new_argv = new_argv; + } +} + struct uwsgi_plugin pyuwsgi_plugin = { .name = "pyuwsgi", - .init = pyuwsgi_init, + .on_load = pyuwsgi_load, }; From 6179f889e9c874202a66a7910040f0bf68f3e726 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Fri, 30 May 2014 06:43:15 +0200 Subject: [PATCH 53/54] implementation of emperor attributes for .ini files --- core/emperor.c | 33 +++++++++++++++++++++------ core/ini.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++---- core/io.c | 6 ++--- uwsgi.h | 3 +++ 4 files changed, 89 insertions(+), 14 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index a63bd57b..97077afe 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -334,7 +334,7 @@ int uwsgi_emperor_is_valid(char *name) { return 0; } -static char *emperor_check_on_demand_socket(char *filename) { +static char *emperor_check_on_demand_socket(char *filename, struct uwsgi_dyn_dict *attrs) { size_t len = 0; if (uwsgi.emperor_on_demand_extension) { char *tmp = uwsgi_concat2(filename, uwsgi.emperor_on_demand_extension); @@ -471,10 +471,17 @@ void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) { } } else { - char *socket_name = emperor_check_on_demand_socket(de->d_name); - emperor_add(ues, de->d_name, st.st_mtime, NULL, 0, t_uid, t_gid, socket_name); + struct uwsgi_dyn_dict *attrs = NULL; + if (uwsgi.emperor_collect_attributes) { + if (uwsgi_endswith(de->d_name, ".ini")) { + uwsgi_emperor_ini_attrs(de->d_name, NULL, &attrs); + } + } + char *socket_name = emperor_check_on_demand_socket(de->d_name, attrs); + emperor_add_with_attrs(ues, de->d_name, st.st_mtime, NULL, 0, t_uid, t_gid, socket_name, attrs); if (socket_name) free(socket_name); + } } closedir(dir); @@ -592,10 +599,16 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) { } } else { - char *socket_name = emperor_check_on_demand_socket(g.gl_pathv[i]); - emperor_add(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, t_uid, t_gid, socket_name); - if (socket_name) - free(socket_name); + struct uwsgi_dyn_dict *attrs = NULL; + if (uwsgi.emperor_collect_attributes) { + if (uwsgi_endswith(g.gl_pathv[i], ".ini")) { + uwsgi_emperor_ini_attrs(g.gl_pathv[i], NULL, &attrs); + } + } + char *socket_name = emperor_check_on_demand_socket(g.gl_pathv[i], attrs); + emperor_add_with_attrs(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, t_uid, t_gid, socket_name, attrs); + if (socket_name) + free(socket_name); } } @@ -946,6 +959,10 @@ void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) { } void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid, char *socket_name) { + emperor_add_with_attrs(ues, name, born, config, config_size, uid, gid, socket_name, NULL); +} + +void emperor_add_with_attrs(struct uwsgi_emperor_scanner *ues, char *name, time_t born, char *config, uint32_t config_size, uid_t uid, gid_t gid, char *socket_name, struct uwsgi_dyn_dict *attrs) { struct uwsgi_instance *c_ui = ui; struct uwsgi_instance *n_ui = NULL; @@ -1036,6 +1053,8 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha n_ui->last_loyal = 0; n_ui->loyal = 0; + n_ui->attrs = attrs; + n_ui->first_run = uwsgi_now(); n_ui->last_run = n_ui->first_run; n_ui->on_demand_fd = -1; diff --git a/core/ini.c b/core/ini.c index 9069fcba..61a3c26a 100644 --- a/core/ini.c +++ b/core/ini.c @@ -9,7 +9,7 @@ extern struct uwsgi_server uwsgi; static char *last_file = NULL; -void ini_rstrip(char *line) { +static void ini_rstrip(char *line) { off_t i; @@ -22,7 +22,7 @@ void ini_rstrip(char *line) { } } -char *ini_lstrip(char *line) { +static char *ini_lstrip(char *line) { off_t i; char *ptr = line; @@ -38,7 +38,7 @@ char *ini_lstrip(char *line) { return ptr; } -char *ini_get_key(char *key) { +static char *ini_get_key(char *key) { off_t i; char *ptr = key; @@ -54,7 +54,7 @@ char *ini_get_key(char *key) { return ptr; } -char *ini_get_line(char *ini, size_t size) { +static char *ini_get_line(char *ini, size_t size) { size_t i; char *ptr = ini; @@ -171,5 +171,58 @@ void uwsgi_ini_config(char *file, char *magic_table[]) { colon[0] = ':'; } +} +void uwsgi_emperor_ini_attrs(char *filename, char *section_asked, struct uwsgi_dyn_dict **attrs) { + if (!section_asked) section_asked = "emperor"; + + char *ini = uwsgi_simple_file_read(filename); + if (!ini) return; + + char *orig_ini = ini; + + size_t len = strlen(ini); + char *section = ""; + char *key, *val, *ini_line; + + while (len) { + ini_line = ini_get_line(ini, len); + if (ini_line == NULL) { + break; + } + // skip empty line + key = ini_lstrip(ini); + ini_rstrip(key); + if (key[0] != 0) { + if (key[0] == '[') { + section = key + 1; + section[strlen(section) - 1] = 0; + } + else if (key[0] == ';' || key[0] == '#') { + // this is a comment + } + else { + // val is always valid, but (obviously) can be ignored + val = ini_get_key(key); + + if (!strcmp(section, section_asked)) { + ini_rstrip(key); + struct uwsgi_string_list *usl = uwsgi_string_list_has_item(uwsgi.emperor_collect_attributes, key, strlen(key)); + if (usl) { + val = ini_lstrip(val); + ini_rstrip(val); + char *value = uwsgi_str(val); + uwsgi_dyn_dict_new(attrs, usl->value, usl->len, value, strlen(value)); + } + } + } + } + + + len -= (ini_line - ini); + ini += (ini_line - ini); + + } + + free(orig_ini); } diff --git a/core/io.c b/core/io.c index bbe59c39..a5194774 100644 --- a/core/io.c +++ b/core/io.c @@ -90,7 +90,7 @@ char *uwsgi_simple_file_read(char *filename) { } if (fstat(fd, &sb)) { - uwsgi_error("fstat()"); + uwsgi_error("uwsgi_simple_file_read()/fstat()"); close(fd); goto end; } @@ -99,7 +99,7 @@ char *uwsgi_simple_file_read(char *filename) { len = read(fd, buffer, sb.st_size); if (len != sb.st_size) { - uwsgi_error("read()"); + uwsgi_error("uwsgi_simple_file_read()/read()"); free(buffer); close(fd); goto end; @@ -112,7 +112,7 @@ char *uwsgi_simple_file_read(char *filename) { buffer[sb.st_size] = 0; return buffer; end: - return (char *) ""; + return NULL; } diff --git a/uwsgi.h b/uwsgi.h index 8b470b94..d6b4f285 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -4091,6 +4091,7 @@ void emperor_stop(struct uwsgi_instance *); void emperor_curse(struct uwsgi_instance *); void emperor_respawn(struct uwsgi_instance *, time_t); void emperor_add(struct uwsgi_emperor_scanner *, char *, time_t, char *, uint32_t, uid_t, gid_t, char *); +void emperor_add_with_attrs(struct uwsgi_emperor_scanner *, char *, time_t, char *, uint32_t, uid_t, gid_t, char *, struct uwsgi_dyn_dict *); void emperor_back_to_ondemand(struct uwsgi_instance *); void uwsgi_exec_command_with_args(char *); @@ -4797,6 +4798,8 @@ int uwsgi_send_fds_and_body(int, int *, int, char *, size_t); ssize_t uwsgi_recv_cred_and_fds(int, char *, size_t buf_len, pid_t *, uid_t *, gid_t *, int *, int *); void uwsgi_fork_server(char *); +void uwsgi_emperor_ini_attrs(char *, char *, struct uwsgi_dyn_dict **); + #ifdef __cplusplus } #endif From 3a6887082e597e1996a71d87f0b4fed04e201216 Mon Sep 17 00:00:00 2001 From: Roberto De Ioris Date: Fri, 30 May 2014 06:50:00 +0200 Subject: [PATCH 54/54] implemented UWSGI_HOOK_CONTEXT --- core/emperor.c | 4 ++-- core/hooks.c | 21 ++++++++++++++++++--- uwsgi.h | 2 +- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/core/emperor.c b/core/emperor.c index 97077afe..e29b2987 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -1080,7 +1080,7 @@ void emperor_add_with_attrs(struct uwsgi_emperor_scanner *ues, char *name, time_ event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->on_demand_fd); uwsgi_log("[uwsgi-emperor] %s -> \"on demand\" instance detected, waiting for connections on socket \"%s\" ...\n", name, socket_name); - if (uwsgi_hooks_run_and_return(uwsgi.hook_as_on_demand_vassal, "as-on-demand-vassal", 0)) { + if (uwsgi_hooks_run_and_return(uwsgi.hook_as_on_demand_vassal, "as-on-demand-vassal", name, 0)) { emperor_del(n_ui); } return; @@ -2106,7 +2106,7 @@ recheck: ui_current->ready = 0; ui_current->accepting = 0; uwsgi_log("[uwsgi-emperor] %s -> back to \"on demand\" mode, waiting for connections on socket \"%s\" ...\n", ui_current->name, ui_current->socket_name); - if (uwsgi_hooks_run_and_return(uwsgi.hook_as_on_demand_vassal, "as-on-demand-vassal", 0)) { + if (uwsgi_hooks_run_and_return(uwsgi.hook_as_on_demand_vassal, "as-on-demand-vassal", ui_current->name, 0)) { emperor_del(ui_current); freq = 1; } diff --git a/core/hooks.c b/core/hooks.c index 773dbb40..12536dc5 100644 --- a/core/hooks.c +++ b/core/hooks.c @@ -586,9 +586,15 @@ void uwsgi_register_base_hooks() { uwsgi_register_hook("log", uwsgi_hook_print); } -int uwsgi_hooks_run_and_return(struct uwsgi_string_list *l, char *phase, int fatal) { +int uwsgi_hooks_run_and_return(struct uwsgi_string_list *l, char *phase, char *context, int fatal) { int final_ret = 0; struct uwsgi_string_list *usl = NULL; + if (context) { + if (setenv("UWSGI_HOOK_CONTEXT", context, 1)) { + uwsgi_error("uwsgi_hooks_run_and_return()/setenv()"); + return -1; + } + } uwsgi_foreach(usl, l) { char *colon = strchr(usl->value, ':'); if (!colon) { @@ -619,16 +625,25 @@ int uwsgi_hooks_run_and_return(struct uwsgi_string_list *l, char *phase, int fat int ret = uh->func(colon+1); if (ret != 0) { - if (fatal) return ret; + if (fatal) { + if (context) { + unsetenv("UWSGI_HOOK_CONTEXT"); + } + return ret; + } final_ret = ret; } } + if (context) { + unsetenv("UWSGI_HOOK_CONTEXT"); + } + return final_ret; } void uwsgi_hooks_run(struct uwsgi_string_list *l, char *phase, int fatal) { - int ret = uwsgi_hooks_run_and_return(l, phase, fatal); + int ret = uwsgi_hooks_run_and_return(l, phase, NULL, fatal); if (fatal && ret != 0) { uwsgi_log_verbose("FATAL hook failed, destroying instance\n"); if (uwsgi.master_process) { diff --git a/uwsgi.h b/uwsgi.h index d6b4f285..49473e56 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -4582,7 +4582,7 @@ int uwsgi_umount(char *, char *); int uwsgi_mount_hook(char *); int uwsgi_umount_hook(char *); -int uwsgi_hooks_run_and_return(struct uwsgi_string_list *, char *, int); +int uwsgi_hooks_run_and_return(struct uwsgi_string_list *, char *, char *, int); void uwsgi_hooks_run(struct uwsgi_string_list *, char *, int); void uwsgi_register_hook(char *, int (*)(char *)); struct uwsgi_hook *uwsgi_hook_by_name(char *);