diff options
-rw-r--r-- | Makefile | 18 | ||||
-rw-r--r-- | src/arg.h | 2 | ||||
-rw-r--r-- | src/communication.c | 171 | ||||
-rw-r--r-- | src/communication.h | 137 | ||||
-rw-r--r-- | src/coopgamma-server/chaining.c | 257 | ||||
-rw-r--r-- | src/coopgamma-server/chaining.h | 75 | ||||
-rw-r--r-- | src/coopgamma-server/server.c | 335 | ||||
-rw-r--r-- | src/coopgamma-server/server.h | 93 | ||||
-rw-r--r-- | src/coopgammad.c | 265 | ||||
-rw-r--r-- | src/crtc-server/server.c | 59 | ||||
-rw-r--r-- | src/crtc-server/server.h | 49 | ||||
-rw-r--r-- | src/gamma-server/server.c | 144 | ||||
-rw-r--r-- | src/gamma-server/server.h | 75 | ||||
-rw-r--r-- | src/server.c | 810 | ||||
-rw-r--r-- | src/server.h | 79 | ||||
-rw-r--r-- | src/state.c | 363 | ||||
-rw-r--r-- | src/state.h | 182 | ||||
-rw-r--r-- | src/types/filter.c (renamed from src/filter.c) | 2 | ||||
-rw-r--r-- | src/types/filter.h (renamed from src/filter.h) | 7 | ||||
-rw-r--r-- | src/types/message.c (renamed from src/message.c) | 2 | ||||
-rw-r--r-- | src/types/message.h (renamed from src/message.h) | 7 | ||||
-rw-r--r-- | src/types/output.c (renamed from src/output.c) | 220 | ||||
-rw-r--r-- | src/types/output.h (renamed from src/output.h) | 34 | ||||
-rw-r--r-- | src/types/ramps.c (renamed from src/ramps.c) | 67 | ||||
-rw-r--r-- | src/types/ramps.h (renamed from src/ramps.h) | 21 | ||||
-rw-r--r-- | src/types/ring.c (renamed from src/ring.c) | 0 | ||||
-rw-r--r-- | src/types/ring.h (renamed from src/ring.h) | 7 | ||||
-rw-r--r-- | src/util.h | 7 |
28 files changed, 2075 insertions, 1413 deletions
@@ -3,7 +3,21 @@ COMMAND = coopgammad KERNEL = $(shell uname | tr '[A-Z]_' '[a-z]-') -SRC = filter coopgammad output ramps util message server ring +SRC = \ + coopgammad \ + server \ + util \ + communication \ + state \ + crtc-server/server \ + gamma-server/server \ + coopgamma-server/server \ + coopgamma-server/chaining \ + types/filter \ + types/output \ + types/ramps \ + types/message \ + types/ring OPTIMISE = -Og -g @@ -34,7 +48,7 @@ bin/coopgammad: $(foreach S,$(SRC),obj/$(S).o) @mkdir -p -- "$$(dirname -- "$@")" $(CC) $(LDFLAGS) -o $@ $^ -obj/%.o: src/%.c src/*.h +obj/%.o: src/%.c src/*.h src/*/*.h @mkdir -p -- "$$(dirname -- "$@")" $(CC) $(CCFLAGS) $(CPPFLAGS) -c -o $@ $< @@ -6,8 +6,6 @@ #ifndef ARG_H__ #define ARG_H__ -extern char *restrict argv0; - /* use main(int argc, char *argv[]) */ #define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ argv[0] && argv[0][0] == '-'\ diff --git a/src/communication.c b/src/communication.c new file mode 100644 index 0000000..c508992 --- /dev/null +++ b/src/communication.c @@ -0,0 +1,171 @@ +/** + * 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 "communication.h" +#include "state.h" +#include "coopgamma-server/server.h" + +#include <sys/socket.h> +#include <errno.h> +#include <string.h> + + + +/** + * Send a message + * + * @param conn The index of the connection + * @param buf The data to send + * @param n The size of `buf` + * @return Zero on success, -1 on error, 1 if disconncted + * EINTR, EAGAIN, EWOULDBLOCK, and ECONNRESET count + * as success (ECONNRESET cause 1 to be returned), + * and are handled appropriately. + */ +int send_message(size_t conn, char* restrict buf, size_t n) +{ + struct ring* restrict ring = outbound + conn; + int fd = connections[conn]; + int saved_errno; + size_t ptr = 0; + ssize_t sent; + size_t chunksize = n; + size_t sendsize; + size_t old_n; + char* old_buf; + + while ((old_buf = ring_peek(ring, &old_n))) + { + size_t old_ptr = 0; + while (old_ptr < n) + { + sendsize = old_n - old_ptr < chunksize ? old_n - old_ptr : chunksize; + sent = send(fd, old_buf + old_ptr, sendsize, 0); + if (sent < 0) + { + if (errno != EMSGSIZE) + goto fail; + chunksize >>= 1; + if (chunksize == 0) + goto fail; + continue; + } + old_ptr += (size_t)sent; + ring_pop(ring, (size_t)sent); + } + } + + while (ptr < n) + { + sendsize = n - ptr < chunksize ? n - ptr : chunksize; + sent = send(fd, buf + ptr, sendsize, 0); + if (sent < 0) + { + if (errno != EMSGSIZE) + goto fail; + chunksize >>= 1; + if (chunksize == 0) + goto fail; + continue; + } + ptr += (size_t)sent; + } + + free(buf); + return 0; + + fail: + switch (errno) + { + case EINTR: + case EAGAIN: +#if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: +#endif + if (ring_push(ring, buf + ptr, n - ptr) < 0) + goto proper_fail; + free(buf); + return 0; + case ECONNRESET: + free(buf); + if (connection_closed(fd) < 0) + return -1; + return 1; + default: + break; + } + proper_fail: + saved_errno = errno; + free(buf); + errno = saved_errno; + return -1; +} + + +/** + * Send a custom error without an error number + * + * @param conn The index of the connection + * @param message_id The ID of the message to which this message is a response + * @param desc The error description to send + * @return 1: Client disconnected + * 0: Success (possibily delayed) + * -1: An error occurred + */ +int (send_error)(size_t conn, const char* restrict message_id, const char* restrict desc) +{ + char* restrict buf; + size_t n; + + MAKE_MESSAGE(&buf, &n, 0, + "Command: error\n" + "In response to: %s\n" + "Error: custom\n" + "Length: %zu\n" + "\n" + "%s\n", + message_id, strlen(desc) + 1, desc); + + return send_message(conn, buf, n); +} + + +/** + * Send a standard error + * + * @param conn The index of the connection + * @param message_id The ID of the message to which this message is a response + * @param number The value of `errno`, 0 to indicate success + * @return 1: Client disconnected + * 0: Success (possibily delayed) + * -1: An error occurred + */ +int (send_errno)(size_t conn, const char* restrict message_id, int number) +{ + char* restrict buf; + size_t n; + + MAKE_MESSAGE(&buf, &n, 0, + "Command: error\n" + "In response to: %s\n" + "Error: %i\n" + "\n", + message_id, number); + + return send_message(conn, buf, n); +} + diff --git a/src/communication.h b/src/communication.h new file mode 100644 index 0000000..43af314 --- /dev/null +++ b/src/communication.h @@ -0,0 +1,137 @@ +/** + * 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 COMMUNICATION_H +#define COMMUNICATION_H + + +#include <stdio.h> +#include <stdlib.h> + + + +#ifndef GCC_ONLY +# if defined(__GNUC__) && !defined(__clang__) +# define GCC_ONLY(...) __VA_ARGS__ +# else +# define GCC_ONLY(...) /* nothing */ +# endif +#endif + + + +/** + * Construct a message + * + * @param bufp:char** Output parameter for the buffer, must not have side-effects + * @param np:size_t* Output parameter for the size of the buffer sans `extra` + * @param extra:size_t The extra number for bytes to allocate to the buffer + * @param format:string-literal Message format string + * @param ... Message formatting arguments + */ +#define MAKE_MESSAGE(bufp, np, extra, format, ...) \ + do \ + { \ + ssize_t m__; \ + snprintf(NULL, 0, format "%zn", __VA_ARGS__, &m__); \ + *(bufp) = malloc((size_t)(extra) + (size_t)m__); \ + if (*(bufp) == NULL) \ + return -1; \ + sprintf(*(bufp), format, __VA_ARGS__); \ + *(np) = (size_t)m__; \ + } \ + while (0) + +/** + * Send a custom error without an error number + * + * @param ... The error description to send + * @return 1: Client disconnected + * 0: Success (possibily delayed) + * -1: An error occurred + */ +#define send_error(...) ((send_error)(conn, message_id, __VA_ARGS__)) + +/** + * Send a standard error + * + * @param ... The value of `errno`, 0 to indicate success + * @return 1: Client disconnected + * 0: Success (possibily delayed) + * -1: An error occurred + */ +#define send_errno(...) ((send_errno)(conn, message_id, __VA_ARGS__)) + + + +/** + * Send a message + * + * @param conn The index of the connection + * @param buf The data to send + * @param n The size of `buf` + * @return Zero on success, -1 on error, 1 if disconncted + * EINTR, EAGAIN, EWOULDBLOCK, and ECONNRESET count + * as success (ECONNRESET cause 1 to be returned), + * and are handled appropriately. + */ +int send_message(size_t conn, char* restrict buf, size_t n); + +/** + * Send a custom error without an error number + * + * @param conn The index of the connection + * @param message_id The ID of the message to which this message is a response + * @param desc The error description to send + * @return 1: Client disconnected + * 0: Success (possibily delayed) + * -1: An error occurred + */ +GCC_ONLY(__attribute__((nonnull))) +int (send_error)(size_t conn, const char* restrict message_id, const char* restrict desc); + +/** + * Send a standard error + * + * @param conn The index of the connection + * @param message_id The ID of the message to which this message is a response + * @param number The value of `errno`, 0 to indicate success + * @return 1: Client disconnected + * 0: Success (possibily delayed) + * -1: An error occurred + */ +GCC_ONLY(__attribute__((nonnull))) +int (send_errno)(size_t conn, const char* restrict message_id, int number); + +/** + * Continue sending the queued messages + * + * @param conn The index of the connection + * @return Zero on success, -1 on error, 1 if disconncted + * EINTR, EAGAIN, EWOULDBLOCK, and ECONNRESET count + * as success (ECONNRESET cause 1 to be returned), + * and are handled appropriately. + */ +static inline int continue_send(size_t conn) +{ + return send_message(conn, NULL, 0); +} + + + +#endif + diff --git a/src/coopgamma-server/chaining.c b/src/coopgamma-server/chaining.c new file mode 100644 index 0000000..b2739c2 --- /dev/null +++ b/src/coopgamma-server/chaining.c @@ -0,0 +1,257 @@ +/** + * 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 "chaining.h" + +#include <libclut.h> + +#include <stdio.h> +#include <stdlib.h> + + + +/** + * The name of the process + */ +extern char* restrict argv0; + + + +/** + * Apply a filter on top of another filter + * + * @param dest The output for the resulting ramp-trio, must be initialised + * @param application The red, green and blue ramps, as one single raw array, + * of the filter that should be applied + * @param depth -1: `float` stops + * -2: `double` stops + * Other: the number of bits of each (integral) stop + * @param base The CLUT on top of which the new filter should be applied, + * this can be the same pointer as `dest` + */ +void apply_filter(union gamma_ramps* restrict dest, void* restrict application, + int depth, union gamma_ramps* restrict base) +{ + union gamma_ramps app; + size_t bytedepth; + size_t red_width, green_width, blue_width; + + if (depth == -1) + bytedepth = sizeof(float); + else if (depth == -2) + bytedepth = sizeof(double); + else + bytedepth = (size_t)depth / 8; + + red_width = (app.u8.red_size = base->u8.red_size) * bytedepth; + green_width = (app.u8.green_size = base->u8.green_size) * bytedepth; + blue_width = (app.u8.blue_size = base->u8.blue_size) * bytedepth; + + app.u8.red = application; + app.u8.green = app.u8.red + red_width; + app.u8.blue = app.u8.green + green_width; + + if (dest != base) + { + memcpy(dest->u8.red, base->u8.red, red_width); + memcpy(dest->u8.green, base->u8.green, green_width); + memcpy(dest->u8.blue, base->u8.blue, blue_width); + } + + switch (depth) + { + case 8: + libclut_apply(&(dest->u8), UINT8_MAX, uint8_t, &(app.u8), UINT8_MAX, uint8_t, 1, 1, 1); + break; + case 16: + libclut_apply(&(dest->u16), UINT16_MAX, uint16_t, &(app.u16), UINT16_MAX, uint16_t, 1, 1, 1); + break; + case 32: + libclut_apply(&(dest->u32), UINT32_MAX, uint32_t, &(app.u32), UINT32_MAX, uint32_t, 1, 1, 1); + break; + case 64: + libclut_apply(&(dest->u64), UINT64_MAX, uint64_t, &(app.u64), UINT64_MAX, uint64_t, 1, 1, 1); + break; + case -1: + libclut_apply(&(dest->f), 1.0f, float, &(app.d), 1.0f, float, 1, 1, 1); + break; + case -2: + libclut_apply(&(dest->d), (double)1, double, &(app.f), (double)1, double, 1, 1, 1); + break; + default: + abort(); + } +} + + + +/** + * Remove a filter from an output + * + * @param out The output + * @param filter The filter + * @return The index of the filter, `out->table_size` if not found + */ +static ssize_t remove_filter(struct output* restrict out, struct filter* restrict filter) +{ + size_t i, n = out->table_size; + + for (i = 0; i < n; i++) + if (!strcmp(filter->class, out->table_filters[i].class)) + break; + + if (i == out->table_size) + { + fprintf(stderr, "%s: ignoring attempt to removing non-existing filter on CRTC %s: %s", + argv0, out->name, filter->class); + return (ssize_t)(out->table_size); + } + + filter_destroy(out->table_filters + i); + libgamma_gamma_ramps8_destroy(&(out->table_sums[i].u8)); + + n = n - i - 1; + memmove(out->table_filters + i, out->table_filters + i + 1, n * sizeof(*(out->table_filters))); + memmove(out->table_sums + i, out->table_sums + i + 1, n * sizeof(*(out->table_sums))); + out->table_size--; + + return (ssize_t)i; +} + + +/** + * Add a filter to an output + * + * @param out The output + * @param filter The filter + * @return The index given to the filter, -1 on error + */ +ssize_t add_filter(struct output* restrict out, struct filter* restrict filter) +{ + size_t i, n = out->table_size; + int r = -1; + + /* Remove? */ + if (filter->lifespan == LIFESPAN_REMOVE) + return remove_filter(out, filter); + + /* Update? */ + for (i = 0; i < n; i++) + if (!strcmp(filter->class, out->table_filters[i].class)) + break; + if (i != n) + { + filter_destroy(out->table_filters + i); + out->table_filters[i] = *filter; + return (ssize_t)i; + } + + /* Add! */ + for (i = 0; i < n; i++) + if (filter->priority > out->table_filters[i].priority) + break; + + if (n == out->table_alloc) + { + void* new; + + new = realloc(out->table_filters, (n + 10) * sizeof(*(out->table_filters))); + if (new == NULL) + return -1; + out->table_filters = new; + + new = realloc(out->table_sums, (n + 10) * sizeof(*(out->table_sums))); + if (new == NULL) + return -1; + out->table_sums = new; + + out->table_alloc += 10; + } + + memmove(out->table_filters + i + 1, out->table_filters + i, (n - i) * sizeof(*(out->table_filters))); + memmove(out->table_sums + i + 1, out->table_sums + i, (n - i) * sizeof(*(out->table_sums))); + out->table_size++; + + COPY_RAMP_SIZES(&(out->table_sums[i].u8), out); + switch (out->depth) + { + case 8: r = libgamma_gamma_ramps8_initialise(&(out->table_sums[i].u8)); break; + case 16: r = libgamma_gamma_ramps16_initialise(&(out->table_sums[i].u16)); break; + case 32: r = libgamma_gamma_ramps32_initialise(&(out->table_sums[i].u32)); break; + case 64: r = libgamma_gamma_ramps64_initialise(&(out->table_sums[i].u64)); break; + case -1: r = libgamma_gamma_rampsf_initialise(&(out->table_sums[i].f)); break; + case -2: r = libgamma_gamma_rampsd_initialise(&(out->table_sums[i].d)); break; + default: + abort(); + } + if (r < 0) + return -1; + + out->table_filters[i] = *filter; + + return (ssize_t)i; +} + + +/** + * Make identity mapping ramps + * + * @param ramps Output parameter for the ramps + * @param output The output for which the ramps shall be configured + * @return Zero on success, -1 on error + */ +int make_plain_ramps(union gamma_ramps* restrict ramps, struct output* restrict output) +{ + COPY_RAMP_SIZES(&(ramps->u8), output); + switch (output->depth) + { + case 8: + if (libgamma_gamma_ramps8_initialise(&(ramps->u8))) + return -1; + libclut_start_over(&(ramps->u8), UINT8_MAX, uint8_t, 1, 1, 1); + break; + case 16: + if (libgamma_gamma_ramps16_initialise(&(ramps->u16))) + return -1; + libclut_start_over(&(ramps->u16), UINT16_MAX, uint16_t, 1, 1, 1); + break; + case 32: + if (libgamma_gamma_ramps32_initialise(&(ramps->u32))) + return -1; + libclut_start_over(&(ramps->u32), UINT32_MAX, uint32_t, 1, 1, 1); + break; + case 64: + if (libgamma_gamma_ramps64_initialise(&(ramps->u64))) + return -1; + libclut_start_over(&(ramps->u64), UINT64_MAX, uint64_t, 1, 1, 1); + break; + case -1: + if (libgamma_gamma_rampsf_initialise(&(ramps->f))) + return -1; + libclut_start_over(&(ramps->f), 1.0f, float, 1, 1, 1); + break; + case -2: + if (libgamma_gamma_rampsd_initialise(&(ramps->d))) + return -1; + libclut_start_over(&(ramps->d), (double)1, double, 1, 1, 1); + break; + default: + abort(); + } + return 0; +} + diff --git a/src/coopgamma-server/chaining.h b/src/coopgamma-server/chaining.h new file mode 100644 index 0000000..cd31e5a --- /dev/null +++ b/src/coopgamma-server/chaining.h @@ -0,0 +1,75 @@ +/** + * 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 COOPGAMMA_SERVER_CHAINING +#define COOPGAMMA_SERVER_CHAINING + + +#include "../types/output.h" + + + +#ifndef GCC_ONLY +# if defined(__GNUC__) && !defined(__clang__) +# define GCC_ONLY(...) __VA_ARGS__ +# else +# define GCC_ONLY(...) /* nothing */ +# endif +#endif + + + +/** + * Apply a filter on top of another filter + * + * @param dest The output for the resulting ramp-trio, must be initialised + * @param application The red, green and blue ramps, as one single raw array, + * of the filter that should be applied + * @param depth -1: `float` stops + * -2: `double` stops + * Other: the number of bits of each (integral) stop + * @param base The CLUT on top of which the new filter should be applied, + * this can be the same pointer as `dest` + */ +GCC_ONLY(__attribute__((nonnull))) +void apply_filter(union gamma_ramps* restrict dest, void* restrict application, + int depth, union gamma_ramps* restrict base); + + +/** + * Add a filter to an output + * + * @param output The output + * @param filter The filter + * @return The index given to the filter, -1 on error + */ +GCC_ONLY(__attribute__((nonnull))) +ssize_t add_filter(struct output* restrict output, struct filter* restrict filter); + +/** + * Make identity mapping ramps + * + * @param ramps Output parameter for the ramps + * @param output The output for which the ramps shall be configured + * @return Zero on success, -1 on error + */ +GCC_ONLY(__attribute__((nonnull))) +int make_plain_ramps(union gamma_ramps* restrict ramps, struct output* restrict output); + + +#endif + diff --git a/src/coopgamma-server/server.c b/src/coopgamma-server/server.c new file mode 100644 index 0000000..8d56119 --- /dev/null +++ b/src/coopgamma-server/server.c @@ -0,0 +1,335 @@ +/** + * 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 "server.h" +#include "chaining.h" +#include "../state.h" +#include "../communication.h" +#include "../util.h" +#include "../gamma-server/server.h" + +#include <libclut.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> + + + +/** + * Handle a closed connection + * + * @param client The file descriptor for the client + * @return Zero on success, -1 on error + */ +int connection_closed(int client) +{ + size_t i, j, k; + int remove; + + for (i = 0; i < outputs_n; i++) + { + struct output* output = outputs + i; + ssize_t updated = -1; + for (j = k = 0; j < output->table_size; j += !remove, k++) + { + remove = output->table_filters[j].client == client; + remove = remove && (output->table_filters[j].lifespan == LIFESPAN_UNTIL_DEATH); + if (remove) + { + filter_destroy(output->table_filters + j); + libgamma_gamma_ramps8_destroy(&(output->table_sums[j].u8)); + output->table_size -= 1; + if (updated == -1) + updated = (ssize_t)j; + } + output->table_filters[j] = output->table_filters[k]; + output->table_sums[j] = output->table_sums[k]; + } + if (updated >= 0) + if (flush_filters(output, (size_t)updated) < 0) + return -1; + } + + return 0; +} + + +/** + * Handle a ‘Command: get-gamma’ message + * + * @param conn The index of the connection + * @param message_id The value of the ‘Message ID’ header + * @param crtc The value of the ‘CRTC’ header + * @param coalesce The value of the ‘Coalesce’ header + * @param high_priority The value of the ‘High priority’ header + * @param low_priority The value of the ‘Low priority’ header + * @return Zero on success (even if ignored), -1 on error, + * 1 if connection closed + */ +int handle_get_gamma(size_t conn, const char* restrict message_id, const char* restrict crtc, + const char* restrict coalesce, const char* restrict high_priority, + const char* restrict low_priority) +{ + struct output* restrict output; + int64_t high, low; + int coal; + char* restrict buf; + size_t start, end, len, n, i; + char depth[3]; + char tables[sizeof("Tables: \n") + 3 * sizeof(size_t)]; + + if (crtc == NULL) return send_error("protocol error: 'CRTC' header omitted"); + if (coalesce == NULL) return send_error("protocol error: 'Coalesce' header omitted"); + if (high_priority == NULL) return send_error("protocol error: 'High priority' header omitted"); + if (low_priority == NULL) return send_error("protocol error: 'Low priority' header omitted"); + + high = (int64_t)atoll(high_priority); + low = (int64_t)atoll(low_priority); + + if (!strcmp(coalesce, "yes")) + coal = 1; + else if (!strcmp(coalesce, "no")) + coal = 0; + else + return send_error("protocol error: recognised value for 'Coalesce' header"); + + output = output_find_by_name(crtc, outputs, outputs_n); + if (output == NULL) + return send_error("selected CRTC does not exist"); + else if (output->supported == LIBGAMMA_NO) + return send_error("selected CRTC does not support gamma adjustments"); + + for (start = 0; start < output->table_size; start++) + if (output->table_filters[start].priority <= high) + break; + + for (end = output->table_size; end > 0; end--) + if (output->table_filters[end - 1].priority >= low) + break; + + switch (output->depth) + { + case -2: strcpy(depth, "d"); break; + case -1: strcpy(depth, "f"); break; + default: + sprintf(depth, "%i", output->depth); + break; + } + + if (coal) + { + *tables = '\0'; + n = output->ramps_size; + } + else + { + sprintf(tables, "Tables: %zu\n", end - start); + n = (sizeof(int64_t) + output->ramps_size) * (end - start); + for (i = start; i < end; i++) + n += strlen(output->table_filters[i].class) + 1; + } + + MAKE_MESSAGE(&buf, &n, 0, + "In response to: %s\n" + "Depth: %s\n" + "Red size: %zu\n" + "Green size: %zu\n" + "Blue size: %zu\n" + "%s" + "Length: %zu\n" + "\n", + message_id, depth, output->red_size, output->green_size, + output->blue_size, tables, n); + + if (coal) + { + if (start == 0) + memcpy(buf + n, output->table_sums[end].u8.red, output->ramps_size); + else + { + union gamma_ramps ramps; + if (make_plain_ramps(&ramps, output)) + { + int saved_errno = errno; + free(buf); + errno = saved_errno; + return -1; + } + for (i = start; i < end; i++) + apply_filter(&ramps, output->table_filters[i].ramps, output->depth, &ramps); + memcpy(buf + n, ramps.u8.red, output->ramps_size); + libgamma_gamma_ramps8_destroy(&(ramps.u8)); + } + n += output->ramps_size; + } + else + for (i = start; i < end; i++) + { +#if defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wcast-align" +#endif + *(int64_t*)(buf + n) = output->table_filters[i].priority; +#if defined(__clang__) +# pragma GCC diagnostic pop +#endif + n += sizeof(int64_t); + len = strlen(output->table_filters[i].class) + 1; + memcpy(buf + n, output->table_filters[i].class, len); + n += len; + memcpy(buf + n, output->table_filters[i].ramps, output->ramps_size); + n += output->ramps_size; + } + + return send_message(conn, buf, n); +} + + +/** + * Handle a ‘Command: set-gamma’ message + * + * @param conn The index of the connection + * @param message_id The value of the ‘Message ID’ header + * @param crtc The value of the ‘CRTC’ header + * @param priority The value of the ‘Priority’ header + * @param class The value of the ‘Class’ header + * @param lifespan The value of the ‘Lifespan’ header + * @return Zero on success (even if ignored), -1 on error, + * 1 if connection closed + */ +int handle_set_gamma(size_t conn, const char* restrict message_id, const char* restrict crtc, + const char* restrict priority, const char* restrict class, const char* restrict lifespan) +{ + struct message* restrict msg = inbound + conn; + struct output* restrict output = NULL; + struct filter filter; + char* restrict p; + char* restrict q; + int saved_errno; + ssize_t r; + + if (crtc == NULL) return send_error("protocol error: 'CRTC' header omitted"); + if (class == NULL) return send_error("protocol error: 'Class' header omitted"); + if (lifespan == NULL) return send_error("protocol error: 'Lifespan' header omitted"); + + filter.client = connections[conn]; + filter.priority = priority == NULL ? 0 : (int64_t)atoll(priority); + filter.ramps = NULL; + + output = output_find_by_name(crtc, outputs, outputs_n); + if (output == NULL) + return send_error("CRTC does not exists"); + + p = strstr(class, "::"); + if ((p == NULL) || (p == class)) + return send_error("protocol error: malformatted value for 'Class' header"); + q = strstr(p + 2, "::"); + if ((q == NULL) || (q == p)) + return send_error("protocol error: malformatted value for 'Class' header"); + + if (!strcmp(lifespan, "until-removal")) + filter.lifespan = LIFESPAN_UNTIL_REMOVAL; + else if (!strcmp(lifespan, "until-death")) + filter.lifespan = LIFESPAN_UNTIL_DEATH; + else if (!strcmp(lifespan, "remove")) + filter.lifespan = LIFESPAN_REMOVE; + else + return send_error("protocol error: recognised value for 'Lifespan' header"); + + if (filter.lifespan == LIFESPAN_REMOVE) + { + if (msg->payload_size) + fprintf(stderr, "%s: ignoring superfluous payload on Command: set-gamma message with " + "Lifespan: remove\n", argv0); + if (priority != NULL) + fprintf(stderr, "%s: ignoring superfluous Priority header on Command: set-gamma message with " + "Lifespan: remove\n", argv0); + } + else if (msg->payload_size != output->ramps_size) + return send_error("invalid payload: size of message payload does matched the expectancy"); + else if (priority == NULL) + return send_error("protocol error: 'Priority' header omitted"); + + filter.class = memdup(class, strlen(class) + 1); + if (filter.class == NULL) + goto fail; + + if (filter.lifespan != LIFESPAN_REMOVE) + { + filter.ramps = memdup(msg->payload, msg->payload_size); + if (filter.ramps == NULL) + goto fail; + } + + if ((r = add_filter(output, &filter)) < 0) + goto fail; + filter.class = NULL; + filter.ramps = NULL; + if (flush_filters(output, (size_t)r)) + goto fail; + + return send_errno(0); + + fail: + saved_errno = errno; + send_errno(saved_errno); + free(filter.class); + free(filter.ramps); + errno = saved_errno; + return -1; +} + + + +/** + * Recalculate the resulting gamma and + * update push the new gamma ramps to the CRTC + * + * @param output The output + * @param first_updated The index of the first added or removed filter + * @return Zero on success, -1 on error + */ +int flush_filters(struct output* restrict output, size_t first_updated) +{ + union gamma_ramps plain; + union gamma_ramps* last; + size_t i; + + if (first_updated == 0) + { + if (make_plain_ramps(&plain, output) < 0) + return -1; + last = &plain; + } + else + last = output->table_sums + (first_updated - 1); + + for (i = first_updated; i < output->table_size; i++) + { + apply_filter(output->table_sums + i, output->table_filters[i].ramps, output->depth, last); + last = output->table_sums + i; + } + + set_gamma(output, last); + + if (first_updated == 0) + libgamma_gamma_ramps8_destroy(&(plain.u8)); + + return 0; +} + diff --git a/src/coopgamma-server/server.h b/src/coopgamma-server/server.h new file mode 100644 index 0000000..971f7df --- /dev/null +++ b/src/coopgamma-server/server.h @@ -0,0 +1,93 @@ +/** + * 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 COOPGAMMA_SERVER_SERVER_H +#define COOPGAMMA_SERVER_SERVER_H + + +#include "../types/output.h" + +#include <stddef.h> + + + +#ifndef GCC_ONLY +# if defined(__GNUC__) && !defined(__clang__) +# define GCC_ONLY(...) __VA_ARGS__ +# else +# define GCC_ONLY(...) /* nothing */ +# endif +#endif + + + +/** + * Handle a closed connection + * + * @param client The file descriptor for the client + * @return Zero on success, -1 on error + */ +int connection_closed(int client); + +/** + * Handle a ‘Command: get-gamma’ message + * + * @param conn The index of the connection + * @param message_id The value of the ‘Message ID’ header + * @param crtc The value of the ‘CRTC’ header + * @param coalesce The value of the ‘Coalesce’ header + * @param high_priority The value of the ‘High priority’ header + * @param low_priority The value of the ‘Low priority’ header + * @return Zero on success (even if ignored), -1 on error, + * 1 if connection closed + */ +GCC_ONLY(__attribute__((nonnull(2)))) +int handle_get_gamma(size_t conn, const char* restrict message_id, const char* restrict crtc, + const char* restrict coalesce, const char* restrict high_priority, + const char* restrict low_priority); + +/** + * Handle a ‘Command: set-gamma’ message + * + * @param conn The index of the connection + * @param message_id The value of the ‘Message ID’ header + * @param crtc The value of the ‘CRTC’ header + * @param priority The value of the ‘Priority’ header + * @param class The value of the ‘Class’ header + * @param lifespan The value of the ‘Lifespan’ header + * @return Zero on success (even if ignored), -1 on error, + * 1 if connection closed + */ +GCC_ONLY(__attribute__((nonnull(2)))) +int handle_set_gamma(size_t conn, const char* restrict message_id, const char* restrict crtc, + const char* restrict priority, const char* restrict class, const char* restrict lifespan); + + +/** + * Recalculate the resulting gamma and + * update push the new gamma ramps to the CRTC + * + * @param output The output + * @param first_updated The index of the first added or removed filter + * @return Zero on success, -1 on error + */ +GCC_ONLY(__attribute__((nonnull))) +int flush_filters(struct output* restrict output, size_t first_updated); + + +#endif + diff --git a/src/coopgammad.c b/src/coopgammad.c index 7e6422e..df8f95d 100644 --- a/src/coopgammad.c +++ b/src/coopgammad.c @@ -15,7 +15,10 @@ * 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 <libgamma.h> +#include "arg.h" +#include "util.h" +#include "server.h" +#include "state.h" #include <sys/resource.h> #include <sys/socket.h> @@ -30,11 +33,6 @@ #include <string.h> #include <unistd.h> -#include "arg.h" -#include "output.h" -#include "util.h" -#include "server.h" - /** @@ -55,51 +53,13 @@ -extern char* restrict argv0_real; -extern struct output* restrict outputs; -extern size_t outputs_n; -extern int socketfd; extern char* restrict pidpath; extern char* restrict socketpath; extern int gerror; -extern int method; -extern char* restrict sitename; -extern libgamma_site_state_t site; -extern libgamma_partition_state_t* restrict partitions; -extern libgamma_crtc_state_t* restrict crtcs; -extern volatile sig_atomic_t reexec; -extern volatile sig_atomic_t terminate; -extern volatile sig_atomic_t connection; /** - * The name of the process - */ -char* restrict argv0; - -/** - * The real pathname of the process's binary, - * `NULL` if `argv0` is satisfactory - */ -char* restrict argv0_real = NULL; - -/** - * Array of all outputs - */ -struct output* restrict outputs = NULL; - -/** - * The nubmer of elements in `outputs` - */ -size_t outputs_n = 0; - -/** - * The server socket's file descriptor - */ -int socketfd = -1; - -/** * The pathname of the PID file */ char* restrict pidpath = NULL; @@ -112,52 +72,7 @@ char* restrict socketpath = NULL; /** * Error code returned by libgamma */ -int gerror; - -/** - * The adjustment method, -1 for automatic - */ -int method = -1; - -/** - * The site's name, may be `NULL` - */ -char* restrict sitename = NULL; - -/** - * The libgamma site state - */ -libgamma_site_state_t site; - -/** - * The libgamma partition states - */ -libgamma_partition_state_t* restrict partitions = NULL; - -/** - * The libgamma CRTC states - */ -libgamma_crtc_state_t* restrict crtcs = NULL; - -/** - * Has the process receive a signal - * telling it to re-execute? - */ -volatile sig_atomic_t reexec = 0; - -/** - * Has the process receive a signal - * telling it to terminate? - */ -volatile sig_atomic_t terminate = 0; - -/** - * Has the process receive a to - * disconnect from or reconnect to - * the site? 1 if disconnct, 2 if - * reconnect, 0 otherwise. - */ -volatile sig_atomic_t connection = 0; +int gerror; /* do not marshal */ @@ -905,12 +820,16 @@ static void destroy(int full) { size_t i; + if (full) + disconnect_all(); + if (full && (socketfd >= 0)) { shutdown(socketfd, SHUT_RDWR); close(socketfd); unlink(socketpath); } + #define RESTORE_RAMPS(SUFFIX, MEMBER) \ do \ if (outputs[i].saved_ramps.MEMBER.red != NULL) \ @@ -922,51 +841,36 @@ static void destroy(int full) while (0) if (outputs != NULL) for (i = 0; i < outputs_n; i++) - { - if (full && (outputs[i].supported != LIBGAMMA_NO)) - switch (outputs[i].depth) - { - case 8: - RESTORE_RAMPS(8, u8); - break; - case 16: - RESTORE_RAMPS(16, u16); - break; - case 32: - RESTORE_RAMPS(32, u32); - break; - case 64: - RESTORE_RAMPS(64, u64); - break; - case -1: - RESTORE_RAMPS(f, f); - break; - case -2: - RESTORE_RAMPS(d, d); - break; - default: - break; /* impossible */ - } - if (crtcs == NULL) - libgamma_crtc_destroy(outputs[i].crtc + i); - output_destroy(outputs + i); - } - free(outputs); - if (crtcs != NULL) - for (i = 0; i < outputs_n; i++) - libgamma_crtc_destroy(crtcs + i); - free(crtcs); - if (partitions != NULL) - for (i = 0; i < site.partitions_available; i++) - libgamma_partition_destroy(partitions + i); - free(partitions); - libgamma_site_destroy(&site); + if (full && (outputs[i].supported != LIBGAMMA_NO)) + switch (outputs[i].depth) + { + case 8: + RESTORE_RAMPS(8, u8); + break; + case 16: + RESTORE_RAMPS(16, u16); + break; + case 32: + RESTORE_RAMPS(32, u32); + break; + case 64: + RESTORE_RAMPS(64, u64); + break; + case -1: + RESTORE_RAMPS(f, f); + break; + case -2: + RESTORE_RAMPS(d, d); + break; + default: + break; /* impossible */ + } + free(socketpath); if (full && (pidpath != NULL)) unlink(pidpath); free(pidpath); - free(argv0_real); - free(sitename); + state_destroy(); } @@ -987,38 +891,13 @@ static void destroy(int full) */ static size_t marshal(void* restrict buf) { - size_t off = 0, i, n; + size_t off = 0, n; char* restrict bs = buf; if (bs != NULL) *(int*)(bs + off) = MARSHAL_VERSION; off += sizeof(int); - if (argv0_real == NULL) - { - if (bs != NULL) - *(bs + off) = '\0'; - off += 1; - } - else - { - n = strlen(argv0_real) + 1; - if (bs != NULL) - memcpy(bs + off, argv0_real, n); - off += n; - } - - if (bs != NULL) - *(size_t*)(bs + off) = outputs_n; - off += sizeof(size_t); - - for (i = 0; i < outputs_n; i++) - off += output_marshal(outputs + i, bs ? bs + off : NULL); - - if (bs != NULL) - *(int*)(bs + off) = socketfd; - off += sizeof(int); - n = strlen(pidpath) + 1; if (bs != NULL) memcpy(bs + off, pidpath, n); @@ -1029,26 +908,7 @@ static size_t marshal(void* restrict buf) memcpy(bs + off, socketpath, n); off += n; - off += server_marshal(bs ? bs + off : NULL); - - if (bs != NULL) - *(int*)(bs + off) = method; - off += sizeof(int); - - if (bs != NULL) - *(int*)(bs + off) = sitename != NULL; - off += sizeof(int); - if (sitename != NULL) - { - n = strlen(sitename) + 1; - if (bs != NULL) - memcpy(bs + off, sitename, n); - off += n; - } - - if (bs != NULL) - *(sig_atomic_t*)(bs + off) = connection; - off += sizeof(sig_atomic_t); + off += state_marshal(bs ? bs + off : NULL); return off; } @@ -1061,12 +921,12 @@ static size_t marshal(void* restrict buf) * @return The number of marshalled bytes, 0 on error */ GCC_ONLY(__attribute__((nonnull))) -static size_t unmarshal(void* restrict buf) +static size_t unmarshal(const void* restrict buf) { - size_t off = 0, i, n; - char* restrict bs = buf; + size_t off = 0, n; + const char* restrict bs = buf; - if (*(int*)(bs + off) != MARSHAL_VERSION) + if (*(const int*)(bs + off) != MARSHAL_VERSION) { fprintf(stderr, "%s: re-executing to incompatible version, sorry about that\n", argv0); errno = 0; @@ -1074,30 +934,6 @@ static size_t unmarshal(void* restrict buf) } off += sizeof(int); - if (*(bs + off)) - { - off += 1; - n = strlen(bs + off) + 1; - if (!(argv0_real = memdup(bs + off, n))) - return 0; - off += n; - } - else - off += 1; - - outputs_n = *(size_t*)(bs + off); - off += sizeof(size_t); - - for (i = 0; i < outputs_n; i++) - { - off += n = output_unmarshal(outputs + i, bs + off); - if (n == 0) - return 0; - } - - socketfd = *(int*)(bs + off); - off += sizeof(int); - n = strlen(bs + off) + 1; if (!(pidpath = memdup(bs + off, n))) return 0; @@ -1108,27 +944,10 @@ static size_t unmarshal(void* restrict buf) return 0; off += n; - off += n = server_unmarshal(bs + off); + off += n = state_unmarshal(bs + off); if (n == 0) return 0; - method = *(int*)(bs + off); - off += sizeof(int); - - if (*(int*)(bs + off)) - { - off += sizeof(int); - n = strlen(bs + off) + 1; - if (!(sitename = memdup(bs + off, n))) - return 0; - off += n; - } - else - off += sizeof(int); - - connection = *(sig_atomic_t*)(bs + off); - off += sizeof(sig_atomic_t); - return off; } diff --git a/src/crtc-server/server.c b/src/crtc-server/server.c new file mode 100644 index 0000000..6c16cee --- /dev/null +++ b/src/crtc-server/server.c @@ -0,0 +1,59 @@ +/** + * 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 "server.h" +#include "../state.h" +#include "../communication.h" + +#include <string.h> + + + +/** + * Handle a ‘Command: enumerate-crtcs’ message + * + * @param conn The index of the connection + * @param message_id The value of the ‘Message ID’ header + * @return Zero on success (even if ignored), -1 on error, + * 1 if connection closed + */ +int handle_enumerate_crtcs(size_t conn, const char* restrict message_id) +{ + size_t i, n = 0, len; + char* restrict buf; + + for (i = 0; i < outputs_n; i++) + n += strlen(outputs[i].name) + 1; + + MAKE_MESSAGE(&buf, &n, 0, + "Command: crtc-enumeration\n" + "In response to: %s\n" + "Length: %zu\n" + "\n", + message_id, n); + + for (i = 0; i < outputs_n; i++) + { + len = strlen(outputs[i].name); + memcpy(buf + n, outputs[i].name, len); + buf[n + len] = '\n'; + n += len + 1; + } + + return send_message(conn, buf, n); +} + diff --git a/src/crtc-server/server.h b/src/crtc-server/server.h new file mode 100644 index 0000000..ffe4f64 --- /dev/null +++ b/src/crtc-server/server.h @@ -0,0 +1,49 @@ +/** + * 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 CRTC_SERVER_SERVER_H +#define CRTC_SERVER_SERVER_H + + +#include <stddef.h> + + + +#ifndef GCC_ONLY +# if defined(__GNUC__) && !defined(__clang__) +# define GCC_ONLY(...) __VA_ARGS__ +# else +# define GCC_ONLY(...) /* nothing */ +# endif +#endif + + + +/** + * Handle a ‘Command: enumerate-crtcs’ message + * + * @param conn The index of the connection + * @param message_id The value of the ‘Message ID’ header + * @return Zero on success (even if ignored), -1 on error, + * 1 if connection closed + */ +GCC_ONLY(__attribute__((nonnull))) +int handle_enumerate_crtcs(size_t conn, const char* restrict message_id); + + +#endif + diff --git a/src/gamma-server/server.c b/src/gamma-server/server.c new file mode 100644 index 0000000..b6ec852 --- /dev/null +++ b/src/gamma-server/server.c @@ -0,0 +1,144 @@ +/** + * 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 "server.h" +#include "../state.h" +#include "../communication.h" + +#include <string.h> + + + +#if defined(__clang__) +# pragma GCC diagnostic ignored "-Wswitch-enum" +#endif + + + +/** + * Handle a ‘Command: set-gamma’ message + * + * @param conn The index of the connection + * @param message_id The value of the ‘Message ID’ header + * @param crtc The value of the ‘CRTC’ header + * @return Zero on success (even if ignored), -1 on error, + * 1 if connection closed + */ +int handle_get_gamma_info(size_t conn, const char* restrict message_id, const char* restrict crtc) +{ + struct output* restrict output; + char* restrict buf; + char depth[3]; + const char* supported; + size_t n; + + if (crtc == NULL) return send_error("protocol error: 'CRTC' header omitted"); + + output = output_find_by_name(crtc, outputs, outputs_n); + if (output == NULL) + return send_error("selected CRTC does not exist"); + + switch (output->depth) + { + case -2: strcpy(depth, "d"); break; + case -1: strcpy(depth, "f"); break; + default: + sprintf(depth, "%i", output->depth); + break; + } + + switch (output->supported) + { + case LIBGAMMA_YES: supported = "yes"; break; + case LIBGAMMA_NO: supported = "no"; break; + default: supported = "maybe"; break; + } + + MAKE_MESSAGE(&buf, &n, 0, + "In response to: %s\n" + "Cooperative: yes\n" /* In mds: say ‘no’, mds-coopgamma changes to ‘yes’.” */ + "Depth: %s\n" + "Red size: %zu\n" + "Green size: %zu\n" + "Blue size: %zu\n" + "Gamma support: %s\n" + "\n", + message_id, depth, output->red_size, output->green_size, + output->blue_size, supported); + + return send_message(conn, buf, n); +} + + +/** + * Set the gamma ramps on an output + * + * @param output The output + * @param ramps The gamma ramps + */ +void set_gamma(const struct output* restrict output, const union gamma_ramps* restrict ramps) +{ + int r = 0; + + if (connected) + { + switch (output->depth) + { + case 8: r = libgamma_crtc_set_gamma_ramps8(output->crtc, ramps->u8); break; + case 16: r = libgamma_crtc_set_gamma_ramps16(output->crtc, ramps->u16); break; + case 32: r = libgamma_crtc_set_gamma_ramps32(output->crtc, ramps->u32); break; + case 64: r = libgamma_crtc_set_gamma_ramps64(output->crtc, ramps->u64); break; + case -1: r = libgamma_crtc_set_gamma_rampsf(output->crtc, ramps->f); break; + case -2: r = libgamma_crtc_set_gamma_rampsd(output->crtc, ramps->d); break; + default: + abort(); + } + if (r) + libgamma_perror(argv0, r); /* Not fatal */ + } +} + + +/** + * Disconnect from the site + * + * @return Zero on success, -1 on error + */ +int disconnect(void) +{ + if (!connected) + return 0; + + connected = 0; + return 0; /* TODO disconnect() */ +} + + +/** + * Reconnect to the site + * + * @return Zero on success, -1 on error + */ +int reconnect(void) +{ + if (connected) + return 0; + + connected = 1; + return 0; /* TODO reconnect() */ +} + diff --git a/src/gamma-server/server.h b/src/gamma-server/server.h new file mode 100644 index 0000000..b84a836 --- /dev/null +++ b/src/gamma-server/server.h @@ -0,0 +1,75 @@ +/** + * 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 GAMMA_SERVER_SERVER_H +#define GAMMA_SERVER_SERVER_H + + +#include "../types/output.h" + +#include <stddef.h> + + + +#ifndef GCC_ONLY +# if defined(__GNUC__) && !defined(__clang__) +# define GCC_ONLY(...) __VA_ARGS__ +# else +# define GCC_ONLY(...) /* nothing */ +# endif +#endif + + + +/** + * Handle a ‘Command: set-gamma’ message + * + * @param conn The index of the connection + * @param message_id The value of the ‘Message ID’ header + * @param crtc The value of the ‘CRTC’ header + * @return Zero on success (even if ignored), -1 on error, + * 1 if connection closed + */ +GCC_ONLY(__attribute__((nonnull(2)))) +int handle_get_gamma_info(size_t conn, const char* restrict message_id, const char* restrict crtc); + +/** + * Set the gamma ramps on an output + * + * @param output The output + * @param ramps The gamma ramps + */ +GCC_ONLY(__attribute__((nonnull))) +void set_gamma(const struct output* restrict output, const union gamma_ramps* restrict ramps); + +/** + * Disconnect from the site + * + * @return Zero on success, -1 on error + */ +int disconnect(void); + +/** + * Reconnect to the site + * + * @return Zero on success, -1 on error + */ +int reconnect(void); + + +#endif + diff --git a/src/server.c b/src/server.c index 2705f4e..4adcc5e 100644 --- a/src/server.c +++ b/src/server.c @@ -16,14 +16,17 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "server.h" -#include "output.h" #include "util.h" +#include "communication.h" +#include "state.h" +#include "crtc-server/server.h" +#include "gamma-server/server.h" +#include "coopgamma-server/server.h" #include <sys/select.h> #include <sys/socket.h> #include <errno.h> #include <fcntl.h> -#include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -31,233 +34,6 @@ -#if defined(__clang__) -# pragma GCC diagnostic ignored "-Wswitch-enum" -#endif - - - -/** - * List of all client's file descriptors - * - * Unused slots, with index less than `connections_used`, - * should have the value -1 (negative) - */ -int* restrict connections = NULL; - -/** - * The number of elements allocated for `connections` - */ -size_t connections_alloc = 0; - -/** - * The index of the first unused slot in `connections` - */ -size_t connections_ptr = 0; - -/** - * The index of the last used slot in `connections`, plus 1 - */ -size_t connections_used = 0; - -/** - * The clients' connections' inbound-message buffers - */ -struct message* restrict inbound = NULL; - -/** - * The clients' connections' outbound-message buffers - */ -struct ring* restrict outbound = NULL; - - -/** - * The name of the process - */ -extern char* restrict argv0; - -/** - * The server socket's file descriptor - */ -extern int socketfd; - -/** - * Has the process receive a signal - * telling it to re-execute? - */ -extern volatile sig_atomic_t reexec; - -/** - * Has the process receive a signal - * telling it to terminate? - */ -extern volatile sig_atomic_t terminate; - -/** - * Has the process receive a to - * disconnect from or reconnect to - * the site? 1 if disconnct, 2 if - * reconnect, 0 otherwise. - */ -extern volatile sig_atomic_t connection; - -/** - * Array of all outputs - */ -extern struct output* restrict outputs; - -/** - * The nubmer of elements in `outputs` - */ -extern size_t outputs_n; - - - -/** - * Construct a message - * - * @param bufp:char** Output parameter for the buffer, must not have side-effects - * @param np:size_t* Output parameter for the size of the buffer sans `extra` - * @param extra:size_t The extra number for bytes to allocate to the buffer - * @param format:string-literal Message format string - * @param ... Message formatting arguments - */ -#define MAKE_MESSAGE(bufp, np, extra, format, ...) \ - do \ - { \ - ssize_t m__; \ - snprintf(NULL, 0, format "%zn", __VA_ARGS__, &m__); \ - *(bufp) = malloc((size_t)(extra) + (size_t)m__); \ - if (*(bufp) == NULL) \ - return -1; \ - sprintf(*(bufp), format, __VA_ARGS__); \ - *(np) = (size_t)m__; \ - } \ - while (0) - - - -/** - * Destroy the state of the connections - * - * @param disconnect Disconnect all connections? - */ -void server_destroy(int disconnect) -{ - size_t i; - for (i = 0; i < connections_used; i++) - if (connections[i] >= 0) - { - if (disconnect) - { - shutdown(connections[i], SHUT_RDWR); - close(connections[i]); - } - message_destroy(inbound + i); - ring_destroy(outbound + i); - } - free(inbound); - free(outbound); - free(connections); -} - - - -#if defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-align" -#endif - - -/** - * Marshal the state of the connections - * - * @param buf Output buffer for the marshalled data, - * `NULL` to only measure how many bytes - * this buffer needs - * @return The number of marshalled bytes - */ -size_t server_marshal(void* restrict buf) -{ - size_t i, off = 0; - char* restrict bs = buf; - - if (bs != NULL) - *(size_t*)(bs + off) = connections_ptr; - off += sizeof(size_t); - - if (bs != NULL) - *(size_t*)(bs + off) = connections_used; - off += sizeof(size_t); - - if (bs != NULL) - memcpy(bs + off, connections, connections_used * sizeof(*connections)); - off += connections_used * sizeof(*connections); - - for (i = 0; i < connections_used; i++) - if (connections[i] >= 0) - { - off += message_marshal(inbound + i, bs ? bs + off : NULL); - off += ring_marshal(outbound + i, bs ? bs + off : NULL); - } - - return off; -} - - -/** - * Unmarshal the state of the connections - * - * @param buf Buffer for the marshalled data - * @return The number of unmarshalled bytes, 0 on error - */ -size_t server_unmarshal(const void* restrict buf) -{ - size_t off = 0, i, n; - const char* restrict bs = buf; - - connections = NULL; - inbound = NULL; - - connections_ptr = *(const size_t*)(bs + off); - off += sizeof(size_t); - - connections_alloc = connections_used = *(const size_t*)(bs + off); - off += sizeof(size_t); - - if (connections_alloc > 0) - { - connections = memdup(bs + off, connections_alloc * sizeof(*connections)); - if (connections == NULL) - return 0; - off += connections_used * sizeof(*connections); - - inbound = malloc(connections_alloc * sizeof(*inbound)); - if (inbound == NULL) - return 0; - } - - for (i = 0; i < connections_used; i++) - if (connections[i] >= 0) - { - off += n = message_unmarshal(inbound + i, bs + off); - if (n == 0) - return 0; - off += n = ring_unmarshal(outbound + i, bs + off); - if (n == 0) - return 0; - } - - return off; -} - - -#if defined(__clang__) -# pragma GCC diagnostic pop -#endif - - - /** * Sets the file descriptor set that includes * the server socket and all connections @@ -354,548 +130,6 @@ static int handle_server(void) } -/** - * Handle a closed connection - * - * @param client The file descriptor for the client - * @return Zero on success, -1 on error - */ -static int connection_closed(int client) -{ - size_t i, j, k; - int remove; - - for (i = 0; i < outputs_n; i++) - { - struct output* output = outputs + i; - ssize_t updated = -1; - for (j = k = 0; j < output->table_size; j += !remove, k++) - { - remove = output->table_filters[j].client == client; - remove = remove && (output->table_filters[j].lifespan == LIFESPAN_UNTIL_DEATH); - if (remove) - { - filter_destroy(output->table_filters + j); - libgamma_gamma_ramps8_destroy(&(output->table_sums[j].u8)); - output->table_size -= 1; - if (updated == -1) - updated = (ssize_t)j; - } - output->table_filters[j] = output->table_filters[k]; - output->table_sums[j] = output->table_sums[k]; - } - if (updated >= 0) - if (flush_filters(output, (size_t)updated) < 0) - return -1; - } - - return 0; -} - - -/** - * Send a message - * - * @param conn The index of the connection - * @param buf The data to send - * @param n The size of `buf` - * @return Zero on success, -1 on error, 1 if disconncted - * EINTR, EAGAIN, EWOULDBLOCK, and ECONNRESET count - * as success (ECONNRESET cause 1 to be returned), - * and are handled appropriately. - */ -static int send_message(size_t conn, char* restrict buf, size_t n) -{ - struct ring* restrict ring = outbound + conn; - int fd = connections[conn]; - int saved_errno; - size_t ptr = 0; - ssize_t sent; - size_t chunksize = n; - size_t sendsize; - size_t old_n; - char* old_buf; - - while ((old_buf = ring_peek(ring, &old_n))) - { - size_t old_ptr = 0; - while (old_ptr < n) - { - sendsize = old_n - old_ptr < chunksize ? old_n - old_ptr : chunksize; - sent = send(fd, old_buf + old_ptr, sendsize, 0); - if (sent < 0) - { - if (errno != EMSGSIZE) - goto fail; - chunksize >>= 1; - if (chunksize == 0) - goto fail; - continue; - } - old_ptr += (size_t)sent; - ring_pop(ring, (size_t)sent); - } - } - - while (ptr < n) - { - sendsize = n - ptr < chunksize ? n - ptr : chunksize; - sent = send(fd, buf + ptr, sendsize, 0); - if (sent < 0) - { - if (errno != EMSGSIZE) - goto fail; - chunksize >>= 1; - if (chunksize == 0) - goto fail; - continue; - } - ptr += (size_t)sent; - } - - free(buf); - return 0; - - fail: - switch (errno) - { - case EINTR: - case EAGAIN: -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif - if (ring_push(ring, buf + ptr, n - ptr) < 0) - goto proper_fail; - free(buf); - return 0; - case ECONNRESET: - free(buf); - if (connection_closed(fd) < 0) - return -1; - return 1; - default: - break; - } - proper_fail: - saved_errno = errno; - free(buf); - errno = saved_errno; - return -1; -} - - -/** - * Continue sending the queued messages - * - * @param conn The index of the connection - * @return Zero on success, -1 on error, 1 if disconncted - * EINTR, EAGAIN, EWOULDBLOCK, and ECONNRESET count - * as success (ECONNRESET cause 1 to be returned), - * and are handled appropriately. - */ -static inline int continue_send(size_t conn) -{ - return send_message(conn, NULL, 0); -} - - -/** - * Send a custom error without an error number - * - * @param ... The error description to send - * @return 1: Client disconnected - * 0: Success (possibily delayed) - * -1: An error occurred - */ -#define send_error(...) ((send_error)(conn, message_id, __VA_ARGS__)) - - -/** - * Send a custom error without an error number - * - * @param conn The index of the connection - * @param message_id The ID of the message to which this message is a response - * @param desc The error description to send - * @return 1: Client disconnected - * 0: Success (possibily delayed) - * -1: An error occurred - */ -GCC_ONLY(__attribute__((nonnull))) -static int (send_error)(size_t conn, const char* restrict message_id, const char* restrict desc) -{ - char* restrict buf; - size_t n; - - MAKE_MESSAGE(&buf, &n, 0, - "Command: error\n" - "In response to: %s\n" - "Error: custom\n" - "Length: %zu\n" - "\n" - "%s\n", - message_id, strlen(desc) + 1, desc); - - return send_message(conn, buf, n); -} - - -/** - * Send a standard error - * - * @param ... The value of `errno`, 0 to indicate success - * @return 1: Client disconnected - * 0: Success (possibily delayed) - * -1: An error occurred - */ -#define send_errno(...) ((send_errno)(conn, message_id, __VA_ARGS__)) - - -/** - * Send a standard error - * - * @param conn The index of the connection - * @param message_id The ID of the message to which this message is a response - * @param number The value of `errno`, 0 to indicate success - * @return 1: Client disconnected - * 0: Success (possibily delayed) - * -1: An error occurred - */ -GCC_ONLY(__attribute__((nonnull))) -static int (send_errno)(size_t conn, const char* restrict message_id, int number) -{ - char* restrict buf; - size_t n; - - MAKE_MESSAGE(&buf, &n, 0, - "Command: error\n" - "In response to: %s\n" - "Error: %i\n" - "\n", - message_id, number); - - return send_message(conn, buf, n); -} - - -/** - * Handle a ‘Command: enumerate-crtcs’ message - * - * @param conn The index of the connection - * @param message_id The value of the ‘Message ID’ header - * @return Zero on success (even if ignored), -1 on error, - * 1 if connection closed - */ -GCC_ONLY(__attribute__((nonnull))) -static int enumerate_crtcs(size_t conn, const char* restrict message_id) -{ - size_t i, n = 0, len; - char* restrict buf; - - for (i = 0; i < outputs_n; i++) - n += strlen(outputs[i].name) + 1; - - MAKE_MESSAGE(&buf, &n, 0, - "Command: crtc-enumeration\n" - "In response to: %s\n" - "Length: %zu\n" - "\n", - message_id, n); - - for (i = 0; i < outputs_n; i++) - { - len = strlen(outputs[i].name); - memcpy(buf + n, outputs[i].name, len); - buf[n + len] = '\n'; - n += len + 1; - } - - return send_message(conn, buf, n); -} - - -/** - * Handle a ‘Command: set-gamma’ message - * - * @param conn The index of the connection - * @param message_id The value of the ‘Message ID’ header - * @param crtc The value of the ‘CRTC’ header - * @return Zero on success (even if ignored), -1 on error, - * 1 if connection closed - */ -GCC_ONLY(__attribute__((nonnull(2)))) -static int get_gamma_info(size_t conn, const char* restrict message_id, const char* restrict crtc) -{ - struct output* restrict output; - char* restrict buf; - char depth[3]; - const char* supported; - size_t n; - - if (crtc == NULL) return send_error("protocol error: 'CRTC' header omitted"); - - output = output_find_by_name(crtc, outputs, outputs_n); - if (output == NULL) - return send_error("selected CRTC does not exist"); - - switch (output->depth) - { - case -2: strcpy(depth, "d"); break; - case -1: strcpy(depth, "f"); break; - default: - sprintf(depth, "%i", output->depth); - break; - } - - switch (output->supported) - { - case LIBGAMMA_YES: supported = "yes"; break; - case LIBGAMMA_NO: supported = "no"; break; - default: supported = "maybe"; break; - } - - MAKE_MESSAGE(&buf, &n, 0, - "In response to: %s\n" - "Cooperative: yes\n" - "Depth: %s\n" - "Red size: %zu\n" - "Green size: %zu\n" - "Blue size: %zu\n" - "Gamma support: %s\n" - "\n", - message_id, depth, output->red_size, output->green_size, - output->blue_size, supported); - - return send_message(conn, buf, n); -} - - -/** - * Handle a ‘Command: get-gamma’ message - * - * @param conn The index of the connection - * @param message_id The value of the ‘Message ID’ header - * @param crtc The value of the ‘CRTC’ header - * @param coalesce The value of the ‘Coalesce’ header - * @param high_priority The value of the ‘High priority’ header - * @param low_priority The value of the ‘Low priority’ header - * @return Zero on success (even if ignored), -1 on error, - * 1 if connection closed - */ -GCC_ONLY(__attribute__((nonnull(2)))) -static int get_gamma(size_t conn, const char* restrict message_id, const char* restrict crtc, - const char* restrict coalesce, const char* restrict high_priority, - const char* restrict low_priority) -{ - struct output* restrict output; - int64_t high, low; - int coal; - char* restrict buf; - size_t start, end, len, n, i; - char depth[3]; - char tables[sizeof("Tables: \n") + 3 * sizeof(size_t)]; - - if (crtc == NULL) return send_error("protocol error: 'CRTC' header omitted"); - if (coalesce == NULL) return send_error("protocol error: 'Coalesce' header omitted"); - if (high_priority == NULL) return send_error("protocol error: 'High priority' header omitted"); - if (low_priority == NULL) return send_error("protocol error: 'Low priority' header omitted"); - - high = (int64_t)atoll(high_priority); - low = (int64_t)atoll(low_priority); - - if (!strcmp(coalesce, "yes")) - coal = 1; - else if (!strcmp(coalesce, "no")) - coal = 0; - else - return send_error("protocol error: recognised value for 'Coalesce' header"); - - output = output_find_by_name(crtc, outputs, outputs_n); - if (output == NULL) - return send_error("selected CRTC does not exist"); - else if (output->supported == LIBGAMMA_NO) - return send_error("selected CRTC does not support gamma adjustments"); - - for (start = 0; start < output->table_size; start++) - if (output->table_filters[start].priority <= high) - break; - - for (end = output->table_size; end > 0; end--) - if (output->table_filters[end - 1].priority >= low) - break; - - switch (output->depth) - { - case -2: strcpy(depth, "d"); break; - case -1: strcpy(depth, "f"); break; - default: - sprintf(depth, "%i", output->depth); - break; - } - - if (coal) - { - *tables = '\0'; - n = output->ramps_size; - } - else - { - sprintf(tables, "Tables: %zu\n", end - start); - n = (sizeof(int64_t) + output->ramps_size) * (end - start); - for (i = start; i < end; i++) - n += strlen(output->table_filters[i].class) + 1; - } - - MAKE_MESSAGE(&buf, &n, 0, - "In response to: %s\n" - "Depth: %s\n" - "Red size: %zu\n" - "Green size: %zu\n" - "Blue size: %zu\n" - "%s" - "Length: %zu\n" - "\n", - message_id, depth, output->red_size, output->green_size, - output->blue_size, tables, n); - - if (coal) - { - if (start == 0) - memcpy(buf + n, output->table_sums[end].u8.red, output->ramps_size); - else - { - union gamma_ramps ramps; - if (make_plain_ramps(&ramps, output)) - { - int saved_errno = errno; - free(buf); - errno = saved_errno; - return -1; - } - for (i = start; i < end; i++) - apply(&ramps, output->table_filters[i].ramps, output->depth, &ramps); - memcpy(buf + n, ramps.u8.red, output->ramps_size); - libgamma_gamma_ramps8_destroy(&(ramps.u8)); - } - n += output->ramps_size; - } - else - for (i = start; i < end; i++) - { -#if defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-align" -#endif - *(int64_t*)(buf + n) = output->table_filters[i].priority; -#if defined(__clang__) -# pragma GCC diagnostic pop -#endif - n += sizeof(int64_t); - len = strlen(output->table_filters[i].class) + 1; - memcpy(buf + n, output->table_filters[i].class, len); - n += len; - memcpy(buf + n, output->table_filters[i].ramps, output->ramps_size); - n += output->ramps_size; - } - - return send_message(conn, buf, n); -} - - -/** - * Handle a ‘Command: set-gamma’ message - * - * @param conn The index of the connection - * @param message_id The value of the ‘Message ID’ header - * @param crtc The value of the ‘CRTC’ header - * @param priority The value of the ‘Priority’ header - * @param class The value of the ‘Class’ header - * @param lifespan The value of the ‘Lifespan’ header - * @return Zero on success (even if ignored), -1 on error, - * 1 if connection closed - */ -GCC_ONLY(__attribute__((nonnull(2)))) -static int set_gamma(size_t conn, const char* restrict message_id, const char* restrict crtc, - const char* restrict priority, const char* restrict class, const char* restrict lifespan) -{ - struct message* restrict msg = inbound + conn; - struct output* restrict output = NULL; - struct filter filter; - char* restrict p; - char* restrict q; - int saved_errno; - ssize_t r; - - if (crtc == NULL) return send_error("protocol error: 'CRTC' header omitted"); - if (class == NULL) return send_error("protocol error: 'Class' header omitted"); - if (lifespan == NULL) return send_error("protocol error: 'Lifespan' header omitted"); - - filter.client = connections[conn]; - filter.priority = priority == NULL ? 0 : (int64_t)atoll(priority); - filter.ramps = NULL; - - output = output_find_by_name(crtc, outputs, outputs_n); - if (output == NULL) - return send_error("CRTC does not exists"); - - p = strstr(class, "::"); - if ((p == NULL) || (p == class)) - return send_error("protocol error: malformatted value for 'Class' header"); - q = strstr(p + 2, "::"); - if ((q == NULL) || (q == p)) - return send_error("protocol error: malformatted value for 'Class' header"); - - if (!strcmp(lifespan, "until-removal")) - filter.lifespan = LIFESPAN_UNTIL_REMOVAL; - else if (!strcmp(lifespan, "until-death")) - filter.lifespan = LIFESPAN_UNTIL_DEATH; - else if (!strcmp(lifespan, "remove")) - filter.lifespan = LIFESPAN_REMOVE; - else - return send_error("protocol error: recognised value for 'Lifespan' header"); - - if (filter.lifespan == LIFESPAN_REMOVE) - { - if (msg->payload_size) - fprintf(stderr, "%s: ignoring superfluous payload on Command: set-gamma message with " - "Lifespan: remove\n", argv0); - if (priority != NULL) - fprintf(stderr, "%s: ignoring superfluous Priority header on Command: set-gamma message with " - "Lifespan: remove\n", argv0); - } - else if (msg->payload_size != output->ramps_size) - return send_error("invalid payload: size of message payload does matched the expectancy"); - else if (priority == NULL) - return send_error("protocol error: 'Priority' header omitted"); - - filter.class = memdup(class, strlen(class) + 1); - if (filter.class == NULL) - goto fail; - - if (filter.lifespan != LIFESPAN_REMOVE) - { - filter.ramps = memdup(msg->payload, msg->payload_size); - if (filter.ramps == NULL) - goto fail; - } - - if ((r = add_filter(output, &filter)) < 0) - goto fail; - filter.class = NULL; - filter.ramps = NULL; - if (flush_filters(output, (size_t)r)) - goto fail; - - return send_errno(0); - - fail: - saved_errno = errno; - send_errno(saved_errno); - free(filter.class); - free(filter.ramps); - errno = saved_errno; - return -1; -} - /** * Handle event on a connection to a client @@ -978,25 +212,25 @@ static int handle_connection(size_t conn) { if (crtc || coalesce || high_priority || low_priority || priority || class || lifespan) fprintf(stderr, "%s: ignoring superfluous headers in Command: enumerate-crtcs message\n", argv0); - r = enumerate_crtcs(conn, message_id); + r = handle_enumerate_crtcs(conn, message_id); } else if (!strcmp(command, "get-gamma-info")) { if (coalesce || high_priority || low_priority || priority || class || lifespan) fprintf(stderr, "%s: ignoring superfluous headers in Command: get-gamma-info message\n", argv0); - r = get_gamma_info(conn, message_id, crtc); + r = handle_get_gamma_info(conn, message_id, crtc); } else if (!strcmp(command, "get-gamma")) { if (priority || class || lifespan) fprintf(stderr, "%s: ignoring superfluous headers in Command: get-gamma message\n", argv0); - r = get_gamma(conn, message_id, crtc, coalesce, high_priority, low_priority); + r = handle_get_gamma(conn, message_id, crtc, coalesce, high_priority, low_priority); } else if (!strcmp(command, "set-gamma")) { if (coalesce || high_priority || low_priority) fprintf(stderr, "%s: ignoring superfluous headers in Command: set-gamma message\n", argv0); - r = set_gamma(conn, message_id, crtc, priority, class, lifespan); + r = handle_set_gamma(conn, message_id, crtc, priority, class, lifespan); } else fprintf(stderr, "%s: ignoring unrecognised command: Command: %s\n", argv0, command); @@ -1007,6 +241,22 @@ static int handle_connection(size_t conn) } + +/** + * Disconnect all clients + */ +void disconnect_all(void) +{ + size_t i; + for (i = 0; i < connections_used; i++) + if (connections[i] >= 0) + { + shutdown(connections[i], SHUT_RDWR); + close(connections[i]); + } +} + + /** * The program's main loop * @@ -1020,15 +270,11 @@ int main_loop(void) while (!reexec && !terminate) { - if (connection == 1) /* disconnect */ - { - connection = 0; - /* TODO */ - } - else if (connection >= 2) /* reconnect */ + if (connection) { connection = 0; - /* TODO */ + if ((connection == 1 ? disconnect() : reconnect()) < 0) + return -1; } memcpy(&fds_rd, &fds_orig, sizeof(fd_set)); diff --git a/src/server.h b/src/server.h index adf4c36..d3cf88c 100644 --- a/src/server.h +++ b/src/server.h @@ -15,82 +15,14 @@ * 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 "ring.h" +#ifndef SERVER_H +#define SERVER_H -#include <stddef.h> - - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * List of all client's file descriptors - * - * Unused slots, with index less than `connections_used`, - * should have the value -1 (negative) - */ -extern int* restrict connections; /** - * The number of elements allocated for `connections` + * Disconnect all clients */ -extern size_t connections_alloc; - -/** - * The index of the first unused slot in `connections` - */ -extern size_t connections_ptr; - -/** - * The index of the last used slot in `connections`, plus 1 - */ -extern size_t connections_used; - -/** - * The clients' connections' inbound-message buffers - */ -extern struct message* restrict inbound; - -/** - * The clients' connections' outbound-message buffers - */ -extern struct ring* restrict outbound; - - - -/** - * Destroy the state of the connections - * - * @param disconnect Disconnect all connections? - */ -void server_destroy(int disconnect); - -/** - * Marshal the state of the connections - * - * @param buf Output buffer for the marshalled data, - * `NULL` to only measure how many bytes - * this buffer needs - * @return The number of marshalled bytes - */ -size_t server_marshal(void* restrict buf); - -/** - * Unmarshal the state of the connections - * - * @param buf Buffer for the marshalled data - * @return The number of unmarshalled bytes, 0 on error - */ -size_t server_unmarshal(const void* restrict buf); +void disconnect_all(void); /** * The program's main loop @@ -99,3 +31,6 @@ size_t server_unmarshal(const void* restrict buf); */ int main_loop(void); + +#endif + diff --git a/src/state.c b/src/state.c new file mode 100644 index 0000000..a7fd57f --- /dev/null +++ b/src/state.c @@ -0,0 +1,363 @@ +/** + * 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 "state.h" +#include "util.h" + +#include <stdlib.h> +#include <string.h> + + + +/** + * The name of the process + */ +char* restrict argv0; /* do not marshal */ + +/** + * The real pathname of the process's binary, + * `NULL` if `argv0` is satisfactory + */ +char* restrict argv0_real = NULL; + +/** + * Array of all outputs + */ +struct output* restrict outputs = NULL; + +/** + * The nubmer of elements in `outputs` + */ +size_t outputs_n = 0; + +/** + * The server socket's file descriptor + */ +int socketfd = -1; + +/** + * Has the process receive a signal + * telling it to re-execute? + */ +volatile sig_atomic_t reexec = 0; /* do not marshal */ + +/** + * Has the process receive a signal + * telling it to terminate? + */ +volatile sig_atomic_t terminate = 0; /* do not marshal */ + +/** + * Has the process receive a to + * disconnect from or reconnect to + * the site? 1 if disconnct, 2 if + * reconnect, 0 otherwise. + */ +volatile sig_atomic_t connection = 0; + +/** + * List of all client's file descriptors + * + * Unused slots, with index less than `connections_used`, + * should have the value -1 (negative) + */ +int* restrict connections = NULL; + +/** + * The number of elements allocated for `connections` + */ +size_t connections_alloc = 0; + +/** + * The index of the first unused slot in `connections` + */ +size_t connections_ptr = 0; + +/** + * The index of the last used slot in `connections`, plus 1 + */ +size_t connections_used = 0; + +/** + * The clients' connections' inbound-message buffers + */ +struct message* restrict inbound = NULL; + +/** + * The clients' connections' outbound-message buffers + */ +struct ring* restrict outbound = NULL; + +/** + * Is the server connect to the display? + * + * Set to true before the initial connection + */ +int connected = 1; + +/** + * The adjustment method, -1 for automatic + */ +int method = -1; + +/** + * The site's name, may be `NULL` + */ +char* restrict sitename = NULL; + +/** + * The libgamma site state + */ +libgamma_site_state_t site; /* do not marshal */ + +/** + * The libgamma partition states + */ +libgamma_partition_state_t* restrict partitions = NULL; /* do not marshal */ + +/** + * The libgamma CRTC states + */ +libgamma_crtc_state_t* restrict crtcs = NULL; /* do not marshal */ + + + +/** + * Destroy the state + */ +void state_destroy(void) +{ + size_t i; + + for (i = 0; i < connections_used; i++) + if (connections[i] >= 0) + { + message_destroy(inbound + i); + ring_destroy(outbound + i); + } + free(inbound); + free(outbound); + free(connections); + + if (outputs != NULL) + for (i = 0; i < outputs_n; i++) + { + if (crtcs == NULL) + libgamma_crtc_destroy(outputs[i].crtc + i); + output_destroy(outputs + i); + } + free(outputs); + if (crtcs != NULL) + for (i = 0; i < outputs_n; i++) + libgamma_crtc_destroy(crtcs + i); + free(crtcs); + if (partitions != NULL) + for (i = 0; i < site.partitions_available; i++) + libgamma_partition_destroy(partitions + i); + free(partitions); + libgamma_site_destroy(&site); + + free(argv0_real); + free(sitename); +} + + +#if defined(__clang__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wcast-align" +#endif + + +/** + * Marshal the state + * + * @param buf Output buffer for the marshalled data, + * `NULL` to only measure how many bytes + * this buffer needs + * @return The number of marshalled bytes + */ +size_t state_marshal(void* restrict buf) +{ + size_t off = 0, i, n; + char* restrict bs = buf; + + if (argv0_real == NULL) + { + if (bs != NULL) + *(bs + off) = '\0'; + off += 1; + } + else + { + n = strlen(argv0_real) + 1; + if (bs != NULL) + memcpy(bs + off, argv0_real, n); + off += n; + } + + if (bs != NULL) + *(size_t*)(bs + off) = outputs_n; + off += sizeof(size_t); + + for (i = 0; i < outputs_n; i++) + off += output_marshal(outputs + i, bs ? bs + off : NULL); + + if (bs != NULL) + *(int*)(bs + off) = socketfd; + off += sizeof(int); + + if (bs != NULL) + *(sig_atomic_t*)(bs + off) = connection; + off += sizeof(sig_atomic_t); + + if (bs != NULL) + *(int*)(bs + off) = connected; + off += sizeof(int); + + if (bs != NULL) + *(size_t*)(bs + off) = connections_ptr; + off += sizeof(size_t); + + if (bs != NULL) + *(size_t*)(bs + off) = connections_used; + off += sizeof(size_t); + + if (bs != NULL) + memcpy(bs + off, connections, connections_used * sizeof(*connections)); + off += connections_used * sizeof(*connections); + + for (i = 0; i < connections_used; i++) + if (connections[i] >= 0) + { + off += message_marshal(inbound + i, bs ? bs + off : NULL); + off += ring_marshal(outbound + i, bs ? bs + off : NULL); + } + + if (bs != NULL) + *(int*)(bs + off) = method; + off += sizeof(int); + + if (bs != NULL) + *(int*)(bs + off) = sitename != NULL; + off += sizeof(int); + if (sitename != NULL) + { + n = strlen(sitename) + 1; + if (bs != NULL) + memcpy(bs + off, sitename, n); + off += n; + } + + return off; +} + + +/** + * Unmarshal the state + * + * @param buf Buffer for the marshalled data + * @return The number of unmarshalled bytes, 0 on error + */ +size_t state_unmarshal(const void* restrict buf) +{ + size_t off = 0, i, n; + const char* restrict bs = buf; + + connections = NULL; + inbound = NULL; + + if (*(bs + off)) + { + off += 1; + n = strlen(bs + off) + 1; + if (!(argv0_real = memdup(bs + off, n))) + return 0; + off += n; + } + else + off += 1; + + outputs_n = *(const size_t*)(bs + off); + off += sizeof(size_t); + + for (i = 0; i < outputs_n; i++) + { + off += n = output_unmarshal(outputs + i, bs + off); + if (n == 0) + return 0; + } + + socketfd = *(const int*)(bs + off); + off += sizeof(int); + + connection = *(const sig_atomic_t*)(bs + off); + off += sizeof(sig_atomic_t); + + connected = *(const int*)(bs + off); + off += sizeof(int); + + connections_ptr = *(const size_t*)(bs + off); + off += sizeof(size_t); + + connections_alloc = connections_used = *(const size_t*)(bs + off); + off += sizeof(size_t); + + if (connections_alloc > 0) + { + connections = memdup(bs + off, connections_alloc * sizeof(*connections)); + if (connections == NULL) + return 0; + off += connections_used * sizeof(*connections); + + inbound = malloc(connections_alloc * sizeof(*inbound)); + if (inbound == NULL) + return 0; + } + + for (i = 0; i < connections_used; i++) + if (connections[i] >= 0) + { + off += n = message_unmarshal(inbound + i, bs + off); + if (n == 0) + return 0; + off += n = ring_unmarshal(outbound + i, bs + off); + if (n == 0) + return 0; + } + + method = *(const int*)(bs + off); + off += sizeof(int); + + if (*(const int*)(bs + off)) + { + off += sizeof(int); + n = strlen(bs + off) + 1; + if (!(sitename = memdup(bs + off, n))) + return 0; + off += n; + } + else + off += sizeof(int); + + return off; +} + + +#if defined(__clang__) +# pragma GCC diagnostic pop +#endif + diff --git a/src/state.h b/src/state.h new file mode 100644 index 0000000..0a09023 --- /dev/null +++ b/src/state.h @@ -0,0 +1,182 @@ +/** + * 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 STATE_H +#define STATE_H + + +#include "types/message.h" +#include "types/ring.h" +#include "types/output.h" + +#include <libgamma.h> + +#include <stddef.h> +#include <signal.h> + + + +#ifndef GCC_ONLY +# if defined(__GNUC__) && !defined(__clang__) +# define GCC_ONLY(...) __VA_ARGS__ +# else +# define GCC_ONLY(...) /* nothing */ +# endif +#endif + + + +/** + * The name of the process + */ +extern char* restrict argv0; + +/** + * The real pathname of the process's binary, + * `NULL` if `argv0` is satisfactory + */ +extern char* restrict argv0_real; + +/** + * Array of all outputs + */ +extern struct output* restrict outputs; + +/** + * The nubmer of elements in `outputs` + */ +extern size_t outputs_n; + +/** + * The server socket's file descriptor + */ +extern int socketfd; + +/** + * Has the process receive a signal + * telling it to re-execute? + */ +extern volatile sig_atomic_t reexec; + +/** + * Has the process receive a signal + * telling it to terminate? + */ +extern volatile sig_atomic_t terminate; + +/** + * Has the process receive a to + * disconnect from or reconnect to + * the site? 1 if disconnct, 2 if + * reconnect, 0 otherwise. + */ +extern volatile sig_atomic_t connection; + +/** + * List of all client's file descriptors + * + * Unused slots, with index less than `connections_used`, + * should have the value -1 (negative) + */ +extern int* restrict connections; + +/** + * The number of elements allocated for `connections` + */ +extern size_t connections_alloc; + +/** + * The index of the first unused slot in `connections` + */ +extern size_t connections_ptr; + +/** + * The index of the last used slot in `connections`, plus 1 + */ +extern size_t connections_used; + +/** + * The clients' connections' inbound-message buffers + */ +extern struct message* restrict inbound; + +/** + * The clients' connections' outbound-message buffers + */ +extern struct ring* restrict outbound; + +/** + * Is the server connect to the display? + * + * Set to true before the initial connection + */ +extern int connected; + +/** + * The adjustment method, -1 for automatic + */ +extern int method; + +/** + * The site's name, may be `NULL` + */ +extern char* restrict sitename; + +/** + * The libgamma site state + */ +extern libgamma_site_state_t site; + +/** + * The libgamma partition states + */ +extern libgamma_partition_state_t* restrict partitions; + +/** + * The libgamma CRTC states + */ +extern libgamma_crtc_state_t* restrict crtcs; + + + +/** + * Destroy the state + */ +void state_destroy(void); + +/** + * Marshal the state + * + * @param buf Output buffer for the marshalled data, + * `NULL` to only measure how many bytes + * this buffer needs + * @return The number of marshalled bytes + */ +size_t state_marshal(void* restrict buf); + +/** + * Unmarshal the state + * + * @param buf Buffer for the marshalled data + * @return The number of unmarshalled bytes, 0 on error + */ +GCC_ONLY(__attribute__((nonnull))) +size_t state_unmarshal(const void* restrict buf); + + +#endif + diff --git a/src/filter.c b/src/types/filter.c index c335e0b..e6facc9 100644 --- a/src/filter.c +++ b/src/types/filter.c @@ -16,7 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "filter.h" -#include "util.h" +#include "../util.h" #include <stdlib.h> #include <string.h> diff --git a/src/filter.h b/src/types/filter.h index 5691f6c..c9e01bb 100644 --- a/src/filter.h +++ b/src/types/filter.h @@ -15,6 +15,10 @@ * 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> @@ -129,3 +133,6 @@ size_t filter_marshal(const struct filter* restrict this, void* restrict buf, si 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/message.c b/src/types/message.c index 48bdbff..e7c844d 100644 --- a/src/message.c +++ b/src/types/message.c @@ -16,7 +16,7 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "message.h" -#include "util.h" +#include "../util.h" #include <sys/socket.h> #include <errno.h> diff --git a/src/message.h b/src/types/message.h index 15a9330..00a2a50 100644 --- a/src/message.h +++ b/src/types/message.h @@ -15,6 +15,10 @@ * 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> @@ -151,3 +155,6 @@ size_t message_unmarshal(struct message* restrict this, const void* restrict buf GCC_ONLY(__attribute__((nonnull))) int message_read(struct message* restrict this, int fd); + +#endif + diff --git a/src/output.c b/src/types/output.c index e8913dd..8576baa 100644 --- a/src/output.c +++ b/src/types/output.c @@ -16,24 +16,14 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "output.h" -#include "util.h" +#include "../util.h" -#include <libclut.h> - -#include <stdio.h> #include <stdlib.h> #include <string.h> /** - * The name of the process - */ -extern char* restrict argv0; - - - -/** * Free all resources allocated to an output. * The allocation of `output` itself is not freed, * nor is its the libgamma destroyed. @@ -272,211 +262,3 @@ struct output* output_find_by_name(const char* restrict key, struct output* rest return bsearch(&k, base, n, sizeof(*base), output_cmp_by_name); } - -/** - * Remove a filter from an output - * - * @param out The output - * @param filter The filter - * @return The index of the filter, `out->table_size` if not found - */ -static ssize_t remove_filter(struct output* restrict out, struct filter* restrict filter) -{ - size_t i, n = out->table_size; - - for (i = 0; i < n; i++) - if (!strcmp(filter->class, out->table_filters[i].class)) - break; - - if (i == out->table_size) - { - fprintf(stderr, "%s: ignoring attempt to removing non-existing filter on CRTC %s: %s", - argv0, out->name, filter->class); - return (ssize_t)(out->table_size); - } - - filter_destroy(out->table_filters + i); - libgamma_gamma_ramps8_destroy(&(out->table_sums[i].u8)); - - n = n - i - 1; - memmove(out->table_filters + i, out->table_filters + i + 1, n * sizeof(*(out->table_filters))); - memmove(out->table_sums + i, out->table_sums + i + 1, n * sizeof(*(out->table_sums))); - out->table_size--; - - return (ssize_t)i; -} - - -/** - * Add a filter to an output - * - * @param out The output - * @param filter The filter - * @return The index given to the filter, -1 on error - */ -ssize_t add_filter(struct output* restrict out, struct filter* restrict filter) -{ - size_t i, n = out->table_size; - int r = -1; - - /* Remove? */ - if (filter->lifespan == LIFESPAN_REMOVE) - return remove_filter(out, filter); - - /* Update? */ - for (i = 0; i < n; i++) - if (!strcmp(filter->class, out->table_filters[i].class)) - break; - if (i != n) - { - filter_destroy(out->table_filters + i); - out->table_filters[i] = *filter; - return (ssize_t)i; - } - - /* Add! */ - for (i = 0; i < n; i++) - if (filter->priority > out->table_filters[i].priority) - break; - - if (n == out->table_alloc) - { - void* new; - - new = realloc(out->table_filters, (n + 10) * sizeof(*(out->table_filters))); - if (new == NULL) - return -1; - out->table_filters = new; - - new = realloc(out->table_sums, (n + 10) * sizeof(*(out->table_sums))); - if (new == NULL) - return -1; - out->table_sums = new; - - out->table_alloc += 10; - } - - memmove(out->table_filters + i + 1, out->table_filters + i, (n - i) * sizeof(*(out->table_filters))); - memmove(out->table_sums + i + 1, out->table_sums + i, (n - i) * sizeof(*(out->table_sums))); - out->table_size++; - - COPY_RAMP_SIZES(&(out->table_sums[i].u8), out); - switch (out->depth) - { - case 8: r = libgamma_gamma_ramps8_initialise(&(out->table_sums[i].u8)); break; - case 16: r = libgamma_gamma_ramps16_initialise(&(out->table_sums[i].u16)); break; - case 32: r = libgamma_gamma_ramps32_initialise(&(out->table_sums[i].u32)); break; - case 64: r = libgamma_gamma_ramps64_initialise(&(out->table_sums[i].u64)); break; - case -1: r = libgamma_gamma_rampsf_initialise(&(out->table_sums[i].f)); break; - case -2: r = libgamma_gamma_rampsd_initialise(&(out->table_sums[i].d)); break; - default: - abort(); - } - if (r < 0) - return -1; - - out->table_filters[i] = *filter; - - return (ssize_t)i; -} - - -/** - * Recalculate the resulting gamma and - * update push the new gamma ramps to the CRTC - * - * @param output The output - * @param first_updated The index of the first added or removed filter - * @return Zero on success, -1 on error - */ -int flush_filters(struct output* restrict output, size_t first_updated) -{ - union gamma_ramps plain; - union gamma_ramps* last; - size_t i; - int r = 0; - - if (first_updated == 0) - { - if (make_plain_ramps(&plain, output) < 0) - return -1; - last = &plain; - } - else - last = output->table_sums + (first_updated - 1); - - for (i = first_updated; i < output->table_size; i++) - { - apply(output->table_sums + i, output->table_filters[i].ramps, output->depth, last); - last = output->table_sums + i; - } - - switch (output->depth) - { - case 8: r = libgamma_crtc_set_gamma_ramps8(output->crtc, last->u8); break; - case 16: r = libgamma_crtc_set_gamma_ramps16(output->crtc, last->u16); break; - case 32: r = libgamma_crtc_set_gamma_ramps32(output->crtc, last->u32); break; - case 64: r = libgamma_crtc_set_gamma_ramps64(output->crtc, last->u64); break; - case -1: r = libgamma_crtc_set_gamma_rampsf(output->crtc, last->f); break; - case -2: r = libgamma_crtc_set_gamma_rampsd(output->crtc, last->d); break; - default: - abort(); - } - if (r) - libgamma_perror(argv0, r); /* Not fatal */ - - if (first_updated == 0) - libgamma_gamma_ramps8_destroy(&(plain.u8)); - - return 0; -} - - -/** - * Make identity mapping ramps - * - * @param ramps Output parameter for the ramps - * @param output The output for which the ramps shall be configured - * @return Zero on success, -1 on error - */ -int make_plain_ramps(union gamma_ramps* restrict ramps, struct output* restrict output) -{ - COPY_RAMP_SIZES(&(ramps->u8), output); - switch (output->depth) - { - case 8: - if (libgamma_gamma_ramps8_initialise(&(ramps->u8))) - return -1; - libclut_start_over(&(ramps->u8), UINT8_MAX, uint8_t, 1, 1, 1); - break; - case 16: - if (libgamma_gamma_ramps16_initialise(&(ramps->u16))) - return -1; - libclut_start_over(&(ramps->u16), UINT16_MAX, uint16_t, 1, 1, 1); - break; - case 32: - if (libgamma_gamma_ramps32_initialise(&(ramps->u32))) - return -1; - libclut_start_over(&(ramps->u32), UINT32_MAX, uint32_t, 1, 1, 1); - break; - case 64: - if (libgamma_gamma_ramps64_initialise(&(ramps->u64))) - return -1; - libclut_start_over(&(ramps->u64), UINT64_MAX, uint64_t, 1, 1, 1); - break; - case -1: - if (libgamma_gamma_rampsf_initialise(&(ramps->f))) - return -1; - libclut_start_over(&(ramps->f), 1.0f, float, 1, 1, 1); - break; - case -2: - if (libgamma_gamma_rampsd_initialise(&(ramps->d))) - return -1; - libclut_start_over(&(ramps->d), (double)1, double, 1, 1, 1); - break; - default: - abort(); - } - return 0; -} - diff --git a/src/output.h b/src/types/output.h index 08978b5..f8a4c3e 100644 --- a/src/output.h +++ b/src/types/output.h @@ -15,6 +15,10 @@ * 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> @@ -197,34 +201,6 @@ int output_cmp_by_name(const void* restrict a, const void* restrict b); GCC_ONLY(__attribute__((pure, nonnull))) struct output* output_find_by_name(const char* restrict key, struct output* restrict base, size_t n); -/** - * Add a filter to an output - * - * @param output The output - * @param filter The filter - * @return The index given to the filter, -1 on error - */ -GCC_ONLY(__attribute__((nonnull))) -ssize_t add_filter(struct output* restrict output, struct filter* restrict filter); - -/** - * Recalculate the resulting gamma and - * update push the new gamma ramps to the CRTC - * - * @param output The output - * @param first_updated The index of the first added or removed filter - * @return Zero on success, -1 on error - */ -GCC_ONLY(__attribute__((nonnull))) -int flush_filters(struct output* restrict output, size_t first_updated); -/** - * Make identity mapping ramps - * - * @param ramps Output parameter for the ramps - * @param output The output for which the ramps shall be configured - * @return Zero on success, -1 on error - */ -GCC_ONLY(__attribute__((nonnull))) -int make_plain_ramps(union gamma_ramps* restrict ramps, struct output* restrict output); +#endif diff --git a/src/ramps.c b/src/types/ramps.c index 2b855a4..30bed3e 100644 --- a/src/ramps.c +++ b/src/types/ramps.c @@ -96,70 +96,3 @@ size_t gamma_ramps_unmarshal(union gamma_ramps* restrict this, const void* restr return ramps_size; } - -/** - * Apply a ramp-trio on top of another ramp-trio - * - * @param dest The output for the resulting ramp-trio, must be initialised - * @param application The red, green and blue ramps, as one single raw array, - * of the filter that should be applied - * @param depth -1: `float` stops - * -2: `double` stops - * Other: the number of bits of each (integral) stop - * @param base The CLUT on top of which the new filter should be applied, - * this can be the same pointer as `dest` - */ -void apply(union gamma_ramps* restrict dest, void* restrict application, - int depth, union gamma_ramps* restrict base) -{ - union gamma_ramps app; - size_t bytedepth; - size_t red_width, green_width, blue_width; - - if (depth == -1) - bytedepth = sizeof(float); - else if (depth == -2) - bytedepth = sizeof(double); - else - bytedepth = (size_t)depth / 8; - - red_width = (app.u8.red_size = base->u8.red_size) * bytedepth; - green_width = (app.u8.green_size = base->u8.green_size) * bytedepth; - blue_width = (app.u8.blue_size = base->u8.blue_size) * bytedepth; - - app.u8.red = application; - app.u8.green = app.u8.red + red_width; - app.u8.blue = app.u8.green + green_width; - - if (dest != base) - { - memcpy(dest->u8.red, base->u8.red, red_width); - memcpy(dest->u8.green, base->u8.green, green_width); - memcpy(dest->u8.blue, base->u8.blue, blue_width); - } - - switch (depth) - { - case 8: - libclut_apply(&(dest->u8), UINT8_MAX, uint8_t, &(app.u8), UINT8_MAX, uint8_t, 1, 1, 1); - break; - case 16: - libclut_apply(&(dest->u16), UINT16_MAX, uint16_t, &(app.u16), UINT16_MAX, uint16_t, 1, 1, 1); - break; - case 32: - libclut_apply(&(dest->u32), UINT32_MAX, uint32_t, &(app.u32), UINT32_MAX, uint32_t, 1, 1, 1); - break; - case 64: - libclut_apply(&(dest->u64), UINT64_MAX, uint64_t, &(app.u64), UINT64_MAX, uint64_t, 1, 1, 1); - break; - case -1: - libclut_apply(&(dest->f), 1.0f, float, &(app.d), 1.0f, float, 1, 1, 1); - break; - case -2: - libclut_apply(&(dest->d), (double)1, double, &(app.f), (double)1, double, 1, 1, 1); - break; - default: - abort(); - } -} - diff --git a/src/ramps.h b/src/types/ramps.h index 0ba8579..001d504 100644 --- a/src/ramps.h +++ b/src/types/ramps.h @@ -15,6 +15,10 @@ * 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> @@ -93,19 +97,6 @@ size_t gamma_ramps_marshal(const union gamma_ramps* restrict this, void* restric GCC_ONLY(__attribute__((nonnull))) size_t gamma_ramps_unmarshal(union gamma_ramps* restrict this, const void* restrict buf, size_t ramps_size); -/** - * Apply a ramp-trio on top of another ramp-trio - * - * @param dest The output for the resulting ramp-trio, must be initialised - * @param application The red, green and blue ramps, as one single raw array, - * of the filter that should be applied - * @param depth -1: `float` stops - * -2: `double` stops - * Other: the number of bits of each (integral) stop - * @param base The CLUT on top of which the new filter should be applied, - * this can be the same pointer as `dest` - */ -GCC_ONLY(__attribute__((nonnull))) -void apply(union gamma_ramps* restrict dest, void* restrict application, - int depth, union gamma_ramps* restrict base); + +#endif diff --git a/src/ring.c b/src/types/ring.c index 13cf8c9..13cf8c9 100644 --- a/src/ring.c +++ b/src/types/ring.c diff --git a/src/ring.h b/src/types/ring.h index 5825810..0474f39 100644 --- a/src/ring.h +++ b/src/types/ring.h @@ -15,6 +15,10 @@ * 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> @@ -143,3 +147,6 @@ static inline int ring_have_more(struct ring* restrict this) return this->buffer != NULL; } + +#endif + @@ -15,6 +15,10 @@ * 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 UTIL_H +#define UTIL_H + + #include <stddef.h> @@ -97,3 +101,6 @@ void msleep(int ms); GCC_ONLY(__attribute__((pure, nonnull))) int verify_utf8(const char* restrict string, int allow_modified_nul); + +#endif + |