Merge branch 'feature/NatTraversal' into develop fixes#5

pull/32/head
Geoffrey Merck 4 years ago
commit 6089757456

@ -71,7 +71,8 @@
"system_error": "cpp",
"thread": "cpp",
"typeindex": "cpp",
"variant": "cpp"
"variant": "cpp",
"iostream": "cpp"
},
"editor.tokenColorCustomizations": {
"textMateRules": [

@ -123,7 +123,9 @@ void* CAPRSHandlerThread::Entry()
startReconnectionTimer();
}
#ifndef DEBUG_DSTARGW
try {
#endif
m_keepAliveTimer.start();
while (!m_exit) {
if (!m_connected) {
@ -194,14 +196,18 @@ void* CAPRSHandlerThread::Entry()
auto s = m_queue.getData();
s.clear();
}
#ifndef DEBUG_DSTARGW
}
catch (std::exception& e) {
std::string message(e.what());
CLog::logInfo("Exception raised in the APRS Writer thread - \"%s\"", message.c_str());
throw;
}
catch (...) {
CLog::logInfo("Unknown exception raised in the APRS Writer thread");
throw;
}
#endif
CLog::logInfo("Stopping the APRS Writer thread");

@ -44,6 +44,10 @@ CDCSProtocolHandlerPool::~CDCSProtocolHandlerPool()
CDCSProtocolHandler *CDCSProtocolHandlerPool::getIncomingHandler()
{
auto it = m_pool.find(m_basePort);
if(it != m_pool.end())
return it->second;
return getHandler(m_basePort);
}

@ -403,8 +403,9 @@ void CDExtraHandler::process(CConnectData& connect)
}
}
void CDExtraHandler::link(IReflectorCallback* handler, const std::string& repeater, const std::string &gateway, const in_addr& address)
void CDExtraHandler::link(IReflectorCallback* handler, const std::string& repeater, const std::string &gateway, const in_addr& address, unsigned int& localPort)
{
localPort = 0U;
CDExtraProtocolHandler* protoHandler = m_pool->getHandler();
if (protoHandler == NULL)
return;
@ -422,6 +423,7 @@ void CDExtraHandler::link(IReflectorCallback* handler, const std::string& repeat
}
if (found) {
localPort = protoHandler->getPort();
CConnectData reply(repeater, gateway, CT_LINK1, address, DEXTRA_PORT);
protoHandler->writeConnect(reply);
} else {

@ -52,7 +52,7 @@ public:
static void setHeaderLogger(CHeaderLogger* logger);
static void setMaxDongles(unsigned int maxDongles);
static void link(IReflectorCallback* handler, const std::string& repeater, const std::string& reflector, const in_addr& address);
static void link(IReflectorCallback* handler, const std::string& repeater, const std::string& reflector, const in_addr& address, unsigned int& localPort);
static void unlink(IReflectorCallback* handler, const std::string& reflector = "", bool exclude = true);
static void unlink();

@ -19,7 +19,7 @@
*/
#include "DExtraProtocolHandler.h"
#include "Log.h"
#include "Utils.h"
// #define DUMP_TX
@ -113,6 +113,17 @@ bool CDExtraProtocolHandler::writeConnect(const CConnectData& connect)
return true;
}
void CDExtraProtocolHandler::traverseNat(const std::string& address, unsigned int remotePort)
{
unsigned char buffer = 0x00U;
in_addr addr = CUDPReaderWriter::lookup(address);
CLog::logInfo("DExtra Punching hole to %s:%u", address.c_str(), remotePort);
m_socket.write(&buffer, 1U, addr, remotePort);
}
DEXTRA_TYPE CDExtraProtocolHandler::read()
{
bool res = true;

@ -51,6 +51,7 @@ public:
bool writeAMBE(const CAMBEData& data);
bool writeConnect(const CConnectData& connect);
bool writePoll(const CPollData& poll);
void traverseNat(const std::string& address, unsigned int remotePort);
DEXTRA_TYPE read();
CHeaderData* readHeader();

@ -43,6 +43,10 @@ CDExtraProtocolHandlerPool::~CDExtraProtocolHandlerPool()
CDExtraProtocolHandler* CDExtraProtocolHandlerPool::getIncomingHandler()
{
auto it = m_pool.find(m_basePort);
if(it != m_pool.end())
return it->second;
return getHandler(m_basePort);
}

@ -72,7 +72,9 @@ void* CDPlusAuthenticator::Entry()
m_timer.start();
#ifndef DEBUG_DSTARGW
try {
#endif
while (!m_killed) {
if (m_timer.hasExpired()) {
authenticate(m_loginCallsign, OPENDSTAR_HOSTNAME, OPENDSTAR_PORT, '2', true);
@ -83,14 +85,18 @@ void* CDPlusAuthenticator::Entry()
m_timer.clock();
}
#ifndef DEBUG_DSTARGW
}
catch (std::exception& e) {
std::string message(e.what());
CLog::logError("Exception raised in the D-Plus Authenticator thread - \"%s\"", message.c_str());
throw;
}
catch (...) {
CLog::logError("Unknown exception raised in the D-Plus Authenticator thread");
throw;
}
#endif
CLog::logInfo("Stopping the D-Plus Authenticator thread");

@ -357,8 +357,9 @@ void CDPlusHandler::process(CConnectData& connect)
}
}
void CDPlusHandler::link(IReflectorCallback* handler, const std::string& repeater, const std::string &gateway, const in_addr& address)
void CDPlusHandler::link(IReflectorCallback* handler, const std::string& repeater, const std::string &gateway, const in_addr& address, unsigned int& localPort)
{
localPort = 0U;
CDPlusProtocolHandler* protoHandler = m_pool->getHandler();
if (protoHandler == NULL)
return;
@ -377,6 +378,7 @@ void CDPlusHandler::link(IReflectorCallback* handler, const std::string& repeate
if (found) {
CConnectData connect(CT_LINK1, address, DPLUS_PORT);
localPort = protoHandler->getPort();
protoHandler->writeConnect(connect);
m_stateChange = true;
} else {

@ -58,7 +58,7 @@ public:
static void startAuthenticator(const std::string& address, CCacheManager* cache);
static void link(IReflectorCallback* handler, const std::string& repeater, const std::string& reflector, const in_addr& address);
static void link(IReflectorCallback* handler, const std::string& repeater, const std::string& reflector, const in_addr& address, unsigned int& localPort);
static void relink(IReflectorCallback* handler, const std::string& reflector);
static void unlink(IReflectorCallback* handler, const std::string& reflector = "", bool exclude = true);
static void unlink();

@ -18,7 +18,7 @@
*/
#include "DPlusProtocolHandler.h"
#include "Log.h"
#include "DStarDefines.h"
#include "Utils.h"
@ -107,6 +107,17 @@ bool CDPlusProtocolHandler::writeConnect(const CConnectData& connect)
return m_socket.write(buffer, length, connect.getYourAddress(), connect.getYourPort());
}
void CDPlusProtocolHandler::traverseNat(const std::string& address, unsigned int remotePort)
{
unsigned char buffer = 0x00U;
in_addr addr = CUDPReaderWriter::lookup(address);
CLog::logInfo("DPlus Punching hole to %s:%u", address.c_str(), remotePort);
m_socket.write(&buffer, 1U, addr, remotePort);
}
DPLUS_TYPE CDPlusProtocolHandler::read()
{
bool res = true;

@ -27,6 +27,7 @@
#include "PollData.h"
#include <netinet/in.h>
#include <string>
enum DPLUS_TYPE {
DP_NONE,
@ -49,6 +50,7 @@ public:
bool writeAMBE(const CAMBEData& data);
bool writeConnect(const CConnectData& connect);
bool writePoll(const CPollData& poll);
void traverseNat(const std::string& address, unsigned int remotePort);
DPLUS_TYPE read();
CHeaderData* readHeader();

@ -44,6 +44,10 @@ CDPlusProtocolHandlerPool::~CDPlusProtocolHandlerPool()
CDPlusProtocolHandler* CDPlusProtocolHandlerPool::getIncomingHandler()
{
auto it = m_pool.find(m_basePort);
if(it != m_pool.end())
return it->second;
return getHandler(m_basePort);
}

@ -23,6 +23,11 @@
#include <string>
#include <iostream>
#include <vector>
#include <signal.h>
#include <exception>
#ifdef DEBUG_DSTARGW
#include <boost/stacktrace.hpp>
#endif
#include "DStarGatewayDefs.h"
#include "DStarGatewayConfig.h"
@ -41,9 +46,20 @@
#include "APRSGPSDIdFrameProvider.h"
#include "APRSFixedIdFrameProvider.h"
#ifndef UNIT_TESTS
#ifdef UNIT_TESTS
int fakemain(int argc, char *argv[])
#else
int main(int argc, char *argv[])
#endif
{
std::set_terminate(CDStarGatewayApp::terminateHandler);
signal(SIGSEGV, CDStarGatewayApp::sigHandlerFatal);
signal(SIGILL, CDStarGatewayApp::sigHandlerFatal);
signal(SIGFPE, CDStarGatewayApp::sigHandlerFatal);
signal(SIGABRT, CDStarGatewayApp::sigHandlerFatal);
// signal(SIGTERM, CDStarGatewayApp::sigHandler);
setbuf(stdout, NULL);
if (2 != argc) {
printf("usage: %s path_to_config_file\n", argv[0]);
@ -70,7 +86,6 @@ int main(int argc, char *argv[])
return 0;
}
#endif
CDStarGatewayApp::CDStarGatewayApp(const std::string &configFile) : m_configFile(configFile), m_thread(NULL)
{
@ -200,12 +215,13 @@ bool CDStarGatewayApp::createThread()
CLog::logInfo("DD Mode enabled: %d", int(ddEnabled));
// Setup ircddb
auto ircddbVersionInfo = "linux_" + PRODUCT_NAME + "-" + VERSION;
std::vector<CIRCDDB *> clients;
for(unsigned int i=0; i < config.getIrcDDBCount(); i++) {
TircDDB ircDDBConfig;
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);
CIRCDDB * ircDDB = new CIRCDDBClient(ircDDBConfig.hostname, 9007U, ircDDBConfig.username, ircDDBConfig.password, FULL_PRODUCT_NAME, gatewayConfig.address, ircDDBConfig.isQuadNet);
CIRCDDB * ircDDB = new CIRCDDBClient(ircDDBConfig.hostname, 9007U, ircDDBConfig.username, ircDDBConfig.password, ircddbVersionInfo, gatewayConfig.address, ircDDBConfig.isQuadNet);
clients.push_back(ircDDB);
}
if(clients.size() > 0U) {
@ -260,3 +276,41 @@ bool CDStarGatewayApp::createThread()
return true;
}
void CDStarGatewayApp::sigHandlerFatal(int sig)
{
CLog::logFatal("Caught signal : %s", strsignal(sig));
#ifdef DEBUG_DSTARGW
std::stringstream stackTrace;
stackTrace << boost::stacktrace::stacktrace();
CLog::logFatal("Stack Trace : \n%s", stackTrace.str().c_str());
#endif
exit(1);
}
void CDStarGatewayApp::terminateHandler()
{
#ifdef DEBUG_DSTARGW
std::stringstream stackTrace;
stackTrace << boost::stacktrace::stacktrace();
#endif
std::exception_ptr eptr;
eptr = std::current_exception();
try {
if (eptr != nullptr) {
std::rethrow_exception(eptr);
}
else {
CLog::logFatal("Unhandled unknown exception occured");
}
} catch(const std::exception& e) {
CLog::logFatal("Unhandled exception occured %s", e.what());
}
#ifdef DEBUG_DSTARGW
CLog::logFatal("Stack Trace : \n%s", stackTrace.str().c_str());
#endif
exit(1);
}

@ -21,6 +21,8 @@
#include "DStarGatewayThread.h"
void __sigHandler(int sig);
class CDStarGatewayApp
{
private:
@ -34,4 +36,7 @@ public:
bool init();
void run();
static void sigHandlerFatal(int sig);
static void terminateHandler();
};

@ -76,9 +76,6 @@ m_dextraPool(NULL),
m_dplusPool(NULL),
m_dcsPool(NULL),
m_g2Handler(NULL),
#if defined(ENABLE_NAT_TRAVERSAL)
m_natTraversal(NULL),
#endif
m_aprsWriter(NULL),
m_irc(NULL),
m_cache(),
@ -209,13 +206,6 @@ void* CDStarGatewayThread::Entry()
m_g2Handler = NULL;
}
#if defined(ENABLE_NAT_TRAVERSAL)
if(m_g2Handler != NULL) {
m_natTraversal = new CNatTraversalHandler();
m_natTraversal->setG2Handler(m_g2Handler);
}
#endif
// Wait here until we have the essentials to run
while (!m_killed && (m_dextraPool == NULL || m_dplusPool == NULL || m_dcsPool == NULL || m_g2Handler == NULL || (m_icomRepeaterHandler == NULL && m_hbRepeaterHandler == NULL && m_dummyRepeaterHandler == NULL) || m_gatewayCallsign.empty()))
::std::this_thread::sleep_for(std::chrono::milliseconds(500UL)); // 1/2 sec
@ -345,7 +335,9 @@ void* CDStarGatewayThread::Entry()
m_statusFileTimer.start();
m_statusTimer2.start();
#ifndef DEBUG_DSTARGW
try {
#endif
while (!m_killed) {
if (m_icomRepeaterHandler != NULL)
processRepeater(m_icomRepeaterHandler);
@ -421,14 +413,18 @@ void* CDStarGatewayThread::Entry()
::std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PER_TIC_MS));
}
#ifndef DEBUG_DSTARGW
}
catch (std::exception& e) {
std::string message(e.what());
CLog::logFatal("Exception raised in the main thread - \"%s\"", message.c_str());
throw;
}
catch (...) {
CLog::logFatal("Unknown exception raised in the main thread");
throw;
}
#endif
CLog::logInfo("Stopping the ircDDB Gateway thread");
@ -733,6 +729,7 @@ void CDStarGatewayThread::processIrcDDB()
m_statusTimer2.start();
}
// Process incoming ircDDB messages, updating the caches
for (;;) {
IRCDDB_RESPONSE_TYPE type = m_irc->getMessageType();
@ -747,9 +744,6 @@ void CDStarGatewayThread::processIrcDDB()
if (!address.empty()) {
CLog::logDebug("USER: %s %s %s %s", user.c_str(), repeater.c_str(), gateway.c_str(), address.c_str());
m_cache.updateUser(user, repeater, gateway, address, timestamp, DP_DEXTRA, false, false);
#if defined(ENABLE_NAT_TRAVERSAL)
m_natTraversal->traverseNatG2(address);
#endif
} else {
CLog::logDebug("USER: %s NOT FOUND", user.c_str());
}
@ -766,9 +760,6 @@ void CDStarGatewayThread::processIrcDDB()
if (!address.empty()) {
CLog::logDebug("REPEATER: %s %s %s", repeater.c_str(), gateway.c_str(), address.c_str());
m_cache.updateRepeater(repeater, gateway, address, DP_DEXTRA, false, false);
#if defined(ENABLE_NAT_TRAVERSAL)
m_natTraversal->traverseNatG2(address);
#endif
} else {
CLog::logDebug("REPEATER: %s NOT FOUND", repeater.c_str());
}
@ -786,15 +777,60 @@ void CDStarGatewayThread::processIrcDDB()
if (!address.empty()) {
CLog::logDebug("GATEWAY: %s %s", gateway.c_str(), address.c_str());
m_cache.updateGateway(gateway, address, DP_DEXTRA, false, false);
#if defined(ENABLE_NAT_TRAVERSAL)
m_natTraversal->traverseNatG2(address);
#endif
} else {
CLog::logDebug("GATEWAY: %s NOT FOUND", gateway.c_str());
}
}
break;
case IDRT_NATTRAVERSAL_G2: {
std::string address;
bool res = m_irc->receiveNATTraversalG2(address);
if(!res)
return;
if(m_g2Handler != nullptr) {
CLog::logInfo("%s wants to G2 route to us, punching UDP Holes through NAT", address.c_str());
m_g2Handler->traverseNat(address);
}
else {
CLog::logInfo("%s wants to G2 route to us, but G2 is disabled", address.c_str());
}
}
break;
case IDRT_NATTRAVERSAL_DEXTRA: {
std::string address, remotePort;
bool res = m_irc->receiveNATTraversalDextra(address, remotePort);
if(!res)
return;
auto remotePortInt = CStringUtils::stringToPort(remotePort);
if(m_dextraEnabled && remotePortInt > 0U && m_dextraPool != nullptr && m_dextraPool->getIncomingHandler() != nullptr) {
CLog::logInfo("%s wants to DExtra connect to us, punching UDP Holes through NAT, remote port %s", address.c_str(), remotePort.c_str());
m_dextraPool->getIncomingHandler()->traverseNat(address, remotePortInt);
}
else {
CLog::logInfo("%s wants to DExtra connect to us, punching UDP Holes through NAT, remote port %s, but DExtra is Disabled", address.c_str(), remotePort.c_str());
}
}
break;
case IDRT_NATTRAVERSAL_DPLUS: {
std::string address, remotePort;
bool res = m_irc->receiveNATTraversalDPlus(address, remotePort);
if(!res)
return;
auto remotePortInt = CStringUtils::stringToPort(remotePort);
if(m_dplusEnabled && remotePortInt > 0U && m_dplusPool != nullptr && m_dplusPool->getIncomingHandler() != nullptr) {
CLog::logInfo("%s wants to DPlus connect to us, punching UDP Holes through NAT, remote port %s", address.c_str(), remotePort.c_str());
m_dplusPool->getIncomingHandler()->traverseNat(address, remotePortInt);
}
else {
CLog::logInfo("%s wants to DPlus connect to us, punching UDP Holes through NAT, remote port %s, but DPlus is Disabled", address.c_str(), remotePort.c_str());
}
}
break;
case IDRT_NONE:
return;
default:
return;
}

@ -37,9 +37,6 @@
#include "Timer.h"
#include "Defs.h"
#include "Thread.h"
#if defined(ENABLE_NAT_TRAVERSAL)
#include "NatTraversalHandler.h"
#endif
class CDStarGatewayThread : public CThread{
public:
@ -106,9 +103,6 @@ private:
CDPlusProtocolHandlerPool* m_dplusPool;
CDCSProtocolHandlerPool* m_dcsPool;
CG2ProtocolHandler* m_g2Handler;
#if defined(ENABLE_NAT_TRAVERSAL)
CNatTraversalHandler* m_natTraversal;
#endif
CAPRSHandler* m_aprsWriter;
CIRCDDB* m_irc;
CCacheManager m_cache;

@ -206,3 +206,5 @@ bool CG2Handler::clockInt(unsigned int ms)
return false;
}

@ -41,7 +41,7 @@ m_port(0U)
CG2ProtocolHandler::~CG2ProtocolHandler()
{
delete[] m_buffer;
portmap.clear();
m_portmap.clear();
}
bool CG2ProtocolHandler::open()
@ -59,8 +59,8 @@ bool CG2ProtocolHandler::writeHeader(const CHeaderData& header)
#endif
in_addr addr = header.getYourAddress();
auto found = portmap.find(addr.s_addr);
unsigned int port = (portmap.end()==found) ? header.getYourPort() : found->second;
auto found = m_portmap.find(addr.s_addr);
unsigned int port = (m_portmap.end()==found) ? header.getYourPort() : found->second;
for (unsigned int i = 0U; i < 5U; i++) {
bool res = m_socket.write(buffer, length, addr, port);
@ -81,8 +81,8 @@ bool CG2ProtocolHandler::writeAMBE(const CAMBEData& data)
#endif
in_addr addr = data.getYourAddress();
auto found = portmap.find(addr.s_addr);
unsigned int port = (portmap.end()==found) ? data.getYourPort() : found->second;
auto found = m_portmap.find(addr.s_addr);
unsigned int port = (m_portmap.end()==found) ? data.getYourPort() : found->second;
return m_socket.write(buffer, length, addr, port);
}
@ -107,16 +107,20 @@ bool CG2ProtocolHandler::readPackets()
if (length <= 0)
return false;
if(length == 1) {
CLog::logDebug("G2 Nat traversal packet received");
}
m_length = length;
// save the incoming port (this is to enable mobile hotspots)
if (portmap.end() == portmap.find(m_address.s_addr)) {
CLog::logInfo("new address %s on port %u\n", inet_ntoa(m_address), m_port);
portmap[m_address.s_addr] = m_port;
if (m_portmap.end() == m_portmap.find(m_address.s_addr)) {
CLog::logInfo("G2 new address %s on port %u\n", inet_ntoa(m_address), m_port);
m_portmap[m_address.s_addr] = m_port;
} else {
if (portmap[m_address.s_addr] != m_port) {
CLog::logInfo("new port for %s is %u, was %u\n", inet_ntoa(m_address), m_port, portmap[m_address.s_addr]);
portmap[m_address.s_addr] = m_port;
if (m_portmap[m_address.s_addr] != m_port) {
CLog::logInfo("G2 new port for %s is %u, was %u\n", inet_ntoa(m_address), m_port, m_portmap[m_address.s_addr]);
m_portmap[m_address.s_addr] = m_port;
}
}
@ -170,3 +174,14 @@ void CG2ProtocolHandler::close()
{
m_socket.close();
}
void CG2ProtocolHandler::traverseNat(const std::string& address)
{
unsigned char buffer = 0x00U;
in_addr addr = CUDPReaderWriter::lookup(address);
CLog::logInfo("G2 Punching hole to %s", address.c_str());
m_socket.write(&buffer, 1U, addr, G2_DV_PORT);
}

@ -47,9 +47,10 @@ public:
CAMBEData* readAMBE();
void close();
void traverseNat(const std::string& address);
private:
std::unordered_map<uint32_t, unsigned int> portmap;
std::unordered_map<uint32_t, unsigned int> m_portmap;
CUDPReaderWriter m_socket;
G2_TYPE m_type;

@ -31,7 +31,10 @@ enum IRCDDB_RESPONSE_TYPE {
IDRT_NONE,
IDRT_USER,
IDRT_GATEWAY,
IDRT_REPEATER
IDRT_REPEATER,
IDRT_NATTRAVERSAL_G2,
IDRT_NATTRAVERSAL_DEXTRA,
IDRT_NATTRAVERSAL_DPLUS,
};
@ -111,6 +114,11 @@ public:
// Send query for a user, a false return implies a network error
virtual bool findUser(const std::string& userCallsign) = 0;
// notify another repeater for NAT Traversal, a false return implies a network error
virtual bool notifyRepeaterG2NatTraversal(const std::string& repeater) = 0;
virtual bool notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myport) = 0;
virtual bool notifyRepeaterDPlusNatTraversal(const std::string& repeater, unsigned int myport) = 0;
// Support for the Smart Group Server
virtual void sendDStarGatewayInfo(const std::string subcommand, const std::vector<std::string> parms) = 0;
@ -134,6 +142,10 @@ public:
virtual bool receiveUser(std::string& userCallsign, std::string& repeaterCallsign, std::string& gatewayCallsign, std::string& address, std::string& timeStamp) = 0;
virtual bool receiveNATTraversalG2(std::string& address) = 0;
virtual bool receiveNATTraversalDextra(std::string& address, std::string& remotePort) = 0;
virtual bool receiveNATTraversalDPlus(std::string& address, std::string& remotePort) = 0;
virtual void close() = 0; // Implictely kills any threads in the IRC code
};

File diff suppressed because it is too large Load Diff

@ -67,6 +67,10 @@ public:
bool findRepeater(const std::string& s);
bool findGateway(const std::string& s);
bool notifyRepeaterG2NatTraversal(const std::string& repeater);
bool notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myLocalPort);
bool notifyRepeaterDPlusNatTraversal(const std::string& repeater, unsigned int myLocalPort);
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);
@ -86,11 +90,14 @@ protected:
private:
void doUpdate(std::string& msg);
void doNotFound(std::string& msg, std::string& retval);
std::string getIPAddress(std::string& zonerp_cs);
std::string getIPAddressFromCall(std::string& zonerp_cs);
std::string getIPAddressFromNick(std::string& ircUser);
bool findServerUser();
unsigned int calculateUsn(const std::string& nick);
std::string getLastEntryTime(int tableID);
IRCDDBAppPrivate *d;
bool getNickForRepeater(const std::string& repeater, std::string& user) const;
IRCDDBAppPrivate *m_d;
time_t m_maxTime;
std::future<void> m_future;
};

@ -28,23 +28,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
struct CIRCDDBClientPrivate
{
IRCClient *client;
IRCDDBApp *app;
IRCDDBApp *m_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_d(new CIRCDDBClientPrivate),
m_isQuadNet(isQuadNet)
{
std::string update_channel("#dstar");
d->app = new IRCDDBApp(update_channel);
d->client = new IRCClient(d->app, update_channel, hostName, port, callsign, password, versionInfo, localAddr);
m_d->m_app = new IRCDDBApp(update_channel);
m_d->client = new IRCClient(m_d->m_app, update_channel, hostName, port, callsign, password, versionInfo, localAddr);
}
CIRCDDBClient::~CIRCDDBClient()
{
delete d->client;
delete d->app;
delete d;
delete m_d->client;
delete m_d->m_app;
delete m_d;
}
@ -52,33 +52,33 @@ CIRCDDBClient::~CIRCDDBClient()
bool CIRCDDBClient::open()
{
CLog::logInfo("start client and app\n");
d->client->startWork();
d->app->startWork();
m_d->client->startWork();
m_d->m_app->startWork();
return true;
}
int CIRCDDBClient::getConnectionState()
{
return d->app->getConnectionState();
return m_d->m_app->getConnectionState();
}
void CIRCDDBClient::rptrQTH(const std::string& callsign, double latitude, double longitude, const std::string& desc1, const std::string& desc2, const std::string& infoURL)
{
d->app->rptrQTH(callsign, latitude, longitude, desc1, desc2, infoURL);
m_d->m_app->rptrQTH(callsign, latitude, longitude, desc1, desc2, infoURL);
}
void CIRCDDBClient::rptrQRG(const std::string& callsign, double txFrequency, double duplexShift, double range, double agl)
{
d->app->rptrQRG(callsign, txFrequency, duplexShift, range, agl);
m_d->m_app->rptrQRG(callsign, txFrequency, duplexShift, range, agl);
}
void CIRCDDBClient::kickWatchdog(const std::string& callsign, const std::string& wdInfo)
{
d->app->kickWatchdog(callsign, wdInfo);
m_d->m_app->kickWatchdog(callsign, wdInfo);
}
@ -112,7 +112,7 @@ bool CIRCDDBClient::sendHeard( const std::string& myCall, const std::string& myC
return false;
}
return d->app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, std::string(" "), std::string(""), std::string(""));
return m_d->m_app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, std::string(" "), std::string(""), std::string(""));
}
void CIRCDDBClient::sendDStarGatewayInfo(const std::string subcommand, const std::vector<std::string> parms)
@ -123,7 +123,7 @@ void CIRCDDBClient::sendDStarGatewayInfo(const std::string subcommand, const std
CLog::logInfo("\n");
if(m_isQuadNet) {
d->app->sendDStarGatewayInfo(subcommand, parms);
m_d->m_app->sendDStarGatewayInfo(subcommand, parms);
}
}
@ -175,7 +175,7 @@ bool CIRCDDBClient::sendHeardWithTXMsg(const std::string& myCall, const std::str
msg.push_back('_');
}
}
return d->app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, dest, msg, std::string(""));
return m_d->m_app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, dest, msg, std::string(""));
}
@ -238,7 +238,7 @@ bool CIRCDDBClient::sendHeardWithTXStats( const std::string& myCall, const std::
}
stats.resize(20, '_');
return d->app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, std::string(" "), std::string(""), stats);
return m_d->m_app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, std::string(" "), std::string(""), stats);
}
// Send query for a gateway/reflector, a false return implies a network error
@ -250,7 +250,7 @@ bool CIRCDDBClient::findGateway(const std::string& gatewayCallsign)
}
std::string gw(gatewayCallsign);
CUtils::ToUpper(gw);
return d->app->findGateway(gw);
return m_d->m_app->findGateway(gw);
}
@ -262,7 +262,7 @@ bool CIRCDDBClient::findRepeater(const std::string& repeaterCallsign)
}
std::string rptr(repeaterCallsign);
CUtils::ToUpper(rptr);
return d->app->findRepeater(rptr);
return m_d->m_app->findRepeater(rptr);
}
// Send query for a user, a false return implies a network error
@ -272,9 +272,25 @@ bool CIRCDDBClient::findUser(const std::string& userCallsign)
CLog::logDebug("CIRCDDBClient::findUser:userCall='%s' len != 8\n", userCallsign.c_str());
return false;
}
CLog::logTrace("IRC Find user %s", userCallsign.c_str());
std::string usr(userCallsign);
CUtils::ToUpper(usr);
return d->app->findUser(usr);
return m_d->m_app->findUser(usr);
}
bool CIRCDDBClient::notifyRepeaterG2NatTraversal(const std::string& repeater)
{
return m_d->m_app->notifyRepeaterG2NatTraversal(repeater);
}
bool CIRCDDBClient::notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myPort)
{
return m_d->m_app->notifyRepeaterDextraNatTraversal(repeater, myPort);
}
bool CIRCDDBClient::notifyRepeaterDPlusNatTraversal(const std::string& repeater, unsigned int myPort)
{
return m_d->m_app->notifyRepeaterDPlusNatTraversal(repeater, myPort);
}
// The following functions are for processing received messages
@ -282,21 +298,21 @@ bool CIRCDDBClient::findUser(const std::string& userCallsign)
// Get the waiting message type
IRCDDB_RESPONSE_TYPE CIRCDDBClient::getMessageType()
{
return d->app->getReplyMessageType();
return m_d->m_app->getReplyMessageType();
}
// Get a gateway message, as a result of IDRT_REPEATER returned from getMessageType()
// A false return implies a network error
bool CIRCDDBClient::receiveRepeater(std::string& repeaterCallsign, std::string& gatewayCallsign, std::string& address)
{
IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType();
IRCDDB_RESPONSE_TYPE rt = m_d->m_app->getReplyMessageType();
if (rt != IDRT_REPEATER) {
CLog::logDebug("CIRCDDBClient::receiveRepeater: unexpected response type=%d\n", rt);
return false;
}
IRCMessage *m = d->app->getReplyMessage();
IRCMessage *m = m_d->m_app->getReplyMessage();
if (m == NULL) {
CLog::logDebug("CIRCDDBClient::receiveRepeater: no message\n");
return false;
@ -325,14 +341,14 @@ bool CIRCDDBClient::receiveRepeater(std::string& repeaterCallsign, std::string&
// A false return implies a network error
bool CIRCDDBClient::receiveGateway(std::string& gatewayCallsign, std::string& address)
{
IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType();
IRCDDB_RESPONSE_TYPE rt = m_d->m_app->getReplyMessageType();
if (rt != IDRT_GATEWAY) {
CLog::logDebug("CIRCDDBClient::receiveGateway: unexpected response type=%d\n", rt);
return false;
}
IRCMessage *m = d->app->getReplyMessage();
IRCMessage *m = m_d->m_app->getReplyMessage();
if (m == NULL) {
CLog::logDebug("CIRCDDBClient::receiveGateway: no message\n");
@ -367,14 +383,14 @@ bool CIRCDDBClient::receiveUser(std::string& userCallsign, std::string& repeater
bool CIRCDDBClient::receiveUser(std::string& userCallsign, std::string& repeaterCallsign, std::string& gatewayCallsign, std::string& address, std::string& timeStamp)
{
IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType();
IRCDDB_RESPONSE_TYPE rt = m_d->m_app->getReplyMessageType();
if (rt != IDRT_USER) {
CLog::logDebug("CIRCDDBClient::receiveUser: unexpected response type=%d\n", rt);
return false;
}
IRCMessage * m = d->app->getReplyMessage();
IRCMessage * m = m_d->m_app->getReplyMessage();
if (m == NULL) {
CLog::logDebug("CIRCDDBClient::receiveUser: no message\n");
@ -398,13 +414,119 @@ bool CIRCDDBClient::receiveUser(std::string& userCallsign, std::string& repeater
gatewayCallsign = m->getParam(2);
address = m->getParam(3);
timeStamp = m->getParam(4);
//CLog::logTrace("IRC Receive User %s %s %s %s %s", userCallsign.c_str(), repeaterCallsign.c_str(), gatewayCallsign.c_str(), address.c_str(), timeStamp.c_str());
delete m;
return true;
}
void CIRCDDBClient::close() // Implictely kills any threads in the IRC code
bool CIRCDDBClient::receiveNATTraversalG2(std::string& address)
{
d->client -> stopWork();
d->app -> stopWork();
IRCDDB_RESPONSE_TYPE rt = m_d->m_app->getReplyMessageType();
if(rt != IDRT_NATTRAVERSAL_G2) {
CLog::logDebug("CIRCDDBClient::receiveNATTraversalG2: unexpected response type=%d\n", rt);
return false;
}
IRCMessage * m = m_d->m_app->getReplyMessage();
if (m == NULL) {
CLog::logDebug("CIRCDDBClient::receiveNATTraversalG2: no message\n");
return false;
}
if (m->getCommand().compare("NATTRAVERSAL_G2")) {
CLog::logDebug("CIRCDDBClient::receiveNATTraversalG2: wrong message type, expected 'NATTRAVERSAL_G2', got '%s'\n", m->getCommand().c_str());
delete m;
return false;
}
if (1 != m->getParamCount()) {
CLog::logDebug("CIRCDDBClient::receiveNATTraversalG2: unexpected number of message parameters, expected 1, got %d\n", m->getParamCount());
delete m;
return false;
}
address = m->m_params[0];
delete m;
return true;
}
bool CIRCDDBClient::receiveNATTraversalDextra(std::string& address, std::string& remotePort)
{
IRCDDB_RESPONSE_TYPE rt = m_d->m_app->getReplyMessageType();
if(rt != IDRT_NATTRAVERSAL_DEXTRA) {
CLog::logDebug("CIRCDDBClient::receiveNATTraversalDextra: unexpected response type=%d\n", rt);
return false;
}
IRCMessage * m = m_d->m_app->getReplyMessage();
if (m == NULL) {
CLog::logDebug("CIRCDDBClient::receiveNATTraversalDextra: no message\n");
return false;
}
if (m->getCommand().compare("NATTRAVERSAL_DEXTRA")) {
CLog::logDebug("CIRCDDBClient::receiveNATTraversalDextra: wrong message type, expected 'NATTRAVERSAL_DEXTRA', got '%s'\n", m->getCommand().c_str());
delete m;
return false;
}
if (2 != m->getParamCount()) {
CLog::logDebug("CIRCDDBClient::receiveNATTraversalDextra: unexpected number of message parameters, expected 2, got %d\n", m->getParamCount());
delete m;
return false;
}
address = m->m_params[0];
remotePort = m->m_params[1];
delete m;
return true;
}
bool CIRCDDBClient::receiveNATTraversalDPlus(std::string& address, std::string& remotePort)
{
IRCDDB_RESPONSE_TYPE rt = m_d->m_app->getReplyMessageType();
if(rt != IDRT_NATTRAVERSAL_DPLUS) {
CLog::logDebug("CIRCDDBClient::receiveNATTraversalDPlus: unexpected response type=%d\n", rt);
return false;
}
IRCMessage * m = m_d->m_app->getReplyMessage();
if (m == NULL) {
CLog::logDebug("CIRCDDBClient::receiveNATTraversalDPlus: no message\n");
return false;
}
if (m->getCommand().compare("NATTRAVERSAL_DPLUS")) {
CLog::logDebug("CIRCDDBClient::receiveNATTraversalDPlus: wrong message type, expected 'NATTRAVERSAL_DPLUS', got '%s'\n", m->getCommand().c_str());
delete m;
return false;
}
if (2 != m->getParamCount()) {
CLog::logDebug("CIRCDDBClient::receiveNATTraversalDPlus: unexpected number of message parameters, expected 2, got %d\n", m->getParamCount());
delete m;
return false;
}
address = m->m_params[0];
remotePort = m->m_params[1];
delete m;
return true;
}
void CIRCDDBClient::close() // Implictely kills any threads in the IRC code
{
m_d->client -> stopWork();
m_d->m_app -> stopWork();
}

@ -106,6 +106,11 @@ public:
// Send query for a user, a false return implies a network error
bool findUser(const std::string& userCallsign);
// notify another repeater for NAT Traversal, a false return implies a network error
bool notifyRepeaterG2NatTraversal(const std::string& repeater);
bool notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myport);
bool notifyRepeaterDPlusNatTraversal(const std::string& repeater, unsigned int myport);
// Support for the Smart Group Server
void sendDStarGatewayInfo(const std::string subcommand, const std::vector<std::string> parms);
@ -128,10 +133,14 @@ public:
bool receiveUser(std::string& userCallsign, std::string& repeaterCallsign, std::string& gatewayCallsign, std::string& address, std::string& timeStamp);
bool receiveNATTraversalG2(std::string& address);
bool receiveNATTraversalDextra(std::string& address, std::string& remotePort);
bool receiveNATTraversalDPlus(std::string& address, std::string& remotePort);
void close(); // Implictely kills any threads in the IRC code
private:
struct CIRCDDBClientPrivate * const d;
struct CIRCDDBClientPrivate * const m_d;
bool m_isQuadNet;
};

@ -150,7 +150,7 @@ void CIRCDDBMultiClient::sendDStarGatewayInfo(const std::string subcommand, cons
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));
bool result = true;
for (unsigned int i = 0; i < m_clients.size(); i++) {
result = m_clients[i]->findGateway(gatewayCallsign) && result;
@ -161,7 +161,7 @@ bool CIRCDDBMultiClient::findGateway(const std::string & gatewayCallsign)
bool CIRCDDBMultiClient::findRepeater(const std::string & repeaterCallsign)
{
pushQuery(IDRT_REPEATER, repeaterCallsign, new CIRCDDBMultiClientQuery("", repeaterCallsign, "", "", "", IDRT_REPEATER));
pushQuery(IDRT_REPEATER, repeaterCallsign, new CIRCDDBMultiClientQuery("", repeaterCallsign, "", "", "", "", IDRT_REPEATER));
bool result = true;
for (unsigned int i = 0; i < m_clients.size(); i++) {
result = m_clients[i]->findRepeater(repeaterCallsign) && result;
@ -172,7 +172,7 @@ bool CIRCDDBMultiClient::findRepeater(const std::string & repeaterCallsign)
bool CIRCDDBMultiClient::findUser(const std::string & userCallsign)
{
pushQuery(IDRT_USER, userCallsign, new CIRCDDBMultiClientQuery(userCallsign, "", "", "", "", IDRT_USER));
pushQuery(IDRT_USER, userCallsign, new CIRCDDBMultiClientQuery(userCallsign, "", "", "", "", "", IDRT_USER));
bool result = true;
for (unsigned int i = 0; i < m_clients.size(); i++) {
result = m_clients[i]->findUser(userCallsign) && result;
@ -181,11 +181,79 @@ bool CIRCDDBMultiClient::findUser(const std::string & userCallsign)
return result;
}
bool CIRCDDBMultiClient::notifyRepeaterG2NatTraversal(const std::string& repeater)
{
// NAT traversal message does not expect a response over IRC
bool result = true;
for (unsigned int i = 0; i < m_clients.size(); i++) {
result = m_clients[i]->notifyRepeaterG2NatTraversal(repeater) && result;
}
return result;
}
bool CIRCDDBMultiClient::notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myPort)
{
// NAT traversal message does not expect a response over IRC
bool result = true;
for (unsigned int i = 0; i < m_clients.size(); i++) {
result = m_clients[i]->notifyRepeaterDextraNatTraversal(repeater, myPort) && result;
}
return result;
}
bool CIRCDDBMultiClient::notifyRepeaterDPlusNatTraversal(const std::string& repeater, unsigned int myPort)
{
// NAT traversal message does not expect a response over IRC
bool result = true;
for (unsigned int i = 0; i < m_clients.size(); i++) {
result = m_clients[i]->notifyRepeaterDPlusNatTraversal(repeater, myPort) && result;
}
return result;
}
bool CIRCDDBMultiClient::receiveNATTraversalG2(std::string& address)
{
CIRCDDBMultiClientQuery * item = checkAndGetNextResponse(IDRT_NATTRAVERSAL_G2, "CIRCDDBMultiClient::receiveNATTraversalG2: unexpected response type");
if (item == NULL)
return false;
address = item->getAddress();
return true;
}
bool CIRCDDBMultiClient::receiveNATTraversalDextra(std::string& address, std::string& remotePort)
{
CIRCDDBMultiClientQuery * item = checkAndGetNextResponse(IDRT_NATTRAVERSAL_DEXTRA, "CIRCDDBMultiClient::receiveNATTraversalDextra: unexpected response type");
if (item == NULL)
return false;
address = item->getAddress();
remotePort = item->getRemotePort();
return true;
}
bool CIRCDDBMultiClient::receiveNATTraversalDPlus(std::string& address, std::string& remotePort)
{
CIRCDDBMultiClientQuery * item = checkAndGetNextResponse(IDRT_NATTRAVERSAL_DPLUS, "CIRCDDBMultiClient::receiveNATTraversalDextra: unexpected response type");
if (item == NULL)
return false;
address = item->getAddress();
remotePort = item->getRemotePort();
return true;
}
IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType()
{
//procees the inner clients at each call
//process the inner clients at each call
for (unsigned int i = 0; i < m_clients.size(); i++) {
std::string user = "", repeater = "", gateway = "", address = "", timestamp = "", key = "";
std::string user = "", repeater = "", gateway = "", address = "", timestamp = "", key = "", port ="";
IRCDDB_RESPONSE_TYPE type = m_clients[i]->getMessageType();
@ -208,6 +276,24 @@ IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType()
key = repeater;
break;
}
case IDRT_NATTRAVERSAL_G2: {
if (!m_clients[i]->receiveNATTraversalG2(address))
type = IDRT_NATTRAVERSAL_G2;
key = "NAT_TRAVERSAL_G2";
break;
}
case IDRT_NATTRAVERSAL_DEXTRA: {
if (!m_clients[i]->receiveNATTraversalDextra(address, port))
type = IDRT_NATTRAVERSAL_DEXTRA;
key = "NAT_TRAVERSAL_DEXTRA";
break;
}
case IDRT_NATTRAVERSAL_DPLUS: {
if (!m_clients[i]->receiveNATTraversalDPlus(address, port))
type = IDRT_NATTRAVERSAL_DEXTRA;
key = "NAT_TRAVERSAL_DPLUS";
break;
}
case IDRT_NONE: {
default:
break;
@ -223,12 +309,12 @@ IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType()
CIRCDDBMultiClientQuery * item = popQuery(type, key);
if (item != NULL) {//is this a response to a query we've sent ?
item->Update(user, repeater, gateway, address, timestamp);//update item (if needed)
item->Update(user, repeater, gateway, address, timestamp, port);//update item (if needed)
canAddToQueue = (item->incrementResponseCount() >= m_clients.size()); //did all the clients respond or did we have an answer ?
wasQuery = true;
}
else {
item = new CIRCDDBMultiClientQuery(user, repeater, gateway, address, timestamp, type);
item = new CIRCDDBMultiClientQuery(user, repeater, gateway, address, timestamp, port, type);
canAddToQueue = true;
}
@ -244,7 +330,7 @@ IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType()
}
}
IRCDDB_RESPONSE_TYPE result = IDRT_NONE;
IRCDDB_RESPONSE_TYPE result = IDRT_NONE;
m_responseQueueLock.lock();
if (m_responseQueue.size() != 0) result = m_responseQueue[0]->getType();
@ -370,5 +456,3 @@ CIRCDDBMultiClientQuery_HashMap * CIRCDDBMultiClient::getQueriesHashMap(IRCDDB_R
return NULL;
}
}

@ -40,12 +40,14 @@ public:
const std::string& gateway,
const std::string& address,
const std::string& timestamp,
const std::string& remotePort,
IRCDDB_RESPONSE_TYPE type) :
m_user(user),
m_repeater(repeater),
m_gateway(gateway),
m_address(address),
m_timestamp(timestamp),
m_remotePort(remotePort),
m_type(type),
m_responseCount(0)
{
@ -77,6 +79,11 @@ public:
return m_timestamp;
}
std::string getRemotePort() const
{
return m_remotePort;
}
unsigned int getResponseCount()
{
return m_responseCount;
@ -92,7 +99,7 @@ public:
/*
Updates the entry, but only if the timestamp is newer. if an address was already specified it is kept.
*/
void Update(const std::string& user, const std::string& repeater, const std::string& gateway, const std::string& address, const std::string& timestamp)
void Update(const std::string& user, const std::string& repeater, const std::string& gateway, const std::string& address, const std::string& timestamp, const std::string& remotePort)
{
//wxLogMessage("Before : %s"), toString());
if (timestamp.empty() || timestamp.compare(m_timestamp) >= 0) {
@ -100,6 +107,7 @@ public:
m_repeater = repeater;
m_gateway = gateway;
m_timestamp = timestamp;
m_remotePort = remotePort;
if(m_address.empty() && !address.empty())
m_address = address;
@ -125,6 +133,7 @@ private:
std::string m_gateway;
std::string m_address;
std::string m_timestamp;
std::string m_remotePort;
IRCDDB_RESPONSE_TYPE m_type;
unsigned int m_responseCount;
};
@ -150,11 +159,17 @@ public:
virtual bool findGateway(const std::string & gatewayCallsign);
virtual bool findRepeater(const std::string & repeaterCallsign);
virtual bool findUser(const std::string & userCallsign);
virtual bool notifyRepeaterG2NatTraversal(const std::string& repeater);
virtual bool notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myPort);
virtual bool notifyRepeaterDPlusNatTraversal(const std::string& repeater, unsigned int myPort);
virtual IRCDDB_RESPONSE_TYPE getMessageType();
virtual bool receiveRepeater(std::string & repeaterCallsign, 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, std::string & timeStamp);
virtual bool receiveNATTraversalG2(std::string& address);
virtual bool receiveNATTraversalDextra(std::string& address, std::string& remotePort);
virtual bool receiveNATTraversalDPlus(std::string& address, std::string& remotePort);
virtual void sendDStarGatewayInfo(const std::string subcommand, const std::vector<std::string> parms);
virtual void close();

@ -24,24 +24,24 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
IRCMessage::IRCMessage()
{
numParams = 0;
prefixParsed = false;
m_numParams = 0;
m_prefixParsed = false;
}
IRCMessage::IRCMessage(const std::string& toNick, const std::string& msg)
{
command.assign("PRIVMSG");
numParams = 2;
params.push_back(toNick);
params.push_back(msg);
prefixParsed = false;
m_command.assign("PRIVMSG");
m_numParams = 2;
m_params.push_back(toNick);
m_params.push_back(msg);
m_prefixParsed = false;
}
IRCMessage::IRCMessage(const std::string& cmd)
{
command = cmd;
numParams = 0;
prefixParsed = false;
m_command = cmd;
m_numParams = 0;
m_prefixParsed = false;
}
IRCMessage::~IRCMessage()
@ -51,79 +51,79 @@ IRCMessage::~IRCMessage()
void IRCMessage::addParam(const std::string& p)
{
params.push_back(p);
numParams = params.size();
m_params.push_back(p);
m_numParams = m_params.size();
}
int IRCMessage::getParamCount()
{
return params.size();
return m_params.size();
}
std::string IRCMessage::getParam(int pos)
{
return params[pos];
return m_params[pos];
}
std::string IRCMessage::getCommand()
{
return command;
return m_command;
}
bool IRCMessage::parsePrefix()
{
std::string::size_type p1 = prefix.find('!');
std::string::size_type p1 = m_prefix.find('!');
if (std::string::npos == p1)
return false;
std::string::size_type p2 = prefix.find('@');
std::string::size_type p2 = m_prefix.find('@');
if (std::string::npos == p2)
return false;
prefixComponents.push_back(prefix.substr(0, p1));
prefixComponents.push_back(prefix.substr(p1+1, p2-p1-1));
prefixComponents.push_back(prefix.substr(p2 + 1));
m_prefixComponents.push_back(m_prefix.substr(0, p1));
m_prefixComponents.push_back(m_prefix.substr(p1+1, p2-p1-1));
m_prefixComponents.push_back(m_prefix.substr(p2 + 1));
return true;
}
std::string& IRCMessage::getPrefixNick()
{
if (!prefixParsed)
prefixParsed = parsePrefix();
if (!m_prefixParsed)
m_prefixParsed = parsePrefix();
return prefixParsed ? prefixComponents[0] : prefix;
return m_prefixParsed ? m_prefixComponents[0] : m_prefix;
}
std::string& IRCMessage::getPrefixName()
{
if (!prefixParsed)
prefixParsed = parsePrefix();
if (!m_prefixParsed)
m_prefixParsed = parsePrefix();
return prefixParsed ? prefixComponents[1] : prefix;
return m_prefixParsed ? m_prefixComponents[1] : m_prefix;
}
std::string& IRCMessage::getPrefixHost()
{
if (!prefixParsed)
prefixParsed = parsePrefix();
if (!m_prefixParsed)
m_prefixParsed = parsePrefix();
return prefixParsed ? prefixComponents[2] : prefix;
return m_prefixParsed ? m_prefixComponents[2] : m_prefix;
}
void IRCMessage::composeMessage(std::string& output)
{
std::string o;
if (prefix.size() > 0)
o = std::string(":") + prefix + std::string(" ");
if (m_prefix.size() > 0)
o = std::string(":") + m_prefix + std::string(" ");
o.append(command);
o.append(m_command);
for (int i=0; i < numParams; i++) {
if (i == (numParams - 1))
o.append(std::string(" :") + params[i]);
for (int i=0; i < m_numParams; i++) {
if (i == (m_numParams - 1))
o.append(std::string(" :") + m_params[i]);
else
o.append(std::string(" ") + params[i]);
o.append(std::string(" ") + m_params[i]);
}
o.append(std::string("\r\n"));

@ -32,11 +32,11 @@ public:
IRCMessage(const std::string& command);
~IRCMessage();
std::string prefix;
std::string command;
std::vector<std::string> params;
std::string m_prefix;
std::string m_command;
std::vector<std::string> m_params;
int numParams;
int m_numParams;
std::string& getPrefixNick();
std::string& getPrefixName();
std::string& getPrefixHost();
@ -49,6 +49,6 @@ public:
private:
bool parsePrefix();
std::vector<std::string> prefixComponents;
bool prefixParsed;
std::vector<std::string> m_prefixComponents;
bool m_prefixParsed;
};

@ -33,7 +33,7 @@ IRCMessageQueue::IRCMessageQueue()
IRCMessageQueue::~IRCMessageQueue()
{
std::lock_guard lockAccessQueue(accessMutex);
std::lock_guard lockAccessQueue(m_accessMutex);
while (! m_queue.empty()) {
delete m_queue.front();
m_queue.pop();
@ -52,7 +52,7 @@ void IRCMessageQueue::signalEOF()
bool IRCMessageQueue::messageAvailable()
{
std::lock_guard lockAccessQueue(accessMutex);
std::lock_guard lockAccessQueue(m_accessMutex);
bool retv = ! m_queue.empty();
return retv;
@ -60,14 +60,14 @@ bool IRCMessageQueue::messageAvailable()
IRCMessage *IRCMessageQueue::peekFirst()
{
std::lock_guard lockAccessQueue(accessMutex);
std::lock_guard lockAccessQueue(m_accessMutex);
IRCMessage *msg = m_queue.empty() ? NULL : m_queue.front();
return msg;
}
IRCMessage *IRCMessageQueue::getMessage()
{
std::lock_guard lockAccessQueue(accessMutex);
std::lock_guard lockAccessQueue(m_accessMutex);
IRCMessage *msg = m_queue.empty() ? NULL : m_queue.front();
if (msg)
m_queue.pop();
@ -77,7 +77,7 @@ IRCMessage *IRCMessageQueue::getMessage()
void IRCMessageQueue::putMessage(IRCMessage *m)
{
std::lock_guard lockAccessQueue(accessMutex);
std::lock_guard lockAccessQueue(m_accessMutex);
m_queue.push(m);
}

@ -46,7 +46,7 @@ public:
private:
bool m_eof;
std::mutex accessMutex;
std::mutex m_accessMutex;
std::queue<IRCMessage *> m_queue;
};

@ -92,26 +92,26 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ)
while (recvQ->messageAvailable()) {
IRCMessage *m = recvQ->getMessage();
if (0 == m->command.compare("004")) {
if (0 == m->m_command.compare("004")) {
if (4 == m_state) {
if (m->params.size() > 1) {
if (m->m_params.size() > 1) {
std::regex serverNamePattern("^grp[1-9]s[1-9].ircDDB$");
if (std::regex_match(m->params[1], serverNamePattern))
m_app->setBestServer(std::string("s-") + m->params[1].substr(0,6));
if (std::regex_match(m->m_params[1], serverNamePattern))
m_app->setBestServer(std::string("s-") + m->m_params[1].substr(0,6));
}
m_state = 5; // next: JOIN
m_app->setCurrentNick(m_currentNick);
}
} else if (0 == m->command.compare("PING")) {
} else if (0 == m->m_command.compare("PING")) {
IRCMessage *m2 = new IRCMessage();
m2->command = std::string("PONG");
if (m->params.size() > 0) {
m2->numParams = 1;
m2->params.push_back(m->params[0]);
m2->m_command = std::string("PONG");
if (m->m_params.size() > 0) {
m2->m_numParams = 1;
m2->m_params.push_back(m->m_params[0]);
}
sendQ -> putMessage(m2);
} else if (0 == m->command.compare("JOIN")) {
if (m->numParams>=1 && 0==m->params[0].compare(m_channel)) {
} else if (0 == m->m_command.compare("JOIN")) {
if (m->m_numParams>=1 && 0==m->m_params[0].compare(m_channel)) {
if (0==m->getPrefixNick().compare(m_currentNick) && 6==m_state) {
if (m_debugChannel.size())
m_state = 7; // next: join debug_channel
@ -121,69 +121,69 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ)
m_app->userJoin(m->getPrefixNick(), m->getPrefixName(), m->getPrefixHost());
}
if (m->numParams>=1 && 0==m->params[0].compare(m_debugChannel)) {
if (m->m_numParams>=1 && 0==m->m_params[0].compare(m_debugChannel)) {
if (0==m->getPrefixNick().compare(m_currentNick) && 8==m_state)
m_state = 10; // next: WHO *
}
} else if (0 == m->command.compare("PONG")) {
} else if (0 == m->m_command.compare("PONG")) {
if (12 == m_state) {
m_timer = m_pingTimer;
m_state = 11;
}
} else if (0 == m->command.compare("PART")) {
if (m->numParams>=1 && 0==m->params[0].compare(m_channel)) {
} else if (0 == m->m_command.compare("PART")) {
if (m->m_numParams>=1 && 0==m->m_params[0].compare(m_channel)) {
if (m_app != NULL)
m_app->userLeave(m->getPrefixNick());
}
} else if (0 == m->command.compare("KICK")) {
if (m->numParams>=2 && 0==m->params[0].compare(m_channel)) {
if (0 == m->params[1].compare(m_currentNick)) {
} else if (0 == m->m_command.compare("KICK")) {
if (m->m_numParams>=2 && 0==m->m_params[0].compare(m_channel)) {
if (0 == m->m_params[1].compare(m_currentNick)) {
// i was kicked!!
delete m;
return false;
} else if (m_app)
m_app->userLeave(m->params[1]);
m_app->userLeave(m->m_params[1]);
}
} else if (0 == m->command.compare("QUIT")) {
} else if (0 == m->m_command.compare("QUIT")) {
if (m_app)
m_app->userLeave(m->getPrefixNick());
} else if (0 == m->command.compare("MODE")) {
if (m->numParams>=3 && 0==m->params[0].compare(m_channel)) {
} else if (0 == m->m_command.compare("MODE")) {
if (m->m_numParams>=3 && 0==m->m_params[0].compare(m_channel)) {
if (m_app) {
std::string mode = m->params[1];
std::string mode = m->m_params[1];
for (size_t i=1; i<mode.size() && (size_t)m->numParams>=i+2; i++) {
for (size_t i=1; i<mode.size() && (size_t)m->m_numParams>=i+2; i++) {
if ('o' == mode[i]) {
if ('+' == mode[0])
m_app->userChanOp(m->params[i+1], true);
m_app->userChanOp(m->m_params[i+1], true);
else if ('-' == mode[0])
m_app->userChanOp(m->params[i+1], false);
m_app->userChanOp(m->m_params[i+1], false);
}
} // for
}
}
} else if (0 == m->command.compare("PRIVMSG")) {
if (m->numParams==2 && m_app) {
if (0 == m->params[0].compare(m_channel) && m_app)
} else if (0 == m->m_command.compare("PRIVMSG")) {
if (m->m_numParams==2 && m_app) {
if (0 == m->m_params[0].compare(m_channel) && m_app)
m_app->msgChannel(m);
else if (0 == m->params[0].compare(m_currentNick) && m_app)
else if (0 == m->m_params[0].compare(m_currentNick) && m_app)
m_app->msgQuery(m);
}
} else if (0 == m->command.compare("352")) { // WHO list
if (m->numParams>=7 && 0==m->params[0].compare(m_currentNick) && 0==m->params[1].compare(m_channel)) {
} else if (0 == m->m_command.compare("352")) { // WHO list
if (m->m_numParams>=7 && 0==m->m_params[0].compare(m_currentNick) && 0==m->m_params[1].compare(m_channel)) {
if (m_app) {
m_app->userJoin(m->params[5], m->params[2], m->params[3]);
m_app->userChanOp(m->params[5], 0==m->params[6].compare("H@"));
m_app->userJoin(m->m_params[5], m->m_params[2], m->m_params[3]);
m_app->userChanOp(m->m_params[5], 0==m->m_params[6].compare("H@"));
}
}
} else if (0 == m->command.compare("433")) { // nick collision
} else if (0 == m->m_command.compare("433")) { // nick collision
if (2 == m_state) {
m_state = 3; // nick collision, choose new nick
m_timer = 10; // wait 5 seconds..
}
} else if (0==m->command.compare("332") || 0==m->command.compare("TOPIC")) { // topic
if (2==m->numParams && m_app && 0==m->params[0].compare(m_channel))
m_app->setTopic(m->params[1]);
} else if (0==m->m_command.compare("332") || 0==m->m_command.compare("TOPIC")) { // topic
if (2==m->m_numParams && m_app && 0==m->m_params[0].compare(m_channel))
m_app->setTopic(m->m_params[1]);
}
delete m;
@ -193,15 +193,15 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ)
switch (m_state) {
case 1:
m = new IRCMessage();
m->command = std::string("PASS");
m->numParams = 1;
m->params.push_back(m_password);
m->m_command = std::string("PASS");
m->m_numParams = 1;
m->m_params.push_back(m_password);
sendQ->putMessage(m);
m = new IRCMessage();
m->command = std::string("NICK");
m->numParams = 1;
m->params.push_back(m_currentNick);
m->m_command = std::string("NICK");
m->m_numParams = 1;
m->m_params.push_back(m_currentNick);
sendQ->putMessage(m);
m_timer = 10; // wait for possible nick collision message
@ -211,12 +211,12 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ)
case 2:
if (0 == m_timer) {
m = new IRCMessage();
m->command = std::string("USER");
m->numParams = 4;
m->params.push_back(m_name);
m->params.push_back(std::string("0"));
m->params.push_back(std::string("*"));
m->params.push_back(m_versionInfo);
m->m_command = std::string("USER");
m->m_numParams = 4;
m->m_params.push_back(m_name);
m->m_params.push_back(std::string("0"));
m->m_params.push_back(std::string("*"));
m->m_params.push_back(m_versionInfo);
sendQ->putMessage(m);
m_timer = 30;
@ -228,9 +228,9 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ)
if (0 == m_timer) {
chooseNewNick();
m = new IRCMessage();
m->command = std::string("NICK");
m->numParams = 1;
m->params.push_back(m_currentNick);
m->m_command = std::string("NICK");
m->m_numParams = 1;
m->m_params.push_back(m_currentNick);
sendQ->putMessage(m);
m_timer = 10; // wait for possible nick collision message
@ -245,9 +245,9 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ)
case 5:
m = new IRCMessage();
m->command = std::string("JOIN");
m->numParams = 1;
m->params.push_back(m_channel);
m->m_command = std::string("JOIN");
m->m_numParams = 1;
m->m_params.push_back(m_channel);
sendQ->putMessage(m);
m_timer = 30;
@ -264,9 +264,9 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ)
return false; // this state cannot be processed if there is no debug_channel
m = new IRCMessage();
m->command = std::string("JOIN");
m->numParams = 1;
m->params.push_back(m_debugChannel);
m->m_command = std::string("JOIN");
m->m_numParams = 1;
m->m_params.push_back(m_debugChannel);
sendQ->putMessage(m);
m_timer = 30;
@ -280,10 +280,10 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ)
case 10:
m = new IRCMessage();
m->command = std::string("WHO");
m->numParams = 2;
m->params.push_back(m_channel);
m->params.push_back(std::string("*"));
m->m_command = std::string("WHO");
m->m_numParams = 2;
m->m_params.push_back(m_channel);
m->m_params.push_back(std::string("*"));
sendQ->putMessage(m);
m_timer = m_pingTimer;
@ -296,9 +296,9 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ)
case 11:
if (0 == m_timer) {
m = new IRCMessage();
m->command = std::string("PING");
m->numParams = 1;
m->params.push_back(m_currentNick);
m->m_command = std::string("PING");
m->m_numParams = 1;
m->m_params.push_back(m_currentNick);
sendQ->putMessage(m);
m_timer = m_pingTimer;

@ -114,43 +114,43 @@ void IRCReceiver::Entry()
switch (state) {
case 0: // command
if (b == ':')
state = 1; // prefix
state = 1; // m_prefix
else if (b != ' ') {
m->command.push_back(b);
m->m_command.push_back(b);
state = 2; // command
}
break;
case 1: // prefix
case 1: // m_prefix
if (b == ' ')
state = 2; // command is next
else
m->prefix.push_back(b);
m->m_prefix.push_back(b);
break;
case 2:
if (b == ' ') {
state = 3; // params are next
m->numParams = 1;
m->params.push_back(std::string(""));
m->m_numParams = 1;
m->m_params.push_back(std::string(""));
} else
m->command.push_back(b);
m->m_command.push_back(b);
break;
case 3:
if (b == ' ') {
m->numParams++;
if (m->numParams >= 15)
m->m_numParams++;
if (m->m_numParams >= 15)
state = 5; // ignore the rest
m->params.push_back(std::string(""));
} else if (b==':' && m->params[m->numParams-1].size()==0)
m->m_params.push_back(std::string(""));
} else if (b==':' && m->m_params[m->m_numParams-1].size()==0)
state = 4; // rest of line is this param
else
m->params[m->numParams-1].push_back(b);
m->m_params[m->m_numParams-1].push_back(b);
break;
case 4:
m->params[m->numParams-1].push_back(b);
m->m_params[m->m_numParams-1].push_back(b);
break;
} // switch
}

@ -135,7 +135,9 @@ void* CIcomRepeaterProtocolHandler::Entry()
{
CLog::logInfo("Starting the Icom Controller thread");
#ifndef DEBUG_DSTARGW
try {
#endif
while (!m_killed) {
sendGwyPackets();
@ -145,14 +147,18 @@ void* CIcomRepeaterProtocolHandler::Entry()
m_retryTimer.clock();
}
#ifndef DEBUG_DSTARGW
}
catch (std::exception& e) {
std::string message(e.what());
CLog::logError("Exception raised in the Icom Controller thread - \"%s\"", message.c_str());
throw;
}
catch (...) {
CLog::logError("Unknown exception raised in the Icom Controller thread");
throw;
}
#endif
CLog::logInfo("Stopping the Icom Controller thread");

@ -95,6 +95,7 @@ void CLogFileTarget::printLogIntRotate(const std::string& msg)
}
void CLogFileTarget::printLogInt(const std::string& msg)
{
m_file.seekp(0, std::ios::end);
if(m_rotate)
printLogIntRotate(msg);
else

@ -23,14 +23,15 @@ export LOG_DIR=/var/log/dstargateway/
ifeq ($(ENABLE_DEBUG), 1)
# choose this if you want debugging help
export CPPFLAGS=-g -ggdb -W -Wall -Werror -std=c++17
export CPPFLAGS=-g -rdynamic -DBOOST_STACKTRACE_USE_ADDR2LINE -DDEBUG_DSTARGW -no-pie -fno-pie -ggdb -W -Wall -Werror -std=c++17
export LDFLAGS=-ldl -no-pie -fno-pie
else
# or, you can choose this for a much smaller executable without debugging help
CPPFLAGS=-W -O3 -Wall -Werror -std=c++17
export CPPFLAGS=-W -O3 -Wall -Werror -std=c++17
endif
export CC=g++
export LDFLAGS:=-lcurl -pthread
export LDFLAGS+= -lcurl -pthread
ifeq ($(USE_GPSD), 1)
export CPPFLAGS+= -DUSE_GPSD

@ -11,6 +11,7 @@
- [3.4. Prerequisites and dependencies](#34-prerequisites-and-dependencies)
- [3.5. Building](#35-building)
- [3.5.0.1. Build With GPSD Support](#3501-build-with-gpsd-support)
- [3.5.0.2. Debug Build](#3502-debug-build)
- [3.6. Installing](#36-installing)
- [3.7. Configuring](#37-configuring)
- [4. Contributing](#4-contributing)
@ -91,6 +92,11 @@ make
```
make USE_GPS=1
```
#### 3.5.0.2. Debug Build
```
make ENABLE_DEBUG=1
```
Note that this will link with libl
## 3.6. Installing
The program is meant to run as a systemd service. All bits an pieces are provided.
```
@ -121,6 +127,7 @@ the testing framwework used is Google Test.
# 5. Version History
## 5.1. Version 0.5
- [Improvement] Add NAT Traversal for G2 and DExtra, using IRCDDB as a Rendez Vous server
- [Improvement] Add forwarding of RS-MS1A messages to APRS-IS ([#9](https://github.com/F4FXL/DStarGateway/issues/9))
- [Bugfix] Failed to download XLX Hosts when URL contains a = sign ([#14](https://github.com/F4FXL/DStarGateway/issues/14))
- [Bugfix] Remote control connection failed ([#13](https://github.com/F4FXL/DStarGateway/issues/13))
@ -139,9 +146,9 @@ the testing framwework used is Google Test.
First working version
# 6. Future
I started this during my 2021 seasons holiday. It took me almost 8 days to get to a workable version. Here are a couple of stuff I'd like to do :
- &#9746; Better NatTraversal
- &#9745; Better NatTraversal
- No banging on every gateway: use ircDDB (or something else) as mitigation server to notify peer
- Support for all protocols (G2, DExtra, DCS, REF)
- Support for all protocols (G2, DExtra, DPlus) DCS does nto make sense as it was historically never used as protocol for linking repeaters
- A [branch](https://github.com/F4FXL/DStarGateway/tree/feature/NatTraversal) already exists for this
- &#9745; Send the connection status to APRS-IS as a status frame
- &#9746; Reinstantiate DRATS

@ -1342,8 +1342,9 @@ void CRepeaterHandler::resolveRepeaterInt(const std::string& repeater, const std
case DP_DPLUS:
if (m_dplusEnabled) {
m_linkGateway = gateway;
unsigned int localPort = 0U;
addr.s_addr = ::inet_addr(address.c_str());
CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, addr);
CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, addr, localPort);
m_linkStatus = LS_LINKING_DPLUS;
} else {
CLog::logInfo("Require D-Plus for linking to %s, but D-Plus is disabled", repeater.c_str());
@ -1381,8 +1382,9 @@ void CRepeaterHandler::resolveRepeaterInt(const std::string& repeater, const std
default:
if (m_dextraEnabled) {
m_linkGateway = gateway;
unsigned int localPort = 0U;
addr.s_addr = ::inet_addr(address.c_str());
CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, addr);
CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, addr, localPort);
m_linkStatus = LS_LINKING_DEXTRA;
} else {
CLog::logInfo("Require DExtra for linking to %s, but DExtra is disabled", repeater.c_str());
@ -2026,7 +2028,7 @@ void CRepeaterHandler::g2CommandHandler(const std::string& callsign, const std::
if (m_linkStatus == LS_LINKING_CCS || m_linkStatus == LS_LINKED_CCS)
return;
if (callsign.substr(0,1) == "/") {
if (!callsign.empty() && callsign[0] == '/') {
if (m_irc == NULL) {
CLog::logInfo("%s is trying to G2 route with ircDDB disabled", user.c_str());
m_g2Status = G2_LOCAL;
@ -2057,6 +2059,7 @@ void CRepeaterHandler::g2CommandHandler(const std::string& callsign, const std::
m_g2User = "CQCQCQ ";
CRepeaterData* data = m_cache->findRepeater(m_g2Repeater);
m_irc->notifyRepeaterG2NatTraversal(m_g2Repeater);
if (data == NULL) {
m_g2Status = G2_REPEATER;
@ -2108,6 +2111,7 @@ void CRepeaterHandler::g2CommandHandler(const std::string& callsign, const std::
m_g2User = callsign;
m_g2Address = data->getAddress();
m_g2Repeater = data->getRepeater();
m_irc->notifyRepeaterG2NatTraversal(m_g2Repeater);
m_g2Gateway = data->getGateway();
header.setDestination(m_g2Address, G2_DV_PORT);
header.setRepeaters(m_g2Gateway, m_g2Repeater);
@ -2284,8 +2288,11 @@ void CRepeaterHandler::linkInt(const std::string& callsign)
switch (data->getProtocol()) {
case DP_DPLUS:
if (m_dplusEnabled) {
unsigned int localPort = 0U;
m_linkStatus = LS_LINKING_DPLUS;
CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress());
CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress(), localPort);
if(m_irc != nullptr && localPort > 0U)
m_irc->notifyRepeaterDPlusNatTraversal(m_linkRepeater, localPort);
writeLinkingTo(m_linkRepeater);
triggerInfo();
} else {
@ -2319,8 +2326,11 @@ void CRepeaterHandler::linkInt(const std::string& callsign)
default:
if (m_dextraEnabled) {
unsigned int localPort = 0U;
m_linkStatus = LS_LINKING_DEXTRA;
CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress());
CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress(), localPort);
if(m_irc != nullptr && localPort > 0U)
m_irc->notifyRepeaterDextraNatTraversal(m_linkRepeater, localPort);
writeLinkingTo(m_linkRepeater);
triggerInfo();
} else {
@ -2456,8 +2466,11 @@ void CRepeaterHandler::startupInt()
switch (protocol) {
case DP_DPLUS:
if (m_dplusEnabled) {
unsigned int localPort = 0U;
m_linkStatus = LS_LINKING_DPLUS;
CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress());
CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress(), localPort);
if(m_irc != nullptr && localPort > 0U)
m_irc->notifyRepeaterDPlusNatTraversal(m_linkRepeater, localPort);
writeLinkingTo(m_linkRepeater);
triggerInfo();
} else {
@ -2491,8 +2504,11 @@ void CRepeaterHandler::startupInt()
default:
if (m_dextraEnabled) {
unsigned int localPort = 0U;
m_linkStatus = LS_LINKING_DEXTRA;
CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress());
CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress(), localPort);
if(m_irc != nullptr && localPort > 0U)
m_irc->notifyRepeaterDextraNatTraversal(m_linkRepeater, localPort);
writeLinkingTo(m_linkRepeater);
triggerInfo();
} else {

@ -16,6 +16,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include "StringUtils.h"
size_t CStringUtils::find_nth(const std::string& haystack, char needle, size_t nth)
@ -32,4 +35,18 @@ size_t CStringUtils::find_nth(const std::string& haystack, char needle, size_t n
}
return std::string::npos;
}
unsigned int CStringUtils::stringToPort(const std::string& s)
{
unsigned int port = 0U;
std::string ls = boost::trim_copy(s);
if(!ls.empty() && std::all_of(ls.begin(), ls.end(), [](char c){ return c >= '0' && c <= '9'; })) {
auto portTemp = boost::lexical_cast<unsigned int>(ls);
if(portTemp > 0U && portTemp <= 65535U)
port = portTemp;
}
return port;
}

@ -52,4 +52,6 @@ public:
}
static size_t find_nth(const std::string& haystack, char needle, size_t nth);
static unsigned int stringToPort(const std::string& s);
};

@ -0,0 +1,55 @@
/*
* Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* 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 <gtest/gtest.h>
#include "../../DCSProtocolHandlerPool.h"
namespace DCSProtocolHandlerPoolTests
{
class DCSProtocolHandler_getHandler : public ::testing::Test {
};
TEST_F(DCSProtocolHandler_getHandler, successiveCallsReturnsDifferentHandlerAndNotIncoming)
{
CDCSProtocolHandlerPool pool(DCS_PORT, "127.0.0.1");
auto handler1 = pool.getHandler();
auto handler2 = pool.getHandler();
auto incoming = pool.getIncomingHandler();
EXPECT_NE(handler1, nullptr);
EXPECT_NE(handler2, nullptr);
EXPECT_NE(incoming, nullptr);
EXPECT_NE(handler1, handler2);
EXPECT_NE(handler1, incoming);
EXPECT_NE(handler2, incoming);
// DCS_PORT is reserved for incoming handler
EXPECT_NE(handler1->getPort(), DCS_PORT);
EXPECT_NE(handler2->getPort(), DCS_PORT);
EXPECT_EQ(incoming->getPort(), DCS_PORT);
pool.release(handler1);
pool.release(handler2);
pool.release(incoming);
}
}

@ -0,0 +1,45 @@
/*
* Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* 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 <gtest/gtest.h>
#include "../../DCSProtocolHandlerPool.h"
namespace DCSProtocolHandlerPoolTests
{
class DCSProtocolHandler_getIncomingHandler : public ::testing::Test {
};
TEST_F(DCSProtocolHandler_getIncomingHandler, successiveCallAlwaysReturnsIncomingHandler)
{
CDCSProtocolHandlerPool pool(DCS_PORT, "127.0.0.1");
auto handler1 = pool.getIncomingHandler();
auto handler2 = pool.getIncomingHandler();
EXPECT_NE(handler1, nullptr);
EXPECT_NE(handler2, nullptr);
EXPECT_EQ(handler1, handler2);
EXPECT_EQ(handler1->getPort(), DCS_PORT);
EXPECT_EQ(handler2->getPort(), DCS_PORT);
pool.release(handler1);
pool.release(handler2);
}
}

@ -0,0 +1,55 @@
/*
* Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* 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 <gtest/gtest.h>
#include "../../DPlusProtocolHandlerPool.h"
namespace DPlusProtocolHandlerPoolTests
{
class DPlusProtocolHandler_getHandler : public ::testing::Test {
};
TEST_F(DPlusProtocolHandler_getHandler, successiveCallsReturnsDifferentHandlerAndNotIncoming)
{
CDPlusProtocolHandlerPool pool(DPLUS_PORT, "127.0.0.1");
auto handler1 = pool.getHandler();
auto handler2 = pool.getHandler();
auto incoming = pool.getIncomingHandler();
EXPECT_NE(handler1, nullptr);
EXPECT_NE(handler2, nullptr);
EXPECT_NE(incoming, nullptr);
EXPECT_NE(handler1, handler2);
EXPECT_NE(handler1, incoming);
EXPECT_NE(handler2, incoming);
// DPLUS_PORT is reserved for incoming handler
EXPECT_NE(handler1->getPort(), DPLUS_PORT);
EXPECT_NE(handler2->getPort(), DPLUS_PORT);
EXPECT_EQ(incoming->getPort(), DPLUS_PORT);
pool.release(handler1);
pool.release(handler2);
pool.release(incoming);
}
}

@ -0,0 +1,45 @@
/*
* Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* 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 <gtest/gtest.h>
#include "../../DPlusProtocolHandlerPool.h"
namespace DPlusProtocolHandlerPoolTests
{
class DPlusProtocolHandler_getIncomingHandler : public ::testing::Test {
};
TEST_F(DPlusProtocolHandler_getIncomingHandler, successiveCallAlwaysReturnsIncomingHandler)
{
CDPlusProtocolHandlerPool pool(DPLUS_PORT, "127.0.0.1");
auto handler1 = pool.getIncomingHandler();
auto handler2 = pool.getIncomingHandler();
EXPECT_NE(handler1, nullptr);
EXPECT_NE(handler2, nullptr);
EXPECT_EQ(handler1, handler2);
EXPECT_EQ(handler1->getPort(), DPLUS_PORT);
EXPECT_EQ(handler2->getPort(), DPLUS_PORT);
pool.release(handler1);
pool.release(handler2);
}
}

@ -0,0 +1,55 @@
/*
* Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* 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 <gtest/gtest.h>
#include "../../DExtraProtocolHandlerPool.h"
namespace DextraProtocolHandlerPoolTests
{
class DextraProtocolHandler_getHandler : public ::testing::Test {
};
TEST_F(DextraProtocolHandler_getHandler, successiveCallsReturnsDifferentHandlerAndNotIncoming)
{
CDExtraProtocolHandlerPool pool(DEXTRA_PORT, "127.0.0.1");
auto handler1 = pool.getHandler();
auto handler2 = pool.getHandler();
auto incoming = pool.getIncomingHandler();
EXPECT_NE(handler1, nullptr);
EXPECT_NE(handler2, nullptr);
EXPECT_NE(incoming, nullptr);
EXPECT_NE(handler1, handler2);
EXPECT_NE(handler1, incoming);
EXPECT_NE(handler2, incoming);
// DEXTRA_PORT is reserved for incoming handler
EXPECT_NE(handler1->getPort(), DEXTRA_PORT);
EXPECT_NE(handler2->getPort(), DEXTRA_PORT);
EXPECT_EQ(incoming->getPort(), DEXTRA_PORT);
pool.release(handler1);
pool.release(handler2);
pool.release(incoming);
}
}

@ -0,0 +1,45 @@
/*
* Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* 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 <gtest/gtest.h>
#include "../../DExtraProtocolHandlerPool.h"
namespace DextraProtocolHandlerPoolTests
{
class DextraProtocolHandler_getIncomingHandler : public ::testing::Test {
};
TEST_F(DextraProtocolHandler_getIncomingHandler, successiveCallAlwaysReturnsIncomingHandler)
{
CDExtraProtocolHandlerPool pool(DEXTRA_PORT, "127.0.0.1");
auto handler1 = pool.getIncomingHandler();
auto handler2 = pool.getIncomingHandler();
EXPECT_NE(handler1, nullptr);
EXPECT_NE(handler2, nullptr);
EXPECT_EQ(handler1, handler2);
EXPECT_EQ(handler1->getPort(), DEXTRA_PORT);
EXPECT_EQ(handler2->getPort(), DEXTRA_PORT);
pool.release(handler1);
pool.release(handler2);
}
}

@ -0,0 +1,86 @@
/*
* Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* 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 <gtest/gtest.h>
#include "../../StringUtils.h"
namespace StringUtilsTests
{
class StringUtils_stringToPort : public ::testing::Test {
};
TEST_F(StringUtils_stringToPort, EmptyStringReturn0)
{
unsigned int port = CStringUtils::stringToPort("");
EXPECT_EQ(port, 0U);
}
TEST_F(StringUtils_stringToPort, SpaceStringReturn0)
{
unsigned int port = CStringUtils::stringToPort(" ");
EXPECT_EQ(port, 0U);
}
TEST_F(StringUtils_stringToPort, NumberStringReturnsCorrectValue)
{
unsigned int port = CStringUtils::stringToPort("12345");
EXPECT_EQ(port, 12345U);
}
TEST_F(StringUtils_stringToPort, NumberStringWithSpacesReturnsCorrectValue)
{
unsigned int port = CStringUtils::stringToPort(" 12345 ");
EXPECT_EQ(port, 12345U);
}
TEST_F(StringUtils_stringToPort, StringWithMixedAlphaAndNumbersreturns0)
{
unsigned int port = CStringUtils::stringToPort("123abc456");
EXPECT_EQ(port, 0U);
}
TEST_F(StringUtils_stringToPort, TooLargeValueReturns0)
{
unsigned int port = CStringUtils::stringToPort("999999");
EXPECT_EQ(port, 0U);
}
TEST_F(StringUtils_stringToPort, TestAllNumDigits)
{
EXPECT_EQ(CStringUtils::stringToPort("10"), 10U);
EXPECT_EQ(CStringUtils::stringToPort("11"), 11U);
EXPECT_EQ(CStringUtils::stringToPort("12"), 12U);
EXPECT_EQ(CStringUtils::stringToPort("13"), 13U);
EXPECT_EQ(CStringUtils::stringToPort("14"), 14U);
EXPECT_EQ(CStringUtils::stringToPort("15"), 15U);
EXPECT_EQ(CStringUtils::stringToPort("16"), 16U);
EXPECT_EQ(CStringUtils::stringToPort("17"), 17U);
EXPECT_EQ(CStringUtils::stringToPort("18"), 18U);
EXPECT_EQ(CStringUtils::stringToPort("19"), 19U);
}
}
Loading…
Cancel
Save

Powered by TurnKey Linux.