From c7afc699356eb6f3720cd253dac1e5f92f0cf693 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Fri, 19 Apr 2024 10:20:54 -0700 Subject: [PATCH] new base classes and back to UnixDgrmSocket --- KRBase.h => Base.h | 33 ++++++-- KRBase.cpp | 63 -------------- Makefile | 14 +-- QnetConfigure.cpp | 8 +- QnetConfigure.h | 4 +- QnetDVAP.cpp | 96 ++++++++++++++------- QnetDVAP.h | 18 ++-- QnetDVRPTR.cpp | 182 +++++++++++++++++++++++---------------- QnetDVRPTR.h | 18 ++-- QnetGateway.cpp | 115 +++++++++++++++---------- QnetGateway.h | 20 ++--- QnetITAP.cpp | 112 +++++++++++++++--------- QnetITAP.h | 22 ++--- QnetLink.cpp | 73 ++++++++++------ QnetLink.h | 18 ++-- QnetModem.cpp | 108 ++++++++++++++--------- QnetModem.h | 22 ++--- QnetRelay.cpp | 106 ++++++++++++++--------- QnetRelay.h | 22 ++--- UnixPacketSock.cpp | 207 --------------------------------------------- UnixPacketSock.h | 58 ------------- defaults | 5 -- 22 files changed, 617 insertions(+), 707 deletions(-) rename KRBase.h => Base.h (62%) delete mode 100644 KRBase.cpp delete mode 100644 UnixPacketSock.cpp delete mode 100644 UnixPacketSock.h diff --git a/KRBase.h b/Base.h similarity index 62% rename from KRBase.h rename to Base.h index 2b1335b..30196f3 100644 --- a/KRBase.h +++ b/Base.h @@ -20,17 +20,34 @@ // base class for all modems -#include +#include #include -class CKRBase +class CBase { public: - CKRBase(); - bool IsRunning(); - void SetState(bool state); + CBase() { keep_running = true; } + virtual ~CBase() {} + virtual bool Initialize(const std::string &path) = 0; + virtual void Run() = 0; + virtual void Close() = 0; + void Stop() { keep_running = false; } protected: - static std::atomic keep_running; - static void SigHandler(int sig); - void AddFDSet(int &max, int newfd, fd_set *set); + std::atomic keep_running; + void AddFDSet(int &max, int newfd, fd_set *set) + { + if (newfd > max) + max = newfd; + FD_SET(newfd, set); + } +}; + +class CModem : public CBase +{ +public: + CModem(int index = -1) : CBase(), m_index(index) {} + virtual ~CModem() {} + +protected: + int m_index; }; diff --git a/KRBase.cpp b/KRBase.cpp deleted file mode 100644 index 76786fd..0000000 --- a/KRBase.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2020 by Thomas Early N7TAE - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include - -#include "KRBase.h" - -std::atomic CKRBase::keep_running(true); - -CKRBase::CKRBase() -{ - std::signal(SIGINT, CKRBase::SigHandler); - std::signal(SIGHUP, CKRBase::SigHandler); - std::signal(SIGTERM, CKRBase::SigHandler); -} - -bool CKRBase::IsRunning() -{ - return keep_running; -} - -void CKRBase::SetState(bool state) -{ - keep_running = state; -} - -void CKRBase::SigHandler(int sig) -{ - switch (sig) - { - case SIGINT: - case SIGHUP: - case SIGTERM: - keep_running = false; - break; - default: - std::cerr << "caught an unexpected signal=" << sig << std::endl; - break; - } -} - -void CKRBase::AddFDSet(int &max, int newfd, fd_set *set) -{ - if (newfd > max) - max = newfd; - FD_SET(newfd, set); -} diff --git a/Makefile b/Makefile index 34c5ae6..0da5bd5 100644 --- a/Makefile +++ b/Makefile @@ -52,25 +52,25 @@ dvrptr : qndvrptr itap : qnitap modem : qnmodem -qngateway : QnetGateway.o KRBase.o aprs.o UnixDgramSocket.o UnixPacketSock.o TCPReaderWriterClient.o QnetConfigure.o QnetDB.o CacheManager.o DStarDecode.o Location.o $(IRCOBJS) +qngateway : QnetGateway.o aprs.o UnixDgramSocket.o TCPReaderWriterClient.o QnetConfigure.o QnetDB.o CacheManager.o DStarDecode.o Location.o $(IRCOBJS) g++ -o $@ $^ $(LDFLAGS) -l sqlite3 -pthread -qnlink : QnetLink.o KRBase.o DPlusAuthenticator.o TCPReaderWriterClient.o UnixPacketSock.o UDPSocket.o QnetConfigure.o QnetDB.o +qnlink : QnetLink.o DPlusAuthenticator.o TCPReaderWriterClient.o UnixDgramSocket.o UDPSocket.o QnetConfigure.o QnetDB.o g++ -o $@ $^ $(LDFLAGS) -l sqlite3 -pthread -qnrelay : QnetRelay.o KRBase.o UnixPacketSock.o QnetConfigure.o +qnrelay : QnetRelay.o UnixDgramSocket.o QnetConfigure.o g++ -o $@ $^ $(LDFLAGS) -qnitap : QnetITAP.o KRBase.o UnixPacketSock.o QnetConfigure.o +qnitap : QnetITAP.o UnixDgramSocket.o QnetConfigure.o g++ -o $@ $^ $(LDFLAGS) -qnmodem : QnetModem.o KRBase.o UnixPacketSock.o QnetConfigure.o +qnmodem : QnetModem.o UnixDgramSocket.o QnetConfigure.o g++ -o $@ $^ $(LDFLAGS) -qndvap : QnetDVAP.o KRBase.o DVAPDongle.o UnixPacketSock.o QnetConfigure.o DStarDecode.o +qndvap : QnetDVAP.o DVAPDongle.o UnixDgramSocket.o QnetConfigure.o DStarDecode.o g++ -o $@ $^ $(LDFLAGS) -pthread -qndvrptr : QnetDVRPTR.o KRBase.o UnixPacketSock.o QnetConfigure.o DStarDecode.o +qndvrptr : QnetDVRPTR.o UnixDgramSocket.o QnetConfigure.o DStarDecode.o g++ -o $@ $^ $(LDFLAGS) qnremote : QnetRemote.o UnixDgramSocket.o QnetConfigure.o diff --git a/QnetConfigure.cpp b/QnetConfigure.cpp index 7c7afad..3be2fc3 100644 --- a/QnetConfigure.cpp +++ b/QnetConfigure.cpp @@ -40,9 +40,9 @@ char *CQnetConfigure::Trim(char *s) return s; } -bool CQnetConfigure::ReadConfigFile(const char *configfile, std::map &amap) +bool CQnetConfigure::ReadConfigFile(const std::string &configfile, std::map &amap) { - FILE *fp = fopen(configfile, "r"); + FILE *fp = fopen(configfile.c_str(), "r"); if (fp) { char line[2048]; @@ -69,11 +69,11 @@ bool CQnetConfigure::ReadConfigFile(const char *configfile, std::map cfg; char *Trim(char *s); - bool ReadConfigFile(const char *file, std::map &amap); + bool ReadConfigFile(const std::string &file, std::map &amap); bool GetDefaultBool (const std::string &key, const std::string &mod, bool &dval); bool GetDefaultDouble(const std::string &key, const std::string &mod, double &dval); bool GetDefaultInt (const std::string &key, const std::string &mod, int &dval); diff --git a/QnetDVAP.cpp b/QnetDVAP.cpp index 8db53a7..6ed7e3d 100644 --- a/QnetDVAP.cpp +++ b/QnetDVAP.cpp @@ -43,13 +43,12 @@ #include "DVAPDongle.h" #include "QnetTypeDefs.h" #include "Random.h" -#include "UnixPacketSock.h" #include "QnetConfigure.h" #include "Timer.h" #include "DStarDecode.h" #include "QnetDVAP.h" -#define DVAP_VERSION "QnetDVAP-40411" +#define DVAP_VERSION "QnetDVAP-40417" #define CALL_SIZE 8 #define IP_SIZE 15 @@ -94,18 +93,18 @@ void CQnetDVAP::calcPFCS(unsigned char *packet, unsigned char *pfcs) } /* process configuration file */ -bool CQnetDVAP::ReadConfig(const char *cfgFile) +bool CQnetDVAP::ReadConfig(const std::string &cfgFile) { CQnetConfigure cfg; - printf("Reading file %s\n", cfgFile); + printf("Reading file %s\n", cfgFile.c_str()); if (cfg.Initialize(cfgFile)) return true; const std::string estr; // an empty string std::string type; std::string dvap_path("module_"); - if (0 > assigned_module) + if (0 > m_index) { // we need to find the lone dvap module for (int i=0; i<3; i++) @@ -118,11 +117,11 @@ bool CQnetDVAP::ReadConfig(const char *cfgFile) if (type.compare("dvap")) continue; // this ain't it! dvap_path.assign(test); - assigned_module = i; + m_index = i; break; } } - if (0 > assigned_module) + if (0 > m_index) { fprintf(stderr, "Error: no 'dvap' module found\n!"); return true; @@ -131,7 +130,7 @@ bool CQnetDVAP::ReadConfig(const char *cfgFile) else { // make sure dvap module is defined - dvap_path.append(1, 'a' + assigned_module); + dvap_path.append(1, 'a' + m_index); if (cfg.KeyExists(dvap_path)) { cfg.GetValue(dvap_path, estr, type, 1, 16); @@ -143,12 +142,11 @@ bool CQnetDVAP::ReadConfig(const char *cfgFile) } else { - fprintf(stderr, "Module '%c' is not defined.\n", 'a'+assigned_module); + fprintf(stderr, "Module '%c' is not defined.\n", 'a'+m_index); return true; } } - RPTR_MOD = 'A' + assigned_module; - cfg.GetValue("gateway_tomodem"+std::string(1, 'a'+assigned_module), estr, togate, 1, FILENAME_MAX); + RPTR_MOD = 'A' + m_index; if (cfg.KeyExists(dvap_path+"_callsign")) { if (cfg.GetValue(dvap_path+"_callsign", type, RPTR, 3, 6)) @@ -233,13 +231,13 @@ void CQnetDVAP::ReadFromGateway() tv.tv_sec = 0; tv.tv_usec = MODULE_PACKET_WAIT; FD_ZERO (&readfd); - int fd = ToGate.GetFD(); + int fd = FromGate.GetFD(); FD_SET (fd, &readfd); select(fd + 1, &readfd, NULL, NULL, &tv); if (FD_ISSET(fd, &readfd)) { - len = ToGate.Read(dsvt.title, 56); + len = FromGate.Read(dsvt.title, 56); if (len == 56) { if (busy20000) @@ -494,7 +492,6 @@ void CQnetDVAP::ReadFromGateway() break; } } - return; } void CQnetDVAP::RptrAckThread(SDVAP_ACK_ARG *parg) @@ -872,13 +869,11 @@ void CQnetDVAP::ReadDVAPThread() return; } -bool CQnetDVAP::Init(const char *file, const int amod) +bool CQnetDVAP::Initialize(const std::string &file) { - assigned_module = amod; - if (ReadConfig(file)) { - printf("Failed to process config file %s\n", file); + printf("Failed to process config file %s\n", file.c_str()); return true; } @@ -910,12 +905,20 @@ bool CQnetDVAP::Init(const char *file, const int amod) if (!dongle.Initialize(MODULE_DEVICE.c_str(), MODULE_SERIAL_NUMBER.c_str(), MODULE_FREQUENCY, MODULE_OFFSET, MODULE_POWER, MODULE_SQUELCH)) return true; - if (ToGate.Open(togate.c_str(), this)) + std::string name("Gate2Modem"); + name.append(1, RPTR_MOD); + + printf("Opening %s\n", name.c_str()); + if (FromGate.Open(name.c_str())) { dongle.Stop(); close(serfd); return true; } + name.assign("Modem"); + name.append(1, RPTR_MOD); + name.append("2Gate"); + ToGate.SetUp(name.c_str()); printf("DVAP opened and initialized!\n"); return false; } @@ -923,10 +926,9 @@ bool CQnetDVAP::Init(const char *file, const int amod) void CQnetDVAP::Run() { CTimer ackpoint; - std::future readthread; try { - readthread = std::async(std::launch::async, &CQnetDVAP::ReadDVAPThread, this); + m_readThread = std::async(std::launch::async, &CQnetDVAP::ReadDVAPThread, this); } catch (const std::exception &e) { @@ -972,16 +974,35 @@ void CQnetDVAP::Run() } } } +} - readthread.get(); - ToGate.Close(); +void CQnetDVAP::Close() +{ + m_readThread.get(); + FromGate.Close(); printf("QnetDVAP exiting\n"); return; } -int main(int argc, char *argv[]) +std::unique_ptr pdvap; + +static void HandleSignal(int sig) +{ + switch (sig) + { + case SIGINT: + case SIGHUP: + case SIGTERM: + pdvap->Stop(); + break; + default: + fprintf(stderr, "Caught an unknown signal: %d\n", sig); + break; + } +} + +int main(int argc, char **argv) { - setvbuf(stdout, NULL, _IOLBF, 0); printf("%s\n", DVAP_VERSION); if (argc != 2) @@ -992,7 +1013,7 @@ int main(int argc, char *argv[]) if ('-' == argv[1][0]) { - printf("%s Copyright (C) 2018-2020 by Thomas A. Early N7TAE\n", DVAP_VERSION); + printf("%s Copyright (C) 2018-2024 by Thomas A. Early N7TAE\n", DVAP_VERSION); printf("QnetDVAP comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"); printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\nS"); return EXIT_SUCCESS; @@ -1026,9 +1047,26 @@ int main(int argc, char *argv[]) return 1; } - CQnetDVAP dvap; - if (dvap.Init(argv[1], mod)) + pdvap = std::unique_ptr(new CQnetDVAP(mod)); + + if (! pdvap) + { + std::fprintf(stderr, "Could not make a DVAP!\n"); return EXIT_FAILURE; - dvap.Run(); + } + + std::signal(SIGINT, HandleSignal); + std::signal(SIGHUP, HandleSignal); + std::signal(SIGTERM, HandleSignal); + + if (pdvap->Initialize(argv[1])) + return EXIT_FAILURE; + + pdvap->Run(); + + pdvap->Close(); + + pdvap.reset(); + return EXIT_SUCCESS; } diff --git a/QnetDVAP.h b/QnetDVAP.h index 4002430..ddf58da 100644 --- a/QnetDVAP.h +++ b/QnetDVAP.h @@ -21,7 +21,8 @@ #include #include -#include "KRBase.h" +#include "UnixDgramSocket.h" +#include "Base.h" using SDVAP_ACK_ARG = struct davp_ack_arg_tag { @@ -29,14 +30,17 @@ using SDVAP_ACK_ARG = struct davp_ack_arg_tag float ber; }; -class CQnetDVAP : public CKRBase +class CQnetDVAP : public CModem { public: - bool Init(const char *file, const int amod); + CQnetDVAP(int index) : CModem(index) {} + ~CQnetDVAP() {} + bool Initialize(const std::string &path); void Run(); + void Close(); private: - bool ReadConfig(const char *file); + bool ReadConfig(const std::string &path); void ReadFromGateway(); void calcPFCS(unsigned char *packet, unsigned char *pfcs); void ReadDVAPThread(); @@ -50,11 +54,11 @@ private: // data std::queue> m_fqueue; - int assigned_module; + std::future m_readThread; // unix sockets - std::string togate; - CUnixPacketClient ToGate; + CUnixDgramWriter ToGate; + CUnixDgramReader FromGate; /* Default configuration data */ std::string RPTR; std::string OWNER; diff --git a/QnetDVRPTR.cpp b/QnetDVRPTR.cpp index b9ab5f2..d766137 100644 --- a/QnetDVRPTR.cpp +++ b/QnetDVRPTR.cpp @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include "Random.h" #include "QnetConfigure.h" @@ -1248,18 +1250,18 @@ void CQnetDVRPTR::calcPFCS(unsigned char *packet) //Netzwerk CRC } /* process configuration file */ -bool CQnetDVRPTR::ReadConfig(const char *cfgFile) +bool CQnetDVRPTR::ReadConfig(const std::string &cfgFile) { CQnetConfigure cfg; - printf("Reading file %s\n", cfgFile); + printf("Reading file %s\n", cfgFile.c_str()); if (cfg.Initialize(cfgFile)) return true; const std::string estr; // an empty string std::string type; std::string path("module_"); - if (0 > assigned_module) + if (0 > m_index) { // we need to find the lone dvrptr module for (int i=0; i<3; i++) @@ -1272,11 +1274,11 @@ bool CQnetDVRPTR::ReadConfig(const char *cfgFile) if (type.compare("dvrptr")) continue; // this ain't it! path.assign(test); - assigned_module = i; + m_index = i; break; } } - if (0 > assigned_module) + if (0 > m_index) { fprintf(stderr, "Error: no 'dvrptr' module found\n!"); return true; @@ -1285,7 +1287,7 @@ bool CQnetDVRPTR::ReadConfig(const char *cfgFile) else { // make sure dvrptr module is defined - path.append(1, 'a' + assigned_module); + path.append(1, 'a' + m_index); if (cfg.KeyExists(path)) { cfg.GetValue(path, estr, type, 1, 16); @@ -1297,12 +1299,11 @@ bool CQnetDVRPTR::ReadConfig(const char *cfgFile) } else { - fprintf(stderr, "Module '%c' is not defined.\n", 'a'+assigned_module); + fprintf(stderr, "Module '%c' is not defined.\n", 'a'+m_index); return true; } } - DVRPTR_MOD = 'A' + assigned_module; - cfg.GetValue(std::string("gateway_tomodem")+std::string(1, 'a'+assigned_module), estr, togate, 1, FILENAME_MAX); + DVRPTR_MOD = 'A' + m_index; std::string call; if (cfg.GetValue("ircddb_login", type, call, 3, 6)) @@ -1636,7 +1637,7 @@ void CQnetDVRPTR::readFrom20000() unsigned char ctrl_in = 0x80; bool written_to_q = false; - int fd = ToGate.GetFD(); + int fd = FromGate.GetFD(); while (keep_running) { written_to_q = false; @@ -1648,7 +1649,7 @@ void CQnetDVRPTR::readFrom20000() select(fd + 1, &readfd, NULL, NULL, &tv); if (FD_ISSET(fd, &readfd)) { - len = ToGate.Read(recv_buf.title, 56); + len = FromGate.Read(recv_buf.title, 56); if (len == 56) { if (busy20000) @@ -1980,67 +1981,11 @@ bool CQnetDVRPTR::check_serial() return match; } -int main(int argc, const char **argv) +bool CQnetDVRPTR::Initialize(const std::string &file) { - setvbuf(stdout, NULL, _IOLBF, 0); - printf("dvrptr VERSION %s\n", DVRPTR_VERSION); - - if (argc != 2) - { - fprintf(stderr, "Usage: %s \n", argv[0]); - return 1; - } - - if ('-' == argv[1][0]) - { - printf("%s Copyright (C) 2018-2019 by Thomas A. Early N7TAE\n", DVRPTR_VERSION); - printf("QnetDVRPTR comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"); - printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\n"); - return 0; - } - - const char *qn = strstr(argv[0], "qndvrptr"); - if (NULL == qn) - { - fprintf(stderr, "Error finding 'qndvrptr' in %s!\n", argv[0]); - return 1; - } - qn += 8; - - int mod; - switch (*qn) - { - case 0: - mod = -1; - break; - case 'a': - mod = 0; - break; - case 'b': - mod = 1; - break; - case 'c': - mod = 2; - break; - default: - fprintf(stderr, "ERROR: '%s' is not a valid module\nassigned module must be a, b or c\n", argv[1]); - return 1; - } - - CQnetDVRPTR dvrptr; - if (dvrptr.Init(argv[1], mod)) - return EXIT_FAILURE; - dvrptr.Run(); - - return EXIT_SUCCESS; -} - -bool CQnetDVRPTR::Init(const char *file, int mod) -{ - assigned_module = mod; if (ReadConfig(file)) { - fprintf(stderr, "Failed to process config file %s\n", file); + fprintf(stderr, "Failed to process config file %s\n", file.c_str()); return true; } @@ -2074,8 +2019,15 @@ bool CQnetDVRPTR::Init(const char *file, int mod) strcpy(DVCALL_and_MOD, DVCALL); DVCALL_and_MOD[7] = DVRPTR_MOD; - if (ToGate.Open(togate.c_str(), this)) + std::string name("Gate2Modem"); + name.append(1, DVRPTR_MOD); + printf("Opening %s\n", name.c_str()); + if (FromGate.Open(name.c_str())) return true; + name.assign("Modem"); + name.append(1, DVRPTR_MOD); + name.append("2Gate"); + ToGate.SetUp(name.c_str()); if (RX_Inverse == true) { @@ -2603,9 +2555,95 @@ void CQnetDVRPTR::Run() } } } +} - ToGate.Close(); +void CQnetDVRPTR::Close() +{ + FromGate.Close(); printf("dvrptr exiting...\n"); +} - return; +std::unique_ptr pdvrptr; + +void SignalHandler(int sig) +{ + switch (sig) + { + case SIGINT: + case SIGHUP: + case SIGTERM: + if (pdvrptr) + pdvrptr->Stop(); + break; + default: + fprintf(stderr, "Caught an unexpected signal: %d\n", sig); + } +} + +int main(int argc, const char **argv) +{ + std::signal(SIGINT, SignalHandler); + std::signal(SIGHUP, SignalHandler); + std::signal(SIGTERM, SignalHandler); + printf("dvrptr VERSION %s\n", DVRPTR_VERSION); + + if (argc != 2) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + + if ('-' == argv[1][0]) + { + printf("%s Copyright (C) 2018-2019 by Thomas A. Early N7TAE\n", DVRPTR_VERSION); + printf("QnetDVRPTR comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"); + printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\n"); + return 0; + } + + const char *qn = strstr(argv[0], "qndvrptr"); + if (NULL == qn) + { + fprintf(stderr, "Error finding 'qndvrptr' in %s!\n", argv[0]); + return 1; + } + qn += 8; + + int mod; + switch (*qn) + { + case 0: + mod = -1; + break; + case 'a': + mod = 0; + break; + case 'b': + mod = 1; + break; + case 'c': + mod = 2; + break; + default: + fprintf(stderr, "ERROR: '%s' is not a valid module\nassigned module must be a, b or c\n", argv[1]); + return 1; + } + + pdvrptr = std::unique_ptr(new CQnetDVRPTR(mod)); + if (!pdvrptr) + { + fprintf(stderr, "Could not make a DVRPTR at %d\n", mod); + return EXIT_FAILURE; + } + + if (pdvrptr->Initialize(argv[1])) + return EXIT_FAILURE; + + pdvrptr->Run(); + + pdvrptr->Close(); + + pdvrptr.reset(); + + return EXIT_SUCCESS; } diff --git a/QnetDVRPTR.h b/QnetDVRPTR.h index 3d82c38..3cc5500 100644 --- a/QnetDVRPTR.h +++ b/QnetDVRPTR.h @@ -20,10 +20,10 @@ #include #include -#include "UnixPacketSock.h" +#include "UnixDgramSocket.h" #include "DStarDecode.h" #include "QnetTypeDefs.h" -#include "KRBase.h" +#include "Base.h" using tambevoicefec = unsigned char[9]; using tambevoice = unsigned char[6]; @@ -35,15 +35,18 @@ using tambevoice = unsigned char[6]; #define GORLAY_MASK12 0xfffff800 // auxiliary vector for testing #define GORLAY_GENPOL 0x00000c75 // generator polinomial, g(x) -class CQnetDVRPTR : public CKRBase +class CQnetDVRPTR : public CModem { public: - bool Init(const char *file, int assigned_module); + CQnetDVRPTR(int index) : CModem(index) {} + ~CQnetDVRPTR() {} + bool Initialize(const std::string &file); void Run(); + void Close(); private: CDStarDecode decode; - bool ReadConfig(const char *cfgFile); + bool ReadConfig(const std::string &cfgFile); void readFrom20000(); bool check_serial(); void CleanCall(std::string &callsign); @@ -97,9 +100,8 @@ private: unsigned char Modem_STATUS[6]= {0xD0,0x01,0x00,0x10,0x00,0x00}; // Status Abfragr unsigned char Modem_SERIAL[6]= {0xD0,0x01,0x00,0x12,0x00,0x00}; - int assigned_module; - std::string togate; - CUnixPacketClient ToGate; + CUnixDgramWriter ToGate; + CUnixDgramReader FromGate; std::string DVRPTR_SERIAL; char DVCALL[CALL_SIZE + 1]; diff --git a/QnetGateway.cpp b/QnetGateway.cpp index fb0c7e6..f5ec57c 100644 --- a/QnetGateway.cpp +++ b/QnetGateway.cpp @@ -203,7 +203,7 @@ void CQnetGateway::calcPFCS(unsigned char *packet, int len) } /* process configuration file */ -bool CQnetGateway::ReadConfig(char *cfgFile) +bool CQnetGateway::ReadConfig(const std::string &cfgFile) { const std::string estr; // an empty string CQnetConfigure cfg; @@ -298,13 +298,10 @@ bool CQnetGateway::ReadConfig(char *cfgFile) cfg.GetValue(path+"ipv6_port", estr, g2_ipv6_external.port, 1024, 65535); cfg.GetValue(path+"header_regen", estr, GATEWAY_HEADER_REGEN); cfg.GetValue(path+"send_qrgs_maps", estr, GATEWAY_SEND_QRGS_MAP); - cfg.GetValue(path+"tolink", estr, tolink, 1, FILENAME_MAX); - cfg.GetValue(path+"fromremote", estr, fromremote, 1, FILENAME_MAX); for (int m=0; m<3; m++) { if (Rptr.mod[m].defined) { - cfg.GetValue(path+"tomodem"+std::string(1, 'a'+m), estr, tomodem[m], 1, FILENAME_MAX); cfg.GetValue(path+"latitude", estr, Rptr.mod[m].latitude, -90.0, 90.0); cfg.GetValue(path+"longitude", estr, Rptr.mod[m].longitude, -180.0, 180.0); cfg.GetValue(path+"desc1", estr, Rptr.mod[m].desc1, 0, 20); @@ -404,7 +401,7 @@ void CQnetGateway::GetIRCDataThread(const int i) not_announced[i] = Rptr.mod[i].defined; // announce to all modules that are defined! bool is_quadnet = (std::string::npos != ircddb[i].ip.find(".openquad.net")); bool doFind = true; - while (IsRunning()) + while (keep_running) { int rc = ii[i]->getConnectionState(); if (rc > 5 && rc < 8 && is_quadnet) @@ -476,7 +473,7 @@ void CQnetGateway::GetIRCDataThread(const int i) threshold = 0; } - while (((type = ii[i]->getMessageType()) != IDRT_NONE) && IsRunning()) + while (((type = ii[i]->getMessageType()) != IDRT_NONE) && keep_running) { switch (type) { @@ -504,7 +501,7 @@ void CQnetGateway::GetIRCDataThread(const int i) default: break; } // switch (type) - } // while (IsRunning()) + } // while (keep_running) std::this_thread::sleep_for(std::chrono::milliseconds(500)); } printf("GetIRCDataThread[%i] exiting...\n", i); @@ -1148,7 +1145,7 @@ void CQnetGateway::ProcessG2Header(const SDSVT &g2buf, const int source_sock) if (source_sock >= 0) printf("IP=[%s]:%u\n", fromDstar.GetAddress(), fromDstar.GetPort()); else - printf("UnixSock=%s\n", tolink.c_str()); + printf("UnixSock=Link2Gate\n"); } lhcallsign[i].assign((const char *)g2buf.hdr.mycall, 8); if (showLastHeard && memcmp(g2buf.hdr.sfx, "RPTR", 4) && std::regex_match(lhcallsign[i].c_str(), preg)) @@ -2031,7 +2028,7 @@ void CQnetGateway::ProcessModem(const ssize_t recvlen, SDSVT &dsvt) } /* run the main loop for QnetGateway */ -void CQnetGateway::Process() +void CQnetGateway::Run() { // dtmf stuff initialize for (int i=0; i<3; i++) @@ -2068,16 +2065,16 @@ void CQnetGateway::Process() catch (const std::exception &e) { printf("Failed to start GetIRCDataThread[%d]. Exception: %s\n", i, e.what()); - SetState(false); + keep_running = false; } - if (IsRunning()) + if (keep_running) printf("get_irc_data thread[%d] started\n", i); ii[i]->kickWatchdog(GW_VERSION); } } - while (IsRunning()) + while (keep_running) { if (! m_fqueue.empty()) { @@ -2105,11 +2102,11 @@ void CQnetGateway::Process() AddFDSet(max_nfds, g2_sock[0], &fdset); if (g2_sock[1] >= 0) AddFDSet(max_nfds, g2_sock[1], &fdset); - AddFDSet(max_nfds, ToLink.GetFD(), &fdset); + AddFDSet(max_nfds, FromLink.GetFD(), &fdset); for (int i=0; i<3; i++) { if (Rptr.mod[i].defined) - AddFDSet(max_nfds, ToModem[i].GetFD(), &fdset); + AddFDSet(max_nfds, FromModem[i].GetFD(), &fdset); } AddFDSet(max_nfds, FromRemote.GetFD(), &fdset); struct timeval tv; @@ -2122,7 +2119,7 @@ void CQnetGateway::Process() { if (g2_sock[i] < 0) continue; - if (IsRunning() && FD_ISSET(g2_sock[i], &fdset)) + if (keep_running && FD_ISSET(g2_sock[i], &fdset)) { SDSVT dsvt; socklen_t fromlen = sizeof(struct sockaddr_storage); @@ -2136,7 +2133,7 @@ void CQnetGateway::Process() } // process packets from qnremote - if (IsRunning() && FD_ISSET(FromRemote.GetFD(), &fdset)) + if (keep_running && FD_ISSET(FromRemote.GetFD(), &fdset)) { SDSVT dsvt; const ssize_t len = FromRemote.Read(dsvt.title, 56); @@ -2145,10 +2142,10 @@ void CQnetGateway::Process() } // process packets from qnlink - if (IsRunning() && FD_ISSET(ToLink.GetFD(), &fdset)) + if (keep_running && FD_ISSET(FromLink.GetFD(), &fdset)) { SDSVT dsvt; - ssize_t g2buflen = ToLink.Read(dsvt.title, 56); + ssize_t g2buflen = FromLink.Read(dsvt.title, 56); if (16==g2buflen && 0==memcmp(dsvt.title, "LINK", 4)) { SLINKFAMILY fam; @@ -2167,19 +2164,19 @@ void CQnetGateway::Process() { ProcessG2(g2buflen, dsvt, -1); } - FD_CLR(ToLink.GetFD(), &fdset); + FD_CLR(FromLink.GetFD(), &fdset); } // process packets coming from local repeater module(s) for (int i=0; i<3; i++) { - if (IsRunning() && FD_ISSET(ToModem[i].GetFD(), &fdset)) + if (keep_running && FD_ISSET(FromModem[i].GetFD(), &fdset)) { SDSVT dsvt; - const ssize_t len = ToModem[i].Read(dsvt.title, 56); + const ssize_t len = FromModem[i].Read(dsvt.title, 56); if (Rptr.mod[i].defined) ProcessModem(len, dsvt); - FD_CLR(ToModem[i].GetFD(), &fdset); + FD_CLR(FromModem[i].GetFD(), &fdset); } } } @@ -2246,7 +2243,7 @@ void CQnetGateway::APRSBeaconThread() time_t last_beacon_time = 0; /* This thread is also saying to the APRS_HOST that we are ALIVE */ - while (IsRunning()) + while (keep_running) { if (aprs->aprs_sock.GetFD() == -1) { @@ -2302,7 +2299,7 @@ void CQnetGateway::APRSBeaconThread() printf("APRS Beacon =[%s]\n", snd_buf); strcat(snd_buf, "\r\n"); - while (IsRunning()) + while (keep_running) { if (aprs->aprs_sock.GetFD() == -1) { @@ -2581,7 +2578,7 @@ void CQnetGateway::qrgs_and_maps() return; } -bool CQnetGateway::Init(char *cfgfile) +bool CQnetGateway::Initialize(const std::string &path) { short int i; @@ -2597,9 +2594,9 @@ bool CQnetGateway::Init(char *cfgfile) } /* process configuration file */ - if ( ReadConfig(cfgfile) ) + if ( ReadConfig(path) ) { - printf("Failed to process config file %s\n", cfgfile); + printf("Failed to process config file %s\n", path.c_str()); return true; } @@ -2611,20 +2608,28 @@ bool CQnetGateway::Init(char *cfgfile) qnDB.ClearLH(); // Open unix sockets between qngateway and qnremote - printf("Connecting to qnlink at %s\n", tolink.c_str()); - if (ToLink.Open(tolink.c_str(), this)) + printf("Opening Link2Gate\n"); + if (FromLink.Open("Link2Gate")) return true; - printf("Opening remote port at %s\n", fromremote.c_str()); - if (FromRemote.Open(fromremote.c_str())) + ToLink.SetUp("Gate2Link"); + printf("Opening Remote2Gate\n"); + if (FromRemote.Open("Remote2Gate")) return true; for (i=0; i<3; i++) { if (Rptr.mod[i].defined) // open unix sockets between qngateway and each defined modem { - printf("Connecting to modem at %s\n", tomodem[i].c_str()); - if (ToModem[i].Open(tomodem[i].c_str(), this)) + const char mod = 'A'+i; + std::string name("Modem"); + name.append(1, mod); + name.append("2Gate"); + printf("Opening %s\n", name.c_str()); + if (FromModem[i].Open(name.c_str())) return true; + name.assign("Gate2Modem"); + name.append(1, mod); + ToModem[i].SetUp(name.c_str()); } // recording for echotest on local repeater modules recd[i].last_time = 0; @@ -2714,7 +2719,7 @@ bool CQnetGateway::Init(char *cfgfile) else break; - if (!IsRunning()) + if (!keep_running) break; if (i > 5) @@ -2811,19 +2816,19 @@ bool CQnetGateway::Init(char *cfgfile) return false; } -CQnetGateway::CQnetGateway() +CQnetGateway::CQnetGateway() : CBase() { ii[0] = ii[1] = NULL; } -CQnetGateway::~CQnetGateway() +void CQnetGateway::Close() { - ToLink.Close(); + FromLink.Close(); FromRemote.Close(); for (int i=0; i<3; i++) { if (Rptr.mod[i].defined) - ToModem[i].Close(); + FromModem[i].Close(); } if (APRS_ENABLE) @@ -2864,19 +2869,43 @@ CQnetGateway::~CQnetGateway() printf("QnetGateway exiting\n"); } +CQnetGateway QnetGateway; + +static void HandleSignal(int sig) +{ + switch (sig) + { + case SIGINT: + case SIGHUP: + case SIGTERM: + QnetGateway.Stop(); + break; + default: + fprintf(stderr, "Caught an unknown signal: %d\n", sig); + break; + } +} + int main(int argc, char **argv) { + std::signal(SIGINT, HandleSignal); + std::signal(SIGHUP, HandleSignal); + std::signal(SIGTERM, HandleSignal); printf("VERSION %s\n", GW_VERSION.c_str()); if (argc != 2) { printf("usage: %s qn.cfg\n", argv[0]); - return 1; + return EXIT_FAILURE; } - CQnetGateway QnetGateway; - if (QnetGateway.Init(argv[1])) + if (QnetGateway.Initialize(argv[1])) { - return 1; + return EXIT_FAILURE; } - QnetGateway.Process(); + + QnetGateway.Run(); + + QnetGateway.Close(); + printf("Leaving processing loop...\n"); + return EXIT_SUCCESS; } diff --git a/QnetGateway.h b/QnetGateway.h index d1df62e..9962877 100644 --- a/QnetGateway.h +++ b/QnetGateway.h @@ -25,12 +25,11 @@ #include "QnetTypeDefs.h" #include "SEcho.h" #include "UnixDgramSocket.h" -#include "UnixPacketSock.h" #include "aprs.h" #include "SockAddress.h" #include "QnetDB.h" #include "DStarDecode.h" -#include "KRBase.h" +#include "Base.h" #include "Location.h" #define MAXHOSTNAMELEN 64 @@ -93,13 +92,13 @@ using SSD = struct sd_tag void Init() { ih = im = ig = 0; first = true; } }; -class CQnetGateway : public CKRBase +class CQnetGateway : public CBase { public: CQnetGateway(); - ~CQnetGateway(); - void Process(); - bool Init(char *cfgfile); + bool Initialize(const std::string &path); + void Run(); + void Close(); private: std::queue> m_fqueue; @@ -112,10 +111,8 @@ private: SPORTIP g2_external, g2_ipv6_external, ircddb[2]; - CUnixDgramReader FromRemote; - CUnixPacketServer ToLink, ToModem[3]; - - std::string tolink, fromremote, tomodem[3]; + CUnixDgramReader FromRemote, FromLink, FromModem[3]; + CUnixDgramWriter ToLink, ToModem[3]; std::string OWNER, owner, FILE_DTMF, FILE_ECHOTEST, IRCDDB_PASSWORD[2], FILE_QNVOICE_FILE, DASH_SHOW_ORDER; @@ -194,7 +191,6 @@ private: void APRSBeaconThread(); bool Printable(unsigned char *string); void ProcessTimeouts(); - void ProcessSlowData(unsigned char *data, const unsigned short sid); void ProcessIncomingSD(const SDSVT &dsvt, const int source_sock); void ProcessOutGoingSD(const SDSVT &dsvt, const int mod); bool ProcessG2Msg(const unsigned char *data, const int mod, std::string &smrtgrp); @@ -207,7 +203,7 @@ private: int FindIndex(const int i) const; // read configuration file - bool ReadConfig(char *); + bool ReadConfig(const std::string &path); void qrgs_and_maps(); diff --git a/QnetITAP.cpp b/QnetITAP.cpp index eafebbc..0a66c5c 100644 --- a/QnetITAP.cpp +++ b/QnetITAP.cpp @@ -39,29 +39,32 @@ #include #include #include +#include #include "QnetITAP.h" #include "QnetTypeDefs.h" #include "QnetConfigure.h" #include "Timer.h" -#define ITAP_VERSION "QnetITAP-20307" +#define ITAP_VERSION "QnetITAP-40419" -CQnetITAP::CQnetITAP(int mod) - : assigned_module(mod) -{ -} - -CQnetITAP::~CQnetITAP() -{ -} - -bool CQnetITAP::Initialize(const char *cfgfile) +bool CQnetITAP::Initialize(const std::string &cfgfile) { if (ReadConfig(cfgfile)) return true; - if (ToGate.Open(togate.c_str(), this)) + std::string name("Gate2Modem"); + std::string(1, RPTR_MOD); + printf("Opening %s\n", name.c_str()); + if (FromGate.Open(name.c_str())) + return true; + name.assign("Modem"); + name.append(1, RPTR_MOD); + name.append("2Gate"); + ToGate.SetUp(name.c_str()); + + serfd = OpenITAP(); + if (serfd < 0) return true; return false; @@ -209,19 +212,8 @@ REPLY_TYPE CQnetITAP::GetITAPData(unsigned char *buf) } } -void CQnetITAP::Run(const char *cfgfile) +void CQnetITAP::Run() { - if (Initialize(cfgfile)) - return; - - serfd = OpenITAP(); - if (serfd < 0) - return; - - int ug2m = ToGate.GetFD(); - printf("gate2modem=%d, serial=%d\n", ug2m, serfd); - - keep_running = true; unsigned int poll_counter = 0; bool initialized = false; bool alive = true; @@ -231,10 +223,11 @@ void CQnetITAP::Run(const char *cfgfile) CTimer pingTimer; double pingtime = 0.001; const double ackwait = AP_MODE ? 0.4 : 0.06; + int ug2m = FromGate.GetFD(); + printf("gate2modem=%d, serial=%d\n", ug2m, serfd); while (keep_running) { - fd_set readfds; FD_ZERO(&readfds); FD_SET(serfd, &readfds); @@ -357,7 +350,7 @@ void CQnetITAP::Run(const char *cfgfile) if (keep_running && FD_ISSET(ug2m, &readfds)) { - ssize_t len = ToGate.Read(buf, 100); + ssize_t len = FromGate.Read(buf, 100); if (len < 0) { @@ -422,9 +415,12 @@ void CQnetITAP::Run(const char *cfgfile) } } } +} +void CQnetITAP::Close() +{ close(serfd); - ToGate.Close(); + FromGate.Close(); } void CQnetITAP::SendToIcom(const unsigned char *buf) @@ -600,17 +596,17 @@ bool CQnetITAP::ProcessITAP(const unsigned char *buf) } // process configuration file and return true if there was a problem -bool CQnetITAP::ReadConfig(const char *cfgFile) +bool CQnetITAP::ReadConfig(const std::string &cfgFile) { CQnetConfigure cfg; - printf("Reading file %s\n", cfgFile); + printf("Reading file %s\n", cfgFile.c_str()); if (cfg.Initialize(cfgFile)) return true; const std::string estr; // an empty string std::string type; std::string itap_path("module_"); - if (0 > assigned_module) + if (0 > m_index) { // we need to find the lone itap module for (int i=0; i<3; i++) @@ -623,11 +619,11 @@ bool CQnetITAP::ReadConfig(const char *cfgFile) if (type.compare("itap")) continue; // this ain't it! itap_path.assign(test); - assigned_module = i; + m_index = i; break; } } - if (0 > assigned_module) + if (0 > m_index) { fprintf(stderr, "Error: no 'itap' module found\n!"); return true; @@ -636,7 +632,7 @@ bool CQnetITAP::ReadConfig(const char *cfgFile) else { // make sure itap module is defined - itap_path.append(1, 'a' + assigned_module); + itap_path.append(1, 'a' + m_index); if (cfg.KeyExists(itap_path)) { cfg.GetValue(itap_path, estr, type, 1, 16); @@ -648,11 +644,11 @@ bool CQnetITAP::ReadConfig(const char *cfgFile) } else { - fprintf(stderr, "Module '%c' is not defined.\n", 'a'+assigned_module); + fprintf(stderr, "Module '%c' is not defined.\n", 'a'+m_index); return true; } } - RPTR_MOD = 'A' + assigned_module; + RPTR_MOD = 'A' + m_index; cfg.GetValue(itap_path+"_device", type, ITAP_DEVICE, 7, FILENAME_MAX); cfg.GetValue(itap_path+"_ap_mode", type, AP_MODE); @@ -688,7 +684,6 @@ bool CQnetITAP::ReadConfig(const char *cfgFile) RPTR.resize(CALL_SIZE, ' '); } - cfg.GetValue(std::string("gateway_tomodem")+std::string(1, 'a'+assigned_module), estr, togate, 1, FILENAME_MAX); cfg.GetValue("log_qso", estr, LOG_QSO); cfg.GetValue("log_debug", estr, LOG_DEBUG); return false; @@ -733,8 +728,31 @@ void CQnetITAP::calcPFCS(const unsigned char *packet, unsigned char *pfcs) return; } +std::unique_ptr pitap; + +static void SignalHandler(int sig) +{ + switch (sig) + { + case SIGINT: + case SIGHUP: + case SIGTERM: + if (pitap) + pitap->Stop(); + break; + + default: + fprintf(stderr, "Caught an unknown signal: %d\n", sig); + break; + } +} + int main(int argc, const char **argv) { + std::signal(SIGINT, SignalHandler); + std::signal(SIGHUP, SignalHandler); + std::signal(SIGTERM, SignalHandler); + setbuf(stdout, NULL); if (2 != argc) { @@ -744,7 +762,7 @@ int main(int argc, const char **argv) if ('-' == argv[1][0]) { - printf("%s Copyright (C) 2018-2019 by Thomas A. Early N7TAE\n", ITAP_VERSION); + printf("%s Copyright (C) 2018-2024 by Thomas A. Early N7TAE\n", ITAP_VERSION); printf("QnetITAP comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"); printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\n"); return 0; @@ -778,11 +796,27 @@ int main(int argc, const char **argv) return 1; } - CQnetITAP qnitap(assigned_module); + pitap = std::unique_ptr(new CQnetITAP(assigned_module)); + + if (!pitap) + { + fprintf(stderr, "Could not make a CQnetITAP\n"); + return EXIT_FAILURE; + } + + if (pitap->Initialize(argv[1])) + { + pitap.reset(); + return EXIT_FAILURE; + } - qnitap.Run(argv[1]); + pitap->Run(); + + pitap->Close(); printf("%s is closing.\n", argv[0]); + pitap.reset(); + return 0; } diff --git a/QnetITAP.h b/QnetITAP.h index 54d3b22..82a40d8 100644 --- a/QnetITAP.h +++ b/QnetITAP.h @@ -25,8 +25,8 @@ #include #include "Random.h" // for streamid generation -#include "UnixPacketSock.h" -#include "KRBase.h" +#include "UnixDgramSocket.h" +#include "Base.h" #define CALL_SIZE 8 #define IP_SIZE 15 @@ -105,20 +105,20 @@ private: SITAP frame; }; -class CQnetITAP : CKRBase +class CQnetITAP : public CModem { public: // functions - CQnetITAP(int mod); - ~CQnetITAP(); - void Run(const char *cfgfile); + CQnetITAP(int mod) : CModem(mod) {} + ~CQnetITAP() {} + bool Initialize(const std::string &cfgfile); + void Run(); + void Close(); // data private: - int assigned_module; // functions - bool Initialize(const char *cfgfile); bool ProcessGateway(const int len, const unsigned char *raw); bool ProcessITAP(const unsigned char *raw); int OpenITAP(); @@ -128,7 +128,7 @@ private: void DumpSerialPacket(const char *title, const unsigned char *); // read configuration file - bool ReadConfig(const char *); + bool ReadConfig(const std::string &path); // config data char RPTR_MOD; @@ -143,8 +143,8 @@ private: CRandom random; // unix sockets - std::string togate; - CUnixPacketClient ToGate; + CUnixDgramWriter ToGate; + CUnixDgramReader FromGate; // Queue std::queue queue; diff --git a/QnetLink.cpp b/QnetLink.cpp index ecf1a5a..f4371a9 100644 --- a/QnetLink.cpp +++ b/QnetLink.cpp @@ -56,7 +56,7 @@ #define LINK_VERSION "QnetLink-40411" -CQnetLink::CQnetLink() +CQnetLink::CQnetLink() : CBase() { } @@ -643,12 +643,12 @@ void CQnetLink::PrintCallsigns(const std::string &key, const std::set &set); void LoadGateways(const std::string &filename); void calcPFCS(unsigned char *packet, int len); - bool ReadConfig(const char *); + bool ReadConfig(const std::string &path); bool srv_open(); void srv_close(); void g2link(const char from_mod, const char *call, const char to_mod); @@ -163,8 +163,8 @@ private: CSockAddress fromDst4; // unix sockets to gateway - std::string togate; - CUnixPacketClient ToGate; + CUnixDgramWriter ToGate; + CUnixDgramReader FromGate; struct timeval tv; diff --git a/QnetModem.cpp b/QnetModem.cpp index 55a1cc1..4cff1b1 100644 --- a/QnetModem.cpp +++ b/QnetModem.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include "QnetModem.h" #include "QnetConfigure.h" @@ -65,16 +66,6 @@ const unsigned char TYPE_EOT = 0x13U; const unsigned char TYPE_ACK = 0x70U; const unsigned char TYPE_NACK = 0x7FU; -CQnetModem::CQnetModem(int mod) - : assigned_module(mod) - , dstarSpace(0U) -{ -} - -CQnetModem::~CQnetModem() -{ -} - bool CQnetModem::VoicePacketIsSync(const unsigned char *text) { return *text==0x55U && *(text+1)==0x2DU && *(text+2)==0x16U; @@ -221,14 +212,20 @@ bool CQnetModem::SetFrequency() return false; } -bool CQnetModem::Initialize(const char *cfgfile) +bool CQnetModem::Initialize(const std::string &cfgfile) { if (ReadConfig(cfgfile)) return true; - printf("Connecting to qngateway at %s\n", togate.c_str()); - if (ToGate.Open(togate.c_str(), this)) + std::string name("Gate2Modem"); + name.append(1, RPTR_MOD); + printf("Opening %s\n", name.c_str()); + if (FromGate.Open(name.c_str())) return true; + name.assign("Modem"); + name.append(1, RPTR_MOD); + name.append("2Gate"); + ToGate.SetUp(name.c_str()); serfd = OpenModem(); if (serfd < 0) @@ -465,12 +462,9 @@ EModemResponse CQnetModem::GetModemData(unsigned char *buf, unsigned int size) }; } -void CQnetModem::Run(const char *cfgfile) +void CQnetModem::Run() { - if (Initialize(cfgfile)) - return; - - int ug2m = ToGate.GetFD(); + int ug2m = FromGate.GetFD(); printf("gate2modem=%d, serial=%d\n", ug2m, serfd); keep_running = true; @@ -540,7 +534,7 @@ void CQnetModem::Run(const char *cfgfile) if (keep_running && FD_ISSET(ug2m, &readfds)) { SDSVT dsvt; - ssize_t len = ToGate.Read(dsvt.title, sizeof(SDSVT)); + ssize_t len = FromGate.Read(dsvt.title, sizeof(SDSVT)); if (len <= 0) { @@ -594,8 +588,12 @@ void CQnetModem::Run(const char *cfgfile) } } } +} + +void CQnetModem::Close() +{ close(serfd); - ToGate.Close(); + FromGate.Close(); } int CQnetModem::SendToModem(const unsigned char *buf) @@ -821,17 +819,17 @@ bool CQnetModem::ProcessModem(const SMODEM &frame) } // process configuration file and return true if there was a problem -bool CQnetModem::ReadConfig(const char *cfgFile) +bool CQnetModem::ReadConfig(const std::string &cfgFile) { CQnetConfigure cfg; - printf("Reading file %s\n", cfgFile); + printf("Reading file %s\n", cfgFile.c_str()); if (cfg.Initialize(cfgFile)) return true; const std::string estr; // an empty string std::string type; std::string modem_path("module_"); - if (0 > assigned_module) + if (0 > m_index) { // we need to find the lone mmdvmmodem module for (int i=0; i<3; i++) @@ -844,11 +842,11 @@ bool CQnetModem::ReadConfig(const char *cfgFile) if (type.compare("mmdvmmodem")) continue; // this ain't it! modem_path.assign(test); - assigned_module = i; + m_index = i; break; } } - if (0 > assigned_module) + if (0 > m_index) { fprintf(stderr, "Error: no 'mmdvmmodem' module found\n!"); return true; @@ -857,7 +855,7 @@ bool CQnetModem::ReadConfig(const char *cfgFile) else { // make sure mmdvmmodem module is defined - modem_path.append(1, 'a' + assigned_module); + modem_path.append(1, 'a' + m_index); if (cfg.KeyExists(modem_path)) { cfg.GetValue(modem_path, estr, type, 1, 16); @@ -869,14 +867,13 @@ bool CQnetModem::ReadConfig(const char *cfgFile) } else { - fprintf(stderr, "Module '%c' is not defined.\n", 'a'+assigned_module); + fprintf(stderr, "Module '%c' is not defined.\n", 'a'+m_index); return true; } } - RPTR_MOD = 'A' + assigned_module; + RPTR_MOD = 'A' + m_index; cfg.GetValue(modem_path+"_device", type, MODEM_DEVICE, 7, FILENAME_MAX); - cfg.GetValue(std::string("gateway_tomodem")+std::string(1, 'a'+assigned_module), estr, togate, 1, FILENAME_MAX); if (cfg.GetValue(modem_path+"_tx_frequency", type, TX_FREQUENCY, 1.0, 6000.0)) return true; // we have to have a valid frequency @@ -933,6 +930,25 @@ bool CQnetModem::ReadConfig(const char *cfgFile) return false; } +std::unique_ptr pmodem; + +static void SignalHandler(int sig) +{ + switch (sig) + { + case SIGINT: + case SIGHUP: + case SIGTERM: + if (pmodem) + pmodem->Stop(); + break; + + default: + fprintf(stderr, "Caught an unexpected signal: %d\n", sig); + break; + } +} + int main(int argc, const char **argv) { setbuf(stdout, NULL); @@ -944,7 +960,7 @@ int main(int argc, const char **argv) if ('-' == argv[1][0]) { - printf("%s Copyright (C) 2019 by Thomas A. Early N7TAE\n", MODEM_VERSION); + printf("%s Copyright (C) 2019,2024 by Thomas A. Early N7TAE\n", MODEM_VERSION); printf("QnetModem comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"); printf("This is free software, and you are welcome to distribute it\n"); printf("under certain conditions that are discussed in the LICENSE file.\n"); @@ -959,31 +975,47 @@ int main(int argc, const char **argv) } qn += 7; - int assigned_module; + int mod; switch (*qn) { case 0: - assigned_module = -1; + mod = -1; break; case 'a': - assigned_module = 0; + mod = 0; break; case 'b': - assigned_module = 1; + mod = 1; break; case 'c': - assigned_module = 2; + mod = 2; break; default: fprintf(stderr, "assigned module must be a, b or c\n"); return 1; } - CQnetModem qnmodem(assigned_module); + pmodem = std::unique_ptr(new CQnetModem(mod)); + + if (!pmodem) + { + fprintf(stderr, "Could not make a CQnetModem!\n"); + return EXIT_FAILURE; + } + + if (pmodem->Initialize(argv[1])) + { + pmodem.reset(); + return EXIT_FAILURE; + } + + pmodem->Run(); + + pmodem->Close(); - qnmodem.Run(argv[1]); + pmodem.reset(); printf("%s is closing.\n", argv[0]); - return 0; + return EXIT_SUCCESS; } diff --git a/QnetModem.h b/QnetModem.h index 61b2b6c..0f7da17 100644 --- a/QnetModem.h +++ b/QnetModem.h @@ -24,10 +24,10 @@ #include #include "Random.h" // for streamid generation -#include "UnixPacketSock.h" +#include "UnixDgramSocket.h" #include "QnetTypeDefs.h" #include "Timer.h" -#include "KRBase.h" +#include "Base.h" #define CALL_SIZE 8 #define IP_SIZE 15 @@ -193,21 +193,21 @@ private: SMODEM frame; }; -class CQnetModem : CKRBase +class CQnetModem : public CModem { public: // functions - CQnetModem(int mod); - ~CQnetModem(); - void Run(const char *cfgfile); + CQnetModem(int mod) : CModem(mod), dstarSpace(0) {} + ~CQnetModem() {} + bool Initialize(const std::string &cfgfile); + void Run(); + void Close(); private: - int assigned_module; unsigned int dstarSpace; // functions bool VoicePacketIsSync(const unsigned char *); - bool Initialize(const char *cfgfile); void ProcessGateway(const SDSVT &dsvt); bool ProcessModem(const SMODEM &frame); int OpenModem(); @@ -219,7 +219,7 @@ private: bool SetConfiguration(); // read configuration file - bool ReadConfig(const char *); + bool ReadConfig(const std::string &path); // config data char RPTR_MOD; @@ -238,8 +238,8 @@ private: CTimer PacketWait; // unix sockets - std::string togate; - CUnixPacketClient ToGate; + CUnixDgramWriter ToGate; + CUnixDgramReader FromGate; // Queue std::queue queue; diff --git a/QnetRelay.cpp b/QnetRelay.cpp index 09cf801..60f81a4 100644 --- a/QnetRelay.cpp +++ b/QnetRelay.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -38,21 +39,24 @@ #define RELAY_VERSION "QnetRelay-20307" -CQnetRelay::CQnetRelay(int mod) : - assigned_module(mod), - seed(time(NULL)), - COUNTER(0) +bool CQnetRelay::Initialize(const std::string &cfgfile) { -} + if (ReadConfig(cfgfile)) + return true; -CQnetRelay::~CQnetRelay() -{ -} + msock = OpenSocket(MMDVM_INTERNAL_IP, MMDVM_OUT_PORT); + if (msock < 0) + return true; -bool CQnetRelay::Initialize(const char *cfgfile) -{ - if (ReadConfig(cfgfile)) + std::string name("Gate2Modem"); + name.append(1, RPTR_MOD); + printf("Opening %s\n", name.c_str()); + if (FromGate.Open(name.c_str())) return true; + name.assign("Modem"); + name.append(1, RPTR_MOD); + name.append("2Gate"); + ToGate.SetUp(name.c_str()); return false; } @@ -107,19 +111,9 @@ int CQnetRelay::OpenSocket(const std::string &address, unsigned short port) return fd; } -bool CQnetRelay::Run(const char *cfgfile) +void CQnetRelay::Run() { - if (Initialize(cfgfile)) - return true; - - msock = OpenSocket(MMDVM_INTERNAL_IP, MMDVM_OUT_PORT); - if (msock < 0) - return true; - - if (ToGate.Open(togate.c_str(), this)) - return true; - - int fd = ToGate.GetFD(); + int fd = FromGate.GetFD(); printf("msock=%d, gateway=%d\n", msock, fd); @@ -168,7 +162,7 @@ bool CQnetRelay::Run(const char *cfgfile) if (FD_ISSET(fd, &readfds)) { - len = ToGate.Read(buf, 100); + len = FromGate.Read(buf, 100); if (len < 0) { @@ -204,10 +198,12 @@ bool CQnetRelay::Run(const char *cfgfile) fprintf(stderr, "DEBUG: Run: received unknow packet '%s' len=%d\n", title, (int)len); } } +} +void CQnetRelay::Close() +{ ::close(msock); - ToGate.Close(); - return false; + FromGate.Close(); } int CQnetRelay::SendTo(const int fd, const unsigned char *buf, const int size, const std::string &address, const unsigned short port) @@ -371,10 +367,10 @@ bool CQnetRelay::ProcessMMDVM(const int len, const unsigned char *raw) } // process configuration file and return true if there was a problem -bool CQnetRelay::ReadConfig(const char *cfgFile) +bool CQnetRelay::ReadConfig(const std::string &cfgFile) { CQnetConfigure cfg; - printf("Reading file %s\n", cfgFile); + printf("Reading file %s\n", cfgFile.c_str()); if (cfg.Initialize(cfgFile)) return true; @@ -382,7 +378,7 @@ bool CQnetRelay::ReadConfig(const char *cfgFile) std::string mmdvm_path("module_"); std::string type; - if (0 > assigned_module) + if (0 > m_index) { // we need to find the lone mmdvmhost module for (int i=0; i<3; i++) @@ -395,11 +391,11 @@ bool CQnetRelay::ReadConfig(const char *cfgFile) if (type.compare("mmdvmhost")) continue; // this ain't it! mmdvm_path.assign(test); - assigned_module = i; + m_index = i; break; } } - if (0 > assigned_module) + if (0 > m_index) { fprintf(stderr, "Error: no 'mmdvmhost' module found\n!"); return true; @@ -408,7 +404,7 @@ bool CQnetRelay::ReadConfig(const char *cfgFile) else { // make sure mmdvmhost module is defined - mmdvm_path.append(1, 'a' + assigned_module); + mmdvm_path.append(1, 'a' + m_index); if (cfg.KeyExists(mmdvm_path)) { cfg.GetValue(mmdvm_path, estr, type, 1, 16); @@ -420,13 +416,12 @@ bool CQnetRelay::ReadConfig(const char *cfgFile) } else { - fprintf(stderr, "Module '%c' is not defined.\n", 'a'+assigned_module); + fprintf(stderr, "Module '%c' is not defined.\n", 'a'+m_index); return true; } } - RPTR_MOD = 'A' + assigned_module; + RPTR_MOD = 'A' + m_index; - cfg.GetValue("gateway_tomodem"+std::string(1, 'a'+assigned_module), estr, togate, 1, FILENAME_MAX); cfg.GetValue(mmdvm_path+"_internal_ip", type, MMDVM_INTERNAL_IP, 7, IP_SIZE); cfg.GetValue(mmdvm_path+"_target_ip", type, MMDVM_TARGET_IP, 7, IP_SIZE); @@ -442,6 +437,25 @@ bool CQnetRelay::ReadConfig(const char *cfgFile) return false; } +std::unique_ptr prelay; + +static void SignalHandler(int sig) +{ + switch (sig) + { + case SIGINT: + case SIGHUP: + case SIGTERM: + if (prelay) + prelay->Stop(); + break; + + default: + fprintf(stderr, "Caught an unexpected signal: %d\n", sig); + break; + } +} + int main(int argc, const char **argv) { setbuf(stdout, NULL); @@ -453,7 +467,7 @@ int main(int argc, const char **argv) if ('-' == argv[1][0]) { - printf("%s Copyright (C) 2018-2021 by Thomas A. Early N7TAE\n", RELAY_VERSION); + printf("%s Copyright (C) 2018-2024 by Thomas A. Early N7TAE\n", RELAY_VERSION); printf("QnetRelay comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"); printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\n"); return 0; @@ -486,11 +500,25 @@ int main(int argc, const char **argv) return 1; } - CQnetRelay qnmmdvm(module); + prelay = std::unique_ptr(new CQnetRelay(module)); + + if (!prelay) + { + fprintf(stderr, "Could not make a CQnetRelay!\n"); + return EXIT_FAILURE; + } + + if (prelay->Initialize(argv[1])) + { + prelay.reset(); + return EXIT_FAILURE; + } + + prelay->Run(); - bool trouble = qnmmdvm.Run(argv[1]); + prelay->Close(); printf("%s is closing.\n", argv[0]); - return trouble ? 1 : 0; + return EXIT_SUCCESS; } diff --git a/QnetRelay.h b/QnetRelay.h index cf190e9..f22715b 100644 --- a/QnetRelay.h +++ b/QnetRelay.h @@ -22,35 +22,35 @@ #include #include -#include "UnixPacketSock.h" -#include "KRBase.h" +#include "UnixDgramSocket.h" +#include "Base.h" #define CALL_SIZE 8 #define IP_SIZE 15 -class CQnetRelay : CKRBase +class CQnetRelay : public CModem { public: // functions - CQnetRelay(int mod); - ~CQnetRelay(); - bool Run(const char *cfgfile); + CQnetRelay(int mod) : CModem(mod), seed(time(NULL)), COUNTER(0) {} + ~CQnetRelay() {} + bool Initialize(const std::string &cfgfile); + void Run(); + void Close(); private: // functions - bool Initialize(const char *cfgfile); bool ProcessGateway(const int len, const unsigned char *raw); bool ProcessMMDVM(const int len, const unsigned char *raw); int OpenSocket(const std::string &address, unsigned short port); int SendTo(const int fd, const unsigned char *buf, const int size, const std::string &address, const unsigned short port); // read configuration file - bool ReadConfig(const char *); + bool ReadConfig(const std::string &); // Unix sockets - int assigned_module; - std::string togate; - CUnixPacketClient ToGate; + CUnixDgramWriter ToGate; + CUnixDgramReader FromGate; // config data char RPTR_MOD; diff --git a/UnixPacketSock.cpp b/UnixPacketSock.cpp deleted file mode 100644 index ba105c0..0000000 --- a/UnixPacketSock.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2020 by Thomas Early N7TAE - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "UnixPacketSock.h" - -CUnixPacket::CUnixPacket() : m_fd(-1), m_host(NULL) {} - -ssize_t CUnixPacket::Read(void *buffer, const ssize_t size) -{ - if (0 > m_fd) - return -1; - ssize_t len = read(m_fd, buffer, size); - if (len < 1) - { - if (-1 == len) - { - std::cerr << "Read error on '" << m_name << "': " << strerror(errno) << std::endl; - } - else if (0 == len) - { - std::cerr << "Read error on '" << m_name << "': EOF" << std::endl; - } - if (Restart()) - return -1; - else - return 0; - } - return len; -} - -bool CUnixPacket::Write(const void *buffer, const ssize_t size) -{ - if (0 > m_fd) - return true; - ssize_t written = write(m_fd, buffer, size); - if (written != size) - { - if (-1 == written) - { - std::cerr << "Write error on '" << m_name << "': " << strerror(errno) << std::endl; - } - else - { - std::cout << "Write error on '" << m_name << "': Only wrote " << written << " of " << size << " bytes" << std::endl; - } - return Restart(); - } - return false; -} - -bool CUnixPacket::Restart() -{ - if (! m_host->IsRunning()) - return true; - std::cout << "Restarting '" << m_name << "'... " << std::endl; - Close(); - std::string name(m_name); - return Open(name.c_str(), m_host); -} - -int CUnixPacket::GetFD() -{ - return m_fd; -} - -CUnixPacketServer::CUnixPacketServer() : m_server(-1) {} - -CUnixPacketServer::~CUnixPacketServer() -{ - Close(); -} - -bool CUnixPacketServer::Open(const char *name, CKRBase *host) -{ - m_server = socket(AF_UNIX, SOCK_SEQPACKET, 0); - m_host = host; - if (m_server < 0) - { - std::cerr << "Cannot open '" << name << "' socket: " << strerror(errno) << std::endl; - return true; - } - - struct sockaddr_un addr; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - memcpy(addr.sun_path+1, name, strlen(name)); - if (-1 == bind(m_server, (struct sockaddr *)&addr, sizeof(addr))) - { - std::cerr << "Cannot bind '" << name << "' socket: " << strerror(errno) << std::endl; - Close(); - return true; - } - - if (-1 == listen(m_server, 1)) - { - std::cerr << "Cannot listen on '" << name << "' socket: " << strerror(errno) << std::endl; - Close(); - return true; - } - - m_fd = accept(m_server, nullptr, 0); - if (m_fd < 0) - { - std::cerr << "Cannot accept on '" << name << "' socket: " << strerror(errno) << std::endl; - Close(); - return true; - } - - strncpy(m_name, name, 108); - return false; -} - -void CUnixPacketServer::Close() -{ - if (m_server >= 0) - { - close(m_server); - m_server = -1; - } - if (m_fd >= 0) - { - close(m_fd); - m_fd = -1; - } -} - -CUnixPacketClient::~CUnixPacketClient() -{ - Close(); -} - -bool CUnixPacketClient::Open(const char *name, CKRBase *host) -{ - m_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0); - if (m_fd < 0) - { - std::cerr << "Cannot open unix client socket " << name << std::endl; - return true; - } - - struct sockaddr_un addr; - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - memcpy(addr.sun_path+1, name, strlen(name)); - int rval = -1; - int tries = 0; - while (rval < 0) - { - rval = connect(m_fd, (struct sockaddr *)&addr, sizeof(addr)); - if (rval < 0) - { - if (ECONNREFUSED == errno) - { - if (0 == tries++ % 20) - std::cout << "Waiting for " << name << " server to start..." << std::endl; - std::this_thread::sleep_for(std::chrono::milliseconds(250)); - } - else - { - std::cerr << "Cannot connect '" << name << "' socket: " << strerror(errno) << std::endl; - Close(); - return true; - } - } - if (! m_host->IsRunning()) - { - Close(); - return true; - } - } - - m_host = host; - strncpy(m_name, name, 108); - return false; -} - -void CUnixPacketClient::Close() -{ - if (m_fd >= 0) - { - close(m_fd); - m_fd = -1; - } -} diff --git a/UnixPacketSock.h b/UnixPacketSock.h deleted file mode 100644 index 6d7dacd..0000000 --- a/UnixPacketSock.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -/* - * Copyright (C) 2020 by Thomas Early N7TAE - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include - -#include "KRBase.h" - -class CUnixPacket -{ -public: - CUnixPacket(); - virtual bool Open(const char *name, CKRBase *host) = 0; - virtual void Close() = 0; - bool Write(const void *buffer, const ssize_t size); - ssize_t Read(void *buffer, const ssize_t size); - int GetFD(); -protected: - bool Restart(); - int m_fd; - CKRBase *m_host; - char m_name[108]; -}; - -class CUnixPacketServer : public CUnixPacket -{ -public: - CUnixPacketServer(); - ~CUnixPacketServer(); - bool Open(const char *name, CKRBase *host); - void Close(); -protected: - int m_server; -}; - -class CUnixPacketClient : public CUnixPacket -{ -public: - ~CUnixPacketClient(); - bool Open(const char *name, CKRBase *host); - void Close(); -}; diff --git a/defaults b/defaults index a0118c8..d6c2cf2 100644 --- a/defaults +++ b/defaults @@ -53,11 +53,6 @@ gateway_ip_d='ANY_PORT' # the g2 port gateway_port_d=40000 # don't change gateway_ipv6_ip_d='ANY_PORT' gateway_ipv6_port_d=9011 # IANA-approved DStar rouing port -gateway_tolink_d='tolink' # Unix SOCK_SEQPACKET to qnlink -gateway_tomodema_d='tomodema' # Unix SOCK_SEQPACKET to modem on module A -gateway_tomodemb_d='tomodemb' # Unix SOCK_SEQPACKET to modem on module B -gateway_tomodemc_d='tomodemc' # Unix SOCK_SEQPACKET to modem on module C -gateway_fromremote_d='fromremote' # Unix SOCK_DRAM from remote to gateway gateway_latitude_d=0 # you can leave this unspecified for a mobile rig gateway_longitude_d=0 # like the latitude gateway_desc1_d='' # maximum of 20 characters, most special symbols are not allowed