/* * This function temporarily disables listening so that another new instance * can start listening. It is designed to be called upon reception of a * SIGTTOU, after which either a SIGUSR1 can be sent to completely stop * the proxy, or a SIGTTIN can be sent to listen again. */ void pause_proxies(void) { int err; struct proxy *p; err = 0; p = proxy; tv_update_date(0,1); /* else, the old time before select will be used */ while (p) { if (p->cap & PR_CAP_FE && p->state != PR_STERROR && p->state != PR_STSTOPPED && p->state != PR_STPAUSED) { Warning("Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); pause_proxy(p); if (p->state != PR_STPAUSED) { err |= 1; Warning("%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); } } p = p->next; } if (err) { Warning("Some proxies refused to pause, performing soft stop now.\n"); send_log(p, LOG_WARNING, "Some proxies refused to pause, performing soft stop now.\n"); soft_stop(); } }
/* Temporarily disables listening on all of the proxy's listeners. Upon * success, the proxy enters the PR_PAUSED state. If disabling at least one * listener returns an error, then the proxy state is set to PR_STERROR * because we don't know how to resume from this. The function returns 0 * if it fails, or non-zero on success. */ int pause_proxy(struct proxy *p) { struct listener *l; if (!(p->cap & PR_CAP_FE) || p->state == PR_STERROR || p->state == PR_STSTOPPED || p->state == PR_STPAUSED) return 1; Warning("Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Pausing %s %s.\n", proxy_cap_str(p->cap), p->id); for (l = p->listen; l != NULL; l = l->next) { if (!pause_listener(l)) p->state = PR_STERROR; } if (p->state == PR_STERROR) { Warning("%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "%s %s failed to enter pause mode.\n", proxy_cap_str(p->cap), p->id); return 0; } p->state = PR_STPAUSED; return 1; }
/* * this function disables health-check servers so that the process will quickly be ignored * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace * time will not be used since it would already not listen anymore to the socket. */ void soft_stop(void) { struct proxy *p; struct peers *prs; stopping = 1; p = proxy; tv_update_date(0,1); /* else, the old time before select will be used */ while (p) { if (p->state != PR_STSTOPPED) { Warning("Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace); send_log(p, LOG_WARNING, "Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace); p->stop_time = tick_add(now_ms, p->grace); } if (p->table.size && p->table.sync_task) task_wakeup(p->table.sync_task, TASK_WOKEN_MSG); /* wake every proxy task up so that they can handle the stopping */ task_wakeup(p->task, TASK_WOKEN_MSG); p = p->next; } prs = peers; while (prs) { stop_proxy((struct proxy *)prs->peers_fe); prs = prs->next; } /* signal zero is used to broadcast the "stopping" event */ signal_handler(0); }
/* * this function disables health-check servers so that the process will quickly be ignored * by load balancers. Note that if a proxy was already in the PAUSED state, then its grace * time will not be used since it would already not listen anymore to the socket. */ void soft_stop(void) { struct proxy *p; stopping = 1; p = proxy; tv_update_date(0,1); /* else, the old time before select will be used */ while (p) { if (p->state != PR_STSTOPPED) { Warning("Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace); send_log(p, LOG_WARNING, "Stopping %s %s in %d ms.\n", proxy_cap_str(p->cap), p->id, p->grace); p->stop_time = tick_add(now_ms, p->grace); } p = p->next; } }
/* * This function reactivates listening. This can be used after a call to * sig_pause(), for example when a new instance has failed starting up. * It is designed to be called upon reception of a SIGTTIN. */ void listen_proxies(void) { struct proxy *p; struct listener *l; p = proxy; tv_update_date(0,1); /* else, the old time before select will be used */ while (p) { if (p->state == PR_STPAUSED) { Warning("Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); for (l = p->listen; l != NULL; l = l->next) { if (listen(l->fd, p->backlog ? p->backlog : p->maxconn) == 0) { if (actconn < global.maxconn && p->feconn < p->maxconn) { EV_FD_SET(l->fd, DIR_RD); p->state = PR_STRUN; } else p->state = PR_STIDLE; } else { int port; if (l->addr.ss_family == AF_INET6) { port = ntohs(((struct sockaddr_in6 *)(&l->addr))->sin6_port); Warning("Port %d busy while trying to enable %s %s.\n", port, proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Port %d busy while trying to enable %s %s.\n", port, proxy_cap_str(p->cap), p->id); } else if (l->addr.ss_family == AF_INET) { port = ntohs(((struct sockaddr_in *)(&l->addr))->sin_port); Warning("Port %d busy while trying to enable %s %s.\n", port, proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Port %d busy while trying to enable %s %s.\n", port, proxy_cap_str(p->cap), p->id); } else { Warning("Bind on socket %d busy while trying to enable %s %s.\n", l->luid, proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Bind on socket %d busy while trying to enable %s %s.\n", l->luid, proxy_cap_str(p->cap), p->id); } /* Another port might have been enabled. Let's stop everything. */ pause_proxy(p); break; } } } p = p->next; } }
/* This function resumes listening on the specified proxy. It scans all of its * listeners and tries to enable them all. If any of them fails, the proxy is * put back to the paused state. It returns 1 upon success, or zero if an error * is encountered. */ int resume_proxy(struct proxy *p) { struct listener *l; int fail; if (p->state != PR_STPAUSED) return 1; Warning("Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Enabling %s %s.\n", proxy_cap_str(p->cap), p->id); fail = 0; for (l = p->listen; l != NULL; l = l->next) { if (!resume_listener(l)) { int port; port = get_host_port(&l->addr); if (port) { Warning("Port %d busy while trying to enable %s %s.\n", port, proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Port %d busy while trying to enable %s %s.\n", port, proxy_cap_str(p->cap), p->id); } else { Warning("Bind on socket %d busy while trying to enable %s %s.\n", l->luid, proxy_cap_str(p->cap), p->id); send_log(p, LOG_WARNING, "Bind on socket %d busy while trying to enable %s %s.\n", l->luid, proxy_cap_str(p->cap), p->id); } /* Another port might have been enabled. Let's stop everything. */ fail = 1; break; } } p->state = PR_STREADY; if (fail) { pause_proxy(p); return 0; } return 1; }