diff options
author | Mattias Andrée <maandree@kth.se> | 2019-10-22 15:04:45 +0200 |
---|---|---|
committer | Mattias Andrée <maandree@kth.se> | 2019-10-22 15:04:45 +0200 |
commit | b13efce73e506b0feb4bb7c275c273a54ae6e716 (patch) | |
tree | 79f93e69b01d236e96037aa60332d214696e048b /src/types | |
parent | Fix NULL-pointer bug in get_pathname when running with -mdrm (diff) | |
download | coopgammad-b13efce73e506b0feb4bb7c275c273a54ae6e716.tar.gz coopgammad-b13efce73e506b0feb4bb7c275c273a54ae6e716.tar.bz2 coopgammad-b13efce73e506b0feb4bb7c275c273a54ae6e716.tar.xz |
Change license and style, reorganise file, make makefile portable, and fix bugs1.3
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'src/types')
-rw-r--r-- | src/types/filter.c | 144 | ||||
-rw-r--r-- | src/types/filter.h | 138 | ||||
-rw-r--r-- | src/types/message.c | 572 | ||||
-rw-r--r-- | src/types/message.h | 160 | ||||
-rw-r--r-- | src/types/output.c | 335 | ||||
-rw-r--r-- | src/types/output.h | 308 | ||||
-rw-r--r-- | src/types/ramps.c | 98 | ||||
-rw-r--r-- | src/types/ramps.h | 102 | ||||
-rw-r--r-- | src/types/ring.c | 224 | ||||
-rw-r--r-- | src/types/ring.h | 152 |
10 files changed, 0 insertions, 2233 deletions
diff --git a/src/types/filter.c b/src/types/filter.c deleted file mode 100644 index e6facc9..0000000 --- a/src/types/filter.c +++ /dev/null @@ -1,144 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "filter.h" -#include "../util.h" - -#include <stdlib.h> -#include <string.h> - - - -/** - * Free all resources allocated to a filter. - * The allocation of `filter` itself is not freed. - * - * @param this The filter - */ -void filter_destroy(struct filter* restrict this) -{ - free(this->class); - free(this->ramps); -} - - - -#if defined(__clang__) -# pragma GCC diagnostic ignored "-Wcast-align" -#endif - - -/** - * Marshal a filter - * - * @param this The filter - * @param buf Output buffer for the marshalled filter, - * `NULL` just measure how large the buffers - * needs to be - * @param ramps_size The byte-size of `this->ramps` - * @return The number of marshalled byte - */ -size_t filter_marshal(const struct filter* restrict this, void* restrict buf, size_t ramps_size) -{ - size_t off = 0, n; - char nonnulls = 0; - char* restrict bs = buf; - - if (bs != NULL) - { - if (this->class != NULL) nonnulls |= 1; - if (this->ramps != NULL) nonnulls |= 2; - *(bs + off) = nonnulls; - } - off += 1; - - if (bs != NULL) - *(int64_t*)(bs + off) = this->priority; - off += sizeof(int64_t); - - if (bs != NULL) - *(enum lifespan*)(bs + off) = this->lifespan; - off += sizeof(enum lifespan); - - if (this->class != NULL) - { - n = strlen(this->class) + 1; - if (bs != NULL) - memcpy(bs + off, this->class, n); - off += n; - } - - if (this->ramps != NULL) - { - if (bs != NULL) - memcpy(bs + off, this->ramps, ramps_size); - off += ramps_size; - } - - return off; -} - - -/** - * Unmarshal a filter - * - * @param this Output for the filter - * @param buf Buffer with the marshalled filter - * @param ramps_size The byte-size of `this->ramps` - * @return The number of unmarshalled bytes, 0 on error - */ -size_t filter_unmarshal(struct filter* restrict this, const void* restrict buf, size_t ramps_size) -{ - size_t off = 0, n; - char nonnulls = 0; - const char* restrict bs = buf; - - nonnulls = *(bs + off); - off += 1; - - this->class = NULL; - this->ramps = NULL; - - this->priority = *(const int64_t*)(bs + off); - off += sizeof(int64_t); - - this->lifespan = *(const enum lifespan*)(bs + off); - off += sizeof(enum lifespan); - - if (nonnulls & 1) - { - n = strlen(bs + off) + 1; - if (!(this->class = memdup(bs + off, n))) - goto fail; - off += n; - } - - if (nonnulls & 2) - { - if (!(this->ramps = memdup(bs + off, ramps_size))) - goto fail; - off += ramps_size; - } - - return off; - - fail: - free(this->class); - free(this->ramps); - return 0; -} - diff --git a/src/types/filter.h b/src/types/filter.h deleted file mode 100644 index c91ccb2..0000000 --- a/src/types/filter.h +++ /dev/null @@ -1,138 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef TYPES_FILTER_H -#define TYPES_FILTER_H - - -#include <stddef.h> -#include <stdint.h> - - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * The lifespan of a filter - */ -enum lifespan -{ - /** - * The filter should be removed now - */ - LIFESPAN_REMOVE = 0, - - /** - * The filter should be applied - * until it is explicitly removed - */ - LIFESPAN_UNTIL_REMOVAL = 1, - - /** - * The filter should be applied - * until the client exists - */ - LIFESPAN_UNTIL_DEATH = 2 - -}; - - -/** - * Information about a filter - */ -struct filter -{ - /** - * The client that applied it. This need not be - * set unless `.lifespan == LIFESPAN_UNTIL_DEATH` - * and unless the process itself added this. - * This is the file descriptor of the client's - * connection. - */ - int client; - - /** - * The lifespan of the filter - */ - enum lifespan lifespan; - - /** - * The priority of the filter - */ - int64_t priority; - - /** - * Identifier for the filter - */ - char* class; - - /** - * The gamma ramp adjustments for the filter. - * This is raw binary data. `NULL` iff - * `lifespan == LIFESPAN_REMOVE`. - */ - void* ramps; - -}; - - - -/** - * Free all resources allocated to a filter. - * The allocation of `filter` itself is not freed. - * - * @param this The filter - */ -GCC_ONLY(__attribute__((nonnull))) -void filter_destroy(struct filter* restrict this); - -/** - * Marshal a filter - * - * @param this The filter - * @param buf Output buffer for the marshalled filter, - * `NULL` just measure how large the buffers - * needs to be - * @param ramps_size The byte-size of `filter->ramps` - * @return The number of marshalled byte - */ -GCC_ONLY(__attribute__((nonnull(1)))) -size_t filter_marshal(const struct filter* restrict this, void* restrict buf, size_t ramps_size); - -/** - * Unmarshal a filter - * - * @param this Output for the filter, `.red_size`, `.green_size`, - * and `.blue_size` must already be set - * @param buf Buffer with the marshalled filter - * @param ramps_size The byte-size of `filter->ramps` - * @return The number of unmarshalled bytes, 0 on error - */ -GCC_ONLY(__attribute__((nonnull))) -size_t filter_unmarshal(struct filter* restrict this, const void* restrict buf, size_t ramps_size); - - -#endif - diff --git a/src/types/message.c b/src/types/message.c deleted file mode 100644 index b0a6469..0000000 --- a/src/types/message.c +++ /dev/null @@ -1,572 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "message.h" -#include "../util.h" - -#include <sys/socket.h> -#include <errno.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - - - -/** - * Initialise a message slot so that it can - * be used by to read messages - * - * @param this Memory slot in which to store the new message - * @return Non-zero on error, `errno` will be set accordingly - */ -int message_initialise(struct message* restrict this) -{ - this->headers = NULL; - this->header_count = 0; - this->payload = NULL; - this->payload_size = 0; - this->payload_ptr = 0; - this->buffer_size = 128; - this->buffer_ptr = 0; - this->stage = 0; - this->buffer = malloc(this->buffer_size); - if (this->buffer == NULL) - return -1; - return 0; -} - - -/** - * Release all resources in a message, should - * be done even if initialisation fails - * - * @param this The message - */ -void message_destroy(struct message* restrict this) -{ - size_t i; - if (this->headers != NULL) - for (i = 0; i < this->header_count; i++) - free(this->headers[i]); - - free(this->headers); - free(this->payload); - free(this->buffer); -} - - - -#if defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-align" -#endif - - -/** - * Marshal a message for state serialisation - * - * @param this The message - * @param buf Output buffer for the marshalled data, - * `NULL` just measure how large the buffers - * needs to be - * @return The number of marshalled byte - */ -size_t message_marshal(const struct message* restrict this, void* restrict buf) -{ - size_t i, n, off = 0; - char* bs = buf; - - if (bs != NULL) - *(size_t*)(bs + off) = this->header_count; - off += sizeof(size_t); - - if (bs != NULL) - *(size_t*)(bs + off) = this->payload_size; - off += sizeof(size_t); - - if (bs != NULL) - *(size_t*)(bs + off) = this->payload_ptr; - off += sizeof(size_t); - - if (bs != NULL) - *(size_t*)(bs + off) = this->buffer_ptr; - off += sizeof(size_t); - - if (bs != NULL) - *(int*)(bs + off) = this->stage; - off += sizeof(int); - - for (i = 0; i < this->header_count; i++) - { - n = strlen(this->headers[i]) + 1; - if (bs != NULL) - memcpy(bs + off, this->headers[i], n); - off += n; - } - - if (bs != NULL) - memcpy(bs + off, this->payload, this->payload_ptr); - off += this->payload_ptr; - - if (bs != NULL) - memcpy(bs + off, this->buffer, this->buffer_ptr); - off += this->buffer_ptr; - - return off; -} - - -/** - * Unmarshal a message for state deserialisation - * - * @param this Memory slot in which to store the new message - * @param buf In buffer with the marshalled data - * @return The number of unmarshalled bytes, 0 on error - */ -size_t message_unmarshal(struct message* restrict this, const void* restrict buf) -{ - size_t i, n, off = 0, header_count; - const char* bs = buf; - - this->header_count = 0; - - header_count = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->payload_size = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->payload_ptr = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->buffer_size = this->buffer_ptr = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->stage = *(const int*)(bs + off); - off += sizeof(int); - - /* Make sure that the pointers are NULL so that they are - not freed without being allocated when the message is - destroyed if this function fails. */ - this->headers = NULL; - this->payload = NULL; - this->buffer = NULL; - - /* To 2-power-multiple of 128 bytes. */ - this->buffer_size >>= 7; - if (this->buffer_size == 0) - this->buffer_size = 1; - else - { - this->buffer_size -= 1; - this->buffer_size |= this->buffer_size >> 1; - this->buffer_size |= this->buffer_size >> 2; - this->buffer_size |= this->buffer_size >> 4; - this->buffer_size |= this->buffer_size >> 8; - this->buffer_size |= this->buffer_size >> 16; -#if SIZE_MAX == UINT64_MAX - this->buffer_size |= this->buffer_size >> 32; -#endif - this->buffer_size += 1; - } - this->buffer_size <<= 7; - - /* Allocate header list, payload and read buffer. */ - - if (header_count > 0) - if (!(this->headers = malloc(header_count * sizeof(char*)))) - goto fail; - - if (this->payload_size > 0) - if (!(this->payload = malloc(this->payload_size))) - goto fail; - - if (!(this->buffer = malloc(this->buffer_size))) - goto fail; - - /* Fill the header list, payload and read buffer. */ - - for (i = 0; i < header_count; i++) - { - n = strlen(bs + off) + 1; - this->headers[i] = memdup(bs + off, n); - if (this->headers[i] == NULL) - goto fail; - off += n; - this->header_count++; - } - - memcpy(this->payload, bs + off, this->payload_ptr); - off += this->payload_ptr; - - memcpy(this->buffer, bs + off, this->buffer_ptr); - off += this->buffer_ptr; - - return off; - - fail: - return 0; -} - - -#if defined(__clang__) -# pragma GCC diagnostic pop -#endif - - - -/** - * Extend the header list's allocation - * - * @param this The message - * @param extent The number of additional entries - * @return Zero on success, -1 on error - */ -GCC_ONLY(__attribute__((nonnull))) -static int extend_headers(struct message* restrict this, size_t extent) -{ - char** new; - if (!(new = realloc(this->headers, (this->header_count + extent) * sizeof(char*)))) - return -1; - this->headers = new; - return 0; -} - - -/** - * Extend the read buffer by way of doubling - * - * @param this The message - * @return Zero on success, -1 on error - */ -GCC_ONLY(__attribute__((nonnull))) -static int extend_buffer(struct message* restrict this) -{ - char* restrict new; - if (!(new = realloc(this->buffer, (this->buffer_size << 1) * sizeof(char)))) - return -1; - this->buffer = new; - this->buffer_size <<= 1; - return 0; -} - - -/** - * Reset the header list and the payload - * - * @param this The message - */ -GCC_ONLY(__attribute__((nonnull))) -static void reset_message(struct message* restrict this) -{ - size_t i; - if (this->headers != NULL) - for (i = 0; i < this->header_count; i++) - free(this->headers[i]); - free(this->headers); - this->headers = NULL; - this->header_count = 0; - - free(this->payload); - this->payload = NULL; - this->payload_size = 0; - this->payload_ptr = 0; -} - - -/** - * Read the headers the message and determine, and store, its payload's length - * - * @param this The message - * @return Zero on success, negative on error (malformated message: unrecoverable state) - */ -GCC_ONLY(__attribute__((pure, nonnull))) -static int get_payload_length(struct message* restrict this) -{ - char* header; - size_t i; - - for (i = 0; i < this->header_count; i++) - if (strstr(this->headers[i], "Length: ") == this->headers[i]) - { - /* Store the message length. */ - header = this->headers[i] + strlen("Length: "); - this->payload_size = (size_t)atol(header); - - /* Do not except a length that is not correctly formated. */ - for (; *header; header++) - if ((*header < '0') || ('9' < *header)) - return -2; /* Malformated value, enters unrecoverable state. */ - - /* Stop searching for the ‘Length’ header, we have found and parsed it. */ - break; - } - - return 0; -} - - -/** - * Verify that a header is correctly formatted - * - * @param header The header, must be NUL-terminated - * @param length The length of the header - * @return Zero if valid, negative if invalid (malformated message: unrecoverable state) - */ -GCC_ONLY(__attribute__((pure, nonnull))) -static int validate_header(const char* restrict header, size_t length) -{ - char* restrict p = memchr(header, ':', length * sizeof(char)); - - if (verify_utf8(header) < 0) - /* Either the string is not UTF-8, or your are under an UTF-8 attack, - let's just call this unrecoverable because the client will not correct. */ - return -2; - - if ((p == NULL) || /* Buck you, rawmemchr should not segfault the program. */ - (p[1] != ' ')) /* Also an invalid format. ' ' is mandated after the ':'. */ - return -2; - - return 0; -} - - -/** - * Remove the beginning of the read buffer - * - * @param this The message - * @param length The number of characters to remove - * @param update_ptr Whether to update the buffer pointer - */ -GCC_ONLY(__attribute__((nonnull))) -static void unbuffer_beginning(struct message* restrict this, size_t length, int update_ptr) -{ - memmove(this->buffer, this->buffer + length, (this->buffer_ptr - length) * sizeof(char)); - if (update_ptr) - this->buffer_ptr -= length; -} - - -/** - * Remove the header–payload delimiter from the buffer, - * get the payload's size and allocate the payload - * - * @param this The message - * @return The return value follows the rules of `message_read` - */ -GCC_ONLY(__attribute__((nonnull))) -static int initialise_payload(struct message* restrict this) -{ - /* Remove the \n (end of empty line) we found from the buffer. */ - unbuffer_beginning(this, 1, 1); - - /* Get the length of the payload. */ - if (get_payload_length(this) < 0) - return -2; /* Malformated value, enters unrecoverable state. */ - - /* Allocate the payload buffer. */ - if (this->payload_size > 0) - if (!(this->payload = malloc(this->payload_size))) - return -1; - - return 0; -} - - -/** - * Create a header from the buffer and store it - * - * @param this The message - * @param length The length of the header, including LF-termination - * @return The return value follows the rules of `message_read` - */ -GCC_ONLY(__attribute__((nonnull))) -static int store_header(struct message* restrict this, size_t length) -{ - char* restrict header; - - /* Allocate the header. */ - if (!(header = malloc(length))) /* Last char is a LF, which is substituted with NUL. */ - return -1; - /* Copy the header data into the allocated header, */ - memcpy(header, this->buffer, length * sizeof(char)); - /* and NUL-terminate it. */ - header[length - 1] = '\0'; - - /* Remove the header data from the read buffer. */ - unbuffer_beginning(this, length, 1); - - /* Make sure the the header syntax is correct so that - the program does not need to care about it. */ - if (validate_header(header, length)) - { - free(header); - return -2; - } - - /* Store the header in the header list. */ - this->headers[this->header_count++] = header; - - return 0; -} - - -/** - * Continue reading from the socket into the buffer - * - * @param this The message - * @param fd The file descriptor of the socket - * @return The return value follows the rules of `message_read` - */ -GCC_ONLY(__attribute__((nonnull))) -static int continue_read(struct message* restrict this, int fd) -{ - size_t n; - ssize_t got; - int r; - - /* Figure out how much space we have left in the read buffer. */ - n = this->buffer_size - this->buffer_ptr; - - /* If we do not have too much left, */ - if (n < 128) - { - /* grow the buffer, */ - if ((r = extend_buffer(this)) < 0) - return r; - - /* and recalculate how much space we have left. */ - n = this->buffer_size - this->buffer_ptr; - } - - /* Then read from the socket. */ - errno = 0; - got = recv(fd, this->buffer + this->buffer_ptr, n, 0); - this->buffer_ptr += (size_t)(got < 0 ? 0 : got); - if (errno) - return -1; - if (got == 0) - { - errno = ECONNRESET; - return -1; - } - - return 0; -} - - -/** - * Read the next message from a file descriptor - * - * @param this Memory slot in which to store the new message - * @param fd The file descriptor - * @return 0: At least one message is available - * -1: Exceptional connection: - * EINTR: System call interrupted - * EAGAIN: No message is available - * EWOULDBLOCK: No message is available - * ECONNRESET: Connection closed - * Other: Failure - * -2: Corrupt message (unrecoverable) - */ -GCC_ONLY(__attribute__((nonnull))) -int message_read(struct message* restrict this, int fd) -{ - size_t header_commit_buffer = 0; - int r; - - /* If we are at stage 2, we are done and it is time to start over. - This is important because the function could have been interrupted. */ - if (this->stage == 2) - { - reset_message(this); - this->stage = 0; - } - - /* Read from file descriptor until we have a full message. */ - for (;;) - { - char* p; - size_t length; - - /* Stage 0: headers. */ - /* Read all headers that we have stored into the read buffer. */ - while ((this->stage == 0) && - ((p = memchr(this->buffer, '\n', this->buffer_ptr * sizeof(char))) != NULL)) - if ((length = (size_t)(p - this->buffer))) - { - /* We have found a header. */ - - /* On every eighth header found with this function call, - we prepare the header list for eight more headers so - that it does not need to be reallocated again and again. */ - if (header_commit_buffer == 0) - if ((r = extend_headers(this, header_commit_buffer = 8)) < 0) - return r; - - /* Create and store header. */ - if ((r = store_header(this, length + 1)) < 0) - return r; - header_commit_buffer -= 1; - } - else - { - /* We have found an empty line, i.e. the end of the headers. */ - - /* Remove the header–payload delimiter from the buffer, - get the payload's size and allocate the payload. */ - if ((r = initialise_payload(this)) < 0) - return r; - - /* Mark end of stage, next stage is getting the payload. */ - this->stage = 1; - } - - - /* Stage 1: payload. */ - if ((this->stage == 1) && (this->payload_size > 0)) - { - /* How much of the payload that has not yet been filled. */ - size_t need = this->payload_size - this->payload_ptr; - /* How much we have of that what is needed. */ - size_t move = this->buffer_ptr < need ? this->buffer_ptr : need; - - /* Copy what we have, and remove it from the the read buffer. */ - memcpy(this->payload + this->payload_ptr, this->buffer, move * sizeof(char)); - unbuffer_beginning(this, move, 1); - - /* Keep track of how much we have read. */ - this->payload_ptr += move; - } - if ((this->stage == 1) && (this->payload_ptr == this->payload_size)) - { - /* If we have filled the payload (or there was no payload), - mark the end of this stage, i.e. that the message is - complete, and return with success. */ - this->stage = 2; - return 0; - } - - - /* If stage 1 was not completed. */ - - /* Continue reading from the socket into the buffer. */ - if ((r = continue_read(this, fd)) < 0) - return r; - } -} - diff --git a/src/types/message.h b/src/types/message.h deleted file mode 100644 index 0f1ade2..0000000 --- a/src/types/message.h +++ /dev/null @@ -1,160 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef TYPES_MESSAGE_H -#define TYPES_MESSAGE_H - - -#include <stddef.h> -#include <limits.h> - - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * Message passed between a server and a client - */ -struct message -{ - /** - * The headers in the message, each element in this list - * as an unparsed header, it consists of both the header - * name and its associated value, joined by ": ". A header - * cannot be `NULL` (unless its memory allocation failed,) - * but `headers` itself is `NULL` if there are no headers. - * The "Length" header should be included in this list. - */ - char** restrict headers; - - /** - * The number of headers in the message - */ - size_t header_count; - - /** - * The payload of the message, `NULL` if none (of zero-length) - */ - char* restrict payload; - - /** - * The size of the payload - */ - size_t payload_size; - - /** - * How much of the payload that has been stored (internal data) - */ - size_t payload_ptr; - - /** - * Internal buffer for the reading function (internal data) - */ - char* restrict buffer; - - /** - * The size allocated to `buffer` (internal data) - */ - size_t buffer_size; - - /** - * The number of bytes used in `buffer` (internal data) - */ - size_t buffer_ptr; - - /** - * 0 while reading headers, 1 while reading payload, and 2 when done (internal data) - */ - int stage; - -#if INT_MAX != LONG_MAX - int padding__; -#endif - -}; - - - -/** - * Initialise a message slot so that it can - * be used by to read messages - * - * @param this Memory slot in which to store the new message - * @return Non-zero on error, `errno` will be set accordingly - */ -GCC_ONLY(__attribute__((nonnull))) -int message_initialise(struct message* restrict this); - -/** - * Release all resources in a message, should - * be done even if initialisation fails - * - * @param this The message - */ -GCC_ONLY(__attribute__((nonnull))) -void message_destroy(struct message* restrict this); - -/** - * Marshal a message for state serialisation - * - * @param this The message - * @param buf Output buffer for the marshalled data, - * `NULL` just measure how large the buffers - * needs to be - * @return The number of marshalled byte - */ -GCC_ONLY(__attribute__((nonnull(1)))) -size_t message_marshal(const struct message* restrict this, void* restrict buf); - -/** - * Unmarshal a message for state deserialisation - * - * @param this Memory slot in which to store the new message - * @param buf In buffer with the marshalled data - * @return The number of unmarshalled bytes, 0 on error - */ -GCC_ONLY(__attribute__((nonnull))) -size_t message_unmarshal(struct message* restrict this, const void* restrict buf); - -/** - * Read the next message from a file descriptor - * - * @param this Memory slot in which to store the new message - * @param fd The file descriptor - * @return 0: At least one message is available - * -1: Exceptional connection: - * EINTR: System call interrupted - * EAGAIN: No message is available - * EWOULDBLOCK: No message is available - * ECONNRESET: Connection closed - * Other: Failure - * -2: Corrupt message (unrecoverable) - */ -GCC_ONLY(__attribute__((nonnull))) -int message_read(struct message* restrict this, int fd); - - -#endif - diff --git a/src/types/output.c b/src/types/output.c deleted file mode 100644 index b94d090..0000000 --- a/src/types/output.c +++ /dev/null @@ -1,335 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "output.h" -#include "../util.h" - -#include <stdlib.h> -#include <string.h> - - - -/** - * Free all resources allocated to an output. - * The allocation of `output` itself is not freed, - * nor is its the libgamma destroyed. - * - * @param this The output - */ -void output_destroy(struct output* restrict this) -{ - size_t i; - - if (this->supported != LIBGAMMA_NO) - switch (this->depth) - { - case 8: - libgamma_gamma_ramps8_destroy(&(this->saved_ramps.u8)); - for (i = 0; i < this->table_size; i++) - libgamma_gamma_ramps8_destroy(&(this->table_sums[i].u8)); - break; - case 16: - libgamma_gamma_ramps16_destroy(&(this->saved_ramps.u16)); - for (i = 0; i < this->table_size; i++) - libgamma_gamma_ramps16_destroy(&(this->table_sums[i].u16)); - break; - case 32: - libgamma_gamma_ramps32_destroy(&(this->saved_ramps.u32)); - for (i = 0; i < this->table_size; i++) - libgamma_gamma_ramps32_destroy(&(this->table_sums[i].u32)); - break; - case 64: - libgamma_gamma_ramps64_destroy(&(this->saved_ramps.u64)); - for (i = 0; i < this->table_size; i++) - libgamma_gamma_ramps64_destroy(&(this->table_sums[i].u64)); - break; - case -1: - libgamma_gamma_rampsf_destroy(&(this->saved_ramps.f)); - for (i = 0; i < this->table_size; i++) - libgamma_gamma_rampsf_destroy(&(this->table_sums[i].f)); - break; - case -2: - libgamma_gamma_rampsd_destroy(&(this->saved_ramps.d)); - for (i = 0; i < this->table_size; i++) - libgamma_gamma_rampsd_destroy(&(this->table_sums[i].d)); - break; - default: - break; /* impossible */ - } - - for (i = 0; i < this->table_size; i++) - filter_destroy(this->table_filters + i); - - free(this->table_filters); - free(this->table_sums); - free(this->name); -} - - - -#if defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-align" -#endif - - -/** - * Marshal an output - * - * @param this The output - * @param buf Output buffer for the marshalled output, - * `NULL` just measure how large the buffers - * needs to be - * @return The number of marshalled byte - */ -size_t output_marshal(const struct output* restrict this, void* restrict buf) -{ - size_t off = 0, i, n; - char* bs = buf; - - if (bs != NULL) - *(signed*)(bs + off) = this->depth; - off += sizeof(signed); - - if (bs != NULL) - *(size_t*)(bs + off) = this->red_size; - off += sizeof(size_t); - - if (bs != NULL) - *(size_t*)(bs + off) = this->green_size; - off += sizeof(size_t); - - if (bs != NULL) - *(size_t*)(bs + off) = this->blue_size; - off += sizeof(size_t); - - if (bs != NULL) - *(size_t*)(bs + off) = this->ramps_size; - off += sizeof(size_t); - - if (bs != NULL) - *(enum libgamma_decision*)(bs + off) = this->supported; - off += sizeof(enum libgamma_decision); - - if (bs != NULL) - *(enum colourspace*)(bs + off) = this->colourspace; - off += sizeof(enum colourspace); - - if (bs != NULL) - *(int*)(bs + off) = this->name_is_edid; - off += sizeof(int); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->red_x; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->red_y; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->green_x; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->green_y; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->blue_x; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->blue_y; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->white_x; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->white_y; - off += sizeof(unsigned); - - n = strlen(this->name) + 1; - if (bs != NULL) - memcpy(bs + off, this->name, n); - off += n; - - off += gamma_ramps_marshal(&(this->saved_ramps), bs ? bs + off : NULL, this->ramps_size); - - if (bs != NULL) - *(size_t*)(bs + off) = this->table_size; - off += sizeof(size_t); - - for (i = 0; i < this->table_size; i++) - { - off += filter_marshal(this->table_filters + i, bs ? bs + off : NULL, this->ramps_size); - off += gamma_ramps_marshal(this->table_sums + i, bs ? bs + off : NULL, this->ramps_size); - } - - return off; -} - - -/** - * Unmarshal an output - * - * @param this Output for the output - * @param buf Buffer with the marshalled output - * @return The number of unmarshalled bytes, 0 on error - */ -size_t output_unmarshal(struct output* restrict this, const void* restrict buf) -{ - size_t off = 0, i, n; - const char* bs = buf; - - this->crtc = NULL; - this->name = NULL; - - this->depth = *(const signed*)(bs + off); - off += sizeof(signed); - - this->red_size = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->green_size = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->blue_size = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->ramps_size = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->supported = *(const enum libgamma_decision*)(bs + off); - off += sizeof(enum libgamma_decision); - - this->colourspace = *(const enum colourspace*)(bs + off); - off += sizeof(enum colourspace); - - this->name_is_edid = *(const int*)(bs + off); - off += sizeof(int); - - this->red_x = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->red_y = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->green_x = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->green_y = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->blue_x = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->blue_y = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->white_x = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->white_y = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - n = strlen(bs + off) + 1; - this->name = memdup(bs + off, n); - if (this->name == NULL) - return 0; - off += n; - - COPY_RAMP_SIZES(&(this->saved_ramps.u8), this); - off += n = gamma_ramps_unmarshal(&(this->saved_ramps), bs + off, this->ramps_size); - if (n == 0) - return 0; - - this->table_size = this->table_alloc = *(const size_t*)(bs + off); - off += sizeof(size_t); - if (this->table_size > 0) - { - this->table_filters = calloc(this->table_size, sizeof(*(this->table_filters))); - if (this->table_filters == NULL) - return 0; - this->table_sums = calloc(this->table_size, sizeof(*(this->table_sums))); - if (this->table_sums == NULL) - return 0; - } - - for (i = 0; i < this->table_size; i++) - { - off += n = filter_unmarshal(this->table_filters + i, bs + off, this->ramps_size); - if (n == 0) - return 0; - COPY_RAMP_SIZES(&(this->table_sums[i].u8), this); - off += n = gamma_ramps_unmarshal(this->table_sums + i, bs + off, this->ramps_size); - if (n == 0) - return 0; - } - - return off; -} - - -#if defined(__clang__) -# pragma GCC diagnostic pop -#endif - - - -/** - * Compare to outputs by the names of their respective CRTC:s - * - * @param a Return -1 if this one is lower - * @param b Return +1 if this one is higher - * @return See description of `a` and `b`, - * 0 if returned if they are the same - */ -int output_cmp_by_name(const void* restrict a, const void* restrict b) -{ - const char* an = ((const struct output*)a)->name; - const char* bn = ((const struct output*)b)->name; - return strcmp(an, bn); -} - - -/** - * Find an output by its name - * - * @param key The name of the output - * @param base The array of outputs - * @param n The number of elements in `base` - * @return Output find in `base`, `NULL` if not found - */ -struct output* output_find_by_name(const char* restrict key, struct output* restrict base, size_t n) -{ - struct output k; - -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-qual" -#endif - k.name = (char*)key; -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#endif - - return bsearch(&k, base, n, sizeof(*base), output_cmp_by_name); -} - diff --git a/src/types/output.h b/src/types/output.h deleted file mode 100644 index 750ec41..0000000 --- a/src/types/output.h +++ /dev/null @@ -1,308 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef TYPES_OUTPUT_H -#define TYPES_OUTPUT_H - - -#include <stddef.h> - -#include <libgamma.h> - -#include "ramps.h" -#include "filter.h" - - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * Copy the ramp sizes - * - * This macro supports both `struct output` - * and `struct gamma_ramps` - * - * @param dest The destination - * @param src The source - */ -#define COPY_RAMP_SIZES(dest, src) \ - ((dest)->red_size = (src)->red_size, \ - (dest)->green_size = (src)->green_size, \ - (dest)->blue_size = (src)->blue_size) - - - -/** - * Colour spaces - */ -enum colourspace -{ - - /** - * Unknown - */ - COLOURSPACE_UNKNOWN = 0, - - /** - * sRGB with explicit gamut - */ - COLOURSPACE_SRGB = 1, - - /** - * sRGB without explicit gamut - */ - COLOURSPACE_SRGB_SANS_GAMUT = 2, - - /** - * RGB (but not sRGB) with known gamut - */ - COLOURSPACE_RGB = 3, - - /** - * RGB (but not sRGB) without known gamut - */ - COLOURSPACE_RGB_SANS_GAMUT = 4, - - /** - * Non-RGB multicolour - */ - COLOURSPACE_NON_RGB = 5, - - /** - * Greyscale or monochrome - */ - COLOURSPACE_GREY = 6 -}; - - - -/** - * Information about an output - */ -struct output -{ - /** - * -2: double - * -1: float - * 8: uint8_t - * 16: uint16_t - * 32: uint32_t - * 64: uint64_t - */ - signed depth; - - /** - * Whether gamma ramps are supported - */ - enum libgamma_decision supported; - - /** - * Whether the name is the EDID - */ - int name_is_edid; - - /** - * The monitor's colour space - */ - enum colourspace colourspace; - - /** - * The x-value (CIE xyY) of the monitor's - * red colour, multiplied by 1024 - */ - unsigned red_x; - - /** - * The y-value (CIE xyY) of the monitor's - * red colour, multiplied by 1024 - */ - unsigned red_y; - - /** - * The x-value (CIE xyY) of the monitor's - * green colour, multiplied by 1024 - */ - unsigned green_x; - - /** - * The y-value (CIE xyY) of the monitor's - * green colour, multiplied by 1024 - */ - unsigned green_y; - - /** - * The x-value (CIE xyY) of the monitor's - * blue colour, multiplied by 1024 - */ - unsigned blue_x; - - /** - * The y-value (CIE xyY) of the monitor's - * blue colour, multiplied by 1024 - */ - unsigned blue_y; - - /** - * The x-value (CIE xyY) of the monitor's - * default white point, multiplied by 1024 - */ - unsigned white_x; - - /** - * The y-value (CIE xyY) of the monitor's - * default white point, multiplied by 1024 - */ - unsigned white_y; - - /** - * The number of stops in the red gamma ramp - */ - size_t red_size; - - /** - * The number of stops in the green gamma ramp - */ - size_t green_size; - - /** - * The number of stops in the blue gamma ramp - */ - size_t blue_size; - - /** - * `.red_size + .green_size + .blue_size` - * multiplied by the byte-size of each stop - */ - size_t ramps_size; - - /** - * The name of the output, will be its EDID - * if available, otherwise it will be the - * index of the partition, followed by a dot - * and the index of the CRTC within the - * partition, or if a name for the connector - * is available: the index of the partition - * followed by a dot and the name of the - * connector - */ - char* restrict name; - - /** - * The libgamma state for the output - */ - libgamma_crtc_state_t* restrict crtc; - - /** - * Saved gamma ramps - */ - union gamma_ramps saved_ramps; - - /** - * The table of all applied filters - */ - struct filter* restrict table_filters; - - /** - * `.table_sums[i]` is the resulting - * adjustment made when all filter - * from `.table_filters[0]` up to and - * including `.table_filters[i]` has - * been applied - */ - union gamma_ramps* restrict table_sums; - - /** - * The number of elements allocated - * for `.table_filters` and for `.table_sums` - */ - size_t table_alloc; - - /** - * The number of elements stored in - * `.table_filters` and in `.table_sums` - */ - size_t table_size; - -}; - - - -/** - * Free all resources allocated to an output. - * The allocation of `output` itself is not freed, - * nor is its the libgamma destroyed. - * - * @param this The output - */ -GCC_ONLY(__attribute__((nonnull))) -void output_destroy(struct output* restrict this); - -/** - * Marshal an output - * - * @param this The output - * @param buf Output buffer for the marshalled output, - * `NULL` just measure how large the buffers - * needs to be - * @return The number of marshalled byte - */ -GCC_ONLY(__attribute__((nonnull(1)))) -size_t output_marshal(const struct output* restrict this, void* restrict buf); - -/** - * Unmarshal an output - * - * @param this Output for the output - * @param buf Buffer with the marshalled output - * @return The number of unmarshalled bytes, 0 on error - */ -GCC_ONLY(__attribute__((nonnull))) -size_t output_unmarshal(struct output* restrict this, const void* restrict buf); - -/** - * Compare to outputs by the names of their respective CRTC:s - * - * @param a Return -1 if this one is lower - * @param b Return +1 if this one is higher - * @return See description of `a` and `b`, - * 0 if returned if they are the same - */ -GCC_ONLY(__attribute__((pure, nonnull))) -int output_cmp_by_name(const void* restrict a, const void* restrict b); - -/** - * Find an output by its name - * - * @param key The name of the output - * @param base The array of outputs - * @param n The number of elements in `base` - * @return Output find in `base`, `NULL` if not found - */ -GCC_ONLY(__attribute__((pure, nonnull))) -struct output* output_find_by_name(const char* restrict key, struct output* restrict base, size_t n); - - -#endif - diff --git a/src/types/ramps.c b/src/types/ramps.c deleted file mode 100644 index 30bed3e..0000000 --- a/src/types/ramps.c +++ /dev/null @@ -1,98 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "ramps.h" - -#include <libclut.h> - -#include <errno.h> -#include <stdlib.h> -#include <string.h> - - - -/** - * The name of the process - */ -extern char* restrict argv0; - - - -/** - * Marshal a ramp trio - * - * @param this The ramps - * @param buf Output buffer for the marshalled ramps, - * `NULL` just measure how large the buffers - * needs to be - * @param ramps_size The byte-size of ramps - * @return The number of marshalled byte - */ -size_t gamma_ramps_marshal(const union gamma_ramps* restrict this, void* restrict buf, size_t ramps_size) -{ - if (buf != NULL) - memcpy(buf, this->u8.red, ramps_size); - return ramps_size; -} - - -/** - * Unmarshal a ramp trio - * - * @param this Output for the ramps, `.red_size`, `.green_size`, - * and `.blue_size` must already be set - * @param buf Buffer with the marshalled ramps - * @param ramps_size The byte-size of ramps - * @return The number of unmarshalled bytes, 0 on error - */ -size_t gamma_ramps_unmarshal(union gamma_ramps* restrict this, const void* restrict buf, size_t ramps_size) -{ - size_t depth = ramps_size / (this->u8.red_size + this->u8.green_size + this->u8.blue_size); - int r = 0; - switch (depth) - { - case 1: - r = libgamma_gamma_ramps8_initialise(&(this->u8)); - break; - case 2: - r = libgamma_gamma_ramps16_initialise(&(this->u16)); - break; - case 4: - r = libgamma_gamma_ramps32_initialise(&(this->u32)); - break; - case 8: - r = libgamma_gamma_ramps64_initialise(&(this->u64)); - break; - default: - if (depth == sizeof(float)) - r = libgamma_gamma_rampsf_initialise(&(this->f)); - else if (depth == sizeof(double)) - r = libgamma_gamma_rampsd_initialise(&(this->d)); - else - abort(); - break; - } - if (r) - { - libgamma_perror(argv0, r); - errno = 0; - return 0; - } - memcpy(this->u8.red, buf, ramps_size); - return ramps_size; -} - diff --git a/src/types/ramps.h b/src/types/ramps.h deleted file mode 100644 index 001d504..0000000 --- a/src/types/ramps.h +++ /dev/null @@ -1,102 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef TYPES_RAMPS_H -#define TYPES_RAMPS_H - - -#include <libgamma.h> - - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * Gamma ramps union for all - * lbigamma gamma ramps types - */ -union gamma_ramps -{ - /** - * Ramps with 8-bit value - */ - libgamma_gamma_ramps8_t u8; - - /** - * Ramps with 16-bit value - */ - libgamma_gamma_ramps16_t u16; - - /** - * Ramps with 32-bit value - */ - libgamma_gamma_ramps32_t u32; - - /** - * Ramps with 64-bit value - */ - libgamma_gamma_ramps64_t u64; - - /** - * Ramps with `float` value - */ - libgamma_gamma_rampsf_t f; - - /** - * Ramps with `double` value - */ - libgamma_gamma_rampsd_t d; - -}; - - - -/** - * Marshal a ramp trio - * - * @param this The ramps - * @param buf Output buffer for the marshalled ramps, - * `NULL` just measure how large the buffers - * needs to be - * @param ramps_size The byte-size of ramps - * @return The number of marshalled byte - */ -GCC_ONLY(__attribute__((nonnull(1)))) -size_t gamma_ramps_marshal(const union gamma_ramps* restrict this, void* restrict buf, size_t ramps_size); - -/** - * Unmarshal a ramp trio - * - * @param this Output for the ramps - * @param buf Buffer with the marshalled ramps - * @param ramps_size The byte-size of ramps - * @return The number of unmarshalled bytes, 0 on error - */ -GCC_ONLY(__attribute__((nonnull))) -size_t gamma_ramps_unmarshal(union gamma_ramps* restrict this, const void* restrict buf, size_t ramps_size); - - -#endif - diff --git a/src/types/ring.c b/src/types/ring.c deleted file mode 100644 index 13cf8c9..0000000 --- a/src/types/ring.c +++ /dev/null @@ -1,224 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "ring.h" - -#include <stdlib.h> -#include <string.h> - - - -/** - * Initialise a ring buffer - * - * @param this The ring buffer - */ -void ring_initialise(struct ring* restrict this) -{ - this->start = 0; - this->end = 0; - this->size = 0; - this->buffer = NULL; -} - - -/** - * Release resource allocated to a ring buffer - * - * @param this The ring buffer - */ -void ring_destroy(struct ring* restrict this) -{ - free(this->buffer); -} - - - -#if defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-align" -#endif - - -/** - * Marshal a ring buffer - * - * @param this The ring buffer - * @param buf Output buffer for the marshalled data, - * `NULL` to only measure how large buffer - * is needed - * @return The number of marshalled bytes - */ -size_t ring_marshal(const struct ring* restrict this, void* restrict buf) -{ - size_t off = 0, n = this->end - this->start; - char* bs = buf; - - if (bs != NULL) - *(size_t*)(bs + off) = n; - off += sizeof(size_t); - - if (bs != NULL) - memcpy(bs + off, this->buffer + this->start, n); - off += n; - - return off; -} - - -/** - * Unmarshal a ring buffer - * - * @param this Output parameter for the ring buffer - * @param buf Buffer with the marshalled data - * @return The number of unmarshalled bytes, 0 on error - */ -size_t ring_unmarshal(struct ring* restrict this, const void* restrict buf) -{ - size_t off = 0; - const char* bs = buf; - - ring_initialise(this); - - this->size = this->end = *(const size_t*)(bs + off); - off += sizeof(size_t); - - if (this->end > 0) - { - if (!(this->buffer = malloc(this->end))) - return 0; - - memcpy(this->buffer, bs + off, this->end); - off += this->end; - } - - return off; -} - - -#if defined(__clang__) -# pragma GCC diagnostic pop -#endif - - - -/** - * Append data to a ring buffer - * - * @param this The ring buffer - * @param data The new data - * @param n The number of bytes in `data` - * @return Zero on success, -1 on error - */ -int ring_push(struct ring* restrict this, void* restrict data, size_t n) -{ - size_t used = 0; - - if (this->start == this->end) - { - if (this->buffer != NULL) - used = this->size; - } - else if (this->start > this->end) - used = this->size - this->start + this->end; - else - used = this->start - this->end; - - if (used + n > this->size) - { - char* restrict new = malloc(used + n); - if (new == NULL) - return -1; - if (this->buffer) - { - if (this->start < this->end) - memcpy(new, this->buffer + this->start, this->end - this->start); - else - { - memcpy(new, this->buffer + this->start, this->size - this->start); - memcpy(new + this->size - this->start, this->buffer, this->end); - } - } - memcpy(new + used, data, n); - this->buffer = new; - this->start = 0; - this->end = used + n; - this->size = used + n; - } - else if ((this->start >= this->end) || (this->end + n <= this->size)) - { - memcpy(this->buffer + this->end, data, n); - this->end += n; - } - else - { - memcpy(this->buffer + this->end, data, this->size - this->end); - data = (char*)data + (this->size - this->end); - n -= this->size - this->end; - memcpy(this->buffer, data, n); - this->end = n; - } - - return 0; -} - - -/** - * Get queued data from a ring buffer - * - * It can take up to two calls (with `ring_pop` between) - * to get all queued data - * - * @param this The ring buffer - * @param n Output parameter for the length - * of the returned segment - * @return The beginning of the queued data, - * `NULL` if there is nothing more - */ -void* ring_peek(struct ring* restrict this, size_t* restrict n) -{ - if (this->buffer == NULL) - return *n = 0, NULL; - - if (this->start < this->end) - *n = this->end - this->start; - else - *n = this->size - this->start; - return this->buffer + this->start; -} - - -/** - * Dequeue data from a ring bubber - * - * @param this The ring buffer - * @param n The number of bytes to dequeue - */ -void ring_pop(struct ring* restrict this, size_t n) -{ - this->start += n; - this->start %= this->size; - if (this->start == this->end) - { - free(this->buffer); - this->start = 0; - this->end = 0; - this->size = 0; - this->buffer = NULL; - } -} - diff --git a/src/types/ring.h b/src/types/ring.h deleted file mode 100644 index 0474f39..0000000 --- a/src/types/ring.h +++ /dev/null @@ -1,152 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef TYPES_RING_H -#define TYPES_RING_H - - -#include <stddef.h> - - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * Ring buffer - */ -struct ring -{ - /** - * Buffer for the data - */ - char* restrict buffer; - - /** - * The first set byte in `.buffer` - */ - size_t start; - - /** - * The last set byte in `.buffer`, plus 1 - */ - size_t end; - - /** - * The size of `.buffer` - */ - size_t size; -}; - - - -/** - * Initialise a ring buffer - * - * @param this The ring buffer - */ -GCC_ONLY(__attribute__((nonnull))) -void ring_initialise(struct ring* restrict this); - -/** - * Release resource allocated to a ring buffer - * - * @param this The ring buffer - */ -GCC_ONLY(__attribute__((nonnull))) -void ring_destroy(struct ring* restrict this); - -/** - * Marshal a ring buffer - * - * @param this The ring buffer - * @param buf Output buffer for the marshalled data, - * `NULL` to only measure how large buffer - * is needed - * @return The number of marshalled bytes - */ -GCC_ONLY(__attribute__((nonnull(1)))) -size_t ring_marshal(const struct ring* restrict this, void* restrict buf); - -/** - * Unmarshal a ring buffer - * - * @param this Output parameter for the ring buffer - * @param buf Buffer with the marshalled data - * @return The number of unmarshalled bytes, 0 on error - */ -GCC_ONLY(__attribute__((nonnull))) -size_t ring_unmarshal(struct ring* restrict this, const void* restrict buf); - -/** - * Append data to a ring buffer - * - * @param this The ring buffer - * @param data The new data - * @param n The number of bytes in `data` - * @return Zero on success, -1 on error - */ -GCC_ONLY(__attribute__((nonnull(1)))) -int ring_push(struct ring* restrict this, void* restrict data, size_t n); - -/** - * Get queued data from a ring buffer - * - * It can take up to two calls (with `ring_pop` between) - * to get all queued data - * - * @param this The ring buffer - * @param n Output parameter for the length - * of the returned segment - * @return The beginning of the queued data, - * `NULL` if there is nothing more - */ -GCC_ONLY(__attribute__((nonnull))) -void* ring_peek(struct ring* restrict this, size_t* restrict n); - -/** - * Dequeue data from a ring bubber - * - * @param this The ring buffer - * @param n The number of bytes to dequeue - */ -GCC_ONLY(__attribute__((nonnull))) -void ring_pop(struct ring* restrict this, size_t n); - -/** - * Check whether there is more data waiting - * in a ring buffer - * - * @param this The ring buffer - * @return 1 if there is more data, 0 otherwise - */ -GCC_ONLY(__attribute__((nonnull))) -static inline int ring_have_more(struct ring* restrict this) -{ - return this->buffer != NULL; -} - - -#endif - |