[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.
diff --git a/include/proto/session.h b/include/proto/session.h
index 7cc50f6..737e065 100644
--- a/include/proto/session.h
+++ b/include/proto/session.h
@@ -37,6 +37,8 @@
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)
{
diff --git a/src/client.c b/src/client.c
index 9bff17b..f5ce3c6 100644
--- a/src/client.c
+++ b/src/client.c
@@ -227,7 +227,7 @@
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 */
diff --git a/src/session.c b/src/session.c
index b5cb81e..6bb6a45 100644
--- a/src/session.c
+++ b/src/session.c
@@ -206,6 +206,8 @@
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 @@
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 @@
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 @@
}
}
+/* 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: