first prototype of a fork server

This commit is contained in:
Unbit
2014-05-03 10:17:27 +02:00
parent 0da0fa211a
commit 8b8b57769e
8 changed files with 105 additions and 1 deletions
+69
View File
@@ -0,0 +1,69 @@
#include <uwsgi.h>
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);
}
}
+2
View File
@@ -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) {
+11
View File
@@ -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;
+2
View File
@@ -67,6 +67,8 @@ struct uwsgi_perl {
CV *spooler;
int no_plack;
void *early_psgi_callable;
};
void init_perl_embedded_module(void);
+6
View File
@@ -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;
+10
View File
@@ -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";
+4
View File
@@ -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
+1 -1
View File
@@ -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')