diff --git a/examples/test.c b/examples/test.c index 86fa17f..1b87c9e 100644 --- a/examples/test.c +++ b/examples/test.c @@ -25,41 +25,55 @@ static int answer_phone_version_message(skipstone_message_service *service, static int answer_music_message(skipstone_message_service *service, void *buf, uint16_t size, uint16_t id, void *context) { - skipstone_message *message; + uint8_t message[256]; + ssize_t len; if (((uint8_t *)buf)[0] == 0x08) { - message = skipstone_message_new(); - skipstone_message_append_uint8(message, 0x10); - skipstone_message_append_string(message, "KMFDM", 5); - skipstone_message_append_string(message, "Nihil", 5); - skipstone_message_append_string(message, "Ultra", 5); - skipstone_message_append_uint32(message, htole32(274)); - skipstone_message_append_uint16(message, htole16(10)); - skipstone_message_append_uint16(message, htole16(1)); - skipstone_message_service_queue(service, message, 32); - skipstone_message_destroy(message); + if ((len = skipstone_message_pack(message, + sizeof(message), + "CzzzLSS", + 0x10, + "KMFDM", + "Nihil", + "Ultra")) < 0) { + goto error_message_pack; + } - message = skipstone_message_new(); - skipstone_message_append_uint8(message, 0x11); - skipstone_message_append_uint8(message, 1); - skipstone_message_append_uint32(message, htole32(120)); - skipstone_message_append_uint32(message, htole32(320)); - skipstone_message_append_uint8(message, 1); - skipstone_message_append_uint8(message, 1); - skipstone_message_service_queue(service, message, 32); - skipstone_message_destroy(message); + skipstone_message_service_queue(service, message, len, 32); - message = skipstone_message_new(); - skipstone_message_append_uint8(message, 0x13); - skipstone_message_append_string(message, "DeaDBeeF", 8); - skipstone_message_append_string(message, "DeaDBeeF", 8); - skipstone_message_service_queue(service, message, 32); - skipstone_message_destroy(message); + if ((len = skipstone_message_pack(message, + sizeof(message), + "CCLLCC", + 0x11, + 1, + htole32(120), + htole32(120), + htole32(320), + 1, + 1)) < 0) { + goto error_message_pack; + } + + skipstone_message_service_queue(service, message, len, 32); + + if ((len = skipstone_message_pack(message, + sizeof(message), + "Czz", + 0x13, + "DeaDBeeF", + "DeaDBeeF")) < 0) { + goto error_message_pack; + } + + skipstone_message_service_queue(service, message, len, 32); } else { printf("Got playback command %02x\n", ((uint8_t *)buf)[0]); } return 0; + +error_message_pack: + return -1; } static int answer_phone_message(skipstone_message_service *service, diff --git a/include/skipstone/message.h b/include/skipstone/message.h index 52cfac1..d5778e0 100644 --- a/include/skipstone/message.h +++ b/include/skipstone/message.h @@ -2,6 +2,7 @@ #define _SKIPSTONE_MESSAGE_H #include +#include #include #include @@ -29,48 +30,33 @@ typedef struct _skipstone_message_service skipstone_message_service; typedef struct _skipstone_message skipstone_message; typedef int (skipstone_message_handler)(skipstone_message_service *service, - void *buf, uint16_t size, uint16_t id, void *context); + void *buf, + uint16_t size, + uint16_t id, + void *context); -skipstone_message *skipstone_message_new(); - -void skipstone_message_destroy(skipstone_message *message); - -uint16_t skipstone_message_size(skipstone_message *message); - -int skipstone_message_append_string(skipstone_message *message, - char *string, uint8_t size); - -int skipstone_message_append_uint8(skipstone_message *message, - uint8_t value); - -int skipstone_message_append_uint16(skipstone_message *message, - uint16_t value); - -int skipstone_message_append_uint32(skipstone_message *message, - uint32_t value); - -int skipstone_message_append_uint64(skipstone_message *message, - uint64_t value); - -int skipstone_message_pack(skipstone_message *message, void *buf); +ssize_t skipstone_message_pack(void *message, + size_t len, + const char *template, ...); skipstone_message_service *skipstone_message_service_new(); void skipstone_message_service_destroy(skipstone_message_service *service); int skipstone_message_service_register(skipstone_message_service *service, - uint16_t id, skipstone_message_handler *handler, void *context); + uint16_t id, + skipstone_message_handler *handler, + void *context); int skipstone_message_service_deregister(skipstone_message_service *service, - uint16_t id); - -int skipstone_message_service_queue_packed(skipstone_message_service *service, - void *buf, uint16_t size, uint16_t id); + uint16_t id); int skipstone_message_service_queue(skipstone_message_service *service, - skipstone_message *message, uint16_t id); + void *buf, + uint16_t size, + uint16_t id); int skipstone_message_service_next_event(skipstone_message_service *service, - skipstone_link *link, struct timeval *timeout); + skipstone_link *link, struct timeval *timeout); #endif /* _SKIPSTONE_MESSAGE_H */ diff --git a/src/message.c b/src/message.c index 242999a..f803f93 100644 --- a/src/message.c +++ b/src/message.c @@ -1,20 +1,14 @@ #include +#include +#include #include +#include #include #include #include #include -struct part { - uint8_t size; -}; - -struct _skipstone_message { - skipstone_queue *parts; - uint16_t size; -}; - struct endpoint { skipstone_message_handler *handler; void *context; @@ -27,157 +21,82 @@ struct _skipstone_message_service { void *buf; }; -skipstone_message *skipstone_message_new() { - skipstone_message *message; - - if ((message = malloc(sizeof(*message))) == NULL) { - goto error_malloc_message; +#define case_type(t, type_t) \ + case t: { \ + type_t v = va_arg(args, type_t); \ + if (len < offset + sizeof(v)) { \ + goto done; \ + } else { \ + memcpy((uint8_t *)message, &v, sizeof(v)); \ + offset += sizeof(v); \ + } \ + break; \ } - if ((message->parts = skipstone_queue_new()) == NULL) { - goto error_queue_new_parts; +#define case_type_int(t, type_t) \ + case t: { \ + type_t v = (type_t)va_arg(args, int); \ + if (len < offset + sizeof(v)) { \ + goto done; \ + } else { \ + memcpy((uint8_t *)message, &v, sizeof(v)); \ + offset += sizeof(v); \ + } \ + break; \ } - message->size = 0; +ssize_t skipstone_message_pack(void *message, + size_t len, + const char *template, ...) { + va_list args; - return message; + size_t offset = 0, + i; -error_queue_new_parts: - free(message); + va_start(args, template); -error_malloc_message: - return NULL; -} + for (i=0; template[i]; i++) { + char c = template[i]; -void skipstone_message_destroy(skipstone_message *message) { - void *part; + switch (c) { + case_type_int('c', int8_t); + case_type_int('C', uint8_t); + case_type_int('s', int16_t); + case_type_int('S', uint16_t); + case_type('l', int32_t); + case_type('L', uint32_t); + case_type('q', int64_t); + case_type('Q', uint64_t); - while (skipstone_queue_remove(message->parts, &part)) { - free(part); + case 'z': { + char *value = va_arg(args, char *); + size_t sz = strlen(value); + + if (len < offset + sz) { + goto done; + } + + memcpy((uint8_t *)message + offset, value, sz); + + break; + } + + default: + errno = EINVAL; + + goto error_invalid_template; + } } - skipstone_queue_destroy(message->parts); + va_end(args); - free(message); +done: + return offset; - return; -} - -static int append_part(skipstone_message *message, void *buf, uint8_t size) { - struct part *part; - - if ((part = malloc(sizeof(*part) + size)) == NULL) { - goto error_malloc_part; - } - - part->size = size; - - memcpy(part + 1, buf, size); - - if (skipstone_queue_add(message->parts, part) < 0) { - goto error_queue_add_parts; - } - - return 0; - -error_queue_add_parts: - free(part); - -error_malloc_part: +error_invalid_template: return -1; } -int skipstone_message_append_string(skipstone_message *message, - char *string, uint8_t size) { - struct part *part; - uint8_t bodysz = sizeof(size) + size; - - if ((part = malloc(sizeof(*part) + bodysz)) == NULL) { - goto error_malloc_part; - } - - part->size = bodysz; - - memcpy(part + 1, &size, sizeof(size)); - memcpy(((uint8_t *)(part + 1)) + sizeof(size), string, size); - - if (skipstone_queue_add(message->parts, part) < 0) { - goto error_queue_add_part; - } - - message->size += bodysz; - - return 0; - -error_queue_add_part: - free(part); - -error_malloc_part: - return -1; -} - -uint16_t skipstone_message_size(skipstone_message *message) { - return message->size; -} - -int skipstone_message_append_uint8(skipstone_message *message, uint8_t value) { - if (append_part(message, &value, sizeof(value)) < 0) { - return -1; - } - - message->size += sizeof(value); - - return 0; -} - -int skipstone_message_append_uint16(skipstone_message *message, uint16_t value) { - if (append_part(message, &value, sizeof(value)) < 0) { - return -1; - } - - message->size += sizeof(value); - - return 0; -} - -int skipstone_message_append_uint32(skipstone_message *message, uint32_t value) { - if (append_part(message, &value, sizeof(value)) < 0) { - return -1; - } - - message->size += sizeof(value); - - return 0; -} - -int skipstone_message_append_uint64(skipstone_message *message, uint64_t value) { - if (append_part(message, &value, sizeof(value)) < 0) { - return -1; - } - - message->size += sizeof(value); - - return 0; -} - -int skipstone_message_pack(skipstone_message *message, void *buf) { - size_t offset = 0; - - struct part *part; - - if (message->size > SKIPSTONE_MESSAGE_MAX_PAYLOAD) { - return -1; - } - - while (skipstone_queue_remove(message->parts, (void **)&part)) { - memcpy(((uint8_t *)buf) + offset, part + 1, part->size); - - offset += part->size; - } - - return 0; -} - skipstone_message_service *skipstone_message_service_new() { skipstone_message_service *service; @@ -213,14 +132,8 @@ error_malloc_service: } void skipstone_message_service_destroy(skipstone_message_service *service) { - skipstone_message *message; - skipstone_map_destroy(service->endpoints, free); - while (skipstone_queue_remove(service->pending, (void **)&message)) { - skipstone_message_destroy(message); - } - skipstone_queue_destroy(service->pending); free(service->buf); @@ -248,12 +161,15 @@ error_malloc_endpoint: return -1; } -int skipstone_message_service_deregister(skipstone_message_service *service, uint16_t id) { +int skipstone_message_service_deregister(skipstone_message_service *service, + uint16_t id) { return skipstone_map_set((skipstone_map *)service, id, NULL); } -int skipstone_message_service_queue_packed(skipstone_message_service *service, - void *buf, uint16_t size, uint16_t id) { +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) { @@ -278,37 +194,9 @@ error_malloc_message: return -1; } -int skipstone_message_service_queue(skipstone_message_service *service, - skipstone_message *message, uint16_t id) { - skipstone_message_header *packed; - - if ((packed = malloc(sizeof(*packed) + message->size)) == NULL) { - goto error_malloc_packed; - } - - packed->size = message->size; - packed->id = id; - - if (skipstone_message_pack(message, packed + 1) < 0) { - goto error_pack; - } - - if (skipstone_queue_add(service->pending, packed) < 0) { - goto error_queue_add_pending; - } - - return 0; - -error_queue_add_pending: -error_pack: - free(message); - -error_malloc_packed: - return -1; -} - int skipstone_message_service_next_event(skipstone_message_service *service, - skipstone_link *link, struct timeval *timeout) { + skipstone_link *link, + struct timeval *timeout) { skipstone_message_header *message; struct endpoint *endpoint; uint16_t size, id; diff --git a/src/system.c b/src/system.c index c971083..02d7b29 100644 --- a/src/system.c +++ b/src/system.c @@ -6,34 +6,35 @@ #include "util.h" int skipstone_system_send_client_version(skipstone_message_service *service, - uint32_t flags) { - skipstone_message *message; + uint32_t flags) { + uint8_t message[25]; + ssize_t len; - if ((message = skipstone_message_new()) == NULL) { - goto error_message_new; + if ((len = skipstone_message_pack(message, + sizeof(message), + "CLLLCCCCQ", + SKIPSTONE_SYSTEM_VERSION_RESPONSE, + htobe32(SKIPSTONE_SYSTEM_PROTOCOL), + htobe32(SKIPSTONE_SYSTEM_SESSION_GAMMA_RAY), + htobe32(flags), + 2, + SKIPSTONE_SYSTEM_CLIENT_MAJOR, + SKIPSTONE_SYSTEM_CLIENT_MINOR, + SKIPSTONE_SYSTEM_CLIENT_BUGFIX, + htobe64(SKIPSTONE_SYSTEM_PROTOCOL_CAPS))) < 0) { + goto error_message_pack; } - skipstone_message_append_uint8( message, SKIPSTONE_SYSTEM_VERSION_RESPONSE); - skipstone_message_append_uint32(message, htobe32(SKIPSTONE_SYSTEM_PROTOCOL)); - skipstone_message_append_uint32(message, htobe32(SKIPSTONE_SYSTEM_SESSION_GAMMA_RAY)); - skipstone_message_append_uint32(message, htobe32(flags)); - skipstone_message_append_uint8( message, 2); - skipstone_message_append_uint8( message, SKIPSTONE_SYSTEM_CLIENT_MAJOR); - skipstone_message_append_uint8( message, SKIPSTONE_SYSTEM_CLIENT_MINOR); - skipstone_message_append_uint8( message, SKIPSTONE_SYSTEM_CLIENT_BUGFIX); - skipstone_message_append_uint64(message, htobe64(SKIPSTONE_SYSTEM_PROTOCOL_CAPS)); - - if (skipstone_message_service_queue(service, message, SKIPSTONE_SYSTEM_ENDPOINT_PHONE_VERSION) < 0) { + if (skipstone_message_service_queue(service, + message, + (uint16_t)len, + SKIPSTONE_SYSTEM_ENDPOINT_PHONE_VERSION) < 0) { goto error_message_service_queue; } - skipstone_message_destroy(message); - return 0; error_message_service_queue: - skipstone_message_destroy(message); - -error_message_new: +error_message_pack: return -1; }