From d8a5a2c3b8e69239098f328e57cb054439f9b81e Mon Sep 17 00:00:00 2001 From: nirenjan Date: Thu, 4 Nov 2021 18:32:18 -0700 Subject: [PATCH] Add daemon command handler loop This change adds the logic to read a packet from the socket, accept connections from clients, and close connections from clients that have hung up. This commit does not yet have support for parsing and handling the commands, and simply echoes the request back to the client. --- daemon/Makefile.am | 2 + daemon/x52d_command.c | 166 ++++++++++++++++++++++++++++++++++++++++++ daemon/x52d_command.h | 15 ++++ daemon/x52d_main.c | 6 +- po/POTFILES.in | 1 + po/libx52.pot | 75 +++++++++++++------ po/xx_PL.po | 73 +++++++++++++------ 7 files changed, 291 insertions(+), 47 deletions(-) create mode 100644 daemon/x52d_command.c create mode 100644 daemon/x52d_command.h diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 5e6552b..1184c19 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -15,6 +15,7 @@ x52d_SOURCES = \ daemon/x52d_clock.c \ daemon/x52d_mouse.c \ daemon/x52d_led.c \ + daemon/x52d_command.c \ daemon/x52d_comm_internal.c x52d_CFLAGS = \ @@ -88,6 +89,7 @@ EXTRA_DIST += \ daemon/x52d_device.h \ daemon/x52d_io.h \ daemon/x52d_mouse.h \ + daemon/x52d_command.h \ daemon/x52dcomm.h \ daemon/x52dcomm-internal.h \ daemon/x52d.conf diff --git a/daemon/x52d_command.c b/daemon/x52d_command.c new file mode 100644 index 0000000..10a41d9 --- /dev/null +++ b/daemon/x52d_command.c @@ -0,0 +1,166 @@ +/* + * Saitek X52 Pro MFD & LED driver - Command processor + * + * Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org) + * + * SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0 + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include + +#include "pinelog.h" +#include "x52d_const.h" +#include "x52d_command.h" + +#define MAX_CONN (X52D_MAX_CLIENTS + 1) + +#define INVALID_CLIENT -1 + +static int client_fd[X52D_MAX_CLIENTS]; +static int active_clients; + +void x52d_command_init(void) +{ + for (int i = 0; i < X52D_MAX_CLIENTS; i++) { + client_fd[i] = INVALID_CLIENT; + } + + active_clients = 0; +} + +static void register_client(int sock_fd) +{ + int fd; + + if (active_clients >= X52D_MAX_CLIENTS) { + /* Ignore the incoming connection */ + return; + } + + fd = accept(sock_fd, NULL, NULL); + if (fd < 0) { + PINELOG_ERROR(_("Error accepting client connection on command socket: %s"), + strerror(errno)); + return; + } + + PINELOG_TRACE("Accepted client %d on command socket", fd); + + for (int i = 0; i < X52D_MAX_CLIENTS; i++) { + if (client_fd[i] == INVALID_CLIENT) { + client_fd[i] = fd; + active_clients++; + break; + } + } +} + +static void deregister_client(int fd) +{ + for (int i = 0; i < X52D_MAX_CLIENTS; i++) { + if (client_fd[i] == fd) { + client_fd[i] = INVALID_CLIENT; + active_clients--; + close(fd); + + PINELOG_TRACE("Disconnected client %d from command socket", fd); + break; + } + } + +} + +static void client_error(int fd) +{ + int error; + socklen_t errlen = sizeof(error); + + getsockopt(fd, SOL_SOCKET, SO_ERROR, (void *)&error, &errlen); + PINELOG_ERROR(_("Error when polling command socket: FD %d, error %d, len %lu"), + fd, error, (unsigned long int)errlen); + deregister_client(fd); +} + +static int poll_clients(int sock_fd, struct pollfd *pfd) +{ + int pfd_count; + int rc; + + memset(pfd, 0, sizeof(*pfd) * MAX_CONN); + + pfd_count = 1; + pfd[0].fd = sock_fd; + pfd[0].events = POLLIN | POLLERR; + for (int i = 0; i < X52D_MAX_CLIENTS; i++) { + if (client_fd[i] != INVALID_CLIENT) { + pfd[pfd_count].fd = client_fd[i]; + pfd[pfd_count].events = POLLIN | POLLERR | POLLHUP; + pfd_count++; + } + } + + PINELOG_TRACE("Polling %d file descriptors", pfd_count); + rc = poll(pfd, pfd_count, -1); + if (rc < 0) { + if (errno != EINTR) { + PINELOG_ERROR(_("Error when polling for command: %s"), strerror(errno)); + return -1; + } + } else if (rc == 0) { + PINELOG_INFO(_("Timed out when polling for command")); + } + + return rc; +} + +int x52d_command_loop(int sock_fd) +{ + struct pollfd pfd[MAX_CONN]; + int rc; + int i; + + rc = poll_clients(sock_fd, pfd); + if (rc <= 0) { + return -1; + } + + for (i = 0; i < MAX_CONN; i++) { + if (pfd[i].revents & POLLHUP) { + /* Remote hungup */ + deregister_client(pfd[i].fd); + } else if (pfd[i].revents & POLLERR) { + /* Error reading from the socket */ + client_error(pfd[i].fd); + } else if (pfd[i].revents & POLLIN) { + if (pfd[i].fd == sock_fd) { + register_client(sock_fd); + } else { + char buffer[1024]; + int sent; + + rc = recv(pfd[i].fd, buffer, sizeof(buffer), 0); + if (rc < 0) { + PINELOG_ERROR(_("Error reading from client %d: %s"), + pfd[i].fd, strerror(errno)); + continue; + } + + // TODO: Parse and handle command. + // Echo it back to the client for now. + sent = send(pfd[i].fd, buffer, rc, 0); + if (sent != rc) { + PINELOG_ERROR(_("Short write to client %d; expected %d bytes, wrote %d bytes"), + pfd[i].fd, rc, sent); + } + } + } + } + + return 0; +} diff --git a/daemon/x52d_command.h b/daemon/x52d_command.h new file mode 100644 index 0000000..96513a2 --- /dev/null +++ b/daemon/x52d_command.h @@ -0,0 +1,15 @@ +/* + * Saitek X52 Pro MFD & LED driver - Command processor + * + * Copyright (C) 2021 Nirenjan Krishnan (nirenjan@nirenjan.org) + * + * SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0 + */ + +#ifndef X52D_COMMAND_H +#define X52D_COMMAND_H + +void x52d_command_init(void); +int x52d_command_loop(int sock_fd); + +#endif // !defined X52D_COMMAND_H diff --git a/daemon/x52d_main.c b/daemon/x52d_main.c index ff8d87c..fff3c51 100644 --- a/daemon/x52d_main.c +++ b/daemon/x52d_main.c @@ -23,6 +23,7 @@ #include "x52d_device.h" #include "x52d_io.h" #include "x52d_mouse.h" +#include "x52d_command.h" #include "x52dcomm-internal.h" #include "x52dcomm.h" #include "pinelog.h" @@ -356,6 +357,7 @@ int main(int argc, char **argv) // Start device threads x52d_dev_init(); x52d_clock_init(); + x52d_command_init(); #if defined(HAVE_EVDEV) x52d_io_init(); x52d_mouse_evdev_init(); @@ -371,9 +373,7 @@ int main(int argc, char **argv) flag_quit = 0; while(!flag_quit) { - // TODO: Replace with main event loop - // Let all threads run in background forever - sleep(600); + x52d_command_loop(command_sock_fd); /* Check if we need to reload configuration */ if (flag_reload) { diff --git a/po/POTFILES.in b/po/POTFILES.in index 3b7426c..1435f68 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -14,6 +14,7 @@ joytest/x52_test_mfd.c daemon/x52d_main.c daemon/x52d_clock.c +daemon/x52d_command.c daemon/x52d_config.c daemon/x52d_config_dump.c daemon/x52d_config_parser.c diff --git a/po/libx52.pot b/po/libx52.pot index 6cde6a2..92b03c2 100644 --- a/po/libx52.pot +++ b/po/libx52.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: libx52 0.2.3\n" "Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\n" -"POT-Creation-Date: 2021-11-04 13:37-0700\n" +"POT-Creation-Date: 2021-11-04 15:33-0700\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -491,17 +491,17 @@ msgstr "" msgid "OK" msgstr "" -#: daemon/x52d_main.c:63 +#: daemon/x52d_main.c:64 #, c-format msgid "Error %d setting log file: %s\n" msgstr "" -#: daemon/x52d_main.c:79 +#: daemon/x52d_main.c:80 #, c-format msgid "Error %d installing handler for signal %d: %s" msgstr "" -#: daemon/x52d_main.c:90 +#: daemon/x52d_main.c:91 #, c-format msgid "" "Usage: %s [-f] [-v] [-q]\n" @@ -510,81 +510,81 @@ msgid "" "\t[-s command-socket-path]\n" msgstr "" -#: daemon/x52d_main.c:121 +#: daemon/x52d_main.c:122 #, c-format msgid "Daemon is already running as PID %u" msgstr "" -#: daemon/x52d_main.c:217 +#: daemon/x52d_main.c:218 #, c-format msgid "Error creating command socket: %s" msgstr "" -#: daemon/x52d_main.c:224 +#: daemon/x52d_main.c:225 #, c-format msgid "Error getting command socket flags: %s" msgstr "" -#: daemon/x52d_main.c:228 +#: daemon/x52d_main.c:229 #, c-format msgid "Error setting command socket flags: %s" msgstr "" -#: daemon/x52d_main.c:236 +#: daemon/x52d_main.c:237 #, c-format msgid "Error binding to command socket: %s" msgstr "" -#: daemon/x52d_main.c:241 +#: daemon/x52d_main.c:242 #, c-format msgid "Error listening on command socket: %s" msgstr "" -#: daemon/x52d_main.c:315 +#: daemon/x52d_main.c:316 #, c-format msgid "Unable to parse configuration override '%s'\n" msgstr "" -#: daemon/x52d_main.c:343 +#: daemon/x52d_main.c:344 #, c-format msgid "Foreground = %s" msgstr "" -#: daemon/x52d_main.c:343 daemon/x52d_main.c:344 +#: daemon/x52d_main.c:344 daemon/x52d_main.c:345 msgid "true" msgstr "" -#: daemon/x52d_main.c:343 daemon/x52d_main.c:344 +#: daemon/x52d_main.c:344 daemon/x52d_main.c:345 msgid "false" msgstr "" -#: daemon/x52d_main.c:344 -#, c-format -msgid "Quiet = %s" -msgstr "" - #: daemon/x52d_main.c:345 #, c-format -msgid "Verbosity = %d" +msgid "Quiet = %s" msgstr "" #: daemon/x52d_main.c:346 #, c-format -msgid "Log file = %s" +msgid "Verbosity = %d" msgstr "" #: daemon/x52d_main.c:347 #, c-format -msgid "Config file = %s" +msgid "Log file = %s" msgstr "" #: daemon/x52d_main.c:348 #, c-format -msgid "PID file = %s" +msgid "Config file = %s" msgstr "" #: daemon/x52d_main.c:349 #, c-format +msgid "PID file = %s" +msgstr "" + +#: daemon/x52d_main.c:350 +#, c-format msgid "Command socket = %s" msgstr "" @@ -659,6 +659,35 @@ msgstr "" msgid "Shutting down X52 clock manager thread" msgstr "" +#: daemon/x52d_command.c:48 +#, c-format +msgid "Error accepting client connection on command socket: %s" +msgstr "" + +#: daemon/x52d_command.c:85 +#, c-format +msgid "Error when polling command socket: FD %d, error %d, len %lu" +msgstr "" + +#: daemon/x52d_command.c:112 +#, c-format +msgid "Error when polling for command: %s" +msgstr "" + +#: daemon/x52d_command.c:116 +msgid "Timed out when polling for command" +msgstr "" + +#: daemon/x52d_command.c:149 +#, c-format +msgid "Error reading from client %d: %s" +msgstr "" + +#: daemon/x52d_command.c:158 +#, c-format +msgid "Short write to client %d; expected %d bytes, wrote %d bytes" +msgstr "" + #: daemon/x52d_config.c:26 #, c-format msgid "Error %d setting configuration defaults: %s" diff --git a/po/xx_PL.po b/po/xx_PL.po index cb5c026..57b8fa9 100644 --- a/po/xx_PL.po +++ b/po/xx_PL.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: libx52 0.2.3\n" "Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\n" -"POT-Creation-Date: 2021-11-04 13:37-0700\n" -"PO-Revision-Date: 2021-11-04 13:45-0700\n" +"POT-Creation-Date: 2021-11-04 15:33-0700\n" +"PO-Revision-Date: 2021-11-04 15:35-0700\n" "Last-Translator: Nirenjan Krishnan \n" "Language-Team: Dummy Language for testing i18n\n" "Language: xx_PL\n" @@ -534,17 +534,17 @@ msgstr "Estingtay aracterchay 0x%02x..." msgid "OK" msgstr "OKay" -#: daemon/x52d_main.c:63 +#: daemon/x52d_main.c:64 #, c-format msgid "Error %d setting log file: %s\n" msgstr "Erroray %d ettingsay oglay ilefay: %s\n" -#: daemon/x52d_main.c:79 +#: daemon/x52d_main.c:80 #, c-format msgid "Error %d installing handler for signal %d: %s" msgstr "Erroray %d installingay andlerhay orfay ignalsay %d: %s" -#: daemon/x52d_main.c:90 +#: daemon/x52d_main.c:91 #, c-format msgid "" "Usage: %s [-f] [-v] [-q]\n" @@ -557,80 +557,80 @@ msgstr "" "\t[-c onfigcay-ilefay] [-p idpay-ilefay]\n" "\t[-s ommandcay-ocketsay-athpay]\n" -#: daemon/x52d_main.c:121 +#: daemon/x52d_main.c:122 #, c-format msgid "Daemon is already running as PID %u" msgstr "Aemonday isay alreadyay unningray asay IDPay %u" -#: daemon/x52d_main.c:217 +#: daemon/x52d_main.c:218 #, c-format msgid "Error creating command socket: %s" msgstr "Erroray eatingcray ommandcay ocketsay: %s" -#: daemon/x52d_main.c:224 +#: daemon/x52d_main.c:225 #, c-format msgid "Error getting command socket flags: %s" msgstr "Erroray ettinggay ommandcay ocketsay agsflay: %s" -#: daemon/x52d_main.c:228 +#: daemon/x52d_main.c:229 #, c-format msgid "Error setting command socket flags: %s" msgstr "Erroray ettingsay ommandcay ocketsay agsflay: %s" -#: daemon/x52d_main.c:236 +#: daemon/x52d_main.c:237 #, c-format msgid "Error binding to command socket: %s" msgstr "Erroray indingbay otay ommandcay ocketsay: %s" -#: daemon/x52d_main.c:241 +#: daemon/x52d_main.c:242 #, c-format msgid "Error listening on command socket: %s" msgstr "Erroray isteninglay onay ommandcay ocketsay: %s" -#: daemon/x52d_main.c:315 +#: daemon/x52d_main.c:316 #, c-format msgid "Unable to parse configuration override '%s'\n" msgstr "Unableay otay arsepay onfigurationcay overrideay '%s'\n" -#: daemon/x52d_main.c:343 +#: daemon/x52d_main.c:344 #, c-format msgid "Foreground = %s" msgstr "Oregroundfay = %s" -#: daemon/x52d_main.c:343 daemon/x52d_main.c:344 +#: daemon/x52d_main.c:344 daemon/x52d_main.c:345 msgid "true" msgstr "uetray" -#: daemon/x52d_main.c:343 daemon/x52d_main.c:344 +#: daemon/x52d_main.c:344 daemon/x52d_main.c:345 msgid "false" msgstr "alsefay" -#: daemon/x52d_main.c:344 +#: daemon/x52d_main.c:345 #, c-format msgid "Quiet = %s" msgstr "Uietqay = %s" -#: daemon/x52d_main.c:345 +#: daemon/x52d_main.c:346 #, c-format msgid "Verbosity = %d" msgstr "Erbosityvay = %d" -#: daemon/x52d_main.c:346 +#: daemon/x52d_main.c:347 #, c-format msgid "Log file = %s" msgstr "Oglay ilefay = %s" -#: daemon/x52d_main.c:347 +#: daemon/x52d_main.c:348 #, c-format msgid "Config file = %s" msgstr "Onfigcay ilefay = %s" -#: daemon/x52d_main.c:348 +#: daemon/x52d_main.c:349 #, c-format msgid "PID file = %s" msgstr "IDPay ilefay = %s" -#: daemon/x52d_main.c:349 +#: daemon/x52d_main.c:350 #, c-format msgid "Command socket = %s" msgstr "Ommandcay ocketsay = %s" @@ -709,6 +709,37 @@ msgstr "Erroray %d initializingay ockclay eadthray: %s" msgid "Shutting down X52 clock manager thread" msgstr "Uttingshay ownday X52 ockclay anagermay eadthray" +#: daemon/x52d_command.c:48 +#, c-format +msgid "Error accepting client connection on command socket: %s" +msgstr "Erroray acceptingay ientclay onnectioncay onay ommandcay ocketsay: %s" + +#: daemon/x52d_command.c:85 +#, c-format +msgid "Error when polling command socket: FD %d, error %d, len %lu" +msgstr "" +"Erroray enwhay ollingpay ommandcay ocketsay: FDay %d, erroray %d, enlay %lu" + +#: daemon/x52d_command.c:112 +#, c-format +msgid "Error when polling for command: %s" +msgstr "Erroray enwhay ollingpay orfay ommandcay: %s" + +#: daemon/x52d_command.c:116 +msgid "Timed out when polling for command" +msgstr "Imedtay outay enwhay ollingpay orfay ommandcay" + +#: daemon/x52d_command.c:149 +#, c-format +msgid "Error reading from client %d: %s" +msgstr "Erroray eadingray omfray ientclay %d: %s" + +#: daemon/x52d_command.c:158 +#, c-format +msgid "Short write to client %d; expected %d bytes, wrote %d bytes" +msgstr "" +"Ortshay itewray otay ientclay %d; expecteday %d ytesbay, otewray %d ytesbay" + #: daemon/x52d_config.c:26 #, c-format msgid "Error %d setting configuration defaults: %s"