diff options
Diffstat (limited to 'src/common/protocol.c')
-rw-r--r-- | src/common/protocol.c | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/src/common/protocol.c b/src/common/protocol.c new file mode 100644 index 0000000..b2e0d40 --- /dev/null +++ b/src/common/protocol.c @@ -0,0 +1,133 @@ +/* + * Usurpataion --- clinet-server protocol implementation. + * + * 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 + */ + +/** + * Common parts of protocol implementation. Handling of anything that actually + * deals with connection descriptor has to be implemented by device and daemon + * separately. + */ + +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "protocol.h" +#include "protocol_private.h" +#include "net.h" +#include "utils.h" + +int push_tlv(struct tlv_packet *packet, enum tlv_type type, char *data) +{ + int ret = 0; + size_t size; + + switch (type) { + case TEXT: + size = strlen(data) + 1; + break; + case FPI1: + size = sizeof(fpi1_t); + break; + case TIMESTAMP: + size = sizeof(time_t); + break; + case REQUEST: + size = sizeof(msg_idx_t); + break; + case REPLY: + size = sizeof(msg_idx_t) + strlen(data + sizeof(msg_idx_t)); + break; + case UUID: + size = sizeof(uuid_t); + break; + default: + ret = E_UNKNOWN_TYPE; + } + ret |= push_tlv_header(packet, type, size); + ret |= push_bytes(packet, data, size); + return ret; +} + +void clear_data(struct tlv_packet *packet) +{ + packet->offset = 0; + packet->type = 0; + memset(packet->data, 0, packet->size); +} + +static int push_bytes(struct tlv_packet *packet, char *data, size_t size) +{ + int ret = 0; + + if (packet->offset + size >= packet->size) { + ret = E_TLV_OVERFLOW; + } else { + memcpy(packet->data + packet->offset, data, size); + packet->offset += size; + } +} + +static int push_tlv_header(struct tlv_packet *packet, enum tlv_type type, size_t size) +{ + int ret = 0; + + if (packet->offset + sizeof(type) + sizeof(size) >= packet->size) { + ret = E_TLV_OVERFLOW; + } else { + memcpy(packet->data + packet->size, type, sizeof(type)); + packet->offset += sizeof(type); + memcpy(packet->data + packet->offset, size, sizeof(size)); + packet->offset += sizeof(size); + } + return ret; +} + +int get_tlv(struct tlv_parser *parser, struct tlv *ret) +{ + int ret = 0; + + if (parser->offset + sizeof(ret->type) + sizeof(ret->length) >= parser->size) { + ret = E_TLV_OVERFLOW; + } else if (parser -> offset == parser->size) { + ret = END_OF_PACKET; + } else { + ret->type = memcpy(&ret->type, parser->data + parser->offset, sizeof(ret->type)); + parser->size += sizeof(ret->type); + ret->length = memcpy(&ret->length, parser->data + parser->offset, sizeof(ret->length)); + parser->offset += sizeof(ret->length); + if (parser->offset + ret->length >= parser->size) { + ret = E_TLV_OVERFLOW; + } else { + memcpy(ret->data, parser->data, ret->length); + } + } + return ret; +} + +size_t tlv_data_size(struct tlv_parser *parser) +{ + size_t size; + + if (parser->offset + sizeof(enum tlv_type) + sizeof(size_t) >= parser->size) { + size = 0; + } else { + memcpy(&size, parser->data + parser->offset + sizeof(enum tlv_type), sizeof(size_t)); + } + return size; +} |