new base classes and back to UnixDgrmSocket

dev
Tom Early 2 years ago
parent 80bec7ff0b
commit c7afc69935

@ -20,17 +20,34 @@
// base class for all modems // base class for all modems
#include <sys/select.h> #include <string>
#include <atomic> #include <atomic>
class CKRBase class CBase
{ {
public: public:
CKRBase(); CBase() { keep_running = true; }
bool IsRunning(); virtual ~CBase() {}
void SetState(bool state); virtual bool Initialize(const std::string &path) = 0;
virtual void Run() = 0;
virtual void Close() = 0;
void Stop() { keep_running = false; }
protected: protected:
static std::atomic<bool> keep_running; std::atomic<bool> keep_running;
static void SigHandler(int sig); void AddFDSet(int &max, int newfd, fd_set *set)
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;
}; };

@ -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 <csignal>
#include <iostream>
#include "KRBase.h"
std::atomic<bool> 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);
}

@ -52,25 +52,25 @@ dvrptr : qndvrptr
itap : qnitap itap : qnitap
modem : qnmodem 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 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 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) g++ -o $@ $^ $(LDFLAGS)
qnitap : QnetITAP.o KRBase.o UnixPacketSock.o QnetConfigure.o qnitap : QnetITAP.o UnixDgramSocket.o QnetConfigure.o
g++ -o $@ $^ $(LDFLAGS) g++ -o $@ $^ $(LDFLAGS)
qnmodem : QnetModem.o KRBase.o UnixPacketSock.o QnetConfigure.o qnmodem : QnetModem.o UnixDgramSocket.o QnetConfigure.o
g++ -o $@ $^ $(LDFLAGS) 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 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) g++ -o $@ $^ $(LDFLAGS)
qnremote : QnetRemote.o UnixDgramSocket.o QnetConfigure.o qnremote : QnetRemote.o UnixDgramSocket.o QnetConfigure.o

@ -40,9 +40,9 @@ char *CQnetConfigure::Trim(char *s)
return s; return s;
} }
bool CQnetConfigure::ReadConfigFile(const char *configfile, std::map<std::string, std::string> &amap) bool CQnetConfigure::ReadConfigFile(const std::string &configfile, std::map<std::string, std::string> &amap)
{ {
FILE *fp = fopen(configfile, "r"); FILE *fp = fopen(configfile.c_str(), "r");
if (fp) if (fp)
{ {
char line[2048]; char line[2048];
@ -69,11 +69,11 @@ bool CQnetConfigure::ReadConfigFile(const char *configfile, std::map<std::string
fclose(fp); fclose(fp);
return false; return false;
} }
fprintf(stderr, "could not open file %s\n", configfile); fprintf(stderr, "could not open file %s\n", configfile.c_str());
return true; return true;
} }
bool CQnetConfigure::Initialize(const char *file) bool CQnetConfigure::Initialize(const std::string &file)
{ {
std::string filename(CFG_DIR); std::string filename(CFG_DIR);
filename.append("/defaults"); filename.append("/defaults");

@ -26,7 +26,7 @@ class CQnetConfigure
public: public:
CQnetConfigure(); CQnetConfigure();
virtual ~CQnetConfigure(); virtual ~CQnetConfigure();
bool Initialize(const char *configfile); bool Initialize(const std::string &path);
bool GetValue(const std::string &path, const std::string &mod, bool &value); bool GetValue(const std::string &path, const std::string &mod, bool &value);
bool GetValue(const std::string &path, const std::string &mod, double &value, const double min, const double max); bool GetValue(const std::string &path, const std::string &mod, double &value, const double min, const double max);
bool GetValue(const std::string &path, const std::string &mod, int &value, const int min, const int max); bool GetValue(const std::string &path, const std::string &mod, int &value, const int min, const int max);
@ -38,7 +38,7 @@ private:
std::map<std::string, std::string> cfg; std::map<std::string, std::string> cfg;
char *Trim(char *s); char *Trim(char *s);
bool ReadConfigFile(const char *file, std::map<std::string, std::string> &amap); bool ReadConfigFile(const std::string &file, std::map<std::string, std::string> &amap);
bool GetDefaultBool (const std::string &key, const std::string &mod, bool &dval); 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 GetDefaultDouble(const std::string &key, const std::string &mod, double &dval);
bool GetDefaultInt (const std::string &key, const std::string &mod, int &dval); bool GetDefaultInt (const std::string &key, const std::string &mod, int &dval);

@ -43,13 +43,12 @@
#include "DVAPDongle.h" #include "DVAPDongle.h"
#include "QnetTypeDefs.h" #include "QnetTypeDefs.h"
#include "Random.h" #include "Random.h"
#include "UnixPacketSock.h"
#include "QnetConfigure.h" #include "QnetConfigure.h"
#include "Timer.h" #include "Timer.h"
#include "DStarDecode.h" #include "DStarDecode.h"
#include "QnetDVAP.h" #include "QnetDVAP.h"
#define DVAP_VERSION "QnetDVAP-40411" #define DVAP_VERSION "QnetDVAP-40417"
#define CALL_SIZE 8 #define CALL_SIZE 8
#define IP_SIZE 15 #define IP_SIZE 15
@ -94,18 +93,18 @@ void CQnetDVAP::calcPFCS(unsigned char *packet, unsigned char *pfcs)
} }
/* process configuration file */ /* process configuration file */
bool CQnetDVAP::ReadConfig(const char *cfgFile) bool CQnetDVAP::ReadConfig(const std::string &cfgFile)
{ {
CQnetConfigure cfg; CQnetConfigure cfg;
printf("Reading file %s\n", cfgFile); printf("Reading file %s\n", cfgFile.c_str());
if (cfg.Initialize(cfgFile)) if (cfg.Initialize(cfgFile))
return true; return true;
const std::string estr; // an empty string const std::string estr; // an empty string
std::string type; std::string type;
std::string dvap_path("module_"); std::string dvap_path("module_");
if (0 > assigned_module) if (0 > m_index)
{ {
// we need to find the lone dvap module // we need to find the lone dvap module
for (int i=0; i<3; i++) for (int i=0; i<3; i++)
@ -118,11 +117,11 @@ bool CQnetDVAP::ReadConfig(const char *cfgFile)
if (type.compare("dvap")) if (type.compare("dvap"))
continue; // this ain't it! continue; // this ain't it!
dvap_path.assign(test); dvap_path.assign(test);
assigned_module = i; m_index = i;
break; break;
} }
} }
if (0 > assigned_module) if (0 > m_index)
{ {
fprintf(stderr, "Error: no 'dvap' module found\n!"); fprintf(stderr, "Error: no 'dvap' module found\n!");
return true; return true;
@ -131,7 +130,7 @@ bool CQnetDVAP::ReadConfig(const char *cfgFile)
else else
{ {
// make sure dvap module is defined // 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)) if (cfg.KeyExists(dvap_path))
{ {
cfg.GetValue(dvap_path, estr, type, 1, 16); cfg.GetValue(dvap_path, estr, type, 1, 16);
@ -143,12 +142,11 @@ bool CQnetDVAP::ReadConfig(const char *cfgFile)
} }
else 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; 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);
if (cfg.KeyExists(dvap_path+"_callsign")) if (cfg.KeyExists(dvap_path+"_callsign"))
{ {
if (cfg.GetValue(dvap_path+"_callsign", type, RPTR, 3, 6)) if (cfg.GetValue(dvap_path+"_callsign", type, RPTR, 3, 6))
@ -233,13 +231,13 @@ void CQnetDVAP::ReadFromGateway()
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = MODULE_PACKET_WAIT; tv.tv_usec = MODULE_PACKET_WAIT;
FD_ZERO (&readfd); FD_ZERO (&readfd);
int fd = ToGate.GetFD(); int fd = FromGate.GetFD();
FD_SET (fd, &readfd); FD_SET (fd, &readfd);
select(fd + 1, &readfd, NULL, NULL, &tv); select(fd + 1, &readfd, NULL, NULL, &tv);
if (FD_ISSET(fd, &readfd)) if (FD_ISSET(fd, &readfd))
{ {
len = ToGate.Read(dsvt.title, 56); len = FromGate.Read(dsvt.title, 56);
if (len == 56) if (len == 56)
{ {
if (busy20000) if (busy20000)
@ -494,7 +492,6 @@ void CQnetDVAP::ReadFromGateway()
break; break;
} }
} }
return;
} }
void CQnetDVAP::RptrAckThread(SDVAP_ACK_ARG *parg) void CQnetDVAP::RptrAckThread(SDVAP_ACK_ARG *parg)
@ -872,13 +869,11 @@ void CQnetDVAP::ReadDVAPThread()
return; return;
} }
bool CQnetDVAP::Init(const char *file, const int amod) bool CQnetDVAP::Initialize(const std::string &file)
{ {
assigned_module = amod;
if (ReadConfig(file)) 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; 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)) if (!dongle.Initialize(MODULE_DEVICE.c_str(), MODULE_SERIAL_NUMBER.c_str(), MODULE_FREQUENCY, MODULE_OFFSET, MODULE_POWER, MODULE_SQUELCH))
return true; 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(); dongle.Stop();
close(serfd); close(serfd);
return true; return true;
} }
name.assign("Modem");
name.append(1, RPTR_MOD);
name.append("2Gate");
ToGate.SetUp(name.c_str());
printf("DVAP opened and initialized!\n"); printf("DVAP opened and initialized!\n");
return false; return false;
} }
@ -923,10 +926,9 @@ bool CQnetDVAP::Init(const char *file, const int amod)
void CQnetDVAP::Run() void CQnetDVAP::Run()
{ {
CTimer ackpoint; CTimer ackpoint;
std::future<void> readthread;
try 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) catch (const std::exception &e)
{ {
@ -972,16 +974,35 @@ void CQnetDVAP::Run()
} }
} }
} }
}
readthread.get(); void CQnetDVAP::Close()
ToGate.Close(); {
m_readThread.get();
FromGate.Close();
printf("QnetDVAP exiting\n"); printf("QnetDVAP exiting\n");
return; return;
} }
int main(int argc, char *argv[]) std::unique_ptr<CQnetDVAP> 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); printf("%s\n", DVAP_VERSION);
if (argc != 2) if (argc != 2)
@ -992,7 +1013,7 @@ int main(int argc, char *argv[])
if ('-' == argv[1][0]) 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("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"); 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; return EXIT_SUCCESS;
@ -1026,9 +1047,26 @@ int main(int argc, char *argv[])
return 1; return 1;
} }
CQnetDVAP dvap; pdvap = std::unique_ptr<CQnetDVAP>(new CQnetDVAP(mod));
if (dvap.Init(argv[1], mod))
if (! pdvap)
{
std::fprintf(stderr, "Could not make a DVAP!\n");
return EXIT_FAILURE; 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; return EXIT_SUCCESS;
} }

@ -21,7 +21,8 @@
#include <future> #include <future>
#include <queue> #include <queue>
#include "KRBase.h" #include "UnixDgramSocket.h"
#include "Base.h"
using SDVAP_ACK_ARG = struct davp_ack_arg_tag using SDVAP_ACK_ARG = struct davp_ack_arg_tag
{ {
@ -29,14 +30,17 @@ using SDVAP_ACK_ARG = struct davp_ack_arg_tag
float ber; float ber;
}; };
class CQnetDVAP : public CKRBase class CQnetDVAP : public CModem
{ {
public: public:
bool Init(const char *file, const int amod); CQnetDVAP(int index) : CModem(index) {}
~CQnetDVAP() {}
bool Initialize(const std::string &path);
void Run(); void Run();
void Close();
private: private:
bool ReadConfig(const char *file); bool ReadConfig(const std::string &path);
void ReadFromGateway(); void ReadFromGateway();
void calcPFCS(unsigned char *packet, unsigned char *pfcs); void calcPFCS(unsigned char *packet, unsigned char *pfcs);
void ReadDVAPThread(); void ReadDVAPThread();
@ -50,11 +54,11 @@ private:
// data // data
std::queue<std::future<void>> m_fqueue; std::queue<std::future<void>> m_fqueue;
int assigned_module; std::future<void> m_readThread;
// unix sockets // unix sockets
std::string togate; CUnixDgramWriter ToGate;
CUnixPacketClient ToGate; CUnixDgramReader FromGate;
/* Default configuration data */ /* Default configuration data */
std::string RPTR; std::string RPTR;
std::string OWNER; std::string OWNER;

@ -34,6 +34,8 @@
#include <termios.h> #include <termios.h>
#include <wchar.h> #include <wchar.h>
#include <sys/file.h> #include <sys/file.h>
#include <csignal>
#include <memory>
#include "Random.h" #include "Random.h"
#include "QnetConfigure.h" #include "QnetConfigure.h"
@ -1248,18 +1250,18 @@ void CQnetDVRPTR::calcPFCS(unsigned char *packet) //Netzwerk CRC
} }
/* process configuration file */ /* process configuration file */
bool CQnetDVRPTR::ReadConfig(const char *cfgFile) bool CQnetDVRPTR::ReadConfig(const std::string &cfgFile)
{ {
CQnetConfigure cfg; CQnetConfigure cfg;
printf("Reading file %s\n", cfgFile); printf("Reading file %s\n", cfgFile.c_str());
if (cfg.Initialize(cfgFile)) if (cfg.Initialize(cfgFile))
return true; return true;
const std::string estr; // an empty string const std::string estr; // an empty string
std::string type; std::string type;
std::string path("module_"); std::string path("module_");
if (0 > assigned_module) if (0 > m_index)
{ {
// we need to find the lone dvrptr module // we need to find the lone dvrptr module
for (int i=0; i<3; i++) for (int i=0; i<3; i++)
@ -1272,11 +1274,11 @@ bool CQnetDVRPTR::ReadConfig(const char *cfgFile)
if (type.compare("dvrptr")) if (type.compare("dvrptr"))
continue; // this ain't it! continue; // this ain't it!
path.assign(test); path.assign(test);
assigned_module = i; m_index = i;
break; break;
} }
} }
if (0 > assigned_module) if (0 > m_index)
{ {
fprintf(stderr, "Error: no 'dvrptr' module found\n!"); fprintf(stderr, "Error: no 'dvrptr' module found\n!");
return true; return true;
@ -1285,7 +1287,7 @@ bool CQnetDVRPTR::ReadConfig(const char *cfgFile)
else else
{ {
// make sure dvrptr module is defined // make sure dvrptr module is defined
path.append(1, 'a' + assigned_module); path.append(1, 'a' + m_index);
if (cfg.KeyExists(path)) if (cfg.KeyExists(path))
{ {
cfg.GetValue(path, estr, type, 1, 16); cfg.GetValue(path, estr, type, 1, 16);
@ -1297,12 +1299,11 @@ bool CQnetDVRPTR::ReadConfig(const char *cfgFile)
} }
else 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; return true;
} }
} }
DVRPTR_MOD = 'A' + assigned_module; DVRPTR_MOD = 'A' + m_index;
cfg.GetValue(std::string("gateway_tomodem")+std::string(1, 'a'+assigned_module), estr, togate, 1, FILENAME_MAX);
std::string call; std::string call;
if (cfg.GetValue("ircddb_login", type, call, 3, 6)) if (cfg.GetValue("ircddb_login", type, call, 3, 6))
@ -1636,7 +1637,7 @@ void CQnetDVRPTR::readFrom20000()
unsigned char ctrl_in = 0x80; unsigned char ctrl_in = 0x80;
bool written_to_q = false; bool written_to_q = false;
int fd = ToGate.GetFD(); int fd = FromGate.GetFD();
while (keep_running) while (keep_running)
{ {
written_to_q = false; written_to_q = false;
@ -1648,7 +1649,7 @@ void CQnetDVRPTR::readFrom20000()
select(fd + 1, &readfd, NULL, NULL, &tv); select(fd + 1, &readfd, NULL, NULL, &tv);
if (FD_ISSET(fd, &readfd)) if (FD_ISSET(fd, &readfd))
{ {
len = ToGate.Read(recv_buf.title, 56); len = FromGate.Read(recv_buf.title, 56);
if (len == 56) if (len == 56)
{ {
if (busy20000) if (busy20000)
@ -1980,67 +1981,11 @@ bool CQnetDVRPTR::check_serial()
return match; 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 <config_file>\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)) 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; return true;
} }
@ -2074,8 +2019,15 @@ bool CQnetDVRPTR::Init(const char *file, int mod)
strcpy(DVCALL_and_MOD, DVCALL); strcpy(DVCALL_and_MOD, DVCALL);
DVCALL_and_MOD[7] = DVRPTR_MOD; 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; return true;
name.assign("Modem");
name.append(1, DVRPTR_MOD);
name.append("2Gate");
ToGate.SetUp(name.c_str());
if (RX_Inverse == true) if (RX_Inverse == true)
{ {
@ -2603,9 +2555,95 @@ void CQnetDVRPTR::Run()
} }
} }
} }
}
ToGate.Close(); void CQnetDVRPTR::Close()
{
FromGate.Close();
printf("dvrptr exiting...\n"); printf("dvrptr exiting...\n");
}
return; std::unique_ptr<CQnetDVRPTR> 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 <config_file>\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<CQnetDVRPTR>(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;
} }

@ -20,10 +20,10 @@
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include "UnixPacketSock.h" #include "UnixDgramSocket.h"
#include "DStarDecode.h" #include "DStarDecode.h"
#include "QnetTypeDefs.h" #include "QnetTypeDefs.h"
#include "KRBase.h" #include "Base.h"
using tambevoicefec = unsigned char[9]; using tambevoicefec = unsigned char[9];
using tambevoice = unsigned char[6]; using tambevoice = unsigned char[6];
@ -35,15 +35,18 @@ using tambevoice = unsigned char[6];
#define GORLAY_MASK12 0xfffff800 // auxiliary vector for testing #define GORLAY_MASK12 0xfffff800 // auxiliary vector for testing
#define GORLAY_GENPOL 0x00000c75 // generator polinomial, g(x) #define GORLAY_GENPOL 0x00000c75 // generator polinomial, g(x)
class CQnetDVRPTR : public CKRBase class CQnetDVRPTR : public CModem
{ {
public: public:
bool Init(const char *file, int assigned_module); CQnetDVRPTR(int index) : CModem(index) {}
~CQnetDVRPTR() {}
bool Initialize(const std::string &file);
void Run(); void Run();
void Close();
private: private:
CDStarDecode decode; CDStarDecode decode;
bool ReadConfig(const char *cfgFile); bool ReadConfig(const std::string &cfgFile);
void readFrom20000(); void readFrom20000();
bool check_serial(); bool check_serial();
void CleanCall(std::string &callsign); 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_STATUS[6]= {0xD0,0x01,0x00,0x10,0x00,0x00}; // Status Abfragr
unsigned char Modem_SERIAL[6]= {0xD0,0x01,0x00,0x12,0x00,0x00}; unsigned char Modem_SERIAL[6]= {0xD0,0x01,0x00,0x12,0x00,0x00};
int assigned_module; CUnixDgramWriter ToGate;
std::string togate; CUnixDgramReader FromGate;
CUnixPacketClient ToGate;
std::string DVRPTR_SERIAL; std::string DVRPTR_SERIAL;
char DVCALL[CALL_SIZE + 1]; char DVCALL[CALL_SIZE + 1];

@ -203,7 +203,7 @@ void CQnetGateway::calcPFCS(unsigned char *packet, int len)
} }
/* process configuration file */ /* process configuration file */
bool CQnetGateway::ReadConfig(char *cfgFile) bool CQnetGateway::ReadConfig(const std::string &cfgFile)
{ {
const std::string estr; // an empty string const std::string estr; // an empty string
CQnetConfigure cfg; 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+"ipv6_port", estr, g2_ipv6_external.port, 1024, 65535);
cfg.GetValue(path+"header_regen", estr, GATEWAY_HEADER_REGEN); cfg.GetValue(path+"header_regen", estr, GATEWAY_HEADER_REGEN);
cfg.GetValue(path+"send_qrgs_maps", estr, GATEWAY_SEND_QRGS_MAP); 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++) for (int m=0; m<3; m++)
{ {
if (Rptr.mod[m].defined) 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+"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+"longitude", estr, Rptr.mod[m].longitude, -180.0, 180.0);
cfg.GetValue(path+"desc1", estr, Rptr.mod[m].desc1, 0, 20); 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! 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 is_quadnet = (std::string::npos != ircddb[i].ip.find(".openquad.net"));
bool doFind = true; bool doFind = true;
while (IsRunning()) while (keep_running)
{ {
int rc = ii[i]->getConnectionState(); int rc = ii[i]->getConnectionState();
if (rc > 5 && rc < 8 && is_quadnet) if (rc > 5 && rc < 8 && is_quadnet)
@ -476,7 +473,7 @@ void CQnetGateway::GetIRCDataThread(const int i)
threshold = 0; threshold = 0;
} }
while (((type = ii[i]->getMessageType()) != IDRT_NONE) && IsRunning()) while (((type = ii[i]->getMessageType()) != IDRT_NONE) && keep_running)
{ {
switch (type) switch (type)
{ {
@ -504,7 +501,7 @@ void CQnetGateway::GetIRCDataThread(const int i)
default: default:
break; break;
} // switch (type) } // switch (type)
} // while (IsRunning()) } // while (keep_running)
std::this_thread::sleep_for(std::chrono::milliseconds(500)); std::this_thread::sleep_for(std::chrono::milliseconds(500));
} }
printf("GetIRCDataThread[%i] exiting...\n", i); printf("GetIRCDataThread[%i] exiting...\n", i);
@ -1148,7 +1145,7 @@ void CQnetGateway::ProcessG2Header(const SDSVT &g2buf, const int source_sock)
if (source_sock >= 0) if (source_sock >= 0)
printf("IP=[%s]:%u\n", fromDstar.GetAddress(), fromDstar.GetPort()); printf("IP=[%s]:%u\n", fromDstar.GetAddress(), fromDstar.GetPort());
else else
printf("UnixSock=%s\n", tolink.c_str()); printf("UnixSock=Link2Gate\n");
} }
lhcallsign[i].assign((const char *)g2buf.hdr.mycall, 8); 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)) 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 */ /* run the main loop for QnetGateway */
void CQnetGateway::Process() void CQnetGateway::Run()
{ {
// dtmf stuff initialize // dtmf stuff initialize
for (int i=0; i<3; i++) for (int i=0; i<3; i++)
@ -2068,16 +2065,16 @@ void CQnetGateway::Process()
catch (const std::exception &e) catch (const std::exception &e)
{ {
printf("Failed to start GetIRCDataThread[%d]. Exception: %s\n", i, e.what()); 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); printf("get_irc_data thread[%d] started\n", i);
ii[i]->kickWatchdog(GW_VERSION); ii[i]->kickWatchdog(GW_VERSION);
} }
} }
while (IsRunning()) while (keep_running)
{ {
if (! m_fqueue.empty()) if (! m_fqueue.empty())
{ {
@ -2105,11 +2102,11 @@ void CQnetGateway::Process()
AddFDSet(max_nfds, g2_sock[0], &fdset); AddFDSet(max_nfds, g2_sock[0], &fdset);
if (g2_sock[1] >= 0) if (g2_sock[1] >= 0)
AddFDSet(max_nfds, g2_sock[1], &fdset); 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++) for (int i=0; i<3; i++)
{ {
if (Rptr.mod[i].defined) 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); AddFDSet(max_nfds, FromRemote.GetFD(), &fdset);
struct timeval tv; struct timeval tv;
@ -2122,7 +2119,7 @@ void CQnetGateway::Process()
{ {
if (g2_sock[i] < 0) if (g2_sock[i] < 0)
continue; continue;
if (IsRunning() && FD_ISSET(g2_sock[i], &fdset)) if (keep_running && FD_ISSET(g2_sock[i], &fdset))
{ {
SDSVT dsvt; SDSVT dsvt;
socklen_t fromlen = sizeof(struct sockaddr_storage); socklen_t fromlen = sizeof(struct sockaddr_storage);
@ -2136,7 +2133,7 @@ void CQnetGateway::Process()
} }
// process packets from qnremote // process packets from qnremote
if (IsRunning() && FD_ISSET(FromRemote.GetFD(), &fdset)) if (keep_running && FD_ISSET(FromRemote.GetFD(), &fdset))
{ {
SDSVT dsvt; SDSVT dsvt;
const ssize_t len = FromRemote.Read(dsvt.title, 56); const ssize_t len = FromRemote.Read(dsvt.title, 56);
@ -2145,10 +2142,10 @@ void CQnetGateway::Process()
} }
// process packets from qnlink // process packets from qnlink
if (IsRunning() && FD_ISSET(ToLink.GetFD(), &fdset)) if (keep_running && FD_ISSET(FromLink.GetFD(), &fdset))
{ {
SDSVT dsvt; 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)) if (16==g2buflen && 0==memcmp(dsvt.title, "LINK", 4))
{ {
SLINKFAMILY fam; SLINKFAMILY fam;
@ -2167,19 +2164,19 @@ void CQnetGateway::Process()
{ {
ProcessG2(g2buflen, dsvt, -1); ProcessG2(g2buflen, dsvt, -1);
} }
FD_CLR(ToLink.GetFD(), &fdset); FD_CLR(FromLink.GetFD(), &fdset);
} }
// process packets coming from local repeater module(s) // process packets coming from local repeater module(s)
for (int i=0; i<3; i++) 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; 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) if (Rptr.mod[i].defined)
ProcessModem(len, dsvt); 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; time_t last_beacon_time = 0;
/* This thread is also saying to the APRS_HOST that we are ALIVE */ /* This thread is also saying to the APRS_HOST that we are ALIVE */
while (IsRunning()) while (keep_running)
{ {
if (aprs->aprs_sock.GetFD() == -1) if (aprs->aprs_sock.GetFD() == -1)
{ {
@ -2302,7 +2299,7 @@ void CQnetGateway::APRSBeaconThread()
printf("APRS Beacon =[%s]\n", snd_buf); printf("APRS Beacon =[%s]\n", snd_buf);
strcat(snd_buf, "\r\n"); strcat(snd_buf, "\r\n");
while (IsRunning()) while (keep_running)
{ {
if (aprs->aprs_sock.GetFD() == -1) if (aprs->aprs_sock.GetFD() == -1)
{ {
@ -2581,7 +2578,7 @@ void CQnetGateway::qrgs_and_maps()
return; return;
} }
bool CQnetGateway::Init(char *cfgfile) bool CQnetGateway::Initialize(const std::string &path)
{ {
short int i; short int i;
@ -2597,9 +2594,9 @@ bool CQnetGateway::Init(char *cfgfile)
} }
/* process configuration file */ /* 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; return true;
} }
@ -2611,20 +2608,28 @@ bool CQnetGateway::Init(char *cfgfile)
qnDB.ClearLH(); qnDB.ClearLH();
// Open unix sockets between qngateway and qnremote // Open unix sockets between qngateway and qnremote
printf("Connecting to qnlink at %s\n", tolink.c_str()); printf("Opening Link2Gate\n");
if (ToLink.Open(tolink.c_str(), this)) if (FromLink.Open("Link2Gate"))
return true; return true;
printf("Opening remote port at %s\n", fromremote.c_str()); ToLink.SetUp("Gate2Link");
if (FromRemote.Open(fromremote.c_str())) printf("Opening Remote2Gate\n");
if (FromRemote.Open("Remote2Gate"))
return true; return true;
for (i=0; i<3; i++) for (i=0; i<3; i++)
{ {
if (Rptr.mod[i].defined) // open unix sockets between qngateway and each defined modem 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()); const char mod = 'A'+i;
if (ToModem[i].Open(tomodem[i].c_str(), this)) 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; return true;
name.assign("Gate2Modem");
name.append(1, mod);
ToModem[i].SetUp(name.c_str());
} }
// recording for echotest on local repeater modules // recording for echotest on local repeater modules
recd[i].last_time = 0; recd[i].last_time = 0;
@ -2714,7 +2719,7 @@ bool CQnetGateway::Init(char *cfgfile)
else else
break; break;
if (!IsRunning()) if (!keep_running)
break; break;
if (i > 5) if (i > 5)
@ -2811,19 +2816,19 @@ bool CQnetGateway::Init(char *cfgfile)
return false; return false;
} }
CQnetGateway::CQnetGateway() CQnetGateway::CQnetGateway() : CBase()
{ {
ii[0] = ii[1] = NULL; ii[0] = ii[1] = NULL;
} }
CQnetGateway::~CQnetGateway() void CQnetGateway::Close()
{ {
ToLink.Close(); FromLink.Close();
FromRemote.Close(); FromRemote.Close();
for (int i=0; i<3; i++) for (int i=0; i<3; i++)
{ {
if (Rptr.mod[i].defined) if (Rptr.mod[i].defined)
ToModem[i].Close(); FromModem[i].Close();
} }
if (APRS_ENABLE) if (APRS_ENABLE)
@ -2864,19 +2869,43 @@ CQnetGateway::~CQnetGateway()
printf("QnetGateway exiting\n"); 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) 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()); printf("VERSION %s\n", GW_VERSION.c_str());
if (argc != 2) if (argc != 2)
{ {
printf("usage: %s qn.cfg\n", argv[0]); printf("usage: %s qn.cfg\n", argv[0]);
return 1; return EXIT_FAILURE;
} }
CQnetGateway QnetGateway; if (QnetGateway.Initialize(argv[1]))
if (QnetGateway.Init(argv[1]))
{ {
return 1; return EXIT_FAILURE;
} }
QnetGateway.Process();
QnetGateway.Run();
QnetGateway.Close();
printf("Leaving processing loop...\n"); printf("Leaving processing loop...\n");
return EXIT_SUCCESS;
} }

@ -25,12 +25,11 @@
#include "QnetTypeDefs.h" #include "QnetTypeDefs.h"
#include "SEcho.h" #include "SEcho.h"
#include "UnixDgramSocket.h" #include "UnixDgramSocket.h"
#include "UnixPacketSock.h"
#include "aprs.h" #include "aprs.h"
#include "SockAddress.h" #include "SockAddress.h"
#include "QnetDB.h" #include "QnetDB.h"
#include "DStarDecode.h" #include "DStarDecode.h"
#include "KRBase.h" #include "Base.h"
#include "Location.h" #include "Location.h"
#define MAXHOSTNAMELEN 64 #define MAXHOSTNAMELEN 64
@ -93,13 +92,13 @@ using SSD = struct sd_tag
void Init() { ih = im = ig = 0; first = true; } void Init() { ih = im = ig = 0; first = true; }
}; };
class CQnetGateway : public CKRBase class CQnetGateway : public CBase
{ {
public: public:
CQnetGateway(); CQnetGateway();
~CQnetGateway(); bool Initialize(const std::string &path);
void Process(); void Run();
bool Init(char *cfgfile); void Close();
private: private:
std::queue<std::future<void>> m_fqueue; std::queue<std::future<void>> m_fqueue;
@ -112,10 +111,8 @@ private:
SPORTIP g2_external, g2_ipv6_external, ircddb[2]; SPORTIP g2_external, g2_ipv6_external, ircddb[2];
CUnixDgramReader FromRemote; CUnixDgramReader FromRemote, FromLink, FromModem[3];
CUnixPacketServer ToLink, ToModem[3]; CUnixDgramWriter ToLink, ToModem[3];
std::string tolink, fromremote, tomodem[3];
std::string OWNER, owner, FILE_DTMF, FILE_ECHOTEST, IRCDDB_PASSWORD[2], FILE_QNVOICE_FILE, DASH_SHOW_ORDER; std::string OWNER, owner, FILE_DTMF, FILE_ECHOTEST, IRCDDB_PASSWORD[2], FILE_QNVOICE_FILE, DASH_SHOW_ORDER;
@ -194,7 +191,6 @@ private:
void APRSBeaconThread(); void APRSBeaconThread();
bool Printable(unsigned char *string); bool Printable(unsigned char *string);
void ProcessTimeouts(); void ProcessTimeouts();
void ProcessSlowData(unsigned char *data, const unsigned short sid);
void ProcessIncomingSD(const SDSVT &dsvt, const int source_sock); void ProcessIncomingSD(const SDSVT &dsvt, const int source_sock);
void ProcessOutGoingSD(const SDSVT &dsvt, const int mod); void ProcessOutGoingSD(const SDSVT &dsvt, const int mod);
bool ProcessG2Msg(const unsigned char *data, const int mod, std::string &smrtgrp); bool ProcessG2Msg(const unsigned char *data, const int mod, std::string &smrtgrp);
@ -207,7 +203,7 @@ private:
int FindIndex(const int i) const; int FindIndex(const int i) const;
// read configuration file // read configuration file
bool ReadConfig(char *); bool ReadConfig(const std::string &path);
void qrgs_and_maps(); void qrgs_and_maps();

@ -39,29 +39,32 @@
#include <errno.h> #include <errno.h>
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#include <memory>
#include "QnetITAP.h" #include "QnetITAP.h"
#include "QnetTypeDefs.h" #include "QnetTypeDefs.h"
#include "QnetConfigure.h" #include "QnetConfigure.h"
#include "Timer.h" #include "Timer.h"
#define ITAP_VERSION "QnetITAP-20307" #define ITAP_VERSION "QnetITAP-40419"
CQnetITAP::CQnetITAP(int mod) bool CQnetITAP::Initialize(const std::string &cfgfile)
: assigned_module(mod)
{
}
CQnetITAP::~CQnetITAP()
{
}
bool CQnetITAP::Initialize(const char *cfgfile)
{ {
if (ReadConfig(cfgfile)) if (ReadConfig(cfgfile))
return true; 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 true;
return false; 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; unsigned int poll_counter = 0;
bool initialized = false; bool initialized = false;
bool alive = true; bool alive = true;
@ -231,10 +223,11 @@ void CQnetITAP::Run(const char *cfgfile)
CTimer pingTimer; CTimer pingTimer;
double pingtime = 0.001; double pingtime = 0.001;
const double ackwait = AP_MODE ? 0.4 : 0.06; const double ackwait = AP_MODE ? 0.4 : 0.06;
int ug2m = FromGate.GetFD();
printf("gate2modem=%d, serial=%d\n", ug2m, serfd);
while (keep_running) while (keep_running)
{ {
fd_set readfds; fd_set readfds;
FD_ZERO(&readfds); FD_ZERO(&readfds);
FD_SET(serfd, &readfds); FD_SET(serfd, &readfds);
@ -357,7 +350,7 @@ void CQnetITAP::Run(const char *cfgfile)
if (keep_running && FD_ISSET(ug2m, &readfds)) if (keep_running && FD_ISSET(ug2m, &readfds))
{ {
ssize_t len = ToGate.Read(buf, 100); ssize_t len = FromGate.Read(buf, 100);
if (len < 0) if (len < 0)
{ {
@ -422,9 +415,12 @@ void CQnetITAP::Run(const char *cfgfile)
} }
} }
} }
}
void CQnetITAP::Close()
{
close(serfd); close(serfd);
ToGate.Close(); FromGate.Close();
} }
void CQnetITAP::SendToIcom(const unsigned char *buf) 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 // 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; CQnetConfigure cfg;
printf("Reading file %s\n", cfgFile); printf("Reading file %s\n", cfgFile.c_str());
if (cfg.Initialize(cfgFile)) if (cfg.Initialize(cfgFile))
return true; return true;
const std::string estr; // an empty string const std::string estr; // an empty string
std::string type; std::string type;
std::string itap_path("module_"); std::string itap_path("module_");
if (0 > assigned_module) if (0 > m_index)
{ {
// we need to find the lone itap module // we need to find the lone itap module
for (int i=0; i<3; i++) for (int i=0; i<3; i++)
@ -623,11 +619,11 @@ bool CQnetITAP::ReadConfig(const char *cfgFile)
if (type.compare("itap")) if (type.compare("itap"))
continue; // this ain't it! continue; // this ain't it!
itap_path.assign(test); itap_path.assign(test);
assigned_module = i; m_index = i;
break; break;
} }
} }
if (0 > assigned_module) if (0 > m_index)
{ {
fprintf(stderr, "Error: no 'itap' module found\n!"); fprintf(stderr, "Error: no 'itap' module found\n!");
return true; return true;
@ -636,7 +632,7 @@ bool CQnetITAP::ReadConfig(const char *cfgFile)
else else
{ {
// make sure itap module is defined // 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)) if (cfg.KeyExists(itap_path))
{ {
cfg.GetValue(itap_path, estr, type, 1, 16); cfg.GetValue(itap_path, estr, type, 1, 16);
@ -648,11 +644,11 @@ bool CQnetITAP::ReadConfig(const char *cfgFile)
} }
else 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; 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+"_device", type, ITAP_DEVICE, 7, FILENAME_MAX);
cfg.GetValue(itap_path+"_ap_mode", type, AP_MODE); cfg.GetValue(itap_path+"_ap_mode", type, AP_MODE);
@ -688,7 +684,6 @@ bool CQnetITAP::ReadConfig(const char *cfgFile)
RPTR.resize(CALL_SIZE, ' '); 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_qso", estr, LOG_QSO);
cfg.GetValue("log_debug", estr, LOG_DEBUG); cfg.GetValue("log_debug", estr, LOG_DEBUG);
return false; return false;
@ -733,8 +728,31 @@ void CQnetITAP::calcPFCS(const unsigned char *packet, unsigned char *pfcs)
return; return;
} }
std::unique_ptr<CQnetITAP> 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) int main(int argc, const char **argv)
{ {
std::signal(SIGINT, SignalHandler);
std::signal(SIGHUP, SignalHandler);
std::signal(SIGTERM, SignalHandler);
setbuf(stdout, NULL); setbuf(stdout, NULL);
if (2 != argc) if (2 != argc)
{ {
@ -744,7 +762,7 @@ int main(int argc, const char **argv)
if ('-' == argv[1][0]) 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("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"); 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; return 0;
@ -778,11 +796,27 @@ int main(int argc, const char **argv)
return 1; return 1;
} }
CQnetITAP qnitap(assigned_module); pitap = std::unique_ptr<CQnetITAP>(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]); printf("%s is closing.\n", argv[0]);
pitap.reset();
return 0; return 0;
} }

@ -25,8 +25,8 @@
#include <netinet/in.h> #include <netinet/in.h>
#include "Random.h" // for streamid generation #include "Random.h" // for streamid generation
#include "UnixPacketSock.h" #include "UnixDgramSocket.h"
#include "KRBase.h" #include "Base.h"
#define CALL_SIZE 8 #define CALL_SIZE 8
#define IP_SIZE 15 #define IP_SIZE 15
@ -105,20 +105,20 @@ private:
SITAP frame; SITAP frame;
}; };
class CQnetITAP : CKRBase class CQnetITAP : public CModem
{ {
public: public:
// functions // functions
CQnetITAP(int mod); CQnetITAP(int mod) : CModem(mod) {}
~CQnetITAP(); ~CQnetITAP() {}
void Run(const char *cfgfile); bool Initialize(const std::string &cfgfile);
void Run();
void Close();
// data // data
private: private:
int assigned_module;
// functions // functions
bool Initialize(const char *cfgfile);
bool ProcessGateway(const int len, const unsigned char *raw); bool ProcessGateway(const int len, const unsigned char *raw);
bool ProcessITAP(const unsigned char *raw); bool ProcessITAP(const unsigned char *raw);
int OpenITAP(); int OpenITAP();
@ -128,7 +128,7 @@ private:
void DumpSerialPacket(const char *title, const unsigned char *); void DumpSerialPacket(const char *title, const unsigned char *);
// read configuration file // read configuration file
bool ReadConfig(const char *); bool ReadConfig(const std::string &path);
// config data // config data
char RPTR_MOD; char RPTR_MOD;
@ -143,8 +143,8 @@ private:
CRandom random; CRandom random;
// unix sockets // unix sockets
std::string togate; CUnixDgramWriter ToGate;
CUnixPacketClient ToGate; CUnixDgramReader FromGate;
// Queue // Queue
std::queue<CFrame> queue; std::queue<CFrame> queue;

@ -56,7 +56,7 @@
#define LINK_VERSION "QnetLink-40411" #define LINK_VERSION "QnetLink-40411"
CQnetLink::CQnetLink() CQnetLink::CQnetLink() : CBase()
{ {
} }
@ -643,12 +643,12 @@ void CQnetLink::PrintCallsigns(const std::string &key, const std::set<std::strin
} }
/* process configuration file */ /* process configuration file */
bool CQnetLink::ReadConfig(const char *cfgFile) bool CQnetLink::ReadConfig(const std::string &cfgFile)
{ {
CQnetConfigure cfg; CQnetConfigure cfg;
const std::string estr; // an empty string const std::string estr; // an empty string
printf("Reading file %s\n", cfgFile); printf("Reading file %s\n", cfgFile.c_str());
if (cfg.Initialize(cfgFile)) if (cfg.Initialize(cfgFile))
return true; return true;
@ -737,8 +737,6 @@ bool CQnetLink::ReadConfig(const char *cfgFile)
saved_max_dongles = max_dongles = (unsigned int)maxdongle; saved_max_dongles = max_dongles = (unsigned int)maxdongle;
key.assign("gateway_"); key.assign("gateway_");
cfg.GetValue(key+"tolink", estr, togate, 1, FILENAME_MAX);
cfg.GetValue("log_qso", estr, qso_details); cfg.GetValue("log_qso", estr, qso_details);
cfg.GetValue("log_debug", estr, log_debug); cfg.GetValue("log_debug", estr, log_debug);
@ -788,12 +786,13 @@ bool CQnetLink::srv_open()
} }
/* create our gateway unix sockets */ /* create our gateway unix sockets */
printf("Connecting to qngateway at %s\n", togate.c_str()); printf("Opening Gate2Link\n");
if (ToGate.Open(togate.c_str(), this)) if (FromGate.Open("Gate2Link"))
{ {
srv_close(); srv_close();
return true; return true;
} }
ToGate.SetUp("Link2Gate");
/* initialize all remote links */ /* initialize all remote links */
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
@ -819,7 +818,7 @@ void CQnetLink::srv_close()
XRFSock4.Close(); XRFSock4.Close();
DCSSock4.Close(); DCSSock4.Close();
REFSock4.Close(); REFSock4.Close();
ToGate.Close(); FromGate.Close();
} }
/* find the repeater IP by callsign and link to it */ /* find the repeater IP by callsign and link to it */
@ -2715,14 +2714,14 @@ void CQnetLink::ProcessREF(unsigned char *buf, const int length)
} }
} }
void CQnetLink::Process() void CQnetLink::Run()
{ {
tnow = 0; tnow = 0;
auto heartbeat = time(NULL); auto heartbeat = time(NULL);
if (uses_ipv6) if (uses_ipv6)
printf("xrf6=%d, dcs6=%d, ref6=%d ", XRFSock6.GetSocket(), DCSSock6.GetSocket(), REFSock6.GetSocket()); printf("xrf6=%d, dcs6=%d, ref6=%d ", XRFSock6.GetSocket(), DCSSock6.GetSocket(), REFSock6.GetSocket());
printf("xrf4=%d, dcs4=%d, ref4=%d, gateway=%d\n", XRFSock4.GetSocket(), DCSSock4.GetSocket(), REFSock4.GetSocket(), ToGate.GetFD()); printf("xrf4=%d, dcs4=%d, ref4=%d, gateway=%d\n", XRFSock4.GetSocket(), DCSSock4.GetSocket(), REFSock4.GetSocket(), FromGate.GetFD());
// initialize all request links // initialize all request links
bool first = true; bool first = true;
@ -2806,7 +2805,7 @@ void CQnetLink::Process()
AddFDSet(max_nfds, DCSSock6.GetSocket(), &fdset); AddFDSet(max_nfds, DCSSock6.GetSocket(), &fdset);
AddFDSet(max_nfds, REFSock6.GetSocket(), &fdset); AddFDSet(max_nfds, REFSock6.GetSocket(), &fdset);
} }
AddFDSet(max_nfds, ToGate.GetFD(), &fdset); AddFDSet(max_nfds, FromGate.GetFD(), &fdset);
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = 20000; tv.tv_usec = 20000;
auto sval = select(max_nfds + 1, &fdset, 0, 0, &tv); auto sval = select(max_nfds + 1, &fdset, 0, 0, &tv);
@ -2868,11 +2867,11 @@ void CQnetLink::Process()
} }
} }
if (keep_running && FD_ISSET(ToGate.GetFD(), &fdset)) if (keep_running && FD_ISSET(FromGate.GetFD(), &fdset))
{ {
unsigned char your[3] = { 'C', 'C', 'C' }; unsigned char your[3] = { 'C', 'C', 'C' };
SDSVT dsvt; SDSVT dsvt;
int length = ToGate.Read(dsvt.title, 56); int length = FromGate.Read(dsvt.title, 56);
if ((length==56 || length==27) && 0==memcmp(dsvt.title,"DSVT", 4U) && dsvt.id==0x20U && (dsvt.config==0x10U || dsvt.config==0x20U)) if ((length==56 || length==27) && 0==memcmp(dsvt.title,"DSVT", 4U) && dsvt.id==0x20U && (dsvt.config==0x10U || dsvt.config==0x20U))
{ {
@ -2880,7 +2879,7 @@ void CQnetLink::Process()
if (length == 56) if (length == 56)
{ {
if (qso_details) if (qso_details)
printf("START from local g2: streamID=%04x, flags=%02x:%02x:%02x, my=%.8s/%.4s, ur=%.8s, rpt1=%.8s, rpt2=%.8s, %d bytes on %s\n", ntohs(dsvt.streamid), dsvt.hdr.flag[0], dsvt.hdr.flag[1], dsvt.hdr.flag[2], dsvt.hdr.mycall, dsvt.hdr.sfx, dsvt.hdr.urcall, dsvt.hdr.rpt1, dsvt.hdr.rpt2, length, togate.c_str()); printf("START from local g2: streamID=%04x, flags=%02x:%02x:%02x, my=%.8s/%.4s, ur=%.8s, rpt1=%.8s, rpt2=%.8s, %d bytes on Gate2Link\n", ntohs(dsvt.streamid), dsvt.hdr.flag[0], dsvt.hdr.flag[1], dsvt.hdr.flag[2], dsvt.hdr.mycall, dsvt.hdr.sfx, dsvt.hdr.urcall, dsvt.hdr.rpt1, dsvt.hdr.rpt2, length);
// save mycall // save mycall
char call[CALL_SIZE + 1]; char call[CALL_SIZE + 1];
@ -3412,7 +3411,7 @@ void CQnetLink::Process()
} }
} }
} }
FD_CLR (ToGate.GetFD(), &fdset); FD_CLR (FromGate.GetFD(), &fdset);
} }
for (int i=0; i<3 && keep_running; i++) for (int i=0; i<3 && keep_running; i++)
{ {
@ -3666,7 +3665,7 @@ void CQnetLink::AudioNotifyThread(SECHO &edata)
return; return;
} }
bool CQnetLink::Init(const char *cfgfile) bool CQnetLink::Initialize(const std::string &cfgfile)
{ {
tzset(); tzset();
setvbuf(stdout, (char *)NULL, _IOLBF, 0); setvbuf(stdout, (char *)NULL, _IOLBF, 0);
@ -3701,7 +3700,7 @@ bool CQnetLink::Init(const char *cfgfile)
/* process configuration file */ /* process configuration file */
if (ReadConfig(cfgfile)) if (ReadConfig(cfgfile))
{ {
printf("Failed to process config file %s\n", cfgfile); printf("Failed to process config file %s\n", cfgfile.c_str());
return true; return true;
} }
// open sqlite // open sqlite
@ -3750,7 +3749,7 @@ bool CQnetLink::Init(const char *cfgfile)
return false; return false;
} }
void CQnetLink::Shutdown() void CQnetLink::Close()
{ {
char unlink_request[CALL_SIZE + 3]; char unlink_request[CALL_SIZE + 3];
char cmd_2_dcs[19]; char cmd_2_dcs[19];
@ -3810,18 +3809,44 @@ void CQnetLink::Shutdown()
return; return;
} }
CQnetLink qnlink;
static void SignalHandler(int sig)
{
switch (sig)
{
case SIGINT:
case SIGHUP:
case SIGTERM:
qnlink.Stop();
break;
default:
fprintf(stderr, "Caught an unknown signal: %d\n", sig);
break;
}
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
std::signal(SIGINT, SignalHandler);
std::signal(SIGHUP, SignalHandler);
std::signal(SIGTERM, SignalHandler);
if (argc != 2) if (argc != 2)
{ {
printf("Usage: %s configuration_file\n", argv[0]); printf("Usage: %s configuration_file\n", argv[0]);
return 1; return EXIT_FAILURE;
} }
CQnetLink qnlink;
if (qnlink.Init(argv[1])) if (qnlink.Initialize(argv[1]))
return 1; return EXIT_FAILURE;
printf("QnetLink %s initialized...entering processing loop\n", LINK_VERSION); printf("QnetLink %s initialized...entering processing loop\n", LINK_VERSION);
qnlink.Process();
qnlink.Run();
printf("QnetLink exiting\n"); printf("QnetLink exiting\n");
qnlink.Shutdown();
qnlink.Close();
return EXIT_SUCCESS;
} }

@ -30,12 +30,12 @@
#include "QnetTypeDefs.h" #include "QnetTypeDefs.h"
#include "SEcho.h" #include "SEcho.h"
#include "Random.h" #include "Random.h"
#include "UnixPacketSock.h" #include "UnixDgramSocket.h"
#include "UDPSocket.h" #include "UDPSocket.h"
#include "UDPSocket.h" #include "UDPSocket.h"
#include "Timer.h" #include "Timer.h"
#include "QnetDB.h" #include "QnetDB.h"
#include "KRBase.h" #include "Base.h"
/*** version number must be x.xx ***/ /*** version number must be x.xx ***/
#define CALL_SIZE 8 #define CALL_SIZE 8
@ -80,15 +80,15 @@ using STRACING = struct tracing_tag
}; };
class CQnetLink : CKRBase class CQnetLink : public CBase
{ {
public: public:
// functions // functions
CQnetLink(); CQnetLink();
~CQnetLink(); ~CQnetLink();
bool Init(const char *cfgfile); bool Initialize(const std::string &path);
void Process(); void Run();
void Shutdown(); void Close();
private: private:
// functions // functions
void ToUpper(std::string &s); void ToUpper(std::string &s);
@ -96,7 +96,7 @@ private:
void PrintCallsigns(const std::string &key, const std::set<std::string> &set); void PrintCallsigns(const std::string &key, const std::set<std::string> &set);
void LoadGateways(const std::string &filename); void LoadGateways(const std::string &filename);
void calcPFCS(unsigned char *packet, int len); void calcPFCS(unsigned char *packet, int len);
bool ReadConfig(const char *); bool ReadConfig(const std::string &path);
bool srv_open(); bool srv_open();
void srv_close(); void srv_close();
void g2link(const char from_mod, const char *call, const char to_mod); void g2link(const char from_mod, const char *call, const char to_mod);
@ -163,8 +163,8 @@ private:
CSockAddress fromDst4; CSockAddress fromDst4;
// unix sockets to gateway // unix sockets to gateway
std::string togate; CUnixDgramWriter ToGate;
CUnixPacketClient ToGate; CUnixDgramReader FromGate;
struct timeval tv; struct timeval tv;

@ -40,6 +40,7 @@
#include <errno.h> #include <errno.h>
#include <thread> #include <thread>
#include <chrono> #include <chrono>
#include <memory>
#include "QnetModem.h" #include "QnetModem.h"
#include "QnetConfigure.h" #include "QnetConfigure.h"
@ -65,16 +66,6 @@ const unsigned char TYPE_EOT = 0x13U;
const unsigned char TYPE_ACK = 0x70U; const unsigned char TYPE_ACK = 0x70U;
const unsigned char TYPE_NACK = 0x7FU; const unsigned char TYPE_NACK = 0x7FU;
CQnetModem::CQnetModem(int mod)
: assigned_module(mod)
, dstarSpace(0U)
{
}
CQnetModem::~CQnetModem()
{
}
bool CQnetModem::VoicePacketIsSync(const unsigned char *text) bool CQnetModem::VoicePacketIsSync(const unsigned char *text)
{ {
return *text==0x55U && *(text+1)==0x2DU && *(text+2)==0x16U; return *text==0x55U && *(text+1)==0x2DU && *(text+2)==0x16U;
@ -221,14 +212,20 @@ bool CQnetModem::SetFrequency()
return false; return false;
} }
bool CQnetModem::Initialize(const char *cfgfile) bool CQnetModem::Initialize(const std::string &cfgfile)
{ {
if (ReadConfig(cfgfile)) if (ReadConfig(cfgfile))
return true; return true;
printf("Connecting to qngateway at %s\n", togate.c_str()); std::string name("Gate2Modem");
if (ToGate.Open(togate.c_str(), this)) name.append(1, RPTR_MOD);
printf("Opening %s\n", name.c_str());
if (FromGate.Open(name.c_str()))
return true; return true;
name.assign("Modem");
name.append(1, RPTR_MOD);
name.append("2Gate");
ToGate.SetUp(name.c_str());
serfd = OpenModem(); serfd = OpenModem();
if (serfd < 0) 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)) int ug2m = FromGate.GetFD();
return;
int ug2m = ToGate.GetFD();
printf("gate2modem=%d, serial=%d\n", ug2m, serfd); printf("gate2modem=%d, serial=%d\n", ug2m, serfd);
keep_running = true; keep_running = true;
@ -540,7 +534,7 @@ void CQnetModem::Run(const char *cfgfile)
if (keep_running && FD_ISSET(ug2m, &readfds)) if (keep_running && FD_ISSET(ug2m, &readfds))
{ {
SDSVT dsvt; SDSVT dsvt;
ssize_t len = ToGate.Read(dsvt.title, sizeof(SDSVT)); ssize_t len = FromGate.Read(dsvt.title, sizeof(SDSVT));
if (len <= 0) if (len <= 0)
{ {
@ -594,8 +588,12 @@ void CQnetModem::Run(const char *cfgfile)
} }
} }
} }
}
void CQnetModem::Close()
{
close(serfd); close(serfd);
ToGate.Close(); FromGate.Close();
} }
int CQnetModem::SendToModem(const unsigned char *buf) 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 // 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; CQnetConfigure cfg;
printf("Reading file %s\n", cfgFile); printf("Reading file %s\n", cfgFile.c_str());
if (cfg.Initialize(cfgFile)) if (cfg.Initialize(cfgFile))
return true; return true;
const std::string estr; // an empty string const std::string estr; // an empty string
std::string type; std::string type;
std::string modem_path("module_"); std::string modem_path("module_");
if (0 > assigned_module) if (0 > m_index)
{ {
// we need to find the lone mmdvmmodem module // we need to find the lone mmdvmmodem module
for (int i=0; i<3; i++) for (int i=0; i<3; i++)
@ -844,11 +842,11 @@ bool CQnetModem::ReadConfig(const char *cfgFile)
if (type.compare("mmdvmmodem")) if (type.compare("mmdvmmodem"))
continue; // this ain't it! continue; // this ain't it!
modem_path.assign(test); modem_path.assign(test);
assigned_module = i; m_index = i;
break; break;
} }
} }
if (0 > assigned_module) if (0 > m_index)
{ {
fprintf(stderr, "Error: no 'mmdvmmodem' module found\n!"); fprintf(stderr, "Error: no 'mmdvmmodem' module found\n!");
return true; return true;
@ -857,7 +855,7 @@ bool CQnetModem::ReadConfig(const char *cfgFile)
else else
{ {
// make sure mmdvmmodem module is defined // 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)) if (cfg.KeyExists(modem_path))
{ {
cfg.GetValue(modem_path, estr, type, 1, 16); cfg.GetValue(modem_path, estr, type, 1, 16);
@ -869,14 +867,13 @@ bool CQnetModem::ReadConfig(const char *cfgFile)
} }
else 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; 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(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)) if (cfg.GetValue(modem_path+"_tx_frequency", type, TX_FREQUENCY, 1.0, 6000.0))
return true; // we have to have a valid frequency return true; // we have to have a valid frequency
@ -933,6 +930,25 @@ bool CQnetModem::ReadConfig(const char *cfgFile)
return false; return false;
} }
std::unique_ptr<CQnetModem> 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) int main(int argc, const char **argv)
{ {
setbuf(stdout, NULL); setbuf(stdout, NULL);
@ -944,7 +960,7 @@ int main(int argc, const char **argv)
if ('-' == argv[1][0]) 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("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("This is free software, and you are welcome to distribute it\n");
printf("under certain conditions that are discussed in the LICENSE file.\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; qn += 7;
int assigned_module; int mod;
switch (*qn) switch (*qn)
{ {
case 0: case 0:
assigned_module = -1; mod = -1;
break; break;
case 'a': case 'a':
assigned_module = 0; mod = 0;
break; break;
case 'b': case 'b':
assigned_module = 1; mod = 1;
break; break;
case 'c': case 'c':
assigned_module = 2; mod = 2;
break; break;
default: default:
fprintf(stderr, "assigned module must be a, b or c\n"); fprintf(stderr, "assigned module must be a, b or c\n");
return 1; return 1;
} }
CQnetModem qnmodem(assigned_module); pmodem = std::unique_ptr<CQnetModem>(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]); printf("%s is closing.\n", argv[0]);
return 0; return EXIT_SUCCESS;
} }

@ -24,10 +24,10 @@
#include <netinet/in.h> #include <netinet/in.h>
#include "Random.h" // for streamid generation #include "Random.h" // for streamid generation
#include "UnixPacketSock.h" #include "UnixDgramSocket.h"
#include "QnetTypeDefs.h" #include "QnetTypeDefs.h"
#include "Timer.h" #include "Timer.h"
#include "KRBase.h" #include "Base.h"
#define CALL_SIZE 8 #define CALL_SIZE 8
#define IP_SIZE 15 #define IP_SIZE 15
@ -193,21 +193,21 @@ private:
SMODEM frame; SMODEM frame;
}; };
class CQnetModem : CKRBase class CQnetModem : public CModem
{ {
public: public:
// functions // functions
CQnetModem(int mod); CQnetModem(int mod) : CModem(mod), dstarSpace(0) {}
~CQnetModem(); ~CQnetModem() {}
void Run(const char *cfgfile); bool Initialize(const std::string &cfgfile);
void Run();
void Close();
private: private:
int assigned_module;
unsigned int dstarSpace; unsigned int dstarSpace;
// functions // functions
bool VoicePacketIsSync(const unsigned char *); bool VoicePacketIsSync(const unsigned char *);
bool Initialize(const char *cfgfile);
void ProcessGateway(const SDSVT &dsvt); void ProcessGateway(const SDSVT &dsvt);
bool ProcessModem(const SMODEM &frame); bool ProcessModem(const SMODEM &frame);
int OpenModem(); int OpenModem();
@ -219,7 +219,7 @@ private:
bool SetConfiguration(); bool SetConfiguration();
// read configuration file // read configuration file
bool ReadConfig(const char *); bool ReadConfig(const std::string &path);
// config data // config data
char RPTR_MOD; char RPTR_MOD;
@ -238,8 +238,8 @@ private:
CTimer PacketWait; CTimer PacketWait;
// unix sockets // unix sockets
std::string togate; CUnixDgramWriter ToGate;
CUnixPacketClient ToGate; CUnixDgramReader FromGate;
// Queue // Queue
std::queue<CFrame> queue; std::queue<CFrame> queue;

@ -22,6 +22,7 @@
#include <cstring> #include <cstring>
#include <csignal> #include <csignal>
#include <ctime> #include <ctime>
#include <memory>
#include <cstdlib> #include <cstdlib>
#include <netdb.h> #include <netdb.h>
#include <sys/time.h> #include <sys/time.h>
@ -38,21 +39,24 @@
#define RELAY_VERSION "QnetRelay-20307" #define RELAY_VERSION "QnetRelay-20307"
CQnetRelay::CQnetRelay(int mod) : bool CQnetRelay::Initialize(const std::string &cfgfile)
assigned_module(mod),
seed(time(NULL)),
COUNTER(0)
{ {
} 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) std::string name("Gate2Modem");
{ name.append(1, RPTR_MOD);
if (ReadConfig(cfgfile)) printf("Opening %s\n", name.c_str());
if (FromGate.Open(name.c_str()))
return true; return true;
name.assign("Modem");
name.append(1, RPTR_MOD);
name.append("2Gate");
ToGate.SetUp(name.c_str());
return false; return false;
} }
@ -107,19 +111,9 @@ int CQnetRelay::OpenSocket(const std::string &address, unsigned short port)
return fd; return fd;
} }
bool CQnetRelay::Run(const char *cfgfile) void CQnetRelay::Run()
{ {
if (Initialize(cfgfile)) int fd = FromGate.GetFD();
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();
printf("msock=%d, gateway=%d\n", msock, fd); printf("msock=%d, gateway=%d\n", msock, fd);
@ -168,7 +162,7 @@ bool CQnetRelay::Run(const char *cfgfile)
if (FD_ISSET(fd, &readfds)) if (FD_ISSET(fd, &readfds))
{ {
len = ToGate.Read(buf, 100); len = FromGate.Read(buf, 100);
if (len < 0) 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); fprintf(stderr, "DEBUG: Run: received unknow packet '%s' len=%d\n", title, (int)len);
} }
} }
}
void CQnetRelay::Close()
{
::close(msock); ::close(msock);
ToGate.Close(); FromGate.Close();
return false;
} }
int CQnetRelay::SendTo(const int fd, const unsigned char *buf, const int size, const std::string &address, const unsigned short port) 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 // 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; CQnetConfigure cfg;
printf("Reading file %s\n", cfgFile); printf("Reading file %s\n", cfgFile.c_str());
if (cfg.Initialize(cfgFile)) if (cfg.Initialize(cfgFile))
return true; return true;
@ -382,7 +378,7 @@ bool CQnetRelay::ReadConfig(const char *cfgFile)
std::string mmdvm_path("module_"); std::string mmdvm_path("module_");
std::string type; std::string type;
if (0 > assigned_module) if (0 > m_index)
{ {
// we need to find the lone mmdvmhost module // we need to find the lone mmdvmhost module
for (int i=0; i<3; i++) for (int i=0; i<3; i++)
@ -395,11 +391,11 @@ bool CQnetRelay::ReadConfig(const char *cfgFile)
if (type.compare("mmdvmhost")) if (type.compare("mmdvmhost"))
continue; // this ain't it! continue; // this ain't it!
mmdvm_path.assign(test); mmdvm_path.assign(test);
assigned_module = i; m_index = i;
break; break;
} }
} }
if (0 > assigned_module) if (0 > m_index)
{ {
fprintf(stderr, "Error: no 'mmdvmhost' module found\n!"); fprintf(stderr, "Error: no 'mmdvmhost' module found\n!");
return true; return true;
@ -408,7 +404,7 @@ bool CQnetRelay::ReadConfig(const char *cfgFile)
else else
{ {
// make sure mmdvmhost module is defined // 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)) if (cfg.KeyExists(mmdvm_path))
{ {
cfg.GetValue(mmdvm_path, estr, type, 1, 16); cfg.GetValue(mmdvm_path, estr, type, 1, 16);
@ -420,13 +416,12 @@ bool CQnetRelay::ReadConfig(const char *cfgFile)
} }
else 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; 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+"_internal_ip", type, MMDVM_INTERNAL_IP, 7, IP_SIZE);
cfg.GetValue(mmdvm_path+"_target_ip", type, MMDVM_TARGET_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; return false;
} }
std::unique_ptr<CQnetRelay> 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) int main(int argc, const char **argv)
{ {
setbuf(stdout, NULL); setbuf(stdout, NULL);
@ -453,7 +467,7 @@ int main(int argc, const char **argv)
if ('-' == argv[1][0]) 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("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"); 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; return 0;
@ -486,11 +500,25 @@ int main(int argc, const char **argv)
return 1; return 1;
} }
CQnetRelay qnmmdvm(module); prelay = std::unique_ptr<CQnetRelay>(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]); printf("%s is closing.\n", argv[0]);
return trouble ? 1 : 0; return EXIT_SUCCESS;
} }

@ -22,35 +22,35 @@
#include <string> #include <string>
#include <netinet/in.h> #include <netinet/in.h>
#include "UnixPacketSock.h" #include "UnixDgramSocket.h"
#include "KRBase.h" #include "Base.h"
#define CALL_SIZE 8 #define CALL_SIZE 8
#define IP_SIZE 15 #define IP_SIZE 15
class CQnetRelay : CKRBase class CQnetRelay : public CModem
{ {
public: public:
// functions // functions
CQnetRelay(int mod); CQnetRelay(int mod) : CModem(mod), seed(time(NULL)), COUNTER(0) {}
~CQnetRelay(); ~CQnetRelay() {}
bool Run(const char *cfgfile); bool Initialize(const std::string &cfgfile);
void Run();
void Close();
private: private:
// functions // functions
bool Initialize(const char *cfgfile);
bool ProcessGateway(const int len, const unsigned char *raw); bool ProcessGateway(const int len, const unsigned char *raw);
bool ProcessMMDVM(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 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); int SendTo(const int fd, const unsigned char *buf, const int size, const std::string &address, const unsigned short port);
// read configuration file // read configuration file
bool ReadConfig(const char *); bool ReadConfig(const std::string &);
// Unix sockets // Unix sockets
int assigned_module; CUnixDgramWriter ToGate;
std::string togate; CUnixDgramReader FromGate;
CUnixPacketClient ToGate;
// config data // config data
char RPTR_MOD; char RPTR_MOD;

@ -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 <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <unistd.h>
#include <sys/un.h>
#include <sys/socket.h>
#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;
}
}

@ -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 <sys/types.h>
#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();
};

@ -53,11 +53,6 @@ gateway_ip_d='ANY_PORT' # the g2 port
gateway_port_d=40000 # don't change gateway_port_d=40000 # don't change
gateway_ipv6_ip_d='ANY_PORT' gateway_ipv6_ip_d='ANY_PORT'
gateway_ipv6_port_d=9011 # IANA-approved DStar rouing 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_latitude_d=0 # you can leave this unspecified for a mobile rig
gateway_longitude_d=0 # like the latitude gateway_longitude_d=0 # like the latitude
gateway_desc1_d='' # maximum of 20 characters, most special symbols are not allowed gateway_desc1_d='' # maximum of 20 characters, most special symbols are not allowed

Loading…
Cancel
Save

Powered by TurnKey Linux.