Refactor skipstone_message_pack() to be variadic

Refactor skipstone_message_pack() to be variadic and similar to Perl's
pack(); eventually implement skipstone_message_unpack()
This commit is contained in:
XANTRONIX Development 2020-09-21 11:07:21 -05:00
parent 6098ef5922
commit b900e21c7b
4 changed files with 148 additions and 259 deletions

View file

@ -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,

View file

@ -2,6 +2,7 @@
#define _SKIPSTONE_MESSAGE_H
#include <stdint.h>
#include <sys/types.h>
#include <skipstone/link.h>
#include <skipstone/map.h>
@ -29,46 +30,31 @@ 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);
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);

View file

@ -1,20 +1,14 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <skipstone/link.h>
#include <skipstone/map.h>
#include <skipstone/queue.h>
#include <skipstone/message.h>
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;
}
skipstone_queue_destroy(message->parts);
memcpy((uint8_t *)message + offset, value, sz);
free(message);
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;
break;
}
part->size = size;
default:
errno = EINVAL;
memcpy(part + 1, buf, size);
if (skipstone_queue_add(message->parts, part) < 0) {
goto error_queue_add_parts;
goto error_invalid_template;
}
}
return 0;
va_end(args);
error_queue_add_parts:
free(part);
done:
return offset;
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;

View file

@ -7,33 +7,34 @@
int skipstone_system_send_client_version(skipstone_message_service *service,
uint32_t flags) {
skipstone_message *message;
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;
}