MINOR: spoe: Add "pipelining" and "async" options in spoe-agent section

These options can be used to enable or to disable (prefixing the option line
with the "no" keyword), respectively, pipelined and asynchronous exchanged
between HAproxy and agents. By default, pipelining and async options are
enabled.
diff --git a/include/types/spoe.h b/include/types/spoe.h
index b65bc7a..e8ef7a1 100644
--- a/include/types/spoe.h
+++ b/include/types/spoe.h
@@ -34,6 +34,8 @@
 
 /* Flags set on the SPOE agent */
 #define SPOE_FL_CONT_ON_ERR       0x00000001 /* Do not stop events processing when an error occurred */
+#define SPOE_FL_PIPELINING        0x00000002 /* Set when SPOE agent supports pipelining (set by default) */
+#define SPOE_FL_ASYNC             0x00000004 /* Set when SPOE agent supports async (set by default) */
 
 /* Flags set on the SPOE context */
 #define SPOE_CTX_FL_CLI_CONNECTED 0x00000001 /* Set after that on-client-session event was processed */
diff --git a/src/flt_spoe.c b/src/flt_spoe.c
index 950b6bc..663c9fd 100644
--- a/src/flt_spoe.c
+++ b/src/flt_spoe.c
@@ -285,9 +285,6 @@
 /* Comma-separated list of supported versions */
 #define SUPPORTED_VERSIONS_VAL  "1.0"
 
-/* Comma-separated list of supported capabilities (none for now) */
-#define CAPABILITIES_VAL "pipelining,async"
-
 /* Convert a string to a SPOE version value. The string must follow the format
  * "MAJOR.MINOR". It will be concerted into the integer (1000 * MAJOR + MINOR).
  * If an error occurred, -1 is returned. */
@@ -353,6 +350,7 @@
 static int
 spoe_prepare_hahello_frame(struct appctx *appctx, char *frame, size_t size)
 {
+	struct chunk      *chk;
 	struct spoe_agent *agent = SPOE_APPCTX(appctx)->agent;
 	char              *p, *end;
 	unsigned int       flags = SPOE_FRM_FL_FIN;
@@ -399,8 +397,17 @@
 		goto too_big;
 
 	*p++ = SPOE_DATA_T_STR;
-	sz = SLEN(CAPABILITIES_VAL);
-	if (spoe_encode_buffer(CAPABILITIES_VAL, sz, &p, end) == -1)
+	chk = get_trash_chunk();
+	if (agent != NULL && (agent->flags & SPOE_FL_PIPELINING)) {
+		memcpy(chk->str, "pipelining", 10);
+		chk->len += 10;
+	}
+	if (agent != NULL && (agent->flags & SPOE_FL_ASYNC)) {
+		if (chk->len) chk->str[chk->len++] = ',';
+		memcpy(chk->str+chk->len, "async", 5);
+		chk->len += 5;
+	}
+	if (spoe_encode_buffer(chk->str, chk->len, &p, end) == -1)
 		goto too_big;
 
 	/* (optionnal) "engine-id" K/V item, if present */
@@ -600,9 +607,10 @@
 static int
 spoe_handle_agenthello_frame(struct appctx *appctx, char *frame, size_t size)
 {
-	char        *p, *end;
-	int          vsn, max_frame_size;
-	unsigned int flags;
+	struct spoe_agent *agent = SPOE_APPCTX(appctx)->agent;
+	char              *p, *end;
+	int                vsn, max_frame_size;
+	unsigned int       flags;
 
 	p   = frame;
 	end = frame + size;
@@ -766,6 +774,10 @@
 		SPOE_APPCTX(appctx)->status_code = SPOE_FRM_ERR_NO_FRAME_SIZE;
 		return -1;
 	}
+	if ((flags & SPOE_APPCTX_FL_PIPELINING) && !(agent->flags & SPOE_FL_PIPELINING))
+		flags &= ~SPOE_APPCTX_FL_PIPELINING;
+	if ((flags & SPOE_APPCTX_FL_ASYNC) && !(agent->flags & SPOE_FL_ASYNC))
+		flags &= ~SPOE_APPCTX_FL_ASYNC;
 
 	SPOE_APPCTX(appctx)->version        = (unsigned int)vsn;
 	SPOE_APPCTX(appctx)->max_frame_size = (unsigned int)max_frame_size;
@@ -3007,7 +3019,7 @@
 		curagent->engine_id      = NULL;
 		curagent->var_pfx        = NULL;
 		curagent->var_on_error   = NULL;
-		curagent->flags          = 0;
+		curagent->flags          = (SPOE_FL_PIPELINING | SPOE_FL_ASYNC);
 		curagent->cps_max        = 0;
 		curagent->eps_max        = 0;
 		curagent->max_frame_size = MAX_FRAME_SIZE;
@@ -3118,6 +3130,33 @@
                         goto out;
                 }
 
+		if (!strcmp(args[1], "pipelining")) {
+			if (*args[2]) {
+				Alert("parsing [%s:%d] : cannot handle unexpected argument '%s'.\n",
+				      file, linenum, args[2]);
+				err_code |= ERR_ALERT | ERR_ABORT;
+				goto out;
+			}
+			if (kwm == 1)
+				curagent->flags &= ~SPOE_FL_PIPELINING;
+			else
+				curagent->flags |= SPOE_FL_PIPELINING;
+			goto out;
+		}
+		else if (!strcmp(args[1], "async")) {
+			if (*args[2]) {
+				Alert("parsing [%s:%d] : cannot handle unexpected argument '%s'.\n",
+				      file, linenum, args[2]);
+				err_code |= ERR_ALERT | ERR_ABORT;
+				goto out;
+			}
+			if (kwm == 1)
+				curagent->flags &= ~SPOE_FL_ASYNC;
+			else
+				curagent->flags |= SPOE_FL_ASYNC;
+			goto out;
+		}
+
 		/* Following options does not support negation */
 		if (kwm == 1) {
 			Alert("parsing [%s:%d]: negation is not supported for option '%s'.\n",