From: Willy Tarreau Date: Fri, 6 Dec 2013 13:19:25 +0000 (+0100) Subject: BUG/MEDIUM: check: tcp-check might miss some outgoing data when socket buffers are... X-Git-Tag: v1.5-dev20~149 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=abca5b6ab533223e653d0207f959b3bfe5d8d551;p=thirdparty%2Fhaproxy.git BUG/MEDIUM: check: tcp-check might miss some outgoing data when socket buffers are full If a "tcp-check send" experiences an EAGAIN on a send() call, it will nevertheless go to next rule, and will not try to send again if the next rule is an expect. Change this so that we always try to send whatever remains in the buffer before doing anything else. --- diff --git a/src/checks.c b/src/checks.c index 1af672598a..6373783cf0 100644 --- a/src/checks.c +++ b/src/checks.c @@ -1981,7 +1981,23 @@ static void tcpcheck_main(struct connection *conn) cur = check->current_step; } - while (&cur->list != head) { + while (1) { + /* we must always ensure that nothing remains in the output buffer */ + while (check->bo->o) { + conn->xprt->snd_buf(conn, check->bo, MSG_DONTWAIT | MSG_NOSIGNAL); + if (conn->flags & CO_FL_ERROR) { + chk_report_conn_err(conn, errno, 0); + __conn_data_stop_both(conn); + goto out_end_tcpcheck; + } + if (conn->flags & CO_FL_WAIT_WR) + goto out_incomplete; + } + + /* did we reach the end ? */ + if (&cur->list == head) + break; + if (check->current_step->action & TCPCHK_ACT_SEND) { /* reset the read buffer */ if (*check->bi->data != '\0') { @@ -1998,27 +2014,20 @@ static void tcpcheck_main(struct connection *conn) if (conn->flags & (CO_FL_HANDSHAKE | CO_FL_WAIT_WR)) return; - /* disable reading for now */ - __conn_data_stop_recv(conn); + if (check->current_step->string_len >= check->bo->size) { + chunk_printf(&trash, "tcp-check send : string too large (%d) for buffer size (%d) at step %d", + check->current_step->string_len, check->bo->size, + tcpcheck_get_step_id(s)); + set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str); + goto out_end_tcpcheck; + } bo_putblk(check->bo, check->current_step->string, check->current_step->string_len); *check->bo->p = '\0'; /* to make gdb output easier to read */ - if (check->bo->o) { - conn->xprt->snd_buf(conn, check->bo, MSG_DONTWAIT | MSG_NOSIGNAL); - if (conn->flags & CO_FL_ERROR) { - chk_report_conn_err(conn, errno, 0); - __conn_data_stop_both(conn); - goto out_end_tcpcheck; - } - } + /* go to next rule and try to send */ cur = (struct tcpcheck_rule *)cur->list.n; check->current_step = cur; - - if (check->bo->o) - goto out_incomplete; - - __conn_data_stop_send(conn); /* nothing more to write */ } /* end 'send' */ else if (check->current_step->action & TCPCHK_ACT_EXPECT) { if (unlikely(check->result & SRV_CHK_FAILED))