From 767f4980e54415c4680a4619c69b14f5b3ec24bb Mon Sep 17 00:00:00 2001 From: cbdev Date: Sat, 20 Feb 2021 20:06:06 +0100 Subject: Implement dynamic32 framing function --- plugins/framing_dynamic32.c | 74 ++++++++++++++++++++++++++++++++++++++++++++ plugins/framing_dynamic32.md | 21 +++++++++++++ plugins/makefile | 2 +- 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 plugins/framing_dynamic32.c create mode 100644 plugins/framing_dynamic32.md diff --git a/plugins/framing_dynamic32.c b/plugins/framing_dynamic32.c new file mode 100644 index 0000000..3b66588 --- /dev/null +++ b/plugins/framing_dynamic32.c @@ -0,0 +1,74 @@ +#include +#include +#include + +#include "../websocksy.h" + +typedef struct /*_framing_config*/ { + uint32_t offset; + int32_t fixed; + uint8_t endian; +} dynamic32_config_t; + +static int64_t framing_dynamic32(uint8_t* data, size_t length, size_t last_read, ws_operation* opcode, void** framing_data, const char* config){ + size_t u; + uint32_t* size_p, size = 0; + //get the current config if set + dynamic32_config_t* conncfg = (*framing_data) ? ((dynamic32_config_t*) (*framing_data)) : NULL; + + //configure framing for this connection + if(data && !conncfg){ + conncfg = calloc(1, sizeof(dynamic32_config_t)); + if(!conncfg){ + fprintf(stderr, "Failed to allocate memory\n"); + return -1; + } + + //parse config string + for(u = 0; config[u];){ + if(!strncmp(config + u, "offset=", 7)){ + conncfg->offset = strtoul(config + u + 7, NULL, 0); + } + else if(!strncmp(config + u, "static=", 7)){ + conncfg->fixed = strtoul(config + u + 7, NULL, 0); + } + else if(!strncmp(config + u, "endian=", 7)){ + conncfg->endian = 0; + if(!strncmp(config + u + 7, "big", 3)){ + conncfg->endian = 1; + } + } + + //skip to next item + for(; config[u] && config[u] != ','; u++){ + } + } + + //store configuration + *framing_data = conncfg; + } + //clean up configuration + else if(!data && conncfg){ + free(*framing_data); + *framing_data = NULL; + } + + if(length > conncfg->offset + 4){ + //read size field + size_p = (uint32_t*) (data + conncfg->offset); + size = le32toh(*size_p); + if(conncfg->endian){ + size = be32toh(*size_p); + } + + if(length >= conncfg->offset + 4 + conncfg->fixed + size){ + return conncfg->offset + 4 + conncfg->fixed + size; + } + } + + return 0; +} + +static void __attribute__((constructor)) init(){ + core_register_framing("dynamic32", framing_dynamic32); +} diff --git a/plugins/framing_dynamic32.md b/plugins/framing_dynamic32.md new file mode 100644 index 0000000..51ca04c --- /dev/null +++ b/plugins/framing_dynamic32.md @@ -0,0 +1,21 @@ +# The `dynamic32` framing function + +The `dynamic32` peer stream framing function segments the peer stream into binary frames +at dynamic byte boundaries inferred from the stream data itself. The function will read +a 32bit length value at a specified offset from the stream and treat it as the length +of the next segment to be framed. + +## Configuration + +The framing configuration string may be a comma-separated list of options of the form +`=`, containing one or more of the following keys: + +* `offset`: Set the offset (in bytes) of the 32-bit segment size in the stream, counted from the start of a segment/stream (Default: `0`) +* `static`: Static amount to add to the segment length, e.g. to account for fixed headers (Default: `0`) +* `endian`: Set the byte order of the transmitteed size to either `big` or `little` (Default: `little`) + +The total size of the segment sent to the Websocket peer can be calculated using the formula + +``` +offset + 4 /*32bit size field*/ + static + size field content +``` diff --git a/plugins/makefile b/plugins/makefile index b09466d..f0b38cb 100644 --- a/plugins/makefile +++ b/plugins/makefile @@ -1,5 +1,5 @@ .PHONY: all clean -PLUGINS = backend_file.so framing_fixedlength.so framing_json.so +PLUGINS = backend_file.so framing_fixedlength.so framing_json.so framing_dynamic32.so CFLAGS += -fPIC -g -I../ LDFLAGS += -shared -- cgit v1.2.3