]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: sample: Code factorization "ungrpc" converter.
authorFrédéric Lécaille <flecaille@haproxy.com>
Mon, 4 Mar 2019 06:33:41 +0000 (07:33 +0100)
committerWilly Tarreau <w@1wt.eu>
Tue, 5 Mar 2019 10:03:53 +0000 (11:03 +0100)
Parsing protocol buffer fields always consists in skip the field
if the field is not found or store the field value if found.
So, with this patch we factorize a little bit the code for "ungrpc" converter.

include/proto/protocol_buffers.h
include/types/protocol_buffers.h
src/sample.c

index d210a725010a9d4710feba73e480948a4870d230..58378a966e0f9c44d1811902b6e84285855a8fe7 100644 (file)
 #ifndef _PROTO_PROTOCOL_BUFFERS_H
 #define _PROTO_PROTOCOL_BUFFERS_H
 
+#include <stdint.h>
 #include <types/protocol_buffers.h>
-
-#define PBUF_TYPE_VARINT           0
-#define PBUF_TYPE_64BIT            1
-#define PBUF_TYPE_LENGTH_DELIMITED 2
-#define PBUF_TYPE_START_GROUP      3
-#define PBUF_TYPE_STOP_GROUP       4
-#define PBUF_TYPE_32BIT            5
+#include <proto/sample.h>
 
 #define PBUF_VARINT_DONT_STOP_BIT       7
 #define PBUF_VARINT_DONT_STOP_BITMASK  (1 << PBUF_VARINT_DONT_STOP_BIT)
 #define PBUF_VARINT_DATA_BITMASK            ~PBUF_VARINT_DONT_STOP_BITMASK
 
+/* .skip and .smp_store prototypes. */
+int protobuf_skip_varint(unsigned char **pos, size_t *len, size_t vlen);
+int protobuf_smp_store_varint(struct sample *smp,
+                              unsigned char *pos, size_t len, size_t vlen);
+int protobuf_skip_64bit(unsigned char **pos, size_t *len, size_t vlen);
+int protobuf_smp_store_64bit(struct sample *smp,
+                             unsigned char *pos, size_t len, size_t vlen);
+int protobuf_skip_vlen(unsigned char **pos, size_t *len, size_t vlen);
+int protobuf_smp_store_vlen(struct sample *smp,
+                            unsigned char *pos, size_t len, size_t vlen);
+int protobuf_skip_32bit(unsigned char **pos, size_t *len, size_t vlen);
+int protobuf_smp_store_32bit(struct sample *smp,
+                             unsigned char *pos, size_t len, size_t vlen);
+
+struct protobuf_parser_def protobuf_parser_defs [] = {
+       [PBUF_TYPE_VARINT          ] = {
+               .skip      = protobuf_skip_varint,
+               .smp_store = protobuf_smp_store_varint,
+       },
+       [PBUF_TYPE_64BIT           ] = {
+               .skip      = protobuf_skip_64bit,
+               .smp_store = protobuf_smp_store_64bit,
+       },
+       [PBUF_TYPE_LENGTH_DELIMITED] = {
+               .skip      = protobuf_skip_vlen,
+               .smp_store = protobuf_smp_store_vlen,
+       },
+       [PBUF_TYPE_START_GROUP     ] = {
+               /* XXX Deprecated XXX */
+       },
+       [PBUF_TYPE_STOP_GROUP      ] = {
+               /* XXX Deprecated XXX */
+       },
+       [PBUF_TYPE_32BIT           ] = {
+               .skip      = protobuf_skip_32bit,
+               .smp_store = protobuf_smp_store_32bit,
+       },
+};
+
 /*
  * Decode a protocol buffers varint located in a buffer at <pos> address with
  * <len> as length. The decoded value is stored at <val>.
@@ -112,8 +146,8 @@ protobuf_decode_varint(uint64_t *val, unsigned char **pos, size_t *len)
  * available byte. Decrease <*len> by the number of skipped bytes.
  * Returns 1 if succeeded, 0 if not.
  */
-static inline int
-protobuf_skip_varint(unsigned char **pos, size_t *len)
+int
+protobuf_skip_varint(unsigned char **pos, size_t *len, size_t vlen)
 {
        unsigned int shift;
 
@@ -147,23 +181,23 @@ protobuf_skip_varint(unsigned char **pos, size_t *len)
  * Return -1 if failed.
  */
 static inline int
-protobuf_varint_getlen(unsigned char **pos, size_t *len)
+protobuf_varint_getlen(unsigned char *pos, size_t len)
 {
        unsigned char *spos;
        unsigned int shift;
 
        shift = 0;
-       spos = *pos;
+       spos = pos;
 
-       while (*len > 0) {
-               int stop = !(**pos & PBUF_VARINT_DONT_STOP_BITMASK);
+       while (len > 0) {
+               int stop = !(*pos & PBUF_VARINT_DONT_STOP_BITMASK);
 
-               ++*pos;
-               --*len;
+               ++pos;
+               --len;
 
                if (stop)
                        break;
-               else if (!*len)
+               else if (!len)
                        return -1;
 
                shift += 7;
@@ -172,7 +206,129 @@ protobuf_varint_getlen(unsigned char **pos, size_t *len)
                        return -1;
        }
 
-       return *pos - spos;
+       return pos - spos;
+}
+
+/*
+ * Store a raw varint field value in a sample from <pos> buffer
+ * with <len> available bytes.
+ * Return 1 if succeeded, 0 if not.
+ */
+int protobuf_smp_store_varint(struct sample *smp,
+                              unsigned char *pos, size_t len, size_t vlen)
+{
+       int varint_len;
+
+       varint_len = protobuf_varint_getlen(pos, len);
+       if (varint_len == -1)
+               return 0;
+
+       smp->data.type = SMP_T_BIN;
+       smp->data.u.str.area = (char *)pos;
+       smp->data.u.str.data = varint_len;
+       smp->flags = SMP_F_VOL_TEST;
+
+       return 1;
+}
+
+/*
+ * Move forward <*pos> buffer by 8 bytes. Used to skip a 64bit field.
+ */
+int protobuf_skip_64bit(unsigned char **pos, size_t *len, size_t vlen)
+{
+       if (*len < sizeof(uint64_t))
+           return 0;
+
+       *pos += sizeof(uint64_t);
+       *len -= sizeof(uint64_t);
+
+       return 1;
+}
+
+/*
+ * Store a fixed size 64bit field value in a sample from <pos> buffer
+ * with <len> available bytes.
+ * Return 1 if succeeded, 0 if not.
+ */
+int protobuf_smp_store_64bit(struct sample *smp,
+                             unsigned char *pos, size_t len, size_t vlen)
+{
+       if (len < sizeof(uint64_t))
+           return 0;
+
+       smp->data.type = SMP_T_BIN;
+       smp->data.u.str.area = (char *)pos;
+       smp->data.u.str.data = sizeof(uint64_t);
+       smp->flags = SMP_F_VOL_TEST;
+
+       return 1;
+}
+
+/*
+ * Move forward <*pos> buffer by <vlen> bytes. Use to skip a length-delimited
+ * field.
+ */
+int protobuf_skip_vlen(unsigned char **pos, size_t *len, size_t vlen)
+{
+       if (*len < vlen)
+               return 0;
+
+       *pos += vlen;
+       *len -= vlen;
+
+       return 1;
+}
+
+/*
+ * Store a <vlen>-bytes length-delimited field value in a sample from <pos>
+ * buffer with <len> available bytes.
+ * Return 1 if succeeded, 0 if not.
+ */
+int protobuf_smp_store_vlen(struct sample *smp,
+                            unsigned char *pos, size_t len, size_t vlen)
+{
+       if (len < vlen)
+               return 0;
+
+       smp->data.type = SMP_T_BIN;
+       smp->data.u.str.area = (char *)pos;
+       smp->data.u.str.data = vlen;
+       smp->flags = SMP_F_VOL_TEST;
+
+       return 1;
+}
+
+/*
+ * Move forward <*pos> buffer by 4 bytes. Used to skip a 32bit field.
+ */
+int protobuf_skip_32bit(unsigned char **pos, size_t *len, size_t vlen)
+{
+       if (*len < sizeof(uint32_t))
+           return 0;
+
+       *pos += sizeof(uint32_t);
+       *len -= sizeof(uint32_t);
+
+       return 1;
+}
+
+/*
+ * Store a fixed size 32bit field value in a sample from <pos> buffer
+ * with <len> available bytes.
+ * Return 1 if succeeded, 0 if not.
+ */
+int protobuf_smp_store_32bit(struct sample *smp,
+                             unsigned char *pos, size_t len, size_t vlen)
+{
+       if (len < sizeof(uint32_t))
+           return 0;
+
+       smp->data.type = SMP_T_BIN;
+       smp->data.u.str.area = (char *)pos;
+       smp->data.u.str.data = sizeof(uint32_t);
+       smp->flags = SMP_F_VOL_TEST;
+
+       return 1;
 }
 
 #endif /* _PROTO_PROTOCOL_BUFFERS_H */
index af5d2621472c0dba09a92b781cdef18ccb819399..9b067f2775162aa33eb4afd82cab0e86dc981b08 100644 (file)
 #ifndef _TYPES_PROTOCOL_BUFFERS_H
 #define _TYPES_PROTOCOL_BUFFERS_H
 
+enum protobuf_wire_type {
+       PBUF_TYPE_VARINT,
+       PBUF_TYPE_64BIT,
+       PBUF_TYPE_LENGTH_DELIMITED,
+       PBUF_TYPE_START_GROUP,      /* Deprecated */
+       PBUF_TYPE_STOP_GROUP,       /* Deprecated */
+       PBUF_TYPE_32BIT,
+};
+
 struct pbuf_fid {
        unsigned int *ids;
        size_t sz;
 };
 
+struct protobuf_parser_def {
+       int (*skip)(unsigned char **pos, size_t *left, size_t vlen);
+       int (*smp_store)(struct sample *, unsigned char *pos, size_t left, size_t vlen);
+};
+
 #endif /* _TYPES_PROTOCOL_BUFFERS_H */
 
 /*
index 9c20469c5aa53a624786f08c37932dbca85ccb87..7cd1425bb68ba112d724ab06f6ef7f4869e3f707 100644 (file)
@@ -2803,8 +2803,8 @@ static int sample_conv_ungrpc(const struct arg *arg_p, struct sample *smp, void
        /* Remaining bytes in the body to be parsed. */
        grpc_left = smp->data.u.str.data;
 
-       while (grpc_left > GRPC_MSG_COMPRESS_FLAG_SZ + GRPC_MSG_LENGTH_SZ) {
-               int next_field, found;
+       while (grpc_left > GRPC_MSG_HEADER_SZ) {
+               int field, found;
                size_t grpc_msg_len, left;
                unsigned int wire_type, field_number;
                uint64_t key, elen;
@@ -2824,8 +2824,8 @@ static int sample_conv_ungrpc(const struct arg *arg_p, struct sample *smp, void
                /* Message decoding: there may be serveral key+value protobuf pairs by
                 * gRPC message.
                 */
-               next_field = 0;
-               while (next_field < fid_sz) {
+               field = 0;
+               while (field < fid_sz) {
                        uint64_t sleft;
 
                        if ((ssize_t)left <= 0)
@@ -2840,50 +2840,32 @@ static int sample_conv_ungrpc(const struct arg *arg_p, struct sample *smp, void
 
                        wire_type = key & 0x7;
                        field_number = key >> 3;
-                       found = field_number == fid[next_field];
-
-                       if (found && field_number != fid[next_field])
-                               found = 0;
+                       found = field_number == fid[field];
 
                        switch (wire_type) {
                        case PBUF_TYPE_VARINT:
+                       case PBUF_TYPE_32BIT:
+                       case PBUF_TYPE_64BIT:
                        {
-                               if (!found) {
-                                       protobuf_skip_varint(&pos, &left);
-                               } else if (next_field == fid_sz - 1) {
-                                       int varint_len;
-                                       unsigned char *spos = pos;
+                               struct protobuf_parser_def *pbuf_parser;
 
-                                       varint_len = protobuf_varint_getlen(&pos, &left);
-                                       if (varint_len == -1)
+                               pbuf_parser = &protobuf_parser_defs[wire_type];
+                               if (!found) {
+                                       /* Skip the data. */
+                                       if (!pbuf_parser->skip(&pos, &left, 0))
                                                return 0;
-
-                                       smp->data.type = SMP_T_BIN;
-                                       smp->data.u.str.area = (char *)spos;
-                                       smp->data.u.str.data = varint_len;
-                                       smp->flags = SMP_F_VOL_TEST;
-                                       return 1;
                                }
-                               break;
-                       }
-
-                       case PBUF_TYPE_64BIT:
-                       {
-                               if (!found) {
-                                       pos += sizeof(uint64_t);
-                                       left -= sizeof(uint64_t);
-                               } else if (next_field == fid_sz - 1) {
-                                       smp->data.type = SMP_T_BIN;
-                                       smp->data.u.str.area = (char *)pos;
-                                       smp->data.u.str.data = sizeof(uint64_t);
-                                       smp->flags = SMP_F_VOL_TEST;
-                                       return 1;
+                               else if (field == fid_sz - 1) {
+                                       return pbuf_parser->smp_store(smp, pos, left, 0);
                                }
+
                                break;
                        }
 
                        case PBUF_TYPE_LENGTH_DELIMITED:
                        {
+                               struct protobuf_parser_def *pbuf_parser;
+
                                /* Decode the length of this length-delimited field. */
                                if (!protobuf_decode_varint(&elen, &pos, &left))
                                        return 0;
@@ -2895,33 +2877,15 @@ static int sample_conv_ungrpc(const struct arg *arg_p, struct sample *smp, void
                                 * the bytes to encode the previous lenght.*
                                 */
                                sleft = left;
+                               pbuf_parser = &protobuf_parser_defs[wire_type];
                                if (!found) {
-                                       /* Skip the current length-delimited field. */
-                                       pos += elen;
-                                       left -= elen;
-                                       break;
-                               } else if (next_field == fid_sz - 1) {
-                                       smp->data.type = SMP_T_BIN;
-                                       smp->data.u.str.area = (char *)pos;
-                                       smp->data.u.str.data = elen;
-                                       smp->flags = SMP_F_VOL_TEST;
-                                       return 1;
+                                       /* Skip the data. */
+                                       if (!pbuf_parser->skip(&pos, &left, elen))
+                                               return 0;
+                               } else if (field == fid_sz - 1) {
+                                       return pbuf_parser->smp_store(smp, pos, left, elen);
                                }
-                               break;
-                       }
 
-                       case PBUF_TYPE_32BIT:
-                       {
-                               if (!found) {
-                                       pos += sizeof(uint32_t);
-                                       left -= sizeof(uint32_t);
-                               } else if (next_field == fid_sz - 1) {
-                                       smp->data.type = SMP_T_BIN;
-                                       smp->data.u.str.area = (char *)pos;
-                                       smp->data.u.str.data = sizeof(uint32_t);
-                                       smp->flags = SMP_F_VOL_TEST;
-                                       return 1;
-                               }
                                break;
                        }
 
@@ -2933,10 +2897,10 @@ static int sample_conv_ungrpc(const struct arg *arg_p, struct sample *smp, void
                                elen -= sleft - left;
 
                        if (found) {
-                               next_field++;
+                               field++;
                        }
                        else if ((ssize_t)elen <= 0) {
-                               next_field = 0;
+                               field = 0;
                        }
                }
                grpc_left -= grpc_msg_len;