]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: spoe/mux-spop: Introduce an NOOP action to deal with empty ACK
authorChristopher Faulet <cfaulet@haproxy.com>
Thu, 20 Feb 2025 10:56:24 +0000 (11:56 +0100)
committerChristopher Faulet <cfaulet@haproxy.com>
Thu, 20 Feb 2025 10:56:27 +0000 (11:56 +0100)
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
src/mux_spop.c

index e2db8a1d81f3aa1fe7676bd62e498cec32c1b129..2b91d14032b125cf2d2dec16d6f883fa39f91f9a 100644 (file)
@@ -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,
index 6f47946763b0dd23e220f3fa67b28364aa5f030e..7cb49363c47c51ba91887cbafe6918471496d3ef 100644 (file)
@@ -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;