void uwsgi_alarm_func_cmd(struct uwsgi_alarm_instance *uai, char *msg, size_t len) { int pipe[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe)) { return; } uwsgi_socket_nb(pipe[0]); uwsgi_socket_nb(pipe[1]); if (write(pipe[1], msg, len) != (ssize_t) len) { close(pipe[0]); close(pipe[1]); return; } uwsgi_run_command(uai->data_ptr, pipe, -1); close(pipe[0]); close(pipe[1]); }
void uwsgi_manage_command_cron(time_t now) { struct tm *uwsgi_cron_delta; struct uwsgi_cron *current_cron = uwsgi.crons; int uc_minute, uc_hour, uc_day, uc_month, uc_week; uwsgi_cron_delta = localtime(&now); if (!uwsgi_cron_delta) { uwsgi_error("localtime()"); return; } // fix month uwsgi_cron_delta->tm_mon++; while (current_cron) { uc_minute = current_cron->minute; uc_hour = current_cron->hour; uc_day = current_cron->day; uc_month = current_cron->month; uc_week = current_cron->week; // negative values as interval -1 = * , -5 = */5 if (current_cron->minute < 0) { if ((uwsgi_cron_delta->tm_min % abs(current_cron->minute)) == 0) { uc_minute = uwsgi_cron_delta->tm_min; } } if (current_cron->hour < 0) { if ((uwsgi_cron_delta->tm_hour % abs(current_cron->hour)) == 0) { uc_hour = uwsgi_cron_delta->tm_hour; } } if (current_cron->month < 0) { if ((uwsgi_cron_delta->tm_hour % abs(current_cron->month)) == 0) { uc_month = uwsgi_cron_delta->tm_mon; } } if (current_cron->day < 0) { if ((uwsgi_cron_delta->tm_mday % abs(current_cron->day)) == 0) { uc_day = uwsgi_cron_delta->tm_mday; } } if (current_cron->week < 0) { if ((uwsgi_cron_delta->tm_wday % abs(current_cron->week)) == 0) { uc_week = uwsgi_cron_delta->tm_wday; } } int run_task = 0; // mday and wday are ORed if (current_cron->day >= 0 && current_cron->week >= 0) { if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && (uwsgi_cron_delta->tm_mday == uc_day || uwsgi_cron_delta->tm_wday == uc_week)) { run_task = 1; } } else { if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && uwsgi_cron_delta->tm_mday == uc_day && uwsgi_cron_delta->tm_wday == uc_week) { run_task = 1; } } if (run_task == 1) { // date match, run command ? if (now - current_cron->last_job > 60) { //call command if (current_cron->command) { if (uwsgi_run_command(current_cron->command, NULL, -1) >= 0) { uwsgi_log_verbose("[uWSGI-cron] running %s\n", current_cron->command); } } current_cron->last_job = now; } } current_cron = current_cron->next; } }
int master_loop(char **argv, char **environ) { struct timeval last_respawn; int last_respawn_rate = 0; pid_t diedpid; int waitpid_status; time_t now = 0; int i = 0; int rlen; int check_interval = 1; struct uwsgi_rb_timer *min_timeout; struct uwsgi_rbtree *rb_timers = uwsgi_init_rb_timer(); if (uwsgi.procname_master) { uwsgi_set_processname(uwsgi.procname_master); } else if (uwsgi.procname) { uwsgi_set_processname(uwsgi.procname); } else if (uwsgi.auto_procname) { uwsgi_set_processname("uWSGI master"); } uwsgi.current_time = uwsgi_now(); uwsgi_unix_signal(SIGTSTP, suspend_resume_them_all); uwsgi_unix_signal(SIGHUP, grace_them_all); if (uwsgi.die_on_term) { uwsgi_unix_signal(SIGTERM, kill_them_all); uwsgi_unix_signal(SIGQUIT, reap_them_all); } else { uwsgi_unix_signal(SIGTERM, reap_them_all); uwsgi_unix_signal(SIGQUIT, kill_them_all); } uwsgi_unix_signal(SIGINT, kill_them_all); uwsgi_unix_signal(SIGUSR1, stats); if (uwsgi.auto_snapshot) { uwsgi_unix_signal(SIGURG, uwsgi_restore_auto_snapshot); } atexit(uwsgi_master_cleanup_hooks); uwsgi.master_queue = event_queue_init(); /* route signals to workers... */ #ifdef UWSGI_DEBUG uwsgi_log("adding %d to signal poll\n", uwsgi.shared->worker_signal_pipe[0]); #endif event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_signal_pipe[0]); if (uwsgi.master_fifo) { uwsgi.master_fifo_fd = uwsgi_master_fifo(); event_queue_add_fd_read(uwsgi.master_queue, uwsgi.master_fifo_fd); } if (uwsgi.spoolers) { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->spooler_signal_pipe[0]); } if (uwsgi.mules_cnt > 0) { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->mule_signal_pipe[0]); } if (uwsgi.log_master) { uwsgi.log_master_buf = uwsgi_malloc(uwsgi.log_master_bufsize); if (!uwsgi.threaded_logger) { #ifdef UWSGI_DEBUG uwsgi_log("adding %d to master logging\n", uwsgi.shared->worker_log_pipe[0]); #endif event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_log_pipe[0]); if (uwsgi.req_log_master) { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_req_log_pipe[0]); } } else { uwsgi_threaded_logger_spawn(); } } #ifdef UWSGI_SSL uwsgi_start_legions(); #endif uwsgi_metrics_start_collector(); uwsgi_add_reload_fds(); uwsgi_cache_start_sweepers(); uwsgi_cache_start_sync_servers(); uwsgi.wsgi_req->buffer = uwsgi.workers[0].cores[0].buffer; if (uwsgi.has_emperor) { if (uwsgi.emperor_proxy) { uwsgi.emperor_fd_proxy = bind_to_unix(uwsgi.emperor_proxy, uwsgi.listen_queue, 0, 0); if (uwsgi.emperor_fd_proxy < 0) exit(1); if (chmod(uwsgi.emperor_proxy, S_IRUSR|S_IWUSR)) { uwsgi_error("[emperor-proxy] chmod()"); exit(1); } event_queue_add_fd_read(uwsgi.master_queue, uwsgi.emperor_fd_proxy); } else { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.emperor_fd); } } if (uwsgi.zerg_server) { uwsgi.zerg_server_fd = bind_to_unix(uwsgi.zerg_server, uwsgi.listen_queue, 0, 0); event_queue_add_fd_read(uwsgi.master_queue, uwsgi.zerg_server_fd); uwsgi_log("*** Zerg server enabled on %s ***\n", uwsgi.zerg_server); } if (uwsgi.stats) { char *tcp_port = strrchr(uwsgi.stats, ':'); if (tcp_port) { // disable deferred accept for this socket int current_defer_accept = uwsgi.no_defer_accept; uwsgi.no_defer_accept = 1; uwsgi.stats_fd = bind_to_tcp(uwsgi.stats, uwsgi.listen_queue, tcp_port); uwsgi.no_defer_accept = current_defer_accept; } else { uwsgi.stats_fd = bind_to_unix(uwsgi.stats, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); } event_queue_add_fd_read(uwsgi.master_queue, uwsgi.stats_fd); uwsgi_log("*** Stats server enabled on %s fd: %d ***\n", uwsgi.stats, uwsgi.stats_fd); } if (uwsgi.stats_pusher_instances) { if (!uwsgi_thread_new(uwsgi_stats_pusher_loop)) { uwsgi_log("!!! unable to spawn stats pusher thread !!!\n"); exit(1); } } if (uwsgi.udp_socket) { uwsgi.udp_fd = bind_to_udp(uwsgi.udp_socket, 0, 0); if (uwsgi.udp_fd < 0) { uwsgi_log("unable to bind to udp socket. SNMP services will be disabled.\n"); } else { uwsgi_log("UDP server enabled.\n"); event_queue_add_fd_read(uwsgi.master_queue, uwsgi.udp_fd); } } uwsgi.snmp_fd = uwsgi_setup_snmp(); if (uwsgi.status.is_cheap) { uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1); for (i = 1; i <= uwsgi.numproc; i++) { uwsgi.workers[i].cheaped = 1; } uwsgi_log("cheap mode enabled: waiting for socket connection...\n"); } // spawn mules for (i = 0; i < uwsgi.mules_cnt; i++) { size_t mule_patch_size = 0; uwsgi.mules[i].patch = uwsgi_string_get_list(&uwsgi.mules_patches, i, &mule_patch_size); uwsgi_mule(i + 1); } // spawn gateways for (i = 0; i < ushared->gateways_cnt; i++) { if (ushared->gateways[i].pid == 0) { gateway_respawn(i); } } // spawn daemons uwsgi_daemons_spawn_all(); // first subscription uwsgi_subscribe_all(0, 1); // sync the cache store if needed uwsgi_cache_sync_all(); if (uwsgi.queue_store && uwsgi.queue_filesize) { if (msync(uwsgi.queue_header, uwsgi.queue_filesize, MS_ASYNC)) { uwsgi_error("msync()"); } } // update touches timestamps uwsgi_check_touches(uwsgi.touch_reload); uwsgi_check_touches(uwsgi.touch_logrotate); uwsgi_check_touches(uwsgi.touch_logreopen); uwsgi_check_touches(uwsgi.touch_chain_reload); uwsgi_check_touches(uwsgi.touch_workers_reload); uwsgi_check_touches(uwsgi.touch_gracefully_stop); // update exec touches struct uwsgi_string_list *usl = uwsgi.touch_exec; while (usl) { char *space = strchr(usl->value, ' '); if (space) { *space = 0; usl->len = strlen(usl->value); usl->custom_ptr = space + 1; } usl = usl->next; } uwsgi_check_touches(uwsgi.touch_exec); // update signal touches usl = uwsgi.touch_signal; while (usl) { char *space = strchr(usl->value, ' '); if (space) { *space = 0; usl->len = strlen(usl->value); usl->custom_ptr = space + 1; } usl = usl->next; } uwsgi_check_touches(uwsgi.touch_signal); // fsmon uwsgi_fsmon_setup(); // setup cheaper algos (can be stacked) uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare; if (uwsgi.requested_cheaper_algo) { uwsgi.cheaper_algo = NULL; struct uwsgi_cheaper_algo *uca = uwsgi.cheaper_algos; while (uca) { if (!strcmp(uca->name, uwsgi.requested_cheaper_algo)) { uwsgi.cheaper_algo = uca->func; break; } uca = uca->next; } if (!uwsgi.cheaper_algo) { uwsgi_log("unable to find requested cheaper algorithm, falling back to spare\n"); uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare; } } // here really starts the master loop for (;;) { //uwsgi_log("uwsgi.ready_to_reload %d %d\n", uwsgi.ready_to_reload, uwsgi.numproc); // run master_cycle hook for every plugin for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->master_cycle) { uwsgi.gp[i]->master_cycle(); } } for (i = 0; i < 256; i++) { if (uwsgi.p[i]->master_cycle) { uwsgi.p[i]->master_cycle(); } } // check for death (before reload !!!) uwsgi_master_check_death(); // check for realod if (uwsgi_master_check_reload(argv)) { return -1; } // check chain reload uwsgi_master_check_chain(); // check if some worker is taking too much to die... uwsgi_master_check_mercy(); // check for daemons (smart and dumb) uwsgi_daemons_smart_check(); if (uwsgi.respawn_snapshots) { for (i = 1; i <= uwsgi.respawn_snapshots; i++) { if (uwsgi_respawn_worker(i)) return 0; } uwsgi.respawn_snapshots = 0; } if (uwsgi.restore_snapshot) { uwsgi_master_restore_snapshot(); continue; } // cheaper management if (uwsgi.cheaper && !uwsgi.status.is_cheap && !uwsgi_instance_is_reloading && !uwsgi_instance_is_dying && !uwsgi.workers[0].suspended) { if (!uwsgi_calc_cheaper()) return 0; } // check if someone is dead diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG); if (diedpid == -1) { if (errno == ECHILD) { // something did not work as expected, just assume all has been cleared uwsgi_master_commit_status(); diedpid = 0; } else { uwsgi_error("waitpid()"); /* here is better to reload all the uWSGI stack */ uwsgi_log("something horrible happened...\n"); reap_them_all(0); exit(1); } } // no one died just run all of the standard master tasks if (diedpid == 0) { /* all processes ok, doing status scan after N seconds */ check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL]; if (!check_interval) check_interval = 1; // add unregistered file monitors // locking is not needed as monitors can only increase for (i = 0; i < ushared->files_monitored_cnt; i++) { if (!ushared->files_monitored[i].registered) { ushared->files_monitored[i].fd = event_queue_add_file_monitor(uwsgi.master_queue, ushared->files_monitored[i].filename, &ushared->files_monitored[i].id); ushared->files_monitored[i].registered = 1; } } // add unregistered timers // locking is not needed as timers can only increase for (i = 0; i < ushared->timers_cnt; i++) { if (!ushared->timers[i].registered) { ushared->timers[i].fd = event_queue_add_timer(uwsgi.master_queue, &ushared->timers[i].id, ushared->timers[i].value); ushared->timers[i].registered = 1; } } // add unregistered rb_timers // locking is not needed as rb_timers can only increase for (i = 0; i < ushared->rb_timers_cnt; i++) { if (!ushared->rb_timers[i].registered) { ushared->rb_timers[i].uwsgi_rb_timer = uwsgi_add_rb_timer(rb_timers, uwsgi_now() + ushared->rb_timers[i].value, &ushared->rb_timers[i]); ushared->rb_timers[i].registered = 1; } } int interesting_fd = -1; if (ushared->rb_timers_cnt > 0) { min_timeout = uwsgi_min_rb_timer(rb_timers, NULL); if (min_timeout == NULL) { check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL]; } else { check_interval = min_timeout->value - uwsgi_now(); if (check_interval <= 0) { expire_rb_timeouts(rb_timers); check_interval = 0; } } } // wait for event rlen = event_queue_wait(uwsgi.master_queue, check_interval, &interesting_fd); if (rlen == 0) { if (ushared->rb_timers_cnt > 0) { expire_rb_timeouts(rb_timers); } } // check uwsgi-cron table if (ushared->cron_cnt) { uwsgi_manage_signal_cron(uwsgi_now()); } if (uwsgi.crons) { uwsgi_manage_command_cron(uwsgi_now()); } // some event returned if (rlen > 0) { // if the following function returns -1, a new worker has just spawned if (uwsgi_master_manage_events(interesting_fd)) { return 0; } } now = uwsgi_now(); if (now - uwsgi.current_time < 1) { continue; } uwsgi.current_time = now; // checking logsize if (uwsgi.logfile) { uwsgi_check_logrotate(); } // this will be incremented at (more or less) regular intervals uwsgi.master_cycles++; // recalculate requests counter on race conditions risky configurations // a bit of inaccuracy is better than locking;) uwsgi_master_fix_request_counters(); // check for idle uwsgi_master_check_idle(); check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL]; if (!check_interval) check_interval = 1; // get listen_queue status struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; int tmp_queue = 0; while (uwsgi_sock) { if (uwsgi_sock->family == AF_INET) { uwsgi_sock->queue = uwsgi_get_tcp_info(uwsgi_sock->fd); } #ifdef __linux__ #ifdef SIOBKLGQ else if (uwsgi_sock->family == AF_UNIX) { uwsgi_sock->queue = get_linux_unbit_SIOBKLGQ(uwsgi_sock->fd); } #endif #endif if (uwsgi_sock->queue > tmp_queue) { tmp_queue = uwsgi_sock->queue; } uwsgi_sock = uwsgi_sock->next; } // fix queue size on multiple sockets uwsgi.shared->load = tmp_queue; // check if some worker has to die (harakiri, evil checks...) uwsgi_master_check_workers_deadline(); uwsgi_master_check_gateways_deadline(); uwsgi_master_check_mules_deadline(); uwsgi_master_check_spoolers_deadline(); uwsgi_master_check_crons_deadline(); uwsgi_master_check_mountpoints(); #ifdef __linux__ #ifdef MADV_MERGEABLE if (uwsgi.linux_ksm > 0 && (uwsgi.master_cycles % uwsgi.linux_ksm) == 0) { uwsgi_linux_ksm_map(); } #endif #endif // resubscribe every 10 cycles by default if (((uwsgi.subscriptions || uwsgi.subscriptions2) && ((uwsgi.master_cycles % uwsgi.subscribe_freq) == 0 || uwsgi.master_cycles == 1)) && !uwsgi_instance_is_reloading && !uwsgi_instance_is_dying && !uwsgi.workers[0].suspended) { uwsgi_subscribe_all(0, 0); } uwsgi_cache_sync_all(); if (uwsgi.queue_store && uwsgi.queue_filesize && uwsgi.queue_store_sync && ((uwsgi.master_cycles % uwsgi.queue_store_sync) == 0)) { if (msync(uwsgi.queue_header, uwsgi.queue_filesize, MS_ASYNC)) { uwsgi_error("msync()"); } } // check touch_reload if (!uwsgi_instance_is_reloading && !uwsgi_instance_is_dying) { char *touched = uwsgi_check_touches(uwsgi.touch_reload); if (touched) { uwsgi_log_verbose("*** %s has been touched... grace them all !!! ***\n", touched); uwsgi_block_signal(SIGHUP); grace_them_all(0); uwsgi_unblock_signal(SIGHUP); continue; } touched = uwsgi_check_touches(uwsgi.touch_workers_reload); if (touched) { uwsgi_log_verbose("*** %s has been touched... workers reload !!! ***\n", touched); uwsgi_reload_workers(); continue; } touched = uwsgi_check_touches(uwsgi.touch_chain_reload); if (touched) { if (uwsgi.status.chain_reloading == 0) { uwsgi_log_verbose("*** %s has been touched... chain reload !!! ***\n", touched); uwsgi.status.chain_reloading = 1; } else { uwsgi_log_verbose("*** %s has been touched... but chain reload is already running ***\n", touched); } } // be sure to run it as the last touch check touched = uwsgi_check_touches(uwsgi.touch_exec); if (touched) { if (uwsgi_run_command(touched, NULL, -1) >= 0) { uwsgi_log_verbose("[uwsgi-touch-exec] running %s\n", touched); } } touched = uwsgi_check_touches(uwsgi.touch_signal); if (touched) { uint8_t signum = atoi(touched); uwsgi_route_signal(signum); uwsgi_log_verbose("[uwsgi-touch-signal] raising %u\n", signum); } } continue; } // no one died if (diedpid <= 0) continue; // check for deadlocks first uwsgi_deadlock_check(diedpid); // reload gateways and daemons only on normal workflow (+outworld status) if (!uwsgi_instance_is_reloading && !uwsgi_instance_is_dying) { if (uwsgi_master_check_emperor_death(diedpid)) continue; if (uwsgi_master_check_spoolers_death(diedpid)) continue; if (uwsgi_master_check_mules_death(diedpid)) continue; if (uwsgi_master_check_gateways_death(diedpid)) continue; if (uwsgi_master_check_daemons_death(diedpid)) continue; if (uwsgi_master_check_cron_death(diedpid)) continue; } /* What happens here ? case 1) the diedpid is not a worker, report it and continue case 2) the diedpid is a worker and we are not in a reload procedure -> reload it case 3) the diedpid is a worker and we are in graceful reload -> uwsgi.ready_to_reload++ and continue case 3) the diedpid is a worker and we are in brutal reload -> uwsgi.ready_to_die++ and continue */ int thewid = find_worker_id(diedpid); if (thewid <= 0) { // check spooler, mules, gateways and daemons struct uwsgi_spooler *uspool = uwsgi.spoolers; while (uspool) { if (uspool->pid > 0 && diedpid == uspool->pid) { uwsgi_log("spooler (pid: %d) annihilated\n", (int) diedpid); goto next; } uspool = uspool->next; } for (i = 0; i < uwsgi.mules_cnt; i++) { if (uwsgi.mules[i].pid == diedpid) { uwsgi_log("mule %d (pid: %d) annihilated\n", i + 1, (int) diedpid); goto next; } } for (i = 0; i < ushared->gateways_cnt; i++) { if (ushared->gateways[i].pid == diedpid) { uwsgi_log("gateway %d (%s, pid: %d) annihilated\n", i + 1, ushared->gateways[i].fullname, (int) diedpid); goto next; } } if (uwsgi_daemon_check_pid_death(diedpid)) goto next; if (WIFEXITED(waitpid_status)) { uwsgi_log("subprocess %d exited with code %d\n", (int) diedpid, WEXITSTATUS(waitpid_status)); } else if (WIFSIGNALED(waitpid_status)) { uwsgi_log("subprocess %d exited by signal %d\n", (int) diedpid, WTERMSIG(waitpid_status)); } else if (WIFSTOPPED(waitpid_status)) { uwsgi_log("subprocess %d stopped\n", (int) diedpid); } next: continue; } // ok a worker died... uwsgi.workers[thewid].pid = 0; // only to be safe :P uwsgi.workers[thewid].harakiri = 0; // ok, if we are reloading or dying, just continue the master loop // as soon as all of the workers have pid == 0, the action (exit, or reload) is triggered if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying) { if (!uwsgi.workers[thewid].cursed_at) uwsgi.workers[thewid].cursed_at = uwsgi_now(); uwsgi_log("worker %d buried after %d seconds\n", thewid, (int) (uwsgi_now() - uwsgi.workers[thewid].cursed_at)); uwsgi.workers[thewid].cursed_at = 0; continue; } // if we are stopping workers, just end here 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); } else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_DE_HIJACKED_CODE) { uwsgi_log("...restoring worker %d (pid: %d)...\n", thewid, (int) diedpid); } else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXCEPTION_CODE) { uwsgi_log("... monitored exception detected, respawning worker %d (pid: %d)...\n", thewid, (int) diedpid); } else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_QUIET_CODE) { // noop } else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_BRUTAL_RELOAD_CODE) { uwsgi_log("!!! inconsistent state reported by worker %d (pid: %d) !!!\n", thewid, (int) diedpid); reap_them_all(0); continue; } 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)); } else { uwsgi_log("DAMN ! worker %d (pid: %d) died :( trying respawn ...\n", thewid, (int) diedpid); } } else if (uwsgi.workers[thewid].cursed_at > 0) { uwsgi_log("worker %d killed successfully (pid: %d)\n", thewid, (int) diedpid); } // manage_next_request is zero, but killed by signal... else if (WIFSIGNALED(waitpid_status)) { uwsgi_log("DAMN ! worker %d (pid: %d) MISTERIOUSLY killed by signal %d :( trying respawn ...\n", thewid, (int) diedpid, (int) WTERMSIG(waitpid_status)); } if (uwsgi.workers[thewid].cheaped == 1) { uwsgi_log("uWSGI worker %d cheaped.\n", thewid); continue; } // avoid fork bombing gettimeofday(&last_respawn, NULL); if (last_respawn.tv_sec <= uwsgi.respawn_delta + check_interval) { last_respawn_rate++; if (last_respawn_rate > uwsgi.numproc) { if (uwsgi.forkbomb_delay > 0) { uwsgi_log("worker respawning too fast !!! i have to sleep a bit (%d seconds)...\n", uwsgi.forkbomb_delay); /* use --forkbomb-delay 0 to disable sleeping */ sleep(uwsgi.forkbomb_delay); } last_respawn_rate = 0; } } else { last_respawn_rate = 0; } gettimeofday(&last_respawn, NULL); uwsgi.respawn_delta = last_respawn.tv_sec; // are we chain reloading it ? if (uwsgi.status.chain_reloading == thewid) { uwsgi.status.chain_reloading++; } // respawn the worker (if needed) if (uwsgi_respawn_worker(thewid)) return 0; // end of the loop } // never here }
void uwsgi_manage_command_cron(time_t now) { struct tm *uwsgi_cron_delta; struct uwsgi_cron *current_cron = uwsgi.crons; uwsgi_cron_delta = localtime(&now); if (!uwsgi_cron_delta) { uwsgi_error("uwsgi_manage_command_cron()/localtime()"); return; } // fix month uwsgi_cron_delta->tm_mon++; while (current_cron) { #ifdef UWSGI_SSL // check for legion cron if (current_cron->legion) { if (!uwsgi_legion_i_am_the_lord(current_cron->legion)) goto next; } #endif // skip unique crons that are still running if (current_cron->unique && current_cron->pid >= 0) goto next; int run_task = uwsgi_cron_task_needs_execution(uwsgi_cron_delta, current_cron->minute, current_cron->hour, current_cron->day, current_cron->month, current_cron->week); if (run_task == 1) { // date match, run command ? if (now - current_cron->last_job >= 60) { //call command if (current_cron->command) { if (current_cron->func) { current_cron->func(current_cron, now); } else { pid_t pid = uwsgi_run_command(current_cron->command, NULL, -1); if (pid >= 0) { current_cron->pid = pid; current_cron->started_at = now; uwsgi_log_verbose("[uwsgi-cron] running \"%s\" (pid %d)\n", current_cron->command, current_cron->pid); if (current_cron->mercy) { //uwsgi_cron->mercy can be negative to inform master that harakiri should be disabled for this cron if (current_cron->mercy > 0) current_cron->harakiri = now + current_cron->mercy; } else if (uwsgi.cron_harakiri) current_cron->harakiri = now + uwsgi.cron_harakiri; } } } current_cron->last_job = now; } } next: current_cron = current_cron->next; } }
static char *emperor_check_on_demand_socket(char *filename) { size_t len = 0; if (uwsgi.emperor_on_demand_extension) { char *tmp = uwsgi_concat2(filename, uwsgi.emperor_on_demand_extension); int fd = open(tmp, O_RDONLY); free(tmp); if (fd < 0) return NULL; char *ret = uwsgi_read_fd(fd, &len, 1); close(fd); // change the first non prinabel character to 0 size_t i; for(i=0;i<len;i++) { if (ret[i] < 32) { ret[i] = 0; break; } } if (ret[0] == 0) { free(ret); return NULL; } return ret; } else if (uwsgi.emperor_on_demand_directory) { // we need to build the socket path automagically char *start_of_vassal_name = uwsgi_get_last_char(filename, '/'); if (!start_of_vassal_name) { start_of_vassal_name = filename; } else { start_of_vassal_name++; } char *last_dot = uwsgi_get_last_char(filename, '.'); if (!last_dot) return NULL; return uwsgi_concat4n(uwsgi.emperor_on_demand_directory, strlen(uwsgi.emperor_on_demand_directory), "/", 1, start_of_vassal_name, last_dot - start_of_vassal_name, ".socket", 7); } else if (uwsgi.emperor_on_demand_exec) { int cpipe[2]; if (pipe(cpipe)) { uwsgi_error("emperor_check_on_demand_socket()pipe()"); return NULL; } char *cmd = uwsgi_concat4(uwsgi.emperor_on_demand_exec, " \"", filename, "\""); int r = uwsgi_run_command(cmd, NULL, cpipe[1]); free(cmd); if (r < 0) { close(cpipe[0]); close(cpipe[1]); return NULL; } char *ret = uwsgi_read_fd(cpipe[0], &len, 1); close(cpipe[0]); close(cpipe[1]); // change the first non prinabel character to 0 size_t i; for(i=0;i<len;i++) { if (ret[i] < 32) { ret[i] = 0; break; } } if (ret[0] == 0) { free(ret); return NULL; } return ret; } return NULL; }
/* extremely complex function for reading resources (files, url...) need a lot of refactoring... */ char *uwsgi_open_and_read(char *url, size_t *size, int add_zero, char *magic_table[]) { int fd; struct stat sb; char *buffer = NULL; char byte; ssize_t len; char *uri, *colon; char *domain; char *ip; int body = 0; char *magic_buf; // stdin ? if (!strcmp(url, "-")) { buffer = uwsgi_read_fd(0, size, add_zero); } // fd ? else if (!strncmp("fd://", url, 5)) { fd = atoi(url + 5); buffer = uwsgi_read_fd(fd, size, add_zero); } // exec ? else if (!strncmp("exec://", url, 5)) { int cpipe[2]; if (pipe(cpipe)) { uwsgi_error("pipe()"); exit(1); } uwsgi_run_command(url + 7, NULL, cpipe[1]); buffer = uwsgi_read_fd(cpipe[0], size, add_zero); close(cpipe[0]); close(cpipe[1]); } // http url ? else if (!strncmp("http://", url, 7)) { domain = url + 7; uri = strchr(domain, '/'); if (!uri) { uwsgi_log("invalid http url\n"); exit(1); } uri[0] = 0; uwsgi_log("domain: %s\n", domain); colon = uwsgi_get_last_char(domain, ':'); if (colon) { colon[0] = 0; } ip = uwsgi_resolve_ip(domain); if (!ip) { uwsgi_log("unable to resolve address %s\n", domain); exit(1); } if (colon) { colon[0] = ':'; ip = uwsgi_concat2(ip, colon); } else { ip = uwsgi_concat2(ip, ":80"); } fd = uwsgi_connect(ip, 0, 0); if (fd < 0) { exit(1); } free(ip); uri[0] = '/'; len = write(fd, "GET ", 4); len = write(fd, uri, strlen(uri)); len = write(fd, " HTTP/1.0\r\n", 11); len = write(fd, "Host: ", 6); uri[0] = 0; len = write(fd, domain, strlen(domain)); uri[0] = '/'; len = write(fd, "\r\nUser-Agent: uWSGI on ", 23); len = write(fd, uwsgi.hostname, uwsgi.hostname_len); len = write(fd, "\r\n\r\n", 4); int http_status_code_ptr = 0; while (read(fd, &byte, 1) == 1) { if (byte == '\r' && body == 0) { body = 1; } else if (byte == '\n' && body == 1) { body = 2; } else if (byte == '\r' && body == 2) { body = 3; } else if (byte == '\n' && body == 3) { body = 4; } else if (body == 4) { *size = *size + 1; char *tmp = realloc(buffer, *size); if (!tmp) { uwsgi_error("uwsgi_open_and_read()/realloc()"); exit(1); } buffer = tmp; buffer[*size - 1] = byte; } else { body = 0; http_status_code_ptr++; if (http_status_code_ptr == 10) { if (byte != '2') { uwsgi_log("Not usable HTTP response: %cxx\n", byte); if (uwsgi.has_emperor) { exit(UWSGI_EXILE_CODE); } else { exit(1); } } } } } close(fd); if (add_zero) { *size = *size + 1; char *tmp = realloc(buffer, *size); if (!tmp) { uwsgi_error("uwsgi_open_and_read()/realloc()"); exit(1); } buffer = tmp; buffer[*size - 1] = 0; } } else if (!strncmp("emperor://", url, 10)) { if (uwsgi.emperor_fd_config < 0) { uwsgi_log("this is not a vassal instance\n"); exit(1); } ssize_t rlen; *size = 0; struct uwsgi_header uh; size_t remains = 4; char *ptr = (char *) &uh; while(remains) { int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5); if (ret <= 0) { uwsgi_log("[uwsgi-vassal] error waiting for config header %s !!!\n", url); exit(1); } rlen = read(uwsgi.emperor_fd_config, ptr, remains); if (rlen <= 0) { uwsgi_log("[uwsgi-vassal] error reading config header from !!!\n", url); exit(1); } ptr+=rlen; remains-=rlen; } remains = uh.pktsize; if (!remains) { uwsgi_log("[uwsgi-vassal] invalid config from %s\n", url); exit(1); } buffer = uwsgi_calloc(remains + add_zero); ptr = buffer; while (remains) { int ret = uwsgi_waitfd(uwsgi.emperor_fd_config, 5); if (ret <= 0) { uwsgi_log("[uwsgi-vassal] error waiting for config %s !!!\n", url); exit(1); } rlen = read(uwsgi.emperor_fd_config, ptr, remains); if (rlen <= 0) { uwsgi_log("[uwsgi-vassal] error reading config from !!!\n", url); exit(1); } ptr+=rlen; remains-=rlen; } *size = uh.pktsize + add_zero; } #ifdef UWSGI_EMBED_CONFIG else if (url[0] == 0) { *size = &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG; if (add_zero) { *size += 1; } buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); memcpy(buffer, &UWSGI_EMBED_CONFIG, &UWSGI_EMBED_CONFIG_END - &UWSGI_EMBED_CONFIG); } #endif else if (!strncmp("data://", url, 7)) { fd = open(uwsgi.binary_path, O_RDONLY); if (fd < 0) { uwsgi_error_open(uwsgi.binary_path); exit(1); } int slot = atoi(url + 7); if (slot < 0) { uwsgi_log("invalid binary data slot requested\n"); exit(1); } uwsgi_log("requesting binary data slot %d\n", slot); off_t fo = lseek(fd, 0, SEEK_END); if (fo < 0) { uwsgi_error("lseek()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } int i = 0; uint64_t datasize = 0; for (i = 0; i <= slot; i++) { fo = lseek(fd, -9, SEEK_CUR); if (fo < 0) { uwsgi_error("lseek()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } ssize_t len = read(fd, &datasize, 8); if (len != 8) { uwsgi_error("read()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } if (datasize == 0) { uwsgi_log("0 size binary data !!!\n"); exit(1); } fo = lseek(fd, -(datasize + 9), SEEK_CUR); if (fo < 0) { uwsgi_error("lseek()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } if (i == slot) { *size = datasize; if (add_zero) { *size += 1; } buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); len = read(fd, buffer, datasize); if (len != (ssize_t) datasize) { uwsgi_error("read()"); uwsgi_log("invalid binary data slot requested\n"); exit(1); } } } } else if (!strncmp("sym://", url, 6)) { char *symbol = uwsgi_concat3("_binary_", url + 6, "_start"); void *sym_start_ptr = dlsym(RTLD_DEFAULT, symbol); if (!sym_start_ptr) { uwsgi_log("unable to find symbol %s\n", symbol); exit(1); } free(symbol); symbol = uwsgi_concat3("_binary_", url + 6, "_end"); void *sym_end_ptr = dlsym(RTLD_DEFAULT, symbol); if (!sym_end_ptr) { uwsgi_log("unable to find symbol %s\n", symbol); exit(1); } free(symbol); *size = sym_end_ptr - sym_start_ptr; if (add_zero) { *size += 1; } buffer = uwsgi_malloc(*size); memset(buffer, 0, *size); memcpy(buffer, sym_start_ptr, sym_end_ptr - sym_start_ptr); } #ifdef UWSGI_ELF else if (!strncmp("section://", url, 10)) { size_t s_len = 0; buffer = uwsgi_elf_section(uwsgi.binary_path, url + 10, &s_len); if (!buffer) { uwsgi_log("unable to find section %s in %s\n", url + 10, uwsgi.binary_path); exit(1); } *size = s_len; if (add_zero) *size += 1; } #endif // fallback to file else { fd = open(url, O_RDONLY); if (fd < 0) { uwsgi_error_open(url); exit(1); } if (fstat(fd, &sb)) { uwsgi_error("fstat()"); exit(1); } if (S_ISFIFO(sb.st_mode)) { buffer = uwsgi_read_fd(fd, size, add_zero); close(fd); goto end; } buffer = uwsgi_malloc(sb.st_size + add_zero); len = read(fd, buffer, sb.st_size); if (len != sb.st_size) { uwsgi_error("read()"); exit(1); } close(fd); *size = sb.st_size + add_zero; if (add_zero) buffer[sb.st_size] = 0; } end: if (magic_table) { magic_buf = magic_sub(buffer, *size, size, magic_table); free(buffer); return magic_buf; } return buffer; }