summaryrefslogtreecommitdiffstats
path: root/aclk
diff options
context:
space:
mode:
Diffstat (limited to 'aclk')
-rw-r--r--aclk/aclk.c2
-rw-r--r--aclk/aclk_otp.c2
-rw-r--r--aclk/aclk_query.h2
-rw-r--r--aclk/aclk_stats.h2
-rw-r--r--aclk/aclk_tx_msgs.h2
-rw-r--r--aclk/aclk_util.h2
-rw-r--r--aclk/https_client.h4
-rw-r--r--aclk/mqtt_websockets/.github/workflows/run-tests.yaml14
-rw-r--r--aclk/mqtt_websockets/.gitignore10
-rw-r--r--aclk/mqtt_websockets/README.md7
-rw-r--r--aclk/mqtt_websockets/c-rbuf/cringbuffer.c203
-rw-r--r--aclk/mqtt_websockets/c-rbuf/cringbuffer.h47
-rw-r--r--aclk/mqtt_websockets/c-rbuf/cringbuffer_internal.h37
-rw-r--r--aclk/mqtt_websockets/c-rbuf/ringbuffer_test.c485
-rw-r--r--aclk/mqtt_websockets/c_rhash/c_rhash.c264
-rw-r--r--aclk/mqtt_websockets/c_rhash/c_rhash.h61
-rw-r--r--aclk/mqtt_websockets/c_rhash/c_rhash_internal.h19
-rw-r--r--aclk/mqtt_websockets/c_rhash/tests.c273
-rw-r--r--aclk/mqtt_websockets/common_internal.h27
-rw-r--r--aclk/mqtt_websockets/common_public.c9
-rw-r--r--aclk/mqtt_websockets/common_public.h33
-rw-r--r--aclk/mqtt_websockets/endian_compat.h31
-rw-r--r--aclk/mqtt_websockets/mqtt_constants.h103
-rw-r--r--aclk/mqtt_websockets/mqtt_ng.c2237
-rw-r--r--aclk/mqtt_websockets/mqtt_ng.h99
-rw-r--r--aclk/mqtt_websockets/mqtt_wss_client.c1126
-rw-r--r--aclk/mqtt_websockets/mqtt_wss_client.h162
-rw-r--r--aclk/mqtt_websockets/mqtt_wss_log.c130
-rw-r--r--aclk/mqtt_websockets/mqtt_wss_log.h39
-rw-r--r--aclk/mqtt_websockets/test.c90
-rw-r--r--aclk/mqtt_websockets/ws_client.c744
-rw-r--r--aclk/mqtt_websockets/ws_client.h120
32 files changed, 6378 insertions, 8 deletions
diff --git a/aclk/aclk.c b/aclk/aclk.c
index e95d7d6ab7..6d583a76a6 100644
--- a/aclk/aclk.c
+++ b/aclk/aclk.c
@@ -4,7 +4,7 @@
#ifdef ENABLE_ACLK
#include "aclk_stats.h"
-#include "mqtt_wss_client.h"
+#include "mqtt_websockets/mqtt_wss_client.h"
#include "aclk_otp.h"
#include "aclk_tx_msgs.h"
#include "aclk_query.h"
diff --git a/aclk/aclk_otp.c b/aclk/aclk_otp.c
index 207ca08cf0..e03f8b2121 100644
--- a/aclk/aclk_otp.c
+++ b/aclk/aclk_otp.c
@@ -7,7 +7,7 @@
#include "daemon/common.h"
-#include "mqtt_websockets/c-rbuf/include/ringbuffer.h"
+#include "mqtt_websockets/c-rbuf/cringbuffer.h"
static int aclk_https_request(https_req_t *request, https_req_response_t *response) {
int rc;
diff --git a/aclk/aclk_query.h b/aclk/aclk_query.h
index dbe6f9e5e6..371b8d0a24 100644
--- a/aclk/aclk_query.h
+++ b/aclk/aclk_query.h
@@ -5,7 +5,7 @@
#include "libnetdata/libnetdata.h"
-#include "mqtt_wss_client.h"
+#include "mqtt_websockets/mqtt_wss_client.h"
#include "aclk_query_queue.h"
diff --git a/aclk/aclk_stats.h b/aclk/aclk_stats.h
index 002ebcfa6b..758347ae26 100644
--- a/aclk/aclk_stats.h
+++ b/aclk/aclk_stats.h
@@ -6,7 +6,7 @@
#include "daemon/common.h"
#include "libnetdata/libnetdata.h"
#include "aclk_query_queue.h"
-#include "mqtt_wss_client.h"
+#include "mqtt_websockets/mqtt_wss_client.h"
extern netdata_mutex_t aclk_stats_mutex;
diff --git a/aclk/aclk_tx_msgs.h b/aclk/aclk_tx_msgs.h
index 9e7d890772..86ed20c381 100644
--- a/aclk/aclk_tx_msgs.h
+++ b/aclk/aclk_tx_msgs.h
@@ -5,7 +5,7 @@
#include <json-c/json.h>
#include "libnetdata/libnetdata.h"
#include "daemon/common.h"
-#include "mqtt_wss_client.h"
+#include "mqtt_websockets/mqtt_wss_client.h"
#include "schema-wrappers/schema_wrappers.h"
#include "aclk_util.h"
diff --git a/aclk/aclk_util.h b/aclk/aclk_util.h
index 38ef5b0bcb..6c0239cc31 100644
--- a/aclk/aclk_util.h
+++ b/aclk/aclk_util.h
@@ -5,7 +5,7 @@
#include "libnetdata/libnetdata.h"
#ifdef ENABLE_ACLK
-#include "mqtt_wss_client.h"
+#include "mqtt_websockets/mqtt_wss_client.h"
#define CLOUD_EC_MALFORMED_NODE_ID 1
#define CLOUD_EMSG_MALFORMED_NODE_ID "URL requests node_id but there is not enough chars following (for it to be valid uuid)."
diff --git a/aclk/https_client.h b/aclk/https_client.h
index c87b3b69fd..79d0a42b75 100644
--- a/aclk/https_client.h
+++ b/aclk/https_client.h
@@ -5,8 +5,8 @@
#include "libnetdata/libnetdata.h"
-#include "mqtt_websockets/c-rbuf/include/ringbuffer.h"
-#include "mqtt_websockets/c_rhash/include/c_rhash.h"
+#include "mqtt_websockets/c-rbuf/cringbuffer.h"
+#include "mqtt_websockets/c_rhash/c_rhash.h"
typedef enum http_req_type {
HTTP_REQ_GET = 0,
diff --git a/aclk/mqtt_websockets/.github/workflows/run-tests.yaml b/aclk/mqtt_websockets/.github/workflows/run-tests.yaml
new file mode 100644
index 0000000000..da5dde821b
--- /dev/null
+++ b/aclk/mqtt_websockets/.github/workflows/run-tests.yaml
@@ -0,0 +1,14 @@
+name: run-tests
+on:
+ push:
+ schedule:
+ - cron: '5 3 * * 0'
+ pull_request:
+jobs:
+ run-tests:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Install ruby and deps
+ run: sudo apt-get install ruby ruby-dev mosquitto
+ - name: Checkout
+ uses: actions/checkout@v2
diff --git a/aclk/mqtt_websockets/.gitignore b/aclk/mqtt_websockets/.gitignore
new file mode 100644
index 0000000000..9f1a0d89a3
--- /dev/null
+++ b/aclk/mqtt_websockets/.gitignore
@@ -0,0 +1,10 @@
+build/*
+!build/.keep
+test
+.vscode
+mqtt/mqtt.c
+mqtt/include/mqtt.h
+libmqttwebsockets.*
+*.o
+.dirstamp
+.deps
diff --git a/aclk/mqtt_websockets/README.md b/aclk/mqtt_websockets/README.md
new file mode 100644
index 0000000000..b159686dfb
--- /dev/null
+++ b/aclk/mqtt_websockets/README.md
@@ -0,0 +1,7 @@
+# mqtt_websockets
+
+Library to connect MQTT client over Websockets Secure (WSS).
+
+## License
+
+The Project is released under GPL v3 license. See [License](LICENSE)
diff --git a/aclk/mqtt_websockets/c-rbuf/cringbuffer.c b/aclk/mqtt_websockets/c-rbuf/cringbuffer.c
new file mode 100644
index 0000000000..165980166e
--- /dev/null
+++ b/aclk/mqtt_websockets/c-rbuf/cringbuffer.c
@@ -0,0 +1,203 @@
+// Copyright: SPDX-License-Identifier: GPL-3.0-only
+
+#include "cringbuffer.h"
+#include "cringbuffer_internal.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+#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/aclk/mqtt_websockets/c-rbuf/cringbuffer.h b/aclk/mqtt_websockets/c-rbuf/cringbuffer.h
new file mode 100644
index 0000000000..eb98035a96
--- /dev/null
+++ b/aclk/mqtt_websockets/c-rbuf/cringbuffer.h
@@ -0,0 +1,47 @@
+// Copyright: SPDX-License-Identifier: GPL-3.0-only
+
+#ifndef CRINGBUFFER_H
+#define CRINGBUFFER_H
+
+#include <stddef.h>
+
+typedef struct rbuf_t *rbuf_t;
+
+rbuf_t rbuf_create(size_t size);
+void rbuf_free(rbuf_t buffer);
+void rbuf_flush(rbuf_t buffer);
+
+/* /param bytes how much bytes can be copied into pointer returned
+ * /return pointer where data can be copied to or NULL if buffer full
+ */
+char *rbuf_get_linear_insert_range(rbuf_t buffer, size_t *bytes);
+char *rbuf_get_linear_read_range(rbuf_t buffer, size_t *bytes);
+
+int rbuf_bump_head(rbuf_t buffer, size_t bytes);
+int rbuf_bump_tail(rbuf_t buffer, size_t bytes);
+
+/* @param buffer related buffer instance
+ * @returns total capacity of buffer in bytes (not free/used)
+ */
+size_t rbuf_get_capacity(rbuf_t buffer);
+
+/* @param buffer related buffer instance
+ * @returns count of bytes stored in the buffer
+ */
+size_t rbuf_bytes_available(rbuf_t buffer);
+
+/* @param buffer related buffer instance
+ * @returns count of bytes available/free in the buffer (how many more bytes you can store in this buffer)
+ */
+size_t rbuf_bytes_free(rbuf_t buffer);
+
+/* writes as many bytes from `data` into the `buffer` as possible
+ * but maximum `len` bytes
+ */
+size_t rbuf_push(rbuf_t buffer, const char *data, size_t len);
+size_t rbuf_pop(rbuf_t buffer, char *data, size_t len);
+
+char *rbuf_find_bytes(rbuf_t buffer, const char *needle, size_t needle_bytes, int *found_idx);
+int rbuf_memcmp_n(rbuf_t buffer, const char *to_cmp, size_t to_cmp_bytes);
+
+#endif
diff --git a/aclk/mqtt_websockets/c-rbuf/cringbuffer_internal.h b/aclk/mqtt_websockets/c-rbuf/cringbuffer_internal.h
new file mode 100644
index 0000000000..d32de187ce
--- /dev/null
+++ b/aclk/mqtt_websockets/c-rbuf/cringbuffer_internal.h
@@ -0,0 +1,37 @@
+// Copyright: SPDX-License-Identifier: GPL-3.0-only
+
+#ifndef CRINGBUFFER_INTERNAL_H
+#define CRINGBUFFER_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
diff --git a/aclk/mqtt_websockets/c-rbuf/ringbuffer_test.c b/aclk/mqtt_websockets/c-rbuf/ringbuffer_test.c
new file mode 100644
index 0000000000..6a17c99567
--- /dev/null
+++ b/aclk/mqtt_websockets/c-rbuf/ringbuffer_test.c
@@ -0,0 +1,485 @@
+// Copyright: SPDX-License-Identifier: GPL-3.0-only
+
+#include "ringbuffer.h"
+
+// to be able to access internals
+// never do this from app
+#include "../src/ringbuffer_internal.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#define KNRM "\x1B[0m"
+#define KRED "\x1B[31m"
+#define KGRN "\x1B[32m"
+#define KYEL "\x1B[33m"
+#define KBLU "\x1B[34m"
+#define KMAG "\x1B[35m"
+#define KCYN "\x1B[36m"
+#define KWHT "\x1B[37m"
+
+#define UNUSED(x) (void)(x)
+
+int total_fails = 0;
+int total_tests = 0;
+int total_checks = 0;
+
+#define CHECK_EQ_RESULT(x, y) \
+ while (s_len--) \
+ putchar('.'); \
+ printf("%s%s " KNRM "\n", (((x) == (y)) ? KGRN : KRED), (((x) == (y)) ? " PASS " : " FAIL ")); \
+ if ((x) != (y)) \
+ total_fails++; \
+ total_checks++;
+
+#define CHECK_EQ_PREFIX(x, y, prefix, subtest_name, ...) \
+ { \
+ int s_len = \
+ 100 - \
+ printf(("Checking: " KWHT "%s %s%2d " subtest_name " " KNRM), __func__, prefix, subtest_no, ##__VA_ARGS__); \
+ CHECK_EQ_RESULT(x, y) \
+ }
+
+#define CHECK_EQ(x, y, subtest_name, ...) \
+ { \
+ int s_len = \
+ 100 - printf(("Checking: " KWHT "%s %2d " subtest_name " " KNRM), __func__, subtest_no, ##__VA_ARGS__); \
+ CHECK_EQ_RESULT(x, y) \
+ }
+
+#define TEST_DECL() \
+ int subtest_no = 0; \
+ printf(KYEL "TEST SUITE: %s\n" KNRM, __func__); \
+ total_tests++;
+
+static void test_rbuf_get_linear_insert_range()
+{
+ TEST_DECL();
+
+ // check empty buffer behaviour
+ rbuf_t buff = rbuf_create(5);
+ char *to_write;
+ size_t ret;
+ to_write = rbuf_get_linear_insert_range(buff, &ret);
+ CHECK_EQ(ret, 5, "empty size");
+ CHECK_EQ(to_write, buff->head, "empty write ptr");
+ rbuf_free(buff);
+
+ // check full buffer behaviour
+ subtest_no++;
+ buff = rbuf_create(5);
+ ret = rbuf_bump_head(buff, 5);
+ CHECK_EQ(ret, 1, "ret");
+ to_write = rbuf_get_linear_insert_range(buff, &ret);
+ CHECK_EQ(to_write, NULL, "writable NULL");
+ CHECK_EQ(ret, 0, "writable count = 0");
+
+ // check buffer flush
+ subtest_no++;
+ rbuf_flush(buff);
+ CHECK_EQ(rbuf_bytes_free(buff), 5, "size_free");
+ CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail");
+ CHECK_EQ(buff->head, buff->data, "head_ptr");
+ CHECK_EQ(buff->tail, buff->data, "tail_ptr");
+
+ // check behaviour head > tail
+ subtest_no++;
+ rbuf_flush(buff);
+ rbuf_bump_head(buff, 3);
+ to_write = rbuf_get_linear_insert_range(buff, &ret);
+ CHECK_EQ(to_write, buff->head, "write location");
+ CHECK_EQ(ret, 2, "availible to linear write");
+
+ // check behaviour tail > head
+ subtest_no++;
+ rbuf_flush(buff);
+ rbuf_bump_head(buff, 5);
+ rbuf_bump_tail(buff, 3);
+ CHECK_EQ(buff->head, buff->data, "head_ptr");
+ CHECK_EQ(buff->tail, buff->data + 3, "tail_ptr");
+ to_write = rbuf_get_linear_insert_range(buff, &ret);
+ CHECK_EQ(to_write, buff->head, "write location");
+ CHECK_EQ(ret, 3, "availible to linear write");
+
+/* // check behaviour tail and head at last element
+ subtest_no++;
+ rbuf_flush(buff);
+ rbuf_bump_head(buff, 4);
+ rbuf_bump_tail(buff, 4);
+ CHECK_EQ(buff->head, buff->end - 1, "head_ptr");
+ CHECK_EQ(buff->tail, buff->end - 1, "tail_ptr");
+ to_write = rbuf_get_linear_insert_range(buff, &ret);
+ CHECK_EQ(to_write, buff->head, "write location");
+ CHECK_EQ(ret, 1, "availible to linear write");*/
+
+ // check behaviour tail and head at last element
+ // after rbuf_bump_tail optimisation that restarts buffer
+ // in case tail catches up with head
+ subtest_no++;
+ rbuf_flush(buff);
+ rbuf_bump_head(buff, 4);
+ rbuf_bump_tail(buff, 4);
+ CHECK_EQ(buff->head, buff->data, "head_ptr");
+ CHECK_EQ(buff->tail, buff->data, "tail_ptr");
+ to_write = rbuf_get_linear_insert_range(buff, &ret);
+ CHECK_EQ(to_write, buff->head, "write location");
+ CHECK_EQ(ret, 5, "availible to linear write");
+}
+
+#define _CHECK_EQ(x, y, subtest_name, ...) CHECK_EQ_PREFIX(x, y, prefix, subtest_name, ##__VA_ARGS__)
+#define _PREFX "(size = %5zu) "
+static void test_rbuf_bump_head_bsize(size_t size)
+{
+ char prefix[16];
+ snprintf(prefix, 16, _PREFX, size);
+ int subtest_no = 0;
+ rbuf_t buff = rbuf_create(size);
+ _CHECK_EQ(rbuf_bytes_free(buff), size, "size_free");
+
+ subtest_no++;
+ int ret = rbuf_bump_head(buff, size);
+ _CHECK_EQ(buff->data, buff->head, "loc");
+ _CHECK_EQ(ret, 1, "ret");
+ _CHECK_EQ(buff->size_data, buff->size, "size");
+ _CHECK_EQ(rbuf_bytes_free(buff), 0, "size_free");
+
+ subtest_no++;
+ ret = rbuf_bump_head(buff, 1);
+ _CHECK_EQ(buff->data, buff->head, "loc no move");
+ _CHECK_EQ(ret, 0, "ret error");
+ _CHECK_EQ(buff->size_data, buff->size, "size");
+ _CHECK_EQ(rbuf_bytes_free(buff), 0, "size_free");
+ rbuf_free(buff);
+
+ subtest_no++;
+ buff = rbuf_create(size);
+ ret = rbuf_bump_head(buff, size - 1);
+ _CHECK_EQ(buff->head, buff->end-1, "loc end");
+ rbuf_free(buff);
+}
+#undef _CHECK_EQ
+
+static void test_rbuf_bump_head()
+{
+ TEST_DECL();
+ UNUSED(subtest_no);
+
+ size_t test_sizes[] = { 1, 2, 3, 5, 6, 7, 8, 100, 99999, 0 };
+ for (int i = 0; test_sizes[i]; i++)
+ test_rbuf_bump_head_bsize(test_sizes[i]);
+}
+
+static void test_rbuf_bump_tail_noopt(int subtest_no)
+{
+ rbuf_t buff = rbuf_create(10);
+ CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free");
+ CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail");
+
+ subtest_no++;
+ int ret = rbuf_bump_head(buff, 5);
+ CHECK_EQ(ret, 1, "ret");
+ CHECK_EQ(rbuf_bytes_free(buff), 5, "size_free");
+ CHECK_EQ(rbuf_bytes_available(buff), 5, "size_avail");
+ CHECK_EQ(buff->head, buff->data + 5, "head_ptr");
+ CHECK_EQ(buff->tail, buff->data, "tail_ptr");
+
+ subtest_no++;
+ ret = rbuf_bump_tail_noopt(buff, 2);
+ CHECK_EQ(ret, 1, "ret");
+ CHECK_EQ(rbuf_bytes_available(buff), 3, "size_avail");
+ CHECK_EQ(rbuf_bytes_free(buff), 7, "size_free");
+ CHECK_EQ(buff->head, buff->data + 5, "head_ptr");
+ CHECK_EQ(buff->tail, buff->data + 2, "tail_ptr");
+
+ subtest_no++;
+ ret = rbuf_bump_tail_noopt(buff, 3);
+ CHECK_EQ(ret, 1, "ret");
+ CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail");
+ CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free");
+ CHECK_EQ(buff->head, buff->data + 5, "head_ptr");
+ CHECK_EQ(buff->tail, buff->data + 5, "tail_ptr");
+
+ subtest_no++;
+ ret = rbuf_bump_tail_noopt(buff, 1);
+ CHECK_EQ(ret, 0, "ret");
+ CHECK_EQ(rbuf_bytes_available(buff), 0, "size_avail");
+ CHECK_EQ(rbuf_bytes_free(buff), 10, "size_free");
+ CHECK_EQ(buff->head, buff->data + 5, "head_ptr");
+ CHECK_EQ(buff->tail, buff->data + 5, "tail_ptr");
+
+ subtest_no++;
+ ret = rbuf_bump_head(buff, 7);
+ CHECK_EQ(ret, 1, "ret");
+ CHECK_EQ(rbuf_bytes_available(buff), 7, "size_avail");
+ CHECK_EQ(rbuf_bytes_free(buff), 3, "size_free");
+ CHECK_EQ(buff->head, buff->data + 2, "head_ptr");
+ CHECK_EQ(buff->tail, buff->data + 5, "tail_ptr");
+
+ subtest_no++;
+ ret = rbuf_bump_tail_noopt(buff, 5);
+ CHECK_EQ(ret, 1, "ret");
+ CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail");
+ CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free");
+ CHECK_EQ(buff->head, buff->data + 2, "head_ptr");
+ CHECK_EQ(buff->tail, buff->data, "tail_ptr");
+
+ // check tail can't overrun head
+ subtest_no++;
+ ret = rbuf_bump_tail_noopt(buff, 3);
+ CHECK_EQ(ret, 0, "ret");
+ CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail");
+ CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free");
+ CHECK_EQ(buff->head, buff->data + 2, "head_ptr");
+ CHECK_EQ(buff->tail, buff->data, "tail_ptr");
+
+ // check head can't overrun tail
+ subtest_no++;
+ ret = rbuf_bump_head(buff, 9);
+ CHECK_EQ(ret, 0, "ret");
+ CHECK_EQ(rbuf_bytes_available(buff), 2, "size_avail");
+ CHECK_EQ(rbuf_bytes_free(buff), 8, "size_free");
+ CHECK_EQ(buff->head, buff->data + 2, "head_ptr");
+ CHECK_EQ(buff->tail, buff->data, "tail_ptr");
+
+ // check head can fill the buffer
+ subtest_no++;
+ ret = rbuf_bump_head(buff, 8);
+ CHECK_EQ(ret, 1, "ret");
+ CHECK_EQ(rbuf_bytes_available(buff), 10, "size_avail");
+ CHECK_EQ(rbuf_bytes_free(buff), 0, "size_free");
+ CHECK_EQ(buff->head, buff->data, "head_ptr");
+ CHECK_EQ(buff->tail, buff->data, "tail_ptr");