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 {
|
|
|
|
skipstone_queue *parts;
|
2017-11-24 23:49:00 -06:00
|
|
|
uint16_t size;
|
2017-11-24 15:25:28 -06:00
|
|
|
};
|
|
|
|
|
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 23:49:00 -06:00
|
|
|
skipstone_message *skipstone_message_new() {
|
2017-11-24 15:25:28 -06:00
|
|
|
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;
|
|
|
|
|
|
|
|
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) {
|
2017-11-24 23:49:00 -06:00
|
|
|
if (append_part(message, string, size, SKIPSTONE_MESSAGE_PART_STRING) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
message->size += sizeof(size) + size;
|
|
|
|
|
|
|
|
return 0;
|
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) {
|
2017-11-24 23:49:00 -06:00
|
|
|
if (append_part(message, &value, sizeof(value), SKIPSTONE_MESSAGE_PART_UINT8) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
message->size += sizeof(value);
|
|
|
|
|
|
|
|
return 0;
|
2017-11-24 23:38:23 -06:00
|
|
|
}
|
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) {
|
2017-11-24 23:49:00 -06:00
|
|
|
if (append_part(message, &value, sizeof(value), SKIPSTONE_MESSAGE_PART_UINT16) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
message->size += sizeof(value);
|
|
|
|
|
|
|
|
return 0;
|
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() {
|
2017-11-23 18:57:33 +00:00
|
|
|
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;
|
|
|
|
}
|