From: Willy Tarreau Date: Wed, 3 Oct 2012 19:12:16 +0000 (+0200) Subject: MEDIUM: connection: make it possible for data->wake to return an error X-Git-Tag: v1.5-dev13~212 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2396c1c4a24052e34af0e2b165cf86deeef069aa;p=thirdparty%2Fhaproxy.git MEDIUM: connection: make it possible for data->wake to return an error Just like ->init(), ->wake() may now be used to return an error and abort the connection. Currently this is not used but will be with embryonic sessions. --- diff --git a/include/types/connection.h b/include/types/connection.h index 44fdb0d6c8..3219309dbb 100644 --- a/include/types/connection.h +++ b/include/types/connection.h @@ -180,12 +180,13 @@ struct xprt_ops { * at the transport layer, which can be a connection opening/close, or any * data movement. The callback may be called by the connection handler * at the end of a transport handshake, when it is about to transfer data and - * the data layer is not ready yet. + * the data layer is not ready yet. Both and may abort a connection + * by returning < 0. */ struct data_cb { void (*recv)(struct connection *conn); /* data-layer recv callback */ void (*send)(struct connection *conn); /* data-layer send callback */ - void (*wake)(struct connection *conn); /* data-layer callback to report activity */ + int (*wake)(struct connection *conn); /* data-layer callback to report activity */ int (*init)(struct connection *conn); /* data-layer initialization */ }; diff --git a/src/connection.c b/src/connection.c index 949e9ccd3e..e156366f2b 100644 --- a/src/connection.c +++ b/src/connection.c @@ -123,8 +123,14 @@ int conn_fd_handler(int fd) return 0; } - if ((conn->flags & CO_FL_WAKE_DATA) && ((conn->flags ^ flags) & CO_FL_CONN_STATE)) - conn->data->wake(conn); + /* The wake callback may be used to process a critical error and abort the + * connection. If so, we don't want to go further as the connection will + * have been released and the FD destroyed. + */ + if ((conn->flags & CO_FL_WAKE_DATA) && + ((conn->flags ^ flags) & CO_FL_CONN_STATE) && + conn->data->wake(conn) < 0) + return 0; /* Last check, verify if the connection just established */ if (unlikely(!(conn->flags & (CO_FL_WAIT_L4_CONN | CO_FL_WAIT_L6_CONN | CO_FL_CONNECTED)))) diff --git a/src/stream_interface.c b/src/stream_interface.c index 83e085920c..8bc5bbbb25 100644 --- a/src/stream_interface.c +++ b/src/stream_interface.c @@ -46,7 +46,7 @@ static void stream_int_chk_rcv_conn(struct stream_interface *si); static void stream_int_chk_snd_conn(struct stream_interface *si); static void si_conn_recv_cb(struct connection *conn); static void si_conn_send_cb(struct connection *conn); -static void si_conn_wake_cb(struct connection *conn); +static int si_conn_wake_cb(struct connection *conn); /* stream-interface operations for embedded tasks */ struct si_ops si_embedded_ops = { @@ -561,9 +561,9 @@ int conn_si_send_proxy(struct connection *conn, unsigned int flag) * the update function in that it is designed to be called by lower layers after I/O * events have been completed. It will also try to wake the associated task up if * an important event requires special handling. It relies on the connection handler - * to commit any polling updates. + * to commit any polling updates. The function always returns 0. */ -static void si_conn_wake_cb(struct connection *conn) +static int si_conn_wake_cb(struct connection *conn) { struct stream_interface *si = conn->owner; @@ -659,6 +659,7 @@ static void si_conn_wake_cb(struct connection *conn) } if (si->ib->flags & CF_READ_ACTIVITY) si->ib->flags &= ~CF_READ_DONTWAIT; + return 0; } /*