#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>.
* 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;
* 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;
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 */
/* 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;
/* 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)
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;
* 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;
}
elen -= sleft - left;
if (found) {
- next_field++;
+ field++;
}
else if ((ssize_t)elen <= 0) {
- next_field = 0;
+ field = 0;
}
}
grpc_left -= grpc_msg_len;