Merge remote-tracking branch 'origin/develop'

develop
Geoffrey Merck 2 months ago
commit d017e0c616

4
.gitignore vendored

@ -35,3 +35,7 @@ sgs-xl
#Generated source files #Generated source files
/GitVersion.h /GitVersion.h
/sgs-xl.cfg /sgs-xl.cfg
#certs
sgs-xl.crt
sgs-xl.key

@ -1,68 +1,6 @@
{ {
"files.associations": { "files.exclude": {
"*.tcc": "cpp", "*.d":true,
"optional": "cpp", "*.o":true
"future": "cpp",
"numeric": "cpp",
"cmath": "cpp",
"*.h++": "cpp",
"array": "cpp",
"atomic": "cpp",
"hash_map": "cpp",
"bit": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"codecvt": "cpp",
"complex": "cpp",
"condition_variable": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"random": "cpp",
"ratio": "cpp",
"regex": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"shared_mutex": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"typeinfo": "cpp"
} }
} }

@ -974,8 +974,6 @@ void CGroupHandler::updateReflectorInfo()
info.resize(20, '_'); info.resize(20, '_');
CUtils::ReplaceChar(info, ' ', '_'); CUtils::ReplaceChar(info, ' ', '_');
parms.push_back(info); parms.push_back(info);
m_irc->sendSGSInfo(subcommand, parms);
} }
void CGroupHandler::logUser(LOGUSER lu, const std::string channel, const std::string user) void CGroupHandler::logUser(LOGUSER lu, const std::string channel, const std::string user)
@ -988,7 +986,6 @@ void CGroupHandler::logUser(LOGUSER lu, const std::string channel, const std::st
std::vector<std::string> parms; std::vector<std::string> parms;
parms.push_back(chn); parms.push_back(chn);
parms.push_back(usr); parms.push_back(usr);
m_irc->sendSGSInfo(cmd, parms);
} }
void CGroupHandler::sendToRepeaters(CHeaderData& header) const void CGroupHandler::sendToRepeaters(CHeaderData& header) const

@ -111,9 +111,6 @@ public:
// Send query for a user, a false return implies a network error // Send query for a user, a false return implies a network error
virtual bool findUser(const std::string& userCallsign) = 0; virtual bool findUser(const std::string& userCallsign) = 0;
// Support for the Smart Group Server
virtual void sendSGSInfo(const std::string subcommand, const std::vector<std::string> parms) = 0;
// The following functions are for processing received messages // The following functions are for processing received messages
// Get the waiting message type // Get the waiting message type

@ -550,22 +550,6 @@ bool IRCDDBApp::findRepeater(const std::string& rptrCall)
return true; return true;
} }
void IRCDDBApp::sendSGSInfo(const std::string &subcommand, const std::vector<std::string> &pars)
{
IRCMessageQueue *q = getSendQ();
std::string srv(d->currentServer);
if (srv.size() && d->state>=6 && q) {
std::string command("SGS ");
command.append(subcommand);
for (auto it=pars.begin(); it!=pars.end(); it++) {
command.push_back(' ');
command.append(*it);
}
IRCMessage *m = new IRCMessage(srv, command);
q->putMessage(m);
}
}
bool IRCDDBApp::sendHeard(const std::string& myCall, const std::string& myCallExt, const std::string& yourCall, const std::string& rpt1, const std::string& rpt2, unsigned char flag1, bool IRCDDBApp::sendHeard(const std::string& myCall, const std::string& myCallExt, const std::string& yourCall, const std::string& rpt1, const std::string& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3, const std::string& destination, const std::string& tx_msg, const std::string& tx_stats) unsigned char flag2, unsigned char flag3, const std::string& destination, const std::string& tx_msg, const std::string& tx_stats)
{ {

@ -70,8 +70,6 @@ public:
bool sendHeard(const std::string& myCall, const std::string& myCallExt, const std::string& yourCall, const std::string& rpt1, const std::string& rpt2, unsigned char flag1, bool sendHeard(const std::string& myCall, const std::string& myCallExt, const std::string& yourCall, const std::string& rpt1, const std::string& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3, const std::string& destination, const std::string& tx_msg, const std::string& tx_stats); unsigned char flag2, unsigned char flag3, const std::string& destination, const std::string& tx_msg, const std::string& tx_stats);
void sendSGSInfo(const std::string &subcommand, const std::vector<std::string> &pars);
int getConnectionState(); int getConnectionState();
void rptrQRG(const std::string& callsign, double txFrequency, double duplexShift, double range, double agl); void rptrQRG(const std::string& callsign, double txFrequency, double duplexShift, double range, double agl);

@ -30,9 +30,8 @@ struct CIRCDDBClientPrivate
IRCDDBApp *app; IRCDDBApp *app;
}; };
CIRCDDBClient::CIRCDDBClient(const std::string& hostName, unsigned int port, const std::string& callsign, const std::string& password, const std::string& versionInfo, const std::string& localAddr, bool isQuadNet ) : CIRCDDBClient::CIRCDDBClient(const std::string& hostName, unsigned int port, const std::string& callsign, const std::string& password, const std::string& versionInfo, const std::string& localAddr) :
d(new CIRCDDBClientPrivate), d(new CIRCDDBClientPrivate)
m_isQuadNet(isQuadNet)
{ {
std::string update_channel("#dstar"); std::string update_channel("#dstar");
d->app = new IRCDDBApp(update_channel); d->app = new IRCDDBApp(update_channel);
@ -114,17 +113,6 @@ bool CIRCDDBClient::sendHeard( const std::string& myCall, const std::string& myC
return d->app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, std::string(" "), std::string(""), std::string("")); return d->app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, std::string(" "), std::string(""), std::string(""));
} }
void CIRCDDBClient::sendSGSInfo(const std::string subcommand, const std::vector<std::string> parms)
{
printf("CIRCDDBClient::sendSGSInfo subcommand %s parms", subcommand.c_str());
for(unsigned int i=0; i < parms.size();i++)
printf(" %s", parms[i].c_str());
printf("\n");
if(m_isQuadNet) {
d->app->sendSGSInfo(subcommand, parms);
}
}
// Send heard data, a false return implies a network error // Send heard data, a false return implies a network error
bool CIRCDDBClient::sendHeardWithTXMsg(const std::string& myCall, const std::string& myCallExt, const std::string& yourCall, const std::string& rpt1, bool CIRCDDBClient::sendHeardWithTXMsg(const std::string& myCall, const std::string& myCallExt, const std::string& yourCall, const std::string& rpt1,

@ -33,7 +33,7 @@ struct CIRCDDBPrivate;
class CIRCDDBClient : public CIRCDDB{ class CIRCDDBClient : public CIRCDDB{
public: public:
CIRCDDBClient(const std::string& hostName, unsigned int port, const std::string& callsign, const std::string& password, const std::string& versionInfo, CIRCDDBClient(const std::string& hostName, unsigned int port, const std::string& callsign, const std::string& password, const std::string& versionInfo,
const std::string& localAddr = std::string(""), bool isQuadNet = false); const std::string& localAddr = std::string(""));
~CIRCDDBClient(); ~CIRCDDBClient();
// A false return implies a network error, or unable to log in // A false return implies a network error, or unable to log in
@ -106,9 +106,6 @@ public:
// Send query for a user, a false return implies a network error // Send query for a user, a false return implies a network error
bool findUser(const std::string& userCallsign); bool findUser(const std::string& userCallsign);
// Support for the Smart Group Server
void sendSGSInfo(const std::string subcommand, const std::vector<std::string> parms);
// The following functions are for processing received messages // The following functions are for processing received messages
// Get the waiting message type // Get the waiting message type
@ -132,7 +129,6 @@ public:
private: private:
struct CIRCDDBClientPrivate * const d; struct CIRCDDBClientPrivate * const d;
bool m_isQuadNet;
}; };

@ -137,13 +137,6 @@ bool CIRCDDBMultiClient::sendHeardWithTXStats(const std::string & myCall, const
return result; return result;
} }
void CIRCDDBMultiClient::sendSGSInfo(const std::string subcommand, const std::vector<std::string> parms)
{
for (unsigned int i = 0; i < m_clients.size(); i++) {
m_clients[i]->sendSGSInfo(subcommand, parms);
}
}
bool CIRCDDBMultiClient::findGateway(const std::string & gatewayCallsign) bool CIRCDDBMultiClient::findGateway(const std::string & gatewayCallsign)
{ {
pushQuery(IDRT_GATEWAY, gatewayCallsign, new CIRCDDBMultiClientQuery("", "", gatewayCallsign, "", "", IDRT_GATEWAY)); pushQuery(IDRT_GATEWAY, gatewayCallsign, new CIRCDDBMultiClientQuery("", "", gatewayCallsign, "", "", IDRT_GATEWAY));

@ -154,7 +154,6 @@ public:
virtual bool receiveGateway(std::string & gatewayCallsign, std::string & address); virtual bool receiveGateway(std::string & gatewayCallsign, std::string & address);
virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address); virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address);
virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address, std::string & timeStamp); virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address, std::string & timeStamp);
virtual void sendSGSInfo(const std::string subcommand, const std::vector<std::string> parms);
virtual void close(); virtual void close();
// //

@ -7,7 +7,7 @@ CFGDIR=/usr/local/etc/sgs-xl/
DATADIR=/usr/local/sgs-xl/data/ DATADIR=/usr/local/sgs-xl/data/
# choose this if you want debugging help # choose this if you want debugging help
# CPPFLAGS=-g -ggdb -W -Wall -std=c++17 -DCFG_DIR=\"$(CFGDIR)\" -DDATA_DIR=\"$(DATADIR)\" #CPPFLAGS=-g -ggdb -W -Wall -std=c++17 -DCFG_DIR=\"$(CFGDIR)\" -DDATA_DIR=\"$(DATADIR)\"
# or, you can choose this for a much smaller executable without debugging help # or, you can choose this for a much smaller executable without debugging help
CPPFLAGS= -W -Wall -O3 -std=c++17 -DCFG_DIR=\"$(CFGDIR)\" -DDATA_DIR=\"$(DATADIR)\" CPPFLAGS= -W -Wall -O3 -std=c++17 -DCFG_DIR=\"$(CFGDIR)\" -DDATA_DIR=\"$(DATADIR)\"
@ -16,14 +16,17 @@ OBJS = $(SRCS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d) DEPS = $(SRCS:.cpp=.d)
sgs-xl : GitVersion.h $(OBJS) sgs-xl : GitVersion.h $(OBJS)
g++ $(CPPFLAGS) -o sgs-xl $(OBJS) -lconfig++ -pthread g++ $(CPPFLAGS) -o sgs-xl $(OBJS) -lconfig++ -lssl -lcrypto -pthread
%.o : %.cpp %.o : %.cpp
g++ $(CPPFLAGS) -MMD -MD -c $< -o $@ g++ $(CPPFLAGS) -MMD -MD -c $< -o $@
sgs-xl.crt sgs-xl.key :
openssl req -new -newkey rsa:4096 -days 36500 -nodes -x509 -subj "/CN=Smart Group Server XL" -keyout sgs-xl.key -out sgs-xl.crt
.PHONY: clean .PHONY: clean
clean: clean:
$(RM) GitVersion.h $(OBJS) $(DEPS) sgs-xl $(RM) GitVersion.h $(OBJS) $(DEPS) sgs-xl sgs-xl.crt sgs-xl.key
-include $(DEPS) -include $(DEPS)
@ -36,11 +39,13 @@ newhostfiles :
wget -O $(DATADIR)/DCS_Hosts.txt http://www.pistar.uk/downloads/DCS_Hosts.txt wget -O $(DATADIR)/DCS_Hosts.txt http://www.pistar.uk/downloads/DCS_Hosts.txt
.PHONY: install .PHONY: install
install : newhostfiles sgs-xl install : newhostfiles sgs-xl.key sgs-xl.crt sgs-xl
mkdir -p $(CFGDIR) mkdir -p $(CFGDIR)
mkdir -p $(DATADIR) mkdir -p $(DATADIR)
cp -rf data/* $(DATADIR) cp -rf data/* $(DATADIR)
cp -f sgs-xl.cfg $(CFGDIR) cp -f sgs-xl.cfg $(CFGDIR)
cp -f sgs-xl.crt $(DATADIR)
cp -f sgs-xl.key $(DATADIR)
cp -f sgs-xl $(BINDIR) cp -f sgs-xl $(BINDIR)
cp -f sgs-xl.service /lib/systemd/system cp -f sgs-xl.service /lib/systemd/system
sed -i "s|REPLACEME|$(BINDIR)sgs-xl $(CFGDIR)sgs-xl.cfg|g" /lib/systemd/system/sgs-xl.service sed -i "s|REPLACEME|$(BINDIR)sgs-xl $(CFGDIR)sgs-xl.cfg|g" /lib/systemd/system/sgs-xl.service
@ -63,7 +68,6 @@ removehostfiles :
rm -f $(DATADIR)/DExtra_Hosts.txt rm -f $(DATADIR)/DExtra_Hosts.txt
rm -f $(DATADIR)/DCS_Hosts.txt rm -f $(DATADIR)/DCS_Hosts.txt
.PHONY: GitVersion.h
GitVersion.h: force GitVersion.h: force
ifneq ("$(wildcard .git/index)","") ifneq ("$(wildcard .git/index)","")
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@ echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@

@ -39,7 +39,7 @@ git clone git://github.com/F4FXL/smart-group-server-xl.git
``` ```
Install the only needed development library: Install the only needed development library:
``` ```
sudo apt-get install build-essential libconfig++-dev sudo apt-get install build-essential libconfig++-dev openssl libssl-dev
``` ```
Change to the smart-group-server directory and type `make`. This should make the executable, `sgs-xl` without errors or warnings. By default, you will have a group server that can link groups to X-Reflectors or DCS-Reflectors. Of course you can declare an unlinked channel by simply not defining a *reflector* parameter for that channel. Change to the smart-group-server directory and type `make`. This should make the executable, `sgs-xl` without errors or warnings. By default, you will have a group server that can link groups to X-Reflectors or DCS-Reflectors. Of course you can declare an unlinked channel by simply not defining a *reflector* parameter for that channel.
@ -58,6 +58,11 @@ sudo make install && sudo journalctl -u sgs-xl.service -f
This will allow you to view the smart-group-server log file while it's booting up. When you are satisfied it's running okay you can Control-C to end the journalctl session. To uninstall it, type `sudo make uninstall` and `sudo make removehostfiles`. This will stop the server and remove all files. You can then delete the build directory to remove every trace of the smart-group-server. This will allow you to view the smart-group-server log file while it's booting up. When you are satisfied it's running okay you can Control-C to end the journalctl session. To uninstall it, type `sudo make uninstall` and `sudo make removehostfiles`. This will stop the server and remove all files. You can then delete the build directory to remove every trace of the smart-group-server.
## Whatsnew ## Whatsnew
### v1.1
#### 2021-03-03
Removed specific SGS IRC messages
Is now compatible with N7TAE's remote https://github.com/n7tae/sgs-remote
### v1.0 ### v1.0
#### 2020-03-10 #### 2020-03-10
Groups can share same logoff. Thus users will be logged off at once from every group sharing the same logoff Groups can share same logoff. Thus users will be logged off at once from every group sharing the same logoff

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2011 by Jonathan Naylor G4KLX * Copyright (C) 2011 by Jonathan Naylor G4KLX
* Copyright (c) 2017,2018 by Thomas A. Early N7TAE * Copyright (c) 2017,2018, 2020 by Thomas A. Early N7TAE
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -19,8 +19,7 @@
#include "RemoteGroup.h" #include "RemoteGroup.h"
CRemoteGroup::CRemoteGroup(const std::string& callsign, const std::string& logoff, const std::string &repeater, const std::string &infoText, CRemoteGroup::CRemoteGroup(const std::string &callsign, const std::string &logoff, const std::string &repeater, const std::string &infoText, const std::string &linkReflector, LINK_STATUS linkStatus, unsigned int userTimeout) :
const std::string &linkReflector, LINK_STATUS linkStatus, unsigned int userTimeout) :
m_callsign(callsign), m_callsign(callsign),
m_logoff(logoff), m_logoff(logoff),
m_repeater(repeater), m_repeater(repeater),
@ -30,7 +29,7 @@ m_linkStatus(linkStatus),
m_userTimeout(userTimeout), m_userTimeout(userTimeout),
m_users() m_users()
{ {
if (m_logoff.compare(" ")) if (m_logoff.compare(" ") == 0)
m_logoff.clear(); m_logoff.clear();
} }

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2011 by Jonathan Naylor G4KLX * Copyright (C) 2011 by Jonathan Naylor G4KLX
* Copyright (c) 2017,2018 by Thomas A. Early N7TAE * Copyright (c) 2017,2018,2020 by Thomas A. Early N7TAE
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -28,8 +28,7 @@
class CRemoteGroup { class CRemoteGroup {
public: public:
CRemoteGroup(const std::string& callsign, const std::string& logoff, const std::string &repeater, const std::string &infoText, const std::string &linkReflector, CRemoteGroup(const std::string& callsign, const std::string& logoff, const std::string &repeater, const std::string &infoText, const std::string &linkReflector, LINK_STATUS linkStatus, unsigned int userTimeout);
LINK_STATUS linkStatus, unsigned int userTimeout);
~CRemoteGroup(); ~CRemoteGroup();
void addUser(const std::string& callsign, uint32_t timer, uint32_t timeout); void addUser(const std::string& callsign, uint32_t timer, uint32_t timeout);

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX * Copyright (C) 2011,2012,2013 by Jonathan Naylor G4KLX
* Copyright (c) 2017-2018 by Thomas A. Early N7TAE * Copyright (c) 2017-2018,2020 by Thomas A. Early N7TAE
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -20,165 +20,203 @@
#include <cassert> #include <cassert>
#include <cstdlib> #include <cstdlib>
#include <list> #include <list>
#include <vector>
#include <sstream>
#include <iterator>
#include "GroupHandler.h"
#include "RemoteHandler.h" #include "RemoteHandler.h"
#include "DExtraHandler.h" #include "DExtraHandler.h"
#include "DStarDefines.h" #include "DStarDefines.h"
#include "DCSHandler.h" #include "DCSHandler.h"
#include "Utils.h" #include "Utils.h"
CRemoteHandler::CRemoteHandler(const std::string &password, unsigned int port, const std::string &address) : bool CRemoteHandler::open(const std::string &password, const unsigned short port, const bool isIPV6)
m_password(password),
m_handler(port, address),
m_random(0U)
{ {
assert(port > 0U); return m_tlsserver.OpenSocket(password, isIPV6 ? "::" : "0.0.0.0", port);
assert(password.size());
} }
CRemoteHandler::~CRemoteHandler() bool CRemoteHandler::process()
{ {
} std::string command;
if (m_tlsserver.GetCommand(command))
return false; // nothing to do...
// parse the command into words
std::stringstream ss(command);
std::istream_iterator<std::string> begin(ss);
std::istream_iterator<std::string> end;
std::vector<std::string> cwords(begin, end);
if (cwords.size() == 0) {
return false;
}
bool CRemoteHandler::open() if (0 == cwords[0].compare("halt")) {
{ printf("Received halt command from remote client, shutting down...\n");
return m_handler.open(); //auto groups = CGroupHandler::listGroups();
//for (auto it=groups.begin(); it!=groups.end(); it++) {
// CGroupHandler *group = CGroupHandler::findGroup(*it);
// logoff(group, "ALL ");
//}
return true;
}
if (cwords.size() < 2) {
fprintf(stderr, "Not enough words in the command: [%s]\n", command.c_str());
return false;
}
CUtils::ReplaceChar(cwords[1], '_', ' '); // this is the subscribe callsign
cwords[1].resize(8, ' ');
CGroupHandler *group = CGroupHandler::findGroup(cwords[1]);
if (0 == cwords[0].compare("list")) {
sendGroup(group);
} else if (NULL == group) {
char emsg[128];
snprintf(emsg, 128, "Smart Group [%s] not found", cwords[1].c_str());
m_tlsserver.Write(emsg);
} else {
if (cwords.size() > 2 && 0 == cwords[0].compare("link")) {
CUtils::ReplaceChar(cwords[2], '_', ' ');
cwords[2].resize(8, ' ');
printf("Remote control user has linked \"%s\" to \"%s\"\n", cwords[1].c_str(), cwords[2].c_str());
link(group, cwords[2]);
}
else if (cwords.size() > 1 && 0 == cwords[0].compare("unlink")) {
printf("Remote control user has unlinked \"%s\"\n", cwords[1].c_str());
unlink(group);
}
else if (cwords.size() > 2 && 0 == cwords[0].compare("drop")) {
CUtils::ReplaceChar(cwords[2], '_', ' ');
cwords[2].resize(8, ' ');
printf("Remote control user has logged off \"%s\" from \"%s\"\n", cwords[2].c_str(), cwords[1].c_str());
logoff(group, cwords[2]);
}
else {
printf("The command \"%s\" is bad\n", command.c_str());
}
}
m_tlsserver.CloseClient();
return false;
} }
void CRemoteHandler::process()
void CRemoteHandler::sendGroup(CGroupHandler *group)
{ {
RPH_TYPE type = m_handler.readType(); char msg[128];
switch (type) { if (group) {
case RPHT_LOGOUT: CRemoteGroup *data = group->getInfo();
m_handler.setLoggedIn(false); if (data) {
printf("Remote control user has logged out\n"); snprintf(msg, 128, "Subscribe = %s", data->getCallsign().c_str());
break; m_tlsserver.Write(msg);
case RPHT_LOGIN: snprintf(msg, 128, "Unsubscribe = %s", data->getLogoff().c_str());
m_random = (uint32_t)rand(); m_tlsserver.Write(msg);
m_handler.sendRandom(m_random); snprintf(msg, 128, "Module = %s", data->getRepeater().c_str());
break; m_tlsserver.Write(msg);
case RPHT_HASH: { snprintf(msg, 128, "Description = %s", data->getInfoText().c_str());
bool valid = m_handler.readHash(m_password, m_random); m_tlsserver.Write(msg);
if (valid) { snprintf(msg, 128, "Reflector = %s", data->getReflector().c_str());
printf("Remote control user has logged in\n"); m_tlsserver.Write(msg);
m_handler.setLoggedIn(true); switch (data->getLinkStatus()) {
m_handler.sendACK(); case LS_LINKING_DCS:
} else { case LS_LINKING_DEXTRA:
printf("Remote control user has failed login authentication\n"); m_tlsserver.Write("Link Status = Linking");
m_handler.setLoggedIn(false); break;
m_handler.sendNAK("Invalid password"); case LS_LINKED_DCS:
} case LS_LINKED_DEXTRA:
} m_tlsserver.Write("Link Status = Linked");
break; break;
case RPHT_SMARTGROUP: { default:
std::string callsign = m_handler.readGroup(); m_tlsserver.Write("Link Status = Unlinked");
sendGroup(callsign); break;
}
break;
case RPHT_LINK: {
std::string callsign, reflector;
m_handler.readLink(callsign, reflector);
printf("Remote control user has linked \"%s\" to \"%s\"\n", callsign.c_str(), reflector.c_str());
link(callsign, reflector);
} }
break; snprintf(msg, 128, "User Timeout = %u min", data->getUserTimeout());
case RPHT_UNLINK: { m_tlsserver.Write(msg);
std::string callsign; for (uint32_t i=0; i<data->getUserCount(); i++) {
m_handler.readUnlink(callsign); CRemoteUser *user = data->getUser(i);
printf("Remote control user has unlinked \"%s\"\n", callsign.c_str()); snprintf(msg, 128, " User = %s, timer = %u min, timeout = %u min", user->getCallsign().c_str(), user->getTimer()/60U, user->getTimeout()/60U);
unlink(callsign); m_tlsserver.Write(msg);
} }
break; }
case RPHT_LOGOFF: { delete data;
std::string callsign, user; } else {
m_handler.readLogoff(callsign, user); // no group, so let's summarize all groups
printf("Remote control user has logged off \"%s\" from \"%s\"\n", user.c_str(), callsign.c_str()); auto groups = CGroupHandler::listGroups();
logoff(callsign, user); m_tlsserver.Write("Logon Logoff Channel Description Status Reflector Timeout");
for (auto it=groups.begin(); it!=groups.end(); it++) {
CGroupHandler *group = CGroupHandler::findGroup(*it);
if (group) {
CRemoteGroup *data = group->getInfo();
if (data) {
std::string linkstat;
switch (data->getLinkStatus()) {
case LS_LINKING_DCS:
case LS_LINKING_DEXTRA:
linkstat.assign("Linking ");
break;
case LS_LINKED_DCS:
case LS_LINKED_DEXTRA:
linkstat.assign("Linked ");
break;
default:
linkstat.assign("Unlinked");
break;
}
snprintf(msg, 128, "%s %s %s %s %s %8.8s %4u", data->getCallsign().c_str(), data->getLogoff().c_str(), data->getRepeater().c_str(), data->getInfoText().c_str(), linkstat.c_str(), data->getReflector().c_str(), data->getUserTimeout());
m_tlsserver.Write(msg);
delete data;
}
} }
break; }
default:
break;
} }
} }
void CRemoteHandler::close() void CRemoteHandler::link(CGroupHandler *group, const std::string &reflector)
{
m_handler.close();
}
void CRemoteHandler::sendGroup(const std::string &callsign)
{ {
CGroupHandler *group = CGroupHandler::findGroup(callsign); char msg[128];
if (group == NULL) {
m_handler.sendNAK("Invalid Smart Group callsign");
return;
}
CRemoteGroup *data = group->getInfo(); CRemoteGroup *data = group->getInfo();
if (data != NULL) if (group->remoteLink(reflector))
m_handler.sendGroup(*data); snprintf(msg, 128, "Smart Group %s linked to %s", data->getCallsign().c_str(), reflector.c_str());
delete data;
}
void CRemoteHandler::link(const std::string &callsign, const std::string &reflector)
{
CGroupHandler *smartGroup = CGroupHandler::findGroup(callsign);
if (NULL == smartGroup) {
m_handler.sendNAK(std::string("Invalid Smart Group subscribe call ") + callsign);
return;
}
if (smartGroup->remoteLink(reflector))
m_handler.sendACK();
else else
m_handler.sendNAK("link failed"); snprintf(msg, 128, "Failed to link Smart Group %s to %s", data->getCallsign().c_str(), reflector.c_str());
m_tlsserver.Write(msg);
delete data;
} }
void CRemoteHandler::unlink(const std::string &callsign) void CRemoteHandler::unlink(CGroupHandler *group)
{ {
CGroupHandler *smartGroup = CGroupHandler::findGroup(callsign); char msg[128];
if (NULL == smartGroup) { CRemoteGroup *data = group->getInfo();
m_handler.sendNAK(std::string("Invalid Smart Group subscribe call ") + callsign); switch (group->getLinkType()) {
return; case LT_DEXTRA:
} CDExtraHandler::unlink(group, data->getReflector(), false);
snprintf(msg, 128, "Smart Group %s unlinked from %s", data->getCallsign().c_str(), data->getReflector().c_str());
CRemoteGroup *data = smartGroup->getInfo(); break;
if (data) { case LT_DCS:
switch (smartGroup->getLinkType()) { CDCSHandler::unlink(group, data->getReflector(), false);
case LT_DEXTRA: snprintf(msg, 128, "Smart Group %s unlinked from %s", data->getCallsign().c_str(), data->getReflector().c_str());
CDExtraHandler::unlink(smartGroup, data->getReflector(), false); break;
break; default:
case LT_DCS: snprintf(msg, 128, "Smart Group %s is already unlinked", data->getCallsign().c_str());
CDCSHandler::unlink(smartGroup, data->getReflector(), false); m_tlsserver.Write(msg);
break; delete data;
default: return;
delete data;
m_handler.sendNAK("alread unlinked");
return;
}
delete data;
} else {
m_handler.sendNAK("could not get Smart Group info");
return;
} }
smartGroup->setLinkType(LT_NONE); delete data;
smartGroup->clearReflector(); group->setLinkType(LT_NONE);
m_handler.sendACK(); group->clearReflector();
m_tlsserver.Write(msg);
} }
void CRemoteHandler::logoff(const std::string &callsign, const std::string &user) void CRemoteHandler::logoff(CGroupHandler *group, const std::string &user)
{ {
CGroupHandler *pGroup = CGroupHandler::findGroup(callsign); char msg[128];
if (pGroup == NULL) { CRemoteGroup *data = group->getInfo();
m_handler.sendNAK("Invalid Smart Group callsign"); if (group->logoff(user))
return; snprintf(msg, 128, "Logging off %s from Smart Group %s", user.c_str(), data->getCallsign().c_str());
}
bool res = pGroup->logoff(user);
if (!res)
m_handler.sendNAK("Invalid Smart Group user callsign");
else else
m_handler.sendACK(); snprintf(msg, 128, "Could not logoff %s from Smart Group %s", user.c_str(), data->getCallsign().c_str());
m_tlsserver.Write(msg);
delete data;
} }

@ -22,27 +22,24 @@
#include <string> #include <string>
#include <cstdint> #include <cstdint>
#include "RemoteProtocolHandler.h" #include "GroupHandler.h"
#include "Timer.h" #include "TLSServer.h"
class CRemoteHandler { class CRemoteHandler {
public: public:
CRemoteHandler(const std::string &password, unsigned int port, const std::string &address = std::string("")); CRemoteHandler() {};
~CRemoteHandler(); ~CRemoteHandler() {};
bool open(); bool open(const std::string &password, const unsigned short port, const bool isIPV6);
void process(); bool process();
void close();
private: private:
std::string m_password; std::string m_password;
CRemoteProtocolHandler m_handler; CTLSServer m_tlsserver;
uint32_t m_random;
void sendGroup(CGroupHandler *group);
void sendGroup(const std::string &callsign); void link(CGroupHandler *group, const std::string &reflector);
void link(const std::string &callsign, const std::string &reflector); void unlink(CGroupHandler *group);
void unlink(const std::string &callsign); void logoff(CGroupHandler *group, const std::string &user);
void logoff(const std::string &callsign, const std::string &user);
}; };

@ -109,10 +109,9 @@ bool CSGSXLApp::createThread()
CIRCDDB_Array clients; CIRCDDB_Array clients;
for(unsigned int i=0; i < config.getIrcDDBCount(); i++) { for(unsigned int i=0; i < config.getIrcDDBCount(); i++) {
std::string hostname, username, password; std::string hostname, username, password;
bool isQuadNet; config.getIrcDDB(i, hostname, username, password);
config.getIrcDDB(i, hostname, username, password, isQuadNet); std::cout << "ircDDB " << i + 1 << " set to " << hostname << " username set to " << username << std::endl;
std::cout << "ircDDB " << i + 1 << " set to " << hostname << " username set to " << username << " QuadNet " << isQuadNet << std::endl; CIRCDDB *ircDDB = new CIRCDDBClient(hostname, 9007U, username, password, std::string("linux_SmartGroupServerXL-") + VERSION, address);
CIRCDDB *ircDDB = new CIRCDDBClient(hostname, 9007U, username, password, std::string("linux_SmartGroupServerXL-") + VERSION, address, isQuadNet);
clients.push_back(ircDDB); clients.push_back(ircDDB);
} }

@ -85,7 +85,6 @@ CSGSXLConfig::CSGSXLConfig(const std::string &pathname)
continue; continue;
} }
ircddb->isQuadNet = ircddb->hostname.find("openquad.net") != std::string::npos;
this->m_ircDDB.push_back(ircddb); this->m_ircDDB.push_back(ircddb);
std::cout << "IRCDDB: host=" << ircddb->hostname << " user=" << ircddb->username << " password=" << ircddb->password << "\n"; std::cout << "IRCDDB: host=" << ircddb->hostname << " user=" << ircddb->username << " password=" << ircddb->password << "\n";
} }
@ -95,7 +94,6 @@ CSGSXLConfig::CSGSXLConfig(const std::string &pathname)
ircddb->hostname = "rr.openquad.net"; ircddb->hostname = "rr.openquad.net";
ircddb->password = ""; ircddb->password = "";
ircddb->username = m_callsign; ircddb->username = m_callsign;
ircddb->isQuadNet = true;
this->m_ircDDB.push_back(ircddb); this->m_ircDDB.push_back(ircddb);
std::cout << "No ircDDB networks configure'd, defaulting to IRCDDB: host=" << ircddb->hostname << " user=" << ircddb->username << " password=" << ircddb->password << "\n"; std::cout << "No ircDDB networks configure'd, defaulting to IRCDDB: host=" << ircddb->hostname << " user=" << ircddb->username << " password=" << ircddb->password << "\n";
} }
@ -362,12 +360,11 @@ void CSGSXLConfig::getGateway(std::string& callsign, std::string& address) const
address = m_address; address = m_address;
} }
void CSGSXLConfig::getIrcDDB(unsigned int ircddb, std::string& hostname, std::string& username, std::string& password, bool &isQuadNet) const void CSGSXLConfig::getIrcDDB(unsigned int ircddb, std::string& hostname, std::string& username, std::string& password) const
{ {
hostname = m_ircDDB[ircddb]->hostname; hostname = m_ircDDB[ircddb]->hostname;
username = m_ircDDB[ircddb]->username; username = m_ircDDB[ircddb]->username;
password = m_ircDDB[ircddb]->password; password = m_ircDDB[ircddb]->password;
isQuadNet = m_ircDDB[ircddb]->isQuadNet;
} }
void CSGSXLConfig::getGroup(unsigned int mod, std::string& band, std::string& callsign, std::string& logoff, std::string& info, std::string& permanent, unsigned int& userTimeout, CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, std::string& reflector) const void CSGSXLConfig::getGroup(unsigned int mod, std::string& band, std::string& callsign, std::string& logoff, std::string& info, std::string& permanent, unsigned int& userTimeout, CALLSIGN_SWITCH& callsignSwitch, bool& txMsgSwitch, std::string& reflector) const

@ -40,7 +40,6 @@ struct SircDDB {
std::string hostname; std::string hostname;
std::string username; std::string username;
std::string password; std::string password;
bool isQuadNet;
}; };
class CSGSXLConfig { class CSGSXLConfig {
@ -50,7 +49,7 @@ public:
void getGateway(std::string &callsign, std::string &address) const; void getGateway(std::string &callsign, std::string &address) const;
void getIrcDDB(unsigned int ircddb, std::string &hostname, std::string &username, std::string &password, bool &isQuadNet) const; void getIrcDDB(unsigned int ircddb, std::string &hostname, std::string &username, std::string &password) const;
void getGroup(unsigned int mod, std::string &band, std::string &callsign, std::string &logoff, std::string &info, std::string &permanent, unsigned int &userTimeout, CALLSIGN_SWITCH &callsignSwitch, bool &txMsgSwitch, std::string &reflector) const; void getGroup(unsigned int mod, std::string &band, std::string &callsign, std::string &logoff, std::string &info, std::string &permanent, unsigned int &userTimeout, CALLSIGN_SWITCH &callsignSwitch, bool &txMsgSwitch, std::string &reflector) const;

@ -115,9 +115,9 @@ void CSGSXLThread::run()
CGroupHandler::link(); CGroupHandler::link();
if (m_remoteEnabled && m_remotePassword.size() && m_remotePort > 0U) { if (m_remoteEnabled && m_remotePassword.size() && m_remotePort > 0U) {
m_remote = new CRemoteHandler(m_remotePassword, m_remotePort); m_remote = new CRemoteHandler();
bool res = m_remote->open(); bool res = m_remote->open(m_remotePassword, m_remotePort, false);
if (!res) { if (res) {
delete m_remote; delete m_remote;
m_remote = NULL; m_remote = NULL;
} }
@ -176,7 +176,6 @@ void CSGSXLThread::run()
delete m_irc; delete m_irc;
if (m_remote != NULL) { if (m_remote != NULL) {
m_remote->close();
delete m_remote; delete m_remote;
} }

@ -0,0 +1,230 @@
/*
* Copyright (C) 2020 by Thomas A. 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 <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <cstring>
#include "TLSServer.h"
CTLSServer::~CTLSServer()
{
CloseClient();
if (m_sock >= 0)
close(m_sock);
if (m_ctx)
SSL_CTX_free(m_ctx);
}
bool CTLSServer::CreateContext(const SSL_METHOD *method)
{
m_ctx = SSL_CTX_new(method);
if (!m_ctx) {
fprintf(stderr, "Unable to create SSL context");
ERR_print_errors_fp(stderr);
return true;
}
return false;
}
// Server Class Definitions
#ifndef CFG_DIR
#define CFG_DIR "/usr/local/etc"
#endif
bool CTLSServer::OpenSocket(const std::string &password, const std::string &address, unsigned short port)
{
m_password.assign(password);
m_address.assign(address);
m_port = port;
SSL_load_error_strings();
OpenSSL_add_ssl_algorithms();
const SSL_METHOD *method = TLS_server_method();
if (NULL == method) {
perror("Can't set SSL method");
return true;
}
if (CreateContext(method))
return true;
if (0 == SSL_CTX_set_min_proto_version(m_ctx, TLS1_2_VERSION)) {
perror("Can't sent minimum version");
return true;
}
std::string path(DATA_DIR);
std::string file(path+"/sgs-xl.crt");
SSL_CTX_set_ecdh_auto(ctx, 1);
if (0 >= SSL_CTX_use_certificate_file(m_ctx, file.c_str(), SSL_FILETYPE_PEM)) {
ERR_print_errors_fp(stderr);
return true;
}
file.assign(path+"/sgs-xl.key");
if (0 >= SSL_CTX_use_PrivateKey_file(m_ctx, file.c_str(), SSL_FILETYPE_PEM)) {
ERR_print_errors_fp(stderr);
return true;
}
if (CreateSocket())
return true;
return false;
}
bool CTLSServer::CreateSocket()
{
struct sockaddr_storage addr;
memset(&addr, 0, sizeof(struct sockaddr_storage));
int family;
if (m_address.npos != m_address.find(':')) {
struct sockaddr_in6 *a = (struct sockaddr_in6 *)&addr;
a->sin6_family = family = AF_INET6;
a->sin6_port = htons(m_port);
inet_pton(AF_INET6, m_address.c_str(), &(a->sin6_addr));
} else if (m_address.npos != m_address.find('.')) {
struct sockaddr_in *a = (struct sockaddr_in *)&addr;
a->sin_family = family = AF_INET;
a->sin_port = htons(m_port);
inet_pton(AF_INET, m_address.c_str(), &(a->sin_addr));
} else {
fprintf(stderr, "Improper addess [%s], remote socket creation failed!\n", m_address.c_str());
return true;
}
m_sock = socket(family, SOCK_STREAM, 0);
if (m_sock < 0) {
perror("Unable to create socket");
return true;
}
if (0 > bind(m_sock, (struct sockaddr*)&addr, sizeof(addr))) {
perror("Unable to bind");
close(m_sock);
return true;
}
if (0 > listen(m_sock, 1)) {
perror("Unable to listen");
close(m_sock);
return true;
}
return false;
}
bool CTLSServer::GetCommand(std::string &command)
{
struct sockaddr_storage addr;
uint len = sizeof(addr);
memset(&addr, 0, len);
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(m_sock, &readfds);
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 0;
// don't care about writefds and exceptfds:
// and we will return immediately
int ret = select(m_sock+1, &readfds, NULL, NULL, &tv);
if (ret && FD_ISSET(m_sock, &readfds)) {
// there is someting to read
m_client = accept(m_sock, (struct sockaddr*)&addr, &len);
if (m_client < 0) {
perror("Remote is unable to accept");
return true;
}
if (AF_INET6 == addr.ss_family) {
struct sockaddr_in6 *a = (struct sockaddr_in6 *)&addr;
char s[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &(a->sin6_addr), s, INET6_ADDRSTRLEN);
printf("Remote IPV6 client from %s\n", s);
} else {
struct sockaddr_in *a = (struct sockaddr_in *)&addr;
char s[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(a->sin_addr), s, INET_ADDRSTRLEN);
printf("Remote IPV4 client from %s\n", s);
}
m_ssl = SSL_new(m_ctx);
if (NULL == m_ssl) {
CloseClient();
perror("Remote can't create a new SSL");
return true;
} else {
if (0 == SSL_set_fd(m_ssl, m_client)) {
CloseClient();
perror("Remote can't set fd");
return true;
} else {
if (SSL_accept(m_ssl) <= 0) {
CloseClient();
ERR_print_errors_fp(stderr);
return true;
} else {
char buf[256] = { 0 };
SSL_read(m_ssl, buf, 256);
if (m_password.compare(buf)) {
printf("Password [%s] from remote client failed.\n", buf);
SSL_write(m_ssl, "fail", 4);
CloseClient();
return true;
} else {
SSL_write(m_ssl, "pass", 4);
char com[1024] = { 0 };
SSL_read(m_ssl, com, 1024);
command.assign(com);
}
}
}
}
return false;
} else {
// nothing to read
command.clear();
return true;
}
}
int CTLSServer::Write(const char *line)
{
return SSL_write(m_ssl, line, strlen(line));
}
void CTLSServer::CloseClient()
{
if (m_ssl)
SSL_free(m_ssl);
m_ssl = NULL;
if (m_client >= 0)
close(m_client);
m_client = 0;
}

@ -0,0 +1,45 @@
#pragma once
/*
* Copyright (C) 2020 by Thomas A. 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 <string>
#include <openssl/ssl.h>
#include <openssl/err.h>
class CTLSServer
{
public:
CTLSServer() : m_sock(-1) , m_ctx(NULL) , m_ssl(NULL) , m_client(-1) {}
~CTLSServer();
virtual bool OpenSocket(const std::string &password, const std::string &address, unsigned short port);
bool GetCommand(std::string &command);
int Write(const char *line);
void CloseClient();
private:
bool CreateContext(const SSL_METHOD *method);
virtual bool CreateSocket();
int m_sock;
SSL_CTX *m_ctx;
SSL *m_ssl;
int m_client;
std::string m_address, m_password;
unsigned short m_port;
};

@ -17,8 +17,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <string> #include <string>
#include <vector> #include <vector>
#include <time.h> #include <ctime>
#include <cstdint>
enum TRISTATE { enum TRISTATE {
STATE_FALSE, STATE_FALSE,

Loading…
Cancel
Save

Powered by TurnKey Linux.