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
/GitVersion.h
/sgs-xl.cfg
#certs
sgs-xl.crt
sgs-xl.key

@ -1,68 +1,6 @@
{
"files.associations": {
"*.tcc": "cpp",
"optional": "cpp",
"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"
"files.exclude": {
"*.d":true,
"*.o":true
}
}

@ -974,8 +974,6 @@ void CGroupHandler::updateReflectorInfo()
info.resize(20, '_');
CUtils::ReplaceChar(info, ' ', '_');
parms.push_back(info);
m_irc->sendSGSInfo(subcommand, parms);
}
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;
parms.push_back(chn);
parms.push_back(usr);
m_irc->sendSGSInfo(cmd, parms);
}
void CGroupHandler::sendToRepeaters(CHeaderData& header) const

@ -111,9 +111,6 @@ public:
// Send query for a user, a false return implies a network error
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
// Get the waiting message type

@ -550,22 +550,6 @@ bool IRCDDBApp::findRepeater(const std::string& rptrCall)
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,
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,
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();
void rptrQRG(const std::string& callsign, double txFrequency, double duplexShift, double range, double agl);

@ -30,9 +30,8 @@ struct CIRCDDBClientPrivate
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 ) :
d(new CIRCDDBClientPrivate),
m_isQuadNet(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)
{
std::string update_channel("#dstar");
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(""));
}
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
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{
public:
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();
// 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
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
// Get the waiting message type
@ -132,7 +129,6 @@ public:
private:
struct CIRCDDBClientPrivate * const d;
bool m_isQuadNet;
};

@ -137,13 +137,6 @@ bool CIRCDDBMultiClient::sendHeardWithTXStats(const std::string & myCall, const
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)
{
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 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 void sendSGSInfo(const std::string subcommand, const std::vector<std::string> parms);
virtual void close();
//

@ -7,7 +7,7 @@ CFGDIR=/usr/local/etc/sgs-xl/
DATADIR=/usr/local/sgs-xl/data/
# 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
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)
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
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
clean:
$(RM) GitVersion.h $(OBJS) $(DEPS) sgs-xl
$(RM) GitVersion.h $(OBJS) $(DEPS) sgs-xl sgs-xl.crt sgs-xl.key
-include $(DEPS)
@ -36,11 +39,13 @@ newhostfiles :
wget -O $(DATADIR)/DCS_Hosts.txt http://www.pistar.uk/downloads/DCS_Hosts.txt
.PHONY: install
install : newhostfiles sgs-xl
install : newhostfiles sgs-xl.key sgs-xl.crt sgs-xl
mkdir -p $(CFGDIR)
mkdir -p $(DATADIR)
cp -rf data/* $(DATADIR)
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.service /lib/systemd/system
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)/DCS_Hosts.txt
.PHONY: GitVersion.h
GitVersion.h: force
ifneq ("$(wildcard .git/index)","")
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
@ -72,4 +76,4 @@ else
endif
.PHONY: force
force:
force:

@ -39,7 +39,7 @@ git clone git://github.com/F4FXL/smart-group-server-xl.git
```
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.
@ -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.
## 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
#### 2020-03-10
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) 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
* it under the terms of the GNU General Public License as published by
@ -19,8 +19,7 @@
#include "RemoteGroup.h"
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) :
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) :
m_callsign(callsign),
m_logoff(logoff),
m_repeater(repeater),
@ -30,7 +29,7 @@ m_linkStatus(linkStatus),
m_userTimeout(userTimeout),
m_users()
{
if (m_logoff.compare(" "))
if (m_logoff.compare(" ") == 0)
m_logoff.clear();
}

@ -1,6 +1,6 @@
/*
* 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
* it under the terms of the GNU General Public License as published by
@ -28,8 +28,7 @@
class CRemoteGroup {
public:
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);
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);
~CRemoteGroup();
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) 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
* it under the terms of the GNU General Public License as published by
@ -20,165 +20,203 @@
#include <cassert>
#include <cstdlib>
#include <list>
#include <vector>
#include <sstream>
#include <iterator>
#include "GroupHandler.h"
#include "RemoteHandler.h"
#include "DExtraHandler.h"
#include "DStarDefines.h"
#include "DCSHandler.h"
#include "Utils.h"
CRemoteHandler::CRemoteHandler(const std::string &password, unsigned int port, const std::string &address) :
m_password(password),
m_handler(port, address),
m_random(0U)
bool CRemoteHandler::open(const std::string &password, const unsigned short port, const bool isIPV6)
{
assert(port > 0U);
assert(password.size());
return m_tlsserver.OpenSocket(password, isIPV6 ? "::" : "0.0.0.0", port);
}
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()
{
return m_handler.open();
if (0 == cwords[0].compare("halt")) {
printf("Received halt command from remote client, shutting down...\n");
//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();
switch (type) {
case RPHT_LOGOUT:
m_handler.setLoggedIn(false);
printf("Remote control user has logged out\n");
break;
case RPHT_LOGIN:
m_random = (uint32_t)rand();
m_handler.sendRandom(m_random);
break;
case RPHT_HASH: {
bool valid = m_handler.readHash(m_password, m_random);
if (valid) {
printf("Remote control user has logged in\n");
m_handler.setLoggedIn(true);
m_handler.sendACK();
} else {
printf("Remote control user has failed login authentication\n");
m_handler.setLoggedIn(false);
m_handler.sendNAK("Invalid password");
}
}
break;
case RPHT_SMARTGROUP: {
std::string callsign = m_handler.readGroup();
sendGroup(callsign);
}
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);
char msg[128];
if (group) {
CRemoteGroup *data = group->getInfo();
if (data) {
snprintf(msg, 128, "Subscribe = %s", data->getCallsign().c_str());
m_tlsserver.Write(msg);
snprintf(msg, 128, "Unsubscribe = %s", data->getLogoff().c_str());
m_tlsserver.Write(msg);
snprintf(msg, 128, "Module = %s", data->getRepeater().c_str());
m_tlsserver.Write(msg);
snprintf(msg, 128, "Description = %s", data->getInfoText().c_str());
m_tlsserver.Write(msg);
snprintf(msg, 128, "Reflector = %s", data->getReflector().c_str());
m_tlsserver.Write(msg);
switch (data->getLinkStatus()) {
case LS_LINKING_DCS:
case LS_LINKING_DEXTRA:
m_tlsserver.Write("Link Status = Linking");
break;
case LS_LINKED_DCS:
case LS_LINKED_DEXTRA:
m_tlsserver.Write("Link Status = Linked");
break;
default:
m_tlsserver.Write("Link Status = Unlinked");
break;
}
break;
case RPHT_UNLINK: {
std::string callsign;
m_handler.readUnlink(callsign);
printf("Remote control user has unlinked \"%s\"\n", callsign.c_str());
unlink(callsign);
snprintf(msg, 128, "User Timeout = %u min", data->getUserTimeout());
m_tlsserver.Write(msg);
for (uint32_t i=0; i<data->getUserCount(); i++) {
CRemoteUser *user = data->getUser(i);
snprintf(msg, 128, " User = %s, timer = %u min, timeout = %u min", user->getCallsign().c_str(), user->getTimer()/60U, user->getTimeout()/60U);
m_tlsserver.Write(msg);
}
break;
case RPHT_LOGOFF: {
std::string callsign, user;
m_handler.readLogoff(callsign, user);
printf("Remote control user has logged off \"%s\" from \"%s\"\n", user.c_str(), callsign.c_str());
logoff(callsign, user);
}
delete data;
} else {
// no group, so let's summarize all groups
auto groups = CGroupHandler::listGroups();
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()
{
m_handler.close();
}
void CRemoteHandler::sendGroup(const std::string &callsign)
void CRemoteHandler::link(CGroupHandler *group, const std::string &reflector)
{
CGroupHandler *group = CGroupHandler::findGroup(callsign);
if (group == NULL) {
m_handler.sendNAK("Invalid Smart Group callsign");
return;
}
char msg[128];
CRemoteGroup *data = group->getInfo();
if (data != NULL)
m_handler.sendGroup(*data);
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();
if (group->remoteLink(reflector))
snprintf(msg, 128, "Smart Group %s linked to %s", data->getCallsign().c_str(), reflector.c_str());
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);
if (NULL == smartGroup) {
m_handler.sendNAK(std::string("Invalid Smart Group subscribe call ") + callsign);
return;
}
CRemoteGroup *data = smartGroup->getInfo();
if (data) {
switch (smartGroup->getLinkType()) {
case LT_DEXTRA:
CDExtraHandler::unlink(smartGroup, data->getReflector(), false);
break;
case LT_DCS:
CDCSHandler::unlink(smartGroup, data->getReflector(), false);
break;
default:
delete data;
m_handler.sendNAK("alread unlinked");
return;
}
delete data;
} else {
m_handler.sendNAK("could not get Smart Group info");
return;
char msg[128];
CRemoteGroup *data = group->getInfo();
switch (group->getLinkType()) {
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());
break;
case LT_DCS:
CDCSHandler::unlink(group, data->getReflector(), false);
snprintf(msg, 128, "Smart Group %s unlinked from %s", data->getCallsign().c_str(), data->getReflector().c_str());
break;
default:
snprintf(msg, 128, "Smart Group %s is already unlinked", data->getCallsign().c_str());
m_tlsserver.Write(msg);
delete data;
return;
}
smartGroup->setLinkType(LT_NONE);
smartGroup->clearReflector();
m_handler.sendACK();
delete data;
group->setLinkType(LT_NONE);
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);
if (pGroup == NULL) {
m_handler.sendNAK("Invalid Smart Group callsign");
return;
}
bool res = pGroup->logoff(user);
if (!res)
m_handler.sendNAK("Invalid Smart Group user callsign");
char msg[128];
CRemoteGroup *data = group->getInfo();
if (group->logoff(user))
snprintf(msg, 128, "Logging off %s from Smart Group %s", user.c_str(), data->getCallsign().c_str());
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 <cstdint>
#include "RemoteProtocolHandler.h"
#include "Timer.h"
#include "GroupHandler.h"
#include "TLSServer.h"
class CRemoteHandler {
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();
void close();
bool process();
private:
std::string m_password;
CRemoteProtocolHandler m_handler;
uint32_t m_random;
void sendGroup(const std::string &callsign);
void link(const std::string &callsign, const std::string &reflector);
void unlink(const std::string &callsign);
void logoff(const std::string &callsign, const std::string &user);
std::string m_password;
CTLSServer m_tlsserver;
void sendGroup(CGroupHandler *group);
void link(CGroupHandler *group, const std::string &reflector);
void unlink(CGroupHandler *group);
void logoff(CGroupHandler *group, const std::string &user);
};

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

@ -85,7 +85,6 @@ CSGSXLConfig::CSGSXLConfig(const std::string &pathname)
continue;
}
ircddb->isQuadNet = ircddb->hostname.find("openquad.net") != std::string::npos;
this->m_ircDDB.push_back(ircddb);
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->password = "";
ircddb->username = m_callsign;
ircddb->isQuadNet = true;
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";
}
@ -362,12 +360,11 @@ void CSGSXLConfig::getGateway(std::string& callsign, std::string& address) const
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;
username = m_ircDDB[ircddb]->username;
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

@ -40,7 +40,6 @@ struct SircDDB {
std::string hostname;
std::string username;
std::string password;
bool isQuadNet;
};
class CSGSXLConfig {
@ -50,7 +49,7 @@ public:
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;

@ -115,9 +115,9 @@ void CSGSXLThread::run()
CGroupHandler::link();
if (m_remoteEnabled && m_remotePassword.size() && m_remotePort > 0U) {
m_remote = new CRemoteHandler(m_remotePassword, m_remotePort);
bool res = m_remote->open();
if (!res) {
m_remote = new CRemoteHandler();
bool res = m_remote->open(m_remotePassword, m_remotePort, false);
if (res) {
delete m_remote;
m_remote = NULL;
}
@ -176,7 +176,6 @@ void CSGSXLThread::run()
delete m_irc;
if (m_remote != NULL) {
m_remote->close();
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 <string>
#include <vector>
#include <time.h>
#include <cstdint>
#include <ctime>
enum TRISTATE {
STATE_FALSE,

Loading…
Cancel
Save

Powered by TurnKey Linux.