diff --git a/core/emperor.c b/core/emperor.c index 765eb28d..3d040304 100644 --- a/core/emperor.c +++ b/core/emperor.c @@ -175,7 +175,7 @@ void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *ues) { } } else { - emperor_add(ues, de->d_name, st.st_mtime, NULL, 0, st.st_uid, st.st_gid); + emperor_add(ues, de->d_name, st.st_mtime, NULL, 0, st.st_uid, st.st_gid, NULL); } } closedir(dir); @@ -250,7 +250,7 @@ void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *ues) { } } else { - emperor_add(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, st.st_uid, st.st_gid); + emperor_add(ues, g.gl_pathv[i], st.st_mtime, NULL, 0, st.st_uid, st.st_gid, NULL); } } @@ -377,6 +377,22 @@ struct uwsgi_instance *emperor_get_by_fd(int fd) { return NULL; } +struct uwsgi_instance *emperor_get_by_socket_fd(int fd) { + + struct uwsgi_instance *c_ui = ui; + + 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; +} + + struct uwsgi_instance *emperor_get(char *name) { @@ -478,17 +494,10 @@ void emperor_respawn(struct uwsgi_instance *c_ui, time_t mod) { uwsgi_log("[emperor] reload the uwsgi instance %s\n", c_ui->name); } -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) { +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) { struct uwsgi_instance *c_ui = ui; struct uwsgi_instance *n_ui = NULL; - pid_t pid; - char **vassal_argv; - char *uef; - char **uenvs; - int counter; - char *colon = NULL; - int i; struct timeval tv; #ifdef UWSGI_DEBUG @@ -544,8 +553,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha c_ui = c_ui->ui_next; } - n_ui = uwsgi_malloc(sizeof(struct uwsgi_instance)); - memset(n_ui, 0, sizeof(struct uwsgi_instance)); + n_ui = uwsgi_calloc(sizeof(struct uwsgi_instance)); if (config) { n_ui->use_config = 1; @@ -576,10 +584,56 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha n_ui->first_run = uwsgi_now(); n_ui->last_run = n_ui->first_run; + n_ui->on_demand_fd = -1; + + n_ui->pid = -1; + + // ok here we check if we need to bind to the specified socket or continue with the activation + if (socket_name) { + char *tcp_port = strchr(socket_name, ':'); + if (tcp_port) { + // disable deferred accept for this socket + int current_defer_accept = uwsgi.no_defer_accept; + uwsgi.no_defer_accept = 1; + n_ui->on_demand_fd = bind_to_tcp(socket_name, uwsgi.listen_queue, tcp_port); + uwsgi.no_defer_accept = current_defer_accept; + } + else { + n_ui->on_demand_fd = bind_to_unix(socket_name, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); + } + + if (n_ui->on_demand_fd < 0) { + uwsgi_error("emperor_add()/bind()"); + free(n_ui); + c_ui->ui_next = NULL; + } + + 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); + c_ui->ui_next = NULL; + } +} + + +int uwsgi_emperor_vassal_start(struct uwsgi_instance *n_ui) { + + int i; + char *colon = NULL; + int counter; + char **uenvs; + char *uef; + char **vassal_argv; + pid_t pid; if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe)) { uwsgi_error("socketpair()"); - goto clear; + return -1; } event_queue_add_fd_read(uwsgi.emperor_queue, n_ui->pipe[0]); @@ -587,7 +641,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha if (n_ui->use_config) { if (socketpair(AF_UNIX, SOCK_STREAM, 0, n_ui->pipe_config)) { uwsgi_error("socketpair()"); - goto clear; + return -1; } } @@ -606,6 +660,11 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha n_ui->pid = pid; // close the right side of the pipe close(n_ui->pipe[1]); + // 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]); } @@ -625,13 +684,13 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha } } - return; + return 0; } else { if (uwsgi.emperor_tyrant) { - uwsgi_log("[emperor-tyrant] dropping privileges to %d %d for instance %s\n", (int) uid, (int) gid, name); - if (setgid(gid)) { + 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); } @@ -640,7 +699,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha exit(1); } - if (setuid(uid)) { + if (setuid(n_ui->uid)) { uwsgi_error("setuid()"); exit(1); } @@ -720,7 +779,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha vassal_argv[0] = uwsgi.binary_path; if (uwsgi.emperor_broodlord) { - colon = strchr(name, ':'); + colon = strchr(n_ui->name, ':'); if (colon) { colon[0] = 0; } @@ -728,17 +787,17 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha // initialize to a default value vassal_argv[1] = "--inherit"; - if (!strcmp(name + (strlen(name) - 4), ".xml")) + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".xml")) vassal_argv[1] = "--xml"; - if (!strcmp(name + (strlen(name) - 4), ".ini")) + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".ini")) vassal_argv[1] = "--ini"; - if (!strcmp(name + (strlen(name) - 4), ".yml")) + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 4), ".yml")) vassal_argv[1] = "--yaml"; - if (!strcmp(name + (strlen(name) - 5), ".yaml")) + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".yaml")) vassal_argv[1] = "--yaml"; - if (!strcmp(name + (strlen(name) - 3), ".js")) + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 3), ".js")) vassal_argv[1] = "--json"; - if (!strcmp(name + (strlen(name) - 5), ".json")) + if (!strcmp(n_ui->name + (strlen(n_ui->name) - 5), ".json")) vassal_argv[1] = "--json"; if (colon) { @@ -746,16 +805,16 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha } - vassal_argv[2] = name; + vassal_argv[2] = n_ui->name; if (uwsgi.emperor_magic_exec) { - if (!access(name, R_OK | X_OK)) { - vassal_argv[2] = uwsgi_concat2("exec://", name); + if (!access(n_ui->name, R_OK | X_OK)) { + vassal_argv[2] = uwsgi_concat2("exec://", n_ui->name); } } if (n_ui->use_config) { - vassal_argv[2] = uwsgi_concat2("emperor://", name); + vassal_argv[2] = uwsgi_concat2("emperor://", n_ui->name); } counter = 3; @@ -768,18 +827,29 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha } vassal_argv[counter] = NULL; - // disable stdin - int stdin_fd = open("/dev/null", O_RDONLY); - if (stdin_fd < 0) { - uwsgi_error_open("/dev/null"); - exit(1); + // 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); + } } - if (stdin_fd != 0) { - if (dup2(stdin_fd, 0) < 0) { - uwsgi_error("dup2()"); + else { + int stdin_fd = open("/dev/null", O_RDONLY); + if (stdin_fd < 0) { + uwsgi_error_open("/dev/null"); exit(1); } - close(stdin_fd); + if (stdin_fd != 0) { + if (dup2(stdin_fd, 0) < 0) { + uwsgi_error("dup2()"); + exit(1); + } + close(stdin_fd); + } } // close all of the unneded fd @@ -813,11 +883,7 @@ void emperor_add(struct uwsgi_emperor_scanner *ues, char *name, time_t born, cha exit(UWSGI_EXILE_CODE); } -clear: - - free(n_ui); - c_ui->ui_next = NULL; - + return -1; } void uwsgi_imperial_monitor_glob_init(struct uwsgi_emperor_scanner *ues) { @@ -1087,14 +1153,23 @@ void emperor_loop() { else if (byte == 30 && uwsgi.emperor_broodlord > 0 && uwsgi.emperor_broodlord_count < uwsgi.emperor_broodlord) { uwsgi_log("[emperor] going in broodlord mode: launching zergs for %s\n", ui_current->name); char *zerg_name = uwsgi_concat3(ui_current->name, ":", "zerg"); - emperor_add(ui_current->scanner, zerg_name, uwsgi_now(), NULL, 0, ui_current->uid, ui_current->gid); + emperor_add(ui_current->scanner, zerg_name, uwsgi_now(), NULL, 0, ui_current->uid, ui_current->gid, NULL); free(zerg_name); } } } else { - uwsgi_log("[emperor] unrecognized vassal event on fd %d\n", interesting_fd); - close(interesting_fd); + ui_current = emperor_get_by_socket_fd(interesting_fd); + if (ui_current) { + event_queue_del_fd(uwsgi.emperor_queue, ui_current->on_demand_fd, event_queue_read()); + if (uwsgi_emperor_vassal_start(ui_current)) { + emperor_del(ui_current); + } + } + else { + uwsgi_log("[emperor] unrecognized vassal event on fd %d\n", interesting_fd); + close(interesting_fd); + } } } @@ -1120,7 +1195,9 @@ void emperor_loop() { has_children = 0; while (ui_current->ui_next) { ui_current = ui_current->ui_next; - has_children++; + if (ui_current->pid > -1) { + has_children++; + } } if (uwsgi.notify) { @@ -1172,7 +1249,7 @@ void emperor_loop() { } 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); + 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, NULL); emperor_del(ui_current); } break; @@ -1436,7 +1513,7 @@ void uwsgi_check_emperor() { } -void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char *config, time_t ts, uid_t uid, gid_t gid) { +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)) return; @@ -1473,6 +1550,6 @@ void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *ues, char *name, char new_config = uwsgi_str(config); new_config_len = strlen(new_config); } - emperor_add(ues, name, ts, new_config, new_config_len, uid, gid); + emperor_add(ues, name, ts, new_config, new_config_len, uid, gid, socket_name); } } diff --git a/plugins/emperor_amqp/emperor_amqp.c b/plugins/emperor_amqp/emperor_amqp.c index 64b8a77f..3c0f862d 100644 --- a/plugins/emperor_amqp/emperor_amqp.c +++ b/plugins/emperor_amqp/emperor_amqp.c @@ -49,7 +49,7 @@ void uwsgi_imperial_monitor_amqp_event(struct uwsgi_emperor_scanner *ues) { } if (msgsize > 0) { - emperor_add(ues, amqp_routing_key, uwsgi_now(), config, msgsize, 0, 0); + emperor_add(ues, amqp_routing_key, uwsgi_now(), config, msgsize, 0, 0, NULL); } end0: @@ -88,7 +88,7 @@ end0: emperor_respawn(ui_current, uwsgi_now()); } else { - emperor_add(ues, config_file, uwsgi_now(), NULL, 0, 0, 0); + emperor_add(ues, config_file, uwsgi_now(), NULL, 0, 0, 0, NULL); } free(config_file); diff --git a/plugins/emperor_mongodb/emperor_mongodb.cc b/plugins/emperor_mongodb/emperor_mongodb.cc index d3a2380e..b7512175 100644 --- a/plugins/emperor_mongodb/emperor_mongodb.cc +++ b/plugins/emperor_mongodb/emperor_mongodb.cc @@ -60,7 +60,9 @@ extern "C" void uwsgi_imperial_monitor_mongodb(struct uwsgi_emperor_scanner *ues vassal_gid = tmp_gid; } - uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid); + const char *socket_name = p.getStringField("socket"); + + uwsgi_emperor_simple_do(ues, (char *) name, (char *) config, vassal_ts/1000, vassal_uid, vassal_gid, (char *) socket_name); } diff --git a/plugins/emperor_pg/emperor_pg.c b/plugins/emperor_pg/emperor_pg.c index be2c28f7..98ff0391 100644 --- a/plugins/emperor_pg/emperor_pg.c +++ b/plugins/emperor_pg/emperor_pg.c @@ -68,7 +68,11 @@ void uwsgi_imperial_monitor_pg(struct uwsgi_emperor_scanner *ues) { vassal_uid = uwsgi_str_num(q_uid, strlen(q_uid)); vassal_gid = uwsgi_str_num(q_gid, strlen(q_gid)); } - uwsgi_emperor_simple_do(ues, name, config, uwsgi_str_num(ts, len), vassal_uid, vassal_gid); + char *socket_name = NULL; + if (PQnfields(res) > 5) { + socket_name = PQgetvalue(res, i, 5); + } + uwsgi_emperor_simple_do(ues, name, config, uwsgi_str_num(ts, len), vassal_uid, vassal_gid, socket_name); } } diff --git a/plugins/emperor_zeromq/emperor_zeromq.c b/plugins/emperor_zeromq/emperor_zeromq.c index e319f707..de9ff08d 100644 --- a/plugins/emperor_zeromq/emperor_zeromq.c +++ b/plugins/emperor_zeromq/emperor_zeromq.c @@ -64,15 +64,16 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues) int64_t more = 0; size_t more_size = sizeof(more); int i; - zmq_msg_t msg[5]; + zmq_msg_t msg[6]; zmq_msg_init(&msg[0]); zmq_msg_init(&msg[1]); zmq_msg_init(&msg[2]); zmq_msg_init(&msg[3]); zmq_msg_init(&msg[4]); + zmq_msg_init(&msg[5]); - for(i=0;i<5;i++) { + for(i=0;i<6;i++) { #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3,0,0) zmq_recvmsg(ues->data, &msg[i], ZMQ_DONTWAIT); #else @@ -105,6 +106,11 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues) char *ez_gid = NULL; size_t ez_gid_len = 0; + char *ez_socket_name = NULL; + size_t ez_socket_name_len = 0; + + char *socket_name = NULL; + // config if (i > 1) { ez_config = zmq_msg_data(&msg[2]); @@ -123,6 +129,12 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues) ez_gid_len = zmq_msg_size(&msg[4]); } + // gid + if (i > 4) { + ez_socket_name = zmq_msg_data(&msg[5]); + ez_socket_name_len = zmq_msg_size(&msg[5]); + } + char *name = uwsgi_concat2n(ez_name, ez_name_len, "", 0); // ok let's start checking commands @@ -142,10 +154,16 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues) vassal_gid = uwsgi_str_num(ez_gid, ez_gid_len); } - uwsgi_emperor_simple_do(ues, name, config, uwsgi_now(), vassal_uid, vassal_gid); + if (ez_socket_name) { + socket_name = uwsgi_concat2n(ez_socket_name, ez_socket_name_len, "", 0); + } + uwsgi_emperor_simple_do(ues, name, config, uwsgi_now(), vassal_uid, vassal_gid, socket_name); if (config) { free(config); } + if (socket_name) { + free(socket_name); + } } // destroy an instance else if (!uwsgi_strncmp(ez_cmd, ez_cmd_len, "destroy", 6)) { @@ -158,7 +176,7 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues) } } else { - uwsgi_log("[emperor-zeromq] unkonwn command \"%.*s\"\n", (int)ez_cmd_len, ez_cmd); + uwsgi_log("[emperor-zeromq] unknown command \"%.*s\"\n", (int)ez_cmd_len, ez_cmd); } free(name); @@ -168,6 +186,7 @@ static void uwsgi_imperial_monitor_zeromq_cmd(struct uwsgi_emperor_scanner *ues) zmq_msg_close(&msg[2]); zmq_msg_close(&msg[3]); zmq_msg_close(&msg[4]); + zmq_msg_close(&msg[5]); } // this is the event manager diff --git a/uwsgi.h b/uwsgi.h index ce7f65d6..75c5ca54 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -3517,79 +3517,81 @@ struct uwsgi_stats_pusher * uwsgi_register_stats_pusher(char *, void (*)(struct // an instance (called vassal) is a uWSGI stack running // it is identified by the name of its config file // a vassal is 'loyal' as soon as it manages a request - struct uwsgi_instance { - struct uwsgi_instance *ui_prev; - struct uwsgi_instance *ui_next; +struct uwsgi_instance { + struct uwsgi_instance *ui_prev; + struct uwsgi_instance *ui_next; - char name[0xff]; - pid_t pid; + char name[0xff]; + pid_t pid; - int status; - time_t born; - time_t last_mod; - time_t last_loyal; + int status; + time_t born; + time_t last_mod; + time_t last_loyal; - time_t last_run; - time_t first_run; + time_t last_run; + time_t first_run; - time_t last_heartbeat; + time_t last_heartbeat; - uint64_t respawns; - int use_config; + uint64_t respawns; + int use_config; - int pipe[2]; - int pipe_config[2]; + int pipe[2]; + int pipe_config[2]; - char *config; - uint32_t config_len; + char *config; + uint32_t config_len; - int loyal; + int loyal; - int zerg; + int zerg; - struct uwsgi_emperor_scanner *scanner; + struct uwsgi_emperor_scanner *scanner; - uid_t uid; - gid_t gid; - }; + uid_t uid; + gid_t gid; - struct uwsgi_instance *emperor_get_by_fd(int); - struct uwsgi_instance *emperor_get(char *); - void emperor_stop(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); + int on_demand_fd; +}; - void uwsgi_exec_command_with_args(char *); +struct uwsgi_instance *emperor_get_by_fd(int); +struct uwsgi_instance *emperor_get(char *); +void emperor_stop(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 uwsgi_imperial_monitor_glob_init(struct uwsgi_emperor_scanner *); - void uwsgi_imperial_monitor_directory_init(struct uwsgi_emperor_scanner *); - void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *); - void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *); +void uwsgi_exec_command_with_args(char *); - void uwsgi_register_clock(struct uwsgi_clock *); - void uwsgi_set_clock(char *name); +void uwsgi_imperial_monitor_glob_init(struct uwsgi_emperor_scanner *); +void uwsgi_imperial_monitor_directory_init(struct uwsgi_emperor_scanner *); +void uwsgi_imperial_monitor_directory(struct uwsgi_emperor_scanner *); +void uwsgi_imperial_monitor_glob(struct uwsgi_emperor_scanner *); - void uwsgi_init_default(void); - void uwsgi_setup_reload(void); - void uwsgi_autoload_plugins_by_name(char *); - void uwsgi_commandline_config(void); +void uwsgi_register_clock(struct uwsgi_clock *); +void uwsgi_set_clock(char *name); - void uwsgi_setup_log(void); - void uwsgi_setup_log_master(void); +void uwsgi_init_default(void); +void uwsgi_setup_reload(void); +void uwsgi_autoload_plugins_by_name(char *); +void uwsgi_commandline_config(void); - void uwsgi_setup_shared_sockets(void); +void uwsgi_setup_log(void); +void uwsgi_setup_log_master(void); - void uwsgi_setup_mules_and_farms(void); +void uwsgi_setup_shared_sockets(void); - void uwsgi_setup_workers(void); - void uwsgi_map_sockets(void); +void uwsgi_setup_mules_and_farms(void); - void uwsgi_set_cpu_affinity(void); +void uwsgi_setup_workers(void); +void uwsgi_map_sockets(void); - void uwsgi_emperor_start(void); +void uwsgi_set_cpu_affinity(void); - void uwsgi_bind_sockets(void); - void uwsgi_set_sockets_protocols(void); +void uwsgi_emperor_start(void); + +void uwsgi_bind_sockets(void); +void uwsgi_set_sockets_protocols(void); struct uwsgi_buffer *uwsgi_buffer_new(size_t); int uwsgi_buffer_append(struct uwsgi_buffer *, char *, size_t); @@ -3631,7 +3633,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); +void uwsgi_emperor_simple_do(struct uwsgi_emperor_scanner *, char *, char *, time_t, uid_t, gid_t, char *); #if defined(__linux__) #define UWSGI_ELF @@ -3928,6 +3930,7 @@ int uwsgi_cache_magic_clear(char *); void uwsgi_cache_magic_context_hook(char *, uint16_t, char *, uint16_t, void *); char *uwsgi_legion_scrolls(char *, uint64_t *); +int uwsgi_emperor_vassal_start(struct uwsgi_instance *); #ifdef UWSGI_ZLIB #include