* released 1.1.16
* implement HTTP health checks when option "httpchk" is specified.
* put the changelog into a new CHANGELOG file
* updated the Formilux init script
diff --git a/haproxy.c b/haproxy.c
index d51ea2d..0dfa46e 100644
--- a/haproxy.c
+++ b/haproxy.c
@@ -18,6 +18,8 @@
*
* ChangeLog :
*
+ * 2002/09/01 : 1.1.16
+ * - implement HTTP health checks when option "httpchk" is specified.
* 2002/08/07 : 1.1.15
* - replaced setpgid()/setpgrp() with setsid() for better portability, because
* setpgrp() doesn't have the same meaning under Solaris, Linux, and OpenBSD.
@@ -147,7 +149,6 @@
*
* TODO:
* - handle properly intermediate incomplete server headers. Done ?
- * - log proxies start/stop
* - handle hot-reconfiguration
*
*/
@@ -176,8 +177,8 @@
#include <linux/netfilter_ipv4.h>
#endif
-#define HAPROXY_VERSION "1.1.15"
-#define HAPROXY_DATE "2002/08/07"
+#define HAPROXY_VERSION "1.1.16"
+#define HAPROXY_DATE "2002/09/01"
/* this is for libc5 for example */
#ifndef TCP_NODELAY
@@ -342,6 +343,7 @@
#define PR_O_NULLNOLOG 512 /* a connect without request will not be logged */
#define PR_O_COOK_NOC 1024 /* add a 'Cache-control' header with the cookie */
#define PR_O_COOK_POST 2048 /* don't insert cookies for requests other than a POST */
+#define PR_O_HTTP_CHK 4096 /* use HTTP 'OPTIONS' method to check server health */
/* various session flags */
@@ -2061,10 +2063,11 @@
/*
* This function is used only for server health-checks. It handles
- * the connection acknowledgement and returns 1 if the socket is OK,
+ * the connection acknowledgement. If the proxy requires HTTP health-checks,
+ * it sends the request. In other cases, it returns 1 if the socket is OK,
* or -1 if an error occured.
*/
-int event_srv_hck(int fd) {
+int event_srv_chk_w(int fd) {
struct task *t = fdtab[fd].owner;
struct server *s = t->context;
@@ -2073,9 +2076,64 @@
getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
if (skerr)
s->result = -1;
- else
- s->result = 1;
+ else {
+ if (s->proxy->options & PR_O_HTTP_CHK) {
+ int ret;
+ /* we want to check if this host replies to "OPTIONS / HTTP/1.0"
+ * so we'll send the request, and won't wake the checker up now.
+ */
+#ifndef MSG_NOSIGNAL
+ ret = send(fd, "OPTIONS / HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT);
+#else
+ ret = send(fd, "OPTIONS / HTTP/1.0\r\n\r\n", 22, MSG_DONTWAIT | MSG_NOSIGNAL);
+#endif
+ if (ret == 22) {
+ FD_SET(fd, StaticReadEvent); /* prepare for reading reply */
+ FD_CLR(fd, StaticWriteEvent); /* nothing more to write */
+ return 0;
+ }
+ else
+ s->result = -1;
+ }
+ else {
+ /* good TCP connection is enough */
+ s->result = 1;
+ }
+ }
+
+ task_wakeup(&rq, t);
+ return 0;
+}
+
+/*
+ * This function is used only for server health-checks. It handles
+ * the server's reply to an HTTP request. It returns 1 if the server replies
+ * 2xx or 3xx (valid responses), or -1 in other cases.
+ */
+int event_srv_chk_r(int fd) {
+ char reply[64];
+ int len;
+ struct task *t = fdtab[fd].owner;
+ struct server *s = t->context;
+
+ int skerr, lskerr;
+ lskerr = sizeof(skerr);
+ getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr);
+ s->result = -1;
+ if (!skerr) {
+#ifndef MSG_NOSIGNAL
+ len = recv(fd, reply, sizeof(reply), 0);
+#else
+ len = recv(fd, reply, sizeof(reply), MSG_NOSIGNAL);
+#endif
+ if ((len >= sizeof("HTTP/1.0 000")) &&
+ !memcmp(reply, "HTTP/1.", 7) &&
+ (reply[9] == '2' || reply[9] == '3')) /* 2xx or 3xx */
+ s->result = 1;
+ }
+
+ FD_CLR(fd, StaticReadEvent);
task_wakeup(&rq, t);
return 0;
}
@@ -3277,8 +3335,8 @@
s->curfd = fd; /* that's how we know a test is in progress ;-) */
fdtab[fd].owner = t;
- fdtab[fd].read = NULL;
- fdtab[fd].write = &event_srv_hck;
+ fdtab[fd].read = &event_srv_chk_r;
+ fdtab[fd].write = &event_srv_chk_w;
fdtab[fd].state = FD_STCONN; /* connection in progress */
FD_SET(fd, StaticWriteEvent); /* for connect status */
fd_insert(fd);
@@ -3981,6 +4039,10 @@
/* don't log empty requests */
curproxy->options |= PR_O_NULLNOLOG;
}
+ else if (!strcmp(args[1], "httpchk")) {
+ /* use HTTP request to check servers' health */
+ curproxy->options |= PR_O_HTTP_CHK;
+ }
else {
Alert("parsing [%s:%d] : unknown option <%s>.\n", file, linenum, args[1]);
return -1;