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);