Adding upstream version 0.1.1.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
4664226545
commit
d3d193d4ac
35 changed files with 2608 additions and 0 deletions
21
src/Makefile.am
Normal file
21
src/Makefile.am
Normal file
|
@ -0,0 +1,21 @@
|
|||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
CLEANFILES = *.gcda *.gcno *.gcov
|
||||
|
||||
EXTRA_DIST =
|
||||
|
||||
SUBDIRS = test
|
||||
|
||||
lib_LTLIBRARIES = libtinyframe.la
|
||||
|
||||
libtinyframe_la_SOURCES = tinyframe.c
|
||||
nobase_include_HEADERS = tinyframe/tinyframe.h
|
||||
nobase_nodist_include_HEADERS = tinyframe/version.h
|
||||
libtinyframe_la_LDFLAGS = -version-info $(TINYFRAME_LIBRARY_VERSION)
|
||||
EXTRA_DIST += tinyframe/version.h.in
|
||||
|
||||
if ENABLE_GCOV
|
||||
gcov-local:
|
||||
for src in $(libtinyframe_la_SOURCES); do \
|
||||
gcov -l -r -s "$(srcdir)" "$$src"; \
|
||||
done
|
||||
endif
|
29
src/test/Makefile.am
Normal file
29
src/test/Makefile.am
Normal file
|
@ -0,0 +1,29 @@
|
|||
MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
|
||||
|
||||
CLEANFILES = test*.log test*.trs test2.fstrm *.gcda *.gcno *.gcov
|
||||
|
||||
AM_CFLAGS = -I$(top_srcdir)/src
|
||||
|
||||
check_PROGRAMS = test1 test2 test3
|
||||
TESTS = test1.sh test2.sh test3.sh
|
||||
EXTRA_DIST = $(TESTS)
|
||||
|
||||
test1_SOURCES = test1.c
|
||||
test1_LDADD = ../libtinyframe.la
|
||||
test1_LDFLAGS = -static
|
||||
EXTRA_DIST += test.fstrm
|
||||
|
||||
test2_SOURCES = test2.c
|
||||
test2_LDADD = ../libtinyframe.la
|
||||
test2_LDFLAGS = -static
|
||||
|
||||
test3_SOURCES = test3.c
|
||||
test3_LDADD = ../libtinyframe.la
|
||||
test3_LDFLAGS = -static
|
||||
|
||||
if ENABLE_GCOV
|
||||
gcov-local:
|
||||
for src in $(test1_SOURCES) $(test2_SOURCES) $(test3_SOURCES); do \
|
||||
gcov -l -r -s "$(srcdir)" "$$src"; \
|
||||
done
|
||||
endif
|
BIN
src/test/test.fstrm
Normal file
BIN
src/test/test.fstrm
Normal file
Binary file not shown.
125
src/test/test1.c
Normal file
125
src/test/test1.c
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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/tinyframe.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static void
|
||||
print_string(const void* data, size_t len)
|
||||
{
|
||||
uint8_t* str = (uint8_t*)data;
|
||||
putc('"', stdout);
|
||||
while (len-- != 0) {
|
||||
unsigned c = *(str++);
|
||||
if (isprint(c)) {
|
||||
if (c == '"')
|
||||
puts("\\\"");
|
||||
else
|
||||
putc(c, stdout);
|
||||
} else {
|
||||
printf("\\x%02x", c);
|
||||
}
|
||||
}
|
||||
putc('"', stdout);
|
||||
}
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc < 3) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE* fp = fopen(argv[1], "r");
|
||||
if (!fp) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
int rbuf_len = atoi(argv[2]);
|
||||
|
||||
struct tinyframe_reader h = TINYFRAME_READER_INITIALIZER;
|
||||
|
||||
size_t s = 0, r;
|
||||
uint8_t buf[4096], rbuf[rbuf_len];
|
||||
while ((r = fread(rbuf, 1, sizeof(rbuf), fp)) > 0) {
|
||||
printf("read %zu\n", r);
|
||||
|
||||
if (s + r > sizeof(buf)) {
|
||||
printf("overflow\n");
|
||||
break;
|
||||
}
|
||||
memcpy(&buf[s], rbuf, r);
|
||||
s += r;
|
||||
|
||||
int r = 1;
|
||||
while (r) {
|
||||
switch (tinyframe_read(&h, buf, s)) {
|
||||
case tinyframe_have_control:
|
||||
printf("control type %" PRIu32 " len %" PRIu32 "\n", h.control.type, h.control.length);
|
||||
break;
|
||||
case tinyframe_have_control_field:
|
||||
printf("control_field type %" PRIu32 " len %" PRIu32 " data: ", h.control_field.type, h.control_field.length);
|
||||
print_string(h.control_field.data, h.control_field.length);
|
||||
printf("\n");
|
||||
break;
|
||||
case tinyframe_have_frame:
|
||||
printf("frame len %" PRIu32 " data: ", h.frame.length);
|
||||
print_string(h.frame.data, h.frame.length);
|
||||
printf("\n");
|
||||
break;
|
||||
case tinyframe_need_more:
|
||||
printf("need more\n");
|
||||
r = 0;
|
||||
break;
|
||||
case tinyframe_error:
|
||||
printf("error\n");
|
||||
fclose(fp);
|
||||
return 2;
|
||||
case tinyframe_stopped:
|
||||
printf("stopped\n");
|
||||
fclose(fp);
|
||||
return 0;
|
||||
case tinyframe_finished:
|
||||
printf("finished\n");
|
||||
fclose(fp);
|
||||
return 0;
|
||||
default:
|
||||
printf("unexpected return code\n");
|
||||
fclose(fp);
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (r && h.bytes_read && h.bytes_read <= s) {
|
||||
s -= h.bytes_read;
|
||||
if (s) {
|
||||
memmove(buf, &buf[h.bytes_read], s);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
8
src/test/test1.sh
Executable file
8
src/test/test1.sh
Executable file
|
@ -0,0 +1,8 @@
|
|||
#!/bin/sh -xe
|
||||
|
||||
./test1 "$srcdir/test.fstrm" 7
|
||||
./test1 "$srcdir/test.fstrm" 15
|
||||
./test1 "$srcdir/test.fstrm" 24
|
||||
./test1 "$srcdir/test.fstrm" 44
|
||||
./test1 "$srcdir/test.fstrm" 79
|
||||
./test1 "$srcdir/test.fstrm" 134
|
141
src/test/test2.c
Normal file
141
src/test/test2.c
Normal file
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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/tinyframe.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static char content_type[] = "tinyframe.test";
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
if (argc < 3) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (argv[1][0] == 'w') {
|
||||
FILE* fp = fopen(argv[2], "w");
|
||||
if (!fp) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct tinyframe_writer writer = TINYFRAME_WRITER_INITIALIZER;
|
||||
|
||||
uint8_t out[sizeof(content_type) + (TINYFRAME_CONTROL_FRAME_LENGTH_MAX * 3)];
|
||||
size_t len = sizeof(out);
|
||||
size_t wrote = 0;
|
||||
|
||||
if (tinyframe_write_control_start(&writer, &out[wrote], len, content_type, sizeof(content_type) - 1) != tinyframe_ok) {
|
||||
return 1;
|
||||
}
|
||||
wrote += writer.bytes_wrote;
|
||||
len -= writer.bytes_wrote;
|
||||
|
||||
if (tinyframe_write_frame(&writer, &out[wrote], len, (uint8_t*)content_type, sizeof(content_type)) != tinyframe_ok) {
|
||||
return 1;
|
||||
}
|
||||
wrote += writer.bytes_wrote;
|
||||
len -= writer.bytes_wrote;
|
||||
|
||||
if (tinyframe_write_control_stop(&writer, &out[wrote], len) != tinyframe_ok) {
|
||||
return 1;
|
||||
}
|
||||
wrote += writer.bytes_wrote;
|
||||
len -= writer.bytes_wrote;
|
||||
|
||||
if (fwrite(out, 1, wrote, fp) != wrote) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
} else if (argv[1][0] == 'r') {
|
||||
FILE* fp = fopen(argv[2], "r");
|
||||
if (!fp) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
long content_length;
|
||||
|
||||
if (fseek(fp, 0, SEEK_END)) {
|
||||
return 1;
|
||||
}
|
||||
content_length = ftell(fp);
|
||||
if (fseek(fp, 0, SEEK_SET)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t* content = malloc(content_length);
|
||||
if (!content) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fread(content, 1, content_length, fp) != content_length) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
struct tinyframe_reader reader = TINYFRAME_READER_INITIALIZER;
|
||||
uint8_t* decoding = content;
|
||||
size_t left = content_length;
|
||||
|
||||
if (tinyframe_read(&reader, decoding, left) != tinyframe_have_control
|
||||
|| reader.control.type != TINYFRAME_CONTROL_START) {
|
||||
return 1;
|
||||
}
|
||||
decoding += reader.bytes_read;
|
||||
left -= reader.bytes_read;
|
||||
|
||||
if (tinyframe_read(&reader, decoding, left) != tinyframe_have_control_field
|
||||
|| reader.control_field.type != TINYFRAME_CONTROL_FIELD_CONTENT_TYPE
|
||||
|| strncmp(content_type, (const char*)reader.control_field.data, reader.control_field.length)) {
|
||||
return 1;
|
||||
}
|
||||
decoding += reader.bytes_read;
|
||||
left -= reader.bytes_read;
|
||||
|
||||
while (1) {
|
||||
switch (tinyframe_read(&reader, decoding, left)) {
|
||||
case tinyframe_have_frame: {
|
||||
if (strncmp(content_type, (char*)reader.frame.data, reader.frame.length)) {
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case tinyframe_stopped:
|
||||
case tinyframe_finished:
|
||||
return 0;
|
||||
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
|
||||
decoding += reader.bytes_read;
|
||||
left -= reader.bytes_read;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
4
src/test/test2.sh
Executable file
4
src/test/test2.sh
Executable file
|
@ -0,0 +1,4 @@
|
|||
#!/bin/sh -xe
|
||||
|
||||
./test2 w test2.fstrm
|
||||
./test2 r test2.fstrm
|
93
src/test/test3.c
Normal file
93
src/test/test3.c
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* 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 <assert.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
|
||||
|
||||
static inline uint32_t _need32(const void* ptr)
|
||||
{
|
||||
uint32_t v;
|
||||
memcpy(&v, ptr, sizeof(v));
|
||||
return be32toh(v);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
assert(tinyframe_frame_size(0) == 4);
|
||||
|
||||
struct tinyframe_writer writer = TINYFRAME_WRITER_INITIALIZER;
|
||||
static struct tinyframe_control_field _content_type = {
|
||||
TINYFRAME_CONTROL_FIELD_CONTENT_TYPE,
|
||||
4,
|
||||
(uint8_t*)"test",
|
||||
};
|
||||
uint8_t out[64];
|
||||
|
||||
// correct control
|
||||
assert(tinyframe_write_control(&writer, out, sizeof(out), TINYFRAME_CONTROL_READY, 0, 0) == tinyframe_ok);
|
||||
assert(tinyframe_write_control(&writer, out, sizeof(out), TINYFRAME_CONTROL_READY, &_content_type, 1) == tinyframe_ok);
|
||||
|
||||
// wrong control field type
|
||||
_content_type.type = 0;
|
||||
assert(tinyframe_write_control(&writer, out, sizeof(out), TINYFRAME_CONTROL_READY, &_content_type, 1) == tinyframe_error);
|
||||
_content_type.type = TINYFRAME_CONTROL_FIELD_CONTENT_TYPE;
|
||||
|
||||
// too large control field
|
||||
_content_type.length = TINYFRAME_CONTROL_FIELD_CONTENT_TYPE_LENGTH_MAX + 1;
|
||||
assert(tinyframe_write_control(&writer, out, sizeof(out), TINYFRAME_CONTROL_READY, &_content_type, 1) == tinyframe_error);
|
||||
_content_type.length = 4;
|
||||
|
||||
// too small buffer
|
||||
assert(tinyframe_write_control(&writer, out, 1, TINYFRAME_CONTROL_READY, &_content_type, 1) == tinyframe_need_more);
|
||||
|
||||
// too large control field
|
||||
assert(tinyframe_write_control_start(&writer, out, sizeof(out), "test", TINYFRAME_CONTROL_FIELD_CONTENT_TYPE_LENGTH_MAX + 1) == tinyframe_error);
|
||||
|
||||
// too small buffer
|
||||
assert(tinyframe_write_control_start(&writer, out, 1, "test", 4) == tinyframe_need_more);
|
||||
|
||||
// too small buffer
|
||||
assert(tinyframe_write_frame(&writer, out, 1, out, 4) == tinyframe_need_more);
|
||||
|
||||
// too small buffer
|
||||
assert(tinyframe_write_control_stop(&writer, out, 1) == tinyframe_need_more);
|
||||
|
||||
// correct
|
||||
tinyframe_set_header(out, 111);
|
||||
assert(_need32(out) == 111);
|
||||
|
||||
return 0;
|
||||
}
|
3
src/test/test3.sh
Executable file
3
src/test/test3.sh
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/sh -xe
|
||||
|
||||
./test3
|
403
src/tinyframe.c
Normal file
403
src/tinyframe.c
Normal file
|
@ -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
|
||||
|
||||
*/
|
145
src/tinyframe/tinyframe.h
Normal file
145
src/tinyframe/tinyframe.h
Normal file
|
@ -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
|
31
src/tinyframe/version.h.in
Normal file
31
src/tinyframe/version.h.in
Normal file
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue