#21 make it a real daemon

pull/32/head
Geoffrey Merck 4 years ago
parent 88f51f75b3
commit 75abc130c1

@ -25,6 +25,8 @@
#include <vector> #include <vector>
#include <signal.h> #include <signal.h>
#include <exception> #include <exception>
#include <cassert>
#include <unistd.h>
#ifdef DEBUG_DSTARGW #ifdef DEBUG_DSTARGW
#include <boost/stacktrace.hpp> #include <boost/stacktrace.hpp>
#endif #endif
@ -45,6 +47,7 @@
#include "LogConsoleTarget.h" #include "LogConsoleTarget.h"
#include "APRSGPSDIdFrameProvider.h" #include "APRSGPSDIdFrameProvider.h"
#include "APRSFixedIdFrameProvider.h" #include "APRSFixedIdFrameProvider.h"
#include "Daemon.h"
CDStarGatewayApp * CDStarGatewayApp::g_app = nullptr; CDStarGatewayApp * CDStarGatewayApp::g_app = nullptr;
@ -70,16 +73,52 @@ int main(int argc, char *argv[])
return 1; return 1;
} }
if ('-' == argv[1][0]) {
printf("\n%s Copyright (C) %s\n", FULL_PRODUCT_NAME.c_str(), VENDOR_NAME.c_str()); printf("\n%s Copyright (C) %s\n", FULL_PRODUCT_NAME.c_str(), VENDOR_NAME.c_str());
printf("DStarGateway comes with ABSOLUTELY NO WARRANTY; see the LICENSE for details.\n"); printf("DStarGateway 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\n"); printf("This is free software, and you are welcome to distribute it\nunder certain conditions that are discussed in the LICENSE file.\n\n");
if ('-' == argv[1][0]) {
return 0; return 0;
} }
std::string cfgFile(argv[1]); CDStarGatewayConfig * config = new CDStarGatewayConfig(std::string((argv[1])));
if(!config->load()) {
CLog::logFatal("Invalid configuration, aborting");
return false;
}
TDaemon daemon;
config->getGeneral(daemon);
if (daemon.daemon) {
CLog::logInfo("Configured as a daemon, detaching ...");
auto res = CDaemon::daemonize(daemon.pidFile);
CDStarGatewayApp gateway(cfgFile); switch (res)
{
case DR_PARENT:
return 0;
case DR_CHILD:
break;
case DR_PIDFILE_FAILED:
break;
case DR_FAILURE:
[[fallthrough]];
default:
CLog::logFatal("Fork failed, exiting");
delete config;
return 1;
}
}
// Setup Log
TLog logConf;
config->getLog(logConf);
CLog::finalise();
if(logConf.m_displayLevel != LOG_NONE && !daemon.daemon) CLog::addTarget(new CLogConsoleTarget(logConf.m_displayLevel));
if(logConf.m_fileLevel != LOG_NONE) CLog::addTarget(new CLogFileTarget(logConf.m_fileLevel, logConf.logDir, logConf.m_fileRotate));
CDStarGatewayApp gateway(config);
if (!gateway.init()) { if (!gateway.init()) {
return 1; return 1;
@ -87,22 +126,30 @@ int main(int argc, char *argv[])
gateway.run(); gateway.run();
if(daemon.daemon) {
CDaemon::finalize();
}
return 0; return 0;
} }
CDStarGatewayApp::CDStarGatewayApp(const std::string &configFile) : m_configFile(configFile), m_thread(NULL) CDStarGatewayApp::CDStarGatewayApp(CDStarGatewayConfig * config) :
m_config(config),
m_thread(NULL)
{ {
assert(config != nullptr);
g_app = this; g_app = this;
} }
CDStarGatewayApp::~CDStarGatewayApp() CDStarGatewayApp::~CDStarGatewayApp()
{ {
delete m_config;
delete m_thread;
} }
bool CDStarGatewayApp::init() bool CDStarGatewayApp::init()
{ {
return createThread(); return createThread();
//2021-12-31 F4FXL This is ugly, if we failed to create the thread we do not clean up ... :(
} }
void CDStarGatewayApp::run() void CDStarGatewayApp::run()
@ -115,30 +162,18 @@ void CDStarGatewayApp::run()
bool CDStarGatewayApp::createThread() bool CDStarGatewayApp::createThread()
{ {
printf("\n%s Copyright (C) %s\n", FULL_PRODUCT_NAME.c_str(), VENDOR_NAME.c_str()); // Log
printf("DStarGateway 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\n");
CDStarGatewayConfig config(m_configFile);
if(!config.load()) {
CLog::logFatal("Invalid configuration, aborting");
return false;
}
// Setup Log
TLog log; TLog log;
config.getLog(log); m_config->getLog(log);
CLog::finalise();
if(log.m_displayLevel != LOG_NONE) CLog::addTarget(new CLogConsoleTarget(log.m_displayLevel));
if(log.m_fileLevel != LOG_NONE) CLog::addTarget(new CLogFileTarget(log.m_fileLevel, log.logDir, log.m_fileRotate));
// Paths
Tpaths paths; Tpaths paths;
config.getPaths(paths); m_config->getPaths(paths);
m_thread = new CDStarGatewayThread(log.logDir, paths.dataDir, ""); m_thread = new CDStarGatewayThread(log.logDir, paths.dataDir, "");
// Setup the gateway // Setup the gateway
TGateway gatewayConfig; TGateway gatewayConfig;
config.getGateway(gatewayConfig); m_config->getGateway(gatewayConfig);
m_thread->setGateway(gatewayConfig.type, gatewayConfig.callsign, gatewayConfig.address); m_thread->setGateway(gatewayConfig.type, gatewayConfig.callsign, gatewayConfig.address);
m_thread->setLanguage(gatewayConfig.language); m_thread->setLanguage(gatewayConfig.language);
m_thread->setLocation(gatewayConfig.latitude, gatewayConfig.longitude); m_thread->setLocation(gatewayConfig.latitude, gatewayConfig.longitude);
@ -146,12 +181,12 @@ bool CDStarGatewayApp::createThread()
#ifdef USE_GPSD #ifdef USE_GPSD
// Setup GPSD // Setup GPSD
TGPSD gpsdConfig; TGPSD gpsdConfig;
config.getGPSD(gpsdConfig); m_config->getGPSD(gpsdConfig);
#endif #endif
// Setup APRS // Setup APRS
TAPRS aprsConfig; TAPRS aprsConfig;
config.getAPRS(aprsConfig); m_config->getAPRS(aprsConfig);
CAPRSHandler * aprsWriter = NULL; CAPRSHandler * aprsWriter = NULL;
if(aprsConfig.enabled && !aprsConfig.password.empty()) { if(aprsConfig.enabled && !aprsConfig.password.empty()) {
aprsWriter = new CAPRSHandler(aprsConfig.hostname, aprsConfig.port, gatewayConfig.callsign, aprsConfig.password, gatewayConfig.address); aprsWriter = new CAPRSHandler(aprsConfig.hostname, aprsConfig.port, gatewayConfig.callsign, aprsConfig.password, gatewayConfig.address);
@ -176,9 +211,9 @@ bool CDStarGatewayApp::createThread()
bool ddEnabled = false; bool ddEnabled = false;
bool atLeastOneRepeater = false; bool atLeastOneRepeater = false;
CRepeaterProtocolHandlerFactory repeaterProtocolFactory; CRepeaterProtocolHandlerFactory repeaterProtocolFactory;
for(unsigned int i = 0U; i < config.getRepeaterCount(); i++) { for(unsigned int i = 0U; i < m_config->getRepeaterCount(); i++) {
TRepeater rptrConfig; TRepeater rptrConfig;
config.getRepeater(i, rptrConfig); m_config->getRepeater(i, rptrConfig);
auto repeaterProtocolHandler = repeaterProtocolFactory.getRepeaterProtocolHandler(rptrConfig.hwType, gatewayConfig, rptrConfig.address, rptrConfig.port); auto repeaterProtocolHandler = repeaterProtocolFactory.getRepeaterProtocolHandler(rptrConfig.hwType, gatewayConfig, rptrConfig.address, rptrConfig.port);
if(repeaterProtocolHandler == nullptr) if(repeaterProtocolHandler == nullptr)
continue; continue;
@ -221,9 +256,9 @@ bool CDStarGatewayApp::createThread()
// Setup ircddb // Setup ircddb
auto ircddbVersionInfo = "linux_" + PRODUCT_NAME + "-" + VERSION; auto ircddbVersionInfo = "linux_" + PRODUCT_NAME + "-" + VERSION;
std::vector<CIRCDDB *> clients; std::vector<CIRCDDB *> clients;
for(unsigned int i=0; i < config.getIrcDDBCount(); i++) { for(unsigned int i=0; i < m_config->getIrcDDBCount(); i++) {
TircDDB ircDDBConfig; TircDDB ircDDBConfig;
config.getIrcDDB(i, ircDDBConfig); m_config->getIrcDDB(i, ircDDBConfig);
CLog::logInfo("ircDDB Network %d set to %s user: %s, Quadnet %d", i + 1,ircDDBConfig.hostname.c_str(), ircDDBConfig.username.c_str(), ircDDBConfig.isQuadNet); CLog::logInfo("ircDDB Network %d set to %s user: %s, Quadnet %d", i + 1,ircDDBConfig.hostname.c_str(), ircDDBConfig.username.c_str(), ircDDBConfig.isQuadNet);
CIRCDDB * ircDDB = new CIRCDDBClient(ircDDBConfig.hostname, 9007U, ircDDBConfig.username, ircDDBConfig.password, ircddbVersionInfo, gatewayConfig.address, ircDDBConfig.isQuadNet); CIRCDDB * ircDDB = new CIRCDDBClient(ircDDBConfig.hostname, 9007U, ircDDBConfig.username, ircDDBConfig.password, ircddbVersionInfo, gatewayConfig.address, ircDDBConfig.isQuadNet);
clients.push_back(ircDDB); clients.push_back(ircDDB);
@ -240,31 +275,31 @@ bool CDStarGatewayApp::createThread()
// Setup Dextra // Setup Dextra
TDextra dextraConfig; TDextra dextraConfig;
config.getDExtra(dextraConfig); m_config->getDExtra(dextraConfig);
CLog::logInfo("DExtra enabled: %d, max. dongles: %u", int(dextraConfig.enabled), dextraConfig.maxDongles); CLog::logInfo("DExtra enabled: %d, max. dongles: %u", int(dextraConfig.enabled), dextraConfig.maxDongles);
m_thread->setDExtra(dextraConfig.enabled, dextraConfig.maxDongles); m_thread->setDExtra(dextraConfig.enabled, dextraConfig.maxDongles);
// Setup DCS // Setup DCS
TDCS dcsConfig; TDCS dcsConfig;
config.getDCS(dcsConfig); m_config->getDCS(dcsConfig);
CLog::logInfo("DCS enabled: %d", int(dcsConfig.enabled)); CLog::logInfo("DCS enabled: %d", int(dcsConfig.enabled));
m_thread->setDCS(dcsConfig.enabled); m_thread->setDCS(dcsConfig.enabled);
// Setup DPlus // Setup DPlus
TDplus dplusConfig; TDplus dplusConfig;
config.getDPlus(dplusConfig); m_config->getDPlus(dplusConfig);
CLog::logInfo("D-Plus enabled: %d, max. dongles: %u, login: %s", int(dplusConfig.enabled), dplusConfig.maxDongles, dplusConfig.login.c_str()); CLog::logInfo("D-Plus enabled: %d, max. dongles: %u, login: %s", int(dplusConfig.enabled), dplusConfig.maxDongles, dplusConfig.login.c_str());
m_thread->setDPlus(dplusConfig.enabled, dplusConfig.maxDongles, dplusConfig.login); m_thread->setDPlus(dplusConfig.enabled, dplusConfig.maxDongles, dplusConfig.login);
// Setup XLX // Setup XLX
TXLX xlxConfig; TXLX xlxConfig;
config.getXLX(xlxConfig); m_config->getXLX(xlxConfig);
CLog::logInfo("XLX enabled: %d, Hosts file url: %s", int(xlxConfig.enabled), xlxConfig.url.c_str()); CLog::logInfo("XLX enabled: %d, Hosts file url: %s", int(xlxConfig.enabled), xlxConfig.url.c_str());
m_thread->setXLX(xlxConfig.enabled, xlxConfig.enabled ? CXLXHostsFileDownloader::download(xlxConfig.url) : ""); m_thread->setXLX(xlxConfig.enabled, xlxConfig.enabled ? CXLXHostsFileDownloader::download(xlxConfig.url) : "");
// Setup Remote // Setup Remote
TRemote remoteConfig; TRemote remoteConfig;
config.getRemote(remoteConfig); m_config->getRemote(remoteConfig);
CLog::logInfo("Remote enabled: %d, port %u", int(remoteConfig.enabled), remoteConfig.port); CLog::logInfo("Remote enabled: %d, port %u", int(remoteConfig.enabled), remoteConfig.port);
m_thread->setRemote(remoteConfig.enabled, remoteConfig.password, remoteConfig.port); m_thread->setRemote(remoteConfig.enabled, remoteConfig.password, remoteConfig.port);
@ -287,6 +322,8 @@ void CDStarGatewayApp::sigHandler(int sig)
if(g_app != nullptr && g_app->m_thread != nullptr) { if(g_app != nullptr && g_app->m_thread != nullptr) {
g_app->m_thread->kill(); g_app->m_thread->kill();
} }
CDaemon::finalize();
} }
void CDStarGatewayApp::sigHandlerFatal(int sig) void CDStarGatewayApp::sigHandlerFatal(int sig)

@ -20,18 +20,18 @@
#pragma once #pragma once
#include "DStarGatewayThread.h" #include "DStarGatewayThread.h"
#include "DStarGatewayConfig.h"
class CDStarGatewayApp class CDStarGatewayApp
{ {
private: private:
std::string m_configFile; CDStarGatewayConfig * m_config;
CDStarGatewayThread *m_thread; CDStarGatewayThread * m_thread;
bool createThread(); bool createThread();
static CDStarGatewayApp * g_app; static CDStarGatewayApp * g_app;
public: public:
CDStarGatewayApp(const std::string &configFile); CDStarGatewayApp(CDStarGatewayConfig * config);
~CDStarGatewayApp(); ~CDStarGatewayApp();
bool init(); bool init();

@ -55,6 +55,7 @@ bool CDStarGatewayConfig::load()
#ifdef USE_GPSD #ifdef USE_GPSD
ret = loadGPSD(cfg) && ret; ret = loadGPSD(cfg) && ret;
#endif #endif
ret = loadDaemon(cfg) && ret;
} }
if(ret) { if(ret) {
@ -69,6 +70,13 @@ bool CDStarGatewayConfig::load()
return ret; return ret;
} }
bool CDStarGatewayConfig::loadDaemon(const CConfig & cfg)
{
bool ret = cfg.getValue("daemon", "daemon", m_general.daemon, false);
ret = cfg.getValue("daemon", "pidfile", m_general.pidFile, 0, 1024, "") && ret;
return ret;
}
bool CDStarGatewayConfig::loadXLX(const CConfig & cfg) bool CDStarGatewayConfig::loadXLX(const CConfig & cfg)
{ {
bool ret = cfg.getValue("xlx", "enabled", m_xlx.enabled, true); bool ret = cfg.getValue("xlx", "enabled", m_xlx.enabled, true);
@ -438,3 +446,8 @@ void CDStarGatewayConfig::getGPSD(TGPSD & gpsd) const
gpsd = m_gpsd; gpsd = m_gpsd;
} }
#endif #endif
void CDStarGatewayConfig::getGeneral(TDaemon & gen) const
{
gen = m_general;
}

@ -25,6 +25,11 @@
#include "Config.h" #include "Config.h"
#include "LogSeverity.h" #include "LogSeverity.h"
typedef struct {
bool daemon;
std::string pidFile;
} TDaemon;
typedef struct { typedef struct {
GATEWAY_TYPE type; GATEWAY_TYPE type;
std::string callsign; std::string callsign;
@ -150,6 +155,7 @@ public:
#ifdef USE_GPSD #ifdef USE_GPSD
void getGPSD(TGPSD & gpsd) const; void getGPSD(TGPSD & gpsd) const;
#endif #endif
void getGeneral(TDaemon & gen) const;
private: private:
bool open(CConfig & cfg); bool open(CConfig & cfg);
@ -167,6 +173,7 @@ private:
#ifdef USE_GPSD #ifdef USE_GPSD
bool loadGPSD(const CConfig & cfg); bool loadGPSD(const CConfig & cfg);
#endif #endif
bool loadDaemon(const CConfig & cfg);
std::string m_fileName; std::string m_fileName;
TGateway m_gateway; TGateway m_gateway;
@ -181,6 +188,8 @@ private:
#ifdef USE_GPSD #ifdef USE_GPSD
TGPSD m_gpsd; TGPSD m_gpsd;
#endif #endif
TDaemon m_general;
std::vector<TRepeater *> m_repeaters; std::vector<TRepeater *> m_repeaters;
std::vector<TircDDB *> m_ircDDB; std::vector<TircDDB *> m_ircDDB;
}; };

@ -21,6 +21,7 @@ install: dstargateway
@cp -fn example.cfg $(CFG_DIR)/dstargateway.cfg @cp -fn example.cfg $(CFG_DIR)/dstargateway.cfg
@sed -i "s|path=/var/log/dstargateway/|path=$(LOG_DIR)|g" $(CFG_DIR)/dstargateway.cfg @sed -i "s|path=/var/log/dstargateway/|path=$(LOG_DIR)|g" $(CFG_DIR)/dstargateway.cfg
@sed -i "s|data=/usr/local/share/dstargateway.d/|data=$(DATA_DIR)|g" $(CFG_DIR)/dstargateway.cfg @sed -i "s|data=/usr/local/share/dstargateway.d/|data=$(DATA_DIR)|g" $(CFG_DIR)/dstargateway.cfg
@sed -i "s|daemon=false|daemon=true|g" $(CFG_DIR)/dstargateway.cfg
../APRS/APRS.a: ../APRS/APRS.a:
../Common/Common.a: ../Common/Common.a:

@ -2,7 +2,6 @@
# The order of the sections or key/values pairs inside the sections does not matter nor does casing. # The order of the sections or key/values pairs inside the sections does not matter nor does casing.
# Boolean values can be set using true, false, 1 or 0 # Boolean values can be set using true, false, 1 or 0
# Floating point values must use . (point) as decimal separator # Floating point values must use . (point) as decimal separator
[Gateway] [Gateway]
type= # repeater, hotspot, dongle. Defaults to repeater type= # repeater, hotspot, dongle. Defaults to repeater
callsign= callsign=
@ -22,7 +21,7 @@ language= # valid values: english_uk, deutsch, dansk, francais, ita
[ircddb_1] [ircddb_1]
enabled=true enabled=true
hostname=ircv4.openquad.net hostname=ircv4.openquad.net
username= # The ircDDB username default to the value defined for gateway callsign. username= # The ircDDB username defaults to the value defined for gateway callsign.
password= password=
[ircddb_2] [ircddb_2]
@ -178,3 +177,7 @@ enabled=false
port=4242 port=4242
password=CHANGE_ME # If password is left blank, remote will be disabled regardless of the enabled field password=CHANGE_ME # If password is left blank, remote will be disabled regardless of the enabled field
[Daemon]
daemon=false
# pid file is in our case useless when running as a daemon using systemd as systemd handles all the pid stuff for us
pidfile=#/var/run/dstargateway/dstargateway.pid
Loading…
Cancel
Save

Powered by TurnKey Linux.