[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:
parent
a3780f2db8
commit
844553303d
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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 */
|
||||
|
|
128
src/session.c
128
src/session.c
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue