aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile18
-rw-r--r--src/arg.h2
-rw-r--r--src/communication.c171
-rw-r--r--src/communication.h137
-rw-r--r--src/coopgamma-server/chaining.c257
-rw-r--r--src/coopgamma-server/chaining.h75
-rw-r--r--src/coopgamma-server/server.c335
-rw-r--r--src/coopgamma-server/server.h93
-rw-r--r--src/coopgammad.c265
-rw-r--r--src/crtc-server/server.c59
-rw-r--r--src/crtc-server/server.h49
-rw-r--r--src/gamma-server/server.c144
-rw-r--r--src/gamma-server/server.h75
-rw-r--r--src/server.c810
-rw-r--r--src/server.h79
-rw-r--r--src/state.c363
-rw-r--r--src/state.h182
-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.h7
28 files changed, 2075 insertions, 1413 deletions
diff --git a/Makefile b/Makefile
index 4e2139c..921121a 100644
--- a/Makefile
+++ b/Makefile
@@ -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 $@ $<
diff --git a/src/arg.h b/src/arg.h
index 97e5980..8418b38 100644
--- a/src/arg.h
+++ b/src/arg.h
@@ -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
+
diff --git a/src/util.h b/src/util.h
index c1f8934..7429f5f 100644
--- a/src/util.h
+++ b/src/util.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 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
+