/* * 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) #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ /** * 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); #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* USURPATION_PROTOCOL_H_INCLUDED */