From 2b199c9ac33703e3e212d9643ee4816464078e3c Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 23 Nov 2012 17:32:21 +0100 Subject: [PATCH] MEDIUM: connection: provide a common conn_full_close() function Several places got the connection close sequence wrong because it was not obvious. In practice we always need the same sequence when aborting, so let's have a common function for this. --- include/proto/connection.h | 18 ++++++++++++++++++ src/checks.c | 13 +++---------- src/session.c | 7 +------ src/stream_interface.c | 11 +++-------- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/include/proto/connection.h b/include/proto/connection.h index 4686e7f115..3bf337dcbd 100644 --- a/include/proto/connection.h +++ b/include/proto/connection.h @@ -26,6 +26,7 @@ #include #include #include +#include #include extern struct pool_head *pool2_connection; @@ -66,6 +67,23 @@ static inline void conn_xprt_close(struct connection *conn) } } +/* If the connection still has a transport layer, then call its close() function + * if any, and delete the file descriptor if a control layer is set. This is + * used to close everything at once and atomically. However this is not done if + * the CO_FL_XPRT_TRACKED flag is set, which allows logs to take data from the + * transport layer very late if needed. + */ +static inline void conn_full_close(struct connection *conn) +{ + if (conn->xprt && !(conn->flags & CO_FL_XPRT_TRACKED)) { + if (conn->xprt->close) + conn->xprt->close(conn); + if (conn->ctrl) + fd_delete(conn->t.sock.fd); + conn->xprt = NULL; + } +} + /* Update polling on connection 's file descriptor depending on its current * state as reported in the connection's CO_FL_CURR_* flags, reports of EAGAIN * in CO_FL_WAIT_*, and the sock layer expectations indicated by CO_FL_SOCK_*. diff --git a/src/checks.c b/src/checks.c index 530ccd8bcf..e63d34e8c3 100644 --- a/src/checks.c +++ b/src/checks.c @@ -1184,12 +1184,8 @@ static int wake_srv_chk(struct connection *conn) if (unlikely(conn->flags & CO_FL_ERROR)) task_wakeup(s->check.task, TASK_WOKEN_IO); - if (s->result & (SRV_CHK_FAILED|SRV_CHK_PASSED)) { - conn_xprt_close(conn); - if (conn->ctrl) - fd_delete(conn->t.sock.fd); - conn->ctrl = NULL; - } + if (s->result & (SRV_CHK_FAILED|SRV_CHK_PASSED)) + conn_full_close(conn); return 0; } @@ -1387,10 +1383,7 @@ static struct task *process_chk(struct task *t) /* the check expired and the connection was not * yet closed, start by doing this. */ - conn_xprt_close(conn); - if (conn->ctrl) - fd_delete(conn->t.sock.fd); - conn->ctrl = NULL; + conn_full_close(conn); } if ((conn->flags & (CO_FL_CONNECTED|CO_FL_WAIT_L4_CONN)) == CO_FL_WAIT_L4_CONN) { diff --git a/src/session.c b/src/session.c index 9827eb82e6..0a070568b1 100644 --- a/src/session.c +++ b/src/session.c @@ -249,7 +249,7 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr) static void kill_mini_session(struct session *s) { /* kill the connection now */ - conn_xprt_close(s->si[0].conn); + conn_full_close(s->si[0].conn); s->fe->feconn--; if (s->stkctr1_entry || s->stkctr2_entry) @@ -273,11 +273,6 @@ static void kill_mini_session(struct session *s) task_delete(s->task); task_free(s->task); - if (fdtab[s->si[0].conn->t.sock.fd].owner) - fd_delete(s->si[0].conn->t.sock.fd); - else - close(s->si[0].conn->t.sock.fd); - pool_free2(pool2_connection, s->si[1].conn); pool_free2(pool2_connection, s->si[0].conn); pool_free2(pool2_session, s); diff --git a/src/stream_interface.c b/src/stream_interface.c index aa8677375b..e70f0f54dc 100644 --- a/src/stream_interface.c +++ b/src/stream_interface.c @@ -227,9 +227,7 @@ int stream_int_shutr(struct stream_interface *si) return 0; if (si->ob->flags & CF_SHUTW) { - conn_xprt_close(si->conn); - if (conn->ctrl) - fd_delete(si->conn->t.sock.fd); + conn_full_close(si->conn); si->state = SI_ST_DIS; si->exp = TICK_ETERNITY; @@ -318,9 +316,7 @@ int stream_int_shutw(struct stream_interface *si) /* we may have to close a pending connection, and mark the * response buffer as shutr */ - conn_xprt_close(si->conn); - if (conn->ctrl) - fd_delete(si->conn->t.sock.fd); + conn_full_close(si->conn); /* fall through */ case SI_ST_CER: case SI_ST_QUE: @@ -1166,8 +1162,7 @@ void stream_sock_read0(struct stream_interface *si) do_close: /* OK we completely close the socket here just as if we went through si_shut[rw]() */ - conn_xprt_close(si->conn); - fd_delete(si->conn->t.sock.fd); + conn_full_close(si->conn); si->ib->flags &= ~CF_SHUTR_NOW; si->ib->flags |= CF_SHUTR; -- 2.39.5