summaryrefslogtreecommitdiffstats
path: root/src/tinyframe
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2022-01-14 15:08:02 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2022-01-14 15:08:02 +0000
commit8d76eb12d5223d0fc3ea65d8d97f1feda2fcc340 (patch)
tree0fd0dd005a08843d538923c1a31d968a417dc4bf /src/tinyframe
parentInitial commit. (diff)
downloadtinyframe-8d76eb12d5223d0fc3ea65d8d97f1feda2fcc340.tar.xz
tinyframe-8d76eb12d5223d0fc3ea65d8d97f1feda2fcc340.zip
Adding upstream version 0.1.1.upstream/0.1.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--src/tinyframe.c403
-rw-r--r--src/tinyframe/tinyframe.h145
-rw-r--r--src/tinyframe/version.h.in31
3 files changed, 579 insertions, 0 deletions
diff --git a/src/tinyframe.c b/src/tinyframe.c
new file mode 100644
index 0000000..3615b59
--- /dev/null
+++ b/src/tinyframe.c
@@ -0,0 +1,403 @@
+/*
+ * Author Jerry Lundström <jerry@dns-oarc.net>
+ * Copyright (c) 2020, OARC, Inc.
+ * All rights reserved.
+ *
+ * This file is part of the tinyframe library.
+ *
+ * tinyframe library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * tinyframe library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with tinyframe library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "tinyframe/tinyframe.h"
+
+#include <string.h>
+#ifdef HAVE_ENDIAN_H
+#include <endian.h>
+#else
+#ifdef HAVE_SYS_ENDIAN_H
+#include <sys/endian.h>
+#else
+#ifdef HAVE_MACHINE_ENDIAN_H
+#include <machine/endian.h>
+#endif
+#endif
+#endif
+#include <assert.h>
+#ifdef TINYFRAME_TRACE
+#include <stdio.h>
+#include <ctype.h>
+static const char* printable_string(const uint8_t* data, size_t len)
+{
+ static char buf[512], hex;
+ size_t r = 0, w = 0;
+
+ while (r < len && w < sizeof(buf) - 1) {
+ if (isprint(data[r])) {
+ buf[w++] = data[r++];
+ } else {
+ if (w + 4 >= sizeof(buf) - 1) {
+ break;
+ }
+
+ buf[w++] = '\\';
+ buf[w++] = 'x';
+ hex = (data[r] & 0xf0) >> 4;
+ if (hex > 9) {
+ buf[w++] = 'a' + (hex - 10);
+ } else {
+ buf[w++] = '0' + hex;
+ }
+ hex = data[r++] & 0xf;
+ if (hex > 9) {
+ buf[w++] = 'a' + (hex - 10);
+ } else {
+ buf[w++] = '0' + hex;
+ }
+ }
+ }
+ if (w >= sizeof(buf)) {
+ buf[sizeof(buf) - 1] = 0;
+ } else {
+ buf[w] = 0;
+ }
+
+ return buf;
+}
+#define trace(x...) \
+ fprintf(stderr, "tinyframe %s(): ", __func__); \
+ fprintf(stderr, x); \
+ fprintf(stderr, "\n"); \
+ fflush(stderr);
+#else
+#define trace(x...)
+#define printable_string(x...)
+#endif
+
+const char* const tinyframe_state_string[] = {
+ "control",
+ "control_field",
+ "frame",
+ "done",
+};
+
+const char* const tinyframe_result_string[] = {
+ "ok",
+ "error",
+ "have_control",
+ "have_control_field",
+ "have_frame",
+ "stopped",
+ "finished",
+ "need_more",
+};
+
+static inline uint32_t _need32(const void* ptr)
+{
+ uint32_t v;
+ memcpy(&v, ptr, sizeof(v));
+ return be32toh(v);
+}
+
+static inline void _put32(void* ptr, uint32_t v)
+{
+ uint32_t be_v = htobe32(v);
+ memcpy(ptr, &be_v, sizeof(be_v));
+}
+
+static inline enum tinyframe_result __read_control(struct tinyframe_reader* handle, const uint8_t* data, size_t len)
+{
+ if (len < 12) {
+ trace("data len %zu < 12, need more", len);
+ return tinyframe_need_more;
+ }
+ handle->control.length = _need32(data); // "escape"
+ if (handle->control.length) {
+ trace("control length !zero, error, header: %s", printable_string(data, 12));
+ return tinyframe_error;
+ }
+ handle->control.length = _need32(data + 4); // length
+ if (handle->control.length > TINYFRAME_CONTROL_FRAME_LENGTH_MAX) {
+ trace("control length > max, error, header: %s", printable_string(data, 12));
+ return tinyframe_error;
+ }
+ handle->control.type = _need32(data + 8); // type
+
+ switch (handle->control.type) {
+ case TINYFRAME_CONTROL_ACCEPT:
+ case TINYFRAME_CONTROL_START:
+ case TINYFRAME_CONTROL_READY:
+ break;
+ case TINYFRAME_CONTROL_STOP:
+ handle->state = tinyframe_done;
+ handle->bytes_read = 12;
+ return tinyframe_stopped;
+ case TINYFRAME_CONTROL_FINISH:
+ handle->state = tinyframe_done;
+ handle->bytes_read = 12;
+ return tinyframe_finished;
+ default:
+ trace("control type %d invalid, error", handle->control.type);
+ return tinyframe_error;
+ }
+
+ // "escape" and length are not included in length, if not just type
+ // then we have control fields
+ if (handle->control.length > 4) {
+ handle->state = tinyframe_control_field;
+ handle->control_length = handle->control.length - 4; // - type length
+ handle->control_length_left = handle->control_length;
+ trace("control %d len %zu, next fields", handle->control.type, handle->control_length);
+ } else {
+ handle->state = tinyframe_frame;
+ trace("control %d len %zu, next frame", handle->control.type, handle->control_length);
+ }
+
+ handle->bytes_read = 12;
+ return tinyframe_have_control;
+}
+
+enum tinyframe_result tinyframe_read(struct tinyframe_reader* handle, const uint8_t* data, size_t len)
+{
+ assert(handle);
+ assert(data);
+
+ switch (handle->state) {
+ case tinyframe_control:
+ return __read_control(handle, data, len);
+
+ case tinyframe_control_field:
+ if (len < 8) {
+ trace("data len %zu < 8 for control field, need more", len);
+ return tinyframe_need_more;
+ }
+ handle->control_field.type = _need32(data);
+ switch (handle->control_field.type) {
+ case TINYFRAME_CONTROL_FIELD_CONTENT_TYPE:
+ break;
+ default:
+ trace("control field type %d invalid, error", handle->control_field.type);
+ return tinyframe_error;
+ }
+
+ handle->control_field.length = _need32(data + 4);
+ if (handle->control_field.length > TINYFRAME_CONTROL_FIELD_CONTENT_TYPE_LENGTH_MAX) {
+ trace("control field length > max, error");
+ return tinyframe_error;
+ }
+ if (len - 8 < handle->control_field.length) {
+ trace("data len %zu < control field length, need more", len - 8);
+ return tinyframe_need_more;
+ }
+
+ // did we over read control frame length?
+ if (handle->control_length_left < handle->control_field.length + 8) {
+ trace("control field goes beyond control, error");
+ return tinyframe_error;
+ }
+ handle->control_length_left -= handle->control_field.length + 8;
+ if (!handle->control_length_left) {
+ trace("no control fields left, next frame");
+ handle->state = tinyframe_frame;
+ }
+
+ handle->control_field.data = data + 8;
+ handle->bytes_read = 8 + handle->control_field.length;
+ trace("control field %d, data: %s", handle->control_field.type, printable_string(handle->control_field.data, handle->control_field.length));
+ return tinyframe_have_control_field;
+
+ case tinyframe_frame:
+ if (len < 4) {
+ trace("data len %zu < 4 for frame, need more", len);
+ return tinyframe_need_more;
+ }
+ handle->frame.length = _need32(data);
+ if (!handle->frame.length) {
+ handle->state = tinyframe_control;
+ return __read_control(handle, data, len);
+ }
+
+ if (len - 4 < handle->frame.length) {
+ trace("data len %zu < frame length, need more", len - 4);
+ return tinyframe_need_more;
+ }
+
+ handle->frame.data = data + 4;
+ handle->bytes_read = 4 + handle->frame.length;
+ trace("frame data [%zu]: %s...", handle->bytes_read, printable_string(data, handle->bytes_read > 20 ? 20 : handle->bytes_read));
+ return tinyframe_have_frame;
+
+ case tinyframe_done:
+ break;
+ }
+
+ return tinyframe_error;
+}
+
+enum tinyframe_result tinyframe_write_control(struct tinyframe_writer* handle, uint8_t* out, size_t len, uint32_t type, const struct tinyframe_control_field* fields, size_t num_fields)
+{
+ size_t out_len = 12;
+ size_t n;
+ uint8_t* outp;
+
+ assert(handle);
+ assert(out);
+ assert(!num_fields || (num_fields && fields));
+
+ for (n = 0; n < num_fields; n++) {
+ switch (fields[n].type) {
+ case TINYFRAME_CONTROL_FIELD_CONTENT_TYPE:
+ break;
+ default:
+ trace("field %zu type %d invalid, error", n, fields[n].type);
+ return tinyframe_error;
+ }
+ if (fields[n].length > TINYFRAME_CONTROL_FIELD_CONTENT_TYPE_LENGTH_MAX) {
+ trace("field %zu length > max, error", n);
+ return tinyframe_error;
+ }
+ out_len += 8 + fields[n].length;
+ }
+
+ if (len < out_len) {
+ trace("not enought space, need more");
+ return tinyframe_need_more;
+ }
+
+ _put32(out, 0); // "escape"
+ _put32(out + 4, out_len - 8); // length
+ // - 8 is because "escape" and length is not included in length
+ _put32(out + 8, type); // type
+
+ outp = out + 12;
+ for (n = 0; n < num_fields; n++) {
+ _put32(outp, fields[n].type);
+ _put32(outp + 4, fields[n].length);
+ if (fields[n].length) {
+ assert(fields[n].data);
+ memcpy(outp + 8, fields[n].data, fields[n].length);
+ }
+ outp += 8 + fields[n].length;
+ }
+
+ handle->bytes_wrote = out_len;
+ trace("control %u data: %s", type, printable_string(out, handle->bytes_wrote));
+ return tinyframe_ok;
+}
+
+enum tinyframe_result tinyframe_write_control_start(struct tinyframe_writer* handle, uint8_t* out, size_t len, const char* content_type, size_t content_type_len)
+{
+ assert(handle);
+ assert(out);
+ assert(content_type);
+
+ if (content_type_len > TINYFRAME_CONTROL_FIELD_CONTENT_TYPE_LENGTH_MAX) {
+ trace("field length > max, error");
+ return tinyframe_error;
+ }
+ if (len < 12 + 8 + content_type_len) {
+ trace("not enought space, need more");
+ return tinyframe_need_more;
+ }
+
+ _put32(out, 0); // "escape"
+ _put32(out + 4, 12 + 8 + content_type_len - 8); // length
+ // - 8 is because "escape" and length is not included in length
+ _put32(out + 8, TINYFRAME_CONTROL_START); // type
+ _put32(out + 12, TINYFRAME_CONTROL_FIELD_CONTENT_TYPE); // field type
+ _put32(out + 16, content_type_len); // field length
+ memcpy(out + 20, content_type, content_type_len); // field data
+
+ handle->bytes_wrote = 12 + 8 + content_type_len;
+ trace("control start data: %s", printable_string(out, handle->bytes_wrote));
+ return tinyframe_ok;
+}
+
+enum tinyframe_result tinyframe_write_frame(struct tinyframe_writer* handle, uint8_t* out, size_t len, const uint8_t* data, uint32_t data_len)
+{
+ assert(handle);
+ assert(out);
+ assert(data);
+
+ if (len < 4 + data_len) {
+ trace("not enought space, need more");
+ return tinyframe_need_more;
+ }
+
+ _put32(out, data_len); // length
+ memcpy(out + 4, data, data_len); // frame
+
+ handle->bytes_wrote = 4 + data_len;
+ trace("frame data: %s...", printable_string(out, handle->bytes_wrote > 20 ? 20 : handle->bytes_wrote));
+ return tinyframe_ok;
+}
+
+enum tinyframe_result tinyframe_write_control_stop(struct tinyframe_writer* handle, uint8_t* out, size_t len)
+{
+ assert(handle);
+ assert(out);
+
+ if (len < 12) {
+ trace("not enought space, need more");
+ return tinyframe_need_more;
+ }
+
+ _put32(out, 0); // "escape"
+ _put32(out + 4, 12 - 8); // length
+ // - 8 is because "escape" and length is not included in length
+ _put32(out + 8, TINYFRAME_CONTROL_STOP); // type
+
+ handle->bytes_wrote = 12;
+ trace("control stop data: %s", printable_string(out, handle->bytes_wrote));
+ return tinyframe_ok;
+}
+
+void tinyframe_set_header(uint8_t* frame, uint32_t frame_length)
+{
+ assert(frame);
+
+ _put32(frame, frame_length);
+}
+
+/*
+
+frame:
+- 32 length (if zero == control frame)
+- data
+
+control frame:
+- 32 bit "escape" (always zero)
+- 32 bit frame length
+- 32 bit control type
+
+control field: FSTRM_CONTROL_FIELD_CONTENT_TYPE:
+- 32 bit field type == FSTRM_CONTROL_FIELD_CONTENT_TYPE
+- 32 bit content type length
+- content type
+
+control start frame:
+- <control frame>
+- <control field: FSTRM_CONTROL_FIELD_CONTENT_TYPE>
+
+control accept & ready frame:
+- <control frame>
+- <control field: FSTRM_CONTROL_FIELD_CONTENT_TYPE>
+ ...
+ (additional control fields)
+
+control stop & finish:
+ nothing more
+
+*/
diff --git a/src/tinyframe/tinyframe.h b/src/tinyframe/tinyframe.h
new file mode 100644
index 0000000..e16806d
--- /dev/null
+++ b/src/tinyframe/tinyframe.h
@@ -0,0 +1,145 @@
+/*
+ * Author Jerry Lundström <jerry@dns-oarc.net>
+ * Copyright (c) 2020, OARC, Inc.
+ * All rights reserved.
+ *
+ * This file is part of the tinyframe library.
+ *
+ * tinyframe library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * tinyframe library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with tinyframe library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <tinyframe/version.h>
+
+#include <unistd.h>
+#include <stdint.h>
+
+#ifndef __tinyframe_h_tinyframe
+#define __tinyframe_h_tinyframe 1
+
+#define TINYFRAME_CONTROL_FRAME_LENGTH_MAX 512
+#define TINYFRAME_CONTROL_FIELD_CONTENT_TYPE_LENGTH_MAX 256
+
+#define TINYFRAME_CONTROL_ACCEPT 0x01
+#define TINYFRAME_CONTROL_START 0x02
+#define TINYFRAME_CONTROL_STOP 0x03
+#define TINYFRAME_CONTROL_READY 0x04
+#define TINYFRAME_CONTROL_FINISH 0x05
+
+#define TINYFRAME_CONTROL_FIELD_CONTENT_TYPE 0x01
+
+struct tinyframe_control {
+ uint32_t length;
+ uint32_t type;
+};
+
+#define TINYFRAME_CONTROL_INITIALIZER \
+ { \
+ .length = 0, \
+ .type = 0, \
+ }
+
+struct tinyframe_control_field {
+ uint32_t type;
+ uint32_t length;
+ const uint8_t* data;
+};
+
+#define TINYFRAME_CONTROL_FIELD_INITIALIZER \
+ { \
+ .type = 0, \
+ .length = 0, \
+ .data = 0, \
+ }
+
+struct tinyframe {
+ uint32_t length;
+ const uint8_t* data;
+};
+
+#define TINYFRAME_INITIALIZER \
+ { \
+ .length = 0, \
+ .data = 0, \
+ }
+
+#define TINYFRAME_HEADER_SIZE sizeof(uint32_t)
+
+enum tinyframe_state {
+ tinyframe_control,
+ tinyframe_control_field,
+ tinyframe_frame,
+ tinyframe_done,
+};
+extern const char* const tinyframe_state_string[];
+
+struct tinyframe_reader {
+ enum tinyframe_state state;
+
+ size_t control_length, control_length_left;
+
+ struct tinyframe_control control;
+ struct tinyframe_control_field control_field;
+ struct tinyframe frame;
+
+ size_t bytes_read;
+};
+
+#define TINYFRAME_READER_INITIALIZER \
+ { \
+ .state = tinyframe_control, \
+ .control_length = 0, \
+ .control_length_left = 0, \
+ .control = TINYFRAME_CONTROL_INITIALIZER, \
+ .control_field = TINYFRAME_CONTROL_FIELD_INITIALIZER, \
+ .frame = TINYFRAME_INITIALIZER, \
+ .bytes_read = 0, \
+ }
+
+struct tinyframe_writer {
+ size_t bytes_wrote;
+};
+
+#define TINYFRAME_WRITER_INITIALIZER \
+ { \
+ .bytes_wrote = 0, \
+ }
+
+enum tinyframe_result {
+ tinyframe_ok = 0,
+ tinyframe_error = 1,
+ tinyframe_have_control = 2,
+ tinyframe_have_control_field = 3,
+ tinyframe_have_frame = 4,
+ tinyframe_stopped = 5,
+ tinyframe_finished = 6,
+ tinyframe_need_more = 7,
+};
+extern const char* const tinyframe_result_string[];
+
+enum tinyframe_result tinyframe_read(struct tinyframe_reader*, const uint8_t*, size_t);
+
+enum tinyframe_result tinyframe_write_control(struct tinyframe_writer*, uint8_t*, size_t, uint32_t, const struct tinyframe_control_field*, size_t);
+
+enum tinyframe_result tinyframe_write_control_start(struct tinyframe_writer*, uint8_t*, size_t, const char*, size_t);
+enum tinyframe_result tinyframe_write_frame(struct tinyframe_writer*, uint8_t*, size_t, const uint8_t*, uint32_t);
+enum tinyframe_result tinyframe_write_control_stop(struct tinyframe_writer*, uint8_t*, size_t);
+
+void tinyframe_set_header(uint8_t*, uint32_t);
+
+static inline size_t tinyframe_frame_size(size_t data_len)
+{
+ return 4 + data_len;
+}
+
+#endif
diff --git a/src/tinyframe/version.h.in b/src/tinyframe/version.h.in
new file mode 100644
index 0000000..c4357b8
--- /dev/null
+++ b/src/tinyframe/version.h.in
@@ -0,0 +1,31 @@
+/*
+ * Author Jerry Lundström <jerry@dns-oarc.net>
+ * Copyright (c) 2020, OARC, Inc.
+ * All rights reserved.
+ *
+ * This file is part of the tinyframe library.
+ *
+ * tinyframe library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * tinyframe library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with tinyframe library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __tinyframe_h_version
+#define __tinyframe_h_version 1
+
+#define TINYFRAME_VERSION @TINYFRAME_VERSION_MAJOR@@TINYFRAME_VERSION_MINOR@@TINYFRAME_VERSION_PATCH@
+#define TINYFRAME_VERSION_MAJOR @TINYFRAME_VERSION_MAJOR@
+#define TINYFRAME_VERSION_MINOR @TINYFRAME_VERSION_MINOR@
+#define TINYFRAME_VERSION_PATCH @TINYFRAME_VERSION_PATCH@
+#define TINYFRAME_VERSION_STRING "@PACKAGE_VERSION@"
+
+#endif