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.
This commit is contained in:
Willy Tarreau 2012-11-23 17:32:21 +01:00
parent db3b4a2891
commit 2b199c9ac3
4 changed files with 25 additions and 24 deletions

View File

@ -26,6 +26,7 @@
#include <common/memory.h>
#include <types/connection.h>
#include <types/listener.h>
#include <proto/fd.h>
#include <proto/obj_type.h>
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 <c>'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_*.

View File

@ -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) {

View File

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

View File

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