*
* - pure status flags, reported by stream connector layer, which must also
* be cleared before doing further I/O :
- * CF_*_TIMEOUT, CF_*_ERROR
+ * CF_*_TIMEOUT
*
* - read-only indicators reported by lower data levels :
* CF_STREAMER, CF_STREAMER_FAST
#define CF_READ_EVENT 0x00000001 /* a read event detected on producer side */
/* unused: 0x00000002 */
#define CF_READ_TIMEOUT 0x00000004 /* timeout while waiting for producer */
-#define CF_READ_ERROR 0x00000008 /* unrecoverable error on producer side */
+/* unused 0x00000008 */
/* unused: 0x00000010 */
#define CF_SHUTR 0x00000020 /* producer has already shut down */
#define CF_WRITE_EVENT 0x00000100 /* a write event detected on consumer side */
/* unused: 0x00000200 */
#define CF_WRITE_TIMEOUT 0x00000400 /* timeout while waiting for consumer */
-#define CF_WRITE_ERROR 0x00000800 /* unrecoverable error on consumer side */
+/* unused 0x00000800 */
#define CF_WAKE_WRITE 0x00001000 /* wake the task up when there's write activity */
#define CF_SHUTW 0x00002000 /* consumer has already shut down */
#define CF_ISRESP 0x80000000 /* 0 = request channel, 1 = response channel */
/* Masks which define input events for stream analysers */
-#define CF_MASK_ANALYSER (CF_READ_EVENT|CF_READ_ERROR|CF_READ_TIMEOUT|CF_WRITE_EVENT|CF_WRITE_ERROR|CF_WAKE_ONCE)
+#define CF_MASK_ANALYSER (CF_READ_EVENT|CF_READ_TIMEOUT|CF_WRITE_EVENT|CF_WAKE_ONCE)
/* Mask for static flags which cause analysers to be woken up when they change */
#define CF_MASK_STATIC (CF_SHUTR|CF_SHUTW|CF_SHUTR_NOW|CF_SHUTW_NOW)
/* prologue */
_(0);
/* flags */
- _(CF_READ_EVENT, _(CF_READ_TIMEOUT, _(CF_READ_ERROR,
+ _(CF_READ_EVENT, _(CF_READ_TIMEOUT,
_(CF_SHUTR, _(CF_SHUTR_NOW, _(CF_WRITE_EVENT,
- _(CF_WRITE_TIMEOUT, _(CF_WRITE_ERROR,
+ _(CF_WRITE_TIMEOUT,
_(CF_WAKE_WRITE, _(CF_SHUTW, _(CF_SHUTW_NOW, _(CF_AUTO_CLOSE,
_(CF_STREAMER, _(CF_STREAMER_FAST, _(CF_WROTE_DATA,
_(CF_KERN_SPLICING, _(CF_READ_DONTWAIT,
_(CF_AUTO_CONNECT, _(CF_DONT_READ, _(CF_EXPECT_MORE,
_(CF_SEND_DONTWAIT, _(CF_NEVER_WAIT, _(CF_WAKE_ONCE, _(CF_FLT_ANALYZE,
- _(CF_EOI, _(CF_ISRESP))))))))))))))))))))))))));
+ _(CF_EOI, _(CF_ISRESP))))))))))))))))))))))));
/* epilogue */
_(~0U);
return buf;
}
-/* to be called only when in SC_ST_DIS with SC_FL_ERR */
-static inline void sc_report_error(struct stconn *sc)
-{
- if (!__sc_strm(sc)->conn_err_type)
- __sc_strm(sc)->conn_err_type = STRM_ET_DATA_ERR;
-
- sc_oc(sc)->flags |= CF_WRITE_ERROR;
- sc_ic(sc)->flags |= CF_READ_ERROR;
-}
-
/* sets the current and previous state of a stream connector to <state>. This is
* mainly used to create one in the established state on incoming conncetions.
*/
/* Check if the connection request is in such a state that it can be aborted. */
static int back_may_abort_req(struct channel *req, struct stream *s)
{
- return ((req->flags & (CF_READ_ERROR)) ||
+ return (sc_ep_test(s->scf, SE_FL_ERROR) ||
((req->flags & (CF_SHUTW_NOW|CF_SHUTW)) && /* empty and client aborted */
(channel_is_empty(req) || (s->be->options & PR_O_ABRT_CLOSE))));
}
/* Failed and not retryable. */
sc_shutr(sc);
sc_shutw(sc);
- req->flags |= CF_WRITE_ERROR;
+ sc_ep_set(sc, SE_FL_ERROR|SE_FL_EOS);
+ req->flags |= CF_WRITE_EVENT;
s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
sc_shutr(sc);
sc_shutw(sc);
- s->req.flags |= CF_WRITE_ERROR;
+ sc_ep_set(sc, SE_FL_ERROR|SE_FL_EOS);
+ s->req.flags |= CF_WRITE_EVENT;
s->conn_err_type = STRM_ET_CONN_RES;
sc->state = SC_ST_CLO;
if (s->srv_error)
/* we did not get any server, let's check the cause */
sc_shutr(sc);
sc_shutw(sc);
- s->req.flags |= CF_WRITE_ERROR;
+ sc_ep_set(sc, SE_FL_ERROR|SE_FL_EOS);
+ s->req.flags |= CF_WRITE_EVENT;
if (!s->conn_err_type)
s->conn_err_type = STRM_ET_CONN_OTHER;
sc->state = SC_ST_CLO;
/* shutw is enough to stop a connecting socket */
sc_shutw(sc);
- s->req.flags |= CF_WRITE_ERROR;
- s->res.flags |= CF_READ_ERROR;
+ sc_ep_set(sc, SE_FL_ERROR|SE_FL_EOS);
+ s->req.flags |= CF_WRITE_EVENT;
+ s->res.flags |= CF_READ_EVENT;
sc->state = SC_ST_CLO;
if (s->srv_error)
/* shutw is enough to stop a connecting socket */
sc_shutw(sc);
- s->req.flags |= CF_WRITE_ERROR;
- s->res.flags |= CF_READ_ERROR;
+ sc_ep_set(sc, SE_FL_ERROR|SE_FL_EOS);
+ s->req.flags |= CF_WRITE_EVENT;
+ s->res.flags |= CF_READ_EVENT;
sc->state = SC_ST_CLO;
if (s->srv_error)
struct proxy *fe = strm_fe(s);
struct proxy *be = s->be;
- if ((rep->flags & (CF_READ_ERROR|CF_READ_TIMEOUT|CF_WRITE_ERROR|CF_WRITE_TIMEOUT)) ||
+ if (sc_ep_test(s->scb, SE_FL_ERR_PENDING|SE_FL_ERROR) || (rep->flags & (CF_READ_TIMEOUT|CF_WRITE_TIMEOUT)) ||
((rep->flags & CF_SHUTW) && (rep->to_forward || co_data(rep)))) {
pcli_reply_and_close(s, "Can't connect to the target CLI!\n");
s->req.analysers &= ~AN_REQ_WAIT_CLI;
sc_set_state(s->scb, SC_ST_INI);
s->scb->flags &= SC_FL_ISBACK | SC_FL_DONT_WAKE; /* we're in the context of process_stream */
- s->req.flags &= ~(CF_SHUTW|CF_SHUTW_NOW|CF_AUTO_CONNECT|CF_WRITE_ERROR|CF_STREAMER|CF_STREAMER_FAST|CF_NEVER_WAIT|CF_WROTE_DATA);
- s->res.flags &= ~(CF_SHUTR|CF_SHUTR_NOW|CF_READ_ERROR|CF_STREAMER|CF_STREAMER_FAST|CF_WRITE_EVENT|CF_NEVER_WAIT|CF_WROTE_DATA|CF_READ_EVENT);
+ s->req.flags &= ~(CF_SHUTW|CF_SHUTW_NOW|CF_AUTO_CONNECT|CF_STREAMER|CF_STREAMER_FAST|CF_NEVER_WAIT|CF_WROTE_DATA);
+ s->res.flags &= ~(CF_SHUTR|CF_SHUTR_NOW|CF_STREAMER|CF_STREAMER_FAST|CF_WRITE_EVENT|CF_NEVER_WAIT|CF_WROTE_DATA|CF_READ_EVENT);
s->flags &= ~(SF_DIRECT|SF_ASSIGNED|SF_BE_ASSIGNED|SF_FORCE_PRST|SF_IGNORE_PRST);
s->flags &= ~(SF_CURR_SESS|SF_REDIRECTABLE|SF_SRV_REUSED);
s->flags &= ~(SF_ERR_MASK|SF_FINST_MASK|SF_REDISP);
if (!HAS_DATA_FILTERS(s, chn))
goto end;
- /* Be sure that the output is still opened. Else we stop the data
- * filtering. */
- if ((chn->flags & (CF_READ_ERROR|CF_READ_TIMEOUT|CF_WRITE_ERROR|CF_WRITE_TIMEOUT)) ||
- ((chn->flags & CF_SHUTW) && (chn->to_forward || co_data(chn))))
- goto end;
-
if (s->flags & SF_HTX) {
struct htx *htx = htxbuf(&chn->buf);
len = htx->data;
goto end;
c_adv(chn, ret);
- /* Stop waiting data if the input in closed and no data is pending or if
- * the output is closed. */
+ /* Stop waiting data if:
+ * - it the output is closed
+ * - the input in closed and no data is pending
+ * - There is a READ/WRITE timeout
+ */
if (chn->flags & CF_SHUTW) {
ret = 1;
goto end;
goto end;
}
}
+ if (chn->flags & (CF_READ_TIMEOUT|CF_WRITE_TIMEOUT)) {
+ ret = 1;
+ goto end;
+ }
/* Wait for data */
DBG_TRACE_DEVEL("waiting for more data", STRM_EV_STRM_ANA|STRM_EV_TCP_ANA|STRM_EV_FLT_ANA, s);
*/
s->logs.t_queue = tv_ms_elapsed(&s->logs.tv_accept, &now);
- http_reply_and_close(s, txn->status, (!(req->flags & CF_READ_ERROR) ? http_error_message(s) : NULL));
+ http_reply_and_close(s, txn->status, (!sc_ep_test(s->scf, SE_FL_ERROR) ? http_error_message(s) : NULL));
http_set_term_flags(s);
DBG_TRACE_LEAVE(STRM_EV_STRM_ANA|STRM_EV_HTTP_ANA, s, txn);
req = &s->req;
res = &s->res;
/* Remove any write error from the request, and read error from the response */
- req->flags &= ~(CF_WRITE_ERROR | CF_WRITE_TIMEOUT | CF_SHUTW | CF_SHUTW_NOW);
- res->flags &= ~(CF_READ_ERROR | CF_READ_TIMEOUT | CF_SHUTR | CF_EOI | CF_READ_EVENT | CF_SHUTR_NOW);
+ req->flags &= ~(CF_WRITE_TIMEOUT | CF_SHUTW | CF_SHUTW_NOW);
+ res->flags &= ~(CF_READ_TIMEOUT | CF_SHUTR | CF_EOI | CF_READ_EVENT | CF_SHUTR_NOW);
res->analysers &= AN_RES_FLT_END;
s->conn_err_type = STRM_ET_NONE;
s->flags &= ~(SF_CONN_EXP | SF_ERR_MASK | SF_FINST_MASK);
next_one:
if (unlikely(htx_is_empty(htx) || htx->first == -1)) {
/* 1: have we encountered a read error ? */
- if (rep->flags & CF_READ_ERROR) {
+ if (sc_ep_test(s->scb, SE_FL_ERROR)) {
struct connection *conn = sc_conn(s->scb);
/* Perform a L7 retry because server refuses the early data. */
}
/* 5: write error to client (we don't send any message then) */
- else if (rep->flags & CF_WRITE_ERROR) {
+ else if (sc_ep_test(s->scf, SE_FL_ERR_PENDING)) {
if (txn->flags & TX_NOT_FIRST)
goto abort_keep_alive;
/* Always call the action function if defined */
if (rule->action_ptr) {
- if ((s->req.flags & CF_READ_ERROR) ||
+ if (sc_ep_test(s->scf, SE_FL_ERROR) ||
((s->req.flags & CF_SHUTR) &&
(px->options & PR_O_ABRT_CLOSE)))
act_opts |= ACT_OPT_FINAL;
/* Always call the action function if defined */
if (rule->action_ptr) {
- if ((s->req.flags & CF_READ_ERROR) ||
+ if (sc_ep_test(s->scf, SE_FL_ERROR) ||
((s->req.flags & CF_SHUTR) &&
(px->options & PR_O_ABRT_CLOSE)))
act_opts |= ACT_OPT_FINAL;
oc->wex = tick_add_ifset(now_ms, oc->wto);
}
- if (likely(oc->flags & (CF_WRITE_EVENT|CF_WRITE_ERROR))) {
+ if (likely(oc->flags & CF_WRITE_EVENT)) {
struct channel *ic = sc_ic(sc);
/* update timeout if we have written something */
- if ((oc->flags & (CF_SHUTW|CF_WRITE_EVENT)) == CF_WRITE_EVENT &&
- !channel_is_empty(oc))
+ if (!(oc->flags & CF_SHUTW) && !channel_is_empty(oc))
oc->wex = tick_add_ifset(now_ms, oc->wto);
if (tick_isset(ic->rex) && !(sc->flags & SC_FL_INDEP_STR)) {
sc_ep_clr(sc, SE_FL_WAIT_DATA);
/* update OC timeouts and wake the other side up if it's waiting for room */
- if (oc->flags & (CF_WRITE_EVENT|CF_WRITE_ERROR)) {
- if (!(oc->flags & CF_WRITE_ERROR) &&
+ if (oc->flags & (CF_WRITE_EVENT)) {
+ if (sc_ep_test(sc, SE_FL_ERR_PENDING|SE_FL_ERROR) &&
!channel_is_empty(oc))
if (tick_isset(oc->wex))
oc->wex = tick_add_ifset(now_ms, oc->wto);
/* wake the task up only when needed */
if (/* changes on the production side that must be handled:
- * - An error on receipt: CF_READ_ERROR or SE_FL_ERROR
+ * - An error on receipt: SE_FL_ERROR
* - A read event: shutdown for reads (CF_READ_EVENT + SHUTR)
* end of input (CF_READ_EVENT + CF_EOI)
* data received and no fast-forwarding (CF_READ_EVENT + !to_forward)
* read event while consumer side is not established (CF_READ_EVENT + sco->state != SC_ST_EST)
*/
((ic->flags & CF_READ_EVENT) && ((ic->flags & (CF_SHUTR|CF_EOI)) || !ic->to_forward || sco->state != SC_ST_EST)) ||
- (ic->flags & CF_READ_ERROR) || sc_ep_test(sc, SE_FL_ERROR) ||
+ sc_ep_test(sc, SE_FL_ERROR) ||
/* changes on the consumption side */
- (oc->flags & CF_WRITE_ERROR) ||
+ sc_ep_test(sc, SE_FL_ERR_PENDING) ||
((oc->flags & CF_WRITE_EVENT) &&
((sc->state < SC_ST_EST) ||
(oc->flags & CF_SHUTW) ||
task_queue(task);
}
- if (ic->flags & (CF_READ_EVENT|CF_READ_ERROR))
+ if (ic->flags & CF_READ_EVENT)
ic->flags &= ~CF_READ_DONTWAIT;
}
}
if (sc_ep_test(sc, SE_FL_ERROR | SE_FL_ERR_PENDING)) {
+ oc->flags |= CF_WRITE_EVENT;
if (sc_ep_test(sc, SE_FL_EOS))
- sc_ep_set(sc, SE_FL_ERROR);
+ sc_ep_set(sc, SE_FL_ERROR);
return 1;
}
/* errors faced after sending data need to be reported */
if (sc_ep_test(s->scb, SE_FL_ERROR) && req->flags & CF_WROTE_DATA) {
- /* Don't add CF_WRITE_ERROR if we're here because
- * early data were rejected by the server, or
- * http_wait_for_response() will never be called
- * to send a 425.
- */
- if (conn && conn->err_code != CO_ER_SSL_EARLY_FAILED)
- req->flags |= CF_WRITE_ERROR;
- rep->flags |= CF_READ_ERROR;
+ s->req.flags |= CF_WRITE_EVENT;
+ s->res.flags |= CF_READ_EVENT;
s->conn_err_type = STRM_ET_DATA_ERR;
DBG_TRACE_STATE("read/write error", STRM_EV_STRM_PROC|STRM_EV_CS_ST|STRM_EV_STRM_ERR, s);
}
if (sc_state_in(scf->state, SC_SB_EST|SC_SB_DIS)) {
sc_shutr(scf);
sc_shutw(scf);
- sc_report_error(scf);
+ //sc_report_error(scf); TODO: Be sure it is useless
if (!(req->analysers) && !(res->analysers)) {
_HA_ATOMIC_INC(&s->be->be_counters.cli_aborts);
_HA_ATOMIC_INC(&sess->fe->fe_counters.cli_aborts);
if (sc_state_in(scb->state, SC_SB_EST|SC_SB_DIS)) {
sc_shutr(scb);
sc_shutw(scb);
- sc_report_error(scb);
+ //sc_report_error(scb); TODO: Be sure it is useless
_HA_ATOMIC_INC(&s->be->be_counters.failed_resp);
if (srv)
_HA_ATOMIC_INC(&srv->counters.failed_resp);
*/
srv = objt_server(s->target);
if (unlikely(!(s->flags & SF_ERR_MASK))) {
- if (req->flags & (CF_READ_ERROR|CF_READ_TIMEOUT|CF_WRITE_ERROR|CF_WRITE_TIMEOUT)) {
+ if (sc_ep_test(s->scf, SE_FL_ERROR) || req->flags & (CF_READ_TIMEOUT|CF_WRITE_TIMEOUT)) {
/* Report it if the client got an error or a read timeout expired */
req->analysers &= AN_REQ_FLT_END;
- if (req->flags & CF_READ_ERROR) {
+ if (sc_ep_test(s->scf, SE_FL_ERROR)) {
_HA_ATOMIC_INC(&s->be->be_counters.cli_aborts);
_HA_ATOMIC_INC(&sess->fe->fe_counters.cli_aborts);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&srv->counters.cli_aborts);
s->flags |= SF_ERR_CLITO;
}
- else if (req->flags & CF_WRITE_ERROR) {
- _HA_ATOMIC_INC(&s->be->be_counters.srv_aborts);
- _HA_ATOMIC_INC(&sess->fe->fe_counters.srv_aborts);
- if (sess->listener && sess->listener->counters)
- _HA_ATOMIC_INC(&sess->listener->counters->srv_aborts);
- if (srv)
- _HA_ATOMIC_INC(&srv->counters.srv_aborts);
- s->flags |= SF_ERR_SRVCL;
- }
else {
_HA_ATOMIC_INC(&s->be->be_counters.srv_aborts);
_HA_ATOMIC_INC(&sess->fe->fe_counters.srv_aborts);
channel_erase(req);
}
}
- else if (res->flags & (CF_READ_ERROR|CF_READ_TIMEOUT|CF_WRITE_ERROR|CF_WRITE_TIMEOUT)) {
+ else if (sc_ep_test(s->scb, SE_FL_ERROR) || res->flags & (CF_READ_TIMEOUT|CF_WRITE_TIMEOUT)) {
/* Report it if the server got an error or a read timeout expired */
res->analysers &= AN_RES_FLT_END;
- if (res->flags & CF_READ_ERROR) {
+ if (sc_ep_test(s->scb, SE_FL_ERROR)) {
_HA_ATOMIC_INC(&s->be->be_counters.srv_aborts);
_HA_ATOMIC_INC(&sess->fe->fe_counters.srv_aborts);
if (sess->listener && sess->listener->counters)
_HA_ATOMIC_INC(&srv->counters.srv_aborts);
s->flags |= SF_ERR_SRVTO;
}
- else if (res->flags & CF_WRITE_ERROR) {
- _HA_ATOMIC_INC(&s->be->be_counters.cli_aborts);
- _HA_ATOMIC_INC(&sess->fe->fe_counters.cli_aborts);
- if (sess->listener && sess->listener->counters)
- _HA_ATOMIC_INC(&sess->listener->counters->cli_aborts);
- if (srv)
- _HA_ATOMIC_INC(&srv->counters.cli_aborts);
- s->flags |= SF_ERR_CLICL;
- }
else {
_HA_ATOMIC_INC(&s->be->be_counters.cli_aborts);
_HA_ATOMIC_INC(&sess->fe->fe_counters.cli_aborts);
/* shutdown(write) pending */
if (unlikely((req->flags & (CF_SHUTW|CF_SHUTW_NOW)) == CF_SHUTW_NOW &&
channel_is_empty(req))) {
- if (req->flags & CF_READ_ERROR)
+ if (sc_ep_test(s->scf, SE_FL_ERROR))
scb->flags |= SC_FL_NOLINGER;
sc_shutw(scb);
}
!s->be->tcp_req.inspect_delay || tick_is_expired(s->rules_exp, now_ms)) {
partial = SMP_OPT_FINAL;
/* Action may yield while the inspect_delay is not expired and there is no read error */
- if ((req->flags & CF_READ_ERROR) || !s->be->tcp_req.inspect_delay || tick_is_expired(s->rules_exp, now_ms))
+ if (sc_ep_test(s->scf, SE_FL_ERROR) || !s->be->tcp_req.inspect_delay || tick_is_expired(s->rules_exp, now_ms))
act_opts |= ACT_OPT_FINAL;
}
else
!s->be->tcp_rep.inspect_delay || tick_is_expired(s->rules_exp, now_ms)) {
partial = SMP_OPT_FINAL;
/* Action may yield while the inspect_delay is not expired and there is no read error */
- if ((rep->flags & CF_READ_ERROR) || !s->be->tcp_rep.inspect_delay || tick_is_expired(s->rules_exp, now_ms))
+ if (sc_ep_test(s->scb, SE_FL_ERROR) || !s->be->tcp_rep.inspect_delay || tick_is_expired(s->rules_exp, now_ms))
act_opts |= ACT_OPT_FINAL;
}
else