diff options
Diffstat (limited to '')
-rw-r--r-- | arg.h (renamed from src/arg.h) | 0 | ||||
-rw-r--r-- | communication.h (renamed from src/communication.h) | 73 | ||||
-rw-r--r-- | servers-coopgamma.h (renamed from src/servers/coopgamma.h) | 51 | ||||
-rw-r--r-- | servers-crtc.h (renamed from src/servers/crtc.h) | 43 | ||||
-rw-r--r-- | src/communication.c | 175 | ||||
-rw-r--r-- | src/coopgammad.c | 895 | ||||
-rw-r--r-- | src/servers/coopgamma.c | 558 | ||||
-rw-r--r-- | src/servers/crtc.c | 325 | ||||
-rw-r--r-- | src/servers/gamma.c | 398 | ||||
-rw-r--r-- | src/servers/gamma.h | 85 | ||||
-rw-r--r-- | src/servers/kernel.c | 384 | ||||
-rw-r--r-- | src/servers/kernel.h | 85 | ||||
-rw-r--r-- | src/servers/master.c | 394 | ||||
-rw-r--r-- | src/servers/master.h | 36 | ||||
-rw-r--r-- | src/state.c | 638 | ||||
-rw-r--r-- | src/types/filter.c | 144 | ||||
-rw-r--r-- | src/types/filter.h | 138 | ||||
-rw-r--r-- | src/types/message.c | 572 | ||||
-rw-r--r-- | src/types/message.h | 160 | ||||
-rw-r--r-- | src/types/output.c | 335 | ||||
-rw-r--r-- | src/types/output.h | 308 | ||||
-rw-r--r-- | src/types/ramps.c | 98 | ||||
-rw-r--r-- | src/types/ramps.h | 102 | ||||
-rw-r--r-- | src/types/ring.c | 224 | ||||
-rw-r--r-- | src/types/ring.h | 152 | ||||
-rw-r--r-- | src/util.c | 316 | ||||
-rw-r--r-- | src/util.h | 115 | ||||
-rw-r--r-- | state.h (renamed from src/state.h) | 61 |
28 files changed, 63 insertions, 6802 deletions
diff --git a/src/communication.h b/communication.h index 244ba9d..b40022b 100644 --- a/src/communication.h +++ b/communication.h @@ -1,39 +1,18 @@ -/** - * 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/>. - */ +/* See LICENSE file for copyright and license details. */ #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__ +# define GCC_ONLY(...) __VA_ARGS__ # else -# define GCC_ONLY(...) /* nothing */ +# define GCC_ONLY(...) /* nothing */ # endif #endif - - /** * Construct a message * @@ -43,18 +22,16 @@ * @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__ + (size_t)1); \ - if (*(bufp) == NULL) \ - return -1; \ - sprintf(*(bufp), format, __VA_ARGS__); \ - *(np) = (size_t)m__; \ - } \ - while (0) +#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__ + (size_t)1);\ + if (!*(bufp))\ + return -1;\ + sprintf(*(bufp), format, __VA_ARGS__);\ + *(np) = (size_t)m__;\ + } while (0) /** * Send a custom error without an error number @@ -64,7 +41,7 @@ * 0: Success (possibily delayed) * -1: An error occurred */ -#define send_error(...) ((send_error)(conn, message_id, __VA_ARGS__)) +#define send_error(...) ((send_error)(conn, message_id, __VA_ARGS__)) /** * Send a standard error @@ -74,9 +51,7 @@ * 0: Success (possibily delayed) * -1: An error occurred */ -#define send_errno(...) ((send_errno)(conn, message_id, __VA_ARGS__)) - - +#define send_errno(...) ((send_errno)(conn, message_id, __VA_ARGS__)) /** * Send a message @@ -89,7 +64,7 @@ * as success (ECONNRESET cause 1 to be returned), * and are handled appropriately. */ -int send_message(size_t conn, char* restrict buf, size_t n); +int send_message(size_t conn, char *restrict buf, size_t n); /** * Send a custom error without an error number @@ -101,8 +76,8 @@ int send_message(size_t conn, char* restrict buf, size_t n); * 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); +GCC_ONLY(__attribute__((__nonnull__))) +int (send_error)(size_t conn, const char *restrict message_id, const char *restrict desc); /** * Send a standard error @@ -114,8 +89,8 @@ int (send_error)(size_t conn, const char* restrict message_id, const char* restr * 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); +GCC_ONLY(__attribute__((__nonnull__))) +int (send_errno)(size_t conn, const char *restrict message_id, int number); /** * Continue sending the queued messages @@ -126,12 +101,10 @@ int (send_errno)(size_t conn, const char* restrict message_id, int number); * as success (ECONNRESET cause 1 to be returned), * and are handled appropriately. */ -static inline int continue_send(size_t conn) +static inline int +continue_send(size_t conn) { - return send_message(conn, NULL, 0); + return send_message(conn, NULL, 0); } - - #endif - diff --git a/src/servers/coopgamma.h b/servers-coopgamma.h index 5a9f7d9..584e760 100644 --- a/src/servers/coopgamma.h +++ b/servers-coopgamma.h @@ -1,40 +1,19 @@ -/** - * 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/>. - */ +/* See LICENSE file for copyright and license details. */ #ifndef SERVERS_COOPGAMMA_H #define SERVERS_COOPGAMMA_H - -#include "../types/output.h" +#include "types-output.h" #include <stddef.h> - - #ifndef GCC_ONLY # if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ +# define GCC_ONLY(...) __VA_ARGS__ # else -# define GCC_ONLY(...) /* nothing */ +# define GCC_ONLY(...) /* nothing */ # endif #endif - - /** * Handle a closed connection * @@ -55,10 +34,10 @@ int connection_closed(int client); * @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); +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 @@ -72,10 +51,9 @@ int handle_get_gamma(size_t conn, const char* restrict message_id, const char* r * @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); - +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 @@ -85,9 +63,8 @@ int handle_set_gamma(size_t conn, const char* restrict message_id, const char* r * @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); - +GCC_ONLY(__attribute__((__nonnull__))) +int flush_filters(struct output *restrict output, size_t first_updated); /** * Preserve current gamma ramps at priority 0 for all outputs @@ -96,6 +73,4 @@ int flush_filters(struct output* restrict output, size_t first_updated); */ int preserve_gamma(void); - #endif - diff --git a/src/servers/crtc.h b/servers-crtc.h index 68239d4..08e4b02 100644 --- a/src/servers/crtc.h +++ b/servers-crtc.h @@ -1,40 +1,19 @@ -/** - * 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/>. - */ +/* See LICENSE file for copyright and license details. */ #ifndef SERVERS_CRTC_H #define SERVERS_CRTC_H - -#include "../types/output.h" +#include "types-output.h" #include <libgamma.h> - - #ifndef GCC_ONLY # if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ +# define GCC_ONLY(...) __VA_ARGS__ # else -# define GCC_ONLY(...) /* nothing */ +# define GCC_ONLY(...) /* nothing */ # endif #endif - - /** * Handle a ‘Command: enumerate-crtcs’ message * @@ -43,8 +22,8 @@ * @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); +GCC_ONLY(__attribute__((__nonnull__))) +int handle_enumerate_crtcs(size_t conn, const char *restrict message_id); /** * Get the name of a CRTC @@ -53,9 +32,8 @@ int handle_enumerate_crtcs(size_t conn, const char* restrict message_id); * @param crtc libgamma's state for the CRTC * @return The name of the CRTC, `NULL` on error */ -GCC_ONLY(__attribute__((nonnull))) -char* get_crtc_name(const libgamma_crtc_information_t* restrict info, - const libgamma_crtc_state_t* restrict crtc); +GCC_ONLY(__attribute__((__nonnull__))) +char *get_crtc_name(const libgamma_crtc_information_t *restrict info, const libgamma_crtc_state_t *restrict crtc); /** * Initialise the site @@ -78,8 +56,7 @@ int initialise_crtcs(void); * @param old_outputs_n The old `outputs_n` * @return Zero on success, -1 on error */ -int merge_state(struct output* restrict old_outputs, size_t old_outputs_n); - +int merge_state(struct output *restrict old_outputs, size_t old_outputs_n); /** * Disconnect from the site @@ -95,6 +72,4 @@ int disconnect(void); */ int reconnect(void); - #endif - diff --git a/src/communication.c b/src/communication.c deleted file mode 100644 index 9ede401..0000000 --- a/src/communication.c +++ /dev/null @@ -1,175 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "communication.h" -#include "state.h" -#include "servers/coopgamma.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, MSG_NOSIGNAL); - if (sent < 0) - { - if (errno == EPIPE) - errno = ECONNRESET; - 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, MSG_NOSIGNAL); - if (sent < 0) - { - if (errno == EPIPE) - errno = ECONNRESET; - 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/coopgammad.c b/src/coopgammad.c deleted file mode 100644 index e81840e..0000000 --- a/src/coopgammad.c +++ /dev/null @@ -1,895 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "arg.h" -#include "util.h" -#include "state.h" -#include "servers/master.h" -#include "servers/kernel.h" -#include "servers/crtc.h" -#include "servers/gamma.h" -#include "servers/coopgamma.h" - -#include <sys/resource.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <errno.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - - - -/** - * Number put in front of the marshalled data - * so the program an detect incompatible updates - */ -#define MARSHAL_VERSION 0 - - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * Lists all function recognised adjustment methods, - * will call macro X with the code for the each - * adjustment method as the first argument and - * corresponding name as the second argument - */ -#define LIST_ADJUSTMENT_METHODS \ - X(LIBGAMMA_METHOD_DUMMY, "dummy") \ - X(LIBGAMMA_METHOD_X_RANDR, "randr") \ - X(LIBGAMMA_METHOD_X_VIDMODE, "vidmode") \ - X(LIBGAMMA_METHOD_LINUX_DRM, "drm") \ - X(LIBGAMMA_METHOD_W32_GDI, "gdi") \ - X(LIBGAMMA_METHOD_QUARTZ_CORE_GRAPHICS, "quartz") - - - -/** - * Used by initialisation functions as their return type. If a - * value not listed here is returned by such function, it is the - * exit value the process shall exit with as soon as possible. - */ -enum init_status -{ - /** - * Initialisation was successful - */ - INIT_SUCCESS = -1, - - /** - * Initialisation failed - */ - INIT_FAILURE = -2, - - /** - * Server is already running - */ - INIT_RUNNING = -3, -}; - - - -/** - * The pathname of the PID file - */ -extern char* restrict pidpath; -char* restrict pidpath = NULL; - -/** - * The pathname of the socket - */ -extern char* restrict socketpath; -char* restrict socketpath = NULL; - - - -/** - * Called when the process receives - * a signal telling it to re-execute - * - * @param signo The received signal - */ -static void sig_reexec(int signo) -{ - int saved_errno = errno; - reexec = 1; - signal(signo, sig_reexec); - errno = saved_errno; -} - - -/** - * Called when the process receives - * a signal telling it to terminate - * - * @param signo The received signal - */ -static void sig_terminate(int signo) -{ - terminate = 1; - (void) signo; -} - - -/** - * Called when the process receives - * a signal telling it to disconnect - * from or reconnect to the site - * - * @param signo The received signal - */ -static void sig_connection(int signo) -{ - int saved_errno = errno; - connection = signo - SIGRTMIN + 1; - signal(signo, sig_connection); - errno = saved_errno; -} - - -/** - * Called when the process receives - * a signal telling it to dump its - * state to stderr - * - * @param signo The received signal - */ -static void sig_info(int signo) -{ - int saved_errno = errno; - char* env; - signal(signo, sig_info); - env = getenv("COOPGAMMAD_PIDFILE_TOKEN"); - fprintf(stderr, "PID file token: %s\n", env ? env : "(null)"); - fprintf(stderr, "PID file: %s\n", pidpath ? pidpath : "(null)"); - fprintf(stderr, "Socket path: %s\n", socketpath ? socketpath : "(null)"); - state_dump(); - errno = saved_errno; -} - - -/** - * Parse adjustment method name (or stringised number) - * - * @param arg The adjustment method name (or stringised number) - * @return The adjustment method, -1 (negative) on error - */ -GCC_ONLY(__attribute__((nonnull))) -static int get_method(const char* restrict arg) -{ -#if LIBGAMMA_METHOD_MAX > 5 -# warning libgamma has added more adjustment methods -#endif - - const char* restrict p; - -#define X(C, N) if (!strcmp(arg, N)) return C; - LIST_ADJUSTMENT_METHODS; -#undef X - - if (!*arg || (/* avoid overflow: */ strlen(arg) > 4)) - goto bad; - for (p = arg; *p; p++) - if (('0' > *p) || (*p > '9')) - goto bad; - - return atoi(arg); - - bad: - fprintf(stderr, "%s: unrecognised adjustment method name: %s\n", argv0, arg); - errno = 0; - return -1; -} - - -/** - * Set up signal handlers - * - * @return Zero on success, -1 on error - */ -static int set_up_signals(void) -{ - if ((signal(SIGUSR1, sig_reexec) == SIG_ERR) || - (signal(SIGUSR2, sig_info) == SIG_ERR) || -#if defined(SIGINFO) - (signal(SIGINFO, sig_info) == SIG_ERR) || -#endif - (signal(SIGTERM, sig_terminate) == SIG_ERR) || - (signal(SIGRTMIN + 0, sig_connection) == SIG_ERR) || - (signal(SIGRTMIN + 1, sig_connection) == SIG_ERR)) - return -1; - return 0; -} - - -/** - * Fork the process to the background - * - * @param keep_stderr Keep stderr open? - * @return An `enum init_status` value or an exit value - */ -static enum init_status daemonise(int keep_stderr) -{ - pid_t pid; - int fd = -1, saved_errno; - int notify_rw[2] = { -1, -1 }; - char a_byte = 0; - ssize_t got; - - if (pipe(notify_rw) < 0) - goto fail; - if (notify_rw[0] <= STDERR_FILENO) - if ((notify_rw[0] = dup2atleast(notify_rw[0], STDERR_FILENO + 1)) < 0) - goto fail; - if (notify_rw[1] <= STDERR_FILENO) - if ((notify_rw[1] = dup2atleast(notify_rw[1], STDERR_FILENO + 1)) < 0) - goto fail; - - if ((pid = fork()) < 0) - goto fail; - if (pid > 0) - { - /* Original process (parent): */ - waitpid(pid, NULL, 0); - close(notify_rw[1]), notify_rw[1] = -1; - got = read(notify_rw[0], &a_byte, 1); - if (got < 0) - goto fail; - close(notify_rw[0]); - errno = 0; - return got == 0 ? INIT_FAILURE : (enum init_status)0; - } - - /* Intermediary process (child): */ - close(notify_rw[0]), notify_rw[0] = -1; - if (setsid() < 0) - goto fail; - if ((pid = fork()) < 0) - goto fail; - if (pid > 0) - { - /* Intermediary process (parent): */ - return (enum init_status)0; - } - - /* Daemon process (child): */ - - /* Replace std* with /dev/null */ - fd = open("/dev/null", O_RDWR); - if (fd < 0) - goto fail; -#define xdup2(s, d) do if (s != d) { close(d); if (dup2(s, d) < 0) goto fail; } while (0) - xdup2(fd, STDIN_FILENO); - xdup2(fd, STDOUT_FILENO); - if (keep_stderr) - xdup2(fd, STDERR_FILENO); - if (fd > STDERR_FILENO) - close(fd); - fd = -1; - - /* Update PID file */ - fd = open(pidpath, O_WRONLY); - if (fd < 0) - goto fail; - if (dprintf(fd, "%llu\n", (unsigned long long)getpid()) < 0) - goto fail; - close(fd), fd = -1; - - /* Notify */ - if (write(notify_rw[1], &a_byte, 1) <= 0) - goto fail; - close(notify_rw[1]); - - return INIT_SUCCESS; - fail: - saved_errno = errno; - if (fd >= 0) close(fd); - if (notify_rw[0] >= 0) close(notify_rw[0]); - if (notify_rw[1] >= 0) close(notify_rw[1]); - errno = saved_errno; - return INIT_FAILURE; -} - - -/** - * Initialise the process - * - * @param foreground Keep process in the foreground - * @param keep_stderr Keep stderr open - * @param query Was -q used, see `main` for description - * @return An `enum init_status` value or an exit value - */ -static enum init_status initialise(int foreground, int keep_stderr, int query) -{ - struct rlimit rlimit; - size_t i, n; - sigset_t mask; - int s; - enum init_status r; - - /* Zero out some memory so it can be destoried safely. */ - memset(&site, 0, sizeof(site)); - - if (!query) - { - /* Close all file descriptors above stderr */ - if (getrlimit(RLIMIT_NOFILE, &rlimit) || (rlimit.rlim_cur == RLIM_INFINITY)) - n = 4 << 10; - else - n = (size_t)(rlimit.rlim_cur); - for (i = STDERR_FILENO + 1; i < n; i++) - close((int)i); - - /* Set umask, reset signal handlers, and reset signal mask */ - umask(0); - for (s = 1; s < _NSIG; s++) - signal(s, SIG_DFL); - if (sigfillset(&mask)) - perror(argv0); - else - sigprocmask(SIG_UNBLOCK, &mask, NULL); - } - - /* Get method */ - if ((method < 0) && (libgamma_list_methods(&method, 1, 0) < 1)) - return fprintf(stderr, "%s: no adjustment method available\n", argv0), -1; - - /* Go no further if we are just interested in the adjustment method and site */ - if (query) - return INIT_SUCCESS; - - /* Get site */ - if (initialise_site() < 0) - goto fail; - - /* Get PID file and socket pathname */ - if (!(pidpath = get_pidfile_pathname()) || - !(socketpath = get_socket_pathname())) - goto fail; - - /* Create PID file */ - if ((r = create_pidfile(pidpath)) < 0) - { - free(pidpath), pidpath = NULL; - if (r == -2) - return INIT_RUNNING; - goto fail; - } - - /* Get partitions and CRTC:s */ - if (initialise_crtcs() < 0) - goto fail; - - /* Get CRTC information */ - if (outputs_n && !(outputs = calloc(outputs_n, sizeof(*outputs)))) - goto fail; - if (initialise_gamma_info() < 0) - goto fail; - - /* Sort outputs */ - qsort(outputs, outputs_n, sizeof(*outputs), output_cmp_by_name); - - /* Load current gamma ramps */ - store_gamma(); - - /* Preserve current gamma ramps at priority=0 if -p */ - if (preserve && (preserve_gamma() < 0)) - goto fail; - - /* Create socket and start listening */ - if (create_socket(socketpath) < 0) - goto fail; - - /* Get the real pathname of the process's binary, in case - * it is relative, so we can re-execute without problem. */ - if ((*argv0 != '/') && strchr(argv0, '/') && !(argv0_real = realpath(argv0, NULL))) - goto fail; - - /* Change directory to / to avoid blocking umounting */ - if (chdir("/") < 0) - perror(argv0); - - /* Set up signal handlers */ - if (set_up_signals() < 0) - goto fail; - - /* Place in the background unless -f */ - if (foreground == 0) - return daemonise(keep_stderr); - else - { - /* Signal the spawner that the service is ready */ - close(STDOUT_FILENO); - /* Avoid potential catastrophes that would occur if a library - * that is being used was so mindless as to write to stdout. */ - if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0) - perror(argv0); - } - - return INIT_SUCCESS; - fail: - return INIT_FAILURE; -} - - -/** - * Deinitialise the process - * - * @param full Perform a full deinitialisation, shall be - * done iff the process is going to re-execute - */ -static void destroy(int full) -{ - if (full) - { - disconnect_all(); - close_socket(socketpath); - free(argv0_real); - if ((outputs != NULL) && connected) - restore_gamma(); - } - state_destroy(); - free(socketpath); - if (full && (pidpath != NULL)) - unlink(pidpath); - free(pidpath); -} - - - -#if defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-align" -#endif - - -/** - * Marshal the state of the process - * - * @param buf Output buffer for the marshalled data, - * `NULL` to only measure how large the - * buffer needs to be - * @return The number of marshalled bytes - */ -static size_t marshal(void* restrict buf) -{ - size_t off = 0, n; - char* restrict bs = buf; - - if (bs != NULL) - *(int*)(bs + off) = MARSHAL_VERSION; - off += sizeof(int); - - n = strlen(pidpath) + 1; - if (bs != NULL) - memcpy(bs + off, pidpath, n); - off += n; - - n = strlen(socketpath) + 1; - if (bs != NULL) - memcpy(bs + off, socketpath, n); - off += n; - - off += state_marshal(bs ? bs + off : NULL); - - return off; -} - - -/** - * Unmarshal the state of the process - * - * @param buf Buffer with the marshalled data - * @return The number of marshalled bytes, 0 on error - */ -GCC_ONLY(__attribute__((nonnull))) -static size_t unmarshal(const void* restrict buf) -{ - size_t off = 0, n; - const char* restrict bs = buf; - - if (*(const int*)(bs + off) != MARSHAL_VERSION) - { - fprintf(stderr, "%s: re-executing to incompatible version, sorry about that\n", argv0); - errno = 0; - return 0; - } - off += sizeof(int); - - n = strlen(bs + off) + 1; - if (!(pidpath = memdup(bs + off, n))) - return 0; - off += n; - - n = strlen(bs + off) + 1; - if (!(socketpath = memdup(bs + off, n))) - return 0; - off += n; - - off += n = state_unmarshal(bs + off); - if (n == 0) - return 0; - - return off; -} - - -#if defined(__clang__) -# pragma GCC diagnostic pop -#endif - - - -/** - * Do minimal initialisation, unmarshal the state of - * the process and merge with new state - * - * @param statefile The state file - * @return Zero on success, -1 on error - */ -GCC_ONLY(__attribute__((nonnull))) -static int restore_state(const char* restrict statefile) -{ - void* marshalled = NULL; - int fd = -1, saved_errno; - size_t r, n; - - if (set_up_signals() < 0) - goto fail; - - fd = open(statefile, O_RDONLY); - if (fd < 0) - goto fail; - - if (!(marshalled = nread(fd, &n))) - goto fail; - close(fd), fd = -1; - unlink(statefile), statefile = NULL; - - r = unmarshal(marshalled); - if (r == 0) - goto fail; - if (r != n) - { - fprintf(stderr, "%s: unmarshalled state file was %s than the unmarshalled state: read %zu of %zu bytes\n", - argv0, n > r ? "larger" : "smaller", r, n); - errno = 0; - goto fail; - } - free(marshalled), marshalled = NULL; - - if (connected) - { - connected = 0; - if (reconnect() < 0) - goto fail; - } - - return 0; - fail: - saved_errno = errno; - if (fd >= 0) - close(fd); - free(marshalled); - errno = saved_errno; - return -1; -} - - -/** - * Reexecute the server - * - * Returns only on failure - * - * @return Pathname of file where the state is stored, - * `NULL` if the state is in tact - */ -static char* reexecute(void) -{ - char* statefile = NULL; - char* statebuffer = NULL; - size_t buffer_size; - int fd = -1, saved_errno; - - statefile = get_state_pathname(); - if (statefile == NULL) - goto fail; - - buffer_size = marshal(NULL); - statebuffer = malloc(buffer_size); - if (statebuffer == NULL) - goto fail; - if (marshal(statebuffer) != buffer_size) - { - fprintf(stderr, "%s: internal error\n", argv0); - errno = 0; - goto fail; - } - - fd = open(statefile, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR); - if (fd < 0) - goto fail; - - if (nwrite(fd, statebuffer, buffer_size) != buffer_size) - goto fail; - free(statebuffer), statebuffer = NULL; - - if ((close(fd) < 0) && (fd = -1, errno != EINTR)) - goto fail; - fd = -1; - - destroy(0); - -#if !defined(USE_VALGRIND) - execlp(argv0_real ? argv0_real : argv0, argv0, "- ", statefile, NULL); -#else - execlp("valgrind", "valgrind", "--leak-check=full", argv0_real ? argv0_real : argv0, "- ", statefile, NULL); -#endif - saved_errno = errno; - free(argv0_real), argv0_real = NULL; - errno = saved_errno; - return statefile; - - fail: - saved_errno = errno; - free(statebuffer); - if (fd >= 0) - close(fd); - if (statefile != NULL) - unlink(statefile), free(statefile); - errno = saved_errno; - return NULL; -} - - - -/** - * Print the response for the -q option - * - * @param query See -q for `main`, must be atleast 1 - * @return Zero on success, -1 on error - */ -static int print_method_and_site(int query) -{ - const char* restrict methodname = NULL; - char* p; - - if (query == 1) - { - switch (method) - { -#define X(C, N) case C: methodname = N; break; - LIST_ADJUSTMENT_METHODS; -#undef X - default: - if (printf("%i\n", method) < 0) - return -1; - break; - } - if (methodname != NULL) - if (printf("%s\n", methodname) < 0) - return -1; - } - - if (sitename == NULL) - if ((sitename = libgamma_method_default_site(method))) - if (!(sitename = memdup(sitename, strlen(sitename) + 1))) - return -1; - - if (sitename != NULL) - switch (method) - { - case LIBGAMMA_METHOD_X_RANDR: - case LIBGAMMA_METHOD_X_VIDMODE: - if ((p = strrchr(sitename, ':'))) - if ((p = strchr(p, '.'))) - *p = '\0'; - break; - default: - break; - } - - if ((sitename != NULL) && (query == 1)) - if (printf("%s\n", sitename) < 0) - return -1; - - if (query == 2) - { - site.method = method; - site.site = sitename, sitename = NULL; - socketpath = get_socket_pathname(); - if (socketpath == NULL) - return -1; - if (printf("%s\n", socketpath) < 0) - return -1; - } - - if (fflush(stdout)) - return -1; - return 0; -} - - - -/** - * Print usage information and exit - */ -#if defined(__GNU__) || defined(__clang__) -__attribute__((noreturn)) -#endif -static void usage(void) -{ - printf("Usage: %s [-m method] [-s site] [-fkpq]\n", argv0); - exit(1); -} - - -#if defined(__clang__) -# pragma GCC diagnostic ignored "-Wdocumentation-unknown-command" -#endif - - -/** - * Must not be started without stdin, stdout, or stderr (may be /dev/null) - * - * argv[0] must refer to the real command name or pathname, - * otherwise, re-execute will not work - * - * The process closes stdout when the socket has been created - * - * @signal SIGUSR1 Re-execute to updated process image - * @signal SIGUSR2 Dump the state of the process to standard error - * @signal SIGINFO Ditto - * @signal SIGTERM Terminate the process gracefully - * @signal SIGRTMIN+0 Disconnect from the site - * @signal SiGRTMIN+1 Reconnect to the site - * - * @param argc The number of elements in `argv` - * @param argv Command line arguments. Recognised options: - * -s SITENAME - * The site to which to connect - * -m METHOD - * Adjustment method name or adjustment method number - * -p - * Preserve current gamma ramps at priority 0 - * -f - * Do not fork the process into the background - * -k - * Keep stderr open - * -q - * Print the select (possiblity default) adjustment - * method on the first line in stdout, and the - * selected (possibility defasult) site on the second - * line in stdout, and exit. If the site name is `NULL`, - * the second line is omitted. This is indented to - * be used by clients to figure out to which instance - * of the service it should connect. Use twice to - * simply ge the socket pathname, an a terminating LF. - * By combining -q and -m you can enumerate the name - * of all recognised adjustment method, start from 0 - * and work up until a numerical adjustment method is - * returned. - * @return 0: Successful - * 1: An error occurred - * 2: Already running - */ -int main(int argc, char** argv) -{ - int rc = 1, foreground = 0, keep_stderr = 0, query = 0, r; - char* statefile = NULL; - char* statefile_ = NULL; - - ARGBEGIN - { - case 's': - sitename = EARGF(usage()); - /* To simplify re-exec: */ - sitename = memdup(sitename, strlen(sitename) + 1); - if (sitename == NULL) - goto fail; - break; - case 'm': - method = get_method(EARGF(usage())); - if (method < 0) - goto fail; - break; - case 'p': preserve = 1; break; - case 'f': foreground = 1; break; - case 'k': keep_stderr = 1; break; - case 'q': query = 1 + !!query; break; - case ' ': /* Internal, do not document */ - statefile = statefile_ = EARGF(usage()); - break; - default: - usage(); - } - ARGEND; - if (argc > 0) - usage(); - - restart: - - if (statefile == NULL) - switch ((r = initialise(foreground, keep_stderr, query))) - { - case INIT_SUCCESS: break; - case INIT_RUNNING: rc = 2; /* fall through */ - case INIT_FAILURE: goto fail; - default: return r; - } - else if (restore_state(statefile) < 0) - goto fail; - else - { - if (statefile != statefile_) - free(statefile); - unlink(statefile), statefile = NULL; - } - - if (query) - { - if (print_method_and_site(query) < 0) - goto fail; - goto done; - } - - reenter_loop: - if (main_loop() < 0) - goto fail; - - if (reexec && !terminate) - { - if ((statefile = reexecute())) - { - perror(argv0); - fprintf(stderr, "%s: restoring state without re-executing\n", argv0); - reexec = 0; - goto restart; - } - perror(argv0); - fprintf(stderr, "%s: continuing without re-executing\n", argv0); - reexec = 0; - goto reenter_loop; - } - - done: - rc = 0; - deinit: - if (statefile) - unlink(statefile); - if (reexec) - free(statefile); - destroy(1); - return rc; - fail: - if (errno != 0) - perror(argv0); - goto deinit; -} - diff --git a/src/servers/coopgamma.c b/src/servers/coopgamma.c deleted file mode 100644 index 6e544be..0000000 --- a/src/servers/coopgamma.c +++ /dev/null @@ -1,558 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "coopgamma.h" -#include "gamma.h" -#include "../state.h" -#include "../communication.h" -#include "../util.h" -#include "../types/output.h" - -#include <libclut.h> - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - - - -/** - * 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` - */ -static 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\n", - 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 - */ -static 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; - filter->class = NULL; - filter->ramps = NULL; - 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++; - - out->table_filters[i] = *filter; - filter->class = NULL; - filter->ramps = NULL; - - 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; - - return (ssize_t)i; -} - - -/** - * 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++) - { - if (j != k) - { - output->table_filters[j] = output->table_filters[k]; - output->table_sums[j] = output->table_sums[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; - } - } - 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, n, - "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) && (start < end)) - memcpy(buf + n, output->table_sums[end - 1].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; - if (flush_filters(output, (size_t)r)) - goto fail; - - free(filter.class); - free(filter.ramps); - 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; -} - - - -/** - * Preserve current gamma ramps at priority 0 for all outputs - * - * @return Zero on success, -1 on error - */ -int preserve_gamma(void) -{ - size_t i; - - for (i = 0; i < outputs_n; i++) - { - struct filter filter = { - .client = -1, - .priority = 0, - .class = NULL, - .lifespan = LIFESPAN_UNTIL_REMOVAL, - .ramps = NULL - }; - outputs[i].table_filters = calloc(4, sizeof(*(outputs[i].table_filters))); - outputs[i].table_sums = calloc(4, sizeof(*(outputs[i].table_sums))); - outputs[i].table_alloc = 4; - outputs[i].table_size = 1; - filter.class = memdup(PKGNAME "::" COMMAND "::preserved", sizeof(PKGNAME "::" COMMAND "::preserved")); - if (filter.class == NULL) - return -1; - filter.ramps = memdup(outputs[i].saved_ramps.u8.red, outputs[i].ramps_size); - if (filter.ramps == NULL) - return -1; - outputs[i].table_filters[0] = filter; - COPY_RAMP_SIZES(&(outputs[i].table_sums[0].u8), outputs + i); - if (!gamma_ramps_unmarshal(outputs[i].table_sums, outputs[i].saved_ramps.u8.red, outputs[i].ramps_size)) - return -1; - } - - return 0; -} - diff --git a/src/servers/crtc.c b/src/servers/crtc.c deleted file mode 100644 index ca10940..0000000 --- a/src/servers/crtc.c +++ /dev/null @@ -1,325 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "crtc.h" -#include "gamma.h" -#include "coopgamma.h" -#include "../state.h" -#include "../communication.h" -#include "../util.h" - -#include <errno.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, n, - "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); -} - - -/** - * Get the name of a CRTC - * - * @param info Information about the CRTC - * @param crtc libgamma's state for the CRTC - * @return The name of the CRTC, `NULL` on error - */ -char* get_crtc_name(const libgamma_crtc_information_t* restrict info, - const libgamma_crtc_state_t* restrict crtc) -{ - if ((info->edid_error == 0) && (info->edid != NULL)) - return libgamma_behex_edid(info->edid, info->edid_length); - else if ((info->connector_name_error == 0) && (info->connector_name != NULL)) - { - char* name = malloc(3 * sizeof(size_t) + strlen(info->connector_name) + 2); - if (name != NULL) - sprintf(name, "%zu.%s", crtc->partition->partition, info->connector_name); - return name; - } - else - { - char* name = malloc(2 * 3 * sizeof(size_t) + 2); - if (name != NULL) - sprintf(name, "%zu.%zu", crtc->partition->partition, crtc->crtc); - return name; - } -} - - -/** - * Initialise the site - * - * @return Zero on success, -1 on error - */ -int initialise_site(void) -{ - char* restrict sitename_dup = NULL; - int gerror, saved_errno; - - if ((sitename != NULL) && !(sitename_dup = memdup(sitename, strlen(sitename) + 1))) - goto fail; - if ((gerror = libgamma_site_initialise(&site, method, sitename_dup))) - goto fail_libgamma; - - return 0; - fail_libgamma: - sitename_dup = NULL; - libgamma_perror(argv0, gerror); - errno = 0; - fail: - saved_errno = errno; - free(sitename_dup); - errno = saved_errno; - return -1; -} - - -/** - * Get partitions and CRTC:s - * - * @return Zero on success, -1 on error - */ -int initialise_crtcs(void) -{ - size_t i, j, n, n0; - int gerror; - - /* Get partitions */ - outputs_n = 0; - if (site.partitions_available) - if (!(partitions = calloc(site.partitions_available, sizeof(*partitions)))) - goto fail; - for (i = 0; i < site.partitions_available; i++) - { - if ((gerror = libgamma_partition_initialise(partitions + i, &site, i))) - goto fail_libgamma; - outputs_n += partitions[i].crtcs_available; - } - - /* Get CRTC:s */ - if (outputs_n) - if (!(crtcs = calloc(outputs_n, sizeof(*crtcs)))) - goto fail; - for (i = 0, j = n = 0; i < site.partitions_available; i++) - for (n0 = n, n += partitions[i].crtcs_available; j < n; j++) - if ((gerror = libgamma_crtc_initialise(crtcs + j, partitions + i, j - n0))) - goto fail_libgamma; - - return 0; - - fail_libgamma: - libgamma_perror(argv0, gerror); - errno = 0; - fail: - return -1; -} - - -/** - * Merge the new state with an old state - * - * @param old_outputs The old `outputs` - * @param old_outputs_n The old `outputs_n` - * @return Zero on success, -1 on error - */ -int merge_state(struct output* restrict old_outputs, size_t old_outputs_n) -{ - struct output* restrict new_outputs = NULL; - size_t new_outputs_n; - size_t i, j; - - /* How many outputs does the system now have? */ - i = j = new_outputs_n = 0; - while ((i < old_outputs_n) && (j < outputs_n)) - { - int cmp = strcmp(old_outputs[i].name, outputs[j].name); - if (cmp <= 0) - new_outputs_n++; - i += cmp >= 0; - j += cmp <= 0; - } - new_outputs_n += outputs_n - j; - - /* Allocate output state array */ - if (new_outputs_n > 0) - { - new_outputs = calloc(new_outputs_n, sizeof(*new_outputs)); - if (new_outputs == NULL) - return -1; - } - - /* Merge output states */ - i = j = new_outputs_n = 0; - while ((i < old_outputs_n) && (j < outputs_n)) - { - int is_same = 0, cmp = strcmp(old_outputs[i].name, outputs[j].name); - if (cmp == 0) - is_same = (old_outputs[i].depth == outputs[j].depth && - old_outputs[i].red_size == outputs[j].red_size && - old_outputs[i].green_size == outputs[j].green_size && - old_outputs[i].blue_size == outputs[j].blue_size); - if (is_same) - { - new_outputs[new_outputs_n] = old_outputs[i]; - new_outputs[new_outputs_n].crtc = outputs[j].crtc; - memset(old_outputs + i, 0, sizeof(*old_outputs)); - outputs[j].crtc = NULL; - output_destroy(outputs + j); - new_outputs_n++; - } - else if (cmp <= 0) - new_outputs[new_outputs_n++] = outputs[j]; - i += cmp >= 0; - j += cmp <= 0; - } - while (j < outputs_n) - new_outputs[new_outputs_n++] = outputs[j++]; - - /* Commit merge */ - free(outputs); - outputs = new_outputs; - outputs_n = new_outputs_n; - - return 0; -} - - - -/** - * Disconnect from the site - * - * @return Zero on success, -1 on error - */ -int disconnect(void) -{ - size_t i; - - if (!connected) - return 0; - connected = 0; - - for (i = 0; i < outputs_n; i++) - { - outputs[i].crtc = NULL; - libgamma_crtc_destroy(crtcs + i); - } - free(crtcs), crtcs = NULL; - for (i = 0; i < site.partitions_available; i++) - libgamma_partition_destroy(partitions + i); - free(partitions), partitions = NULL; - libgamma_site_destroy(&site); - memset(&site, 0, sizeof(site)); - - return 0; -} - - -/** - * Reconnect to the site - * - * @return Zero on success, -1 on error - */ -int reconnect(void) -{ - struct output* restrict old_outputs; - size_t i, old_outputs_n; - int saved_errno; - - if (connected) - return 0; - connected = 1; - - /* Remember old state */ - old_outputs = outputs, outputs = NULL; - old_outputs_n = outputs_n, outputs_n = 0; - - /* Get site */ - if (initialise_site() < 0) - goto fail; - - /* Get partitions and CRTC:s */ - if (initialise_crtcs() < 0) - goto fail; - - /* Get CRTC information */ - if (outputs_n && !(outputs = calloc(outputs_n, sizeof(*outputs)))) - goto fail; - if (initialise_gamma_info() < 0) - goto fail; - - /* Sort outputs */ - qsort(outputs, outputs_n, sizeof(*outputs), output_cmp_by_name); - - /* Load current gamma ramps */ - store_gamma(); - - /* Preserve current gamma ramps at priority=0 if -p */ - if (preserve && (preserve_gamma() < 0)) - goto fail; - - /* Merge state */ - if (merge_state(old_outputs, old_outputs_n) < 0) - goto fail; - for (i = 0; i < old_outputs_n; i++) - output_destroy(old_outputs + i); - free(old_outputs), old_outputs = NULL, old_outputs_n = 0; - - /* Reapply gamma ramps */ - reapply_gamma(); - - return 0; - - fail: - saved_errno = errno; - for (i = 0; i < old_outputs_n; i++) - output_destroy(old_outputs + i); - free(old_outputs); - errno = saved_errno; - return -1; -} - diff --git a/src/servers/gamma.c b/src/servers/gamma.c deleted file mode 100644 index 17105d4..0000000 --- a/src/servers/gamma.c +++ /dev/null @@ -1,398 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "gamma.h" -#include "crtc.h" -#include "../state.h" -#include "../communication.h" -#include "../util.h" - -#include <errno.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; - const char* colourspace; - char gamut[8 * sizeof("White x: 1023")]; - 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; - } - - switch (output->colourspace) - { - case COLOURSPACE_SRGB_SANS_GAMUT: - case COLOURSPACE_SRGB: colourspace = "Colour space: sRGB\n"; break; - case COLOURSPACE_RGB_SANS_GAMUT: - case COLOURSPACE_RGB: colourspace = "Colour space: RGB\n"; break; - case COLOURSPACE_NON_RGB: colourspace = "Colour space: non-RGB\n"; break; - case COLOURSPACE_GREY: colourspace = "Colour space: grey\n"; break; - default: colourspace = ""; break; - } - - switch (output->colourspace) - { - case COLOURSPACE_SRGB: - case COLOURSPACE_RGB: - sprintf(gamut, - "Red x: %u\n" - "Red y: %u\n" - "Green x: %u\n" - "Green y: %u\n" - "Blue x: %u\n" - "Blue y: %u\n" - "White x: %u\n" - "White y: %u\n", - output->red_x, output->red_y, output->green_x, output->green_y, - output->blue_x, output->blue_y, output->white_x, output->white_y); - break; - default: - *gamut = '\0'; - 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" - "%s%s" - "\n", - message_id, depth, output->red_size, output->green_size, - output->blue_size, supported, gamut, colourspace); - - 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) - return; - - 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 */ -} - - -/** - * Parse the EDID of a monitor - * - * @param output The output - * @param edid The EDID in binary format - * @param n The length of the EDID - */ -static void parse_edid(struct output* restrict output, const unsigned char* restrict edid, size_t n) -{ - size_t i; - int analogue; - unsigned sum; - - output->red_x = output->green_x = output->blue_x = output->white_x = 0; - output->red_y = output->green_y = output->blue_y = output->white_y = 0; - output->colourspace = COLOURSPACE_UNKNOWN; - - if ((edid == NULL) || (n < 128)) - return; - for (i = 0, sum = 0; i < 128; i++) - sum += (unsigned)edid[i]; - if ((sum & 0xFF) != 0) - return; - if ((edid[0] != 0) || (edid[7] != 0)) - return; - for (i = 1; i < 7; i++) - if (edid[i] != 0xFF) - return; - - analogue = !(edid[20] & 0x80); - if (!analogue) - output->colourspace = COLOURSPACE_RGB; - else - switch ((edid[24] >> 3) & 3) - { - case 0: output->colourspace = COLOURSPACE_GREY; break; - case 1: output->colourspace = COLOURSPACE_RGB; break; - case 2: output->colourspace = COLOURSPACE_NON_RGB; break; - default: output->colourspace = COLOURSPACE_UNKNOWN; break; - } - - if (output->colourspace != COLOURSPACE_RGB) - return; - - if (edid[24] & 4) - output->colourspace = COLOURSPACE_SRGB; - - output->red_x = (edid[25] >> 6) & 3; - output->red_y = (edid[25] >> 4) & 3; - output->green_x = (edid[25] >> 2) & 3; - output->green_y = (edid[25] >> 0) & 3; - output->blue_x = (edid[26] >> 6) & 3; - output->blue_y = (edid[26] >> 4) & 3; - output->white_x = (edid[26] >> 2) & 3; - output->white_y = (edid[26] >> 0) & 3; - - output->red_x |= ((unsigned)(edid[27])) << 2; - output->red_y |= ((unsigned)(edid[28])) << 2; - output->green_x |= ((unsigned)(edid[29])) << 2; - output->green_y |= ((unsigned)(edid[30])) << 2; - output->blue_x |= ((unsigned)(edid[31])) << 2; - output->blue_y |= ((unsigned)(edid[32])) << 2; - output->white_x |= ((unsigned)(edid[33])) << 2; - output->white_y |= ((unsigned)(edid[34])) << 2; - - if ((output->red_x == output->red_y) && - (output->red_x == output->green_x) && - (output->red_x == output->green_y) && - (output->red_x == output->blue_x) && - (output->red_x == output->blue_y) && - (output->red_x == output->white_x) && - (output->red_x == output->white_y)) - { - if (output->colourspace == COLOURSPACE_SRGB) - output->colourspace = COLOURSPACE_SRGB_SANS_GAMUT; - else - output->colourspace = COLOURSPACE_RGB_SANS_GAMUT; - } -} - - -/** - * Store all current gamma ramps - * - * @return Zero on success, -1 on error - */ -int initialise_gamma_info(void) -{ - libgamma_crtc_information_t info; - int saved_errno; - size_t i; - - for (i = 0; i < outputs_n; i++) - { - libgamma_get_crtc_information(&info, crtcs + i, - LIBGAMMA_CRTC_INFO_EDID | - LIBGAMMA_CRTC_INFO_MACRO_RAMP | - LIBGAMMA_CRTC_INFO_GAMMA_SUPPORT | - LIBGAMMA_CRTC_INFO_CONNECTOR_NAME); - outputs[i].depth = info.gamma_depth_error ? 0 : info.gamma_depth; - outputs[i].red_size = info.gamma_size_error ? 0 : info.red_gamma_size; - outputs[i].green_size = info.gamma_size_error ? 0 : info.green_gamma_size; - outputs[i].blue_size = info.gamma_size_error ? 0 : info.blue_gamma_size; - outputs[i].supported = info.gamma_support_error ? 0 : info.gamma_support; - if (info.gamma_support_error == LIBGAMMA_CRTC_INFO_NOT_SUPPORTED) - outputs[i].supported = LIBGAMMA_MAYBE; - if (outputs[i].depth == 0 || outputs[i].red_size == 0 || - outputs[i].green_size == 0 || outputs[i].blue_size == 0) - outputs[i].supported = 0; - parse_edid(outputs + i, info.edid_error ? NULL : info.edid, info.edid_error ? 0 : info.edid_length); - outputs[i].name = get_crtc_name(&info, crtcs + i); - saved_errno = errno; - outputs[i].name_is_edid = ((info.edid_error == 0) && (info.edid != NULL)); - outputs[i].crtc = crtcs + i; - libgamma_crtc_information_destroy(&info); - outputs[i].ramps_size = outputs[i].red_size + outputs[i].green_size + outputs[i].blue_size; - switch (outputs[i].depth) - { - default: - outputs[i].depth = 64; - /* Fall through */ - case 8: - case 16: - case 32: - case 64: outputs[i].ramps_size *= (size_t)(outputs[i].depth / 8); break; - case -2: outputs[i].ramps_size *= sizeof(double); break; - case -1: outputs[i].ramps_size *= sizeof(float); break; - } - errno = saved_errno; - if (outputs[i].name == NULL) - return -1; - } - - return 0; -} - - -/** - * Store all current gamma ramps - */ -void store_gamma(void) -{ - int gerror; - size_t i; - -#define LOAD_RAMPS(SUFFIX, MEMBER) \ - do \ - { \ - libgamma_gamma_ramps##SUFFIX##_initialise(&(outputs[i].saved_ramps.MEMBER)); \ - gerror = libgamma_crtc_get_gamma_ramps##SUFFIX(outputs[i].crtc, &(outputs[i].saved_ramps.MEMBER)); \ - if (gerror) \ - { \ - libgamma_perror(argv0, gerror); \ - outputs[i].supported = LIBGAMMA_NO; \ - libgamma_gamma_ramps##SUFFIX##_destroy(&(outputs[i].saved_ramps.MEMBER)); \ - memset(&(outputs[i].saved_ramps.MEMBER), 0, sizeof(outputs[i].saved_ramps.MEMBER)); \ - } \ - } \ - while (0) - - for (i = 0; i < outputs_n; i++) - { - if (outputs[i].supported == LIBGAMMA_NO) - continue; - - outputs[i].saved_ramps.u8.red_size = outputs[i].red_size; - outputs[i].saved_ramps.u8.green_size = outputs[i].green_size; - outputs[i].saved_ramps.u8.blue_size = outputs[i].blue_size; - - switch (outputs[i].depth) - { - case 64: LOAD_RAMPS(64, u64); break; - case 32: LOAD_RAMPS(32, u32); break; - case 16: LOAD_RAMPS(16, u16); break; - case 8: LOAD_RAMPS( 8, u8); break; - case -2: LOAD_RAMPS(d, d); break; - case -1: LOAD_RAMPS(f, f); break; - default: /* impossible */ break; - } - } -} - - -/** - * Restore all gamma ramps - */ -void restore_gamma(void) -{ - size_t i; - int gerror; - -#define RESTORE_RAMPS(SUFFIX, MEMBER) \ - do \ - if (outputs[i].saved_ramps.MEMBER.red != NULL) \ - { \ - gerror = libgamma_crtc_set_gamma_ramps##SUFFIX(outputs[i].crtc, outputs[i].saved_ramps.MEMBER); \ - if (gerror) \ - libgamma_perror(argv0, gerror); \ - } \ - while (0) - - for (i = 0; i < outputs_n; i++) - { - if (outputs[i].supported == LIBGAMMA_NO) - continue; - if (outputs[i].saved_ramps.u8.red == NULL) - continue; - - switch (outputs[i].depth) - { - case 64: RESTORE_RAMPS(64, u64); break; - case 32: RESTORE_RAMPS(32, u32); break; - case 16: RESTORE_RAMPS(16, u16); break; - case 8: RESTORE_RAMPS( 8, u8); break; - case -2: RESTORE_RAMPS(d, d); break; - case -1: RESTORE_RAMPS(f, f); break; - default: /* impossible */ break; - } - } -} - - -/** - * Reapplu all gamma ramps - */ -void reapply_gamma(void) -{ - union gamma_ramps plain; - size_t i; - - /* Reapply gamma ramps */ - for (i = 0; i < outputs_n; i++) - { - struct output* output = outputs + i; - if (output->table_size > 0) - set_gamma(output, output->table_sums + output->table_size - 1); - else - { - make_plain_ramps(&plain, output); - set_gamma(output, &plain); - libgamma_gamma_ramps8_destroy(&(plain.u8)); - } - } -} - diff --git a/src/servers/gamma.h b/src/servers/gamma.h deleted file mode 100644 index ac269e0..0000000 --- a/src/servers/gamma.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef SERVERS_GAMMA_H -#define SERVERS_GAMMA_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); - - -/** - * Store all current gamma ramps - * - * @return Zero on success, -1 on error - */ -int initialise_gamma_info(void); - -/** - * Store all current gamma ramps - */ -void store_gamma(void); - -/** - * Restore all gamma ramps - */ -void restore_gamma(void); - - -/** - * Reapplu all gamma ramps - */ -void reapply_gamma(void); - - -#endif - diff --git a/src/servers/kernel.c b/src/servers/kernel.c deleted file mode 100644 index 1600d0a..0000000 --- a/src/servers/kernel.c +++ /dev/null @@ -1,384 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "kernel.h" -#include "../state.h" -#include "../util.h" - -#include <libgamma.h> - -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/un.h> -#include <errno.h> -#include <fcntl.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - - - -/** - * Get the pathname of the runtime file - * - * @param suffix The suffix for the file - * @return The pathname of the file, `NULL` on error - */ -GCC_ONLY(__attribute__((malloc, nonnull))) -static char* get_pathname(const char* restrict suffix) -{ - const char* restrict rundir = getenv("XDG_RUNTIME_DIR"); - const char* restrict username = ""; - char* name = NULL; - char* p; - char* restrict rc; - struct passwd* restrict pw; - size_t n; - int saved_errno; - - if (sitename) - { - name = memdup(sitename, strlen(sitename) + 1); - if (name == NULL) - goto fail; - } - else if ((name = libgamma_method_default_site(method))) - { - name = memdup(name, strlen(name) + 1); - if (name == NULL) - goto fail; - } - - if (name != NULL) - switch (method) - { - case LIBGAMMA_METHOD_X_RANDR: - case LIBGAMMA_METHOD_X_VIDMODE: - if ((p = strrchr(name, ':'))) - if ((p = strchr(p, '.'))) - *p = '\0'; - break; - default: - break; - } - - if (!rundir || !*rundir) - rundir = "/tmp"; - - if ((pw = getpwuid(getuid()))) - username = pw->pw_name ? pw->pw_name : ""; - - n = sizeof("/.coopgammad/~/.") + 3 * sizeof(int); - n += strlen(rundir) + strlen(username) + ((name != NULL) ? strlen(name) : 0) + strlen(suffix); - if (!(rc = malloc(n))) - goto fail; - sprintf(rc, "%s/.coopgammad/~%s/%i%s%s%s", - rundir, username, method, name ? "." : "", name ? name : "", suffix); - free(name); - return rc; - - fail: - saved_errno = errno; - free(name); - errno = saved_errno; - return NULL; -} - - -/** - * Get the pathname of the socket - * - * @return The pathname of the socket, `NULL` on error - */ -char* get_socket_pathname(void) -{ - return get_pathname(".socket"); -} - - -/** - * Get the pathname of the PID file - * - * @return The pathname of the PID file, `NULL` on error - */ -char* get_pidfile_pathname(void) -{ - return get_pathname(".pid"); -} - - -/** - * Get the pathname of the state file - * - * @return The pathname of the state file, `NULL` on error - */ -char* get_state_pathname(void) -{ - return get_pathname(".state"); -} - - -/** - * Check whether a PID file is outdated - * - * @param pidpath The PID file - * @param token An environment variable (including both key and value) - * that must exist in the process if it is a coopgammad process - * @return -1: An error occurred - * 0: The service is already running - * 1: The PID file is outdated - */ -GCC_ONLY(__attribute__((nonnull))) -static int is_pidfile_reusable(const char* restrict pidpath, const char* restrict token) -{ - /* PORTERS: /proc/$PID/environ is Linux specific */ - - char temp[sizeof("/proc//environ") + 3 * sizeof(long long int)]; - int fd = -1, saved_errno, tries = 0; - char* content = NULL; - char* p; - pid_t pid = 0; - size_t n; -#if defined(HAVE_LINUX_PROCFS) - char* end; -#else - (void) token; -#endif - - /* Get PID */ - retry: - fd = open(pidpath, O_RDONLY); - if (fd < 0) - return -1; - content = nread(fd, &n); - if (content == NULL) - goto fail; - close(fd), fd = -1; - - if (n == 0) - { - if (++tries > 1) - goto bad; - msleep(100); /* 1 tenth of a second */ - goto retry; - } - - if (('0' > content[0]) || (content[0] > '9')) - goto bad; - if ((content[0] == '0') && ('0' <= content[1]) && (content[1] <= '9')) - goto bad; - for (p = content; *p; p++) - if (('0' <= *p) && (*p <= '9')) - pid = pid * 10 + (*p & 15); - else - break; - if (*p++ != '\n') - goto bad; - if (*p) - goto bad; - if ((size_t)(p - content) != n) - goto bad; - sprintf(temp, "%llu\n", (unsigned long long)pid); - if (strcmp(content, temp)) - goto bad; - free(content); - - /* Validate PID */ -#if defined(HAVE_LINUX_PROCFS) - sprintf(temp, "/proc/%llu/environ", (unsigned long long)pid); - fd = open(temp, O_RDONLY); - if (fd < 0) - return ((errno == ENOENT) || (errno == EACCES)) ? 1 : -1; - content = nread(fd, &n); - if (content == NULL) - goto fail; - close(fd), fd = -1; - - for (end = (p = content) + n; p != end; p = strchr(p, '\0') + 1) - if (!strcmp(p, token)) - return free(content), 0; - free(content); -#else - if ((kill(pid, 0) == 0) || (errno == EINVAL)) - return 0; -#endif - - return 1; - bad: - fprintf(stderr, "%s: pid file contains invalid content: %s\n", argv0, pidpath); - errno = 0; - return -1; - fail: - saved_errno = errno; - free(content); - if (fd >= 0) - close(fd); - errno = saved_errno; - return -1; -} - - -/** - * Create PID file - * - * @param pidpath The pathname of the PID file - * @return Zero on success, -1 on error, - * -2 if the service is already running - */ -int create_pidfile(char* pidpath) -{ - int fd = -1, r, saved_errno; - char* p; - char* restrict token = NULL; - - /* Create token used to validate the service. */ - token = malloc(sizeof("COOPGAMMAD_PIDFILE_TOKEN=") + strlen(pidpath)); - if (token == NULL) - return -1; - sprintf(token, "COOPGAMMAD_PIDFILE_TOKEN=%s", pidpath); -#if !defined(USE_VALGRIND) - if (putenv(token)) - goto putenv_fail; - /* `token` must not be free! */ -#else - { - static char static_token[sizeof("COOPGAMMAD_PIDFILE_TOKEN=") + PATH_MAX]; - if (strlen(pidpath) > PATH_MAX) - abort(); - strcpy(static_token, token); - if (putenv(static_token)) - goto fail; - } -#endif - - /* Create PID file's directory. */ - for (p = pidpath; *p == '/'; p++); - while ((p = strchr(p, '/'))) - { - *p = '\0'; - if (mkdir(pidpath, 0755) < 0) - if (errno != EEXIST) - { - *p = '/'; - goto fail; - } - *p++ = '/'; - } - - /* Create PID file. */ - retry: - fd = open(pidpath, O_CREAT | O_EXCL | O_WRONLY, 0644); - if (fd < 0) - { - if (errno == EINTR) - goto retry; - if (errno != EEXIST) - return -1; - r = is_pidfile_reusable(pidpath, token); - if (r > 0) - { - unlink(pidpath); - goto retry; - } - else if (r < 0) - goto fail; - fprintf(stderr, "%s: service is already running\n", argv0); - errno = 0; - return -2; - } - - /* Write PID to PID file. */ - if (dprintf(fd, "%llu\n", (unsigned long long)getpid()) < 0) - goto fail; - - /* Done */ -#if defined(USE_VALGRIND) - free(token); -#endif - if (close(fd) < 0) - if (errno != EINTR) - return -1; - return 0; -#if !defined(USE_VALGRIND) - putenv_fail: - saved_errno = errno; - free(token); - errno = saved_errno; -#endif - fail: - saved_errno = errno; -#if defined(USE_VALGRIND) - free(token); -#endif - if (fd >= 0) - { - close(fd); - unlink(pidpath); - } - errno = saved_errno; - return -1; -} - - -/** - * Create socket and start listening - * - * @param socketpath The pathname of the socket - * @return Zero on success, -1 on error - */ -int create_socket(const char* socketpath) -{ - struct sockaddr_un address; - - address.sun_family = AF_UNIX; - if (strlen(socketpath) >= sizeof(address.sun_path)) - { - errno = ENAMETOOLONG; - return -1; - } - strcpy(address.sun_path, socketpath); - unlink(socketpath); - if ((socketfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) - return -1; - if (fchmod(socketfd, S_IRWXU) < 0) - return -1; - if (bind(socketfd, (struct sockaddr*)(&address), (socklen_t)sizeof(address)) < 0) - return -1; - if (listen(socketfd, SOMAXCONN) < 0) - return -1; - - return 0; -} - - -/** - * Close and unlink the socket - * - * @param socketpath The pathname of the socket - */ -void close_socket(const char* socketpath) -{ - if (socketfd >= 0) - { - shutdown(socketfd, SHUT_RDWR); - close(socketfd); - unlink(socketpath); - } -} - diff --git a/src/servers/kernel.h b/src/servers/kernel.h deleted file mode 100644 index 494e150..0000000 --- a/src/servers/kernel.h +++ /dev/null @@ -1,85 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef SERVERS_KERNEL_H -#define SERVERS_KERNEL_H - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * Get the pathname of the socket - * - * @return The pathname of the socket, `NULL` on error - */ -GCC_ONLY(__attribute__((malloc))) -char* get_socket_pathname(void); - -/** - * Get the pathname of the PID file - * - * @return The pathname of the PID file, `NULL` on error - */ -GCC_ONLY(__attribute__((malloc))) -char* get_pidfile_pathname(void); - -/** - * Get the pathname of the state file - * - * @return The pathname of the state file, `NULL` on error - */ -GCC_ONLY(__attribute__((malloc))) -char* get_state_pathname(void); - -/** - * Create PID file - * - * @param pidpath The pathname of the PID file - * @return Zero on success, -1 on error, - * -2 if the service is already running - */ -GCC_ONLY(__attribute__((nonnull))) -int create_pidfile(char* pidpath); - -/** - * Create socket and start listening - * - * @param socketpath The pathname of the socket - * @return Zero on success, -1 on error - */ -GCC_ONLY(__attribute__((nonnull))) -int create_socket(const char* socketpath); - -/** - * Close and unlink the socket - * - * @param socketpath The pathname of the socket - */ -GCC_ONLY(__attribute__((nonnull))) -void close_socket(const char* socketpath); - - -#endif - diff --git a/src/servers/master.c b/src/servers/master.c deleted file mode 100644 index 01b9bb5..0000000 --- a/src/servers/master.c +++ /dev/null @@ -1,394 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "master.h" -#include "crtc.h" -#include "gamma.h" -#include "coopgamma.h" -#include "../util.h" -#include "../communication.h" -#include "../state.h" - -#include <sys/socket.h> -#include <errno.h> -#include <fcntl.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - - - -/** - * All poll(3p) events that are not for writing - */ -#define NON_WR_POLL_EVENTS (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI | POLLERR | POLLHUP | POLLNVAL) - - -/** - * Extract headers from an inbound message and pass - * them on to appropriate message handling function - * - * @param conn The index of the connection - * @param msg The inbound message - * @return 1: The connection as closed - * 0: Successful - * -1: Failure - */ -static int dispatch_message(size_t conn, struct message* restrict msg) -{ - size_t i; - int r = 0; - const char* header; - const char* value; - const char* command = NULL; - const char* crtc = NULL; - const char* coalesce = NULL; - const char* high_priority = NULL; - const char* low_priority = NULL; - const char* priority = NULL; - const char* class = NULL; - const char* lifespan = NULL; - const char* message_id = NULL; - - for (i = 0; i < msg->header_count; i++) - { - value = strstr((header = msg->headers[i]), ": ") + 2; - if (strstr(header, "Command: ") == header) command = value; - else if (strstr(header, "CRTC: ") == header) crtc = value; - else if (strstr(header, "Coalesce: ") == header) coalesce = value; - else if (strstr(header, "High priority: ") == header) high_priority = value; - else if (strstr(header, "Low priority: ") == header) low_priority = value; - else if (strstr(header, "Priority: ") == header) priority = value; - else if (strstr(header, "Class: ") == header) class = value; - else if (strstr(header, "Lifespan: ") == header) lifespan = value; - else if (strstr(header, "Message ID: ") == header) message_id = value; - else if (strstr(header, "Length: ") == header) ;/* Handled transparently */ - else - fprintf(stderr, "%s: ignoring unrecognised header: %s\n", argv0, header); - } - - if (command == NULL) - fprintf(stderr, "%s: ignoring message without Command header\n", argv0); - else if (message_id == NULL) - fprintf(stderr, "%s: ignoring message without Message ID header\n", argv0); - else if (!strcmp(command, "enumerate-crtcs")) - { - if (crtc || coalesce || high_priority || low_priority || priority || class || lifespan) - fprintf(stderr, "%s: ignoring superfluous headers in Command: enumerate-crtcs message\n", argv0); - 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 = 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 = 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 = handle_set_gamma(conn, message_id, crtc, priority, class, lifespan); - } - else - fprintf(stderr, "%s: ignoring unrecognised command: Command: %s\n", argv0, command); - - return r; -} - - -/** - * Sets the file descriptor set that includes - * the server socket and all connections - * - * The file descriptor will be ordered as in - * the array `connections`, `socketfd` will - * be last. - * - * @param fds Reference parameter for the array of file descriptors - * @param fdn Output parameter for the number of file descriptors - * @param fds_alloc Reference parameter for the allocation size of `fds`, in elements - * @return Zero on success, -1 on error - */ -static int update_fdset(struct pollfd** restrict fds, nfds_t* restrict fdn, nfds_t* restrict fds_alloc) -{ - size_t i; - nfds_t j = 0; - - if (connections_used + 1 > *fds_alloc) - { - void* new = realloc(*fds, (connections_used + 1) * sizeof(**fds)); - if (new == NULL) - return -1; - *fds = new; - *fds_alloc = connections_used + 1; - } - - for (i = 0; i < connections_used; i++) - if (connections[i] >= 0) - { - (*fds)[j].fd = connections[i]; - (*fds)[j].events = NON_WR_POLL_EVENTS; - j++; - } - - (*fds)[j].fd = socketfd; - (*fds)[j].events = NON_WR_POLL_EVENTS; - j++; - - *fdn = j; - return 0; -} - - -/** - * Handle event on the server socket - * - * @return 1: New connection accepted - * 0: Successful - * -1: Failure - */ -static int handle_server(void) -{ - int fd, flags, saved_errno; - - fd = accept(socketfd, NULL, NULL); - if (fd < 0) - switch (errno) - { - case EINTR: - return 0; - case ECONNABORTED: - case EINVAL: - terminate = 1; - return 0; - default: - return -1; - } - - flags = fcntl(fd, F_GETFL); - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) - goto fail; - - if (connections_ptr == connections_alloc) - { - void* new; - - new = realloc(connections, (connections_alloc + 10) * sizeof(*connections)); - if (new == NULL) - goto fail; - connections = new; - connections[connections_ptr] = fd; - - new = realloc(outbound, (connections_alloc + 10) * sizeof(*outbound)); - if (new == NULL) - goto fail; - outbound = new; - ring_initialise(outbound + connections_ptr); - - new = realloc(inbound, (connections_alloc + 10) * sizeof(*inbound)); - if (new == NULL) - goto fail; - inbound = new; - connections_alloc += 10; - if (message_initialise(inbound + connections_ptr)) - goto fail; - } - else - { - connections[connections_ptr] = fd; - ring_initialise(outbound + connections_ptr); - if (message_initialise(inbound + connections_ptr)) - goto fail; - } - - connections_ptr++; - while ((connections_ptr < connections_used) && (connections[connections_ptr] >= 0)) - connections_ptr++; - if (connections_used < connections_ptr) - connections_used = connections_ptr; - - return 1; - fail: - saved_errno = errno; - shutdown(fd, SHUT_RDWR); - close(fd); - errno = saved_errno; - return -1; -} - - -/** - * Handle event on a connection to a client - * - * @param conn The index of the connection - * @return 1: The connection as closed - * 0: Successful - * -1: Failure - */ -static int handle_connection(size_t conn) -{ - struct message* restrict msg = inbound + conn; - int r, fd = connections[conn]; - - again: - switch (message_read(msg, fd)) - { - default: - break; - case -1: - switch (errno) - { - case EINTR: - case EAGAIN: -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif - return 0; - default: - return -1; - case ECONNRESET:; - /* Fall throught to `case -2` in outer switch */ - } - case -2: - shutdown(fd, SHUT_RDWR); - close(fd); - connections[conn] = -1; - if (conn < connections_ptr) - connections_ptr = conn; - while ((connections_used > 0) && (connections[connections_used - 1] < 0)) - connections_used -= 1; - message_destroy(msg); - ring_destroy(outbound + conn); - if (connection_closed(fd) < 0) - return -1; - return 1; - } - - if ((r = dispatch_message(conn, msg))) - return r; - - goto again; -} - - - -/** - * 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 - * - * @return Zero on success, -1 on error - */ -int main_loop(void) -{ - struct pollfd* fds = NULL; - nfds_t i, fdn = 0, fds_alloc = 0; - int r, update, saved_errno; - size_t j; - - if (update_fdset(&fds, &fdn, &fds_alloc) < 0) - goto fail; - - while (!reexec && !terminate) - { - if (connection) - { - if ((connection == 1 ? disconnect() : reconnect()) < 0) - { - connection = 0; - goto fail; - } - connection = 0; - } - - for (j = 0, i = 0; j < connections_used; j++) - if (connections[j] >= 0) - { - fds[i].revents = 0; - if (ring_have_more(outbound + j)) - fds[(size_t)i++ + j].events |= POLLOUT; - else - fds[(size_t)i++ + j].events &= ~POLLOUT; - } - fds[i].revents = 0; - - if (poll(fds, fdn, -1) < 0) - { - if (errno == EAGAIN) - perror(argv0); - else if (errno != EINTR) - goto fail; - } - - update = 0; - for (i = 0; i < fdn; i++) - { - int do_read = fds[i].revents & NON_WR_POLL_EVENTS; - int do_write = fds[i].revents & POLLOUT; - int fd = fds[i].fd; - if (!do_read && !do_write) - continue; - - if (fd == socketfd) - r = handle_server(); - else - { - for (j = 0; connections[j] != fd; j++); - r = do_read ? handle_connection(j) : 0; - } - - if ((r >= 0) && do_write) - r |= continue_send(j); - if (r < 0) - goto fail; - update |= (r > 0); - } - if (update) - if (update_fdset(&fds, &fdn, &fds_alloc) < 0) - goto fail; - } - - free(fds); - return 0; - fail: - saved_errno = errno; - free(fds); - errno = saved_errno; - return -1; -} - diff --git a/src/servers/master.h b/src/servers/master.h deleted file mode 100644 index d7ef6e5..0000000 --- a/src/servers/master.h +++ /dev/null @@ -1,36 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef SERVERS_MASTER_H -#define SERVERS_MASTER_H - - -/** - * Disconnect all clients - */ -void disconnect_all(void); - -/** - * The program's main loop - * - * @return Zero on success, -1 on error - */ -int main_loop(void); - - -#endif - diff --git a/src/state.c b/src/state.c deleted file mode 100644 index ff4f0e9..0000000 --- a/src/state.c +++ /dev/null @@ -1,638 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "state.h" -#include "util.h" - -#include <inttypes.h> -#include <stdio.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 disconnect, 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 */ - -/** - * Preserve gamma ramps at priority 0? - */ -int preserve = 0; - - - -/** - * As part of a state dump, dump one or two gamma ramp-trios - * - * @param left The left ramps - * @param right The right ramps - * @param depth The gamma ramp type/depth - * @param have_right Print right ramps? - * @param indent Print indent - */ -static void ramps_dump(union gamma_ramps* left, union gamma_ramps* right, - signed depth, int have_right, const char* indent) -{ -#define STRINGISE(SIDE, CH, N, BUF) \ - do \ - if ((SIDE == NULL) || (SIDE->u8.CH == NULL)) \ - strcpy(BUF, "null"); \ - else if (i < N) \ - switch (depth) \ - { \ - case -2: snprintf(BUF, sizeof(BUF), "%lf", SIDE->d.CH[i]); break; \ - case -1: snprintf(BUF, sizeof(BUF), "%f", (double)(SIDE->f.CH[i])); break; \ - case 8: snprintf(BUF, sizeof(BUF), "%02" PRIx8, SIDE->u8.CH[i]); break; \ - case 16: snprintf(BUF, sizeof(BUF), "%04" PRIx16, SIDE->u16.CH[i]); break; \ - case 32: snprintf(BUF, sizeof(BUF), "%08" PRIx32, SIDE->u32.CH[i]); break; \ - case 64: snprintf(BUF, sizeof(BUF), "%16" PRIx64, SIDE->u64.CH[i]); break; \ - default: \ - strcpy(BUF, "corrupt state"); \ - break; \ - } \ - while (0) - - char lr[100], lg[100], lb[100], rr[100], rg[100], rb[100]; - size_t rn = left ? left->u8.red_size : right ? right->u8.red_size : 0; - size_t gn = left ? left->u8.green_size : right ? right->u8.green_size : 0; - size_t bn = left ? left->u8.blue_size : right ? right->u8.blue_size : 0; - size_t i, n = rn > gn ? rn : gn; - n = n > bn ? n : bn; - - for (i = 0; i < n; i++) - { - *lr = *lg = *lb = *rr = *rg = *rb = '\0'; - - STRINGISE(left, red, rn, lr); - STRINGISE(left, green, gn, lg); - STRINGISE(left, blue, bn, lb); - - if (have_right) - { - STRINGISE(right, red, rn, rr); - STRINGISE(right, green, gn, rg); - STRINGISE(right, blue, bn, rb); - } - - if (have_right) - fprintf(stderr, "%s%zu: %s, %s, %s :: %s, %s, %s\n", indent, i, lr, lg, lb, rr, rg, rb); - else - fprintf(stderr, "%s%zu: %s, %s, %s\n", indent, i, lr, lg, lb); - } -} - - -/** - * Dump the state to stderr - */ -void state_dump(void) -{ - size_t i, j; - fprintf(stderr, "argv0: %s\n", argv0 ? argv0 : "(null)"); - fprintf(stderr, "Realpath of argv0: %s\n", argv0_real ? argv0_real : "(null)"); - fprintf(stderr, "Calibrations preserved: %s\n", preserve ? "yes" : "no"); - fprintf(stderr, "Connected: %s\n", connected ? "yes" : "no"); - fprintf(stderr, "Socket FD: %i\n", socketfd); - fprintf(stderr, "Re-execution pending: %s\n", reexec ? "yes" : "no"); - fprintf(stderr, "Termination pending: %s\n", terminate ? "yes" : "no"); - if ((0 <= connection) && (connection <= 2)) - fprintf(stderr, "Pending connection change: %s\n", - connection == 0 ? "none" : connection == 1 ? "disconnect" : "reconnect"); - else - fprintf(stderr, "Pending connection change: %i (CORRUPT STATE)\n", connection); - fprintf(stderr, "Adjustment method: %i\n", method); - fprintf(stderr, "Site name: %s\n", sitename ? sitename : "(automatic)"); - fprintf(stderr, "Clients:\n"); - fprintf(stderr, " Next empty slot: %zu\n", connections_ptr); - fprintf(stderr, " Initialised slots: %zu\n", connections_used); - fprintf(stderr, " Allocated slots: %zu\n", connections_alloc); - if (connections == NULL) - fprintf(stderr, " File descriptor array is null\n"); - else - for (i = 0; i < connections_used; i++) - { - if (connections[i] < 0) - { - fprintf(stderr, " Slot %zu: empty\n", i); - continue; - } - fprintf(stderr, " Slot %zu:\n", i); - fprintf(stderr, " File descriptor: %i\n", connections[i]); - if (inbound == NULL) - fprintf(stderr, " Inbound message array is null\n"); - else - { - fprintf(stderr, " Inbound message:\n"); - fprintf(stderr, " Header array: %s\n", inbound[i].headers ? "non-null" : "null"); - fprintf(stderr, " Headers: %zu\n", inbound[i].header_count); - fprintf(stderr, " Payload buffer: %s\n", inbound[i].payload ? "non-null" : "null"); - fprintf(stderr, " Payload size: %zu\n", inbound[i].payload_size); - fprintf(stderr, " Payload write pointer: %zu\n", inbound[i].payload_ptr); - fprintf(stderr, " Message buffer: %s\n", inbound[i].buffer ? "non-null" : "null"); - fprintf(stderr, " Message buffer size: %zu\n", inbound[i].buffer_size); - fprintf(stderr, " Message buffer write pointer: %zu\n", inbound[i].buffer_ptr); - fprintf(stderr, " Read stage: %i\n", inbound[i].stage); - } - if (outbound == NULL) - fprintf(stderr, " Outbound message array is null\n"); - else - { - fprintf(stderr, " Ring buffer: %s\n", outbound[i].buffer ? "non-null" : "null"); - fprintf(stderr, " Head: %zu\n", outbound[i].end); - fprintf(stderr, " Tail: %zu\n", outbound[i].start); - fprintf(stderr, " Size: %zu\n", outbound[i].size); - } - } - fprintf(stderr, "Partition array: %s\n", partitions ? "non-null" : "null"); - fprintf(stderr, "CRTC array: %s\n", crtcs ? "non-null" : "null"); - fprintf(stderr, "Output:\n"); - fprintf(stderr, " Output count: %zu\n", outputs_n); - if (outputs == NULL) - fprintf(stderr, " Output array is null\n"); - else - for (i = 0; i < outputs_n; i++) - { - struct output* restrict out = outputs + i; - const char* str; - fprintf(stderr, " Output %zu:\n", i); - fprintf(stderr, " Depth: %i (%s)\n", out->depth, - out->depth == -1 ? "float" : - out->depth == -2 ? "double" : - out->depth == 8 ? "uint8_t" : - out->depth == 16 ? "uint16_t" : - out->depth == 32 ? "uint32_t" : - out->depth == 64 ? "uint64_t" : "CORRUPT STATE"); - fprintf(stderr, " Gamma supported: %s (%i)\n", - out->supported == LIBGAMMA_YES ? "yes" : - out->supported == LIBGAMMA_NO ? "no" : - out->supported == LIBGAMMA_MAYBE ? "maybe" : - "CORRUPT STATE", out->supported); - fprintf(stderr, " Name is EDID: %s\n", out->name_is_edid ? "yes" : "no"); - switch (out->colourspace) - { - case COLOURSPACE_UNKNOWN: str = "unknown"; break; - case COLOURSPACE_SRGB: str = "sRGB with explicit gamut"; break; - case COLOURSPACE_SRGB_SANS_GAMUT: str = "sRGB with implicit gamut (actually illegal)"; break; - case COLOURSPACE_RGB: str = "RGB other than sRGB, with unknown gamut"; break; - case COLOURSPACE_RGB_SANS_GAMUT: str = "RGB other than sRGB, with listed gamut"; break; - case COLOURSPACE_NON_RGB: str = "Non-RGB multicolour"; break; - case COLOURSPACE_GREY: str = "Monochrome or singlecolour scale"; break; - default: str = "CORRUPT STATE"; break; - } - fprintf(stderr, " Colourspace: %s (%i)\n", str, out->colourspace); - if ((out->colourspace == COLOURSPACE_SRGB) || (out->colourspace == COLOURSPACE_RGB)) - { - fprintf(stderr, " Red (x, y): (%u / 1024, %u / 1024)\n", out->red_x, out->red_y); - fprintf(stderr, " Green (x, y): (%u / 1024, %u / 1024)\n", out->green_x, out->green_y); - fprintf(stderr, " Blue (x, y): (%u / 1024, %u / 1024)\n", out->blue_x, out->blue_y); - fprintf(stderr, " White (x, y): (%u / 1024, %u / 1024)\n", out->white_x, out->white_y); - if (out->colourspace == COLOURSPACE_SRGB) - { - fprintf(stderr, " Expected red (x, y): (655 / 1024, 338 / 1024)\n"); - fprintf(stderr, " Expected green (x, y): (307 / 1024, 614 / 1024)\n"); - fprintf(stderr, " Expected blue (x, y): (154 / 1024, 61 / 1024)\n"); - fprintf(stderr, " Expected white (x, y): (320 / 1024, 337 / 1024)\n"); - } - } - if (out->supported) - { - fprintf(stderr, " Gamma ramp size:\n"); - fprintf(stderr, " Red: %zu stops\n", out->red_size); - fprintf(stderr, " Green: %zu stops\n", out->green_size); - fprintf(stderr, " Blue: %zu stops\n", out->blue_size); - fprintf(stderr, " Total: %zu bytes\n", out->ramps_size); - fprintf(stderr, " Name: %s\n", out->name ? out->name : "(null)"); - fprintf(stderr, " CRTC state: %s\n", out->crtc ? "non-null" : "null"); - fprintf(stderr, " Saved gamma ramps (stop: red, green, blue):\n"); - ramps_dump(&(out->saved_ramps), NULL, out->depth, 0, " "); - fprintf(stderr, " Filter table:\n"); - fprintf(stderr, " Filter count: %zu\n", out->table_size); - fprintf(stderr, " Slots allocated: %zu\n", out->table_alloc); - if (out->table_size > 0) - { - if (out->table_filters == NULL) - fprintf(stderr, " Filter table is null\n"); - if (out->table_sums == NULL) - fprintf(stderr, " Result table is null\n"); - } - for (j = 0; j < out->table_size; j++) - { - struct filter* restrict filter = out->table_filters ? out->table_filters + j : NULL; - fprintf(stderr, " Filter %zu:\n", j); - if (filter != NULL) - { - if (filter->lifespan == LIFESPAN_UNTIL_DEATH) - fprintf(stderr, " Client FD: %i\n", filter->client); - switch (filter->lifespan) - { - case LIFESPAN_REMOVE: str = "remove (ILLEGAL STATE)"; break; - case LIFESPAN_UNTIL_REMOVAL: str = "until-removal"; break; - case LIFESPAN_UNTIL_DEATH: str = "until-death"; break; - default: str = "CORRUPT STATE"; break; - } - fprintf(stderr, " Lifespan: %s (%i)\n", str, filter->lifespan); - fprintf(stderr, " Priority: %"PRIi64"\n", filter->priority); - fprintf(stderr, " Class: %s\n", filter->class ? filter->class : "(null)"); - str = "yes"; - if (filter->class == NULL) - str = "no, is NULL"; - else if (strchr(filter->class, '\n')) - str = "no, contains LF"; - else if (strstr(filter->class, "::") == NULL) - str = "no, does not contain \"::\""; - else if (strstr(strstr(filter->class, "::") + 2, "::") == NULL) - str = "no, contains only one \"::\""; - else if (verify_utf8(filter->class) < 0) - str = "no, not UTF-8"; - fprintf(stderr, " Class legal: %s\n", str); - if ((filter->ramps == NULL) && (filter->lifespan != LIFESPAN_REMOVE)) - fprintf(stderr, " Ramps are NULL\n"); - } - if (filter != NULL ? (filter->lifespan != LIFESPAN_REMOVE) : (out->table_sums != NULL)) - { - union gamma_ramps left; - size_t depth; - switch (out->depth) - { - case -2: depth = sizeof(double); break; - case -1: depth = sizeof(float); break; - case 8: case 16: case 32: case 64: - depth = (size_t)(out->depth) / 8; - break; - default: - goto corrupt_depth; - } - if (filter && filter->ramps) - { - left.u8.red_size = out->red_size; - left.u8.green_size = out->green_size; - left.u8.blue_size = out->blue_size; - left.u8.red = filter->ramps; - left.u8.green = left.u8.red + out->red_size * depth; - left.u8.blue = left.u8.green + out->green_size * depth; - } - fprintf(stderr," Ramps (stop: filter red, green, blue :: " - "composite red, geen, blue):\n"); - ramps_dump((filter && filter->ramps) ? &left : NULL, - out->table_sums ? out->table_sums + j : NULL, - out->depth, 1, " "); - corrupt_depth:; - } - } - } - } -} - - -/** - * 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++) - 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(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; - } - - if (bs != NULL) - *(int*)(bs + off) = preserve; - off += sizeof(int); - - 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)) - { - 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); - - outputs = calloc(outputs_n, sizeof(*outputs)); - if (outputs == NULL) - return 0; - - 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); - - preserve = *(const int*)(bs + off); - off += sizeof(int); - - return off; -} - - -#if defined(__clang__) -# pragma GCC diagnostic pop -#endif - diff --git a/src/types/filter.c b/src/types/filter.c deleted file mode 100644 index e6facc9..0000000 --- a/src/types/filter.c +++ /dev/null @@ -1,144 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "filter.h" -#include "../util.h" - -#include <stdlib.h> -#include <string.h> - - - -/** - * Free all resources allocated to a filter. - * The allocation of `filter` itself is not freed. - * - * @param this The filter - */ -void filter_destroy(struct filter* restrict this) -{ - free(this->class); - free(this->ramps); -} - - - -#if defined(__clang__) -# pragma GCC diagnostic ignored "-Wcast-align" -#endif - - -/** - * Marshal a filter - * - * @param this The filter - * @param buf Output buffer for the marshalled filter, - * `NULL` just measure how large the buffers - * needs to be - * @param ramps_size The byte-size of `this->ramps` - * @return The number of marshalled byte - */ -size_t filter_marshal(const struct filter* restrict this, void* restrict buf, size_t ramps_size) -{ - size_t off = 0, n; - char nonnulls = 0; - char* restrict bs = buf; - - if (bs != NULL) - { - if (this->class != NULL) nonnulls |= 1; - if (this->ramps != NULL) nonnulls |= 2; - *(bs + off) = nonnulls; - } - off += 1; - - if (bs != NULL) - *(int64_t*)(bs + off) = this->priority; - off += sizeof(int64_t); - - if (bs != NULL) - *(enum lifespan*)(bs + off) = this->lifespan; - off += sizeof(enum lifespan); - - if (this->class != NULL) - { - n = strlen(this->class) + 1; - if (bs != NULL) - memcpy(bs + off, this->class, n); - off += n; - } - - if (this->ramps != NULL) - { - if (bs != NULL) - memcpy(bs + off, this->ramps, ramps_size); - off += ramps_size; - } - - return off; -} - - -/** - * Unmarshal a filter - * - * @param this Output for the filter - * @param buf Buffer with the marshalled filter - * @param ramps_size The byte-size of `this->ramps` - * @return The number of unmarshalled bytes, 0 on error - */ -size_t filter_unmarshal(struct filter* restrict this, const void* restrict buf, size_t ramps_size) -{ - size_t off = 0, n; - char nonnulls = 0; - const char* restrict bs = buf; - - nonnulls = *(bs + off); - off += 1; - - this->class = NULL; - this->ramps = NULL; - - this->priority = *(const int64_t*)(bs + off); - off += sizeof(int64_t); - - this->lifespan = *(const enum lifespan*)(bs + off); - off += sizeof(enum lifespan); - - if (nonnulls & 1) - { - n = strlen(bs + off) + 1; - if (!(this->class = memdup(bs + off, n))) - goto fail; - off += n; - } - - if (nonnulls & 2) - { - if (!(this->ramps = memdup(bs + off, ramps_size))) - goto fail; - off += ramps_size; - } - - return off; - - fail: - free(this->class); - free(this->ramps); - return 0; -} - diff --git a/src/types/filter.h b/src/types/filter.h deleted file mode 100644 index c91ccb2..0000000 --- a/src/types/filter.h +++ /dev/null @@ -1,138 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef TYPES_FILTER_H -#define TYPES_FILTER_H - - -#include <stddef.h> -#include <stdint.h> - - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * The lifespan of a filter - */ -enum lifespan -{ - /** - * The filter should be removed now - */ - LIFESPAN_REMOVE = 0, - - /** - * The filter should be applied - * until it is explicitly removed - */ - LIFESPAN_UNTIL_REMOVAL = 1, - - /** - * The filter should be applied - * until the client exists - */ - LIFESPAN_UNTIL_DEATH = 2 - -}; - - -/** - * Information about a filter - */ -struct filter -{ - /** - * The client that applied it. This need not be - * set unless `.lifespan == LIFESPAN_UNTIL_DEATH` - * and unless the process itself added this. - * This is the file descriptor of the client's - * connection. - */ - int client; - - /** - * The lifespan of the filter - */ - enum lifespan lifespan; - - /** - * The priority of the filter - */ - int64_t priority; - - /** - * Identifier for the filter - */ - char* class; - - /** - * The gamma ramp adjustments for the filter. - * This is raw binary data. `NULL` iff - * `lifespan == LIFESPAN_REMOVE`. - */ - void* ramps; - -}; - - - -/** - * Free all resources allocated to a filter. - * The allocation of `filter` itself is not freed. - * - * @param this The filter - */ -GCC_ONLY(__attribute__((nonnull))) -void filter_destroy(struct filter* restrict this); - -/** - * Marshal a filter - * - * @param this The filter - * @param buf Output buffer for the marshalled filter, - * `NULL` just measure how large the buffers - * needs to be - * @param ramps_size The byte-size of `filter->ramps` - * @return The number of marshalled byte - */ -GCC_ONLY(__attribute__((nonnull(1)))) -size_t filter_marshal(const struct filter* restrict this, void* restrict buf, size_t ramps_size); - -/** - * Unmarshal a filter - * - * @param this Output for the filter, `.red_size`, `.green_size`, - * and `.blue_size` must already be set - * @param buf Buffer with the marshalled filter - * @param ramps_size The byte-size of `filter->ramps` - * @return The number of unmarshalled bytes, 0 on error - */ -GCC_ONLY(__attribute__((nonnull))) -size_t filter_unmarshal(struct filter* restrict this, const void* restrict buf, size_t ramps_size); - - -#endif - diff --git a/src/types/message.c b/src/types/message.c deleted file mode 100644 index b0a6469..0000000 --- a/src/types/message.c +++ /dev/null @@ -1,572 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "message.h" -#include "../util.h" - -#include <sys/socket.h> -#include <errno.h> -#include <stdint.h> -#include <stdlib.h> -#include <string.h> - - - -/** - * Initialise a message slot so that it can - * be used by to read messages - * - * @param this Memory slot in which to store the new message - * @return Non-zero on error, `errno` will be set accordingly - */ -int message_initialise(struct message* restrict this) -{ - this->headers = NULL; - this->header_count = 0; - this->payload = NULL; - this->payload_size = 0; - this->payload_ptr = 0; - this->buffer_size = 128; - this->buffer_ptr = 0; - this->stage = 0; - this->buffer = malloc(this->buffer_size); - if (this->buffer == NULL) - return -1; - return 0; -} - - -/** - * Release all resources in a message, should - * be done even if initialisation fails - * - * @param this The message - */ -void message_destroy(struct message* restrict this) -{ - size_t i; - if (this->headers != NULL) - for (i = 0; i < this->header_count; i++) - free(this->headers[i]); - - free(this->headers); - free(this->payload); - free(this->buffer); -} - - - -#if defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-align" -#endif - - -/** - * Marshal a message for state serialisation - * - * @param this The message - * @param buf Output buffer for the marshalled data, - * `NULL` just measure how large the buffers - * needs to be - * @return The number of marshalled byte - */ -size_t message_marshal(const struct message* restrict this, void* restrict buf) -{ - size_t i, n, off = 0; - char* bs = buf; - - if (bs != NULL) - *(size_t*)(bs + off) = this->header_count; - off += sizeof(size_t); - - if (bs != NULL) - *(size_t*)(bs + off) = this->payload_size; - off += sizeof(size_t); - - if (bs != NULL) - *(size_t*)(bs + off) = this->payload_ptr; - off += sizeof(size_t); - - if (bs != NULL) - *(size_t*)(bs + off) = this->buffer_ptr; - off += sizeof(size_t); - - if (bs != NULL) - *(int*)(bs + off) = this->stage; - off += sizeof(int); - - for (i = 0; i < this->header_count; i++) - { - n = strlen(this->headers[i]) + 1; - if (bs != NULL) - memcpy(bs + off, this->headers[i], n); - off += n; - } - - if (bs != NULL) - memcpy(bs + off, this->payload, this->payload_ptr); - off += this->payload_ptr; - - if (bs != NULL) - memcpy(bs + off, this->buffer, this->buffer_ptr); - off += this->buffer_ptr; - - return off; -} - - -/** - * Unmarshal a message for state deserialisation - * - * @param this Memory slot in which to store the new message - * @param buf In buffer with the marshalled data - * @return The number of unmarshalled bytes, 0 on error - */ -size_t message_unmarshal(struct message* restrict this, const void* restrict buf) -{ - size_t i, n, off = 0, header_count; - const char* bs = buf; - - this->header_count = 0; - - header_count = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->payload_size = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->payload_ptr = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->buffer_size = this->buffer_ptr = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->stage = *(const int*)(bs + off); - off += sizeof(int); - - /* Make sure that the pointers are NULL so that they are - not freed without being allocated when the message is - destroyed if this function fails. */ - this->headers = NULL; - this->payload = NULL; - this->buffer = NULL; - - /* To 2-power-multiple of 128 bytes. */ - this->buffer_size >>= 7; - if (this->buffer_size == 0) - this->buffer_size = 1; - else - { - this->buffer_size -= 1; - this->buffer_size |= this->buffer_size >> 1; - this->buffer_size |= this->buffer_size >> 2; - this->buffer_size |= this->buffer_size >> 4; - this->buffer_size |= this->buffer_size >> 8; - this->buffer_size |= this->buffer_size >> 16; -#if SIZE_MAX == UINT64_MAX - this->buffer_size |= this->buffer_size >> 32; -#endif - this->buffer_size += 1; - } - this->buffer_size <<= 7; - - /* Allocate header list, payload and read buffer. */ - - if (header_count > 0) - if (!(this->headers = malloc(header_count * sizeof(char*)))) - goto fail; - - if (this->payload_size > 0) - if (!(this->payload = malloc(this->payload_size))) - goto fail; - - if (!(this->buffer = malloc(this->buffer_size))) - goto fail; - - /* Fill the header list, payload and read buffer. */ - - for (i = 0; i < header_count; i++) - { - n = strlen(bs + off) + 1; - this->headers[i] = memdup(bs + off, n); - if (this->headers[i] == NULL) - goto fail; - off += n; - this->header_count++; - } - - memcpy(this->payload, bs + off, this->payload_ptr); - off += this->payload_ptr; - - memcpy(this->buffer, bs + off, this->buffer_ptr); - off += this->buffer_ptr; - - return off; - - fail: - return 0; -} - - -#if defined(__clang__) -# pragma GCC diagnostic pop -#endif - - - -/** - * Extend the header list's allocation - * - * @param this The message - * @param extent The number of additional entries - * @return Zero on success, -1 on error - */ -GCC_ONLY(__attribute__((nonnull))) -static int extend_headers(struct message* restrict this, size_t extent) -{ - char** new; - if (!(new = realloc(this->headers, (this->header_count + extent) * sizeof(char*)))) - return -1; - this->headers = new; - return 0; -} - - -/** - * Extend the read buffer by way of doubling - * - * @param this The message - * @return Zero on success, -1 on error - */ -GCC_ONLY(__attribute__((nonnull))) -static int extend_buffer(struct message* restrict this) -{ - char* restrict new; - if (!(new = realloc(this->buffer, (this->buffer_size << 1) * sizeof(char)))) - return -1; - this->buffer = new; - this->buffer_size <<= 1; - return 0; -} - - -/** - * Reset the header list and the payload - * - * @param this The message - */ -GCC_ONLY(__attribute__((nonnull))) -static void reset_message(struct message* restrict this) -{ - size_t i; - if (this->headers != NULL) - for (i = 0; i < this->header_count; i++) - free(this->headers[i]); - free(this->headers); - this->headers = NULL; - this->header_count = 0; - - free(this->payload); - this->payload = NULL; - this->payload_size = 0; - this->payload_ptr = 0; -} - - -/** - * Read the headers the message and determine, and store, its payload's length - * - * @param this The message - * @return Zero on success, negative on error (malformated message: unrecoverable state) - */ -GCC_ONLY(__attribute__((pure, nonnull))) -static int get_payload_length(struct message* restrict this) -{ - char* header; - size_t i; - - for (i = 0; i < this->header_count; i++) - if (strstr(this->headers[i], "Length: ") == this->headers[i]) - { - /* Store the message length. */ - header = this->headers[i] + strlen("Length: "); - this->payload_size = (size_t)atol(header); - - /* Do not except a length that is not correctly formated. */ - for (; *header; header++) - if ((*header < '0') || ('9' < *header)) - return -2; /* Malformated value, enters unrecoverable state. */ - - /* Stop searching for the ‘Length’ header, we have found and parsed it. */ - break; - } - - return 0; -} - - -/** - * Verify that a header is correctly formatted - * - * @param header The header, must be NUL-terminated - * @param length The length of the header - * @return Zero if valid, negative if invalid (malformated message: unrecoverable state) - */ -GCC_ONLY(__attribute__((pure, nonnull))) -static int validate_header(const char* restrict header, size_t length) -{ - char* restrict p = memchr(header, ':', length * sizeof(char)); - - if (verify_utf8(header) < 0) - /* Either the string is not UTF-8, or your are under an UTF-8 attack, - let's just call this unrecoverable because the client will not correct. */ - return -2; - - if ((p == NULL) || /* Buck you, rawmemchr should not segfault the program. */ - (p[1] != ' ')) /* Also an invalid format. ' ' is mandated after the ':'. */ - return -2; - - return 0; -} - - -/** - * Remove the beginning of the read buffer - * - * @param this The message - * @param length The number of characters to remove - * @param update_ptr Whether to update the buffer pointer - */ -GCC_ONLY(__attribute__((nonnull))) -static void unbuffer_beginning(struct message* restrict this, size_t length, int update_ptr) -{ - memmove(this->buffer, this->buffer + length, (this->buffer_ptr - length) * sizeof(char)); - if (update_ptr) - this->buffer_ptr -= length; -} - - -/** - * Remove the header–payload delimiter from the buffer, - * get the payload's size and allocate the payload - * - * @param this The message - * @return The return value follows the rules of `message_read` - */ -GCC_ONLY(__attribute__((nonnull))) -static int initialise_payload(struct message* restrict this) -{ - /* Remove the \n (end of empty line) we found from the buffer. */ - unbuffer_beginning(this, 1, 1); - - /* Get the length of the payload. */ - if (get_payload_length(this) < 0) - return -2; /* Malformated value, enters unrecoverable state. */ - - /* Allocate the payload buffer. */ - if (this->payload_size > 0) - if (!(this->payload = malloc(this->payload_size))) - return -1; - - return 0; -} - - -/** - * Create a header from the buffer and store it - * - * @param this The message - * @param length The length of the header, including LF-termination - * @return The return value follows the rules of `message_read` - */ -GCC_ONLY(__attribute__((nonnull))) -static int store_header(struct message* restrict this, size_t length) -{ - char* restrict header; - - /* Allocate the header. */ - if (!(header = malloc(length))) /* Last char is a LF, which is substituted with NUL. */ - return -1; - /* Copy the header data into the allocated header, */ - memcpy(header, this->buffer, length * sizeof(char)); - /* and NUL-terminate it. */ - header[length - 1] = '\0'; - - /* Remove the header data from the read buffer. */ - unbuffer_beginning(this, length, 1); - - /* Make sure the the header syntax is correct so that - the program does not need to care about it. */ - if (validate_header(header, length)) - { - free(header); - return -2; - } - - /* Store the header in the header list. */ - this->headers[this->header_count++] = header; - - return 0; -} - - -/** - * Continue reading from the socket into the buffer - * - * @param this The message - * @param fd The file descriptor of the socket - * @return The return value follows the rules of `message_read` - */ -GCC_ONLY(__attribute__((nonnull))) -static int continue_read(struct message* restrict this, int fd) -{ - size_t n; - ssize_t got; - int r; - - /* Figure out how much space we have left in the read buffer. */ - n = this->buffer_size - this->buffer_ptr; - - /* If we do not have too much left, */ - if (n < 128) - { - /* grow the buffer, */ - if ((r = extend_buffer(this)) < 0) - return r; - - /* and recalculate how much space we have left. */ - n = this->buffer_size - this->buffer_ptr; - } - - /* Then read from the socket. */ - errno = 0; - got = recv(fd, this->buffer + this->buffer_ptr, n, 0); - this->buffer_ptr += (size_t)(got < 0 ? 0 : got); - if (errno) - return -1; - if (got == 0) - { - errno = ECONNRESET; - return -1; - } - - return 0; -} - - -/** - * Read the next message from a file descriptor - * - * @param this Memory slot in which to store the new message - * @param fd The file descriptor - * @return 0: At least one message is available - * -1: Exceptional connection: - * EINTR: System call interrupted - * EAGAIN: No message is available - * EWOULDBLOCK: No message is available - * ECONNRESET: Connection closed - * Other: Failure - * -2: Corrupt message (unrecoverable) - */ -GCC_ONLY(__attribute__((nonnull))) -int message_read(struct message* restrict this, int fd) -{ - size_t header_commit_buffer = 0; - int r; - - /* If we are at stage 2, we are done and it is time to start over. - This is important because the function could have been interrupted. */ - if (this->stage == 2) - { - reset_message(this); - this->stage = 0; - } - - /* Read from file descriptor until we have a full message. */ - for (;;) - { - char* p; - size_t length; - - /* Stage 0: headers. */ - /* Read all headers that we have stored into the read buffer. */ - while ((this->stage == 0) && - ((p = memchr(this->buffer, '\n', this->buffer_ptr * sizeof(char))) != NULL)) - if ((length = (size_t)(p - this->buffer))) - { - /* We have found a header. */ - - /* On every eighth header found with this function call, - we prepare the header list for eight more headers so - that it does not need to be reallocated again and again. */ - if (header_commit_buffer == 0) - if ((r = extend_headers(this, header_commit_buffer = 8)) < 0) - return r; - - /* Create and store header. */ - if ((r = store_header(this, length + 1)) < 0) - return r; - header_commit_buffer -= 1; - } - else - { - /* We have found an empty line, i.e. the end of the headers. */ - - /* Remove the header–payload delimiter from the buffer, - get the payload's size and allocate the payload. */ - if ((r = initialise_payload(this)) < 0) - return r; - - /* Mark end of stage, next stage is getting the payload. */ - this->stage = 1; - } - - - /* Stage 1: payload. */ - if ((this->stage == 1) && (this->payload_size > 0)) - { - /* How much of the payload that has not yet been filled. */ - size_t need = this->payload_size - this->payload_ptr; - /* How much we have of that what is needed. */ - size_t move = this->buffer_ptr < need ? this->buffer_ptr : need; - - /* Copy what we have, and remove it from the the read buffer. */ - memcpy(this->payload + this->payload_ptr, this->buffer, move * sizeof(char)); - unbuffer_beginning(this, move, 1); - - /* Keep track of how much we have read. */ - this->payload_ptr += move; - } - if ((this->stage == 1) && (this->payload_ptr == this->payload_size)) - { - /* If we have filled the payload (or there was no payload), - mark the end of this stage, i.e. that the message is - complete, and return with success. */ - this->stage = 2; - return 0; - } - - - /* If stage 1 was not completed. */ - - /* Continue reading from the socket into the buffer. */ - if ((r = continue_read(this, fd)) < 0) - return r; - } -} - diff --git a/src/types/message.h b/src/types/message.h deleted file mode 100644 index 0f1ade2..0000000 --- a/src/types/message.h +++ /dev/null @@ -1,160 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef TYPES_MESSAGE_H -#define TYPES_MESSAGE_H - - -#include <stddef.h> -#include <limits.h> - - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * Message passed between a server and a client - */ -struct message -{ - /** - * The headers in the message, each element in this list - * as an unparsed header, it consists of both the header - * name and its associated value, joined by ": ". A header - * cannot be `NULL` (unless its memory allocation failed,) - * but `headers` itself is `NULL` if there are no headers. - * The "Length" header should be included in this list. - */ - char** restrict headers; - - /** - * The number of headers in the message - */ - size_t header_count; - - /** - * The payload of the message, `NULL` if none (of zero-length) - */ - char* restrict payload; - - /** - * The size of the payload - */ - size_t payload_size; - - /** - * How much of the payload that has been stored (internal data) - */ - size_t payload_ptr; - - /** - * Internal buffer for the reading function (internal data) - */ - char* restrict buffer; - - /** - * The size allocated to `buffer` (internal data) - */ - size_t buffer_size; - - /** - * The number of bytes used in `buffer` (internal data) - */ - size_t buffer_ptr; - - /** - * 0 while reading headers, 1 while reading payload, and 2 when done (internal data) - */ - int stage; - -#if INT_MAX != LONG_MAX - int padding__; -#endif - -}; - - - -/** - * Initialise a message slot so that it can - * be used by to read messages - * - * @param this Memory slot in which to store the new message - * @return Non-zero on error, `errno` will be set accordingly - */ -GCC_ONLY(__attribute__((nonnull))) -int message_initialise(struct message* restrict this); - -/** - * Release all resources in a message, should - * be done even if initialisation fails - * - * @param this The message - */ -GCC_ONLY(__attribute__((nonnull))) -void message_destroy(struct message* restrict this); - -/** - * Marshal a message for state serialisation - * - * @param this The message - * @param buf Output buffer for the marshalled data, - * `NULL` just measure how large the buffers - * needs to be - * @return The number of marshalled byte - */ -GCC_ONLY(__attribute__((nonnull(1)))) -size_t message_marshal(const struct message* restrict this, void* restrict buf); - -/** - * Unmarshal a message for state deserialisation - * - * @param this Memory slot in which to store the new message - * @param buf In buffer with the marshalled data - * @return The number of unmarshalled bytes, 0 on error - */ -GCC_ONLY(__attribute__((nonnull))) -size_t message_unmarshal(struct message* restrict this, const void* restrict buf); - -/** - * Read the next message from a file descriptor - * - * @param this Memory slot in which to store the new message - * @param fd The file descriptor - * @return 0: At least one message is available - * -1: Exceptional connection: - * EINTR: System call interrupted - * EAGAIN: No message is available - * EWOULDBLOCK: No message is available - * ECONNRESET: Connection closed - * Other: Failure - * -2: Corrupt message (unrecoverable) - */ -GCC_ONLY(__attribute__((nonnull))) -int message_read(struct message* restrict this, int fd); - - -#endif - diff --git a/src/types/output.c b/src/types/output.c deleted file mode 100644 index b94d090..0000000 --- a/src/types/output.c +++ /dev/null @@ -1,335 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "output.h" -#include "../util.h" - -#include <stdlib.h> -#include <string.h> - - - -/** - * Free all resources allocated to an output. - * The allocation of `output` itself is not freed, - * nor is its the libgamma destroyed. - * - * @param this The output - */ -void output_destroy(struct output* restrict this) -{ - size_t i; - - if (this->supported != LIBGAMMA_NO) - switch (this->depth) - { - case 8: - libgamma_gamma_ramps8_destroy(&(this->saved_ramps.u8)); - for (i = 0; i < this->table_size; i++) - libgamma_gamma_ramps8_destroy(&(this->table_sums[i].u8)); - break; - case 16: - libgamma_gamma_ramps16_destroy(&(this->saved_ramps.u16)); - for (i = 0; i < this->table_size; i++) - libgamma_gamma_ramps16_destroy(&(this->table_sums[i].u16)); - break; - case 32: - libgamma_gamma_ramps32_destroy(&(this->saved_ramps.u32)); - for (i = 0; i < this->table_size; i++) - libgamma_gamma_ramps32_destroy(&(this->table_sums[i].u32)); - break; - case 64: - libgamma_gamma_ramps64_destroy(&(this->saved_ramps.u64)); - for (i = 0; i < this->table_size; i++) - libgamma_gamma_ramps64_destroy(&(this->table_sums[i].u64)); - break; - case -1: - libgamma_gamma_rampsf_destroy(&(this->saved_ramps.f)); - for (i = 0; i < this->table_size; i++) - libgamma_gamma_rampsf_destroy(&(this->table_sums[i].f)); - break; - case -2: - libgamma_gamma_rampsd_destroy(&(this->saved_ramps.d)); - for (i = 0; i < this->table_size; i++) - libgamma_gamma_rampsd_destroy(&(this->table_sums[i].d)); - break; - default: - break; /* impossible */ - } - - for (i = 0; i < this->table_size; i++) - filter_destroy(this->table_filters + i); - - free(this->table_filters); - free(this->table_sums); - free(this->name); -} - - - -#if defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-align" -#endif - - -/** - * Marshal an output - * - * @param this The output - * @param buf Output buffer for the marshalled output, - * `NULL` just measure how large the buffers - * needs to be - * @return The number of marshalled byte - */ -size_t output_marshal(const struct output* restrict this, void* restrict buf) -{ - size_t off = 0, i, n; - char* bs = buf; - - if (bs != NULL) - *(signed*)(bs + off) = this->depth; - off += sizeof(signed); - - if (bs != NULL) - *(size_t*)(bs + off) = this->red_size; - off += sizeof(size_t); - - if (bs != NULL) - *(size_t*)(bs + off) = this->green_size; - off += sizeof(size_t); - - if (bs != NULL) - *(size_t*)(bs + off) = this->blue_size; - off += sizeof(size_t); - - if (bs != NULL) - *(size_t*)(bs + off) = this->ramps_size; - off += sizeof(size_t); - - if (bs != NULL) - *(enum libgamma_decision*)(bs + off) = this->supported; - off += sizeof(enum libgamma_decision); - - if (bs != NULL) - *(enum colourspace*)(bs + off) = this->colourspace; - off += sizeof(enum colourspace); - - if (bs != NULL) - *(int*)(bs + off) = this->name_is_edid; - off += sizeof(int); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->red_x; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->red_y; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->green_x; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->green_y; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->blue_x; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->blue_y; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->white_x; - off += sizeof(unsigned); - - if (bs != NULL) - *(unsigned*)(bs + off) = this->white_y; - off += sizeof(unsigned); - - n = strlen(this->name) + 1; - if (bs != NULL) - memcpy(bs + off, this->name, n); - off += n; - - off += gamma_ramps_marshal(&(this->saved_ramps), bs ? bs + off : NULL, this->ramps_size); - - if (bs != NULL) - *(size_t*)(bs + off) = this->table_size; - off += sizeof(size_t); - - for (i = 0; i < this->table_size; i++) - { - off += filter_marshal(this->table_filters + i, bs ? bs + off : NULL, this->ramps_size); - off += gamma_ramps_marshal(this->table_sums + i, bs ? bs + off : NULL, this->ramps_size); - } - - return off; -} - - -/** - * Unmarshal an output - * - * @param this Output for the output - * @param buf Buffer with the marshalled output - * @return The number of unmarshalled bytes, 0 on error - */ -size_t output_unmarshal(struct output* restrict this, const void* restrict buf) -{ - size_t off = 0, i, n; - const char* bs = buf; - - this->crtc = NULL; - this->name = NULL; - - this->depth = *(const signed*)(bs + off); - off += sizeof(signed); - - this->red_size = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->green_size = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->blue_size = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->ramps_size = *(const size_t*)(bs + off); - off += sizeof(size_t); - - this->supported = *(const enum libgamma_decision*)(bs + off); - off += sizeof(enum libgamma_decision); - - this->colourspace = *(const enum colourspace*)(bs + off); - off += sizeof(enum colourspace); - - this->name_is_edid = *(const int*)(bs + off); - off += sizeof(int); - - this->red_x = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->red_y = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->green_x = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->green_y = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->blue_x = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->blue_y = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->white_x = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - this->white_y = *(const unsigned*)(bs + off); - off += sizeof(unsigned); - - n = strlen(bs + off) + 1; - this->name = memdup(bs + off, n); - if (this->name == NULL) - return 0; - off += n; - - COPY_RAMP_SIZES(&(this->saved_ramps.u8), this); - off += n = gamma_ramps_unmarshal(&(this->saved_ramps), bs + off, this->ramps_size); - if (n == 0) - return 0; - - this->table_size = this->table_alloc = *(const size_t*)(bs + off); - off += sizeof(size_t); - if (this->table_size > 0) - { - this->table_filters = calloc(this->table_size, sizeof(*(this->table_filters))); - if (this->table_filters == NULL) - return 0; - this->table_sums = calloc(this->table_size, sizeof(*(this->table_sums))); - if (this->table_sums == NULL) - return 0; - } - - for (i = 0; i < this->table_size; i++) - { - off += n = filter_unmarshal(this->table_filters + i, bs + off, this->ramps_size); - if (n == 0) - return 0; - COPY_RAMP_SIZES(&(this->table_sums[i].u8), this); - off += n = gamma_ramps_unmarshal(this->table_sums + i, bs + off, this->ramps_size); - if (n == 0) - return 0; - } - - return off; -} - - -#if defined(__clang__) -# pragma GCC diagnostic pop -#endif - - - -/** - * Compare to outputs by the names of their respective CRTC:s - * - * @param a Return -1 if this one is lower - * @param b Return +1 if this one is higher - * @return See description of `a` and `b`, - * 0 if returned if they are the same - */ -int output_cmp_by_name(const void* restrict a, const void* restrict b) -{ - const char* an = ((const struct output*)a)->name; - const char* bn = ((const struct output*)b)->name; - return strcmp(an, bn); -} - - -/** - * Find an output by its name - * - * @param key The name of the output - * @param base The array of outputs - * @param n The number of elements in `base` - * @return Output find in `base`, `NULL` if not found - */ -struct output* output_find_by_name(const char* restrict key, struct output* restrict base, size_t n) -{ - struct output k; - -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-qual" -#endif - k.name = (char*)key; -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#endif - - return bsearch(&k, base, n, sizeof(*base), output_cmp_by_name); -} - diff --git a/src/types/output.h b/src/types/output.h deleted file mode 100644 index 750ec41..0000000 --- a/src/types/output.h +++ /dev/null @@ -1,308 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef TYPES_OUTPUT_H -#define TYPES_OUTPUT_H - - -#include <stddef.h> - -#include <libgamma.h> - -#include "ramps.h" -#include "filter.h" - - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * Copy the ramp sizes - * - * This macro supports both `struct output` - * and `struct gamma_ramps` - * - * @param dest The destination - * @param src The source - */ -#define COPY_RAMP_SIZES(dest, src) \ - ((dest)->red_size = (src)->red_size, \ - (dest)->green_size = (src)->green_size, \ - (dest)->blue_size = (src)->blue_size) - - - -/** - * Colour spaces - */ -enum colourspace -{ - - /** - * Unknown - */ - COLOURSPACE_UNKNOWN = 0, - - /** - * sRGB with explicit gamut - */ - COLOURSPACE_SRGB = 1, - - /** - * sRGB without explicit gamut - */ - COLOURSPACE_SRGB_SANS_GAMUT = 2, - - /** - * RGB (but not sRGB) with known gamut - */ - COLOURSPACE_RGB = 3, - - /** - * RGB (but not sRGB) without known gamut - */ - COLOURSPACE_RGB_SANS_GAMUT = 4, - - /** - * Non-RGB multicolour - */ - COLOURSPACE_NON_RGB = 5, - - /** - * Greyscale or monochrome - */ - COLOURSPACE_GREY = 6 -}; - - - -/** - * Information about an output - */ -struct output -{ - /** - * -2: double - * -1: float - * 8: uint8_t - * 16: uint16_t - * 32: uint32_t - * 64: uint64_t - */ - signed depth; - - /** - * Whether gamma ramps are supported - */ - enum libgamma_decision supported; - - /** - * Whether the name is the EDID - */ - int name_is_edid; - - /** - * The monitor's colour space - */ - enum colourspace colourspace; - - /** - * The x-value (CIE xyY) of the monitor's - * red colour, multiplied by 1024 - */ - unsigned red_x; - - /** - * The y-value (CIE xyY) of the monitor's - * red colour, multiplied by 1024 - */ - unsigned red_y; - - /** - * The x-value (CIE xyY) of the monitor's - * green colour, multiplied by 1024 - */ - unsigned green_x; - - /** - * The y-value (CIE xyY) of the monitor's - * green colour, multiplied by 1024 - */ - unsigned green_y; - - /** - * The x-value (CIE xyY) of the monitor's - * blue colour, multiplied by 1024 - */ - unsigned blue_x; - - /** - * The y-value (CIE xyY) of the monitor's - * blue colour, multiplied by 1024 - */ - unsigned blue_y; - - /** - * The x-value (CIE xyY) of the monitor's - * default white point, multiplied by 1024 - */ - unsigned white_x; - - /** - * The y-value (CIE xyY) of the monitor's - * default white point, multiplied by 1024 - */ - unsigned white_y; - - /** - * The number of stops in the red gamma ramp - */ - size_t red_size; - - /** - * The number of stops in the green gamma ramp - */ - size_t green_size; - - /** - * The number of stops in the blue gamma ramp - */ - size_t blue_size; - - /** - * `.red_size + .green_size + .blue_size` - * multiplied by the byte-size of each stop - */ - size_t ramps_size; - - /** - * The name of the output, will be its EDID - * if available, otherwise it will be the - * index of the partition, followed by a dot - * and the index of the CRTC within the - * partition, or if a name for the connector - * is available: the index of the partition - * followed by a dot and the name of the - * connector - */ - char* restrict name; - - /** - * The libgamma state for the output - */ - libgamma_crtc_state_t* restrict crtc; - - /** - * Saved gamma ramps - */ - union gamma_ramps saved_ramps; - - /** - * The table of all applied filters - */ - struct filter* restrict table_filters; - - /** - * `.table_sums[i]` is the resulting - * adjustment made when all filter - * from `.table_filters[0]` up to and - * including `.table_filters[i]` has - * been applied - */ - union gamma_ramps* restrict table_sums; - - /** - * The number of elements allocated - * for `.table_filters` and for `.table_sums` - */ - size_t table_alloc; - - /** - * The number of elements stored in - * `.table_filters` and in `.table_sums` - */ - size_t table_size; - -}; - - - -/** - * Free all resources allocated to an output. - * The allocation of `output` itself is not freed, - * nor is its the libgamma destroyed. - * - * @param this The output - */ -GCC_ONLY(__attribute__((nonnull))) -void output_destroy(struct output* restrict this); - -/** - * Marshal an output - * - * @param this The output - * @param buf Output buffer for the marshalled output, - * `NULL` just measure how large the buffers - * needs to be - * @return The number of marshalled byte - */ -GCC_ONLY(__attribute__((nonnull(1)))) -size_t output_marshal(const struct output* restrict this, void* restrict buf); - -/** - * Unmarshal an output - * - * @param this Output for the output - * @param buf Buffer with the marshalled output - * @return The number of unmarshalled bytes, 0 on error - */ -GCC_ONLY(__attribute__((nonnull))) -size_t output_unmarshal(struct output* restrict this, const void* restrict buf); - -/** - * Compare to outputs by the names of their respective CRTC:s - * - * @param a Return -1 if this one is lower - * @param b Return +1 if this one is higher - * @return See description of `a` and `b`, - * 0 if returned if they are the same - */ -GCC_ONLY(__attribute__((pure, nonnull))) -int output_cmp_by_name(const void* restrict a, const void* restrict b); - -/** - * Find an output by its name - * - * @param key The name of the output - * @param base The array of outputs - * @param n The number of elements in `base` - * @return Output find in `base`, `NULL` if not found - */ -GCC_ONLY(__attribute__((pure, nonnull))) -struct output* output_find_by_name(const char* restrict key, struct output* restrict base, size_t n); - - -#endif - diff --git a/src/types/ramps.c b/src/types/ramps.c deleted file mode 100644 index 30bed3e..0000000 --- a/src/types/ramps.c +++ /dev/null @@ -1,98 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "ramps.h" - -#include <libclut.h> - -#include <errno.h> -#include <stdlib.h> -#include <string.h> - - - -/** - * The name of the process - */ -extern char* restrict argv0; - - - -/** - * Marshal a ramp trio - * - * @param this The ramps - * @param buf Output buffer for the marshalled ramps, - * `NULL` just measure how large the buffers - * needs to be - * @param ramps_size The byte-size of ramps - * @return The number of marshalled byte - */ -size_t gamma_ramps_marshal(const union gamma_ramps* restrict this, void* restrict buf, size_t ramps_size) -{ - if (buf != NULL) - memcpy(buf, this->u8.red, ramps_size); - return ramps_size; -} - - -/** - * Unmarshal a ramp trio - * - * @param this Output for the ramps, `.red_size`, `.green_size`, - * and `.blue_size` must already be set - * @param buf Buffer with the marshalled ramps - * @param ramps_size The byte-size of ramps - * @return The number of unmarshalled bytes, 0 on error - */ -size_t gamma_ramps_unmarshal(union gamma_ramps* restrict this, const void* restrict buf, size_t ramps_size) -{ - size_t depth = ramps_size / (this->u8.red_size + this->u8.green_size + this->u8.blue_size); - int r = 0; - switch (depth) - { - case 1: - r = libgamma_gamma_ramps8_initialise(&(this->u8)); - break; - case 2: - r = libgamma_gamma_ramps16_initialise(&(this->u16)); - break; - case 4: - r = libgamma_gamma_ramps32_initialise(&(this->u32)); - break; - case 8: - r = libgamma_gamma_ramps64_initialise(&(this->u64)); - break; - default: - if (depth == sizeof(float)) - r = libgamma_gamma_rampsf_initialise(&(this->f)); - else if (depth == sizeof(double)) - r = libgamma_gamma_rampsd_initialise(&(this->d)); - else - abort(); - break; - } - if (r) - { - libgamma_perror(argv0, r); - errno = 0; - return 0; - } - memcpy(this->u8.red, buf, ramps_size); - return ramps_size; -} - diff --git a/src/types/ramps.h b/src/types/ramps.h deleted file mode 100644 index 001d504..0000000 --- a/src/types/ramps.h +++ /dev/null @@ -1,102 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef TYPES_RAMPS_H -#define TYPES_RAMPS_H - - -#include <libgamma.h> - - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * Gamma ramps union for all - * lbigamma gamma ramps types - */ -union gamma_ramps -{ - /** - * Ramps with 8-bit value - */ - libgamma_gamma_ramps8_t u8; - - /** - * Ramps with 16-bit value - */ - libgamma_gamma_ramps16_t u16; - - /** - * Ramps with 32-bit value - */ - libgamma_gamma_ramps32_t u32; - - /** - * Ramps with 64-bit value - */ - libgamma_gamma_ramps64_t u64; - - /** - * Ramps with `float` value - */ - libgamma_gamma_rampsf_t f; - - /** - * Ramps with `double` value - */ - libgamma_gamma_rampsd_t d; - -}; - - - -/** - * Marshal a ramp trio - * - * @param this The ramps - * @param buf Output buffer for the marshalled ramps, - * `NULL` just measure how large the buffers - * needs to be - * @param ramps_size The byte-size of ramps - * @return The number of marshalled byte - */ -GCC_ONLY(__attribute__((nonnull(1)))) -size_t gamma_ramps_marshal(const union gamma_ramps* restrict this, void* restrict buf, size_t ramps_size); - -/** - * Unmarshal a ramp trio - * - * @param this Output for the ramps - * @param buf Buffer with the marshalled ramps - * @param ramps_size The byte-size of ramps - * @return The number of unmarshalled bytes, 0 on error - */ -GCC_ONLY(__attribute__((nonnull))) -size_t gamma_ramps_unmarshal(union gamma_ramps* restrict this, const void* restrict buf, size_t ramps_size); - - -#endif - diff --git a/src/types/ring.c b/src/types/ring.c deleted file mode 100644 index 13cf8c9..0000000 --- a/src/types/ring.c +++ /dev/null @@ -1,224 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "ring.h" - -#include <stdlib.h> -#include <string.h> - - - -/** - * Initialise a ring buffer - * - * @param this The ring buffer - */ -void ring_initialise(struct ring* restrict this) -{ - this->start = 0; - this->end = 0; - this->size = 0; - this->buffer = NULL; -} - - -/** - * Release resource allocated to a ring buffer - * - * @param this The ring buffer - */ -void ring_destroy(struct ring* restrict this) -{ - free(this->buffer); -} - - - -#if defined(__clang__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wcast-align" -#endif - - -/** - * Marshal a ring buffer - * - * @param this The ring buffer - * @param buf Output buffer for the marshalled data, - * `NULL` to only measure how large buffer - * is needed - * @return The number of marshalled bytes - */ -size_t ring_marshal(const struct ring* restrict this, void* restrict buf) -{ - size_t off = 0, n = this->end - this->start; - char* bs = buf; - - if (bs != NULL) - *(size_t*)(bs + off) = n; - off += sizeof(size_t); - - if (bs != NULL) - memcpy(bs + off, this->buffer + this->start, n); - off += n; - - return off; -} - - -/** - * Unmarshal a ring buffer - * - * @param this Output parameter for the ring buffer - * @param buf Buffer with the marshalled data - * @return The number of unmarshalled bytes, 0 on error - */ -size_t ring_unmarshal(struct ring* restrict this, const void* restrict buf) -{ - size_t off = 0; - const char* bs = buf; - - ring_initialise(this); - - this->size = this->end = *(const size_t*)(bs + off); - off += sizeof(size_t); - - if (this->end > 0) - { - if (!(this->buffer = malloc(this->end))) - return 0; - - memcpy(this->buffer, bs + off, this->end); - off += this->end; - } - - return off; -} - - -#if defined(__clang__) -# pragma GCC diagnostic pop -#endif - - - -/** - * Append data to a ring buffer - * - * @param this The ring buffer - * @param data The new data - * @param n The number of bytes in `data` - * @return Zero on success, -1 on error - */ -int ring_push(struct ring* restrict this, void* restrict data, size_t n) -{ - size_t used = 0; - - if (this->start == this->end) - { - if (this->buffer != NULL) - used = this->size; - } - else if (this->start > this->end) - used = this->size - this->start + this->end; - else - used = this->start - this->end; - - if (used + n > this->size) - { - char* restrict new = malloc(used + n); - if (new == NULL) - return -1; - if (this->buffer) - { - if (this->start < this->end) - memcpy(new, this->buffer + this->start, this->end - this->start); - else - { - memcpy(new, this->buffer + this->start, this->size - this->start); - memcpy(new + this->size - this->start, this->buffer, this->end); - } - } - memcpy(new + used, data, n); - this->buffer = new; - this->start = 0; - this->end = used + n; - this->size = used + n; - } - else if ((this->start >= this->end) || (this->end + n <= this->size)) - { - memcpy(this->buffer + this->end, data, n); - this->end += n; - } - else - { - memcpy(this->buffer + this->end, data, this->size - this->end); - data = (char*)data + (this->size - this->end); - n -= this->size - this->end; - memcpy(this->buffer, data, n); - this->end = n; - } - - return 0; -} - - -/** - * Get queued data from a ring buffer - * - * It can take up to two calls (with `ring_pop` between) - * to get all queued data - * - * @param this The ring buffer - * @param n Output parameter for the length - * of the returned segment - * @return The beginning of the queued data, - * `NULL` if there is nothing more - */ -void* ring_peek(struct ring* restrict this, size_t* restrict n) -{ - if (this->buffer == NULL) - return *n = 0, NULL; - - if (this->start < this->end) - *n = this->end - this->start; - else - *n = this->size - this->start; - return this->buffer + this->start; -} - - -/** - * Dequeue data from a ring bubber - * - * @param this The ring buffer - * @param n The number of bytes to dequeue - */ -void ring_pop(struct ring* restrict this, size_t n) -{ - this->start += n; - this->start %= this->size; - if (this->start == this->end) - { - free(this->buffer); - this->start = 0; - this->end = 0; - this->size = 0; - this->buffer = NULL; - } -} - diff --git a/src/types/ring.h b/src/types/ring.h deleted file mode 100644 index 0474f39..0000000 --- a/src/types/ring.h +++ /dev/null @@ -1,152 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef TYPES_RING_H -#define TYPES_RING_H - - -#include <stddef.h> - - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * Ring buffer - */ -struct ring -{ - /** - * Buffer for the data - */ - char* restrict buffer; - - /** - * The first set byte in `.buffer` - */ - size_t start; - - /** - * The last set byte in `.buffer`, plus 1 - */ - size_t end; - - /** - * The size of `.buffer` - */ - size_t size; -}; - - - -/** - * Initialise a ring buffer - * - * @param this The ring buffer - */ -GCC_ONLY(__attribute__((nonnull))) -void ring_initialise(struct ring* restrict this); - -/** - * Release resource allocated to a ring buffer - * - * @param this The ring buffer - */ -GCC_ONLY(__attribute__((nonnull))) -void ring_destroy(struct ring* restrict this); - -/** - * Marshal a ring buffer - * - * @param this The ring buffer - * @param buf Output buffer for the marshalled data, - * `NULL` to only measure how large buffer - * is needed - * @return The number of marshalled bytes - */ -GCC_ONLY(__attribute__((nonnull(1)))) -size_t ring_marshal(const struct ring* restrict this, void* restrict buf); - -/** - * Unmarshal a ring buffer - * - * @param this Output parameter for the ring buffer - * @param buf Buffer with the marshalled data - * @return The number of unmarshalled bytes, 0 on error - */ -GCC_ONLY(__attribute__((nonnull))) -size_t ring_unmarshal(struct ring* restrict this, const void* restrict buf); - -/** - * Append data to a ring buffer - * - * @param this The ring buffer - * @param data The new data - * @param n The number of bytes in `data` - * @return Zero on success, -1 on error - */ -GCC_ONLY(__attribute__((nonnull(1)))) -int ring_push(struct ring* restrict this, void* restrict data, size_t n); - -/** - * Get queued data from a ring buffer - * - * It can take up to two calls (with `ring_pop` between) - * to get all queued data - * - * @param this The ring buffer - * @param n Output parameter for the length - * of the returned segment - * @return The beginning of the queued data, - * `NULL` if there is nothing more - */ -GCC_ONLY(__attribute__((nonnull))) -void* ring_peek(struct ring* restrict this, size_t* restrict n); - -/** - * Dequeue data from a ring bubber - * - * @param this The ring buffer - * @param n The number of bytes to dequeue - */ -GCC_ONLY(__attribute__((nonnull))) -void ring_pop(struct ring* restrict this, size_t n); - -/** - * Check whether there is more data waiting - * in a ring buffer - * - * @param this The ring buffer - * @return 1 if there is more data, 0 otherwise - */ -GCC_ONLY(__attribute__((nonnull))) -static inline int ring_have_more(struct ring* restrict this) -{ - return this->buffer != NULL; -} - - -#endif - diff --git a/src/util.c b/src/util.c deleted file mode 100644 index 2fdbeae..0000000 --- a/src/util.c +++ /dev/null @@ -1,316 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "util.h" - -#include <libclut.h> - -#include <sys/stat.h> -#include <errno.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> - - - -/** - * Duplicate a memory segment - * - * @param src The memory segment, must not be `NULL` - * @param n The size of the memory segment, must not be zero - * @return The duplicate of the memory segment, - * `NULL` on error - */ -void* memdup(const void* restrict src, size_t n) -{ - void* dest = malloc(n); - if (dest == NULL) - return NULL; - memcpy(dest, src, n); - return dest; -} - - -/** - * Read an entire file - * - * @param fd The file descriptor - * @param n Output for the size of the file - * @return The read content, plus a NUL byte at - * the end (not counted in `*n`) - */ -void* nread(int fd, size_t* restrict n) -{ - size_t size = 32; - ssize_t got; - struct stat st; - char* buf = NULL; - char* new; - int saved_errno; - - *n = 0; - - if (!fstat(fd, &st)) - size = st.st_size <= 0 ? 32 : (size_t)(st.st_size); - - buf = malloc(size + 1); - if (buf == NULL) - return NULL; - - for (;;) - { - if (*n == size) - { - new = realloc(buf, (size <<= 1) + 1); - if (new == NULL) - goto fail; - buf = new; - } - - got = read(fd, buf + *n, size - *n); - if (got < 0) - { - if (errno == EINTR) - continue; - goto fail; - } - if (got == 0) - break; - *n += (size_t)got; - } - - buf[*n] = '\0'; - return buf; - fail: - saved_errno = errno; - free(buf); - errno = saved_errno; - return NULL; -} - - -/** - * Write an entire buffer to a file - * - * Not cancelled by `EINTR` - * - * @param fd The file descriptor - * @param buf The buffer which shall be written to the fail - * @param n The size of the buffer - * @return The number of written bytes, less than `n` - * on error, cannot exceed `n` - */ -size_t nwrite(int fd, const void* restrict buf, size_t n) -{ - const char* restrict bs = buf; - ssize_t wrote; - size_t ptr = 0; - - while (ptr < n) - { - wrote = write(fd, bs + ptr, n - ptr); - if (wrote <= 0) - { - if ((wrote < 0) && (errno == EINTR)) - continue; - return ptr; - } - ptr += (size_t)wrote; - } - - return ptr; -} - - -/** - * Duplicate a file descriptor an make sure - * the new file descriptor's index as a - * specified minimum value - * - * @param fd The file descriptor - * @param atleast The least acceptable new file descriptor - * @return The new file descriptor, -1 on error - */ -int dup2atleast(int fd, int atleast) -{ - int* stack = malloc((size_t)(atleast + 1) * sizeof(int)); - size_t stack_ptr = 0; - int new = -1, saved_errno; - - if (stack == NULL) - goto fail; - - for (;;) - { - new = dup(fd); - if (new < 0) - goto fail; - if (new >= atleast) - break; - } - - fail: - saved_errno = errno; - while (stack_ptr--) - close(stack[stack_ptr]); - free(stack); - errno = saved_errno; - return new; -} - - -/** - * Perform a timed suspention of the process. - * The process resumes when the timer expires, - * or when it is interrupted. - * - * @param ms The number of milliseconds to sleep, - * must be less than 1000 - */ -void msleep(unsigned ms) -{ - struct timespec ts; - ts.tv_sec = 0; - ts.tv_nsec = (long)ms * 1000000L; - if (clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL) == ENOTSUP) - nanosleep(&ts, NULL); -} - - -/** - * Check whether a NUL-terminated string is encoded in UTF-8 - * - * @param string The string - * @return Zero if good, -1 on encoding error - */ -int verify_utf8(const char* restrict string) -{ - static long BYTES_TO_MIN_BITS[] = {0, 0, 8, 12, 17, 22, 37}; - static long BYTES_TO_MAX_BITS[] = {0, 7, 11, 16, 21, 26, 31}; - long bytes = 0, read_bytes = 0, bits = 0, c, character = 0; - - /* min bits max bits - 0....... 0 7 - 110..... 10...... 8 11 - 1110.... 10...... 10...... 12 16 - 11110... 10...... 10...... 10...... 17 21 - 111110.. 10...... 10...... 10...... 10...... 22 26 - 1111110. 10...... 10...... 10...... 10...... 10...... 27 31 - */ - - while ((c = (long)(*string++))) - if (read_bytes == 0) - { - /* First byte of the character. */ - - if ((c & 0x80) == 0x00) - /* Single-byte character. */ - continue; - - if ((c & 0xC0) == 0x80) - /* Single-byte character marked as multibyte, or - a non-first byte in a multibyte character. */ - return -1; - - /* Multibyte character. */ - while ((c & 0x80)) - bytes++, c <<= 1; - read_bytes = 1; - character = c & 0x7F; - if (bytes > 6) - /* 31-bit characters can be encoded with 6-bytes, - and UTF-8 does not cover higher code points. */ - return -1; - } - else - { - /* Not first byte of the character. */ - - if ((c & 0xC0) != 0x80) - /* Beginning of new character before a - multibyte character has ended. */ - return -1; - - character = (character << 6) | (c & 0x7F); - - if (++read_bytes < bytes) - /* Not at last byte yet. */ - continue; - - /* Check that the character is not unnecessarily long. */ - while (character) - character >>= 1, bits++; - if ((bits < BYTES_TO_MIN_BITS[bytes]) || (BYTES_TO_MAX_BITS[bytes] < bits)) - return -1; - - read_bytes = bytes = bits = 0; - } - - /* Make sure we did not stop at the middle of a multibyte character. */ - return read_bytes == 0 ? 0 : -1; -} - - -/** - * 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/util.h b/src/util.h deleted file mode 100644 index eb98285..0000000 --- a/src/util.h +++ /dev/null @@ -1,115 +0,0 @@ -/** - * coopgammad -- Cooperative gamma server - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#ifndef UTIL_H -#define UTIL_H - - -#include "types/output.h" - - - -#ifndef GCC_ONLY -# if defined(__GNUC__) && !defined(__clang__) -# define GCC_ONLY(...) __VA_ARGS__ -# else -# define GCC_ONLY(...) /* nothing */ -# endif -#endif - - - -/** - * Duplicate a memory segment - * - * @param src The memory segment, must not be `NULL` - * @param n The size of the memory segment, must not be zero - * @return The duplicate of the memory segment, - * `NULL` on error - */ -GCC_ONLY(__attribute__((malloc, nonnull))) -void* memdup(const void* restrict src, size_t n); - -/** - * Read an entire file - * - * Not cancelled by `EINTR` - * - * @param fd The file descriptor - * @param n Output for the size of the file - * @return The read content, plus a NUL byte at - * the end (not counted in `*n`) - */ -GCC_ONLY(__attribute__((malloc))) -void* nread(int fd, size_t* restrict n); - -/** - * Write an entire buffer to a file - * - * Not cancelled by `EINTR` - * - * @param fd The file descriptor - * @param buf The buffer which shall be written to the fail - * @param n The size of the buffer - * @return The number of written bytes, less than `n` - * on error, cannot exceed `n` - */ -size_t nwrite(int fd, const void* restrict buf, size_t n); - -/** - * Duplicate a file descriptor an make sure - * the new file descriptor's index as a - * specified minimum value - * - * @param fd The file descriptor - * @param atleast The least acceptable new file descriptor - * @return The new file descriptor, -1 on error - */ -int dup2atleast(int fd, int atleast); - -/** - * Perform a timed suspention of the process. - * The process resumes when the timer expires, - * or when it is interrupted. - * - * @param ms The number of milliseconds to sleep, - * must be less than 1000 - */ -void msleep(unsigned ms); - -/** - * Check whether a NUL-terminated string is encoded in UTF-8 - * - * @param string The string - * @return Zero if good, -1 on encoding error - */ -GCC_ONLY(__attribute__((pure, nonnull))) -int verify_utf8(const char* restrict string); - -/** - * 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 - @@ -1,60 +1,39 @@ -/** - * 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/>. - */ +/* See LICENSE file for copyright and license details. */ #ifndef STATE_H #define STATE_H - -#include "types/message.h" -#include "types/ring.h" -#include "types/output.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__ +# define GCC_ONLY(...) __VA_ARGS__ # else -# define GCC_ONLY(...) /* nothing */ +# define GCC_ONLY(...) /* nothing */ # endif #endif - - /** * The name of the process */ -extern char* restrict argv0; +extern char *restrict argv0; /** * The real pathname of the process's binary, * `NULL` if `argv0` is satisfactory */ -extern char* restrict argv0_real; +extern char *restrict argv0_real; /** * Array of all outputs */ -extern struct output* restrict outputs; +extern struct output *restrict outputs; /** * The nubmer of elements in `outputs` @@ -92,7 +71,7 @@ extern volatile sig_atomic_t connection; * Unused slots, with index less than `connections_used`, * should have the value -1 (negative) */ -extern int* restrict connections; +extern int *restrict connections; /** * The number of elements allocated for `connections` @@ -112,12 +91,12 @@ extern size_t connections_used; /** * The clients' connections' inbound-message buffers */ -extern struct message* restrict inbound; +extern struct message *restrict inbound; /** * The clients' connections' outbound-message buffers */ -extern struct ring* restrict outbound; +extern struct ring *restrict outbound; /** * Is the server connect to the display? @@ -134,7 +113,7 @@ extern int method; /** * The site's name, may be `NULL` */ -extern char* restrict sitename; +extern char *restrict sitename; /** * The libgamma site state @@ -144,20 +123,18 @@ extern libgamma_site_state_t site; /** * The libgamma partition states */ -extern libgamma_partition_state_t* restrict partitions; +extern libgamma_partition_state_t *restrict partitions; /** * The libgamma CRTC states */ -extern libgamma_crtc_state_t* restrict crtcs; +extern libgamma_crtc_state_t *restrict crtcs; /** * Preserve gamma ramps at priority 0? */ extern int preserve; - - /** * Dump the state to stderr */ @@ -176,7 +153,7 @@ void state_destroy(void); * this buffer needs * @return The number of marshalled bytes */ -size_t state_marshal(void* restrict buf); +size_t state_marshal(void *restrict buf); /** * Unmarshal the state @@ -184,9 +161,7 @@ size_t state_marshal(void* restrict buf); * @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); - +GCC_ONLY(__attribute__((__nonnull__))) +size_t state_unmarshal(const void *restrict buf); #endif - |