]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[BUG] check: we must not check for error before reading a response
authorWilly Tarreau <w@1wt.eu>
Fri, 15 Jan 2010 09:35:58 +0000 (10:35 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 28 Jan 2010 22:16:37 +0000 (23:16 +0100)
We can receive data with a notification of socket error. But we
must not check for the error before reading the data, because it
may be an asynchronous error notification that we check too early
while the response we're waiting for is available. If there is an
error, recv() will get it.

This should help with servers that close very fast after the response
and should also slightly lower the CPU usage during very fast checks
on massive amounts of servers since we eliminate one system call.

This should probably be backported to 1.3.

(cherry picked from commit a5aa1c86a55f795dc9d52afe0ba0a2847e4c1e5d)

src/checks.c

index 4d988308123dec46ee3f539dd0f14659a86d04ef..36df06f9bfd8534780cdc27717fe404bb2375736 100644 (file)
@@ -435,16 +435,12 @@ static int event_srv_chk_r(int fd)
        int len;
        struct task *t = fdtab[fd].owner;
        struct server *s = t->context;
-       int skerr;
-       socklen_t lskerr = sizeof(skerr);
 
        len = -1;
 
        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))) {
+                    (fdtab[fd].ev & FD_POLL_ERR))) {
                /* in case of TCP only, this tells us if the connection failed */
                s->result |= SRV_CHK_ERROR;
                goto out_wakeup;
@@ -455,10 +451,15 @@ static int event_srv_chk_r(int fd)
         * works correctly and we don't need to do the getsockopt() on linux.
         */
        len = recv(fd, trash, sizeof(trash), 0);
-       if (unlikely(len < 0 && errno == EAGAIN)) {
-               /* we want some polling to happen first */
-               fdtab[fd].ev &= ~FD_POLL_IN;
-               return 0;
+       if (unlikely(len < 0)) {
+               if (errno == EAGAIN) {
+                       /* not ready, we want to poll first */
+                       fdtab[fd].ev &= ~FD_POLL_IN;
+                       return 0;
+               }
+               /* network error, report it */
+               s->result |= SRV_CHK_ERROR;
+               goto out_wakeup;
        }
 
        /* Note: the response will only be accepted if read at once */