summaryrefslogtreecommitdiffstats
path: root/src/common/tlv.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/tlv.c')
-rwxr-xr-xsrc/common/tlv.c209
1 files changed, 89 insertions, 120 deletions
diff --git a/src/common/tlv.c b/src/common/tlv.c
index 72d0399..bf8a99c 100755
--- a/src/common/tlv.c
+++ b/src/common/tlv.c
@@ -1,7 +1,8 @@
/*
- * Usurpataion --- clinet-server protocol implementation.
+ * Usurpation – clinet-server protocol implementation.
*
* Copyright (C) 2019 Ramūnas Mažeikis
+ * Copyright (C) 2019 Gediminas Jakutis
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -28,7 +29,6 @@
#include <string.h>
#include <time.h>
#include "tlv.h"
-#include "net.h"
#include "utils.h"
#ifdef unix
@@ -37,156 +37,125 @@
#include <lwip/def.h>
#endif
-struct tlv_header {
- enum tlv_type type;
- uint16_t size;
-};
-
-/**
- * Returns tlv_size from packet
- */
-uint16_t tlv_size(char *buf);
-
-/**
- * Returns tlv_type from packet.
- */
-enum tlv_type tlv_get_type(char *buf);
-
-/* Changes to be made:
- * * Trust tlv size from raw data
- * * Don't fail on 0 length. In that case data points to NULL
- * * tlv_parser should be opaque.
- * * Make a constructor that takes a user-supplied buffer.
- */
-int tlv_get(struct tlv_parser *parser, struct tlv *ret)
+int tlv_get(char *in, struct tlv *tlv, char **saveptr)
{
- int retval = 0;
+ struct tlv_header head;
+ int ret = A_OK;
- size_t packet_size;
- size_t final_size;
- struct tlv *crr_tlv = parser->data + parser->offset;
+ memcpy(&head, in, sizeof(head));
+ head = ntoh_tlvh(&head);
- packet_size = tlv_size(parser->data);
- final_size = parser->offset + crr_tlv->length + sizeof(struct tlv_header);
- if (final_size >= packet_size) {
- return retval = E_TLV_OVERFLOW;
- } else {
- if (crr_tlv->length != 0) {
- ret->data = parser->data + parser->offset + sizeof(struct tlv_header);
- } else {
- ret->data = NULL;
- }
- ret->type = crr_tlv->type;
- ret->length = crr_tlv->length;
- parser->offset += sizeof(struct tlv_header) + ret->length;
- if (final_size == packet_size) {
- retval = END_OF_PACKET;
- }
+ if (head.type == INVALID || !head.size) {
+ ret = NONEWDATA;
+ goto out;
}
- return retval;
+ tlv->head = head;
+ tlv->data = in + sizeof(head);
+ if (saveptr) {
+ *saveptr = in + sizeof(head) + head.size;
+ }
+out:
+ return ret;
}
-int tlv_parser_init(struct tlv_parser *parser, char *buf, struct tlv *ret)
+struct tlv_header ntoh_tlvh(const struct tlv_header * const in)
{
- /* Data points to the beggining of the buffer for size and
- * type acquisition purposes.
- * */
- struct tlv_header *data = buf;
- /* It is known that the first tlv will be of the meta kind.
- * We can safely skip the header.
- * */
- parser->data = buf + sizeof(struct tlv_header);
- ret->type = READ_ENUM(data->type);
- ret->length = ntohs(data->size);
-}
+ struct tlv_header ret;
-uint16_t tlv_size(char *buf)
-{
- struct tlv_header *data = buf;
- return ntohs(data->size);
+ ret.type = ntohl(in->type);
+ ret.size = ntohl(in->size);
+
+ return ret;
}
-enum tlv_type tlv_get_type(char *buf)
+struct tlv_header hton_tlvh(const struct tlv_header * const in)
{
- struct tlv_header *data = buf;
- return READ_ENUM(data->type);
+ struct tlv_header ret;
+
+ ret.type = htonl(in->type);
+ ret.size = htonl(in->size);
+
+ return ret;
}
-size_t tlv_data_size(struct tlv_parser *parser)
+int tlv_pack(struct tlv_packet *pack, struct tlv *tlv)
{
- size_t size;
+ struct tlv_header head;
+ size_t raw_size;
+ int ret = A_OK;
+
+ /* packed tlv loses the pointer, so only take the header part into account */
+ raw_size = sizeof(tlv->head) + tlv->head.size;
- if (parser->offset + sizeof(enum tlv_type) + sizeof(size_t) >= tlv_size(parser)) {
- size = 0;
+ if ((raw_size + pack->cursor + sizeof(tlv->head)) >= TLV_SZ_MAX) {
+ ret = ERROR;
} else {
- memcpy(&size, parser->data + parser->offset + sizeof(enum tlv_type), sizeof(size_t));
+ if (pack->size < pack->cursor + raw_size) {
+ pack->data = realloc(pack->data, pack->size + raw_size);
+ pack->size += raw_size;
+ }
+
+ head = tlv->head;
+ head = hton_tlvh(&head);
+ memcpy(pack->data + pack->cursor, &head, sizeof(head));
+ pack->cursor += sizeof(tlv->head);
+ if (tlv->head.size && tlv->data) {
+ memcpy(pack->data + pack->cursor, tlv->data, tlv->head.size);
+ pack->cursor += tlv->head.size;
+ }
}
- return size;
+ return ret;
}
-void tlv_destroy(struct tlv *t)
+int tlv_packet_finalize(struct tlv_packet *pack)
{
- size_t i = 0;
- size_t tlv_count;
- struct tlv *arr;
- switch (t->type)
- {
- case REGURAL:
- case HEARTBEAT:
- case DISCOVERY:
- tlv_count = t->length / sizeof(struct tlv);
- arr = t->data;
- for (i = 0; i < tlv_count; i++) {
- tlv_destroy(&arr[i]);
- }
- default:
- free(t->data);
- t->length = 0;
- break;
- }
+ struct tlv terminator;
+ int ret = A_OK;
+
+ terminator = tlv_none;
+
+ tlv_pack(pack, &terminator);
+
+ return ret;
}
-size_t tlv_raw_size(const struct tlv *t)
+struct tlv *tlv_init(struct tlv *in, enum tlv_type type)
{
- return sizeof(*t) + t->length;
+ in->head.type = type;
+ in->head.size = 0;
+ in->data = NULL;
+
+ return in;
}
-int tlv_push_data(struct tlv *t, const char *data, uint16_t size)
+void tlv_destroy(struct tlv *in)
{
- int ret = 0;
- size_t final_size = tlv_raw_size(t) + size;
- if (final_size > TLV_SZ_MAX_RAW) {
- ret = E_TLV_OVERFLOW;
- } else {
- t->data = realloc(t->data, final_size);
- memcpy(t->data + t->length, data, size);
- t->length = final_size;
- }
- return ret;
+ free(in->data);
+ *in = tlv_none;
}
-void tlv_init(struct tlv *t, enum tlv_type type)
+struct tlv_packet *tlv_packet_init(struct tlv_packet *in)
{
- t->type = type;
- t->length = 0;
- t->data = NULL;
+ in->size = 0;
+ in->cursor = 0;
+ in->data = NULL;
+
+ return in;
}
-int tlv_push_tlv(struct tlv *t, const struct tlv *other)
+struct tlv_packet *tlv_packet_reset(struct tlv_packet *in)
{
- int ret = 0;
- size_t other_size;
- size_t final_size;
-
- other_size = tlv_raw_size(other);
- final_size = tlv_raw_size(t) + other_size;
- if (final_size > TLV_SZ_MAX_RAW) {
- ret = E_TLV_OVERFLOW;
- } else {
- tlv_get_raw(other, t->data + t->length);
- t->length = final_size;
- }
+ memset(in->data, 0, in->cursor);
+ in->cursor = 0;
- return ret;
+ return in;
+}
+
+void tlv_packet_destroy(struct tlv_packet *in)
+{
+ free(in->data);
+ in->size = 0;
+ in->cursor = 0;
+ in->data = NULL;
}