[MEDIUM] change server check result to a bit field

A server check currently returns either -1 or 1. This is not very
convenient to enhance the health-checks system. Let's use flags
instead.
diff --git a/include/types/server.h b/include/types/server.h
index 4258502..47c152c 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -54,6 +54,11 @@
 #define SRV_STATUS_FULL     3   /* the/all server(s) are saturated */
 #define SRV_STATUS_QUEUED   4   /* the/all server(s) are saturated but the connection was queued */
 
+/* bits for s->result used for health-checks */
+#define SRV_CHK_UNKNOWN 0x0000   /* initialized to this by default */
+#define SRV_CHK_ERROR   0x0001   /* error encountered during the check; has precedence */
+#define SRV_CHK_RUNNING 0x0002   /* server seen as running */
+#define SRV_CHK_DISABLE 0x0004   /* server returned a "disable" code */
 
 struct server {
 	struct server *next;
@@ -81,7 +86,7 @@
 	int health;				/* 0->rise-1 = bad; rise->rise+fall-1 = good */
 	int rise, fall;				/* time in iterations */
 	int inter;				/* time in milliseconds */
-	int result;				/* 0 = connect OK, -1 = connect KO */
+	int result;				/* health-check result : SRV_CHK_* */
 	int curfd;				/* file desc used for current test, or -1 if not in test */
 
 	char *id;				/* just for identification */
diff --git a/src/checks.c b/src/checks.c
index 5fe98ab..e02b891 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -109,8 +109,7 @@
 /*
  * This function is used only for server health-checks. It handles
  * the connection acknowledgement. If the proxy requires HTTP health-checks,
- * it sends the request. In other cases, it returns 1 in s->result if the
- * socket is OK, or -1 if an error occured.
+ * it sends the request. In other cases, it fills s->result with SRV_CHK_*.
  * The function itself returns 0 if it needs some polling before being called
  * again, otherwise 1.
  */
@@ -125,7 +124,7 @@
 
 	/* here, we know that the connection is established */
 
-	if (s->result != -1) {
+	if (!(s->result & SRV_CHK_ERROR)) {
 		/* we don't want to mark 'UP' a server on which we detected an error earlier */
 		if ((s->proxy->options & PR_O_HTTP_CHK) ||
 		    (s->proxy->options & PR_O_SSL3_CHK) ||
@@ -181,7 +180,7 @@
 				goto out_error;
 
 			/* good TCP connection is enough */
-			s->result = 1;
+			s->result |= SRV_CHK_RUNNING;
 			goto out_wakeup;
 		}
 	}
@@ -197,7 +196,7 @@
 	fdtab[fd].ev &= ~FD_POLL_WR;
 	return 0;
  out_error:
-	s->result = -1;
+	s->result |= SRV_CHK_ERROR;
 	fdtab[fd].state = FD_STERROR;
 	goto out_wakeup;
 }
@@ -205,31 +204,32 @@
 
 /*
  * This function is used only for server health-checks. It handles the server's
- * reply to an HTTP request or SSL HELLO. It returns 1 in s->result if the
- * server replies HTTP 2xx or 3xx (valid responses), or if it returns at least
- * 5 bytes in response to SSL HELLO. The principle is that this is enough to
- * distinguish between an SSL server and a pure TCP relay. All other cases will
- * return -1. The function returns 0 if it needs to be called again after some
- * polling, otherwise non-zero..
+ * reply to an HTTP request or SSL HELLO. It sets s->result to SRV_CHK_RUNNING
+ * if an HTTP server replies HTTP 2xx or 3xx (valid responses), if an SMTP
+ * server returns 2xx, or if an SSL server returns at least 5 bytes in response
+ * to an SSL HELLO (the principle is that this is enough to distinguish between
+ * an SSL server and a pure TCP relay). All other cases will set s->result to
+ * SRV_CHK_ERROR. The function returns 0 if it needs to be called again after
+ * some polling, otherwise non-zero..
  */
 static int event_srv_chk_r(int fd)
 {
 	__label__ out_wakeup;
-	int len, result;
+	int len;
 	struct task *t = fdtab[fd].owner;
 	struct server *s = t->context;
 	int skerr;
 	socklen_t lskerr = sizeof(skerr);
 
-	result = len = -1;
+	len = -1;
 
-	if (unlikely(fdtab[fd].state == FD_STERROR ||
+	if (unlikely((s->result & SRV_CHK_ERROR) ||
+		     (fdtab[fd].state == FD_STERROR) ||
 		     (fdtab[fd].ev & FD_POLL_ERR) ||
 		     (getsockopt(fd, SOL_SOCKET, SO_ERROR, &skerr, &lskerr) == -1) ||
 		     (skerr != 0))) {
 		/* in case of TCP only, this tells us if the connection failed */
-		s->result = -1;
-		fdtab[fd].state = FD_STERROR;
+		s->result |= SRV_CHK_ERROR;
 		goto out_wakeup;
 	}
 
@@ -248,28 +248,44 @@
 		return 0;
 	}
 
+	/* Note: the response will only be accepted if read at once */
+	if (s->proxy->options & PR_O_HTTP_CHK) {
+		/* Check if the server speaks HTTP 1.X */
+		if ((len < strlen("HTTP/1.0 000\r")) ||
+		    (memcmp(trash, "HTTP/1.", 7) != 0)) {
+			s->result |= SRV_CHK_ERROR;
+			goto out_wakeup;
+		}
+
-	if ((s->proxy->options & PR_O_HTTP_CHK) && (len >= sizeof("HTTP/1.0 000")) &&
-	     (memcmp(trash, "HTTP/1.", 7) == 0) && (trash[9] == '2' || trash[9] == '3')) {
-		/* HTTP/1.X 2xx or 3xx */
-		result = 1;
+		/* check the reply : HTTP/1.X 2xx and 3xx are OK */
+		if (trash[9] == '2' || trash[9] == '3')
+			s->result |= SRV_CHK_RUNNING;
+		else
+			s->result |= SRV_CHK_ERROR;
+	}
+	else if (s->proxy->options & PR_O_SSL3_CHK) {
+		/* Check for SSLv3 alert or handshake */
+		if ((len >= 5) && (trash[0] == 0x15 || trash[0] == 0x16))
+			s->result |= SRV_CHK_RUNNING;
+		else
+			s->result |= SRV_CHK_ERROR;
 	}
-	else if ((s->proxy->options & PR_O_SSL3_CHK) && (len >= 5) &&
-		 (trash[0] == 0x15 || trash[0] == 0x16)) {
-		/* SSLv3 alert or handshake */
-		result = 1;
+	else if (s->proxy->options & PR_O_SMTP_CHK) {
+		/* Check for SMTP code 2xx (should be 250) */
+		if ((len >= 3) && (trash[0] == '2'))
+			s->result |= SRV_CHK_RUNNING;
+		else
+			s->result |= SRV_CHK_ERROR;
 	}
-	else if ((s->proxy->options & PR_O_SMTP_CHK) && (len >= 3) &&
-		   (trash[0] == '2')) /* 2xx (should be 250) */ {
-		result = 1;
+	else {
+		/* other checks are valid if the connection succeeded anyway */
+		s->result |= SRV_CHK_RUNNING;
 	}
 
-	if (result == -1)
+ out_wakeup:
+	if (s->result & SRV_CHK_ERROR)
 		fdtab[fd].state = FD_STERROR;
 
-	if (s->result != -1)
-		s->result = result;
-
- out_wakeup:
 	EV_FD_CLR(fd, DIR_RD);
 	task_wakeup(t);
 	fdtab[fd].ev &= ~FD_POLL_RD;
@@ -312,7 +328,7 @@
 		}
 
 		/* we'll initiate a new check */
-		s->result = 0; /* no result yet */
+		s->result = SRV_CHK_UNKNOWN; /* no result yet */
 		if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1) {
 			if ((fd < global.maxsock) &&
 			    (fcntl(fd, F_SETFL, O_NONBLOCK) != -1) &&
@@ -343,7 +359,7 @@
 					if (bind(fd, (struct sockaddr *)&s->source_addr, sizeof(s->source_addr)) == -1) {
 						Alert("Cannot bind to source address before connect() for server %s/%s. Aborting.\n",
 						      s->proxy->id, s->id);
-						s->result = -1;
+						s->result |= SRV_CHK_ERROR;
 					}
 #ifdef CONFIG_HAP_CTTPROXY
 					if ((s->state & SRV_TPROXY_MASK) == SRV_TPROXY_ADDR) {
@@ -362,7 +378,7 @@
 						    setsockopt(fd, SOL_IP, IP_TPROXY, &itp2, sizeof(itp2)) == -1) {
 							Alert("Cannot bind to tproxy source address before connect() for server %s/%s. Aborting.\n",
 							      s->proxy->id, s->id);
-							s->result = -1;
+							s->result |= SRV_CHK_ERROR;
 						}
 					}
 #endif
@@ -372,7 +388,7 @@
 					if (bind(fd, (struct sockaddr *)&s->proxy->source_addr, sizeof(s->proxy->source_addr)) == -1) {
 						Alert("Cannot bind to source address before connect() for %s '%s'. Aborting.\n",
 						      proxy_type_str(s->proxy), s->proxy->id);
-						s->result = -1;
+						s->result |= SRV_CHK_ERROR;
 					}
 #ifdef CONFIG_HAP_CTTPROXY
 					if ((s->proxy->options & PR_O_TPXY_MASK) == PR_O_TPXY_ADDR) {
@@ -391,13 +407,13 @@
 						    setsockopt(fd, SOL_IP, IP_TPROXY, &itp2, sizeof(itp2)) == -1) {
 							Alert("Cannot bind to tproxy source address before connect() for %s '%s'. Aborting.\n",
 							      proxy_type_str(s->proxy), s->proxy->id);
-							s->result = -1;
+							s->result |= SRV_CHK_ERROR;
 						}
 					}
 #endif
 				}
 
-				if (!s->result) {
+				if (s->result == SRV_CHK_UNKNOWN) {
 					if ((connect(fd, (struct sockaddr *)&sa, sizeof(sa)) != -1) || (errno == EINPROGRESS)) {
 						/* OK, connection in progress or established */
 			
@@ -425,14 +441,14 @@
 						return;
 					}
 					else if (errno != EALREADY && errno != EISCONN && errno != EAGAIN) {
-						s->result = -1;    /* a real error */
+						s->result |= SRV_CHK_ERROR;    /* a real error */
 					}
 				}
 			}
 			close(fd); /* socket creation error */
 		}
 
-		if (!s->result) { /* nothing done */
+		if (s->result == SRV_CHK_UNKNOWN) { /* nothing done */
 			//fprintf(stderr, "process_chk: 6\n");
 			while (tv_isle(&t->expire, &now))
 				tv_ms_add(&t->expire, &t->expire, s->inter);
@@ -456,7 +472,7 @@
 	else {
 		//fprintf(stderr, "process_chk: 8\n");
 		/* there was a test running */
-		if (s->result > 0) { /* good server detected */
+		if ((s->result & (SRV_CHK_ERROR|SRV_CHK_RUNNING)) == SRV_CHK_RUNNING) { /* good server detected */
 			//fprintf(stderr, "process_chk: 9\n");
 
 			if (s->health < s->rise + s->fall - 1) {
@@ -521,7 +537,7 @@
 			tv_ms_add(&t->expire, &now, s->inter + rv);
 			goto new_chk;
 		}
-		else if (s->result < 0 || tv_isle(&t->expire, &now)) {
+		else if ((s->result & SRV_CHK_ERROR) || tv_isle(&t->expire, &now)) {
 			//fprintf(stderr, "process_chk: 10\n");
 			/* failure or timeout detected */
 			if (s->health > s->rise) {
@@ -542,10 +558,10 @@
 			tv_ms_add(&t->expire, &now, s->inter + rv);
 			goto new_chk;
 		}
-		/* if result is 0 and there's no timeout, we have to wait again */
+		/* if result is unknown and there's no timeout, we have to wait again */
 	}
 	//fprintf(stderr, "process_chk: 11\n");
-	s->result = 0;
+	s->result = SRV_CHK_UNKNOWN;
 	task_queue(t);	/* restore t to its place in the task list */
 	*next = t->expire;
  out: