MINOR: sample: Add UUID-fetch

Adds the fetch uuid(int). It returns a UUID following the format of
version 4 in the RFC4122 standard.

New feature, but could be backported.

(cherry picked from commit 8a694b859cf98f8b0855b4aa5a50ebf64b501215)
Signed-off-by: Christopher Faulet <cfaulet@haproxy.com>
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 2e11774..85e8c73 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -14770,6 +14770,11 @@
   needed to take some routing decisions for example, or just for debugging
   purposes. This random must not be used for security purposes.
 
+uuid([<version>]) : string
+  Returns a UUID following the RFC4122 standard. If the version is not
+  specified, a UUID version 4 (fully random) is returned.
+  Currently, only version 4 is supported.
+
 srv_conn([<backend>/]<server>) : integer
   Returns an integer value corresponding to the number of currently established
   connections on the designated server, possibly including the connection being
diff --git a/src/sample.c b/src/sample.c
index 522ca9e..ab25726 100644
--- a/src/sample.c
+++ b/src/sample.c
@@ -3132,6 +3132,60 @@
 	return 1;
 }
 
+// This function checks the "uuid" sample's arguments.
+// Function won't get called when no parameter is specified (maybe a bug?)
+static int smp_check_uuid(struct arg *args, char **err)
+{
+	if (!args[0].type) {
+		args[0].type = ARGT_SINT;
+		args[0].data.sint = 4;
+	}
+	else if (args[0].data.sint != 4) {
+		memprintf(err, "Unsupported UUID version: '%lld'", args[0].data.sint);
+		return 0;
+	}
+
+	return 1;
+}
+
+// Generate a RFC4122 UUID (default is v4 = fully random)
+static int smp_fetch_uuid(const struct arg *args, struct sample *smp, const char *kw, void *private)
+{
+	if (args[0].data.sint == 4 || !args[0].type) {
+		uint32_t rnd[4] = { 0, 0, 0, 0 };
+		uint64_t last = 0;
+		int byte = 0;
+		uint8_t bits = 0;
+		unsigned int rand_max_bits = my_flsl(RAND_MAX);
+
+		while (byte < 4) {
+			while (bits < 32) {
+				last |= (uint64_t)random() << bits;
+				bits += rand_max_bits;
+			}
+			rnd[byte++] = last;
+			last >>= 32u;
+			bits  -= 32;
+		}
+
+		chunk_printf(&trash, "%8.8x-%4.4x-%4.4x-%4.4x-%12.12llx",
+			     rnd[0],
+			     rnd[1] & 0xFFFF,
+			     ((rnd[1] >> 16u) & 0xFFF) | 0x4000,  // highest 4 bits indicate the uuid version
+			     (rnd[2] & 0x3FFF) | 0x8000,  // the highest 2 bits indicate the UUID variant (10),
+			     (long long)((rnd[2] >> 14u) | ((uint64_t) rnd[3] << 18u)) & 0xFFFFFFFFFFFFull
+			);
+
+		smp->data.type = SMP_T_STR;
+		smp->flags = SMP_F_VOL_TEST | SMP_F_MAY_CHANGE;
+		smp->data.u.str = trash;
+		return 1;
+	}
+
+	// more implementations of other uuid formats possible here
+	return 0;
+}
+
 /* Note: must not be declared <const> as its list will be overwritten.
  * Note: fetches that may return multiple types must be declared as the lowest
  * common denominator, the type that can be casted into all other ones. For
@@ -3150,6 +3204,7 @@
 	{ "rand",         smp_fetch_rand,  ARG1(0,SINT), NULL, SMP_T_SINT, SMP_USE_INTRN },
 	{ "stopping",     smp_fetch_stopping, 0,         NULL, SMP_T_BOOL, SMP_USE_INTRN },
 	{ "stopping",     smp_fetch_stopping, 0,         NULL, SMP_T_BOOL, SMP_USE_INTRN },
+	{ "uuid",         smp_fetch_uuid,  ARG1(0, SINT),      smp_check_uuid, SMP_T_STR, SMP_USE_INTRN },
 
 	{ "cpu_calls",    smp_fetch_cpu_calls,  0,       NULL, SMP_T_SINT, SMP_USE_INTRN },
 	{ "cpu_ns_avg",   smp_fetch_cpu_ns_avg, 0,       NULL, SMP_T_SINT, SMP_USE_INTRN },