#include "uwsgi.h" extern struct uwsgi_server uwsgi; struct uwsgi_gateway *register_gateway(char *name, void (*loop) (int, void *), void *data) { struct uwsgi_gateway *ug; int num = 1, i; if (ushared->gateways_cnt >= MAX_GATEWAYS) { uwsgi_log("you can register max %d gateways\n", MAX_GATEWAYS); return NULL; } for (i = 0; i < ushared->gateways_cnt; i++) { if (!strcmp(name, ushared->gateways[i].name)) { num++; } } char *str = uwsgi_num2str(num); char *fullname = uwsgi_concat3(name, " ", str); free(str); ug = &ushared->gateways[ushared->gateways_cnt]; ug->pid = 0; ug->name = name; ug->loop = loop; ug->num = num; ug->fullname = fullname; ug->data = data; ug->uid = 0; ug->gid = 0; #if defined(SOCK_SEQPACKET) && defined(__linux__) if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, ug->internal_subscription_pipe)) { #else if (socketpair(AF_UNIX, SOCK_DGRAM, 0, ug->internal_subscription_pipe)) { #endif uwsgi_error("socketpair()"); } uwsgi_socket_nb(ug->internal_subscription_pipe[0]); uwsgi_socket_nb(ug->internal_subscription_pipe[1]); if (!uwsgi.master_process && !uwsgi.force_gateway) gateway_respawn(ushared->gateways_cnt); ushared->gateways_cnt++; return ug; } static void gateway_brutal_end() { _exit(UWSGI_END_CODE); } void gateway_respawn(int id) { pid_t gw_pid; struct uwsgi_gateway *ug = &ushared->gateways[id]; if (uwsgi.master_process) uwsgi.shared->gateways_harakiri[id] = 0; gw_pid = uwsgi_fork(ug->fullname); if (gw_pid < 0) { uwsgi_error("fork()"); return; } if (gw_pid == 0) { uwsgi_fixup_fds(0, 0, ug); uwsgi_close_all_unshared_sockets(); if (uwsgi.master_as_root) uwsgi_as_root(); #ifdef __linux__ if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) { uwsgi_error("prctl()"); } #endif uwsgi.mypid = getpid(); atexit(gateway_brutal_end); signal(SIGALRM, SIG_IGN); signal(SIGHUP, SIG_IGN); signal(SIGINT, end_me); signal(SIGTERM, end_me); signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, SIG_IGN); signal(SIGPIPE, SIG_IGN); signal(SIGSTOP, SIG_IGN); signal(SIGTSTP, SIG_IGN); uwsgi_hooks_run(uwsgi.hook_as_gateway, "as-gateway", 1); if (ug->gid) { uwsgi_log("%s %d setgid() to %d\n", ug->name, ug->num, (int) ug->gid); if (setgid(ug->gid)) { uwsgi_error("gateway_respawn()/setgid()"); exit(1); } } if (ug->uid) { uwsgi_log("%s %d setuid() to %d\n", ug->name, ug->num, (int) ug->uid); if (setuid(ug->uid)) { uwsgi_error("gateway_respawn()/setuid()"); exit(1); } } ug->loop(id, ug->data); // never here !!! (i hope) exit(1); } ug->pid = gw_pid; ug->respawns++; if (ug->respawns == 1) { uwsgi_log("spawned %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid); } else { uwsgi_log("respawned %s %d (pid: %d)\n", ug->name, ug->num, (int) gw_pid); } } struct uwsgi_gateway_socket *uwsgi_new_gateway_socket(char *name, char *owner) { struct uwsgi_gateway_socket *uwsgi_sock = uwsgi.gateway_sockets, *old_uwsgi_sock; if (!uwsgi_sock) { uwsgi.gateway_sockets = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket)); uwsgi_sock = uwsgi.gateway_sockets; } else { while (uwsgi_sock) { old_uwsgi_sock = uwsgi_sock; uwsgi_sock = uwsgi_sock->next; } uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket)); old_uwsgi_sock->next = uwsgi_sock; } memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket)); uwsgi_sock->fd = -1; uwsgi_sock->shared = 0; uwsgi_sock->name = name; uwsgi_sock->name_len = strlen(name); uwsgi_sock->owner = owner; return uwsgi_sock; } struct uwsgi_gateway_socket *uwsgi_new_gateway_socket_from_fd(int fd, char *owner) { struct uwsgi_gateway_socket *uwsgi_sock = uwsgi.gateway_sockets, *old_uwsgi_sock; if (!uwsgi_sock) { uwsgi.gateway_sockets = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket)); uwsgi_sock = uwsgi.gateway_sockets; } else { while (uwsgi_sock) { old_uwsgi_sock = uwsgi_sock; uwsgi_sock = uwsgi_sock->next; } uwsgi_sock = uwsgi_malloc(sizeof(struct uwsgi_gateway_socket)); old_uwsgi_sock->next = uwsgi_sock; } memset(uwsgi_sock, 0, sizeof(struct uwsgi_gateway_socket)); uwsgi_sock->fd = fd; uwsgi_sock->name = uwsgi_getsockname(fd); uwsgi_sock->name_len = strlen(uwsgi_sock->name); uwsgi_sock->owner = owner; return uwsgi_sock; } void uwsgi_gateway_go_cheap(char *gw_id, int queue, int *i_am_cheap) { uwsgi_log("[%s pid %d] no more nodes available. Going cheap...\n", gw_id, (int) uwsgi.mypid); struct uwsgi_gateway_socket *ugs = uwsgi.gateway_sockets; while (ugs) { if (!strcmp(ugs->owner, gw_id) && !ugs->subscription) { event_queue_del_fd(queue, ugs->fd, event_queue_read()); } ugs = ugs->next; } *i_am_cheap = 1; }