aboutsummaryrefslogtreecommitdiffstats
path: root/radharc.c
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2025-02-05 21:40:34 +0100
committerMattias Andrée <m@maandree.se>2025-02-05 21:40:34 +0100
commit2cbebb23d08537e0075a7d38b411497e9d9df292 (patch)
treeb80cd37a9019b21b2ecc21b66efc2cc2e82e2de7 /radharc.c
parentAdd -W linear (diff)
downloadradharc-2cbebb23d08537e0075a7d38b411497e9d9df292.tar.gz
radharc-2cbebb23d08537e0075a7d38b411497e9d9df292.tar.bz2
radharc-2cbebb23d08537e0075a7d38b411497e9d9df292.tar.xz
Begin implementation of radharc-ipc
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to 'radharc.c')
-rw-r--r--radharc.c154
1 files changed, 153 insertions, 1 deletions
diff --git a/radharc.c b/radharc.c
index ac53ca3..e48dc6f 100644
--- a/radharc.c
+++ b/radharc.c
@@ -1,8 +1,11 @@
/* See LICENSE file for copyright and license details. */
#include "cg-base.h"
+#include <sys/socket.h>
#include <sys/timerfd.h>
+#include <sys/un.h>
#include <errno.h>
+#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@@ -13,6 +16,7 @@
#define IF_LINEARISING(...) do { if (linearise) { __VA_ARGS__; } } while (0)
+#define SOCKLEN (socklen_t)sizeof
/**
@@ -23,7 +27,7 @@ const int64_t default_priority = (int64_t)7 << 61;
/**
* The default class for the program
*/
-char default_class[] = "radharc::radharc::standard";
+char default_class[] = PACKAGE_NAME"::"COMMAND_NAME"::standard";
/**
* Class suffixes
@@ -110,6 +114,16 @@ static int print_temperature = 0;
*/
static int linearise = 1;
+/**
+ * The abstract address the socket shall have,
+ * if empty, no socket will be created, if
+ * `NULL` a default address derived from the
+ * process ID and the filter class will be used.
+ * If "-", standard input will be used and should
+ * already be bound.
+ */
+static const char *sockname = NULL;
+
/**
* Set to 1 by `handle_args` if the used arguments
@@ -228,6 +242,22 @@ vendor_options(char *arg)
linearise = 0;
else
goto invalid_value;
+ } else if (!strcmp(arg, "socket")) {
+ if (next) {
+ next[-1] = ',';
+ next = NULL;
+ }
+ if (!value)
+ goto missing_value;
+ else if (!*value)
+ goto invalid_value;
+ else
+ sockname = value;
+ } else if (!strcmp(arg, "no-socket")) {
+ if (value)
+ goto unexpected_value;
+ else
+ sockname = "";
} else {
fprintf(stderr, "%s: invalid -W option: %s\n", argv0, arg);
exit(1);
@@ -236,6 +266,10 @@ vendor_options(char *arg)
return;
+unexpected_value:
+ fprintf(stderr, "%s: -W option '%s' has an associated value, but must not\n", argv0, arg);
+ exit(1);
+
missing_value:
fprintf(stderr, "%s: invalid -W option '%s' is missing associated value\n", argv0, arg);
exit(1);
@@ -651,6 +685,41 @@ sigusr2_handler(int sig)
/**
+ * Called to pull all messages from the IPC socket
+ *
+ * @param sock The socket's file descriptor, or -1 if there is none
+ */
+static void
+read_socket(int sock)
+{
+ char buffer[64];
+ ssize_t r;
+
+ if (sock < 0)
+ return;
+
+ for (;;) {
+ r = recv(sock, buffer, sizeof(buffer), MSG_DONTWAIT | MSG_TRUNC);
+ if (r < 0) {
+ if (errno == EAGAIN)
+ break;
+ if (errno == EINTR || errno == ECONNREFUSED)
+ continue;
+ perror(argv0);
+ exit(1);
+ }
+
+ if (!r || (size_t)r > sizeof(buffer)) {
+ fprintf(stderr, "%s: invalid length of received message: %zi\n", argv0, r);
+ continue;
+ }
+
+ /* TODO parse message */
+ }
+}
+
+
+/**
* The main function for the program-specific code
*
* @return 0: Success
@@ -674,6 +743,10 @@ start(void)
size_t fade_cs;
double cs;
sigset_t empty_sigset;
+ int sock = -1;
+ struct sockaddr_un addr;
+ size_t addrlen;
+ struct f_owner_ex owner;
sigemptyset(&empty_sigset);
@@ -716,6 +789,78 @@ start(void)
if (xflag)
return set_ramps(1, 1, 1);
+ memset(&addr, 0, sizeof(addr));
+ addrlen = offsetof(struct sockaddr_un, sun_path);
+ addr.sun_family = AF_UNIX;
+ if (!sockname) {
+ size_t len = strlen(crtc_updates[0].filter.class);
+ size_t off = 1U;
+ off += (size_t)sprintf(&addr.sun_path[off], "/proc/%ju/", (uintmax_t)getpid());
+ if (len > sizeof(addr.sun_path) - 1U) {
+ fprintf(stderr, "%s: socket name is too long; you can may -R shorter,"
+ "select a name with -W socket, or use -W no-socket to skip the socket\n", argv0);
+ return -3;
+ }
+ memcpy(&addr.sun_path[off], crtc_updates[0].filter.class, len);
+ addrlen += off + len;
+ goto create_socket;
+ } else if (!strcmp(sockname, "-")) {
+ int opt;
+ socklen_t len = SOCKLEN(opt);
+ sock = STDIN_FILENO;
+ if (getsockopt(sock, SOL_SOCKET, SO_DOMAIN, &opt, &len)) {
+ if (errno != ENOTSOCK)
+ return -1;
+ fprintf(stderr, "%s: -W socket=- used but standard input is not socket\n", argv0);
+ return -3;
+ }
+ if (opt != PF_UNIX) {
+ fprintf(stderr, "%s: -W socket=- used but standard input is not a unix socket\n", argv0);
+ return -3;
+ }
+ if (getsockopt(sock, SOL_SOCKET, SO_TYPE, &opt, &len))
+ return -1;
+ if (opt != SOCK_DGRAM) {
+ fprintf(stderr, "%s: -W socket=- used but standard input is not a datagram socket\n", argv0);
+ return -3;
+ }
+ len = SOCKLEN(addr);
+ if (getsockname(sock, &addr, &len))
+ return -1;
+ if (len <= offsetof(struct sockaddr_un, sun_path) || addr.sun_family != AF_UNIX) {
+ fprintf(stderr, "%s: -W socket=- used but standard input is not bound to a unix socket address\n", argv0);
+ return -3;
+ }
+ if (len > SOCKLEN(addr)) {
+ fprintf(stderr, "%s: stanard input is bound to an overly long address\n", argv0);
+ return -3;
+ }
+ addrlen = len;
+ } else if (*sockname) {
+ size_t len = strlen(sockname);
+ if (len > sizeof(addr.sun_path) - 1U) {
+ fprintf(stderr, "%s: selected socket name is too long\n", argv0);
+ return -3;
+ }
+ memcpy(&addr.sun_path[1U], sockname, len);
+ addrlen += len + 1U;
+ create_socket:
+ sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (sock < 0)
+ return -1;
+ if (bind(sock, (void *)&addr, (socklen_t)addrlen))
+ return -1;
+ } else {
+ goto no_socket;
+ }
+ if (fcntl(sock, F_SETSIG, SIGIO) < 0)
+ return -1;
+ owner.type = F_OWNER_TID;
+ owner.pid = gettid();
+ if (fcntl(sock, F_SETOWN_EX, &owner) < 0)
+ return -1;
+no_socket:
+
if ((r = make_slaves()) < 0)
return r;
@@ -740,6 +885,7 @@ fade_in:
original_temperature = 6500;
}
for (i = 0; i < fade_cs;) {
+ read_socket(sock);
if (sigint_received) {
goto reverse_fade_in;
} else if (sigusr2_received) {
@@ -778,6 +924,7 @@ skip_fade_in:
faded_in:
for (;;) {
+ read_socket(sock);
if (sigint_received) {
goto fade_out;
} else if (sighup_received) {
@@ -806,6 +953,7 @@ faded_in:
sleep_timeout.tv_nsec = 0;
while ((errno = clock_nanosleep(CLOCK_BOOTTIME, 0, &sleep_timeout, &sleep_timeout))) {
if (errno == EINTR) {
+ read_socket(sock);
if (sigint_received || sighup_received || sigusr1_received || sigusr2_received)
break;
continue;
@@ -829,6 +977,7 @@ fade_out:
fade_out_have_timer:
original_temperature = current_temperature;
for (i = 0; i < fade_cs;) {
+ read_socket(sock);
if (sigint_received > 1 || sigusr1_received) {
goto skip_fade_out;
} else if (!sigint_received && !sighup_received) {
@@ -868,10 +1017,13 @@ faded_out:
for (i = 0; i < filters_n; i++)
crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL;
for (;;) {
+ read_socket(sock);
sigusr1_received = 0;
if (sigint_received || sighup_received) {
for (i = 0; i < filters_n; i++)
crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_REMOVE;
+ if (sock >= 0)
+ close(sock);
return set_ramps(1, 1, 1);
} else if (sigusr2_received) {
sigusr2_received -= 1;