skipstone/src/message.c

256 lines
5.9 KiB
C
Raw Normal View History

2017-11-23 17:22:36 +00:00
#include <stdlib.h>
2017-11-23 18:02:38 +00:00
#include <string.h>
2017-11-23 17:22:36 +00:00
#include <skipstone/link.h>
#include <skipstone/map.h>
#include <skipstone/queue.h>
#include <skipstone/message.h>
2017-11-24 15:25:28 -06:00
enum part_type {
SKIPSTONE_MESSAGE_PART_STRING,
SKIPSTONE_MESSAGE_PART_UINT8,
SKIPSTONE_MESSAGE_PART_UINT16
};
struct part {
enum part_type type;
enum skipstone_message_endianness endianness;
2017-11-24 23:38:23 -06:00
uint8_t size;
2017-11-24 15:25:28 -06:00
};
struct _skipstone_message {
uint16_t size, id;
skipstone_queue *parts;
};
2017-11-23 17:22:36 +00:00
struct endpoint {
skipstone_message_handler *handler;
void *context;
2017-11-24 15:25:28 -06:00
uint16_t id;
2017-11-23 17:22:36 +00:00
};
struct _skipstone_message_service {
skipstone_map *endpoints;
skipstone_queue *pending;
};
2017-11-24 15:25:28 -06:00
skipstone_message *skipstone_message_new(uint16_t id) {
skipstone_message *message;
if ((message = malloc(sizeof(*message))) == NULL) {
goto error_malloc_message;
}
if ((message->parts = skipstone_queue_new()) == NULL) {
goto error_queue_new_parts;
}
message->size = 0;
message->id = id;
return message;
error_queue_new_parts:
free(message);
error_malloc_message:
return NULL;
}
2017-11-24 23:38:23 -06:00
static int append_part(skipstone_message *message,
void *buf, uint8_t size, enum part_type type) {
2017-11-24 15:25:28 -06:00
struct part *part;
if ((part = malloc(sizeof(*part) + size)) == NULL) {
goto error_malloc_part;
}
2017-11-24 23:38:23 -06:00
part->type = type;
2017-11-24 15:25:28 -06:00
part->endianness = SKIPSTONE_MESSAGE_ENDIAN_LITTLE;
part->size = size;
2017-11-24 23:38:23 -06:00
memcpy(part + 1, buf, size);
2017-11-24 15:25:28 -06:00
if (skipstone_queue_add(message->parts, part) < 0) {
goto error_queue_add_parts;
}
return 0;
error_queue_add_parts:
free(part);
error_malloc_part:
return -1;
}
2017-11-24 23:38:23 -06:00
int skipstone_message_append_string(skipstone_message *message,
char *string, uint8_t size) {
return append_part(message, string, size, SKIPSTONE_MESSAGE_PART_STRING);
2017-11-24 15:25:28 -06:00
}
2017-11-24 23:38:23 -06:00
int skipstone_message_append_uint8(skipstone_message *message, uint8_t value) {
return append_part(message, &value, sizeof(value),
SKIPSTONE_MESSAGE_PART_UINT8);
}
2017-11-24 15:25:28 -06:00
2017-11-24 23:38:23 -06:00
int skipstone_message_append_uint16(skipstone_message *message, uint16_t value) {
return append_part(message, &value, sizeof(value),
SKIPSTONE_MESSAGE_PART_UINT16);
2017-11-24 15:25:28 -06:00
}
int skipstone_message_pack(skipstone_message *message,
void *buf, uint16_t *size) {
size_t offset = 0;
struct part *part;
while (skipstone_queue_remove(message->parts, (void **)&part)) {
switch (part->type) {
case SKIPSTONE_MESSAGE_PART_STRING: {
((uint8_t *)buf)[offset] = part->size;
memcpy((uint8_t *)buf + offset + sizeof(uint8_t), part + 1, part->size);
offset += sizeof(uint8_t) + part->size;
break;
}
case SKIPSTONE_MESSAGE_PART_UINT8: {
((uint8_t *)buf)[offset] = ((uint8_t *)(part + 1))[0];
offset += sizeof(uint8_t);
break;
}
case SKIPSTONE_MESSAGE_PART_UINT16: {
((uint16_t *)((uint8_t *)buf + offset))[0] = ((uint16_t *)(part + 1))[0];
offset += sizeof(uint16_t);
break;
}
}
}
*size = offset;
return 0;
}
2017-11-23 17:22:36 +00:00
skipstone_message_service *skipstone_message_service_new() {
skipstone_message_service *service;
if ((service = malloc(sizeof(*service))) == NULL) {
goto error_malloc_service;
}
if ((service->endpoints = skipstone_map_new()) == NULL) {
goto error_map_new_endpoints;
}
if ((service->pending = skipstone_queue_new()) == NULL) {
goto error_queue_new_pending;
}
return service;
error_queue_new_pending:
skipstone_map_destroy(service->endpoints);
error_map_new_endpoints:
free(service);
error_malloc_service:
return NULL;
2017-11-23 17:22:36 +00:00
}
int skipstone_message_service_register(skipstone_message_service *service,
uint16_t id, skipstone_message_handler *handler, void *context) {
struct endpoint *endpoint;
if ((endpoint = malloc(sizeof(*endpoint))) == NULL) {
goto error_malloc_endpoint;
}
endpoint->id = id;
endpoint->handler = handler;
endpoint->context = context;
return skipstone_map_set(service->endpoints, id, endpoint);
error_malloc_endpoint:
return -1;
}
int skipstone_message_service_deregister(skipstone_message_service *service, uint16_t id) {
return skipstone_map_set((skipstone_map *)service, id, NULL);
}
2017-11-23 18:02:38 +00:00
int skipstone_message_service_queue(skipstone_message_service *service,
void *buf, uint16_t size, uint16_t id) {
skipstone_message_header *message;
if ((message = malloc(sizeof(*message) + size)) == NULL) {
goto error_malloc_message;
}
message->size = size;
message->id = id;
memcpy(message + 1, buf, size);
2017-11-24 12:18:02 -06:00
if (skipstone_queue_add(service->pending, message) < 0) {
goto error_queue_add_pending;
2017-11-24 02:27:57 +00:00
}
2017-11-23 18:02:38 +00:00
return 0;
2017-11-24 12:18:02 -06:00
error_queue_add_pending:
2017-11-24 02:27:57 +00:00
free(message);
2017-11-23 18:02:38 +00:00
error_malloc_message:
return -1;
}
2017-11-23 17:22:36 +00:00
int skipstone_message_service_run(skipstone_message_service *service,
skipstone_link *link) {
void *buf;
if ((buf = malloc(SKIPSTONE_MESSAGE_MAX_PAYLOAD)) == NULL) {
goto error_malloc_buf;
}
2017-11-23 18:02:38 +00:00
while (1) {
skipstone_message_header *message;
2017-11-24 02:27:57 +00:00
struct endpoint *endpoint;
uint16_t size, id;
2017-11-23 18:02:38 +00:00
if (skipstone_link_recv(link, buf, &size, &id) < 0) {
goto error_io;
}
2017-11-24 02:27:57 +00:00
if ((endpoint = skipstone_map_get(service->endpoints, id)) != NULL) {
2017-11-24 12:28:49 -06:00
if (endpoint->handler(service, buf, size, id, endpoint->context) < 0) {
2017-11-23 18:02:38 +00:00
goto error_io;
}
}
2017-11-24 12:18:02 -06:00
while (skipstone_queue_remove(service->pending, (void **)&message)) {
2017-11-23 18:02:38 +00:00
if (skipstone_link_send(link, message + 1, message->size, message->id) < 0) {
goto error_io;
}
}
2017-11-23 17:22:36 +00:00
}
return 0;
2017-11-23 18:02:38 +00:00
error_io:
free(buf);
2017-11-23 17:22:36 +00:00
error_malloc_buf:
return -1;
}