diff options
author | Mattias Andrée <m@maandree.se> | 2025-02-10 17:50:58 +0100 |
---|---|---|
committer | Mattias Andrée <m@maandree.se> | 2025-02-10 17:52:46 +0100 |
commit | ec1bcdcd0dd6e196303e8d9a30b3b2740e32c502 (patch) | |
tree | dcc759aaf897c915827659e00644f12503cf1268 /common.h | |
parent | Improve makefile (diff) | |
download | libcoopgamma-ec1bcdcd0dd6e196303e8d9a30b3b2740e32c502.tar.gz libcoopgamma-ec1bcdcd0dd6e196303e8d9a30b3b2740e32c502.tar.bz2 libcoopgamma-ec1bcdcd0dd6e196303e8d9a30b3b2740e32c502.tar.xz |
Minor code improvements and split into multiple c files
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to 'common.h')
-rw-r--r-- | common.h | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/common.h b/common.h new file mode 100644 index 0000000..2d87b85 --- /dev/null +++ b/common.h @@ -0,0 +1,259 @@ +/* See LICENSE file for copyright and license details. */ +#include "libcoopgamma.h" + +#include <sys/socket.h> +#include <sys/un.h> +#include <sys/wait.h> +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <poll.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + + +#if !defined(COOPGAMMAD) +# define COOPGAMMAD "coopgammad" +#endif + + +#if defined(__clang__) +# pragma clang diagnostic ignored "-Wdocumentation" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# pragma clang diagnostic ignored "-Wcast-align" +#endif + + +#if defined(__GNUC__) +# define NAME_OF_THE_PROCESS (argv0) +extern const char *argv0; +#else +# define NAME_OF_THE_PROCESS ("libcoopgamma") +#endif + + +#if defined(__GNUC__) +# define HIDDEN __attribute__((__visibility__("hidden"))) +#else +# define HIDDEN +#endif + + + +#define SUBBUF\ + (buf ? &buf[off] : NULL) + +#define NNSUBBUF\ + (&buf[off]) + +#define MARSHAL_PROLOGUE\ + char *restrict buf = vbuf;\ + size_t off = 0; + +#define UNMARSHAL_PROLOGUE\ + const char *restrict buf = vbuf;\ + size_t off = 0; + +#define MARSHAL_EPILOGUE\ + return off + +#define UNMARSHAL_EPILOGUE\ + return *np = off, LIBCOOPGAMMA_SUCCESS + +#define marshal_prim(datum, type)\ + ((buf != NULL ? *(type *)&buf[off] = (datum) : 0), off += sizeof(type)) + +#define unmarshal_prim(datum, type)\ + ((datum) = *(const type *)&buf[off], off += sizeof(type)) + +#define marshal_version(version)\ + marshal_prim(version, int) + +#define unmarshal_version(version)\ + do {\ + int version__;\ + unmarshal_prim(version__, int);\ + if (version__ < (version))\ + return LIBCOOPGAMMA_INCOMPATIBLE_DOWNGRADE;\ + if (version__ > (version))\ + return LIBCOOPGAMMA_INCOMPATIBLE_UPGRADE;\ + } while (0) + +#define marshal_buffer(data, n)\ + ((buf ? (memcpy(&buf[off], (data), (n)), 0) : 0), off += (n)) + +#define unmarshal_buffer(data, n)\ + do {\ + (data) = malloc((n));\ + if (!(data))\ + return LIBCOOPGAMMA_ERRNO_SET;\ + memcpy((data), &buf[off], (n));\ + off += (n);\ + } while (0) + +#define marshal_string(datum)\ + (!(datum) ? marshal_prim(0, char) :\ + (marshal_prim(1, char), marshal_buffer((datum), strlen(datum) + 1U))) + +#define unmarshal_string(datum)\ + do {\ + char nonnull__;\ + unmarshal_prim(nonnull__, char);\ + if (nonnull__)\ + unmarshal_buffer((datum), strlen(&buf[off]) + 1U);\ + else\ + (datum) = NULL;\ + } while (0) + + + +#define copy_errno(ctx)\ + (!errno ? NULL :\ + ((ctx)->error.number = (uint64_t)errno,\ + (ctx)->error.custom = 0,\ + (ctx)->error.server_side = 0,\ + free((ctx)->error.description),\ + (ctx)->error.description = NULL)) + + +#define SYNC_CALL(send_call, recv_call, fail_return)\ + libcoopgamma_async_context_t async;\ + if (send_call < 0) {\ + reflush:\ + if (errno != EINTR)\ + return fail_return;\ + if (libcoopgamma_flush(ctx) < 0)\ + goto reflush;\ + }\ + resync:\ + if (libcoopgamma_synchronise(ctx, &async, (size_t)1, &(size_t){0}) < 0) {\ + if (errno != EINTR && errno)\ + return fail_return;\ + goto resync;\ + }\ + return recv_call + + +#define INTEGRAL_DEPTHS\ + case LIBCOOPGAMMA_UINT8:\ + case LIBCOOPGAMMA_UINT16:\ + case LIBCOOPGAMMA_UINT32:\ + case LIBCOOPGAMMA_UINT64: + + +/** + * Send a message to the server and wait for response + * + * @param resp:char** Output parameter for the response, + * will be NUL-terminated + * @param ctx:libcoopgamma_context_t* The state of the library + * @param payload:void* Data to append to the end of the message + * @param payload_size:size_t Byte-size of `payload` + * @param format:string-literal Message formatting string + * @param ... Message formatting arguments + * + * On error, the macro goes to `fail`. + */ +#define SEND_MESSAGE(ctx, payload, payload_size, format, ...)\ + do {\ + ssize_t n__;\ + char *msg__;\ + snprintf(NULL, (size_t)0, format "%zn", __VA_ARGS__, &n__);\ + msg__ = malloc((size_t)n__ + (payload_size) + (size_t)1);\ + if (!msg__)\ + goto fail;\ + sprintf(msg__, format, __VA_ARGS__);\ + if (payload)\ + memcpy(&msg__[n__], (payload), (payload_size));\ + if (libcoopgamma_send_message__((ctx), msg__, (size_t)n__ + (payload_size)) < 0)\ + goto fail;\ + } while (0) + + +/** + * Run coopgammad with -q or -qq and return the response + * + * SIGCHLD must not be ignored or blocked + * + * @param method The adjustment method, `NULL` for automatic + * @param site The site, `NULL` for automatic + * @param arg "-q" or "-qq", which shall be passed to coopgammad? + * @return The output of coopgammad, `NULL` on error. This + * will be NUL-terminated and will not contain any + * other `NUL` bytes. + */ +HIDDEN char *libcoopgamma_query__(const char *restrict method, const char *restrict site, const char *restrict arg); + +/** + * Send a message to the server and wait for response + * + * @param ctx The state of the library + * @param msg The message to send + * @param n The length of `msg` + * @return Zero on success, -1 on error + */ +HIDDEN int libcoopgamma_send_message__(libcoopgamma_context_t *restrict ctx, char *msg, size_t n); + +/** + * Check whether the server sent an error, if so copy it to `ctx` + * + * This function will also reports EBADMSG if the message ID + * that the message is a response to does not match the request + * information, or if it is missing + * + * @param ctx The state of the library, must be connected + * @param async Information about the request + * @return 1 if the server sent an error (even indicating success), + * 0 on success, -1 on failure. Information about failure + * is copied `ctx`. + */ +HIDDEN int libcoopgamma_check_error__(libcoopgamma_context_t *restrict ctx, libcoopgamma_async_context_t *restrict async); + + +/** + * Get the next header of the inbound message + * + * All headers must be read before the payload is read + * + * @param ctx The state of the library, must be connected + * @return The next header line, can never be `NULL`, + * the empty string marks the end of the headers. + * This memory segment must not be freed. + */ +HIDDEN inline char * +libcoopgamma_next_header__(libcoopgamma_context_t *restrict ctx) +{ + char *rc = ctx->inbound + ctx->inbound_tail; + ctx->inbound_tail += strlen(rc) + 1U; + return rc; +} + + +/** + * Get the payload of the inbound message + * + * Calling this function marks that the inbound message + * has been fully ready. You must call this function + * even if you do not expect a payload + * + * @param ctx The state of the library, must be connected + * @param n Output parameter for the size of the payload + * @return The payload (not NUL-terminated), `NULL` if + * there is no payload. Failure is impossible. + * This memory segment must not be freed. + */ +HIDDEN inline char * +libcoopgamma_next_payload__(libcoopgamma_context_t *restrict ctx, size_t *n) +{ + char *rc; + ctx->have_all_headers = 0; + if ((*n = ctx->length)) { + rc = ctx->inbound + ctx->inbound_tail; + ctx->inbound_tail += *n; + ctx->length = 0; + return rc; + } + return NULL; +} |