0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-12-23 02:01:55 +00:00

Lib: mostly rewritten CBOR encoder

This commit is contained in:
Maria Matejka 2024-10-07 15:05:21 +02:00
parent 139355e7ab
commit ccfc127505
3 changed files with 223 additions and 48 deletions

View File

@ -1,4 +1,4 @@
src := bitmap.c bitops.c blake2s.c blake2b.c cbor.c cbor-parser.c cbor_parse_tools.c cbor_shortcuts.c checksum.c defer.c event.c flowspec.c idm.c ip.c lists.c lockfree.c mac.c md5.c mempool.c net.c netindex.c patmatch.c printf.c rcu.c resource.c runtime.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c src := bitmap.c bitops.c blake2s.c blake2b.c cbor.c cbor-parser.c checksum.c defer.c event.c flowspec.c idm.c ip.c lists.c lockfree.c mac.c md5.c mempool.c net.c netindex.c patmatch.c printf.c rcu.c resource.c runtime.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c
obj := $(src-o-files) obj := $(src-o-files)
$(all-lib) $(all-lib)

View File

@ -3,6 +3,7 @@
#include "lib/cbor.h" #include "lib/cbor.h"
/* String versions of type constants */
static const char *cbor_type_str_a[] = { static const char *cbor_type_str_a[] = {
"POSINT", "POSINT",
"NEGINT", "NEGINT",
@ -22,62 +23,179 @@ cbor_type_str(enum cbor_basic_type t)
tmp_sprintf("(unknown: %u)", t); tmp_sprintf("(unknown: %u)", t);
} }
void write_item(struct cbor_writer *writer, uint8_t major, uint64_t num); /* Raw data writing */
void check_memory(struct cbor_writer *writer, int add_size);
struct cbor_writer *cbor_init(uint8_t *buff, uint32_t capacity, struct linpool *lp) bool cbor_put_check(struct cbor_writer *w, u64 amount)
{ {
struct cbor_writer *writer = (struct cbor_writer*)lp_alloc(lp, sizeof(struct cbor_writer)); return w->data.pos + amount <= w->data.end;
writer->cbor = buff;
writer->capacity = capacity;
writer->pt = 0;
writer->lp = lp;
return writer;
} }
void cbor_open_block(struct cbor_writer *writer) { // We will need to close the block later manualy #define CBOR_PUT(amount) ({ \
check_memory(writer, 2); byte *put = w->data.pos; \
writer->cbor[writer->pt] = 0xbf; if ((w->data.pos += (amount)) >= w->data.end) return false; \
writer->pt++; put; })
bool cbor_put_raw_u8(struct cbor_writer *w, byte b)
{
*(CBOR_PUT(1)) = b;
return true;
} }
void cbor_open_list(struct cbor_writer *writer) bool cbor_put_raw_u16(struct cbor_writer *w, u16 val)
{ {
check_memory(writer, 2); put_u16(CBOR_PUT(2), val);
writer->cbor[writer->pt] = 0x9f; return true;
writer->pt++;
} }
void cbor_close_block_or_list(struct cbor_writer *writer) bool cbor_put_raw_u32(struct cbor_writer *w, u32 val)
{ {
check_memory(writer, 2); put_u32(CBOR_PUT(4), val);
writer->cbor[writer->pt] = 0xff; return true;
writer->pt++;
} }
void cbor_open_block_with_length(struct cbor_writer *writer, uint32_t length) bool cbor_put_raw_u64(struct cbor_writer *w, u64 val)
{ {
write_item(writer, 5, length); put_u64(CBOR_PUT(8), val);
return true;
} }
void cbor_open_list_with_length(struct cbor_writer *writer, uint32_t length) bool cbor_put_raw_data(struct cbor_writer *w, const byte *block, u64 size)
{ {
write_item(writer, 4, length); memcpy(CBOR_PUT(size), block, size);
return true;
} }
/* Basic value putting */
void cbor_add_int(struct cbor_writer *writer, int64_t item) bool cbor_put(struct cbor_writer *w, enum cbor_basic_type type, u64 value)
{ {
if (item >= 0) ASSERT_DIE((type >= 0) && (type <= 8));
w->stack[w->stack_pos].items++;
byte tt = type << 5;
if (value < 0x18)
return
cbor_put_raw_u8(w, tt | value);
else if (value < 0x100)
return
cbor_put_raw_u8(w, tt | 0x18) &&
cbor_put_raw_u8(w, value);
else if (value < 0x10000)
return
cbor_put_raw_u8(w, tt | 0x19) &&
cbor_put_raw_u16(w, value);
else if (value < 0x100000000)
return
cbor_put_raw_u8(w, tt | 0x1a) &&
cbor_put_raw_u32(w, value);
else
return
cbor_put_raw_u8(w, tt | 0x1b) &&
cbor_put_raw_u64(w, value);
}
bool cbor_put_int(struct cbor_writer *w, int64_t value)
{
if (value >= 0)
return cbor_put(w, CBOR_POSINT, value);
else
return cbor_put(w, CBOR_NEGINT, -1-value);
}
/* Strings */
bool cbor_put_raw_bytes(struct cbor_writer *w, enum cbor_basic_type type, const byte *block, u64 size)
{
return
cbor_put(w, type, size) &&
cbor_put_raw_data(w, block, size);
}
/* Arrays and maps */
bool cbor_put_open(struct cbor_writer *w, enum cbor_basic_type type)
{
if (++w->stack_pos >= w->stack_max)
return false;
w->stack[w->stack_pos].head = w->data.pos;
w->stack[w->stack_pos].items = 0;
return cbor_put(w, type, ~0ULL);
}
bool cbor_put_close(struct cbor_writer *w, u64 actual_size, bool strict)
{
ASSERT_DIE(w->stack_pos > 0);
/* Pop the stack */
byte *head = w->stack[w->stack_pos].head;
u64 items = w->stack[w->stack_pos].items;
w->stack_pos--;
/* Check the original head position */
ASSERT_DIE((head[0] & 0x1f) == 0x1f);
ASSERT_DIE(w->data.pos >= w->data.start + 9);
switch (head[0] >> 5)
{ {
write_item(writer, 0, item); // 0 is the "major" (three bits) introducing positive int, 1 is for negative case CBOR_ARRAY:
if (strict && (items != actual_size))
bug("Inconsistent array item count");
break;
case CBOR_MAP:
if (strict && (items != actual_size * 2))
bug("Inconsistent map item count");
else if (items & 1)
bug("Trailing map key");
else
items /= 2;
break;
default:
bug("Head points to something other than array or map");
}
/* Move the data back */
if (items < 0x18)
{
memmove(head+1, head+9, w->data.pos - (head+9));
head[0] &= (0xe0 | items);
w->data.pos -= 8;
}
else if (items < 0x100)
{
memmove(head+2, head+9, w->data.pos - (head+9));
head[0] &= 0xf8;
head[1] = items;
w->data.pos -= 7;
}
else if (items < 0x10000)
{
memmove(head+3, head+9, w->data.pos - (head+9));
head[0] &= 0xf9;
put_u16(head+1, items);
w->data.pos -= 6;
}
else if (items < 0x100000000)
{
memmove(head+5, head+9, w->data.pos - (head+9));
head[0] &= 0xfa;
put_u32(head+1, items);
w->data.pos -= 4;
} }
else else
{ {
write_item(writer, 1, -item - 1); head[0] &= 0xfb;
put_u64(head+1, items);
} }
return true;
} }
/* Tags: TODO! */
#if 0
void cbor_epoch_time(struct cbor_writer *writer, int64_t time, int shift) void cbor_epoch_time(struct cbor_writer *writer, int64_t time, int shift)
{ {
write_item(writer, 6, 1); // 6 is TAG, 1 is tag number for epoch time write_item(writer, 6, 1); // 6 is TAG, 1 is tag number for epoch time
@ -253,3 +371,4 @@ void check_memory(struct cbor_writer *writer, int add_size)
bug("There is not enough space for cbor response in given buffer"); bug("There is not enough space for cbor response in given buffer");
} }
} }
#endif

View File

@ -3,6 +3,10 @@
#include "nest/bird.h" #include "nest/bird.h"
/**
* CBOR Commonalities
**/
enum cbor_basic_type { enum cbor_basic_type {
CBOR_POSINT = 0, CBOR_POSINT = 0,
CBOR_NEGINT = 1, CBOR_NEGINT = 1,
@ -16,27 +20,78 @@ enum cbor_basic_type {
const char *cbor_type_str(enum cbor_basic_type); const char *cbor_type_str(enum cbor_basic_type);
/**
* CBOR Writer
**/
struct cbor_writer { struct cbor_writer {
int pt; // where will next byte go buffer data;
int capacity; uint stack_pos, stack_max; /* Nesting of CBOR_ARRAY / CBOR_MAP */
int8_t *cbor; struct cbor_writer_stack_item {
struct linpool *lp; u64 items;
byte *head;
} stack[0];
}; };
/* Initialization */
static inline struct cbor_writer *cbor_writer_init(struct cbor_writer *w, uint stack_max_depth, byte *buf, uint size)
{
*w = (struct cbor_writer) {
.data = {
.start = buf,
.pos = buf,
.end = buf + size,
},
.stack_max = stack_max_depth,
};
return w;
}
struct cbor_writer *cbor_init(uint8_t *buff, uint32_t capacity, struct linpool *lp); #define cbor_writer_new(p, smax, buf, size) cbor_writer_init(mb_alloc((p), sizeof(struct cbor_writer) + (smax) * sizeof(struct cbor_writer_stack_item)), (smax), (buf), (size))
void cbor_open_block(struct cbor_writer *writer);
void cbor_open_list(struct cbor_writer *writer);
void cbor_close_block_or_list(struct cbor_writer *writer);
void cbor_open_block_with_length(struct cbor_writer *writer, uint32_t length);
void cbor_open_list_with_length(struct cbor_writer *writer, uint32_t length);
/* Return how many items have been encoded */
static inline int cbor_writer_done(struct cbor_writer *w)
{
if (w->stack_pos > 0)
return -1;
else
return w->stack[0].items;
}
/* Integer types */
bool cbor_put(struct cbor_writer *w, enum cbor_basic_type type, u64 value);
#define cbor_put_posint(w,v) cbor_put((w), CBOR_POSINT, (v))
#define cbor_put_negint(w,v) cbor_put((w), CBOR_NEGINT, -1-(v))
bool cbor_put_int(struct cbor_writer *w, int64_t value);
/* String types */
bool cbor_put_raw_bytes(struct cbor_writer *w, enum cbor_basic_type type, const byte *block, u64 size);
#define cbor_put_bytes(w, b, s) cbor_put_raw_bytes((w), CBOR_BYTES, (b), (s))
#define cbor_put_text(w, b, s) cbor_put_raw_bytes((w), CBOR_TEXT, (b), (s))
#define cbor_put_string(w, s) cbor_put_raw_bytes((w), CBOR_TEXT, (s), strlen(s))
#define cbor_put_toks(w, s) cbor_put_raw_bytes((w), CBOR_TEXT, #s, sizeof #s)
/* Compound types */
bool cbor_put_open(struct cbor_writer *w, enum cbor_basic_type type);
bool cbor_put_close(struct cbor_writer *w, u64 actual_size, bool strict);
#define cbor_open_array(w) cbor_put_open((w), CBOR_ARRAY)
#define cbor_open_map(w) cbor_put_open((w), CBOR_MAP)
#define cbor_close_array(w) cbor_put_close((w), 0, 0)
#define cbor_close_map(w) cbor_put_close((w), 0, 0)
#define CBOR_PUT_ARRAY(w) for (struct cbor_writer *_w = w, *_ww = cbor_open_array(_w) ? (_w) : (bug("buffer overflow on CBOR_ARRAY"), NULL); (_w = NULL), _ww; cbor_close_array(_ww), _ww = NULL)
#define CBOR_PUT_MAP(w) for (struct cbor_writer *_w = w, *_ww = cbor_open_map(_w) ? (_w) : (bug("buffer overflow on CBOR_MAP"), NULL); (_w = NULL), _ww; cbor_close_map(_ww), _ww = NULL)
/* Specials */
#define cbor_put_false(w) cbor_put((w), CBOR_SPECIAL, 20);
#define cbor_put_true(w) cbor_put((w), CBOR_SPECIAL, 21);
#define cbor_put_null(w) cbor_put((w), CBOR_SPECIAL, 22);
#define cbor_put_undef(w) cbor_put((w), CBOR_SPECIAL, 23);
#if 0
void cbor_add_int(struct cbor_writer *writer, int64_t item); void cbor_add_int(struct cbor_writer *writer, int64_t item);
void cbor_add_ipv4(struct cbor_writer *writer, ip4_addr); void cbor_add_ipv4(struct cbor_writer *writer, ip4_addr);
@ -66,6 +121,7 @@ void write_item(struct cbor_writer *writer, uint8_t major, uint64_t num);
void cbor_write_item_with_constant_val_length_4(struct cbor_writer *writer, uint8_t major, uint64_t num); void cbor_write_item_with_constant_val_length_4(struct cbor_writer *writer, uint8_t major, uint64_t num);
void rewrite_4bytes_int(struct cbor_writer *writer, int pt, int num); void rewrite_4bytes_int(struct cbor_writer *writer, int pt, int num);
#endif
/* /*
* Parser bits * Parser bits