*/
void disable_listener(struct listener *listener);
+/* This function tries to temporarily disable a listener, depending on the OS
+ * capabilities. Linux unbinds the listen socket after a SHUT_RD, and ignores
+ * SHUT_WR. Solaris refuses either shutdown(). OpenBSD ignores SHUT_RD but
+ * closes upon SHUT_WR and refuses to rebind. So a common validation path
+ * involves SHUT_WR && listen && SHUT_RD. In case of success, the FD's polling
+ * is disabled. It normally returns non-zero, unless an error is reported.
+ */
+int pause_listener(struct listener *l);
+
+/* This function tries to resume a temporarily disabled listener.
+ * The resulting state will either be LI_READY or LI_FULL. 0 is returned
+ * in case of failure to resume (eg: dead socket).
+ */
+int resume_listener(struct listener *l);
+
/* This function adds all of the protocol's listener's file descriptors to the
* polling lists when they are in the LI_LISTEN state. It is intended to be
* used as a protocol's generic enable_all() primitive, for use after the
void pause_proxy(struct proxy *p);
void stop_proxy(struct proxy *p);
void pause_proxies(void);
-void listen_proxies(void);
+void resume_proxies(void);
int session_set_backend(struct session *s, struct proxy *be);
const char *proxy_cap_str(int cap);
/*
- include/types/protocols.h
- This file defines the structures used by generic network protocols.
-
- Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation, version 2.1
- exclusively.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-*/
+ * include/types/protocols.h
+ * This file defines the structures used by generic network protocols.
+ *
+ * Copyright (C) 2000-2011 Willy Tarreau - w@1wt.eu
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, version 2.1
+ * exclusively.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
#ifndef _TYPES_PROTOCOLS_H
#define _TYPES_PROTOCOLS_H
#define PROTO_NAME_LEN 16
/* listener state */
-#define LI_NEW 0 /* not initialized yet */
-#define LI_INIT 1 /* all parameters filled in, but not assigned yet */
-#define LI_ASSIGNED 2 /* assigned to the protocol, but not listening yet */
-#define LI_LISTEN 3 /* started, listening but not enabled */
-#define LI_READY 4 /* started, listening and enabled */
-#define LI_FULL 5 /* reached its connection limit */
+enum {
+ LI_NEW = 0, /* not initialized yet */
+ LI_INIT, /* all parameters filled in, but not assigned yet */
+ LI_ASSIGNED, /* assigned to the protocol, but not listening yet */
+ LI_PAUSED, /* listener was paused, it's bound but not listening */
+ LI_LISTEN, /* started, listening but not enabled */
+ LI_READY, /* started, listening and enabled */
+ LI_FULL, /* reached its connection limit */
+};
/* Listener transitions
* calloc() set() add_listener() bind()
*/
void sig_listen(struct sig_handler *sh)
{
- listen_proxies();
+ resume_proxies();
}
/*
*/
static int uxst_unbind_listener(struct listener *listener)
{
- if (listener->state == LI_READY)
- EV_FD_CLR(listener->fd, DIR_RD);
-
- if (listener->state >= LI_LISTEN) {
- fd_delete(listener->fd);
- listener->state = LI_ASSIGNED;
+ if (listener->state > LI_ASSIGNED) {
+ unbind_listener(listener);
destroy_uxst_socket(((struct sockaddr_un *)&listener->addr)->sun_path);
}
return ERR_NONE;
listener->state = LI_LISTEN;
}
+/* This function tries to temporarily disable a listener, depending on the OS
+ * capabilities. Linux unbinds the listen socket after a SHUT_RD, and ignores
+ * SHUT_WR. Solaris refuses either shutdown(). OpenBSD ignores SHUT_RD but
+ * closes upon SHUT_WR and refuses to rebind. So a common validation path
+ * involves SHUT_WR && listen && SHUT_RD. In case of success, the FD's polling
+ * is disabled. It normally returns non-zero, unless an error is reported.
+ */
+int pause_listener(struct listener *l)
+{
+ if (l->state <= LI_PAUSED)
+ return 1;
+
+ if (shutdown(l->fd, SHUT_WR) != 0)
+ return 0; /* Solaris dies here */
+
+ if (listen(l->fd, l->backlog ? l->backlog : l->maxconn) != 0)
+ return 0; /* OpenBSD dies here */
+
+ if (shutdown(l->fd, SHUT_RD) != 0)
+ return 0; /* should always be OK */
+
+ EV_FD_CLR(l->fd, DIR_RD);
+ l->state = LI_PAUSED;
+ return 1;
+}
+
+/* This function tries to resume a temporarily disabled listener. Paused, full
+ * and disabled listeners are handled, which means that this function may
+ * replace enable_listener(). The resulting state will either be LI_READY or
+ * LI_FULL. 0 is returned in case of failure to resume (eg: dead socket).
+ */
+int resume_listener(struct listener *l)
+{
+ if (l->state < LI_PAUSED)
+ return 0;
+
+ if (l->state == LI_PAUSED &&
+ listen(l->fd, l->backlog ? l->backlog : l->maxconn) != 0)
+ return 0;
+
+ if (l->state == LI_READY)
+ return 1;
+
+ if (l->nbconn >= l->maxconn) {
+ l->state = LI_FULL;
+ return 1;
+ }
+
+ EV_FD_SET(l->fd, DIR_RD);
+ l->state = LI_READY;
+ return 1;
+}
+
/* This function adds all of the protocol's listener's file descriptors to the
* polling lists when they are in the LI_LISTEN state. It is intended to be
* used as a protocol's generic enable_all() primitive, for use after the
if (listener->state == LI_READY)
EV_FD_CLR(listener->fd, DIR_RD);
- if (listener->state >= LI_LISTEN) {
+ if (listener->state >= LI_PAUSED) {
fd_delete(listener->fd);
listener->state = LI_ASSIGNED;
}
}
-/*
- * Linux unbinds the listen socket after a SHUT_RD, and ignores SHUT_WR.
- * Solaris refuses either shutdown().
- * OpenBSD ignores SHUT_RD but closes upon SHUT_WR and refuses to rebind.
- * So a common validation path involves SHUT_WR && listen && SHUT_RD.
- * 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.
+/* 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.
*/
void pause_proxy(struct proxy *p)
{
struct listener *l;
for (l = p->listen; l != NULL; l = l->next) {
- if (shutdown(l->fd, SHUT_WR) == 0 &&
- listen(l->fd, p->backlog ? p->backlog : p->maxconn) == 0 &&
- shutdown(l->fd, SHUT_RD) == 0) {
- EV_FD_CLR(l->fd, DIR_RD);
- if (p->state != PR_STERROR)
- p->state = PR_STPAUSED;
- }
- else
+ if (!pause_listener(l))
p->state = PR_STERROR;
}
+ if (p->state != PR_STERROR)
+ p->state = PR_STPAUSED;
}
* 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)
+void resume_proxies(void)
{
struct proxy *p;
struct listener *l;
+ int fail;
p = proxy;
tv_update_date(0,1); /* else, the old time before select will be used */
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 (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 {
+ if (!resume_listener(l)) {
int port;
if (l->addr.ss_family == AF_INET6) {
}
/* Another port might have been enabled. Let's stop everything. */
- pause_proxy(p);
+ fail = 1;
break;
}
}
+
+ /* maintain_proxies() will check if the proxy may remain enabled or not */
+ p->state = PR_STRUN;
+ if (fail)
+ pause_proxy(p);
}
p = p->next;
}