]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: connection: clear errno prior to checking for errors
authorWilly Tarreau <w@1wt.eu>
Wed, 4 Dec 2013 23:49:40 +0000 (00:49 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 5 Dec 2013 01:23:48 +0000 (02:23 +0100)
At some places, we report an error by just detecting FD_POLL_ERR.
The problem is that the caller never knows if it must use errno or
call getsockopt(SO_ERROR). And since this last one clears the
pending error from the queue, it cannot be used inconditionally.

An elegant solution consists in clearing errno prior to inspecting
FD_POLL_ERR. The caller then knows that if it gets CO_FL_ERROR and
errno == 0, it must call getsockopt().

src/raw_sock.c

index ec76604397762f0d8a479bd076da18cbd9e13441..43cd70a830411be7cd2f082aee6b8fa803ae29ca 100644 (file)
@@ -74,6 +74,8 @@ int raw_sock_to_pipe(struct connection *conn, struct pipe *pipe, unsigned int co
        int ret;
        int retval = 0;
 
+       errno = 0;
+
        /* Under Linux, if FD_POLL_HUP is set, we have reached the end.
         * Since older splice() implementations were buggy and returned
         * EAGAIN on end of read, let's bypass the call to splice() now.
@@ -86,6 +88,7 @@ int raw_sock_to_pipe(struct connection *conn, struct pipe *pipe, unsigned int co
                /* report error on POLL_ERR before connection establishment */
                if ((fdtab[conn->t.sock.fd].ev & FD_POLL_ERR) && (conn->flags & CO_FL_WAIT_L4_CONN)) {
                        conn->flags |= CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
+                       errno = 0; /* let the caller do a getsockopt() if it wants it */
                        return retval;
                }
        }
@@ -223,12 +226,16 @@ int raw_sock_from_pipe(struct connection *conn, struct pipe *pipe)
  * empty). The caller is responsible for taking care of those events and
  * avoiding the call if inappropriate. The function does not call the
  * connection's polling update function, so the caller is responsible for this.
+ * errno is cleared before starting so that the caller knows that if it spots an
+ * error without errno, it's pending and can be retrieved via getsockopt(SO_ERROR).
  */
 static int raw_sock_to_buf(struct connection *conn, struct buffer *buf, int count)
 {
        int ret, done = 0;
        int try = count;
 
+       errno = 0;
+
        if (unlikely(!(fdtab[conn->t.sock.fd].ev & FD_POLL_IN))) {
                /* stop here if we reached the end of data */
                if ((fdtab[conn->t.sock.fd].ev & (FD_POLL_ERR|FD_POLL_HUP)) == FD_POLL_HUP)