diff options
| author | winter Sparkles | 2026-04-27 21:55:21 +0100 |
|---|---|---|
| committer | winter Sparkles | 2026-04-27 21:55:21 +0100 |
| commit | c38bcb25aa1805009e399cea40e66d6f31195744 (patch) | |
| tree | 1ac302eb72966eaf106e8cb070a7a32def8370b0 | |
| parent | 05a9d192ee17c503172e785fd1383a62f2feb20b (diff) | |
add requests (but not responses yet)
| -rw-r--r-- | Doxyfile | 4 | ||||
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | docs/examples.md | 3 | ||||
| -rw-r--r-- | docs/write-request.example.c | 14 | ||||
| -rw-r--r-- | libsparklepaw/common.h | 13 | ||||
| -rw-r--r-- | libsparklepaw/request.c | 110 | ||||
| -rw-r--r-- | libsparklepaw/request.h | 87 |
7 files changed, 231 insertions, 4 deletions
@@ -1750,7 +1750,7 @@ ECLIPSE_DOC_ID = org.doxygen.Project # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. -DISABLE_INDEX = YES +DISABLE_INDEX = NO # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag @@ -1767,7 +1767,7 @@ DISABLE_INDEX = YES # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. -GENERATE_TREEVIEW = YES +GENERATE_TREEVIEW = NO # When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the # FULL_SIDEBAR option determines if the side bar is limited to only the treeview @@ -12,10 +12,10 @@ CFLAGS := -Wall -Wextra -flto ### build mode ifeq ($(mode),debug) - CFLAGS += -g -Og -DDEBUG + CFLAGS += -g -Og BUILD_DIR := $(BUILD_DIR)/debug else - CFLAGS += -O3 + CFLAGS += -O3 -DNDEBUG LDFLAGS += -s endif diff --git a/docs/examples.md b/docs/examples.md index b517053..9d2a6d1 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -7,3 +7,6 @@ Example of constructing a service and writing it out: Example of reading a service in and printing it for debugging: \include read-service.example.c + +Example of making a request (to stdout instead of a transport): +\include write-request.example.c diff --git a/docs/write-request.example.c b/docs/write-request.example.c new file mode 100644 index 0000000..3abe82e --- /dev/null +++ b/docs/write-request.example.c @@ -0,0 +1,14 @@ +#include <libsparklepaw/request.h> + +void main() { + struct sprkl_request* request = sprkl_request_make_fetchservice( + SPRKL_SIGALGO_ED25519, + "aaaabbbbccccddddaaaabbbbccccddddaaaabbbbccccddddaaaabbbbccccdddd", + 0 + ); + + int n = sprkl_request_write(request, stdout); + fprintf(stderr, "\nWrote %d bytes\n", n); + + sprkl_request_freeall(request); +} diff --git a/libsparklepaw/common.h b/libsparklepaw/common.h new file mode 100644 index 0000000..511e6de --- /dev/null +++ b/libsparklepaw/common.h @@ -0,0 +1,13 @@ +/** \file + * Common data types. */ + +#ifndef SPRKL_COMMON_H +#define SPRKL_COMMON_H + +/** Available signature algorithms. + * At present the only one is Ed25519, but there may be more in future. */ +enum sprkl_sigalgo { + SPRKL_SIGALGO_ED25519 = 25519 /**< Ed25519. */ +}; + +#endif diff --git a/libsparklepaw/request.c b/libsparklepaw/request.c new file mode 100644 index 0000000..440cdd9 --- /dev/null +++ b/libsparklepaw/request.c @@ -0,0 +1,110 @@ +#include "endian.h" +#include "request.h" + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int sprkl_request_write(struct sprkl_request* request, FILE* stream) { + int n = 0; + n += fwrite(SPRKL_REQUEST_MAGIC, 1, SPRKL_REQUEST_MAGIC_SZ, stream); + n += sprkl_writeuint16be(SPRKL_PROTO_VERSION, stream); + n += sprkl_writeuint16be(request->verb, stream); + switch (request->verb) { + case SPRKL_VERB_ECHO: + n += fwrite( + request->echo.data, 1, + sizeof request->echo.data, stream + ); + break; + case SPRKL_VERB_FETCHSERVICE: + struct sprkl_request_fetchservice* inner = &request->fetchsvc; + n += sprkl_writeuint16be(inner->keyalgo, stream); + n += sprkl_writeuint16be(inner->keysz, stream); + n += fwrite(inner->key, 1, inner->keysz, stream); + n += sprkl_writeuint16be(inner->index, stream); + break; + } + return n; +} + +int sprkl_request_read(struct sprkl_request* request, FILE* stream) { + int n = 0; + uint8_t buf[SPRKL_REQUEST_MAGIC_SZ]; + n += fread(buf, 1, 8, stream); + if (memcmp(buf, SPRKL_REQUEST_MAGIC, sizeof buf) != 0) { + errno = EPROTO; + return n; + } + uint16_t version; + n += sprkl_readuint16be(&version, stream); + if (version != SPRKL_PROTO_VERSION) { + errno = EPROTO; + return n; + } + n += sprkl_readuint16be((uint16_t*) &request->verb, stream); + if ( + request->verb != SPRKL_VERB_ECHO + && request->verb != SPRKL_VERB_FETCHSERVICE + ) { + errno = ENOTSUP; + return n; + } + switch (request->verb) { + case SPRKL_VERB_ECHO: + n += fread( + &request->echo.data, 1, + sizeof request->echo.data, stream + ); + break; + case SPRKL_VERB_FETCHSERVICE: + struct sprkl_request_fetchservice* inner = &request->fetchsvc; + n += sprkl_readuint16be((uint16_t*) &inner->keyalgo, stream); + n += sprkl_readuint16be(&inner->keysz, stream); + inner->key = malloc(inner->keysz); + n += fread(inner->key, 1, inner->keysz, stream); + n += sprkl_readuint16be(&inner->index, stream); + break; + } + return n; +} + +void sprkl_request_freeparts(struct sprkl_request* request) { + switch (request->verb) { + case SPRKL_VERB_ECHO: + // do nothing + break; + case SPRKL_VERB_FETCHSERVICE: + free(request->fetchsvc.key); + break; + } +} + +void sprkl_request_freeall(struct sprkl_request* request) { + sprkl_request_freeparts(request); + free(request); +} + +struct sprkl_request* sprkl_request_make_fetchservice( + enum sprkl_sigalgo keyalgo, + uint8_t* key, + uint16_t serviceidx + ) { + // FIXME: check this properly instead of using assert i think + assert(keyalgo == SPRKL_SIGALGO_ED25519 && "i only support Ed25519"); + uint16_t keysz = 0x40; // based on the above assertion + struct sprkl_request* req = malloc(sizeof(struct sprkl_request)); + uint8_t* copiedkey = malloc(keysz); + memcpy(copiedkey, key, keysz); + req->verb = SPRKL_VERB_FETCHSERVICE; + struct sprkl_request_fetchservice fetchsvc = { + .keyalgo = keyalgo, + .keysz = keysz, + .key = copiedkey, + .index = serviceidx + }; + req->fetchsvc = fetchsvc; + return req; +} diff --git a/libsparklepaw/request.h b/libsparklepaw/request.h new file mode 100644 index 0000000..bf568f6 --- /dev/null +++ b/libsparklepaw/request.h @@ -0,0 +1,87 @@ +/** \file + * Requests and responses. */ + +#ifndef SPRKL_REQUEST_H +#define SPRKL_REQUEST_H + +#include "common.h" + +#include <stdint.h> +#include <stdio.h> + +/** Magic bytes for requests. */ +#define SPRKL_REQUEST_MAGIC "PawRqust" +#define SPRKL_REQUEST_MAGIC_SZ ((sizeof SPRKL_REQUEST_MAGIC) - 1) +/** Currently supported protocol version. */ +#define SPRKL_PROTO_VERSION 1 + +/** Request verb, indicates what action the request is performing. */ +enum sprkl_request_verb { + SPRKL_VERB_ECHO = 0, /**< Return same data back in the response. */ + SPRKL_VERB_FETCHSERVICE = 1, /**< Fetch a service by key and index. */ + //SPRKL_VERB_QUERYSERVICES = 2 +}; + +/** Request payload for \ref SPRKL_VERB_ECHO. */ +struct sprkl_request_echo { + uint8_t data[16]; /**< Data to be returned by the remote party. */ +}; + +/** Request payload for \ref SPRKL_VERB_FETCHSERVICE. */ +struct sprkl_request_fetchservice { + enum sprkl_sigalgo keyalgo; /**< The zone's signature algorithm. */ + uint16_t keysz; /**< Length (in bytes) of the public key. */ + uint8_t* key; /**< The zone's public key (no terminator). */ + uint16_t index; /**< Index of the service within the zone. */ +}; + +/** Request tagged union. */ +struct sprkl_request { + enum sprkl_request_verb verb; /**< Union tag, request verb. */ + union { + struct sprkl_request_echo echo; + struct sprkl_request_fetchservice fetchsvc; + //struct sprkl_request_queryservices querysvcs; + }; +}; + +/** Encodes and writes a request in wire format to a stream. + * \param[in] request Request to write. + * \param[out] stream Stream to write the request to. + * \returns number of bytes written. */ +int sprkl_request_write(struct sprkl_request* request, FILE* stream); + +/** Reads and decodes a request in wire format from a stream. This could fail if + * the protocol magic constant is wrong or the version is unsupported, in which + * case it will set \c errno to \c EPROTO, or if the verb is unsupported, in + * which case it will set \c errno to \c ENOTSUP. + * When reading a fetch service request, it will allocate a buffer for the key. + * \param[out] request Empty request to read into. + * \param[in] stream Stream to read it from. + * \returns number of bytes read. */ +int sprkl_request_read(struct sprkl_request* request, FILE* stream); + +/** Frees any pointers contained within the request, but not the request itself. + * What exactly gets freed varies depending on the request verb. + * \param request Request to free. */ +void sprkl_request_freeparts(struct sprkl_request* request); + +/** Frees any pointers contained within the request, and then the request + * itself. Same as sprkl_request_freeparts() followed by free(request). + * \param request Request to free. */ +void sprkl_request_freeall(struct sprkl_request* request); + +/** Allocates and returns a new request to fetch a service given its key and + * index. Copies the key, so both the request and the key need to be freed. + * \param keyalgo Algorithm used for the zone's public key. + * \param key The zone's public key (will be copied). Does not require a length + * or terminator as the length is determined based on the algorithm. + * \param serviceidx The index of the desired service within the zone. + * \returns a pointer to the new request struct. */ +struct sprkl_request* sprkl_request_make_fetchservice( + enum sprkl_sigalgo keyalgo, + uint8_t* key, + uint16_t serviceidx + ); + +#endif |
