mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-01-03 18:52:04 +00:00
MEDIUM: mux-fcgi: Introduce flags to deal with connection read/write errors
Similarly to the H1 and H2 multiplexers, FCFI_CF_ERR_PENDING is now used to report an error when we try to send data and FCGI_CF_ERROR to report an error when we try to read data. In other funcions, we rely on these flags instead of connection ones. Only FCGI_CF_ERROR is considered as a final error. FCGI_CF_ERR_PENDING does not block receive attempt. In addition, FCGI_CF_EOS flag was added. we rely on it to test if a read0 was received or not.
This commit is contained in:
parent
68ee7845cf
commit
ab79b321d6
@ -54,6 +54,11 @@
|
||||
#define FCGI_CF_KEEP_CONN 0x00001000 /* HAProxy is responsible to close the connection */
|
||||
#define FCGI_CF_GET_VALUES 0x00002000 /* retrieve settings */
|
||||
|
||||
#define FCGI_CF_EOS 0x00004000 /* End-of-stream seen on the H1 connection (read0 detected) */
|
||||
#define FCGI_CF_ERR_PENDING 0x00008000 /* A write error was detected (block sends but not reads) */
|
||||
#define FCGI_CF_ERROR 0x00010000 /* A read error was detected (handled has an abort) */
|
||||
|
||||
|
||||
/* This function is used to report flags in debugging tools. Please reflect
|
||||
* below any single-bit flag addition above in the same order via the
|
||||
* __APPEND_FLAG macro. The new end of the buffer is returned.
|
||||
@ -68,7 +73,8 @@ static forceinline char *fconn_show_flags(char *buf, size_t len, const char *del
|
||||
_(FCGI_CF_DEM_DALLOC, _(FCGI_CF_DEM_DFULL, _(FCGI_CF_DEM_MROOM,
|
||||
_(FCGI_CF_DEM_SALLOC, _(FCGI_CF_DEM_SFULL, _(FCGI_CF_DEM_TOOMANY,
|
||||
_(FCGI_CF_MPXS_CONNS, _(FCGI_CF_ABRTS_SENT, _(FCGI_CF_ABRTS_FAILED,
|
||||
_(FCGI_CF_WAIT_FOR_HS, _(FCGI_CF_KEEP_CONN, _(FCGI_CF_GET_VALUES))))))))))))));
|
||||
_(FCGI_CF_WAIT_FOR_HS, _(FCGI_CF_KEEP_CONN, _(FCGI_CF_GET_VALUES,
|
||||
_(FCGI_CF_EOS, _(FCGI_CF_ERR_PENDING, _(FCGI_CF_ERROR)))))))))))))))));
|
||||
/* epilogue */
|
||||
_(~0U);
|
||||
return buf;
|
||||
|
@ -452,10 +452,10 @@ static void fcgi_trace(enum trace_level level, uint64_t mask, const struct trace
|
||||
*/
|
||||
static inline int fcgi_recv_allowed(const struct fcgi_conn *fconn)
|
||||
{
|
||||
if (b_data(&fconn->dbuf) == 0 &&
|
||||
(fconn->state == FCGI_CS_CLOSED ||
|
||||
fconn->conn->flags & CO_FL_ERROR ||
|
||||
conn_xprt_read0_pending(fconn->conn)))
|
||||
if (fconn->flags & (FCGI_CF_EOS|FCGI_CF_ERROR))
|
||||
return 0;
|
||||
|
||||
if (b_data(&fconn->dbuf) == 0 && fconn->state == FCGI_CS_CLOSED)
|
||||
return 0;
|
||||
|
||||
if (!(fconn->flags & FCGI_CF_DEM_DALLOC) &&
|
||||
@ -793,7 +793,7 @@ static void fcgi_release(struct fcgi_conn *fconn)
|
||||
*/
|
||||
static int fcgi_conn_read0_pending(struct fcgi_conn *fconn)
|
||||
{
|
||||
if (conn_xprt_read0_pending(fconn->conn) && !b_data(&fconn->dbuf))
|
||||
if ((fconn->flags & FCGI_CF_EOS) && !b_data(&fconn->dbuf))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@ -804,12 +804,12 @@ static inline int fcgi_conn_is_dead(struct fcgi_conn *fconn)
|
||||
{
|
||||
if (eb_is_empty(&fconn->streams_by_id) && /* don't close if streams exist */
|
||||
(!(fconn->flags & FCGI_CF_KEEP_CONN) || /* don't keep the connection alive */
|
||||
(fconn->conn->flags & CO_FL_ERROR) || /* errors close immediately */
|
||||
(fconn->flags & FCGI_CF_ERROR) || /* errors close immediately */
|
||||
(fconn->state == FCGI_CS_CLOSED && !fconn->task) ||/* a timeout stroke earlier */
|
||||
(!(fconn->conn->owner)) || /* Nobody's left to take care of the connection, drop it now */
|
||||
(!br_data(fconn->mbuf) && /* mux buffer empty, also process clean events below */
|
||||
conn_xprt_read0_pending(fconn->conn))))
|
||||
return 1;
|
||||
(fconn->flags & FCGI_CF_EOS))))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1077,10 +1077,8 @@ static void fcgi_strm_wake_one_stream(struct fcgi_strm *fstrm)
|
||||
fcgi_strm_close(fstrm);
|
||||
}
|
||||
|
||||
if ((fconn->state == FCGI_CS_CLOSED || fconn->conn->flags & CO_FL_ERROR)) {
|
||||
se_fl_set(fstrm->sd, SE_FL_ERR_PENDING);
|
||||
if (se_fl_test(fstrm->sd, SE_FL_EOS))
|
||||
se_fl_set(fstrm->sd, SE_FL_ERROR);
|
||||
if (fconn->state == FCGI_CS_CLOSED || (fconn->flags & (FCGI_CF_ERR_PENDING|FCGI_CF_ERROR))) {
|
||||
se_fl_set_error(fstrm->sd);
|
||||
|
||||
if (fstrm->state < FCGI_SS_ERROR) {
|
||||
fstrm->state = FCGI_SS_ERROR;
|
||||
@ -2755,10 +2753,18 @@ static int fcgi_recv(struct fcgi_conn *fconn)
|
||||
else
|
||||
TRACE_DATA("recv data", FCGI_EV_FCONN_RECV, conn, 0, 0, (size_t[]){ret});
|
||||
|
||||
if (conn_xprt_read0_pending(conn)) {
|
||||
TRACE_DATA("received read0", FCGI_EV_FCONN_RECV, conn);
|
||||
fconn->flags |= FCGI_CF_EOS;
|
||||
}
|
||||
if (conn->flags & CO_FL_ERROR) {
|
||||
TRACE_DATA("connection error", FCGI_EV_FCONN_RECV, conn);
|
||||
fconn->flags |= FCGI_CF_ERROR;
|
||||
}
|
||||
|
||||
if (!b_data(buf)) {
|
||||
fcgi_release_buf(fconn, &fconn->dbuf);
|
||||
TRACE_LEAVE(FCGI_EV_FCONN_RECV, conn);
|
||||
return (conn->flags & CO_FL_ERROR || conn_xprt_read0_pending(conn));
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (ret == max) {
|
||||
@ -2766,8 +2772,9 @@ static int fcgi_recv(struct fcgi_conn *fconn)
|
||||
fconn->flags |= FCGI_CF_DEM_DFULL;
|
||||
}
|
||||
|
||||
end:
|
||||
TRACE_LEAVE(FCGI_EV_FCONN_RECV, conn);
|
||||
return !!ret || (conn->flags & CO_FL_ERROR) || conn_xprt_read0_pending(conn);
|
||||
return !!ret || (fconn->flags & (FCGI_CF_EOS|FCGI_CF_ERROR));
|
||||
}
|
||||
|
||||
|
||||
@ -2782,8 +2789,11 @@ static int fcgi_send(struct fcgi_conn *fconn)
|
||||
|
||||
TRACE_ENTER(FCGI_EV_FCONN_SEND, conn);
|
||||
|
||||
if (conn->flags & CO_FL_ERROR) {
|
||||
if (fconn->flags & (FCGI_CF_ERROR|FCGI_CF_ERR_PENDING)) {
|
||||
TRACE_DEVEL("leaving on connection error", FCGI_EV_FCONN_SEND, conn);
|
||||
if (fconn->flags & FCGI_CF_EOS)
|
||||
fconn->flags |= FCGI_CF_ERROR;
|
||||
b_reset(br_tail(fconn->mbuf));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -2861,10 +2871,13 @@ static int fcgi_send(struct fcgi_conn *fconn)
|
||||
fconn->flags &= ~(FCGI_CF_MUX_MFULL | FCGI_CF_DEM_MROOM);
|
||||
}
|
||||
|
||||
if (conn->flags & CO_FL_SOCK_WR_SH) {
|
||||
/* output closed, nothing to send, clear the buffer to release it */
|
||||
if (conn->flags & CO_FL_ERROR) {
|
||||
fconn->flags |= FCGI_CF_ERR_PENDING;
|
||||
if (fconn->flags & FCGI_CF_EOS)
|
||||
fconn->flags |= FCGI_CF_ERROR;
|
||||
b_reset(br_tail(fconn->mbuf));
|
||||
}
|
||||
|
||||
/* We're not full anymore, so we can wake any task that are waiting
|
||||
* for us.
|
||||
*/
|
||||
@ -2905,7 +2918,7 @@ static int fcgi_send(struct fcgi_conn *fconn)
|
||||
/* We're done, no more to send */
|
||||
if (!br_data(fconn->mbuf)) {
|
||||
TRACE_DEVEL("leaving with everything sent", FCGI_EV_FCONN_SEND, conn);
|
||||
return sent;
|
||||
goto end;
|
||||
}
|
||||
schedule:
|
||||
if (!(conn->flags & CO_FL_ERROR) && !(fconn->wait_event.events & SUB_RETRY_SEND)) {
|
||||
@ -2914,7 +2927,8 @@ schedule:
|
||||
}
|
||||
|
||||
TRACE_DEVEL("leaving with some data left to send", FCGI_EV_FCONN_SEND, conn);
|
||||
return sent;
|
||||
end:
|
||||
return sent || (fconn->flags & (FCGI_CF_ERR_PENDING|FCGI_CF_ERROR));
|
||||
}
|
||||
|
||||
/* this is the tasklet referenced in fconn->wait_event.tasklet */
|
||||
@ -2996,7 +3010,7 @@ static int fcgi_process(struct fcgi_conn *fconn)
|
||||
if (b_data(&fconn->dbuf) && !(fconn->flags & FCGI_CF_DEM_BLOCK_ANY)) {
|
||||
fcgi_process_demux(fconn);
|
||||
|
||||
if (fconn->state == FCGI_CS_CLOSED || conn->flags & CO_FL_ERROR)
|
||||
if (fconn->state == FCGI_CS_CLOSED || (fconn->flags & FCGI_CF_ERROR))
|
||||
b_reset(&fconn->dbuf);
|
||||
|
||||
if (buf_room_for_htx_data(&fconn->dbuf))
|
||||
@ -3036,7 +3050,7 @@ static int fcgi_process(struct fcgi_conn *fconn)
|
||||
}
|
||||
}
|
||||
|
||||
if ((conn->flags & CO_FL_ERROR) || fcgi_conn_read0_pending(fconn) ||
|
||||
if ((fconn->flags & FCGI_CF_ERROR) || fcgi_conn_read0_pending(fconn) ||
|
||||
fconn->state == FCGI_CS_CLOSED || (fconn->flags & FCGI_CF_ABRTS_FAILED) ||
|
||||
eb_is_empty(&fconn->streams_by_id)) {
|
||||
fcgi_wake_some_streams(fconn, 0);
|
||||
@ -3052,8 +3066,7 @@ static int fcgi_process(struct fcgi_conn *fconn)
|
||||
if (!b_data(&fconn->dbuf))
|
||||
fcgi_release_buf(fconn, &fconn->dbuf);
|
||||
|
||||
if ((conn->flags & CO_FL_SOCK_WR_SH) ||
|
||||
fconn->state == FCGI_CS_CLOSED || (fconn->flags & FCGI_CF_ABRTS_FAILED) ||
|
||||
if (fconn->state == FCGI_CS_CLOSED || (fconn->flags & FCGI_CF_ABRTS_FAILED) ||
|
||||
(!br_data(fconn->mbuf) && ((fconn->flags & FCGI_CF_MUX_BLOCK_ANY) || LIST_ISEMPTY(&fconn->send_list))))
|
||||
fcgi_release_mbuf(fconn);
|
||||
|
||||
@ -3526,7 +3539,7 @@ static void fcgi_detach(struct sedesc *sd)
|
||||
/* this stream may be blocked waiting for some data to leave, so orphan
|
||||
* it in this case.
|
||||
*/
|
||||
if (!(fconn->conn->flags & CO_FL_ERROR) &&
|
||||
if (!(fconn->flags & (FCGI_CF_ERR_PENDING|FCGI_CF_ERROR)) && // FIXME: Be sure for ERR_PENDING
|
||||
(fconn->state != FCGI_CS_CLOSED) &&
|
||||
(fstrm->flags & (FCGI_SF_BLK_MBUSY|FCGI_SF_BLK_MROOM)) &&
|
||||
(fstrm->subs || (fstrm->flags & (FCGI_SF_WANT_SHUTR|FCGI_SF_WANT_SHUTW)))) {
|
||||
@ -3542,7 +3555,7 @@ static void fcgi_detach(struct sedesc *sd)
|
||||
|
||||
fcgi_strm_destroy(fstrm);
|
||||
|
||||
if (!(fconn->conn->flags & (CO_FL_ERROR|CO_FL_SOCK_RD_SH|CO_FL_SOCK_WR_SH)) &&
|
||||
if (!(fconn->flags & (FCGI_CF_EOS|FCGI_CF_ERR_PENDING|FCGI_CF_ERROR)) &&
|
||||
(fconn->flags & FCGI_CF_KEEP_CONN)) {
|
||||
if (fconn->conn->flags & CO_FL_PRIVATE) {
|
||||
/* Add the connection in the session serverlist, if not already done */
|
||||
|
Loading…
Reference in New Issue
Block a user