From 58daab21cd043e1dc37024a7f99b396788372918 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 9 Mar 2024 14:19:48 +0100 Subject: Merging upstream version 1.44.3. Signed-off-by: Daniel Baumann --- mqtt_websockets/c-rbuf/src/ringbuffer.c | 209 +++++++++++++++++++++++ mqtt_websockets/c-rbuf/src/ringbuffer_internal.h | 43 +++++ 2 files changed, 252 insertions(+) create mode 100644 mqtt_websockets/c-rbuf/src/ringbuffer.c create mode 100644 mqtt_websockets/c-rbuf/src/ringbuffer_internal.h (limited to 'mqtt_websockets/c-rbuf/src') diff --git a/mqtt_websockets/c-rbuf/src/ringbuffer.c b/mqtt_websockets/c-rbuf/src/ringbuffer.c new file mode 100644 index 000000000..0dec13654 --- /dev/null +++ b/mqtt_websockets/c-rbuf/src/ringbuffer.c @@ -0,0 +1,209 @@ +/* + * + * Copyright: SPDX-License-Identifier: LGPL-3.0-only + * + * Author: Timotej Šiškovič + * + */ + +#include "ringbuffer.h" +#include "ringbuffer_internal.h" + +#include +#include +#include + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +// this allows user to use their own +// custom memory allocation functions +#ifdef RBUF_CUSTOM_MALLOC +#include "ringbuffer_pal.h" +#else +#define crbuf_malloc(...) malloc(__VA_ARGS__) +#define crbuf_free(...) free(__VA_ARGS__) +#endif + +rbuf_t rbuf_create(size_t size) +{ + rbuf_t buffer = crbuf_malloc(sizeof(struct rbuf_t) + size); + if (!buffer) + return NULL; + + memset(buffer, 0, sizeof(struct rbuf_t)); + + buffer->data = ((char*)buffer) + sizeof(struct rbuf_t); + + buffer->head = buffer->data; + buffer->tail = buffer->data; + buffer->size = size; + buffer->end = buffer->data + size; + + return buffer; +} + +void rbuf_free(rbuf_t buffer) +{ + crbuf_free(buffer); +} + +void rbuf_flush(rbuf_t buffer) +{ + buffer->head = buffer->data; + buffer->tail = buffer->data; + buffer->size_data = 0; +} + +char *rbuf_get_linear_insert_range(rbuf_t buffer, size_t *bytes) +{ + *bytes = 0; + if (buffer->head == buffer->tail && buffer->size_data) + return NULL; + + *bytes = ((buffer->head >= buffer->tail) ? buffer->end : buffer->tail) - buffer->head; + return buffer->head; +} + +char *rbuf_get_linear_read_range(rbuf_t buffer, size_t *bytes) +{ + *bytes = 0; + if(buffer->head == buffer->tail && !buffer->size_data) + return NULL; + + *bytes = ((buffer->tail >= buffer->head) ? buffer->end : buffer->head) - buffer->tail; + + return buffer->tail; +} + +int rbuf_bump_head(rbuf_t buffer, size_t bytes) +{ + size_t free_bytes = rbuf_bytes_free(buffer); + if (bytes > free_bytes) + return 0; + int i = buffer->head - buffer->data; + buffer->head = &buffer->data[(i + bytes) % buffer->size]; + buffer->size_data += bytes; + return 1; +} + +int rbuf_bump_tail(rbuf_t buffer, size_t bytes) +{ + if(!rbuf_bump_tail_noopt(buffer, bytes)) + return 0; + + // if tail catched up with head + // start writing buffer from beggining + // this is not necessary (rbuf must work well without it) + // but helps to optimize big writes as rbuf_get_linear_insert_range + // will return bigger continuous region + if(buffer->tail == buffer->head) { + assert(buffer->size_data == 0); + rbuf_flush(buffer); + } + + return 1; +} + +size_t rbuf_get_capacity(rbuf_t buffer) +{ + return buffer->size; +} + +size_t rbuf_bytes_available(rbuf_t buffer) +{ + return buffer->size_data; +} + +size_t rbuf_bytes_free(rbuf_t buffer) +{ + return buffer->size - buffer->size_data; +} + +size_t rbuf_push(rbuf_t buffer, const char *data, size_t len) +{ + size_t to_cpy; + char *w_ptr = rbuf_get_linear_insert_range(buffer, &to_cpy); + if(!to_cpy) + return to_cpy; + + to_cpy = MIN(to_cpy, len); + memcpy(w_ptr, data, to_cpy); + rbuf_bump_head(buffer, to_cpy); + if(to_cpy < len) + to_cpy += rbuf_push(buffer, &data[to_cpy], len - to_cpy); + return to_cpy; +} + +size_t rbuf_pop(rbuf_t buffer, char *data, size_t len) +{ + size_t to_cpy; + const char *r_ptr = rbuf_get_linear_read_range(buffer, &to_cpy); + if(!to_cpy) + return to_cpy; + + to_cpy = MIN(to_cpy, len); + memcpy(data, r_ptr, to_cpy); + rbuf_bump_tail(buffer, to_cpy); + if(to_cpy < len) + to_cpy += rbuf_pop(buffer, &data[to_cpy], len - to_cpy); + return to_cpy; +} + +static inline void rbuf_ptr_inc(rbuf_t buffer, const char **ptr) +{ + (*ptr)++; + if(*ptr >= buffer->end) + *ptr = buffer->data; +} + +int rbuf_memcmp(rbuf_t buffer, const char *haystack, const char *needle, size_t needle_bytes) +{ + const char *end = needle + needle_bytes; + + // as head==tail can mean 2 things here + if (haystack == buffer->head && buffer->size_data) { + if (*haystack != *needle) + return (*haystack - *needle); + rbuf_ptr_inc(buffer, &haystack); + needle++; + } + + while (haystack != buffer->head && needle != end) { + if (*haystack != *needle) + return (*haystack - *needle); + rbuf_ptr_inc(buffer, &haystack); + needle++; + } + return 0; +} + +int rbuf_memcmp_n(rbuf_t buffer, const char *to_cmp, size_t to_cmp_bytes) +{ + return rbuf_memcmp(buffer, buffer->tail, to_cmp, to_cmp_bytes); +} + +char *rbuf_find_bytes(rbuf_t buffer, const char *needle, size_t needle_bytes, int *found_idx) +{ + const char *ptr = buffer->tail; + *found_idx = 0; + + if (!rbuf_bytes_available(buffer)) + return NULL; + + if (buffer->head == buffer->tail && buffer->size_data) { + if(!rbuf_memcmp(buffer, ptr, needle, needle_bytes)) + return (char *)ptr; + rbuf_ptr_inc(buffer, &ptr); + (*found_idx)++; + } + + while (ptr != buffer->head) + { + if(!rbuf_memcmp(buffer, ptr, needle, needle_bytes)) + return (char *)ptr; + rbuf_ptr_inc(buffer, &ptr); + (*found_idx)++; + } + return NULL; +} diff --git a/mqtt_websockets/c-rbuf/src/ringbuffer_internal.h b/mqtt_websockets/c-rbuf/src/ringbuffer_internal.h new file mode 100644 index 000000000..f7bdf815c --- /dev/null +++ b/mqtt_websockets/c-rbuf/src/ringbuffer_internal.h @@ -0,0 +1,43 @@ +/* + * + * Copyright: SPDX-License-Identifier: LGPL-3.0-only + * + * Author: Timotej Šiškovič + * + */ + +#ifndef RINGBUFFER_INTERNAL_H +#define RINGBUFFER_INTERNAL_H + +struct rbuf_t { + char *data; + + // points to next byte where we can write + char *head; + // points to oldest (next to be poped) readable byte + char *tail; + + // to avoid calculating data + size + // all the time + char *end; + + size_t size; + size_t size_data; +}; + +/* this exists so that it can be tested by unit tests + * without optimization that resets head and tail to + * beginning if buffer empty + */ +inline static int rbuf_bump_tail_noopt(rbuf_t buffer, size_t bytes) +{ + if (bytes > buffer->size_data) + return 0; + int i = buffer->tail - buffer->data; + buffer->tail = &buffer->data[(i + bytes) % buffer->size]; + buffer->size_data -= bytes; + + return 1; +} + +#endif -- cgit v1.2.3