From 2a192a0d062ca504a3c0a29010f179ddbb19df62 Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Tue, 7 Sep 2021 17:17:27 +0100 Subject: [PATCH] Implement unix sockets in Input classes --- config.json.sample | 22 +++- inputlirc.cc | 33 ++++- inputlirc.h | 2 +- inputman.cc | 26 +--- remotelirc.cc | 297 --------------------------------------------- remotelirc.h | 60 --------- tcp.cc | 38 +++++- tcp.h | 6 + vdpc.cc | 2 +- 9 files changed, 91 insertions(+), 395 deletions(-) delete mode 100644 remotelirc.cc delete mode 100644 remotelirc.h diff --git a/config.json.sample b/config.json.sample index 72cbab1..6148411 100644 --- a/config.json.sample +++ b/config.json.sample @@ -44,17 +44,31 @@ { // input_lirc has no defaults - "lirc_ip": "192.0.2.0", - "lirc_port": 8765, + // Use these two options: + + "lirc_ip": "192.0.2.0", /* Numeric IPv4 or IPv6 */ + "lirc_port": 8765, /* except this, this has a default */ + + // Or this one: + + "lirc_socket": "/run/lirc/lircd", + + // + + // List all the Lirc remote names to listen to here: "remotes": [ "lirc-remote-name-1", "lirc-remote-name-2" ], + // Now create a section here for each Lirc remote. Map each Lirc button to vomp keys. + "lirc-remote-name-1": { + /* List all keys to be used by Vomp + On the left - the Lirc key name. On the right - the Vomp key name. See input.h (for now) */ + "KEY_POWER": "POWER", "KEY_MUTE": "MUTE" - /* etc. List all keys to be used by Vomp - On the left - the Lirc key name. On the right - the Vomp key name. See input.h (for now) */ + // etc. }, "lirc-remote-name-2": diff --git a/inputlirc.cc b/inputlirc.cc index af72f66..c112ece 100644 --- a/inputlirc.cc +++ b/inputlirc.cc @@ -100,14 +100,36 @@ void InputLIRC::shutdown() initted = false; } -bool InputLIRC::start(const std::string& ip, USHORT port) +bool InputLIRC::start() { - // FIXME implement unix domain socket connection + log->debug(TAG, "Start called"); + + + + std::string lircIP; + bool checkA = Config::getInstance()->getString("input_lirc", "lirc_ip", lircIP); + int lircPort = 8765; + bool checkB = Config::getInstance()->getInt("input_lirc", "lirc_port", lircPort); + std::string lircSocket; + bool checkC = Config::getInstance()->getString("input_lirc", "lirc_socket", lircSocket); + + bool tr{}; + + // Prefer socket + if (checkC) + { + LogNT::getInstance()->info(TAG, "Starting with unix socket: {}", lircSocket); + tr = tcp.connectSocket(lircSocket); + } + else if (checkA) // If no checkC, must be checkA + { + LogNT::getInstance()->info(TAG, "Starting with IP: {} {}", lircIP, lircPort); + tr = tcp.connect(lircIP, lircPort); + } - bool tr = tcp.connect(ip, port); // NCONFIG if (!tr) { - log->debug(TAG, "InputLIRC TCP connect failed"); + log->debug(TAG, "TCP connect failed"); return false; } @@ -120,7 +142,7 @@ bool InputLIRC::start(const std::string& ip, USHORT port) }); threadStartProtect.unlock(); - log->debug(TAG, "InputLIRC command client started"); + log->debug(TAG, "Started"); return true; } @@ -182,6 +204,7 @@ void InputLIRC::listenLoop() continue; } + log->debug(TAG, "Submitting vomp key: '{}'", button); if (repeatCount == 0) sendInputKey(button); } } diff --git a/inputlirc.h b/inputlirc.h index 39be337..7b6e224 100644 --- a/inputlirc.h +++ b/inputlirc.h @@ -38,7 +38,7 @@ class InputLIRC : public Input void shutdown(); using Input::start; // Bring all start()s from base class so our start doesn't generate compile warnings - bool start(const std::string& ip, USHORT port); + bool start(); void stop(); void InitHWCListwithDefaults() {}; diff --git a/inputman.cc b/inputman.cc index 6e52aac..c7088f0 100644 --- a/inputman.cc +++ b/inputman.cc @@ -135,31 +135,7 @@ bool InputMan::start() if (inputUDP && inputUDP->start()) oneOK = true; - if (inputLirc) - { - std::string lircIP; - bool checkA = Config::getInstance()->getString("input", "lirc_ip", lircIP); - int lircPort = 8765; - bool checkB = Config::getInstance()->getInt("input", "lirc_port", lircPort); - - if (!checkA || !checkB) - { - delete inputLirc; - inputLirc = NULL; - } - else - { - if (inputLirc->start(lircIP, lircPort)) - { - oneOK = true; - } - else - { - delete inputLirc; - inputLirc = NULL; - } - } - } + if (inputLirc && inputLirc->start()) oneOK = true; if (!oneOK) LogNT::getInstance()->crit(TAG, "InputMan could not start any input module"); diff --git a/remotelirc.cc b/remotelirc.cc deleted file mode 100644 index 60268f3..0000000 --- a/remotelirc.cc +++ /dev/null @@ -1,297 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon 2009 Marten Richter - - This file is part of VOMP. - - VOMP 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 2 of the License, or - (at your option) any later version. - - VOMP 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 VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ -#include - -#include "remotelirc.h" -#include "i18n.h" - -#include "oldlog.h" - -#define LIRC_BUFFER_SIZE 128 - - -RemoteLirc::RemoteLirc() -{ - if (instance) return; - initted = 0; - tv.tv_sec = 0; - tv.tv_usec = 0; - device = -1; -} - -RemoteLirc::~RemoteLirc() -{ -} - -int RemoteLirc::init(char* devName) -{ - if (initted) return 0; - initted = 1; - - address.sun_family = AF_UNIX; - - strcpy(address.sun_path, devName); - if (!sockConnect()) return 0; -/* - device = open(devName, O_RDONLY); - if (device < 0) - { - initted = 0; - return 0; - } -*/ - return 1; -} - -int RemoteLirc::shutdown() -{ - if (!initted) return 0; - initted = 0; - close(device); - device = 0; - return 1; -} - -int RemoteLirc::sockConnect() -{ - if ((device = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0) { - if (connect(device, (struct sockaddr *)&address, sizeof(address)) >= 0) - return 1; - Log::getInstance()->log("Remote", Log::INFO, "Connecting lircd failed %s", address.sun_path); - close(device); - device = -1; - } - else - Log::getInstance()->log("Remote", Log::INFO, "Creating socket failed"); - - Log::getInstance()->log("Remote", Log::DEBUG, "Creating socket successfull"); - - return 0; -} - -int RemoteLirc::getDevice() -{ - if (!initted) return 0; - return device; -} - -UCHAR RemoteLirc::getButtonPress(int waitType) -{ - /* how = 0 - block - how = 1 - start new wait - how = 2 - continue wait - how = 3 - no wait - */ - - unsigned long input; - struct timeval* passToSelect = NULL; - char buffer[LIRC_BUFFER_SIZE]; - int retval; - fd_set readfds; - - if (waitType == 0) - { - passToSelect = NULL; - } - else if (waitType == 1) - { - tv.tv_sec = 1; - tv.tv_usec = 000000; - passToSelect = &tv; - } - else if (waitType == 2) - { - if ((tv.tv_sec == 0) && (tv.tv_usec == 0)) // protection in case timer = 0 - { - tv.tv_sec = 1; - tv.tv_usec = 000000; - } - passToSelect = &tv; - } - else if (waitType == 3) - { - tv.tv_sec = 0; - tv.tv_usec = 0; - passToSelect = &tv; - } - FD_ZERO(&readfds); - FD_SET(device, &readfds); - - retval = select(device + 1, &readfds, NULL, NULL, &tv); - // 0 = nothing happened - // 1 = data arrived (actually num of descriptors that changed) - // other value = signal or error - if (retval == 0) return NA_NONE; - if (retval == -1) return NA_SIGNAL; - - int count = read(device, &buffer, sizeof(LIRC_BUFFER_SIZE)); - if (count > 0) - { - int input=NA_UNKNOWN; - if (sscanf(buffer, "%d", &input) != 1) { - Log::getInstance()->log("Remote", Log::DEBUG, "ERROR: unparseable lirc command: %s", buffer); - return NA_UNKNOWN; - } - - Log::getInstance()->log("Remote", Log::DEBUG, "Button %x", input); - - return (UCHAR) TranslateHWC(input); - } - return NA_UNKNOWN; -} - -void RemoteLirc::clearBuffer() -{ -// while(getButtonPress(3) != NA_NONE); -} - -UCHAR RemoteLirc::TranslateHWCFixed(ULLONG code) -{ - switch (code) - { - case 0xa9: - return DOWN; - case 0xa8: - return UP; - case 0xaa: - return LEFT; - case 0xab: - return RIGHT; - case 0x09: - return MENU; - case 0x8d: - return BACK; - case 0x0d: - return OK; - case 0xd2: - return POWER; - default: - return NA_UNKNOWN; - }; -} - - -void RemoteLirc::InitHWCListwithDefaults() -{ - translist[0x9e] = VOLUMEUP; - translist[0x9f] = VOLUMEDOWN; - translist[0x94] = CHANNELUP; - translist[0x90] = CHANNELDOWN; - - // Common buttons - translist[0xf1] = ZERO; - translist[0xf2] = ONE; - translist[0xf3] = TWO; - translist[0xf4] = THREE; - translist[0xf5] = FOUR; - translist[0xf6] = FIVE; - translist[0xf7] = SIX; - translist[0xf8] = SEVEN; - translist[0xf9] = EIGHT; - translist[0xfa] = NINE; - translist[0xd2] = POWER; - translist[0x91] = GO; - translist[0xde] = RED; - translist[0xdf] = GREEN; - translist[0xe0] = YELLOW; - translist[0xe2] = BLUE; - - translist[0xe1] = MUTE; - translist[0xd5] = REVERSE; - translist[0xd6] = FORWARD; - translist[0x1b] = STOP; - translist[0xea] = PAUSE; - translist[0xe9] = PLAY; - translist[0xdb] = SKIPBACK; - translist[0xdc] = SKIPFORWARD; - - // Old remote only - translist[0xda] = FULL; - - -} - - -char* RemoteLirc::HCWDesc(ULLONG hcw) -{ - - char *ret=NULL; - - ret=new char[20]; - - switch(hcw) - { - case 0x01: strncpy(ret,tr("Suspend") ,20);break; - case 0x09: strncpy(ret,tr("Menu") ,20);break; - case 0x0d: strncpy(ret,tr("Enter") ,20);break; - case 0x1b: strncpy(ret,tr("Stop") ,20);break; - case 0x8A: strncpy(ret,tr("TV mode") ,20);break; - case 0x8c: strncpy(ret,tr("Setup") ,20);break; - case 0x8D: strncpy(ret,tr("Return") ,20);break; - case 0x90: strncpy(ret,tr("Repeat") ,20);break; - case 0x91: strncpy(ret,tr("Time Seek"),20);break; - case 0x94: strncpy(ret,tr("Title") ,20);break; - case 0x95: strncpy(ret,tr("Info") ,20);break; - case 0x9e: strncpy(ret,tr("Volume up") ,20);break; - case 0x9f: strncpy(ret,tr("Volume down") ,20);break; - case 0xa8: strncpy(ret,tr("up") ,20);break; - case 0xaa: strncpy(ret,tr("Left") ,20);break; - case 0xab: strncpy(ret,tr("Right") ,20);break; - case 0xa9: strncpy(ret,tr("Down") ,20);break; - case 0xd0: strncpy(ret,tr("Home") ,20);break; - case 0xd2: strncpy(ret,tr("Stand by") ,20);break; - case 0xd5: strncpy(ret,tr("Backward") ,20);break; - case 0xd6: strncpy(ret,tr("Forward") ,20);break; - case 0xd8: strncpy(ret,tr("Audio") ,20);break; - case 0xd9: strncpy(ret,tr("Slow") ,20);break; - case 0xda: strncpy(ret,tr("Zoom") ,20);break; - case 0xdb: strncpy(ret,tr("Previous") ,20);break; - case 0xde: strncpy(ret,tr("Red") ,20);break; - case 0xdc: strncpy(ret,tr("Next") ,20);break; - case 0xdf: strncpy(ret,tr("Green") ,20);break; - case 0xe0: strncpy(ret,tr("Yellow") ,20);break; - case 0xe1: strncpy(ret,tr("Mute") ,20);break; - case 0xe2: strncpy(ret,tr("Blue") ,20);break; - case 0xe9: strncpy(ret,tr("Play") ,20);break; - case 0xea: strncpy(ret,tr("Pause") ,20);break; - case 0xeb: strncpy(ret,tr("Subtitle") ,20);break; - case 0xec: strncpy(ret,tr("Angle") ,20);break; - case 0xef: strncpy(ret,tr("Eject") ,20);break; - case 0xf1: strncpy(ret,tr("0") ,20);break; - case 0xf2: strncpy(ret,tr("1") ,20);break; - case 0xf3: strncpy(ret,tr("2") ,20);break; - case 0xf4: strncpy(ret,tr("3") ,20);break; - case 0xf5: strncpy(ret,tr("4") ,20);break; - case 0xf6: strncpy(ret,tr("5") ,20);break; - case 0xf7: strncpy(ret,tr("6") ,20);break; - case 0xf8: strncpy(ret,tr("7") ,20);break; - case 0xf9: strncpy(ret,tr("8") ,20);break; - case 0xfA: strncpy(ret,tr("9") ,20);break; - case 0xFC: strncpy(ret,tr("Caps") ,20);break; - case 0xFD: strncpy(ret,tr("File mode") ,20);break; - - - default:{ - ULONG ri=(ULONG)hcw; - sprintf(ret,"R: %X",ri); - }break; - }; - return ret; -} diff --git a/remotelirc.h b/remotelirc.h deleted file mode 100644 index 44f4fdb..0000000 --- a/remotelirc.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon 2009 Marten Richter - Inspired from code from vdr by Klaus Schmidinger - - This file is part of VOMP. - - VOMP 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 2 of the License, or - (at your option) any later version. - - VOMP 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 VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef REMOTELIRC_H -#define REMOTELIRC_H - -#include -#include -#include -#include - -#include "input.h" -#include "defines.h" - -class RemoteLirc : public Remote -{ - public: - RemoteLirc(); - ~RemoteLirc(); - - int init(char *devName); - int shutdown(); - int getDevice(); - UCHAR getButtonPress(int how); - void clearBuffer(); - int sockConnect(); - - virtual void InitHWCListwithDefaults(); - virtual char* HCWDesc(ULLONG hcw); - - private: - - virtual UCHAR TranslateHWCFixed(ULLONG code); - - int initted; - int device; - - struct sockaddr_un address; - struct timeval tv; -}; - -#endif diff --git a/tcp.cc b/tcp.cc index a002c47..38d5700 100644 --- a/tcp.cc +++ b/tcp.cc @@ -31,6 +31,7 @@ #include // for getMAC #include // for getMAC #include // getifaddrs + #include // uds #endif #include // socket connect getaddrinfo @@ -86,6 +87,34 @@ bool TCP::init() return true; } +#ifndef WIN32 +bool TCP::connectSocket(const std::string& socketFile) +{ + if (connected) return false; + + int pathLength = strlen(socketFile.c_str()); // Specifically use strlen rather than std::string length stuff + if (pathLength > 107) { logger->crit(TAG, "socket name too long"); return false; } + + sockfd = socket(AF_UNIX, SOCK_STREAM, 0); + if (sockfd == -1) { logger->crit(TAG, "socket error"); return false; } + + fcntl(sockfd, F_SETFL, O_NONBLOCK); + + struct sockaddr_un uds; + uds.sun_family = AF_UNIX; + strcpy(uds.sun_path, socketFile.c_str()); + int connectResult = ::connect(sockfd, (struct sockaddr *)&uds, pathLength + sizeof(uds.sun_family)); + + if (connectResult == 0) // success + { + connected = true; + return true; + } + + return waitForConnect(connectResult); +} +#endif + bool TCP::connect(const std::string& ip, USHORT port) { if (connected) return false; @@ -121,13 +150,19 @@ bool TCP::connect(const std::string& ip, USHORT port) // There should only be one aip result.. int connectResult = ::connect(sockfd, aip->ai_addr, aip->ai_addrlen); + freeaddrinfo(aip); + if (connectResult == 0) // success { - freeaddrinfo(aip); connected = true; return true; } + return waitForConnect(connectResult); +} + +bool TCP::waitForConnect(int connectResult) +{ #ifdef WIN32 if ((connectResult != SOCKET_ERROR) || (WSAGetLastError() != WSAEWOULDBLOCK)) #else @@ -176,7 +211,6 @@ bool TCP::connect(const std::string& ip, USHORT port) if ((selectResult == 1) || FD_ISSET(sockfd, &writefds)) { - freeaddrinfo(aip); logger->info(TAG, "Connected"); connected = true; return true; diff --git a/tcp.h b/tcp.h index 65931a5..680e9db 100644 --- a/tcp.h +++ b/tcp.h @@ -44,6 +44,10 @@ class TCP void abortCall(); // causes a read/connect call to immediately abort bool connect(const std::string& ip, USHORT port); +#ifndef WIN32 + bool connectSocket(const std::string& socketFile); +#endif + bool read(void* dest, ULONG numBytes, int timeoutSec = 2); // Set timeoutSec to 0 for no timeout std::stringstream readString(bool* result, int timeoutSec = 2); bool write(void* src, ULONG numBytes); @@ -62,6 +66,8 @@ class TCP int recStringBufStart{}; int recStringBufUsed{}; + bool waitForConnect(int connectResult); + #ifdef WIN32 SOCKET abortSocket; #else diff --git a/vdpc.cc b/vdpc.cc index 3d60d78..573b5ac 100644 --- a/vdpc.cc +++ b/vdpc.cc @@ -242,7 +242,7 @@ void VDPC::VDPC4::threadMethod() } } - logger->debug("VDPC4", "loop stopnow = %i", stopNow); + logger->debug("VDPC4", "loop stopnow = {}", stopNow); } } -- 2.39.5