diff options
Diffstat (limited to '')
-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/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 |
10 files changed, 22 insertions, 2337 deletions
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/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 - |