]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: tevt/connection: Add support for POLL_HUP/POLL_ERR events
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 30 Jan 2025 10:31:59 +0000 (11:31 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 31 Jan 2025 09:41:50 +0000 (10:41 +0100)
Connection errors can be detected via connect/recv/send syscall, but also
because it was reported by the poller. So dedicated events, at the FD level,
are introduced to make the difference.

term_events tool was updated accordingly.

dev/term_events/term_events.c
include/haproxy/connection-t.h
src/raw_sock.c
src/sock.c

index 2438500948609b79b0084cb97c3423c38139fcc1..4e9b8d0eda19ec34fcdc975b4622e23ef77a187e 100644 (file)
@@ -23,10 +23,10 @@ static const char *tevt_unknown_types[16] = {
 };
 
 static const char *tevt_fd_types[16] = {
-       [ 0] = "-",           [ 1] = "shutw", [ 2] = "shutr", [ 3] = "rcv_err",
-       [ 4] = "snd_err",     [ 5] = "-",     [ 6] = "-",     [ 7] = "conn_err",
-       [ 8] = "intercepted", [ 9] = "-",     [10] = "-",     [11] = "-",
-       [12] = "-",           [13] = "-",     [14] = "-",     [15] = "-",
+       [ 0] = "-",           [ 1] = "shutw",         [ 2] = "shutr",    [ 3] = "rcv_err",
+       [ 4] = "snd_err",     [ 5] = "-",             [ 6] = "-",        [ 7] = "conn_err",
+       [ 8] = "intercepted", [ 9] = "conn_poll_err", [10] = "poll_err", [11] = "poll_hup",
+       [12] = "-",           [13] = "-",             [14] = "-",        [15] = "-",
 };
 
 static const char *tevt_hs_types[16] = {
index 05561d20a6fef77f4c4ad95a699833dfd9fa3435..98f6cc4711aff2993e0608515b73f1bf045de391 100644 (file)
@@ -763,6 +763,10 @@ enum fd_term_event_type {
        /* unused: 5, 6 */
        fd_tevt_type_connect_err = 7,
        fd_tevt_type_intercepted = 8,
+
+       fd_tevt_type_connect_poll_err  =  9,
+       fd_tevt_type_poll_err          = 10,
+       fd_tevt_type_poll_hup          = 11,
 };
 
 enum hs_term_event_type {
index 255a8c01a6e865e48907a795b21c5779d9c990a1..9264e313055c1567ac878f04cfa53aa8ef7dc754 100644 (file)
@@ -72,12 +72,14 @@ int raw_sock_to_pipe(struct connection *conn, void *xprt_ctx, struct pipe *pipe,
         */
        if (unlikely(!(fdtab[conn->handle.fd].state & FD_POLL_IN))) {
                /* stop here if we reached the end of data */
-               if ((fdtab[conn->handle.fd].state & (FD_POLL_ERR|FD_POLL_HUP)) == FD_POLL_HUP)
+               if ((fdtab[conn->handle.fd].state & (FD_POLL_ERR|FD_POLL_HUP)) == FD_POLL_HUP) {
+                       conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_poll_hup);
                        goto out_read0;
+               }
 
                /* report error on POLL_ERR before connection establishment */
                if ((fdtab[conn->handle.fd].state & FD_POLL_ERR) && (conn->flags & CO_FL_WAIT_L4_CONN)) {
-                       conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_rcv_err);
+                       conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_poll_err);
                        conn->flags |= CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
                        conn_set_errcode(conn, CO_ER_POLLERR);
                        errno = 0; /* let the caller do a getsockopt() if it wants it */
@@ -93,8 +95,10 @@ int raw_sock_to_pipe(struct connection *conn, void *xprt_ctx, struct pipe *pipe,
                             SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
 
                if (ret <= 0) {
-                       if (ret == 0)
+                       if (ret == 0) {
+                               conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_shutr);
                                goto out_read0;
+                       }
 
                        if (errno == EAGAIN || errno == EWOULDBLOCK) {
                                /* there are two reasons for EAGAIN :
@@ -157,7 +161,6 @@ int raw_sock_to_pipe(struct connection *conn, void *xprt_ctx, struct pipe *pipe,
        return retval;
 
  out_read0:
-       conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_shutr);
        conn_sock_read0(conn);
        conn->flags &= ~CO_FL_WAIT_L4_CONN;
        goto leave;
@@ -179,7 +182,6 @@ int raw_sock_from_pipe(struct connection *conn, void *xprt_ctx, struct pipe *pip
 
        if (conn->flags & CO_FL_SOCK_WR_SH) {
                /* it's already closed */
-               conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_snd_err);
                conn->flags |= CO_FL_ERROR | CO_FL_SOCK_RD_SH;
                errno = EPIPE;
                conn_set_errno(conn, errno);
@@ -251,12 +253,14 @@ static size_t raw_sock_to_buf(struct connection *conn, void *xprt_ctx, struct bu
 
        if (unlikely(!(fdtab[conn->handle.fd].state & FD_POLL_IN))) {
                /* stop here if we reached the end of data */
-               if ((fdtab[conn->handle.fd].state & (FD_POLL_ERR|FD_POLL_HUP)) == FD_POLL_HUP)
+               if ((fdtab[conn->handle.fd].state & (FD_POLL_ERR|FD_POLL_HUP)) == FD_POLL_HUP) {
+                       conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_poll_hup);
                        goto read0;
+               }
 
                /* report error on POLL_ERR before connection establishment */
                if ((fdtab[conn->handle.fd].state & FD_POLL_ERR) && (conn->flags & CO_FL_WAIT_L4_CONN)) {
-                       conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_rcv_err);
+                       conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_connect_poll_err);
                        conn->flags |= CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
                        conn_set_errcode(conn, CO_ER_POLLERR);
                        goto leave;
@@ -294,8 +298,10 @@ static size_t raw_sock_to_buf(struct connection *conn, void *xprt_ctx, struct bu
                                 * to read an unlikely close from the client since we'll
                                 * close first anyway.
                                 */
-                               if (fdtab[conn->handle.fd].state & FD_POLL_HUP)
+                               if (fdtab[conn->handle.fd].state & FD_POLL_HUP) {
+                                       conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_poll_hup);
                                        goto read0;
+                               }
 
                                if (!(fdtab[conn->handle.fd].state & FD_LINGER_RISK) ||
                                    (cur_poller.flags & HAP_POLL_F_RDHUP)) {
@@ -308,6 +314,7 @@ static size_t raw_sock_to_buf(struct connection *conn, void *xprt_ctx, struct bu
                                break;
                }
                else if (ret == 0) {
+                       conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_shutr);
                        goto read0;
                }
                else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOTCONN) {
@@ -330,7 +337,6 @@ static size_t raw_sock_to_buf(struct connection *conn, void *xprt_ctx, struct bu
        return done;
 
  read0:
-       conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_shutr);
        conn_sock_read0(conn);
        conn->flags &= ~CO_FL_WAIT_L4_CONN;
 
@@ -342,7 +348,7 @@ static size_t raw_sock_to_buf(struct connection *conn, void *xprt_ctx, struct bu
         * an error without checking.
         */
        if (unlikely(!done && fdtab[conn->handle.fd].state & FD_POLL_ERR)) {
-               conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_rcv_err);
+               conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_poll_err);
                conn->flags |= CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
                conn_set_errcode(conn, CO_ER_POLLERR);
        }
@@ -377,7 +383,7 @@ static size_t raw_sock_from_buf(struct connection *conn, void *xprt_ctx, const s
 
        if (unlikely(fdtab[conn->handle.fd].state & FD_POLL_ERR)) {
                /* an error was reported on the FD, we can't send anymore */
-               conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_snd_err);
+               conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_poll_err);
                conn->flags |= CO_FL_ERROR | CO_FL_SOCK_WR_SH | CO_FL_SOCK_RD_SH;
                conn_set_errcode(conn, CO_ER_POLLERR);
                errno = EPIPE;
index 160016e65e171a39e4891bf7a28e9168142b4ad0..feb05269123e4f91e83dbda402ced833934071b7 100644 (file)
@@ -988,8 +988,10 @@ int sock_conn_check(struct connection *conn)
                if (errno == EALREADY || errno == EINPROGRESS)
                        goto wait;
 
-               if (errno && errno != EISCONN)
+               if (errno && errno != EISCONN) {
+                       conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_connect_err);
                        goto out_error;
+               }
        }
 
  done:
@@ -1007,7 +1009,6 @@ int sock_conn_check(struct connection *conn)
        /* Write error on the file descriptor. Report it to the connection
         * and disable polling on this FD.
         */
-       conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_connect_err);
        conn->flags |= CO_FL_ERROR | CO_FL_SOCK_RD_SH | CO_FL_SOCK_WR_SH;
        HA_ATOMIC_AND(&fdtab[fd].state, ~FD_LINGER_RISK);
        fd_stop_both(fd);
@@ -1018,8 +1019,10 @@ int sock_conn_check(struct connection *conn)
         * in some corner cases while the system disagrees and reports an error
         * on the FD.
         */
-       if (fdtab[fd].state & FD_POLL_ERR)
+       if (fdtab[fd].state & FD_POLL_ERR) {
+               conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_connect_poll_err);
                goto out_error;
+       }
 
        fd_cant_send(fd);
        fd_want_send(fd);