MINOR: tevt/connection: Add support for POLL_HUP/POLL_ERR events

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.
This commit is contained in:
Christopher Faulet 2025-01-30 11:31:59 +01:00
parent c7457427ab
commit 71320fc9c1
4 changed files with 31 additions and 18 deletions

View 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] = {

View 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 {

View 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;

View 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);