From 851e52b551f80f319b0de1817fc91b7f3949fc67 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Thu, 20 Feb 2025 11:56:24 +0100 Subject: [PATCH] BUG/MEDIUM: spoe/mux-spop: Introduce an NOOP action to deal with empty ACK In the SPOP protocol, ACK frame with empty payload are allowed. However, in that case, because only the payload is transferred, there is no data to return to the SPOE applet. Only the end of input is reported. Thus the applet is never woken up. It means that the SPOE filter will be blocked during the processing timeout and will finally return an error. To workaournd this issue, a NOOP action is introduced with the value 0. It is only an internal action for now. It does not exist in the SPOP protocol. When an ACK frame with an empy payload is received, this noop action is transferred to the SPOE applet, instead of nothing. Thanks to this trick, the applet is properly notified. This works because unknown actions are ignored by the SPOE filter. This patch must be backported to 3.1. --- include/haproxy/spoe-t.h | 1 + src/mux_spop.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/include/haproxy/spoe-t.h b/include/haproxy/spoe-t.h index e2db8a1d8..2b91d1403 100644 --- a/include/haproxy/spoe-t.h +++ b/include/haproxy/spoe-t.h @@ -52,6 +52,7 @@ /* All supported SPOP actions */ enum spoe_action_type { + SPOP_ACT_T_NOOP = 0, /* internal action for ampty ACK */ SPOP_ACT_T_SET_VAR = 1, SPOP_ACT_T_UNSET_VAR, SPOP_ACT_TYPES, diff --git a/src/mux_spop.c b/src/mux_spop.c index 6f4794676..7cb49363c 100644 --- a/src/mux_spop.c +++ b/src/mux_spop.c @@ -1941,8 +1941,16 @@ static int spop_conn_handle_ack(struct spop_conn *spop_conn, struct spop_strm *s } flen = spop_conn->dfl; - if (!flen) + if (!flen) { + if (!b_room(rxbuf)) { + spop_conn->flags |= SPOP_CF_DEM_SFULL; + TRACE_STATE("spop_strm rxbuf is full", SPOP_EV_RX_FRAME|SPOP_EV_RX_ACK|SPOP_EV_SPOP_STRM_BLK, spop_conn->conn, spop_strm); + goto fail; + } + b_putchr(rxbuf, SPOP_ACT_T_NOOP); + sent = 1; goto end; + } // TODO: For now we know all data were received /* if (flen > b_data(&h2c->dbuf)) { */ @@ -1963,12 +1971,12 @@ static int spop_conn_handle_ack(struct spop_conn *spop_conn, struct spop_strm *s /* b_del(&spop_conn->dbuf, sent); */ spop_conn->dfl -= sent; + end: if (spop_strm->state == SPOP_SS_OPEN) spop_strm->state = SPOP_SS_HREM; else spop_strm_close(spop_strm); - end: spop_strm->flags |= SPOP_SF_ACK_RCVD; TRACE_PROTO("SPOP AGENT ACK frame rcvd", SPOP_EV_RX_FRAME|SPOP_EV_RX_ACK, spop_conn->conn, spop_strm, 0, (size_t[]){sent}); spop_conn->state = SPOP_CS_FRAME_H;