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", "system_error": "cpp",
"thread": "cpp", "thread": "cpp",
"typeindex": "cpp", "typeindex": "cpp",
"variant": "cpp" "variant": "cpp",
"iostream": "cpp"
}, },
"editor.tokenColorCustomizations": { "editor.tokenColorCustomizations": {
"textMateRules": [ "textMateRules": [

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

@ -44,6 +44,10 @@ CDCSProtocolHandlerPool::~CDCSProtocolHandlerPool()
CDCSProtocolHandler *CDCSProtocolHandlerPool::getIncomingHandler() CDCSProtocolHandler *CDCSProtocolHandlerPool::getIncomingHandler()
{ {
auto it = m_pool.find(m_basePort);
if(it != m_pool.end())
return it->second;
return getHandler(m_basePort); 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(); CDExtraProtocolHandler* protoHandler = m_pool->getHandler();
if (protoHandler == NULL) if (protoHandler == NULL)
return; return;
@ -422,6 +423,7 @@ void CDExtraHandler::link(IReflectorCallback* handler, const std::string& repeat
} }
if (found) { if (found) {
localPort = protoHandler->getPort();
CConnectData reply(repeater, gateway, CT_LINK1, address, DEXTRA_PORT); CConnectData reply(repeater, gateway, CT_LINK1, address, DEXTRA_PORT);
protoHandler->writeConnect(reply); protoHandler->writeConnect(reply);
} else { } else {

@ -52,7 +52,7 @@ public:
static void setHeaderLogger(CHeaderLogger* logger); static void setHeaderLogger(CHeaderLogger* logger);
static void setMaxDongles(unsigned int maxDongles); 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(IReflectorCallback* handler, const std::string& reflector = "", bool exclude = true);
static void unlink(); static void unlink();

@ -19,7 +19,7 @@
*/ */
#include "DExtraProtocolHandler.h" #include "DExtraProtocolHandler.h"
#include "Log.h"
#include "Utils.h" #include "Utils.h"
// #define DUMP_TX // #define DUMP_TX
@ -113,6 +113,17 @@ bool CDExtraProtocolHandler::writeConnect(const CConnectData& connect)
return true; 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() DEXTRA_TYPE CDExtraProtocolHandler::read()
{ {
bool res = true; bool res = true;

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

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

@ -72,7 +72,9 @@ void* CDPlusAuthenticator::Entry()
m_timer.start(); m_timer.start();
#ifndef DEBUG_DSTARGW
try { try {
#endif
while (!m_killed) { while (!m_killed) {
if (m_timer.hasExpired()) { if (m_timer.hasExpired()) {
authenticate(m_loginCallsign, OPENDSTAR_HOSTNAME, OPENDSTAR_PORT, '2', true); authenticate(m_loginCallsign, OPENDSTAR_HOSTNAME, OPENDSTAR_PORT, '2', true);
@ -83,14 +85,18 @@ void* CDPlusAuthenticator::Entry()
m_timer.clock(); m_timer.clock();
} }
#ifndef DEBUG_DSTARGW
} }
catch (std::exception& e) { catch (std::exception& e) {
std::string message(e.what()); std::string message(e.what());
CLog::logError("Exception raised in the D-Plus Authenticator thread - \"%s\"", message.c_str()); CLog::logError("Exception raised in the D-Plus Authenticator thread - \"%s\"", message.c_str());
throw;
} }
catch (...) { catch (...) {
CLog::logError("Unknown exception raised in the D-Plus Authenticator thread"); CLog::logError("Unknown exception raised in the D-Plus Authenticator thread");
throw;
} }
#endif
CLog::logInfo("Stopping the D-Plus Authenticator thread"); 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(); CDPlusProtocolHandler* protoHandler = m_pool->getHandler();
if (protoHandler == NULL) if (protoHandler == NULL)
return; return;
@ -377,6 +378,7 @@ void CDPlusHandler::link(IReflectorCallback* handler, const std::string& repeate
if (found) { if (found) {
CConnectData connect(CT_LINK1, address, DPLUS_PORT); CConnectData connect(CT_LINK1, address, DPLUS_PORT);
localPort = protoHandler->getPort();
protoHandler->writeConnect(connect); protoHandler->writeConnect(connect);
m_stateChange = true; m_stateChange = true;
} else { } else {

@ -58,7 +58,7 @@ public:
static void startAuthenticator(const std::string& address, CCacheManager* cache); 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 relink(IReflectorCallback* handler, const std::string& reflector);
static void unlink(IReflectorCallback* handler, const std::string& reflector = "", bool exclude = true); static void unlink(IReflectorCallback* handler, const std::string& reflector = "", bool exclude = true);
static void unlink(); static void unlink();

@ -18,7 +18,7 @@
*/ */
#include "DPlusProtocolHandler.h" #include "DPlusProtocolHandler.h"
#include "Log.h"
#include "DStarDefines.h" #include "DStarDefines.h"
#include "Utils.h" #include "Utils.h"
@ -107,6 +107,17 @@ bool CDPlusProtocolHandler::writeConnect(const CConnectData& connect)
return m_socket.write(buffer, length, connect.getYourAddress(), connect.getYourPort()); 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() DPLUS_TYPE CDPlusProtocolHandler::read()
{ {
bool res = true; bool res = true;

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

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

@ -23,6 +23,11 @@
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <vector> #include <vector>
#include <signal.h>
#include <exception>
#ifdef DEBUG_DSTARGW
#include <boost/stacktrace.hpp>
#endif
#include "DStarGatewayDefs.h" #include "DStarGatewayDefs.h"
#include "DStarGatewayConfig.h" #include "DStarGatewayConfig.h"
@ -41,9 +46,20 @@
#include "APRSGPSDIdFrameProvider.h" #include "APRSGPSDIdFrameProvider.h"
#include "APRSFixedIdFrameProvider.h" #include "APRSFixedIdFrameProvider.h"
#ifndef UNIT_TESTS #ifdef UNIT_TESTS
int fakemain(int argc, char *argv[])
#else
int main(int argc, char *argv[]) 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); setbuf(stdout, NULL);
if (2 != argc) { if (2 != argc) {
printf("usage: %s path_to_config_file\n", argv[0]); printf("usage: %s path_to_config_file\n", argv[0]);
@ -70,7 +86,6 @@ int main(int argc, char *argv[])
return 0; return 0;
} }
#endif
CDStarGatewayApp::CDStarGatewayApp(const std::string &configFile) : m_configFile(configFile), m_thread(NULL) 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)); CLog::logInfo("DD Mode enabled: %d", int(ddEnabled));
// Setup ircddb // Setup ircddb
auto ircddbVersionInfo = "linux_" + PRODUCT_NAME + "-" + VERSION;
std::vector<CIRCDDB *> clients; std::vector<CIRCDDB *> clients;
for(unsigned int i=0; i < config.getIrcDDBCount(); i++) { for(unsigned int i=0; i < config.getIrcDDBCount(); i++) {
TircDDB ircDDBConfig; TircDDB ircDDBConfig;
config.getIrcDDB(i, 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); 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); clients.push_back(ircDDB);
} }
if(clients.size() > 0U) { if(clients.size() > 0U) {
@ -260,3 +276,41 @@ bool CDStarGatewayApp::createThread()
return true; 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" #include "DStarGatewayThread.h"
void __sigHandler(int sig);
class CDStarGatewayApp class CDStarGatewayApp
{ {
private: private:
@ -34,4 +36,7 @@ public:
bool init(); bool init();
void run(); void run();
static void sigHandlerFatal(int sig);
static void terminateHandler();
}; };

@ -76,9 +76,6 @@ m_dextraPool(NULL),
m_dplusPool(NULL), m_dplusPool(NULL),
m_dcsPool(NULL), m_dcsPool(NULL),
m_g2Handler(NULL), m_g2Handler(NULL),
#if defined(ENABLE_NAT_TRAVERSAL)
m_natTraversal(NULL),
#endif
m_aprsWriter(NULL), m_aprsWriter(NULL),
m_irc(NULL), m_irc(NULL),
m_cache(), m_cache(),
@ -209,13 +206,6 @@ void* CDStarGatewayThread::Entry()
m_g2Handler = NULL; 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 // 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())) 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 ::std::this_thread::sleep_for(std::chrono::milliseconds(500UL)); // 1/2 sec
@ -345,7 +335,9 @@ void* CDStarGatewayThread::Entry()
m_statusFileTimer.start(); m_statusFileTimer.start();
m_statusTimer2.start(); m_statusTimer2.start();
#ifndef DEBUG_DSTARGW
try { try {
#endif
while (!m_killed) { while (!m_killed) {
if (m_icomRepeaterHandler != NULL) if (m_icomRepeaterHandler != NULL)
processRepeater(m_icomRepeaterHandler); processRepeater(m_icomRepeaterHandler);
@ -421,14 +413,18 @@ void* CDStarGatewayThread::Entry()
::std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PER_TIC_MS)); ::std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PER_TIC_MS));
} }
#ifndef DEBUG_DSTARGW
} }
catch (std::exception& e) { catch (std::exception& e) {
std::string message(e.what()); std::string message(e.what());
CLog::logFatal("Exception raised in the main thread - \"%s\"", message.c_str()); CLog::logFatal("Exception raised in the main thread - \"%s\"", message.c_str());
throw;
} }
catch (...) { catch (...) {
CLog::logFatal("Unknown exception raised in the main thread"); CLog::logFatal("Unknown exception raised in the main thread");
throw;
} }
#endif
CLog::logInfo("Stopping the ircDDB Gateway thread"); CLog::logInfo("Stopping the ircDDB Gateway thread");
@ -733,6 +729,7 @@ void CDStarGatewayThread::processIrcDDB()
m_statusTimer2.start(); m_statusTimer2.start();
} }
// Process incoming ircDDB messages, updating the caches // Process incoming ircDDB messages, updating the caches
for (;;) { for (;;) {
IRCDDB_RESPONSE_TYPE type = m_irc->getMessageType(); IRCDDB_RESPONSE_TYPE type = m_irc->getMessageType();
@ -747,9 +744,6 @@ void CDStarGatewayThread::processIrcDDB()
if (!address.empty()) { if (!address.empty()) {
CLog::logDebug("USER: %s %s %s %s", user.c_str(), repeater.c_str(), gateway.c_str(), address.c_str()); 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); m_cache.updateUser(user, repeater, gateway, address, timestamp, DP_DEXTRA, false, false);
#if defined(ENABLE_NAT_TRAVERSAL)
m_natTraversal->traverseNatG2(address);
#endif
} else { } else {
CLog::logDebug("USER: %s NOT FOUND", user.c_str()); CLog::logDebug("USER: %s NOT FOUND", user.c_str());
} }
@ -766,9 +760,6 @@ void CDStarGatewayThread::processIrcDDB()
if (!address.empty()) { if (!address.empty()) {
CLog::logDebug("REPEATER: %s %s %s", repeater.c_str(), gateway.c_str(), address.c_str()); 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); m_cache.updateRepeater(repeater, gateway, address, DP_DEXTRA, false, false);
#if defined(ENABLE_NAT_TRAVERSAL)
m_natTraversal->traverseNatG2(address);
#endif
} else { } else {
CLog::logDebug("REPEATER: %s NOT FOUND", repeater.c_str()); CLog::logDebug("REPEATER: %s NOT FOUND", repeater.c_str());
} }
@ -786,15 +777,60 @@ void CDStarGatewayThread::processIrcDDB()
if (!address.empty()) { if (!address.empty()) {
CLog::logDebug("GATEWAY: %s %s", gateway.c_str(), address.c_str()); CLog::logDebug("GATEWAY: %s %s", gateway.c_str(), address.c_str());
m_cache.updateGateway(gateway, address, DP_DEXTRA, false, false); m_cache.updateGateway(gateway, address, DP_DEXTRA, false, false);
#if defined(ENABLE_NAT_TRAVERSAL)
m_natTraversal->traverseNatG2(address);
#endif
} else { } else {
CLog::logDebug("GATEWAY: %s NOT FOUND", gateway.c_str()); CLog::logDebug("GATEWAY: %s NOT FOUND", gateway.c_str());
} }
} }
break; 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: default:
return; return;
} }

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

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

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

@ -31,7 +31,10 @@ enum IRCDDB_RESPONSE_TYPE {
IDRT_NONE, IDRT_NONE,
IDRT_USER, IDRT_USER,
IDRT_GATEWAY, 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 // Send query for a user, a false return implies a network error
virtual bool findUser(const std::string& userCallsign) = 0; virtual bool findUser(const std::string& userCallsign) = 0;
// 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 // Support for the Smart Group Server
virtual void sendDStarGatewayInfo(const std::string subcommand, const std::vector<std::string> parms) = 0; 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 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 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 findRepeater(const std::string& s);
bool findGateway(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, bool sendHeard(const std::string& myCall, const std::string& myCallExt, const std::string& yourCall, const std::string& rpt1, const std::string& rpt2, unsigned char flag1,
unsigned char flag2, unsigned char flag3, const std::string& destination, const std::string& tx_msg, const std::string& tx_stats); unsigned char flag2, unsigned char flag3, const std::string& destination, const std::string& tx_msg, const std::string& tx_stats);
@ -86,11 +90,14 @@ protected:
private: private:
void doUpdate(std::string& msg); void doUpdate(std::string& msg);
void doNotFound(std::string& msg, std::string& retval); 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(); bool findServerUser();
unsigned int calculateUsn(const std::string& nick); unsigned int calculateUsn(const std::string& nick);
std::string getLastEntryTime(int tableID); std::string getLastEntryTime(int tableID);
IRCDDBAppPrivate *d; bool getNickForRepeater(const std::string& repeater, std::string& user) const;
IRCDDBAppPrivate *m_d;
time_t m_maxTime; time_t m_maxTime;
std::future<void> m_future; std::future<void> m_future;
}; };

@ -28,23 +28,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
struct CIRCDDBClientPrivate struct CIRCDDBClientPrivate
{ {
IRCClient *client; 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 ) : 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) m_isQuadNet(isQuadNet)
{ {
std::string update_channel("#dstar"); std::string update_channel("#dstar");
d->app = new IRCDDBApp(update_channel); m_d->m_app = new IRCDDBApp(update_channel);
d->client = new IRCClient(d->app, update_channel, hostName, port, callsign, password, versionInfo, localAddr); m_d->client = new IRCClient(m_d->m_app, update_channel, hostName, port, callsign, password, versionInfo, localAddr);
} }
CIRCDDBClient::~CIRCDDBClient() CIRCDDBClient::~CIRCDDBClient()
{ {
delete d->client; delete m_d->client;
delete d->app; delete m_d->m_app;
delete d; delete m_d;
} }
@ -52,33 +52,33 @@ CIRCDDBClient::~CIRCDDBClient()
bool CIRCDDBClient::open() bool CIRCDDBClient::open()
{ {
CLog::logInfo("start client and app\n"); CLog::logInfo("start client and app\n");
d->client->startWork(); m_d->client->startWork();
d->app->startWork(); m_d->m_app->startWork();
return true; return true;
} }
int CIRCDDBClient::getConnectionState() 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) 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) 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) 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 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) 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"); CLog::logInfo("\n");
if(m_isQuadNet) { 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('_'); 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, '_'); 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 // 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); std::string gw(gatewayCallsign);
CUtils::ToUpper(gw); 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); std::string rptr(repeaterCallsign);
CUtils::ToUpper(rptr); 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 // 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()); CLog::logDebug("CIRCDDBClient::findUser:userCall='%s' len != 8\n", userCallsign.c_str());
return false; return false;
} }
CLog::logTrace("IRC Find user %s", userCallsign.c_str());
std::string usr(userCallsign); std::string usr(userCallsign);
CUtils::ToUpper(usr); 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 // The following functions are for processing received messages
@ -282,21 +298,21 @@ bool CIRCDDBClient::findUser(const std::string& userCallsign)
// Get the waiting message type // Get the waiting message type
IRCDDB_RESPONSE_TYPE CIRCDDBClient::getMessageType() 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() // Get a gateway message, as a result of IDRT_REPEATER returned from getMessageType()
// A false return implies a network error // A false return implies a network error
bool CIRCDDBClient::receiveRepeater(std::string& repeaterCallsign, std::string& gatewayCallsign, std::string& address) 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) { if (rt != IDRT_REPEATER) {
CLog::logDebug("CIRCDDBClient::receiveRepeater: unexpected response type=%d\n", rt); CLog::logDebug("CIRCDDBClient::receiveRepeater: unexpected response type=%d\n", rt);
return false; return false;
} }
IRCMessage *m = d->app->getReplyMessage(); IRCMessage *m = m_d->m_app->getReplyMessage();
if (m == NULL) { if (m == NULL) {
CLog::logDebug("CIRCDDBClient::receiveRepeater: no message\n"); CLog::logDebug("CIRCDDBClient::receiveRepeater: no message\n");
return false; return false;
@ -325,14 +341,14 @@ bool CIRCDDBClient::receiveRepeater(std::string& repeaterCallsign, std::string&
// A false return implies a network error // A false return implies a network error
bool CIRCDDBClient::receiveGateway(std::string& gatewayCallsign, std::string& address) 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) { if (rt != IDRT_GATEWAY) {
CLog::logDebug("CIRCDDBClient::receiveGateway: unexpected response type=%d\n", rt); CLog::logDebug("CIRCDDBClient::receiveGateway: unexpected response type=%d\n", rt);
return false; return false;
} }
IRCMessage *m = d->app->getReplyMessage(); IRCMessage *m = m_d->m_app->getReplyMessage();
if (m == NULL) { if (m == NULL) {
CLog::logDebug("CIRCDDBClient::receiveGateway: no message\n"); 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) 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) { if (rt != IDRT_USER) {
CLog::logDebug("CIRCDDBClient::receiveUser: unexpected response type=%d\n", rt); CLog::logDebug("CIRCDDBClient::receiveUser: unexpected response type=%d\n", rt);
return false; return false;
} }
IRCMessage * m = d->app->getReplyMessage(); IRCMessage * m = m_d->m_app->getReplyMessage();
if (m == NULL) { if (m == NULL) {
CLog::logDebug("CIRCDDBClient::receiveUser: no message\n"); CLog::logDebug("CIRCDDBClient::receiveUser: no message\n");
@ -398,13 +414,119 @@ bool CIRCDDBClient::receiveUser(std::string& userCallsign, std::string& repeater
gatewayCallsign = m->getParam(2); gatewayCallsign = m->getParam(2);
address = m->getParam(3); address = m->getParam(3);
timeStamp = m->getParam(4); 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; delete m;
return true; return true;
} }
void CIRCDDBClient::close() // Implictely kills any threads in the IRC code bool CIRCDDBClient::receiveNATTraversalG2(std::string& address)
{ {
d->client -> stopWork(); IRCDDB_RESPONSE_TYPE rt = m_d->m_app->getReplyMessageType();
d->app -> stopWork();
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 // Send query for a user, a false return implies a network error
bool findUser(const std::string& userCallsign); 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 // Support for the Smart Group Server
void sendDStarGatewayInfo(const std::string subcommand, const std::vector<std::string> parms); 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 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 void close(); // Implictely kills any threads in the IRC code
private: private:
struct CIRCDDBClientPrivate * const d; struct CIRCDDBClientPrivate * const m_d;
bool m_isQuadNet; bool m_isQuadNet;
}; };

@ -150,7 +150,7 @@ void CIRCDDBMultiClient::sendDStarGatewayInfo(const std::string subcommand, cons
bool CIRCDDBMultiClient::findGateway(const std::string & gatewayCallsign) bool CIRCDDBMultiClient::findGateway(const std::string & gatewayCallsign)
{ {
pushQuery(IDRT_GATEWAY, gatewayCallsign, new CIRCDDBMultiClientQuery("", "", gatewayCallsign, "", "", IDRT_GATEWAY)); pushQuery(IDRT_GATEWAY, gatewayCallsign, new CIRCDDBMultiClientQuery("", "", gatewayCallsign, "", "", "", IDRT_GATEWAY));
bool result = true; bool result = true;
for (unsigned int i = 0; i < m_clients.size(); i++) { for (unsigned int i = 0; i < m_clients.size(); i++) {
result = m_clients[i]->findGateway(gatewayCallsign) && result; 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) 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; bool result = true;
for (unsigned int i = 0; i < m_clients.size(); i++) { for (unsigned int i = 0; i < m_clients.size(); i++) {
result = m_clients[i]->findRepeater(repeaterCallsign) && result; 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) 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; bool result = true;
for (unsigned int i = 0; i < m_clients.size(); i++) { for (unsigned int i = 0; i < m_clients.size(); i++) {
result = m_clients[i]->findUser(userCallsign) && result; result = m_clients[i]->findUser(userCallsign) && result;
@ -181,11 +181,79 @@ bool CIRCDDBMultiClient::findUser(const std::string & userCallsign)
return result; 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() 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++) { 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(); IRCDDB_RESPONSE_TYPE type = m_clients[i]->getMessageType();
@ -208,6 +276,24 @@ IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType()
key = repeater; key = repeater;
break; 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: { case IDRT_NONE: {
default: default:
break; break;
@ -223,12 +309,12 @@ IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType()
CIRCDDBMultiClientQuery * item = popQuery(type, key); CIRCDDBMultiClientQuery * item = popQuery(type, key);
if (item != NULL) {//is this a response to a query we've sent ? 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 ? canAddToQueue = (item->incrementResponseCount() >= m_clients.size()); //did all the clients respond or did we have an answer ?
wasQuery = true; wasQuery = true;
} }
else { else {
item = new CIRCDDBMultiClientQuery(user, repeater, gateway, address, timestamp, type); item = new CIRCDDBMultiClientQuery(user, repeater, gateway, address, timestamp, port, type);
canAddToQueue = true; 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(); m_responseQueueLock.lock();
if (m_responseQueue.size() != 0) result = m_responseQueue[0]->getType(); if (m_responseQueue.size() != 0) result = m_responseQueue[0]->getType();
@ -370,5 +456,3 @@ CIRCDDBMultiClientQuery_HashMap * CIRCDDBMultiClient::getQueriesHashMap(IRCDDB_R
return NULL; return NULL;
} }
} }

@ -40,12 +40,14 @@ public:
const std::string& gateway, const std::string& gateway,
const std::string& address, const std::string& address,
const std::string& timestamp, const std::string& timestamp,
const std::string& remotePort,
IRCDDB_RESPONSE_TYPE type) : IRCDDB_RESPONSE_TYPE type) :
m_user(user), m_user(user),
m_repeater(repeater), m_repeater(repeater),
m_gateway(gateway), m_gateway(gateway),
m_address(address), m_address(address),
m_timestamp(timestamp), m_timestamp(timestamp),
m_remotePort(remotePort),
m_type(type), m_type(type),
m_responseCount(0) m_responseCount(0)
{ {
@ -77,6 +79,11 @@ public:
return m_timestamp; return m_timestamp;
} }
std::string getRemotePort() const
{
return m_remotePort;
}
unsigned int getResponseCount() unsigned int getResponseCount()
{ {
return m_responseCount; 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. 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()); //wxLogMessage("Before : %s"), toString());
if (timestamp.empty() || timestamp.compare(m_timestamp) >= 0) { if (timestamp.empty() || timestamp.compare(m_timestamp) >= 0) {
@ -100,6 +107,7 @@ public:
m_repeater = repeater; m_repeater = repeater;
m_gateway = gateway; m_gateway = gateway;
m_timestamp = timestamp; m_timestamp = timestamp;
m_remotePort = remotePort;
if(m_address.empty() && !address.empty()) if(m_address.empty() && !address.empty())
m_address = address; m_address = address;
@ -125,6 +133,7 @@ private:
std::string m_gateway; std::string m_gateway;
std::string m_address; std::string m_address;
std::string m_timestamp; std::string m_timestamp;
std::string m_remotePort;
IRCDDB_RESPONSE_TYPE m_type; IRCDDB_RESPONSE_TYPE m_type;
unsigned int m_responseCount; unsigned int m_responseCount;
}; };
@ -150,11 +159,17 @@ public:
virtual bool findGateway(const std::string & gatewayCallsign); virtual bool findGateway(const std::string & gatewayCallsign);
virtual bool findRepeater(const std::string & repeaterCallsign); virtual bool findRepeater(const std::string & repeaterCallsign);
virtual bool findUser(const std::string & userCallsign); 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 IRCDDB_RESPONSE_TYPE getMessageType();
virtual bool receiveRepeater(std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address); virtual bool receiveRepeater(std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address);
virtual bool receiveGateway(std::string & gatewayCallsign, std::string & address); virtual bool receiveGateway(std::string & gatewayCallsign, std::string & address);
virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address); virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address);
virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address, std::string & timeStamp); virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address, std::string & timeStamp);
virtual 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 sendDStarGatewayInfo(const std::string subcommand, const std::vector<std::string> parms);
virtual void close(); virtual void close();

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

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

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

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

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

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

@ -135,7 +135,9 @@ void* CIcomRepeaterProtocolHandler::Entry()
{ {
CLog::logInfo("Starting the Icom Controller thread"); CLog::logInfo("Starting the Icom Controller thread");
#ifndef DEBUG_DSTARGW
try { try {
#endif
while (!m_killed) { while (!m_killed) {
sendGwyPackets(); sendGwyPackets();
@ -145,14 +147,18 @@ void* CIcomRepeaterProtocolHandler::Entry()
m_retryTimer.clock(); m_retryTimer.clock();
} }
#ifndef DEBUG_DSTARGW
} }
catch (std::exception& e) { catch (std::exception& e) {
std::string message(e.what()); std::string message(e.what());
CLog::logError("Exception raised in the Icom Controller thread - \"%s\"", message.c_str()); CLog::logError("Exception raised in the Icom Controller thread - \"%s\"", message.c_str());
throw;
} }
catch (...) { catch (...) {
CLog::logError("Unknown exception raised in the Icom Controller thread"); CLog::logError("Unknown exception raised in the Icom Controller thread");
throw;
} }
#endif
CLog::logInfo("Stopping the Icom Controller thread"); 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) void CLogFileTarget::printLogInt(const std::string& msg)
{ {
m_file.seekp(0, std::ios::end);
if(m_rotate) if(m_rotate)
printLogIntRotate(msg); printLogIntRotate(msg);
else else

@ -23,14 +23,15 @@ export LOG_DIR=/var/log/dstargateway/
ifeq ($(ENABLE_DEBUG), 1) ifeq ($(ENABLE_DEBUG), 1)
# choose this if you want debugging help # 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 else
# or, you can choose this for a much smaller executable without debugging help # or, you can choose this for a much smaller executable without debugging help
CPPFLAGS=-W -O3 -Wall -Werror -std=c++17 export CPPFLAGS=-W -O3 -Wall -Werror -std=c++17
endif endif
export CC=g++ export CC=g++
export LDFLAGS:=-lcurl -pthread export LDFLAGS+= -lcurl -pthread
ifeq ($(USE_GPSD), 1) ifeq ($(USE_GPSD), 1)
export CPPFLAGS+= -DUSE_GPSD export CPPFLAGS+= -DUSE_GPSD

@ -11,6 +11,7 @@
- [3.4. Prerequisites and dependencies](#34-prerequisites-and-dependencies) - [3.4. Prerequisites and dependencies](#34-prerequisites-and-dependencies)
- [3.5. Building](#35-building) - [3.5. Building](#35-building)
- [3.5.0.1. Build With GPSD Support](#3501-build-with-gpsd-support) - [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.6. Installing](#36-installing)
- [3.7. Configuring](#37-configuring) - [3.7. Configuring](#37-configuring)
- [4. Contributing](#4-contributing) - [4. Contributing](#4-contributing)
@ -91,6 +92,11 @@ make
``` ```
make USE_GPS=1 make USE_GPS=1
``` ```
#### 3.5.0.2. Debug Build
```
make ENABLE_DEBUG=1
```
Note that this will link with libl
## 3.6. Installing ## 3.6. Installing
The program is meant to run as a systemd service. All bits an pieces are provided. 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. Version History
## 5.1. Version 0.5 ## 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)) - [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] 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)) - [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 First working version
# 6. Future # 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 : 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 - 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 - 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 - &#9745; Send the connection status to APRS-IS as a status frame
- &#9746; Reinstantiate DRATS - &#9746; Reinstantiate DRATS

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

@ -16,6 +16,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/ */
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include "StringUtils.h" #include "StringUtils.h"
size_t CStringUtils::find_nth(const std::string& haystack, char needle, size_t nth) 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; 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 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.