From e3224e870f335b04e1eca4e2b74b1974ab063cff Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 29 Oct 2012 22:41:31 +0100 Subject: [PATCH] BUG/MINOR: session: ensure that we don't retry connection if some data were sent With extra-large buffers, it is possible that a lot of data are sent upon connection establishment before the session is notified. The issue is how to handle a send() error after some data were actually sent. At the moment, only a connection error is reported, causing a new connection attempt and send() to restart after the last data. We absolutely don't want to retry the connect() if at least one byte was sent, because those data are lost. The solution consists in reporting exactly what happens, which is : - a successful connection attempt - a read/write error on the channel That way we go on with sess_establish(), the response analysers are called and report the appropriate connection state for the error (typically a server abort while waiting for a response). This mechanism also guarantees that we won't retry since it's a success. The logs also report the correct connect time. Note that 1.4 is not directly affected because it only attempts one send(), so it cannot detect a send() failure here and distinguish it form a failed connection attempt. So no backport is needed. Also, this is just a safe belt we're taking, since this issue should not happen anymore since previous commit. --- src/session.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/session.c b/src/session.c index 840ad29d98..9d727034b4 100644 --- a/src/session.c +++ b/src/session.c @@ -762,6 +762,19 @@ static int sess_update_st_con_tcp(struct session *s, struct stream_interface *si * attempts and error reports. */ if (unlikely(si->flags & (SI_FL_EXP|SI_FL_ERR))) { + if (unlikely(si->ob->flags & CF_WRITE_PARTIAL)) { + /* Some data were sent past the connection establishment, + * so we need to pretend we're established to log correctly + * and let later states handle the failure. + */ + s->logs.t_connect = tv_ms_elapsed(&s->logs.tv_accept, &now); + si->exp = TICK_ETERNITY; + si->state = SI_ST_EST; + si->err_type = SI_ET_DATA_ERR; + si->ib->flags |= CF_READ_ERROR | CF_WRITE_ERROR; + si->err_loc = target_srv(&s->target); + return 1; + } si->exp = TICK_ETERNITY; si->state = SI_ST_CER; fd_delete(si_fd(si)); -- 2.39.5