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, static int answer_music_message(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 *message; uint8_t message[256];
ssize_t len;
if (((uint8_t *)buf)[0] == 0x08) { if (((uint8_t *)buf)[0] == 0x08) {
message = skipstone_message_new(); if ((len = skipstone_message_pack(message,
skipstone_message_append_uint8(message, 0x10); sizeof(message),
skipstone_message_append_string(message, "KMFDM", 5); "CzzzLSS",
skipstone_message_append_string(message, "Nihil", 5); 0x10,
skipstone_message_append_string(message, "Ultra", 5); "KMFDM",
skipstone_message_append_uint32(message, htole32(274)); "Nihil",
skipstone_message_append_uint16(message, htole16(10)); "Ultra")) < 0) {
skipstone_message_append_uint16(message, htole16(1)); goto error_message_pack;
skipstone_message_service_queue(service, message, 32); }
skipstone_message_destroy(message);
message = skipstone_message_new(); skipstone_message_service_queue(service, message, len, 32);
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);
message = skipstone_message_new(); if ((len = skipstone_message_pack(message,
skipstone_message_append_uint8(message, 0x13); sizeof(message),
skipstone_message_append_string(message, "DeaDBeeF", 8); "CCLLCC",
skipstone_message_append_string(message, "DeaDBeeF", 8); 0x11,
skipstone_message_service_queue(service, message, 32); 1,
skipstone_message_destroy(message); 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 { } else {
printf("Got playback command %02x\n", ((uint8_t *)buf)[0]); printf("Got playback command %02x\n", ((uint8_t *)buf)[0]);
} }
return 0; return 0;
error_message_pack:
return -1;
} }
static int answer_phone_message(skipstone_message_service *service, static int answer_phone_message(skipstone_message_service *service,

View file

@ -2,6 +2,7 @@
#define _SKIPSTONE_MESSAGE_H #define _SKIPSTONE_MESSAGE_H
#include <stdint.h> #include <stdint.h>
#include <sys/types.h>
#include <skipstone/link.h> #include <skipstone/link.h>
#include <skipstone/map.h> #include <skipstone/map.h>
@ -29,48 +30,33 @@ typedef struct _skipstone_message_service skipstone_message_service;
typedef struct _skipstone_message skipstone_message; typedef struct _skipstone_message skipstone_message;
typedef int (skipstone_message_handler)(skipstone_message_service *service, 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(); ssize_t skipstone_message_pack(void *message,
size_t len,
void skipstone_message_destroy(skipstone_message *message); const char *template, ...);
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);
skipstone_message_service *skipstone_message_service_new(); skipstone_message_service *skipstone_message_service_new();
void skipstone_message_service_destroy(skipstone_message_service *service); void skipstone_message_service_destroy(skipstone_message_service *service);
int skipstone_message_service_register(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, int skipstone_message_service_deregister(skipstone_message_service *service,
uint16_t id); 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, 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, 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 */ #endif /* _SKIPSTONE_MESSAGE_H */

View file

@ -1,20 +1,14 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <skipstone/link.h> #include <skipstone/link.h>
#include <skipstone/map.h> #include <skipstone/map.h>
#include <skipstone/queue.h> #include <skipstone/queue.h>
#include <skipstone/message.h> #include <skipstone/message.h>
struct part {
uint8_t size;
};
struct _skipstone_message {
skipstone_queue *parts;
uint16_t size;
};
struct endpoint { struct endpoint {
skipstone_message_handler *handler; skipstone_message_handler *handler;
void *context; void *context;
@ -27,157 +21,82 @@ struct _skipstone_message_service {
void *buf; void *buf;
}; };
skipstone_message *skipstone_message_new() { #define case_type(t, type_t) \
skipstone_message *message; case t: { \
type_t v = va_arg(args, type_t); \
if ((message = malloc(sizeof(*message))) == NULL) { if (len < offset + sizeof(v)) { \
goto error_malloc_message; goto done; \
} else { \
memcpy((uint8_t *)message, &v, sizeof(v)); \
offset += sizeof(v); \
} \
break; \
} }
if ((message->parts = skipstone_queue_new()) == NULL) { #define case_type_int(t, type_t) \
goto error_queue_new_parts; 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: va_start(args, template);
free(message);
error_malloc_message: for (i=0; template[i]; i++) {
return NULL; char c = template[i];
}
void skipstone_message_destroy(skipstone_message *message) { switch (c) {
void *part; 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)) { case 'z': {
free(part); 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; error_invalid_template:
}
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:
return -1; 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 *skipstone_message_service_new() {
skipstone_message_service *service; skipstone_message_service *service;
@ -213,14 +132,8 @@ error_malloc_service:
} }
void skipstone_message_service_destroy(skipstone_message_service *service) { void skipstone_message_service_destroy(skipstone_message_service *service) {
skipstone_message *message;
skipstone_map_destroy(service->endpoints, free); skipstone_map_destroy(service->endpoints, free);
while (skipstone_queue_remove(service->pending, (void **)&message)) {
skipstone_message_destroy(message);
}
skipstone_queue_destroy(service->pending); skipstone_queue_destroy(service->pending);
free(service->buf); free(service->buf);
@ -248,12 +161,15 @@ error_malloc_endpoint:
return -1; 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); return skipstone_map_set((skipstone_map *)service, id, NULL);
} }
int skipstone_message_service_queue_packed(skipstone_message_service *service, int skipstone_message_service_queue(skipstone_message_service *service,
void *buf, uint16_t size, uint16_t id) { void *buf,
uint16_t size,
uint16_t id) {
skipstone_message_header *message; skipstone_message_header *message;
if ((message = malloc(sizeof(*message) + size)) == NULL) { if ((message = malloc(sizeof(*message) + size)) == NULL) {
@ -278,37 +194,9 @@ error_malloc_message:
return -1; 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, 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; skipstone_message_header *message;
struct endpoint *endpoint; struct endpoint *endpoint;
uint16_t size, id; uint16_t size, id;

View file

@ -6,34 +6,35 @@
#include "util.h" #include "util.h"
int skipstone_system_send_client_version(skipstone_message_service *service, int skipstone_system_send_client_version(skipstone_message_service *service,
uint32_t flags) { uint32_t flags) {
skipstone_message *message; uint8_t message[25];
ssize_t len;
if ((message = skipstone_message_new()) == NULL) { if ((len = skipstone_message_pack(message,
goto error_message_new; 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); if (skipstone_message_service_queue(service,
skipstone_message_append_uint32(message, htobe32(SKIPSTONE_SYSTEM_PROTOCOL)); message,
skipstone_message_append_uint32(message, htobe32(SKIPSTONE_SYSTEM_SESSION_GAMMA_RAY)); (uint16_t)len,
skipstone_message_append_uint32(message, htobe32(flags)); SKIPSTONE_SYSTEM_ENDPOINT_PHONE_VERSION) < 0) {
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) {
goto error_message_service_queue; goto error_message_service_queue;
} }
skipstone_message_destroy(message);
return 0; return 0;
error_message_service_queue: error_message_service_queue:
skipstone_message_destroy(message); error_message_pack:
error_message_new:
return -1; return -1;
} }