From 30513e7a89cc2f9283458100dea298770c7d18de Mon Sep 17 00:00:00 2001 From: Gediminas Jakutis Date: Fri, 7 Jun 2019 17:13:13 +0300 Subject: refactor server/client discovery to use TLVs. Signed-off-by: Gediminas Jakutis --- src/common/tlv.c | 209 +++++++++++++++++++++++-------------------------------- 1 file changed, 89 insertions(+), 120 deletions(-) (limited to 'src/common') 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 #include #include "tlv.h" -#include "net.h" #include "utils.h" #ifdef unix @@ -37,156 +37,125 @@ #include #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; } -- cgit v1.2.3