From 743f4857ede9f48def462c1ea2cee8be71356fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ram=C5=ABnas=20Ma=C5=BEeikis?= Date: Wed, 29 May 2019 13:53:50 +0300 Subject: Protocol: renamed some files. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Ramūnas Mažeikis --- include/tlv.h | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 include/tlv.h (limited to 'include/tlv.h') diff --git a/include/tlv.h b/include/tlv.h new file mode 100644 index 0000000..7bfb275 --- /dev/null +++ b/include/tlv.h @@ -0,0 +1,190 @@ +/* + * Usurpataion --- client-server protocol interface. + * + * Copyright (C) 2019 Ramūnas Mažeikis + * + * This program 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; version 2.1 + * of the License. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef USURPATION_PROTOCOL_H_INCLUDED +#define USURPATION_PROTOCOL_H_INCLUDED + +#if 0 + +How do we use this API(?), I hear you say. Well, here is a self-contained +example complete with tedious comments, allocation of buffers and cleanup: + +------------------------------------------------------------------------------- + 1 | void functy_the_function(void) + 2 | { + 3 | struct tlv tlv_packet; /* A packet made of tlv's */ + 4 | struct tlv text; /* Actually useful data */ + 5 | char *packet; /* Raw bytes to be pushed via UDP */ + 6 | size_t packet_size; /* Raw packet size */ + 7 | char message[] = "Get jacked!"; /* Duh! */ + 9 | + 10 | tlv_init(&tlv_packet, REGURAL); /* Initialise tlv_packet to regular */ + 11 | tlv_init(&text, TEXT); /* Initialise text packet */ + 12 | tlv_push_data(&text, message, sizeof(message)); /* Push text to appropriate tlv */ + 13 | tlv_push_tlv(&tlv_packet, &text); /* Push the tlv into tlv packet */ + 14 | + 15 | packet_size = tlv_raw_size(&tlv_packet); /* Get raw size required to push entire tlv_packet as bytes */ + 16 | packet = (char *)malloc(packet_size); /* Allocate buffer for outgoing packet */ + 17 | tlv_get_raw(&tlv_packet, packet); /* Flash tlv_packet to buffer */ + 19 | udp_push(packet, packet_size); /* Push packet via UDP */ + 20 | udp_flush(); /* Flush to the other side*/ + 21 | + 22 | tlv_destroy(&tlv_packet); /* Free tlv_packet */ + 23 | free(packet); /* Free packet itself */ + 24 | return; /* GTFO and save stack space */ + 25 | } +------------------------------------------------------------------------------- + +A few things to note: + * Calling tlv_destroy() on a tlv of type REGURAL or HEARTBEAT destorys + all sub-tlv's too. + * Tlv's get copies of data, which means the original buffer can be + freed immediately. + +#endif + + +#include + +#define E_TLV_OVERFLOW (1 << 0) +#define E_UNKNOWN_TYPE (1 << 1) +#define END_OF_PACKET (1 << 2) + +#define TLV_SZ_MAX_RAW (MTU - 64) + +/** + * Message sequence number since beggining of sesssion. + * + * Mainly used for identifying lost messages. + */ +typedef unsigned int msg_idx_t; + +enum tlv_type { + /** + * NULL-terminated string. To be put in a queue to display on the + * screen. + */ + TEXT, + + /** Fixed point. 1 decimal digit of precision. */ + FPI1, + + /** Literally time_t */ + TIMESTAMP, + + /** Represents a request for lost message. Data is unsigned integer + * that uniquely identifies the message. + */ + REQUEST, + + /** + * Response to request. Begins with unsigned integer that represents + * which message is being repeated and the actual null-terminated + * message after that. + */ + REPLY, + + /** + * UUID that represents a particular device. + */ + UUID, + +/* Data of the following types are other tlv's! */ + + /** + * Just a TLV container. + */ + REGURAL, + + /** + * Says "I'm not dead yet.". + */ + HEARTBEAT, + + /** + * Says "Bring out yer dead!". + */ + DISCOVERY +}; + +/** + * Literally type-length-value + * */ +struct tlv { + enum tlv_type type; + size_t length; + void *data; +}; + +/** + * Keeps state of the parsing process. + * + * Related functions return one tlv at a time. + */ +struct tlv_parser { + char *data; + size_t offset; + size_t size; +}; + +/** + * Fills tlv structure to represent the next tlv in the packet. + * + * Returns END_OF_PACKET if all tlv's were read of E_TLV_OVERFLOW, if the last + * tlv, according to its declared size should not fit in a packet. + */ +int tlv_get(struct tlv_parser *parser, struct tlv *ret); + +/** + * Initialises tlv to sane values. + */ +void tlv_init(struct tlv *t, enum tlv_type type); + +/** + * Frees data held in the tlv structure. The structure itself shall be freed as + * needed by calling code. + */ +void tlv_destroy(struct tlv *t); + +/** + * Tells amount of bytes needed to push tlv to a buffer + */ +size_t tlv_raw_size(const struct tlv *t); + +/** + * Pushes tlv to buffer as contiguous data. Check tlv size with tlv_raw_size + * beforehand. If you don't do that and overflow --- tough tiddy. + */ +int tlv_get_raw(struct tlv *t, char *buf); + +/** + * Pushes data to tlv. Returns E_TLV_OVERFLOW if pushing data would cause the + * final size to be greater than TLV_SZ_MAX_RAW. In case of such error the data is left + * untouched. + */ +int tlv_push_data(struct tlv *t, const char *data, size_t size); + +/** + * Pushes a sub-tlv into the packet. 't' can only be REGURAL, HEARTBEAT or + * DISCOVERY. + */ +int tlv_push_tlv(struct tlv *t, const struct tlv *other); + +#endif /* USURPATION_PROTOCOL_H_INCLUDED */ -- cgit v1.2.3