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.
reverse-scroll
nirenjan 2021-11-04 18:32:18 -07:00
parent 5a78492140
commit d8a5a2c3b8
7 changed files with 291 additions and 47 deletions

View File

@ -15,6 +15,7 @@ x52d_SOURCES = \
daemon/x52d_clock.c \ daemon/x52d_clock.c \
daemon/x52d_mouse.c \ daemon/x52d_mouse.c \
daemon/x52d_led.c \ daemon/x52d_led.c \
daemon/x52d_command.c \
daemon/x52d_comm_internal.c daemon/x52d_comm_internal.c
x52d_CFLAGS = \ x52d_CFLAGS = \
@ -88,6 +89,7 @@ EXTRA_DIST += \
daemon/x52d_device.h \ daemon/x52d_device.h \
daemon/x52d_io.h \ daemon/x52d_io.h \
daemon/x52d_mouse.h \ daemon/x52d_mouse.h \
daemon/x52d_command.h \
daemon/x52dcomm.h \ daemon/x52dcomm.h \
daemon/x52dcomm-internal.h \ daemon/x52dcomm-internal.h \
daemon/x52d.conf daemon/x52d.conf

View File

@ -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 <string.h>
#include <errno.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#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;
}

View File

@ -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

View File

@ -23,6 +23,7 @@
#include "x52d_device.h" #include "x52d_device.h"
#include "x52d_io.h" #include "x52d_io.h"
#include "x52d_mouse.h" #include "x52d_mouse.h"
#include "x52d_command.h"
#include "x52dcomm-internal.h" #include "x52dcomm-internal.h"
#include "x52dcomm.h" #include "x52dcomm.h"
#include "pinelog.h" #include "pinelog.h"
@ -356,6 +357,7 @@ int main(int argc, char **argv)
// Start device threads // Start device threads
x52d_dev_init(); x52d_dev_init();
x52d_clock_init(); x52d_clock_init();
x52d_command_init();
#if defined(HAVE_EVDEV) #if defined(HAVE_EVDEV)
x52d_io_init(); x52d_io_init();
x52d_mouse_evdev_init(); x52d_mouse_evdev_init();
@ -371,9 +373,7 @@ int main(int argc, char **argv)
flag_quit = 0; flag_quit = 0;
while(!flag_quit) { while(!flag_quit) {
// TODO: Replace with main event loop x52d_command_loop(command_sock_fd);
// Let all threads run in background forever
sleep(600);
/* Check if we need to reload configuration */ /* Check if we need to reload configuration */
if (flag_reload) { if (flag_reload) {

View File

@ -14,6 +14,7 @@ joytest/x52_test_mfd.c
daemon/x52d_main.c daemon/x52d_main.c
daemon/x52d_clock.c daemon/x52d_clock.c
daemon/x52d_command.c
daemon/x52d_config.c daemon/x52d_config.c
daemon/x52d_config_dump.c daemon/x52d_config_dump.c
daemon/x52d_config_parser.c daemon/x52d_config_parser.c

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: libx52 0.2.3\n" "Project-Id-Version: libx52 0.2.3\n"
"Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -491,17 +491,17 @@ msgstr ""
msgid "OK" msgid "OK"
msgstr "" msgstr ""
#: daemon/x52d_main.c:63 #: daemon/x52d_main.c:64
#, c-format #, c-format
msgid "Error %d setting log file: %s\n" msgid "Error %d setting log file: %s\n"
msgstr "" msgstr ""
#: daemon/x52d_main.c:79 #: daemon/x52d_main.c:80
#, c-format #, c-format
msgid "Error %d installing handler for signal %d: %s" msgid "Error %d installing handler for signal %d: %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:90 #: daemon/x52d_main.c:91
#, c-format #, c-format
msgid "" msgid ""
"Usage: %s [-f] [-v] [-q]\n" "Usage: %s [-f] [-v] [-q]\n"
@ -510,81 +510,81 @@ msgid ""
"\t[-s command-socket-path]\n" "\t[-s command-socket-path]\n"
msgstr "" msgstr ""
#: daemon/x52d_main.c:121 #: daemon/x52d_main.c:122
#, c-format #, c-format
msgid "Daemon is already running as PID %u" msgid "Daemon is already running as PID %u"
msgstr "" msgstr ""
#: daemon/x52d_main.c:217 #: daemon/x52d_main.c:218
#, c-format #, c-format
msgid "Error creating command socket: %s" msgid "Error creating command socket: %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:224 #: daemon/x52d_main.c:225
#, c-format #, c-format
msgid "Error getting command socket flags: %s" msgid "Error getting command socket flags: %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:228 #: daemon/x52d_main.c:229
#, c-format #, c-format
msgid "Error setting command socket flags: %s" msgid "Error setting command socket flags: %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:236 #: daemon/x52d_main.c:237
#, c-format #, c-format
msgid "Error binding to command socket: %s" msgid "Error binding to command socket: %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:241 #: daemon/x52d_main.c:242
#, c-format #, c-format
msgid "Error listening on command socket: %s" msgid "Error listening on command socket: %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:315 #: daemon/x52d_main.c:316
#, c-format #, c-format
msgid "Unable to parse configuration override '%s'\n" msgid "Unable to parse configuration override '%s'\n"
msgstr "" msgstr ""
#: daemon/x52d_main.c:343 #: daemon/x52d_main.c:344
#, c-format #, c-format
msgid "Foreground = %s" msgid "Foreground = %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:343 daemon/x52d_main.c:344 #: daemon/x52d_main.c:344 daemon/x52d_main.c:345
msgid "true" msgid "true"
msgstr "" msgstr ""
#: daemon/x52d_main.c:343 daemon/x52d_main.c:344 #: daemon/x52d_main.c:344 daemon/x52d_main.c:345
msgid "false" msgid "false"
msgstr "" msgstr ""
#: daemon/x52d_main.c:344
#, c-format
msgid "Quiet = %s"
msgstr ""
#: daemon/x52d_main.c:345 #: daemon/x52d_main.c:345
#, c-format #, c-format
msgid "Verbosity = %d" msgid "Quiet = %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:346 #: daemon/x52d_main.c:346
#, c-format #, c-format
msgid "Log file = %s" msgid "Verbosity = %d"
msgstr "" msgstr ""
#: daemon/x52d_main.c:347 #: daemon/x52d_main.c:347
#, c-format #, c-format
msgid "Config file = %s" msgid "Log file = %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:348 #: daemon/x52d_main.c:348
#, c-format #, c-format
msgid "PID file = %s" msgid "Config file = %s"
msgstr "" msgstr ""
#: daemon/x52d_main.c:349 #: daemon/x52d_main.c:349
#, c-format #, c-format
msgid "PID file = %s"
msgstr ""
#: daemon/x52d_main.c:350
#, c-format
msgid "Command socket = %s" msgid "Command socket = %s"
msgstr "" msgstr ""
@ -659,6 +659,35 @@ msgstr ""
msgid "Shutting down X52 clock manager thread" msgid "Shutting down X52 clock manager thread"
msgstr "" 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 #: daemon/x52d_config.c:26
#, c-format #, c-format
msgid "Error %d setting configuration defaults: %s" msgid "Error %d setting configuration defaults: %s"

View File

@ -7,8 +7,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: libx52 0.2.3\n" "Project-Id-Version: libx52 0.2.3\n"
"Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\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: 2021-11-04 13:45-0700\n" "PO-Revision-Date: 2021-11-04 15:35-0700\n"
"Last-Translator: Nirenjan Krishnan <nirenjan@gmail.com>\n" "Last-Translator: Nirenjan Krishnan <nirenjan@gmail.com>\n"
"Language-Team: Dummy Language for testing i18n\n" "Language-Team: Dummy Language for testing i18n\n"
"Language: xx_PL\n" "Language: xx_PL\n"
@ -534,17 +534,17 @@ msgstr "Estingtay aracterchay 0x%02x..."
msgid "OK" msgid "OK"
msgstr "OKay" msgstr "OKay"
#: daemon/x52d_main.c:63 #: daemon/x52d_main.c:64
#, c-format #, c-format
msgid "Error %d setting log file: %s\n" msgid "Error %d setting log file: %s\n"
msgstr "Erroray %d ettingsay oglay ilefay: %s\n" msgstr "Erroray %d ettingsay oglay ilefay: %s\n"
#: daemon/x52d_main.c:79 #: daemon/x52d_main.c:80
#, c-format #, c-format
msgid "Error %d installing handler for signal %d: %s" msgid "Error %d installing handler for signal %d: %s"
msgstr "Erroray %d installingay andlerhay orfay ignalsay %d: %s" msgstr "Erroray %d installingay andlerhay orfay ignalsay %d: %s"
#: daemon/x52d_main.c:90 #: daemon/x52d_main.c:91
#, c-format #, c-format
msgid "" msgid ""
"Usage: %s [-f] [-v] [-q]\n" "Usage: %s [-f] [-v] [-q]\n"
@ -557,80 +557,80 @@ msgstr ""
"\t[-c onfigcay-ilefay] [-p idpay-ilefay]\n" "\t[-c onfigcay-ilefay] [-p idpay-ilefay]\n"
"\t[-s ommandcay-ocketsay-athpay]\n" "\t[-s ommandcay-ocketsay-athpay]\n"
#: daemon/x52d_main.c:121 #: daemon/x52d_main.c:122
#, c-format #, c-format
msgid "Daemon is already running as PID %u" msgid "Daemon is already running as PID %u"
msgstr "Aemonday isay alreadyay unningray asay IDPay %u" msgstr "Aemonday isay alreadyay unningray asay IDPay %u"
#: daemon/x52d_main.c:217 #: daemon/x52d_main.c:218
#, c-format #, c-format
msgid "Error creating command socket: %s" msgid "Error creating command socket: %s"
msgstr "Erroray eatingcray ommandcay ocketsay: %s" msgstr "Erroray eatingcray ommandcay ocketsay: %s"
#: daemon/x52d_main.c:224 #: daemon/x52d_main.c:225
#, c-format #, c-format
msgid "Error getting command socket flags: %s" msgid "Error getting command socket flags: %s"
msgstr "Erroray ettinggay ommandcay ocketsay agsflay: %s" msgstr "Erroray ettinggay ommandcay ocketsay agsflay: %s"
#: daemon/x52d_main.c:228 #: daemon/x52d_main.c:229
#, c-format #, c-format
msgid "Error setting command socket flags: %s" msgid "Error setting command socket flags: %s"
msgstr "Erroray ettingsay ommandcay ocketsay agsflay: %s" msgstr "Erroray ettingsay ommandcay ocketsay agsflay: %s"
#: daemon/x52d_main.c:236 #: daemon/x52d_main.c:237
#, c-format #, c-format
msgid "Error binding to command socket: %s" msgid "Error binding to command socket: %s"
msgstr "Erroray indingbay otay ommandcay ocketsay: %s" msgstr "Erroray indingbay otay ommandcay ocketsay: %s"
#: daemon/x52d_main.c:241 #: daemon/x52d_main.c:242
#, c-format #, c-format
msgid "Error listening on command socket: %s" msgid "Error listening on command socket: %s"
msgstr "Erroray isteninglay onay ommandcay ocketsay: %s" msgstr "Erroray isteninglay onay ommandcay ocketsay: %s"
#: daemon/x52d_main.c:315 #: daemon/x52d_main.c:316
#, c-format #, c-format
msgid "Unable to parse configuration override '%s'\n" msgid "Unable to parse configuration override '%s'\n"
msgstr "Unableay otay arsepay onfigurationcay overrideay '%s'\n" msgstr "Unableay otay arsepay onfigurationcay overrideay '%s'\n"
#: daemon/x52d_main.c:343 #: daemon/x52d_main.c:344
#, c-format #, c-format
msgid "Foreground = %s" msgid "Foreground = %s"
msgstr "Oregroundfay = %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" msgid "true"
msgstr "uetray" msgstr "uetray"
#: daemon/x52d_main.c:343 daemon/x52d_main.c:344 #: daemon/x52d_main.c:344 daemon/x52d_main.c:345
msgid "false" msgid "false"
msgstr "alsefay" msgstr "alsefay"
#: daemon/x52d_main.c:344 #: daemon/x52d_main.c:345
#, c-format #, c-format
msgid "Quiet = %s" msgid "Quiet = %s"
msgstr "Uietqay = %s" msgstr "Uietqay = %s"
#: daemon/x52d_main.c:345 #: daemon/x52d_main.c:346
#, c-format #, c-format
msgid "Verbosity = %d" msgid "Verbosity = %d"
msgstr "Erbosityvay = %d" msgstr "Erbosityvay = %d"
#: daemon/x52d_main.c:346 #: daemon/x52d_main.c:347
#, c-format #, c-format
msgid "Log file = %s" msgid "Log file = %s"
msgstr "Oglay ilefay = %s" msgstr "Oglay ilefay = %s"
#: daemon/x52d_main.c:347 #: daemon/x52d_main.c:348
#, c-format #, c-format
msgid "Config file = %s" msgid "Config file = %s"
msgstr "Onfigcay ilefay = %s" msgstr "Onfigcay ilefay = %s"
#: daemon/x52d_main.c:348 #: daemon/x52d_main.c:349
#, c-format #, c-format
msgid "PID file = %s" msgid "PID file = %s"
msgstr "IDPay ilefay = %s" msgstr "IDPay ilefay = %s"
#: daemon/x52d_main.c:349 #: daemon/x52d_main.c:350
#, c-format #, c-format
msgid "Command socket = %s" msgid "Command socket = %s"
msgstr "Ommandcay ocketsay = %s" msgstr "Ommandcay ocketsay = %s"
@ -709,6 +709,37 @@ msgstr "Erroray %d initializingay ockclay eadthray: %s"
msgid "Shutting down X52 clock manager thread" msgid "Shutting down X52 clock manager thread"
msgstr "Uttingshay ownday X52 ockclay anagermay eadthray" 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 #: daemon/x52d_config.c:26
#, c-format #, c-format
msgid "Error %d setting configuration defaults: %s" msgid "Error %d setting configuration defaults: %s"