[BUG] session: errors were not reported in termination flags in TCP mode

In order to get termination flags properly updated, the session was
relying a bit too much on http_return_srv_error() which is http-centric.

A generic srv_error function was implemented in the session in order to
catch all connection abort situations. It was then noticed that a request
abort during a connection attempt was not reported, which is now fixed.

Read and write errors/timeouts were not logged either. It was necessary
to add those tests at 4 new locations.

Now it looks like everything is correctly logged. Most likely some error
checking code could now be removed from some analysers.
This commit is contained in:
Willy Tarreau 2009-03-15 22:34:05 +01:00
parent a3780f2db8
commit 844553303d
3 changed files with 131 additions and 1 deletions

View File

@ -37,6 +37,8 @@ int init_session();
void session_process_counters(struct session *s);
void sess_change_server(struct session *sess, struct server *newsrv);
struct task *process_session(struct task *t);
void sess_set_term_flags(struct session *s);
void default_srv_error(struct session *s, struct stream_interface *si);
static void inline trace_term(struct session *s, unsigned int code)
{

View File

@ -227,7 +227,7 @@ int event_accept(int fd) {
if (p->mode == PR_MODE_HTTP)
s->srv_error = http_return_srv_error;
else
s->srv_error = NULL;
s->srv_error = default_srv_error;
s->logs.accept_date = date; /* user-visible date for logging */
s->logs.tv_accept = now; /* corrected date for internal use */

View File

@ -206,6 +206,8 @@ int sess_update_st_con_tcp(struct session *s, struct stream_interface *si)
si->shutw(si);
si->err_type |= SI_ET_CONN_ABRT;
si->err_loc = s->srv;
if (s->srv_error)
s->srv_error(s, si);
return 1;
}
@ -758,12 +760,42 @@ struct task *process_session(struct task *t)
break;
}
}
/* Report it if the client got an error or a read timeout expired */
if (unlikely(s->req->flags & (BF_READ_ERROR|BF_READ_TIMEOUT|BF_WRITE_ERROR|BF_WRITE_TIMEOUT)) &&
!(s->flags & SN_ERR_MASK)) {
s->req->analysers = 0;
if (s->req->flags & BF_READ_ERROR)
s->flags |= SN_ERR_CLICL;
else if (s->req->flags & BF_READ_TIMEOUT)
s->flags |= SN_ERR_CLITO;
else if (s->req->flags & BF_WRITE_ERROR)
s->flags |= SN_ERR_SRVCL;
else
s->flags |= SN_ERR_SRVTO;
sess_set_term_flags(s);
}
s->req->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT;
flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT;
if (s->req->flags != flags)
resync = 1;
}
/* Report it if the client got an error or a read timeout expired */
if (unlikely(s->req->flags & (BF_READ_ERROR|BF_READ_TIMEOUT|BF_WRITE_ERROR|BF_WRITE_TIMEOUT)) &&
!(s->flags & SN_ERR_MASK)) {
if (s->req->flags & BF_READ_ERROR)
s->flags |= SN_ERR_CLICL;
else if (s->req->flags & BF_READ_TIMEOUT)
s->flags |= SN_ERR_CLITO;
else if (s->req->flags & BF_WRITE_ERROR)
s->flags |= SN_ERR_SRVCL;
else
s->flags |= SN_ERR_SRVTO;
sess_set_term_flags(s);
}
/* If noone is interested in analysing data, it's time to forward
* everything. We will wake up from time to time when either send_max
* or to_forward are reached.
@ -906,12 +938,42 @@ struct task *process_session(struct task *t)
if (s->rep->analysers)
process_response(s);
}
/* Report it if the server got an error or a read timeout expired */
if (unlikely(s->rep->flags & (BF_READ_ERROR|BF_READ_TIMEOUT|BF_WRITE_ERROR|BF_WRITE_TIMEOUT)) &&
!(s->flags & SN_ERR_MASK)) {
s->rep->analysers = 0;
if (s->rep->flags & BF_READ_ERROR)
s->flags |= SN_ERR_SRVCL;
else if (s->rep->flags & BF_READ_TIMEOUT)
s->flags |= SN_ERR_SRVTO;
else if (s->rep->flags & BF_WRITE_ERROR)
s->flags |= SN_ERR_CLICL;
else
s->flags |= SN_ERR_CLITO;
sess_set_term_flags(s);
}
s->rep->flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT;
flags &= BF_CLEAR_READ & BF_CLEAR_WRITE & BF_CLEAR_TIMEOUT;
if (s->rep->flags != flags)
resync = 1;
}
/* Report it if the server got an error or a read timeout expired */
if (unlikely(s->rep->flags & (BF_READ_ERROR|BF_READ_TIMEOUT|BF_WRITE_ERROR|BF_WRITE_TIMEOUT)) &&
!(s->flags & SN_ERR_MASK)) {
if (s->rep->flags & BF_READ_ERROR)
s->flags |= SN_ERR_SRVCL;
else if (s->rep->flags & BF_READ_TIMEOUT)
s->flags |= SN_ERR_SRVTO;
else if (s->rep->flags & BF_WRITE_ERROR)
s->flags |= SN_ERR_CLICL;
else
s->flags |= SN_ERR_CLITO;
sess_set_term_flags(s);
}
/* If noone is interested in analysing data, it's time to forward
* everything. We will wake up from time to time when either send_max
* or to_forward are reached.
@ -1135,6 +1197,72 @@ void sess_change_server(struct session *sess, struct server *newsrv)
}
}
/* Set correct session termination flags in case no analyser has done it. It
* also counts a failed request if the server state has not reached the request
* stage.
*/
void sess_set_term_flags(struct session *s)
{
if (!(s->flags & SN_FINST_MASK)) {
if (s->si[1].state < SI_ST_REQ) {
s->fe->failed_req++;
s->flags |= SN_FINST_R;
}
else if (s->si[1].state == SI_ST_QUE)
s->flags |= SN_FINST_Q;
else if (s->si[1].state < SI_ST_EST)
s->flags |= SN_FINST_C;
else if (s->si[1].state == SI_ST_EST)
s->flags |= SN_FINST_D;
else
s->flags |= SN_FINST_L;
}
}
/* Handle server-side errors for default protocols. It is called whenever a a
* connection setup is aborted or a request is aborted in queue. It sets the
* session termination flags so that the caller does not have to worry about
* them. It's installed as ->srv_error for the server-side stream_interface.
*/
void default_srv_error(struct session *s, struct stream_interface *si)
{
int err_type = si->err_type;
int err = 0, fin = 0;
if (err_type & SI_ET_QUEUE_ABRT) {
err = SN_ERR_CLICL;
fin = SN_FINST_Q;
}
else if (err_type & SI_ET_CONN_ABRT) {
err = SN_ERR_CLICL;
fin = SN_FINST_C;
}
else if (err_type & SI_ET_QUEUE_TO) {
err = SN_ERR_SRVTO;
fin = SN_FINST_Q;
}
else if (err_type & SI_ET_QUEUE_ERR) {
err = SN_ERR_SRVCL;
fin = SN_FINST_Q;
}
else if (err_type & SI_ET_CONN_TO) {
err = SN_ERR_SRVTO;
fin = SN_FINST_C;
}
else if (err_type & SI_ET_CONN_ERR) {
err = SN_ERR_SRVCL;
fin = SN_FINST_C;
}
else /* SI_ET_CONN_OTHER and others */ {
err = SN_ERR_INTERNAL;
fin = SN_FINST_C;
}
if (!(s->flags & SN_ERR_MASK))
s->flags |= err;
if (!(s->flags & SN_FINST_MASK))
s->flags |= fin;
}
/*
* Local variables: