MEDIUM: monitor: simplify handling of monitor-net and mode health

We were having several different behaviours with monitor-net and
"mode health" :
  - monitor-net on TCP connections was evaluated just after accept(),
    did not count a connection on the frontend and were not subject
    to tcp-request connection rules, and caused an immediate close().

  - monitor-net in HTTP mode was evaluated once the session was
    accepted (eg: on top of SSL), returned "HTTP/1.0 200 OK\r\n\r\n"
    over the connection's data layer and instanciated a session which
    was responsible for closing this connection. A connection AND a
    session were counted for the frontend ;

  - "mode health" with "option httpchk" would do exactly the same as
    monitor-net in HTTP mode ;

  - "mode health" without "option httpchk" would do the same as above
    except that "OK" was returned instead of "HTTP/1.0 200 OK\r\n\r\n".

None of them took care of cleaning the input buffer, sometimes resulting
in a TCP reset to be emitted after the last packet if a request was received
over the connection.

Given the inconsistencies and the complexity in keeping all these features
handled at the right position, we now slightly changed the way they are
handled :

  - all of them are handled just after the "tcp-request connection" rules,
    so that all of them may be blocked using such rules, offering more
    flexibility and consistency ;

  - no connection handshake is performed anymore for non-TCP modes

  - all of them send the response as raw data over the socket, there is no
    more difference between TCP and HTTP mode for example (these rules were
    never meant to be served over SSL connections and were never documented
    as able to do that).

  - any possible pending data on the incoming socket is drained before the
    response is sent, in order to avoid the risk of a reset.

  - none of them exactly did what was documented !

This results in more consistent, more flexible and more accurate handling of
monitor rules, with smaller and more robust code.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 3788ac0..ae830c0 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -2628,11 +2628,13 @@
               brings HAProxy most of its value.
 
     health    The instance will work in "health" mode. It will just reply "OK"
-              to incoming connections and close the connection. Nothing will be
-              logged. This mode is used to reply to external components health
-              checks. This mode is deprecated and should not be used anymore as
-              it is possible to do the same and even better by combining TCP or
-              HTTP modes with the "monitor" keyword.
+              to incoming connections and close the connection. Alternatively,
+              If the "httpchk" option is set, "HTTP/1.0 200 OK" will be sent
+              instead. Nothing will be logged in either case. This mode is used
+              to reply to external components health checks. This mode is
+              deprecated and should not be used anymore as it is possible to do
+              the same and even better by combining TCP or HTTP modes with the
+              "monitor" keyword.
 
   When doing content switching, it is mandatory that the frontend and the
   backend are in the same mode (generally HTTP), otherwise the configuration
@@ -2701,13 +2703,16 @@
   accepted, the following response will be sent without waiting for a request,
   then the connection will be closed : "HTTP/1.0 200 OK". This is normally
   enough for any front-end HTTP probe to detect that the service is UP and
-  running without forwarding the request to a backend server.
+  running without forwarding the request to a backend server. Note that this
+  response is sent in raw format, without any transformation. This is important
+  as it means that it will not be SSL-encrypted on SSL listeners.
 
-  Monitor requests are processed very early. It is not possible to block nor
-  divert them using ACLs. They cannot be logged either, and it is the intended
-  purpose. They are only used to report HAProxy's health to an upper component,
-  nothing more. Right now, it is not possible to set failure conditions on
-  requests caught by "monitor-net".
+  Monitor requests are processed very early, just after tcp-request connection
+  ACLs which are the only ones able to block them. These connections are short
+  lived and never wait for any data from the client. They cannot be logged, and
+  it is the intended purpose. They are only used to report HAProxy's health to
+  an upper component, nothing more. Please note that "monitor fail" rules do
+  not apply to connections intercepted by "monitor-net".
 
   Last, please note that only one "monitor-net" statement can be specified in
   a frontend. If more than one is found, only the last one will be considered.
diff --git a/src/frontend.c b/src/frontend.c
index b2b6b11..3bfd1e5 100644
--- a/src/frontend.c
+++ b/src/frontend.c
@@ -197,27 +197,6 @@
 	s->req->rto = s->fe->timeout.client;
 	s->rep->wto = s->fe->timeout.client;
 
-	if (unlikely((s->fe->mode == PR_MODE_HTTP && (s->flags & SN_MONITOR)) ||
-		     (s->fe->mode == PR_MODE_HEALTH && ((s->fe->options2 & PR_O2_CHK_ANY) == PR_O2_HTTP_CHK)))) {
-		/* Either we got a request from a monitoring system on an HTTP instance,
-		 * or we're in health check mode with the 'httpchk' option enabled. In
-		 * both cases, we return a fake "HTTP/1.0 200 OK" response and we exit.
-		 */
-		struct chunk msg;
-		chunk_initstr(&msg, "HTTP/1.0 200 OK\r\n\r\n");
-		stream_int_retnclose(&s->si[0], &msg); /* forge a 200 response */
-		s->req->analysers = 0;
-		s->task->expire = s->rep->wex;
-		fd_stop_recv(cfd);
-	}
-	else if (unlikely(s->fe->mode == PR_MODE_HEALTH)) {  /* health check mode, no client reading */
-		struct chunk msg;
-		chunk_initstr(&msg, "OK\n");
-		stream_int_retnclose(&s->si[0], &msg); /* forge an "OK" response */
-		s->req->analysers = 0;
-		s->task->expire = s->rep->wex;
-		fd_stop_recv(cfd);
-	}
 	/* everything's OK, let's go on */
 	return 1;
 
diff --git a/src/listener.c b/src/listener.c
index d704b42..f63f9ba 100644
--- a/src/listener.c
+++ b/src/listener.c
@@ -345,18 +345,6 @@
 			}
 		}
 
-		/* if this connection comes from a known monitoring system, we want to ignore
-		 * it as soon as possible, which means closing it immediately if it is only a
-		 * TCP-based monitoring check.
-		 */
-		if (unlikely((l->options & LI_O_CHK_MONNET) &&
-			     (p->mode == PR_MODE_TCP) &&
-			     addr.ss_family == AF_INET &&
-			     (((struct sockaddr_in *)&addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr)) {
-			close(cfd);
-			continue;
-		}
-
 		if (unlikely(cfd >= global.maxsock)) {
 			send_log(p, LOG_EMERG,
 				 "Proxy %s reached the configured maximum connection limit. Please check the global 'maxconn' value.\n",
diff --git a/src/session.c b/src/session.c
index b98b878..be25ccf 100644
--- a/src/session.c
+++ b/src/session.c
@@ -105,17 +105,6 @@
 
 	proxy_inc_fe_conn_ctr(l, p);
 
-	/* if this session comes from a known monitoring system, we want to ignore
-	 * it as soon as possible, which means closing it immediately for TCP, but
-	 * cleanly.
-	 */
-	if (unlikely((l->options & LI_O_CHK_MONNET) &&
-		     addr->ss_family == AF_INET &&
-		     (((struct sockaddr_in *)addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr)) {
-		s->flags |= SN_MONITOR;
-		s->logs.logwait = 0;
-	}
-
 	/* now evaluate the tcp-request layer4 rules. Since we expect to be able
 	 * to abort right here as soon as possible, we check the rules before
 	 * even initializing the stream interfaces.
@@ -127,16 +116,44 @@
 		goto out_free_session;
 	}
 
+	/* Adjust some socket options */
+	if (unlikely(fcntl(cfd, F_SETFL, O_NONBLOCK) == -1))
+		goto out_free_session;
+
+	/* monitor-net and health mode are processed immediately after TCP
+	 * connection rules. This way it's possible to block them, but they
+	 * never use the lower data layers, they send directly over the socket,
+	 * as they were designed for. We first flush the socket receive buffer
+	 * in order to avoid emission of an RST by the system. We ignore any
+	 * error.
+	 */
+	if (unlikely((p->mode == PR_MODE_HEALTH) ||
+		     ((l->options & LI_O_CHK_MONNET) &&
+		      addr->ss_family == AF_INET &&
+		      (((struct sockaddr_in *)addr)->sin_addr.s_addr & p->mon_mask.s_addr) == p->mon_net.s_addr))) {
+		/* we have 4 possibilities here :
+		 *  - HTTP mode, from monitoring address => send "HTTP/1.0 200 OK"
+		 *  - HEALTH mode with HTTP check => send "HTTP/1.0 200 OK"
+		 *  - HEALTH mode without HTTP check => just send "OK"
+		 *  - TCP mode from monitoring address => just close
+		 */
+		recv(cfd, trash, trashlen, 0&MSG_DONTWAIT);
+		if (p->mode == PR_MODE_HTTP ||
+		    (p->mode == PR_MODE_HEALTH && (p->options2 & PR_O2_CHK_ANY) == PR_O2_HTTP_CHK))
+			send(cfd, "HTTP/1.0 200 OK\r\n\r\n", 19, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_MORE);
+		else if (p->mode == PR_MODE_HEALTH)
+			send(cfd, "OK\n", 3, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_MORE);
+		ret = 0;
+		goto out_free_session;
+	}
+
+
 	/* wait for a PROXY protocol header */
 	if (l->options & LI_O_ACC_PROXY) {
 		s->si[0].conn.flags |= CO_FL_ACCEPT_PROXY;
 		conn_sock_want_recv(&s->si[0].conn);
 	}
 
-	/* Adjust some socket options */
-	if (unlikely(fcntl(cfd, F_SETFL, O_NONBLOCK) == -1))
-		goto out_free_session;
-
 	if (unlikely((t = task_new()) == NULL))
 		goto out_free_session;