From 731f26d04e778ae3a66dd11f19848c7a7f6a8bb2 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 30 Dec 2021 13:45:02 +0100 Subject: [PATCH 001/201] Add nattrversal handler --- NatTraversalHandler.cpp | 61 +++++++++++++++++++++++++++++++ NatTraversalHandler.h | 80 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 NatTraversalHandler.cpp create mode 100644 NatTraversalHandler.h diff --git a/NatTraversalHandler.cpp b/NatTraversalHandler.cpp new file mode 100644 index 0000000..8ee9ac0 --- /dev/null +++ b/NatTraversalHandler.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010,2011,2012,2013,2014,2015,2016,2017,2018 by Jonathan Naylor G4KLX + * + * 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. + */ + +#if defined(ENABLE_NAT_TRAVERSAL) + +#include "NatTraversalHandler.h" + +const unsigned int CACHE_SIZE = 500U; + +CNatTraversalHandler::CNatTraversalHandler() : +m_g2cache(CACHE_SIZE), +m_g2Handler(NULL) +{ + +} + +CNatTraversalHandler::~CNatTraversalHandler() +{ + for (CNatTraversalCache_t::iterator it = m_g2cache.begin(); it != m_g2cache.end(); ++it) + delete it->second; +} + +void CNatTraversalHandler::setG2Handler(CG2ProtocolHandler * handler) +{ + m_g2Handler = handler; +} + +void CNatTraversalHandler::traverseNatG2(const wxString& address) +{ + if(m_g2Handler != NULL){ + CNatTraversalRecord* record = m_g2cache[address]; + + if(record == NULL) { + record = new CNatTraversalRecord(address); + m_g2cache[address] = record; + } + + std::time_t currentTime = std::time(NULL); + if(currentTime - record->getTimestamp() > G2_TRAVERSAL_TIMEOUT) { + record->setTimestamp(currentTime); + m_g2Handler->traverseNat(address); + } + } +} + +#endif \ No newline at end of file diff --git a/NatTraversalHandler.h b/NatTraversalHandler.h new file mode 100644 index 0000000..0069fea --- /dev/null +++ b/NatTraversalHandler.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010,2011,2012,2013,2014,2015,2016,2017,2018 by Jonathan Naylor G4KLX + * + * 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. + */ + +#if defined(ENABLE_NAT_TRAVERSAL) +#ifndef NatTraversalHandler_H +#define NatTraversalHandler_H + +#define G2_TRAVERSAL_TIMEOUT 29 //seconds + +#include "G2ProtocolHandler.h" + +#include +#include + +enum NAT_TRAVERSAL_TYPE { + NTT_G2, + //NTT_DEXTRA + //NTT_DCS + //NTT_DPLUS +}; + +class CNatTraversalRecord { +public: + CNatTraversalRecord(const wxString& address) : + m_address(address), + m_timestamp(0) + { + } + + std::time_t getTimestamp() const + { + return m_timestamp; + } + + void setTimestamp(std::time_t timestamp) + { + m_timestamp = timestamp; + } + +private: + wxString m_address; + std::time_t m_timestamp; +}; + +WX_DECLARE_STRING_HASH_MAP(CNatTraversalRecord*, CNatTraversalCache_t); + +/* +* This keeps track of when we UDP punched to one destination so to avoid unnecessary traffic on each ircddb reporting +*/ +class CNatTraversalHandler { +public: + CNatTraversalHandler(); + ~CNatTraversalHandler(); + + void setG2Handler(CG2ProtocolHandler* handler); + void traverseNatG2(const wxString& address); + +private: + CNatTraversalCache_t m_g2cache; + CG2ProtocolHandler* m_g2Handler; +}; + +#endif + +#endif \ No newline at end of file From 80a91ee316d83bb22a3bd3f62c432af034c24ade Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 31 Dec 2021 06:28:03 +0100 Subject: [PATCH 002/201] update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4081e26..f58ca15 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ I Use [Git flow](https://danielkummer.github.io/git-flow-cheatsheet/) as my work # 5. Version History ## 5.1. Version 0.4 +- [Bugfix] Posotions received over radio were not sent to APRS-IS when GPDS connection failed. ([#7](https://github.com/F4FXL/DStarGateway/issues/7)) - [Improvement] Bring back GPSD support (https://github.com/F4FXL/DStarGateway/issues/6) - [Improvement] Log enhancements ([#4])(https://github.com/F4FXL/DStarGateway/issues/4) ## 5.2. Version 0.3 From d6ced92a804dc434fc50e57ad759d0ebf731cc4a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 30 Dec 2021 13:45:02 +0100 Subject: [PATCH 003/201] Add nattrversal handler --- NatTraversalHandler.cpp | 61 +++++++++++++++++++++++++++++++ NatTraversalHandler.h | 80 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 NatTraversalHandler.cpp create mode 100644 NatTraversalHandler.h diff --git a/NatTraversalHandler.cpp b/NatTraversalHandler.cpp new file mode 100644 index 0000000..8ee9ac0 --- /dev/null +++ b/NatTraversalHandler.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (C) 2010,2011,2012,2013,2014,2015,2016,2017,2018 by Jonathan Naylor G4KLX + * + * 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. + */ + +#if defined(ENABLE_NAT_TRAVERSAL) + +#include "NatTraversalHandler.h" + +const unsigned int CACHE_SIZE = 500U; + +CNatTraversalHandler::CNatTraversalHandler() : +m_g2cache(CACHE_SIZE), +m_g2Handler(NULL) +{ + +} + +CNatTraversalHandler::~CNatTraversalHandler() +{ + for (CNatTraversalCache_t::iterator it = m_g2cache.begin(); it != m_g2cache.end(); ++it) + delete it->second; +} + +void CNatTraversalHandler::setG2Handler(CG2ProtocolHandler * handler) +{ + m_g2Handler = handler; +} + +void CNatTraversalHandler::traverseNatG2(const wxString& address) +{ + if(m_g2Handler != NULL){ + CNatTraversalRecord* record = m_g2cache[address]; + + if(record == NULL) { + record = new CNatTraversalRecord(address); + m_g2cache[address] = record; + } + + std::time_t currentTime = std::time(NULL); + if(currentTime - record->getTimestamp() > G2_TRAVERSAL_TIMEOUT) { + record->setTimestamp(currentTime); + m_g2Handler->traverseNat(address); + } + } +} + +#endif \ No newline at end of file diff --git a/NatTraversalHandler.h b/NatTraversalHandler.h new file mode 100644 index 0000000..0069fea --- /dev/null +++ b/NatTraversalHandler.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2010,2011,2012,2013,2014,2015,2016,2017,2018 by Jonathan Naylor G4KLX + * + * 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. + */ + +#if defined(ENABLE_NAT_TRAVERSAL) +#ifndef NatTraversalHandler_H +#define NatTraversalHandler_H + +#define G2_TRAVERSAL_TIMEOUT 29 //seconds + +#include "G2ProtocolHandler.h" + +#include +#include + +enum NAT_TRAVERSAL_TYPE { + NTT_G2, + //NTT_DEXTRA + //NTT_DCS + //NTT_DPLUS +}; + +class CNatTraversalRecord { +public: + CNatTraversalRecord(const wxString& address) : + m_address(address), + m_timestamp(0) + { + } + + std::time_t getTimestamp() const + { + return m_timestamp; + } + + void setTimestamp(std::time_t timestamp) + { + m_timestamp = timestamp; + } + +private: + wxString m_address; + std::time_t m_timestamp; +}; + +WX_DECLARE_STRING_HASH_MAP(CNatTraversalRecord*, CNatTraversalCache_t); + +/* +* This keeps track of when we UDP punched to one destination so to avoid unnecessary traffic on each ircddb reporting +*/ +class CNatTraversalHandler { +public: + CNatTraversalHandler(); + ~CNatTraversalHandler(); + + void setG2Handler(CG2ProtocolHandler* handler); + void traverseNatG2(const wxString& address); + +private: + CNatTraversalCache_t m_g2cache; + CG2ProtocolHandler* m_g2Handler; +}; + +#endif + +#endif \ No newline at end of file From 9a061de196bc06ab96a1c2457203b1d9f72ce639 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 31 Dec 2021 10:13:32 +0100 Subject: [PATCH 004/201] Bump version number and update readme --- README.md | 22 ++++++++++++---------- Version.h | 2 +- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index b04a1a7..0667ac6 100644 --- a/README.md +++ b/README.md @@ -15,10 +15,11 @@ - [4. Contributing](#4-contributing) - [4.1. Work Flow](#41-work-flow) - [5. Version History](#5-version-history) - - [5.1. Version 0.4](#51-version-04) - - [5.2. Version 0.3](#52-version-03) - - [5.3. Version 0.2](#53-version-02) - - [5.4. Version 0.1](#54-version-01) + - [5.1. Version 0.5](#51-version-05) + - [5.2. Version 0.4](#52-version-04) + - [5.3. Version 0.3](#53-version-03) + - [5.4. Version 0.2](#54-version-02) + - [5.5. Version 0.1](#55-version-01) - [6. Future](#6-future) @@ -110,17 +111,18 @@ I Use [Git flow](https://danielkummer.github.io/git-flow-cheatsheet/) as my work - Compilation produces no warnings - Code formating rules are observed (these are very lousy though) # 5. Version History -## 5.1. Version 0.4 +## 5.1. Version 0.5 +## 5.2. Version 0.4 - [Improvement] Add APRS status link feature ([#8](https://github.com/F4FXL/DStarGateway/issues/8)) - [Bugfix] Posotions received over radio were not sent to APRS-IS when GPDS connection failed. ([#7](https://github.com/F4FXL/DStarGateway/issues/7)) -- [Improvement] Bring back GPSD support (https://github.com/F4FXL/DStarGateway/issues/6) -- [Improvement] Log enhancements ([#4])(https://github.com/F4FXL/DStarGateway/issues/4) -## 5.2. Version 0.3 +- [Improvement] Bring back GPSD support ([#6](https://github.com/F4FXL/DStarGateway/issues/6)) +- [Improvement] Log enhancements ([#4](https://github.com/F4FXL/DStarGateway/issues/4)) +## 5.3. Version 0.3 - [Improvement] Get ride of libcongif++ dependency. When upgrading from earlier version you need to manualy delete the config file before reinstalling. -## 5.3. Version 0.2 +## 5.4. Version 0.2 - [Bugfix] ircDDBFreeze when repeater not found ([#1](https://github.com/F4FXL/DStarGateway/issues/1)) - Code sanitization -## 5.4. Version 0.1 +## 5.5. Version 0.1 First working version # 6. Future I started this during my 2021 seasons holiday. It took me almost 8 days to get to a workable version. Here are a couple of stuff I'd like to do : diff --git a/Version.h b/Version.h index e888470..721223a 100644 --- a/Version.h +++ b/Version.h @@ -26,6 +26,6 @@ const std::string PRODUCT_NAME("DStarGateway"); const std::string VENDOR_NAME("Geoffrey Merck F4FXL / KC3FRA and Contributors"); -const std::string VERSION("0.4"); +const std::string VERSION("0.5"); const std::string FULL_PRODUCT_NAME = PRODUCT_NAME + " v" + VERSION + "-" + gitversion; const std::string SHORT_PRODUCT_NAME = "DStarGW v" + VERSION + "-" + gitversion; From 51926208e02f55e9ee740c9732d6be39fe6457d8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 31 Dec 2021 11:28:04 +0100 Subject: [PATCH 005/201] Fix dead repeaterprotocolhandler when interface cannot be opened --- DStarGatewayApp.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/DStarGatewayApp.cpp b/DStarGatewayApp.cpp index c8fd520..cd7358b 100644 --- a/DStarGatewayApp.cpp +++ b/DStarGatewayApp.cpp @@ -160,6 +160,9 @@ bool CDStarGatewayApp::createThread() for(unsigned int i = 0U; i < config.getRepeaterCount(); i++) { TRepeater rptrConfig; config.getRepeater(i, rptrConfig); + auto repeaterProtocolHandler = repeaterProtocolFactory.getRepeaterProtocolHandler(rptrConfig.hwType, gatewayConfig, rptrConfig.address, rptrConfig.port); + if(repeaterProtocolHandler == nullptr) + continue; m_thread->addRepeater(rptrConfig.callsign, rptrConfig.band, rptrConfig.address, @@ -177,7 +180,7 @@ bool CDStarGatewayApp::createThread() rptrConfig.description1, rptrConfig.description2, rptrConfig.url, - repeaterProtocolFactory.getRepeaterProtocolHandler(rptrConfig.hwType, gatewayConfig, rptrConfig.address, rptrConfig.port), + repeaterProtocolHandler, rptrConfig.band1, rptrConfig.band2, rptrConfig.band3); From 41fd91f354bfa0cfd827e20dca508cc1316837b8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 31 Dec 2021 11:40:51 +0100 Subject: [PATCH 006/201] Fix garbage in log --- VersionUnit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VersionUnit.cpp b/VersionUnit.cpp index a382039..ac877aa 100644 --- a/VersionUnit.cpp +++ b/VersionUnit.cpp @@ -48,7 +48,7 @@ m_out(0U) auto vstr = SHORT_PRODUCT_NAME; vstr.resize(NUM_FRAMES, ' '); - CLog::logInfo("Version text set to \"%s\"\n", vstr); + CLog::logInfo("Version text set to \"%s\"\n", vstr.c_str()); CSlowDataEncoder encoder; encoder.setTextData(vstr); From ba233dc89ad8ae6055793da53e6f55ecb84d4bc5 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 31 Dec 2021 11:41:19 +0100 Subject: [PATCH 007/201] really fix failure to open rpeater protocol handler --- DStarGatewayApp.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/DStarGatewayApp.cpp b/DStarGatewayApp.cpp index cd7358b..dd40ce7 100644 --- a/DStarGatewayApp.cpp +++ b/DStarGatewayApp.cpp @@ -81,6 +81,7 @@ CDStarGatewayApp::~CDStarGatewayApp() bool CDStarGatewayApp::init() { return createThread(); + //2021-12-31 F4FXL This is ugly, if we failed to create the thread we do not clean up ... :( } void CDStarGatewayApp::run() @@ -151,11 +152,8 @@ bool CDStarGatewayApp::createThread() } // Setup the repeaters - if(config.getRepeaterCount() == 0U) { - CLog::logInfo("No repeater configured\n"); - return false; - } bool ddEnabled = false; + bool atLeastOneRepeater = false; CRepeaterProtocolHandlerFactory repeaterProtocolFactory; for(unsigned int i = 0U; i < config.getRepeaterCount(); i++) { TRepeater rptrConfig; @@ -163,6 +161,7 @@ bool CDStarGatewayApp::createThread() auto repeaterProtocolHandler = repeaterProtocolFactory.getRepeaterProtocolHandler(rptrConfig.hwType, gatewayConfig, rptrConfig.address, rptrConfig.port); if(repeaterProtocolHandler == nullptr) continue; + atLeastOneRepeater = true; m_thread->addRepeater(rptrConfig.callsign, rptrConfig.band, rptrConfig.address, @@ -189,6 +188,12 @@ bool CDStarGatewayApp::createThread() if(!ddEnabled) ddEnabled = rptrConfig.band.length() > 1U; } + + if(!atLeastOneRepeater) { + CLog::logError("Error: no repeaters are enabled or opening network communication to repeater failed"); + return false; + } + m_thread->setDDModeEnabled(ddEnabled); CLog::logInfo("DD Mode enabled: %d", int(ddEnabled)); From 4e5f2e54376e68e88bd924087ee7358d0ec442f5 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 31 Dec 2021 11:57:45 +0100 Subject: [PATCH 008/201] fix wrong systemd file --- debian/dstargateway.service | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/debian/dstargateway.service b/debian/dstargateway.service index eeada84..4f8c069 100644 --- a/debian/dstargateway.service +++ b/debian/dstargateway.service @@ -3,14 +3,16 @@ User=dstar Description=D-STAR Gateway Daemon After=network.target,network-online.target Wants=network-online.target -RestartSec=5 -StartLimitIntervalSec=60 -StartLimitBurst=0 - [Service] Type=simple ExecStart=/usr/local/bin/dstargateway %CFG_DIR%/dstargateway.cfg +Restart=on-failure +RestartSec=5 +StartLimitIntervalSec=60 +StartLimitBurst=0 [Install] WantedBy=multi-user.target + + From ad76ec937da77498daee81bbcc9478688e9cb859 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 31 Dec 2021 12:15:26 +0100 Subject: [PATCH 009/201] udpate readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0667ac6..0783b3b 100644 --- a/README.md +++ b/README.md @@ -135,4 +135,5 @@ I started this during my 2021 seasons holiday. It took me almost 8 days to get t - ☒ Migrate all the "accessories" (VoiceTransmit, RemoteControl ...) - ☒ Automatic refresh of host files - ☒ Reduce ircDDB dependency, build something more P2P, maybe based on [Distributed Hashtable](https://github.com/DavidKeller/kademlia) ? +- ☒ Forward messages RS-MS1A to APRS and vice versa - Everything that might come handy to make dstar the most powerful system ever :) From 358e7530329bad16aa11faf34593b1f69d625186 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 31 Dec 2021 12:16:32 +0100 Subject: [PATCH 010/201] update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0783b3b..5879b05 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ make USE_GPS=1 ## 3.6. Installing The program is meant to run as a systemd service. All bits an pieces are provided. ``` -sudo make install +sudo make install newhostfiles ``` ## 3.7. Configuring After installing you have to edit the configuration file. If you went with default paths, the config file is located in `/usr/local/etc/dstargateway.cfg` @@ -135,5 +135,5 @@ I started this during my 2021 seasons holiday. It took me almost 8 days to get t - ☒ Migrate all the "accessories" (VoiceTransmit, RemoteControl ...) - ☒ Automatic refresh of host files - ☒ Reduce ircDDB dependency, build something more P2P, maybe based on [Distributed Hashtable](https://github.com/DavidKeller/kademlia) ? -- ☒ Forward messages RS-MS1A to APRS and vice versa +- ☒ Forward messages from RS-MS1A to APRS and vice versa - Everything that might come handy to make dstar the most powerful system ever :) From 8aea19f87c115a4386036ba1218dbc78bab62eb6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 11:36:39 +0100 Subject: [PATCH 011/201] Fix trying to connect to irc when no irc is enabled --- Config.cpp | 1 + DStarGatewayApp.cpp | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Config.cpp b/Config.cpp index 210d26a..c421da2 100644 --- a/Config.cpp +++ b/Config.cpp @@ -120,6 +120,7 @@ TConfigValue * CConfig::readKeyAndValue(const std::string s) const bool CConfig::getValue(const std::string §ion, const std::string& key, bool &value, bool defaultValue) const { + value = defaultValue; std::string valueTemp; std::string dafaultValueStr = defaultValue ? "true" : "false"; bool ret = getValue(section, key, valueTemp, dafaultValueStr, {"true", "1", "false", "0"}); diff --git a/DStarGatewayApp.cpp b/DStarGatewayApp.cpp index dd40ce7..6150d62 100644 --- a/DStarGatewayApp.cpp +++ b/DStarGatewayApp.cpp @@ -206,13 +206,15 @@ bool CDStarGatewayApp::createThread() CIRCDDB * ircDDB = new CIRCDDBClient(ircDDBConfig.hostname, 9007U, ircDDBConfig.username, ircDDBConfig.password, FULL_PRODUCT_NAME, gatewayConfig.address, ircDDBConfig.isQuadNet); clients.push_back(ircDDB); } - CIRCDDBMultiClient* multiClient = new CIRCDDBMultiClient(clients); - bool res = multiClient->open(); - if (!res) { - CLog::logInfo("Cannot initialise the ircDDB protocol handler\n"); - return false; + if(clients.size() > 0U) { + CIRCDDBMultiClient* multiClient = new CIRCDDBMultiClient(clients); + bool res = multiClient->open(); + if (!res) { + CLog::logInfo("Cannot initialise the ircDDB protocol handler\n"); + return false; + } + m_thread->setIRC(multiClient); } - m_thread->setIRC(multiClient); // Setup Dextra TDextra dextraConfig; From 95171694914ae310a2876c1d4acefd14110fb2e0 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 11:38:17 +0100 Subject: [PATCH 012/201] Fix bbuggy default config --- example.cfg | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/example.cfg b/example.cfg index 81c1103..becc060 100644 --- a/example.cfg +++ b/example.cfg @@ -32,12 +32,14 @@ username= # The ircDDB username defaults to the value defined for g password= [ircddb_3] -hostname=false +enabled=false +hostname= username=CHNGME # The ircDDB username defaults to the value defined for gateway callsign. password= [ircddb_4] -hostname=false +enabled=false +hostname= username=CHNGME # The ircDDB username defaults to the value defined for gateway callsign. password= From 28a33aa0c5ca91d83081b6ae6d46642934f8bd03 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 11:54:21 +0100 Subject: [PATCH 013/201] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5879b05..03d5df7 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,7 @@ I Use [Git flow](https://danielkummer.github.io/git-flow-cheatsheet/) as my work - Code formating rules are observed (these are very lousy though) # 5. Version History ## 5.1. Version 0.5 +- [Bugfix] Trying to connect to ghost ircDDB when no ircDDB is configured ## 5.2. Version 0.4 - [Improvement] Add APRS status link feature ([#8](https://github.com/F4FXL/DStarGateway/issues/8)) - [Bugfix] Posotions received over radio were not sent to APRS-IS when GPDS connection failed. ([#7](https://github.com/F4FXL/DStarGateway/issues/7)) From 412edd03df8ff4acabf82950188266be2ae642e4 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 17:11:42 +0100 Subject: [PATCH 014/201] Add file associations --- .vscode/settings.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d6cf341..727ce82 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,5 +5,8 @@ "binaryPath": "/home/geoffrey/Documents/Dev/DStarGateway/dstargateway", "binaryArgs": [] } - ] + ], + "files.associations": { + "new": "cpp" + } } \ No newline at end of file From 769701bedc8c8acc4f9ce137aebac0a2d97f0b8e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 17:12:03 +0100 Subject: [PATCH 015/201] #9 Add logTrace --- Log.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Log.h b/Log.h index 26414c8..86c749e 100644 --- a/Log.h +++ b/Log.h @@ -38,7 +38,8 @@ private: static void getTimeStamp(std::string & s); - template static void formatLogMessage(std::string& output, LOG_SEVERITY severity, const std::string & f, Args... args) + template + static void formatLogMessage(std::string& output, LOG_SEVERITY severity, const std::string & f, Args... args) { assert(severity != LOG_NONE); @@ -82,6 +83,11 @@ public: static void addTarget(CLogTarget * target); static void finalise(); + template static void logTrace(const std::string & f, Args... args) + { + log(LOG_TRACE, f, args...); + } + template static void logDebug(const std::string & f, Args... args) { log(LOG_DEBUG, f, args...); From 045127d90ba337cc3061f6dbc28b3ac801ed6066 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 17:16:09 +0100 Subject: [PATCH 016/201] #9 Refactor APRS Collection logic This is quie a deep change. Collecting logic has been moved to individual objects/classes. This reduces amount of code (better maitainability) and prepares the path for supporting messages. Supporting newer slow data types is just a matter of adding new ClowDataCollector. This also brings the benefit to support interleaved slow data as this is the case with RS-MS1A messages (messages are interleaved with GPS Data) The source callsign for NMEA sentences is also set with correct SSID (-5) as per http://www.aprs.org/aprs11/SSIDs.txt The NMEA sentences are no longer converted but sent to APRS-S almost as is, just packed into an APRS frame. --- APRSCollector.cpp | 530 +++----------------------------------- APRSCollector.h | 40 +-- APRSWriter.cpp | 2 +- DStarDefines.h | 1 + GPSACollector.cpp | 99 +++++++ GPSACollector.h | 63 +++++ NMEASentenceCollector.cpp | 135 ++++++++++ NMEASentenceCollector.h | 40 +++ SentenceCollector.cpp | 75 ++++++ SentenceCollector.h | 46 ++++ SlowDataCollector.cpp | 97 +++++++ SlowDataCollector.h | 51 ++++ 12 files changed, 648 insertions(+), 531 deletions(-) create mode 100644 GPSACollector.cpp create mode 100644 GPSACollector.h create mode 100644 NMEASentenceCollector.cpp create mode 100644 NMEASentenceCollector.h create mode 100644 SentenceCollector.cpp create mode 100644 SentenceCollector.h create mode 100644 SlowDataCollector.cpp create mode 100644 SlowDataCollector.h diff --git a/APRSCollector.cpp b/APRSCollector.cpp index 8af6d24..92284e0 100644 --- a/APRSCollector.cpp +++ b/APRSCollector.cpp @@ -25,6 +25,8 @@ #include "APRSCollector.h" #include "DStarDefines.h" #include "Utils.h" +#include "NMEASentenceCollector.h" +#include "GPSACollector.h" const unsigned int APRS_CSUM_LENGTH = 4U; const unsigned int APRS_DATA_LENGTH = 300U; @@ -34,528 +36,64 @@ const char APRS_OVERLAY = '\\'; const char APRS_SYMBOL = 'K'; CAPRSCollector::CAPRSCollector() : -m_state(AS_NONE), -m_ggaData(NULL), -m_ggaLength(0U), -m_ggaValid(false), -m_rmcData(NULL), -m_rmcLength(0U), -m_rmcValid(false), -m_crcData(NULL), -m_crcLength(0U), -m_crcValid(false), -m_buffer(NULL), -m_slowData(SS_FIRST), -m_collector(), -m_callsign() +m_collectors() { - m_ggaData = new unsigned char[APRS_DATA_LENGTH]; - m_rmcData = new unsigned char[APRS_DATA_LENGTH]; - m_crcData = new unsigned char[APRS_DATA_LENGTH]; - m_buffer = new unsigned char[SLOW_DATA_BLOCK_LENGTH]; + m_collectors.push_back(new CGPSACollector()); + m_collectors.push_back(new CNMEASentenceCollector("$GPRMC")); + m_collectors.push_back(new CNMEASentenceCollector("$GPGGA")); + m_collectors.push_back(new CNMEASentenceCollector("$GPGLL")); + m_collectors.push_back(new CNMEASentenceCollector("$GPVTG")); + m_collectors.push_back(new CNMEASentenceCollector("$GPGSA")); + m_collectors.push_back(new CNMEASentenceCollector("$GPGSV")); } CAPRSCollector::~CAPRSCollector() { - delete[] m_ggaData; - delete[] m_rmcData; - delete[] m_crcData; - delete[] m_buffer; + for(auto collector : m_collectors) { + delete collector; + } + m_collectors.clear(); } void CAPRSCollector::writeHeader(const std::string& callsign) { - m_callsign = callsign; + for(auto collector : m_collectors) { + collector->setMyCall(callsign); + } } bool CAPRSCollector::writeData(const unsigned char* data) { - assert(data != NULL); - - switch (m_slowData) { - case SS_FIRST: - m_buffer[0U] = data[0U] ^ SCRAMBLER_BYTE1; - m_buffer[1U] = data[1U] ^ SCRAMBLER_BYTE2; - m_buffer[2U] = data[2U] ^ SCRAMBLER_BYTE3; - m_slowData = SS_SECOND; - return false; - - case SS_SECOND: - m_buffer[3U] = data[0U] ^ SCRAMBLER_BYTE1; - m_buffer[4U] = data[1U] ^ SCRAMBLER_BYTE2; - m_buffer[5U] = data[2U] ^ SCRAMBLER_BYTE3; - m_slowData = SS_FIRST; - break; + bool ret = false; + for(auto collector : m_collectors) { + bool ret2 = collector->writeData(data); + ret = ret || ret2; } - - // Is it GPS data? - if ((m_buffer[0U] & SLOW_DATA_TYPE_MASK) == SLOW_DATA_TYPE_GPS) - return addGPSData(m_buffer + 1U); - - return false; + return ret; } void CAPRSCollector::reset() { - m_state = AS_NONE; - m_ggaLength = 0U; - m_ggaValid = false; - m_rmcLength = 0U; - m_rmcValid = false; - m_crcLength = 0U; - m_crcValid = false; - m_slowData = SS_FIRST; - m_collector.clear(); - m_callsign.clear(); -} - -void CAPRSCollector::sync() -{ - m_slowData = SS_FIRST; -} - -bool CAPRSCollector::addGPSData(const unsigned char* data) -{ - assert(data != NULL); - - m_collector += std::string((char*)data, 5U); - - if (m_state == AS_GGA) { - addGGAData(); - return false; - } else if (m_state == AS_RMC) { - return addRMCData(); - } else if (m_state == AS_CRC) { - return addCRCData(); - } - - if (m_state != AS_GGA && m_collector.find("$GPGGA") != std::string::npos) { - m_state = AS_GGA; - m_ggaLength = 0U; - m_ggaValid = false; - m_rmcLength = 0U; - m_rmcValid = false; - return false; - } else if (m_state != AS_RMC && m_collector.find("$GPRMC") != std::string::npos) { - m_state = AS_RMC; - m_rmcLength = 0U; - m_rmcValid = false; - return false; - } else if (m_state != AS_CRC && m_collector.find("$$CRC") != std::string::npos) { - m_state = AS_CRC; - m_crcLength = 0U; - m_crcValid = false; - } - - return false; -} - -void CAPRSCollector::addGGAData() -{ - std::string::size_type n2 = m_collector.find_last_of('\x0A'); - if (n2 == std::string::npos) - return; - - std::string::size_type n1 = m_collector.find("$GPGGA"); - if (n1 == std::string::npos) - return; - - if (n2 < n1) - return; - - std::string::size_type len = n2 - n1; - - if (len >= APRS_DATA_LENGTH) { - m_ggaLength = 0U; - m_ggaValid = false; - m_state = AS_NONE; - return; - } - - m_ggaLength = 0U; - for (unsigned int i = n1; i <= n2; i++) { - m_ggaData[m_ggaLength] = m_collector[i]; - m_ggaData[m_ggaLength] &= 0x7FU; - m_ggaLength++; - } - - bool ret = checkXOR(m_ggaData + 1U, m_ggaLength - 1U); - if (ret) { - // CUtils::dump("$GPGGA Valid", m_ggaData, m_ggaLength); - m_ggaValid = true; - m_state = AS_RMC; - } else { - // CUtils::dump("$GPGGA Bad checksum", m_ggaData, m_ggaLength); - m_ggaLength = 0U; - m_ggaValid = false; - m_state = AS_RMC; - } - - m_collector = m_collector.substr(n2); -} - -bool CAPRSCollector::addRMCData() -{ - std::string::size_type n2 = m_collector.find_last_of('\x0A'); - if (n2 == std::string::npos) - return false; - - std::string::size_type n1 = m_collector.find("$GPRMC"); - if (n1 == std::string::npos) - return false; - - if (n2 < n1) - return false; - - unsigned int len = n2 - n1; - - if (len >= APRS_DATA_LENGTH) { - m_rmcLength = 0U; - m_rmcValid = false; - m_state = AS_NONE; - return false; - } - - m_rmcLength = 0U; - for (unsigned int i = n1; i <= n2; i++) { - m_rmcData[m_rmcLength] = m_collector[i]; - m_rmcData[m_rmcLength] &= 0x7FU; - m_rmcLength++; - } - - bool ret = checkXOR(m_rmcData + 1U, m_rmcLength - 1U); - if (ret) { - // CUtils::dump("$GPRMC Valid", m_rmcData, m_rmcLength); - m_rmcValid = true; - } else { - // CUtils::dump("$GPRMC Bad checksum", m_rmcData, m_rmcLength); - m_rmcLength = 0U; - m_rmcValid = false; - } - - m_collector = m_collector.substr(n2); - - m_state = AS_NONE; - - return true; -} - -bool CAPRSCollector::addCRCData() -{ - std::string::size_type n2 = m_collector.find_last_of('\x0D'); - if (n2 == std::string::npos) - return false; - - std::string::size_type n1 = m_collector.find("$$CRC"); - if (n1 == std::string::npos) - return false; - - if (n2 < n1) - return false; - - unsigned int len = n2 - n1; - - if (len >= APRS_DATA_LENGTH) { - m_crcLength = 0U; - m_crcValid = false; - m_state = AS_NONE; - return false; - } - - m_crcLength = 0U; - for (unsigned int i = n1; i <= n2; i++) { - m_crcData[m_crcLength] = m_collector[i]; - m_crcLength++; - } - - bool ret = checkCRC(m_crcData, m_crcLength); - if (ret) { - // CUtils::dump("$$CRC Valid", m_crcData, m_crcLength); - m_crcValid = true; - m_state = AS_NONE; - m_collector = m_collector.substr(n2); - return true; - } else { - // CUtils::dump("$$CRC Bad checksum", m_crcData, m_crcLength); - m_crcLength = 0U; - m_crcValid = false; - m_state = AS_NONE; - m_collector = m_collector.substr(n2); - return false; - } -} - -unsigned int CAPRSCollector::getData(unsigned char* data, unsigned int length) -{ - assert(data != NULL); - - // Have we got GPS-A data? - if (m_crcValid) { - unsigned int len = m_crcLength - 10U; - if (len > length) - len = length; - - ::memcpy(data, m_crcData + 10U, len); - - m_crcLength = 0U; - m_crcValid = false; - - return len; + for(auto collector : m_collectors) { + collector->reset(); } - - // Have we got GGA data? - if (m_ggaValid) { - unsigned int len = convertNMEA1(data, length); - - m_ggaLength = 0U; - m_rmcLength = 0U; - m_ggaValid = false; - m_rmcValid = false; - - return len; - } - - // Have we got RMC data? - if (m_rmcValid) { - unsigned int len = convertNMEA2(data, length); - - m_ggaLength = 0U; - m_rmcLength = 0U; - m_ggaValid = false; - m_rmcValid = false; - - return len; - } - - return 0U; } -bool CAPRSCollector::checkXOR(const unsigned char* data, unsigned int length) const -{ - unsigned int posStar = 0U; - for (unsigned int i = length - 1U; i > 0U; i--) { - if (data[i] == '*') { - posStar = i; - break; - } - } - - if (posStar == 0U) - return false; - - unsigned char csum = calcXOR(data, posStar); - - char buffer[10U]; - ::sprintf(buffer, "%02X", csum); - - return ::memcmp(buffer, data + posStar + 1U, 2U) == 0; -} - -unsigned char CAPRSCollector::calcXOR(const unsigned char* buffer, unsigned int length) const -{ - assert(buffer != NULL); - assert(length > 0U); - - unsigned char res = 0U; - - for (unsigned int i = 0U; i < length; i++) - res ^= buffer[i]; - - return res; -} - -bool CAPRSCollector::checkCRC(const unsigned char* data, unsigned int length) const -{ - unsigned int csum = calcCRC(data + 10U, length - 10U); - - char buffer[10U]; - ::sprintf(buffer, "%04X", csum); - - return ::memcmp(buffer, data + 5U, APRS_CSUM_LENGTH) == 0; -} - -unsigned int CAPRSCollector::calcCRC(const unsigned char* buffer, unsigned int length) const -{ - assert(buffer != NULL); - assert(length > 0U); - - unsigned int icomcrc = 0xFFFFU; - - for (unsigned int j = 0U; j < length; j++) { - unsigned char ch = buffer[j]; - - for (unsigned int i = 0U; i < 8U; i++) { - bool xorflag = (((icomcrc ^ ch) & 0x01U) == 0x01U); - - icomcrc >>= 1; - - if (xorflag) - icomcrc ^= 0x8408U; - - ch >>= 1; - } - } - - return ~icomcrc & 0xFFFFU; -} - -unsigned int CAPRSCollector::convertNMEA1(unsigned char* data, unsigned int) -{ - // Parse the $GPGGA string into tokens - char* pGGA[20U]; - ::memset(pGGA, 0x00U, 20U * sizeof(char*)); - unsigned int nGGA = 0U; - - char* str = (char*)m_ggaData; - while (nGGA < 20U) { - char* p = mystrsep(&str, ",\r\n"); - - pGGA[nGGA++] = p; - if (p == NULL) - break; - } - - // Is there any position data? - if (pGGA[2U] == NULL || pGGA[3U] == NULL || pGGA[4U] == NULL || pGGA[5U] == NULL || ::strlen(pGGA[2U]) == 0U || ::strlen(pGGA[3U]) == 0U || ::strlen(pGGA[4U]) == 0 || ::strlen(pGGA[5U]) == 0) - return 0U; - - // Is it a valid GPS fix? - if (::strcmp(pGGA[6U], "0") == 0) - return 0U; - - char callsign[10U]; - dstarCallsignToAPRS(m_callsign, callsign); - - ::sprintf((char*)data, "%s>APDPRS,DSTAR*:!%.7s%s%c%.8s%s%c", callsign, pGGA[2U], pGGA[3U], APRS_OVERLAY, pGGA[4U], pGGA[5U], APRS_SYMBOL); - - // Get the bearing and speed from the RMC data - if (m_rmcValid) { - // Parse the $GPRMC string into tokens - char* pRMC[20U]; - ::memset(pRMC, 0x00U, 20U * sizeof(char*)); - unsigned int nRMC = 0U; - - str = (char*)m_rmcData; - for (;;) { - char* p = mystrsep(&str, ",\r\n"); - - pRMC[nRMC++] = p; - if (p == NULL) - break; - } - - // Check that we have a bearing and speed - if (pRMC[7U] != NULL && pRMC[8U] != NULL && ::strlen(pRMC[7U]) > 0U && ::strlen(pRMC[8U]) > 0U) { - int bearing = ::atoi(pRMC[8U]); - int speed = ::atoi(pRMC[7U]); - - ::sprintf((char*)data + ::strlen((char*)data), "%03d/%03d", bearing, speed); - } - } - - if (pGGA[9U] != NULL && ::strlen(pGGA[9U]) > 0U) { - // Convert altitude from metres to feet - int altitude = ::atoi(pGGA[9U]); - ::sprintf((char*)data + ::strlen((char*)data), "/A=%06.0f", float(altitude) * 3.28F); - } - - return ::strlen((char*)data); -} - -unsigned int CAPRSCollector::convertNMEA2(unsigned char* data, unsigned int) +void CAPRSCollector::sync() { - // Parse the $GPRMC string into tokens - char* pRMC[20U]; - ::memset(pRMC, 0x00U, 20U * sizeof(char*)); - unsigned int nRMC = 0U; - - char* str = (char*)m_rmcData; - while (nRMC < 20U) { - char* p = mystrsep(&str, ",\r\n"); - - pRMC[nRMC++] = p; - if (p == NULL) - break; + for(auto collector : m_collectors) { + collector->sync(); } - - // Is there any position data? - if (pRMC[3U] == NULL || pRMC[4U] == NULL || pRMC[5U] == NULL || pRMC[6U] == NULL || ::strlen(pRMC[3U]) == 0U || ::strlen(pRMC[4U]) == 0U || ::strlen(pRMC[5U]) == 0 || ::strlen(pRMC[6U]) == 0) - return 0U; - - // Is it a valid GPS fix? - if (::strcmp(pRMC[2U], "A") != 0) - return 0U; - - char callsign[10U]; - dstarCallsignToAPRS(m_callsign, callsign); - - ::sprintf((char*)data, "%s>APDPRS,DSTAR*:!%.7s%s%c%.8s%s%c", callsign, pRMC[3U], pRMC[4U], APRS_OVERLAY, pRMC[5U], pRMC[6U], APRS_SYMBOL); - - if (pRMC[7U] != NULL && pRMC[8U] != NULL && ::strlen(pRMC[7U]) > 0U && ::strlen(pRMC[8U]) > 0U) { - int bearing = ::atoi(pRMC[8U]); - int speed = ::atoi(pRMC[7U]); - - ::sprintf((char*)data + ::strlen((char*)data), "%03d/%03d", bearing, speed); - } - - return ::strlen((char*)data); } -void CAPRSCollector::dstarCallsignToAPRS(const std::string& dstarCallsign, char* aprsCallsign) const +unsigned int CAPRSCollector::getData(unsigned char dataType, unsigned char* data, unsigned int length) { - assert(aprsCallsign != NULL); - - std::string dstarcallsignTmp(dstarCallsign); - - if(dstarcallsignTmp[dstarcallsignTmp.length() - 1] == ' ') { - boost::trim(dstarcallsignTmp); - } else { - //loop until got rid of all double blanks - while(dstarcallsignTmp.find(" ") != std::string::npos) { - boost::replace_all(dstarcallsignTmp, " ", " "); + for(auto collector : m_collectors) { + if(collector->getDataType() == dataType) { + unsigned int res = collector->getData(data, length); + if(res > 0U) + return res; } - boost::replace_all(dstarcallsignTmp, " ", "-");//replace remaining blank with a - } - - unsigned int i = 0U; - for (; i < dstarcallsignTmp.length(); i++) { - aprsCallsign[i] = dstarcallsignTmp[i]; - } - aprsCallsign[i] = '\0'; - - - // std::string first = dstarCallsign.BeforeFirst(wxT(' ')); - // std::string last = dstarCallsign.AfterLast(wxT(' ')); - - // if (last.empty() || first == last) { - // unsigned int n = 0U; - // for (unsigned int i = 0U; i < first.length(); i++) - // aprsCallsign[n++] = first[i]; - // aprsCallsign[n++] = '\0'; - // } else { - // unsigned int n = 0U; - // for (unsigned int i = 0U; i < first.length(); i++) - // aprsCallsign[n++] = first[i]; - // aprsCallsign[n++] = '-'; - // for (unsigned int i = 0U; i < last.length(); i++) - // aprsCallsign[n++] = last[i]; - // aprsCallsign[n++] = '\0'; - // } -} - -// Source found at -char* CAPRSCollector::mystrsep(char** sp, const char* sep) const -{ - if (sp == NULL || *sp == NULL || **sp == '\0') - return NULL; - - char* s = *sp; - char* p = s + ::strcspn(s, sep); - - if (*p != '\0') - *p++ = '\0'; - - *sp = p; - - return s; + return 0U; } diff --git a/APRSCollector.h b/APRSCollector.h index ec44543..27d4eba 100644 --- a/APRSCollector.h +++ b/APRSCollector.h @@ -20,12 +20,16 @@ #ifndef APRSCollector_H #define APRSCollector_H +#include + +#include "SlowDataCollector.h" #include "Defs.h" enum APRS_STATE { AS_NONE, AS_GGA, AS_RMC, + AS_MSG, AS_CRC }; @@ -42,42 +46,10 @@ public: void sync(); - unsigned int getData(unsigned char* data, unsigned int length); + unsigned int getData(unsigned char dataType, unsigned char* data, unsigned int length); private: - APRS_STATE m_state; - unsigned char* m_ggaData; - unsigned int m_ggaLength; - bool m_ggaValid; - unsigned char* m_rmcData; - unsigned int m_rmcLength; - bool m_rmcValid; - unsigned char* m_crcData; - unsigned int m_crcLength; - bool m_crcValid; - unsigned char* m_buffer; - SLOWDATA_STATE m_slowData; - std::string m_collector; - std::string m_callsign; - - bool addGPSData(const unsigned char* data); - - void addGGAData(); - bool addRMCData(); - bool addCRCData(); - - bool checkXOR(const unsigned char* data, unsigned int length) const; - unsigned char calcXOR(const unsigned char* buffer, unsigned int length) const; - - bool checkCRC(const unsigned char* data, unsigned int length) const; - unsigned int calcCRC(const unsigned char* buffer, unsigned int length) const; - - unsigned int convertNMEA1(unsigned char* data, unsigned int length); - unsigned int convertNMEA2(unsigned char* data, unsigned int length); - - void dstarCallsignToAPRS(const std::string& dstarCallsign, char* aprsCallsign) const; - - char* mystrsep(char** sp, const char* sep) const; + std::vector m_collectors; }; #endif diff --git a/APRSWriter.cpp b/APRSWriter.cpp index 57ea6e8..9af5bc9 100644 --- a/APRSWriter.cpp +++ b/APRSWriter.cpp @@ -124,7 +124,7 @@ void CAPRSWriter::writeData(const std::string& callsign, const CAMBEData& data) return; } - unsigned int length = collector->getData(buffer, 400U); + unsigned int length = collector->getData(SLOW_DATA_TYPE_GPS, buffer, 400U); std::string text((char*)buffer, length); auto n = text.find(':'); diff --git a/DStarDefines.h b/DStarDefines.h index 1dcd22f..1af982c 100644 --- a/DStarDefines.h +++ b/DStarDefines.h @@ -85,6 +85,7 @@ const unsigned char SLOW_DATA_TYPE_MASK = 0xF0U; const unsigned char SLOW_DATA_TYPE_GPS = 0x30U; const unsigned char SLOW_DATA_TYPE_TEXT = 0x40U; const unsigned char SLOW_DATA_TYPE_HEADER = 0x50U; +const unsigned char SLOW_DATA_TYPE_MESSAGE = 0x40U; const unsigned char SLOW_DATA_TYPE_FAST_DATA1 = 0x80U; const unsigned char SLOW_DATA_TYPE_FAST_DATA2 = 0x90U; const unsigned char SLOW_DATA_TYPE_SQUELCH = 0xC0U; diff --git a/GPSACollector.cpp b/GPSACollector.cpp new file mode 100644 index 0000000..d6c7b3f --- /dev/null +++ b/GPSACollector.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2010,2012,2018 by Jonathan Naylor G4KLX + * 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 +#include +#include + +#include "GPSACollector.h" +#include "StringUtils.h" +#include "Log.h" + +const unsigned int APRS_CSUM_LENGTH = 4U; + +CGPSACollector::CGPSACollector() : +CSentenceCollector(SLOW_DATA_TYPE_GPS, "$$CRC", '\x0D') +{ + +} + +bool CGPSACollector::isValidSentence(const std::string& sentence) +{ + return isValidGPSA(sentence); +} + +bool CGPSACollector::isValidGPSA(const std::string& gpsa) +{ + if(gpsa.length() < 10U || !boost::starts_with(gpsa, "$$CRC")) + return false; + + auto csum = calcCRC(gpsa); + auto csumStr = CStringUtils::string_format("%04X", csum); + auto expectedCsum = gpsa.substr(5U, APRS_CSUM_LENGTH); + bool res = ::strcasecmp(csumStr.c_str(), expectedCsum.c_str()) == 0; + return res; +} + +unsigned int CGPSACollector::calcCRC(const std::string& gpsa) +{ + unsigned int icomcrc = 0xFFFFU; + + auto length = gpsa.length(); + for (unsigned int j = 10U; j < length; j++) { + unsigned char ch = (unsigned char)gpsa[j]; + + for (unsigned int i = 0U; i < 8U; i++) { + bool xorflag = (((icomcrc ^ ch) & 0x01U) == 0x01U); + + icomcrc >>= 1; + + if (xorflag) + icomcrc ^= 0x8408U; + + ch >>= 1; + } + } + + return ~icomcrc & 0xFFFFU; +} + +unsigned int CGPSACollector::getDataInt(unsigned char * data, unsigned int length) +{ + if(data == nullptr || length == 0U || getSentence().empty()) + return 0U; + + auto aprsFrame = getSentence(); + if(aprsFrame.length() < 11U) + return 0U; + + aprsFrame = aprsFrame.substr(10).append("\r\n"); + auto aprsFrameLen = aprsFrame.length(); + + if(length < aprsFrameLen) { + CLog::logDebug("Not enough space to copy GPS-A APRS frame"); + return 0U; + } + + for(unsigned int i = 0U; i < aprsFrameLen; i++){ + data[i] = aprsFrame[i]; + } + + return aprsFrameLen; +} \ No newline at end of file diff --git a/GPSACollector.h b/GPSACollector.h new file mode 100644 index 0000000..5663685 --- /dev/null +++ b/GPSACollector.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2010,2012,2018 by Jonathan Naylor G4KLX + * 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. + */ + +#pragma once + +/* + * Copyright (C) 2010,2012,2018 by Jonathan Naylor G4KLX + * 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. + */ + +#pragma once + +#include + +#include "SentenceCollector.h" + +class CGPSACollector : public CSentenceCollector +{ +public: + CGPSACollector(); + +protected: + unsigned int getDataInt(unsigned char * data, unsigned int length); + bool isValidSentence(const std::string& sentence); + +private: + static unsigned int calcCRC(const std::string& gpsa); + static bool isValidGPSA(const std::string& gpsa); + + std::string m_sentence; + std::string m_collector; + +}; \ No newline at end of file diff --git a/NMEASentenceCollector.cpp b/NMEASentenceCollector.cpp new file mode 100644 index 0000000..63d2087 --- /dev/null +++ b/NMEASentenceCollector.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2010,2012,2018 by Jonathan Naylor G4KLX + * 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 +#include +#include + +#include "NMEASentenceCollector.h" +#include "StringUtils.h" +#include "Log.h" + +CNMEASentenceCollector::CNMEASentenceCollector(const std::string& sentence) : +CSentenceCollector(SLOW_DATA_TYPE_GPS, sentence, '\x0A') +{ + +} + +bool CNMEASentenceCollector::isValidSentence(const std::string& sentence) +{ + return isValidNMEA(sentence); +} + +bool CNMEASentenceCollector::isValidNMEA(const std::string& nmea) +{ + if(nmea.empty() || nmea[0] != '$') + return false; + + auto posStar = nmea.find_last_of('*'); + if(posStar == 0U || posStar == std::string::npos) + return false; + + auto csum = calcXOR(nmea); + auto csumStr = CStringUtils::string_format("%02X", csum); + auto expctedCSumStr = nmea.substr(posStar + 1, 2U); + auto res = ::strcasecmp(expctedCSumStr.c_str(), csumStr.c_str()) == 0; + return res; +} + +unsigned char CNMEASentenceCollector::calcXOR(const std::string& nmea) +{ + unsigned char res = 0U; + + if(!nmea.empty()) { + unsigned int i = nmea[0] == '$' ? 1U : 0U; //skip $ it it is there + while(i < nmea.length()) + { + if(nmea[i] != '*') { + res ^= (unsigned char)nmea[i]; + } + else { + break; + } + i++; + } + } + + return res; +} + +unsigned int CNMEASentenceCollector::getDataInt(unsigned char * data, unsigned int length) +{ + if(data == nullptr || length == 0U || getMyCall().empty() || getSentence().empty()) + return 0U; + + auto nmea = getSentence(); + fixUpNMEATimeStamp(nmea); + + std::string fromCall = getMyCall(); + dstarCallsignToAPRS(fromCall); + std::string aprsFrame(fromCall); + aprsFrame.append("-5>GPS30,DSTAR*:") + .append(nmea) + .append("\r\n"); + + auto aprsFrameLen = aprsFrame.length(); + if(length < aprsFrameLen) { + CLog::logDebug("Not enough space to copy NMEA APRS frame"); + return 0U; + } + + for(unsigned int i = 0U; i < aprsFrameLen; i++){ + data[i] = aprsFrame[i]; + } + + return aprsFrameLen; +} + + +void CNMEASentenceCollector::dstarCallsignToAPRS(std::string& dstarCallsign) +{ + if(dstarCallsign[dstarCallsign.length() - 1] == ' ') { + boost::trim(dstarCallsign); + } else { + //loop until got rid of all double blanks + while(dstarCallsign.find(" ") != std::string::npos) { + boost::replace_all(dstarCallsign, " ", " "); + } + boost::replace_all(dstarCallsign, " ", "-");//replace remaining blank with a - + } +} + +// When set on manual position Icom radios send 000000.00 as NMEA timestamps +// this is a dirty hack to correct this issue. Actually I am not sure about APRS +// software being peeky about this except APRS.fi +void CNMEASentenceCollector::fixUpNMEATimeStamp(std::string& nmea) +{ + auto posStar = nmea.find_last_of('*'); + if(posStar != std::string::npos) + nmea = nmea.substr(0, posStar); + + time_t now; + ::time(&now); + struct tm* tm = ::gmtime(&now); + auto timeStamp = CStringUtils::string_format(",%02d%02d%02d.00,", tm->tm_hour, tm->tm_min, tm->tm_sec); + + boost::replace_all(nmea, ",000000.00,", timeStamp); + //recalculate checksum + nmea = CStringUtils::string_format("%s*%02x", nmea.c_str(), calcXOR(nmea)); +} \ No newline at end of file diff --git a/NMEASentenceCollector.h b/NMEASentenceCollector.h new file mode 100644 index 0000000..6368fb5 --- /dev/null +++ b/NMEASentenceCollector.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2010,2012,2018 by Jonathan Naylor G4KLX + * 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. + */ + +#pragma once + +#include + +#include "SentenceCollector.h" + +class CNMEASentenceCollector : public CSentenceCollector +{ +public: + CNMEASentenceCollector(const std::string& sentence); + +protected: + unsigned int getDataInt(unsigned char * data, unsigned int length); + bool isValidSentence(const std::string& sentence); + +private: + static void dstarCallsignToAPRS(std::string& call); + static bool isValidNMEA(const std::string& nmea); + static unsigned char calcXOR(const std::string& nmea); + static void fixUpNMEATimeStamp(std::string& nmea); +}; \ No newline at end of file diff --git a/SentenceCollector.cpp b/SentenceCollector.cpp new file mode 100644 index 0000000..551b7d7 --- /dev/null +++ b/SentenceCollector.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010,2012,2018 by Jonathan Naylor G4KLX + * 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 + +#include "SentenceCollector.h" + +CSentenceCollector::CSentenceCollector(unsigned char slowDataType, const std::string& sentenceIdentifier, unsigned char endMarker) : +CSlowDataCollector(slowDataType), +m_collector(), +m_sentenceIdentifier(sentenceIdentifier), +m_sentence(), +m_endMarker(endMarker) +{ + assert(!sentenceIdentifier.empty()); +} + +bool CSentenceCollector::addData(const unsigned char * data) +{ + m_collector.append(std::string((char*)data, 5U)); + + std::string::size_type n2 = m_collector.find_last_of(m_endMarker); + if (n2 == std::string::npos) + return false; + + std::string::size_type n1 = m_collector.find(m_sentenceIdentifier); + if (n1 == std::string::npos) + return false; + + if(n2 < n1) + return false; + + std::string sentence; + for(unsigned int i = n1; i <= n2; i++) { + sentence.push_back(m_collector[i] & 0x7FU); + } + + bool ret = isValidSentence(sentence); + if(ret) { + m_sentence = sentence; + } else { + m_sentence.clear(); + } + + m_collector = m_collector.substr(n2); + + return ret; +} + +std::string CSentenceCollector::getSentence() +{ + return m_sentence; +} + +void CSentenceCollector::resetInt() +{ + m_collector.clear(); + m_sentence.clear(); +} \ No newline at end of file diff --git a/SentenceCollector.h b/SentenceCollector.h new file mode 100644 index 0000000..d8a6c3d --- /dev/null +++ b/SentenceCollector.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010,2012,2018 by Jonathan Naylor G4KLX + * 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. + */ + +#pragma once + +#include + +#include "SlowDataCollector.h" + +class CSentenceCollector : public CSlowDataCollector +{ +public: + CSentenceCollector(unsigned char slowDataType, const std::string& sentenceIdentifier, unsigned char endMarker); + +protected: + bool addData(const unsigned char * data); + + virtual unsigned int getDataInt(unsigned char * data, unsigned int length) = 0; + static void dstarCallsignToAPRS(std::string& call); + std::string getSentence(); + +private: + virtual bool isValidSentence(const std::string& sentence) = 0; + virtual void resetInt(); + + std::string m_collector; + std::string m_sentenceIdentifier; + std::string m_sentence; + unsigned char m_endMarker; +}; \ No newline at end of file diff --git a/SlowDataCollector.cpp b/SlowDataCollector.cpp new file mode 100644 index 0000000..f23aa5c --- /dev/null +++ b/SlowDataCollector.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2010,2012,2018 by Jonathan Naylor G4KLX + * 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 +#include + +#include "SlowDataCollector.h" + +const unsigned int SLOW_DATA_BLOCK_LENGTH = 6U; + +CSlowDataCollector::CSlowDataCollector(unsigned char slowDataType) : +m_slowDataType(slowDataType), +m_myCall(), +m_state(SS_FIRST) +{ + m_buffer = new unsigned char[SLOW_DATA_BLOCK_LENGTH]; + std::memset(m_buffer, 0, SLOW_DATA_BLOCK_LENGTH); +} + +CSlowDataCollector::~CSlowDataCollector() +{ + delete[] m_buffer; +} + +std::string CSlowDataCollector::getMyCall() const +{ + return m_myCall; +} + +void CSlowDataCollector::setMyCall(const std::string& myCall) +{ + m_myCall = myCall; +} + +bool CSlowDataCollector::writeData(const unsigned char* data) +{ + assert(data != nullptr); + + switch (m_state) { + case SS_FIRST: + m_buffer[0U] = data[0U] ^ SCRAMBLER_BYTE1; + m_buffer[1U] = data[1U] ^ SCRAMBLER_BYTE2; + m_buffer[2U] = data[2U] ^ SCRAMBLER_BYTE3; + m_state = SS_SECOND; + return false; + + case SS_SECOND: + m_buffer[3U] = data[0U] ^ SCRAMBLER_BYTE1; + m_buffer[4U] = data[1U] ^ SCRAMBLER_BYTE2; + m_buffer[5U] = data[2U] ^ SCRAMBLER_BYTE3; + m_state = SS_FIRST; + break; + } + + if((m_buffer[0] & SLOW_DATA_TYPE_MASK) == m_slowDataType) + return addData(m_buffer + 1U); + + return false; +} + +void CSlowDataCollector::sync() +{ + m_state = SS_FIRST; +} + +unsigned int CSlowDataCollector::getData(unsigned char * data, unsigned int length) +{ + return getDataInt(data, length); +} + +void CSlowDataCollector::reset() +{ + m_state = SS_FIRST; + m_myCall.clear(); + resetInt(); +} + +unsigned char CSlowDataCollector::getDataType() +{ + return m_slowDataType; +} \ No newline at end of file diff --git a/SlowDataCollector.h b/SlowDataCollector.h new file mode 100644 index 0000000..03d4de1 --- /dev/null +++ b/SlowDataCollector.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010,2012,2018 by Jonathan Naylor G4KLX + * 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. + */ + +#pragma once + +#include + +#include "DStarDefines.h" +#include "Defs.h" + +class CSlowDataCollector +{ +public: + CSlowDataCollector(unsigned char slowDataType); + virtual ~CSlowDataCollector(); + + std::string getMyCall() const; + void setMyCall(const std::string& mycall); + bool writeData(const unsigned char* data); + void sync(); + unsigned int getData(unsigned char* data, unsigned int length); + void reset(); + unsigned char getDataType(); + +protected: + virtual bool addData(const unsigned char* data) = 0; + virtual unsigned int getDataInt(unsigned char* data, unsigned int length) = 0; + virtual void resetInt() { } + +private: + unsigned char m_slowDataType; + std::string m_myCall; + SLOWDATA_STATE m_state; + unsigned char * m_buffer; +}; \ No newline at end of file From 4b479f040fe1981e9db0b083bc91c2affc2caa16 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 17:29:09 +0100 Subject: [PATCH 017/201] Remove duplicate copyright --- GPSACollector.h | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/GPSACollector.h b/GPSACollector.h index 5663685..056c0ba 100644 --- a/GPSACollector.h +++ b/GPSACollector.h @@ -19,27 +19,6 @@ #pragma once -/* - * Copyright (C) 2010,2012,2018 by Jonathan Naylor G4KLX - * 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. - */ - -#pragma once - #include #include "SentenceCollector.h" From 431b84e189a1331103ee5bea8f74f0c2651622fb Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 21:24:41 +0100 Subject: [PATCH 018/201] #9 there is no message type, msg uses gps type --- DStarDefines.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/DStarDefines.h b/DStarDefines.h index 1af982c..b4ed991 100644 --- a/DStarDefines.h +++ b/DStarDefines.h @@ -81,15 +81,14 @@ const unsigned int DATA_BLOCK_SIZE_BYTES = 21U * DV_FRAME_LENGTH_BYTES; const unsigned int LONG_CALLSIGN_LENGTH = 8U; const unsigned int SHORT_CALLSIGN_LENGTH = 4U; -const unsigned char SLOW_DATA_TYPE_MASK = 0xF0U; -const unsigned char SLOW_DATA_TYPE_GPS = 0x30U; -const unsigned char SLOW_DATA_TYPE_TEXT = 0x40U; -const unsigned char SLOW_DATA_TYPE_HEADER = 0x50U; -const unsigned char SLOW_DATA_TYPE_MESSAGE = 0x40U; -const unsigned char SLOW_DATA_TYPE_FAST_DATA1 = 0x80U; -const unsigned char SLOW_DATA_TYPE_FAST_DATA2 = 0x90U; -const unsigned char SLOW_DATA_TYPE_SQUELCH = 0xC0U; -const unsigned char SLOW_DATA_LENGTH_MASK = 0x0FU; +const unsigned char SLOW_DATA_TYPE_MASK = 0xF0U; +const unsigned char SLOW_DATA_TYPE_GPS = 0x30U; +const unsigned char SLOW_DATA_TYPE_TEXT = 0x40U; +const unsigned char SLOW_DATA_TYPE_HEADER = 0x50U; +const unsigned char SLOW_DATA_TYPE_FAST_DATA1 = 0x80U; +const unsigned char SLOW_DATA_TYPE_FAST_DATA2 = 0x90U; +const unsigned char SLOW_DATA_TYPE_SQUELCH = 0xC0U; +const unsigned char SLOW_DATA_LENGTH_MASK = 0x0FU; const unsigned char DATA_MASK = 0x80U; const unsigned char REPEATER_MASK = 0x40U; From c9e06d3404b66655c7c7de5898604ff979de500e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 21:26:02 +0100 Subject: [PATCH 019/201] #9 correct (c) and add find_nth --- StringUtils.cpp | 35 +++++++++++++++++++++++++++++++++++ StringUtils.h | 6 +++--- 2 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 StringUtils.cpp diff --git a/StringUtils.cpp b/StringUtils.cpp new file mode 100644 index 0000000..5586ef3 --- /dev/null +++ b/StringUtils.cpp @@ -0,0 +1,35 @@ +/* + * 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 "StringUtils.h" + +size_t CStringUtils::find_nth(const std::string& haystack, size_t pos, char needle, size_t nth) +{ + size_t matches = 0U; + auto haystackLength = haystack.length(); + + for(size_t i = 0; i < haystackLength; i++) { + if(haystack[i] == needle) { + matches++; + if(matches == nth) + return i; + } + } + + return std::string::npos; +} \ No newline at end of file diff --git a/StringUtils.h b/StringUtils.h index 2dadc82..c759df2 100644 --- a/StringUtils.h +++ b/StringUtils.h @@ -1,7 +1,5 @@ /* - * Copyright (C) 2009-2011,2013 by Jonathan Naylor G4KLX - * Copyright (c) 2017 by Thomas A. Early N7TAE - * Copyright (c) 2021 by Geoffrey Merck F4FXL / KC3FRA + * 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 @@ -38,4 +36,6 @@ public: std::snprintf( buf.get(), size, format.c_str(), args ... ); return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside } + + static size_t find_nth(const std::string& haystack, size_t pos, char needle, size_t nth); }; From bd3b8650c41d3537c2af1d2d32dcb5b9f2a1a754 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 21:28:55 +0100 Subject: [PATCH 020/201] #9 First working proof of concept, msg dstar-> --- APRSCollector.cpp | 2 + APRSUtils.cpp | 34 +++++++++ APRSUtils.h | 27 +++++++ NMEASentenceCollector.cpp | 17 +---- RSMS1AMessageCollector.cpp | 141 +++++++++++++++++++++++++++++++++++++ RSMS1AMessageCollector.h | 42 +++++++++++ SlowDataCollector.cpp | 19 +++++ 7 files changed, 267 insertions(+), 15 deletions(-) create mode 100644 APRSUtils.cpp create mode 100644 APRSUtils.h create mode 100644 RSMS1AMessageCollector.cpp create mode 100644 RSMS1AMessageCollector.h diff --git a/APRSCollector.cpp b/APRSCollector.cpp index 92284e0..9f10a18 100644 --- a/APRSCollector.cpp +++ b/APRSCollector.cpp @@ -27,6 +27,7 @@ #include "Utils.h" #include "NMEASentenceCollector.h" #include "GPSACollector.h" +#include "RSMS1AMessageCollector.h" const unsigned int APRS_CSUM_LENGTH = 4U; const unsigned int APRS_DATA_LENGTH = 300U; @@ -38,6 +39,7 @@ const char APRS_SYMBOL = 'K'; CAPRSCollector::CAPRSCollector() : m_collectors() { + m_collectors.push_back(new CRSMS1AMessageCollector()); m_collectors.push_back(new CGPSACollector()); m_collectors.push_back(new CNMEASentenceCollector("$GPRMC")); m_collectors.push_back(new CNMEASentenceCollector("$GPGGA")); diff --git a/APRSUtils.cpp b/APRSUtils.cpp new file mode 100644 index 0000000..3d0839d --- /dev/null +++ b/APRSUtils.cpp @@ -0,0 +1,34 @@ +/* + * 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 + +#include "APRSUtils.h" + +void CAPRSUtils::dstarCallsignToAPRS(std::string& dstarCallsign) +{ + if(dstarCallsign[dstarCallsign.length() - 1] == ' ') { + boost::trim(dstarCallsign); + } else { + //loop until got rid of all double blanks + while(dstarCallsign.find(" ") != std::string::npos) { + boost::replace_all(dstarCallsign, " ", " "); + } + boost::replace_all(dstarCallsign, " ", "-");//replace remaining blank with a - + } +} \ No newline at end of file diff --git a/APRSUtils.h b/APRSUtils.h new file mode 100644 index 0000000..2ad53d3 --- /dev/null +++ b/APRSUtils.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#pragma once + +#include + +class CAPRSUtils +{ +public: + static void dstarCallsignToAPRS(std::string& dstarCallsign); +}; \ No newline at end of file diff --git a/NMEASentenceCollector.cpp b/NMEASentenceCollector.cpp index 63d2087..2685625 100644 --- a/NMEASentenceCollector.cpp +++ b/NMEASentenceCollector.cpp @@ -24,6 +24,7 @@ #include "NMEASentenceCollector.h" #include "StringUtils.h" #include "Log.h" +#include "APRSUtils.h" CNMEASentenceCollector::CNMEASentenceCollector(const std::string& sentence) : CSentenceCollector(SLOW_DATA_TYPE_GPS, sentence, '\x0A') @@ -82,7 +83,7 @@ unsigned int CNMEASentenceCollector::getDataInt(unsigned char * data, unsigned i fixUpNMEATimeStamp(nmea); std::string fromCall = getMyCall(); - dstarCallsignToAPRS(fromCall); + CAPRSUtils::dstarCallsignToAPRS(fromCall); std::string aprsFrame(fromCall); aprsFrame.append("-5>GPS30,DSTAR*:") .append(nmea) @@ -101,20 +102,6 @@ unsigned int CNMEASentenceCollector::getDataInt(unsigned char * data, unsigned i return aprsFrameLen; } - -void CNMEASentenceCollector::dstarCallsignToAPRS(std::string& dstarCallsign) -{ - if(dstarCallsign[dstarCallsign.length() - 1] == ' ') { - boost::trim(dstarCallsign); - } else { - //loop until got rid of all double blanks - while(dstarCallsign.find(" ") != std::string::npos) { - boost::replace_all(dstarCallsign, " ", " "); - } - boost::replace_all(dstarCallsign, " ", "-");//replace remaining blank with a - - } -} - // When set on manual position Icom radios send 000000.00 as NMEA timestamps // this is a dirty hack to correct this issue. Actually I am not sure about APRS // software being peeky about this except APRS.fi diff --git a/RSMS1AMessageCollector.cpp b/RSMS1AMessageCollector.cpp new file mode 100644 index 0000000..398cc47 --- /dev/null +++ b/RSMS1AMessageCollector.cpp @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2010,2012,2018 by Jonathan Naylor G4KLX + * 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 +#include +#include +#include + +#include "RSMS1AMessageCollector.h" +#include "StringUtils.h" +#include "Log.h" +#include "Utils.h" +#include "APRSUtils.h" + +const unsigned int APRS_CSUM_LENGTH = 4U; + +CRSMS1AMessageCollector::CRSMS1AMessageCollector() : +CSentenceCollector(SLOW_DATA_TYPE_GPS, "$$Msg", '\x0D') +{ + +} + +bool CRSMS1AMessageCollector::isValidSentence(const std::string& sentence) +{ + return isValidGPSA(sentence); +} + +bool CRSMS1AMessageCollector::isValidGPSA(const std::string& msg) +{ + if(msg.empty() || !boost::starts_with(msg, "$$Msg")) + return false; + + std::vector splits; + boost::split(splits, msg, boost::is_any_of(",")); + + bool ret = splits.size() == 4 + && !splits[1].empty() + && !splits[2].empty() + && splits[3].length() > 6U; + return ret; + + // CUtils::dump("RS-MS1A:", (unsigned char *)gpsa.c_str(), gpsa.length() + 1U); + // CLog::logDebug("RS-MS1A: %s", gpsa.c_str()); + + // auto thirdCommaPos = CStringUtils::find_nth(gpsa, 0U, ',', 3); + // auto csum = calcCRC(gpsa, thirdCommaPos + 6 + 1, gpsa.length() - thirdCommaPos - 2U - 6U); + // auto csumStr = CStringUtils::string_format("%06X", csum); + // CLog::logDebug("RS-MS1A CRC: %s", csumStr.c_str()); + + // auto expectedCsum = gpsa.substr(5U, APRS_CSUM_LENGTH); + // bool res = ::strcasecmp(csumStr.c_str(), expectedCsum.c_str()) == 0; + // return res; +} + +unsigned int CRSMS1AMessageCollector::calcCRC(const std::string& gpsa, unsigned int start, unsigned int length) +{ + unsigned int icomcrc = 0xFFFFU; + auto end = start + length; + if(end > gpsa.length()) { + end = gpsa.length(); + } + + for (unsigned int j = start; j < end; j++) { + unsigned char ch = (unsigned char)gpsa[j]; + + for (unsigned int i = 0U; i < 8U; i++) { + bool xorflag = (((icomcrc ^ ch) & 0x01U) == 0x01U); + + icomcrc >>= 1; + + if (xorflag) + icomcrc ^= 0x8408U; + + ch >>= 1; + } + } + + return ~icomcrc & 0xFFFFU; +} + +unsigned int CRSMS1AMessageCollector::getDataInt(unsigned char * data, unsigned int length) +{ + if(data == nullptr || length == 0U || getSentence().empty()) + return 0U; + + auto sentence = getSentence(); + + std::vector splits; + boost::split(splits, sentence, boost::is_any_of(",")); + + bool ret = splits.size() == 4 + && !splits[1].empty() + && !splits[2].empty() + && splits[3].length() > 6U; + if(!ret) { + return 0U; + } + + auto sender = splits[1]; + auto recipient = CUtils::ToUpper(splits[2]); + auto message = splits[3].substr(6, splits[3].length() - 2); + + CAPRSUtils::dstarCallsignToAPRS(sender); + CAPRSUtils::dstarCallsignToAPRS(recipient); + recipient.resize(9, ' '); + + //unescape commas in message body + boost::replace_all(message, "o,", ","); + + auto aprsFrame = CStringUtils::string_format("%s-5>APDPRS,DSTAR*::%s:%s\r\n", sender.c_str(), recipient.c_str(), message.c_str()); + + auto aprsFrameLen = aprsFrame.length(); + + if(length < aprsFrameLen) { + CLog::logDebug("Not enough space to copy GPS-A APRS frame"); + return 0U; + } + + for(unsigned int i = 0U; i < aprsFrameLen; i++){ + data[i] = aprsFrame[i]; + } + + return aprsFrameLen; +} \ No newline at end of file diff --git a/RSMS1AMessageCollector.h b/RSMS1AMessageCollector.h new file mode 100644 index 0000000..359eaab --- /dev/null +++ b/RSMS1AMessageCollector.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2010,2012,2018 by Jonathan Naylor G4KLX + * 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. + */ + +#pragma once + +#include + +#include "SentenceCollector.h" + +class CRSMS1AMessageCollector : public CSentenceCollector +{ +public: + CRSMS1AMessageCollector(); + +protected: + unsigned int getDataInt(unsigned char * data, unsigned int length); + bool isValidSentence(const std::string& sentence); + +private: + static unsigned int calcCRC(const std::string& gpsa, unsigned int start, unsigned int length); + static bool isValidGPSA(const std::string& gpsa); + + std::string m_sentence; + std::string m_collector; + +}; \ No newline at end of file diff --git a/SlowDataCollector.cpp b/SlowDataCollector.cpp index f23aa5c..b651ae7 100644 --- a/SlowDataCollector.cpp +++ b/SlowDataCollector.cpp @@ -21,6 +21,7 @@ #include #include "SlowDataCollector.h" +#include "Log.h" const unsigned int SLOW_DATA_BLOCK_LENGTH = 6U; @@ -68,6 +69,24 @@ bool CSlowDataCollector::writeData(const unsigned char* data) break; } + // unsigned char rxDataType = (m_buffer[0] & SLOW_DATA_TYPE_MASK); + + // switch (rxDataType) + // { + // case SLOW_DATA_TYPE_MASK: CLog::logDebug("SLOW_DATA_TYPE_MASK "); break; + // case SLOW_DATA_TYPE_GPS: CLog::logDebug("SLOW_DATA_TYPE_GPS "); break; + // case SLOW_DATA_TYPE_TEXT: CLog::logDebug("SLOW_DATA_TYPE_TEXT "); break; + // case SLOW_DATA_TYPE_HEADER: CLog::logDebug("SLOW_DATA_TYPE_HEADER "); break; + // case SLOW_DATA_TYPE_MESSAGE: CLog::logDebug("SLOW_DATA_TYPE_MESSAGE "); break; + // case SLOW_DATA_TYPE_FAST_DATA1: CLog::logDebug("SLOW_DATA_TYPE_FAST_DATA1 "); break; + // case SLOW_DATA_TYPE_FAST_DATA2: CLog::logDebug("SLOW_DATA_TYPE_FAST_DATA2 "); break; + // case SLOW_DATA_TYPE_SQUELCH: CLog::logDebug("SLOW_DATA_TYPE_SQUELCH "); break; + // case SLOW_DATA_LENGTH_MASK: CLog::logDebug("SLOW_DATA_LENGTH_MASK "); break; + // default: + // CLog::logDebug("!!!!!!!!!!!!!!! %X", rxDataType); + // break; + // }; + if((m_buffer[0] & SLOW_DATA_TYPE_MASK) == m_slowDataType) return addData(m_buffer + 1U); From bdb4c638b1e2228bf57eb719aa3cb4313a95e603 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 21:46:23 +0100 Subject: [PATCH 021/201] #9 fix function naming --- RSMS1AMessageCollector.cpp | 9 +++++++-- RSMS1AMessageCollector.h | 3 +-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/RSMS1AMessageCollector.cpp b/RSMS1AMessageCollector.cpp index 398cc47..88ce3f6 100644 --- a/RSMS1AMessageCollector.cpp +++ b/RSMS1AMessageCollector.cpp @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include "RSMS1AMessageCollector.h" #include "StringUtils.h" @@ -29,6 +31,7 @@ #include "Utils.h" #include "APRSUtils.h" + const unsigned int APRS_CSUM_LENGTH = 4U; CRSMS1AMessageCollector::CRSMS1AMessageCollector() : @@ -39,10 +42,10 @@ CSentenceCollector(SLOW_DATA_TYPE_GPS, "$$Msg", '\x0D') bool CRSMS1AMessageCollector::isValidSentence(const std::string& sentence) { - return isValidGPSA(sentence); + return isValidMsg(sentence); } -bool CRSMS1AMessageCollector::isValidGPSA(const std::string& msg) +bool CRSMS1AMessageCollector::isValidMsg(const std::string& msg) { if(msg.empty() || !boost::starts_with(msg, "$$Msg")) return false; @@ -56,6 +59,8 @@ bool CRSMS1AMessageCollector::isValidGPSA(const std::string& msg) && splits[3].length() > 6U; return ret; + //TODO 2022-01-01 figure out what the heck it is about thic strange CRCs + // CUtils::dump("RS-MS1A:", (unsigned char *)gpsa.c_str(), gpsa.length() + 1U); // CLog::logDebug("RS-MS1A: %s", gpsa.c_str()); diff --git a/RSMS1AMessageCollector.h b/RSMS1AMessageCollector.h index 359eaab..c7bbe24 100644 --- a/RSMS1AMessageCollector.h +++ b/RSMS1AMessageCollector.h @@ -34,9 +34,8 @@ protected: private: static unsigned int calcCRC(const std::string& gpsa, unsigned int start, unsigned int length); - static bool isValidGPSA(const std::string& gpsa); + static bool isValidMsg(const std::string& gpsa); std::string m_sentence; std::string m_collector; - }; \ No newline at end of file From a4702b995658f89777e7819e095d1f39af77f707 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 23:04:57 +0100 Subject: [PATCH 022/201] #9 Do not splitt message body when it has commas --- RSMS1AMessageCollector.cpp | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/RSMS1AMessageCollector.cpp b/RSMS1AMessageCollector.cpp index 88ce3f6..f9cafe6 100644 --- a/RSMS1AMessageCollector.cpp +++ b/RSMS1AMessageCollector.cpp @@ -50,13 +50,13 @@ bool CRSMS1AMessageCollector::isValidMsg(const std::string& msg) if(msg.empty() || !boost::starts_with(msg, "$$Msg")) return false; + // CUtils::dump("RS-MS1A:", (unsigned char *)msg.c_str(), msg.length()); std::vector splits; boost::split(splits, msg, boost::is_any_of(",")); - bool ret = splits.size() == 4 + bool ret = splits.size() >= 4 && !splits[1].empty() - && !splits[2].empty() - && splits[3].length() > 6U; + && !splits[2].empty(); return ret; //TODO 2022-01-01 figure out what the heck it is about thic strange CRCs @@ -110,26 +110,35 @@ unsigned int CRSMS1AMessageCollector::getDataInt(unsigned char * data, unsigned std::vector splits; boost::split(splits, sentence, boost::is_any_of(",")); - bool ret = splits.size() == 4 + bool ret = splits.size() >= 4 && !splits[1].empty() - && !splits[2].empty() - && splits[3].length() > 6U; + && !splits[2].empty(); if(!ret) { return 0U; } auto sender = splits[1]; auto recipient = CUtils::ToUpper(splits[2]); - auto message = splits[3].substr(6, splits[3].length() - 2); + + for(unsigned int i = 0;i < 3; i++) { + splits.erase(splits.begin()); + } + + auto message = boost::join(splits, ","); + if(message.length() > 6) + message = message.substr(6); + + auto seqNum = rand() % 0xFFFFFU; CAPRSUtils::dstarCallsignToAPRS(sender); CAPRSUtils::dstarCallsignToAPRS(recipient); recipient.resize(9, ' '); + message.resize(std::max(0 , ((int)message.length()) - 2)); //unescape commas in message body boost::replace_all(message, "o,", ","); - auto aprsFrame = CStringUtils::string_format("%s-5>APDPRS,DSTAR*::%s:%s\r\n", sender.c_str(), recipient.c_str(), message.c_str()); + auto aprsFrame = CStringUtils::string_format("%s-5>APDPRS,DSTAR*::%s:%s{%05X\r\n", sender.c_str(), recipient.c_str(), message.c_str(), seqNum); auto aprsFrameLen = aprsFrame.length(); From da45d7dc80a5d544f3159e87c40fea388c70690e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 23:08:26 +0100 Subject: [PATCH 023/201] #9 Add some logging from incoming aprs-is frames --- APRSWriterThread.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/APRSWriterThread.cpp b/APRSWriterThread.cpp index fe27a9b..796054c 100644 --- a/APRSWriterThread.cpp +++ b/APRSWriterThread.cpp @@ -159,10 +159,12 @@ void* CAPRSWriterThread::Entry() startReconnectionTimer(); } + if(line.length() > 0 && line[0] != '#') + CLog::logDebug("Received APRS Frame : %s", line.c_str()); + if(length > 0 && line[0] != '#'//check if we have something and if that something is an APRS frame && m_APRSReadCallback != NULL)//do we have someone wanting an APRS Frame? { - //CLog::logInfo("Received APRS Frame : ") + line); m_APRSReadCallback(std::string(line)); } } From 02a1f5dd89e73f45b426559d188821d2dcc41b08 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 1 Jan 2022 23:23:36 +0100 Subject: [PATCH 024/201] Removed unused param --- StringUtils.cpp | 2 +- StringUtils.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/StringUtils.cpp b/StringUtils.cpp index 5586ef3..63de202 100644 --- a/StringUtils.cpp +++ b/StringUtils.cpp @@ -18,7 +18,7 @@ #include "StringUtils.h" -size_t CStringUtils::find_nth(const std::string& haystack, size_t pos, char needle, size_t nth) +size_t CStringUtils::find_nth(const std::string& haystack, char needle, size_t nth) { size_t matches = 0U; auto haystackLength = haystack.length(); diff --git a/StringUtils.h b/StringUtils.h index c759df2..e0dbac2 100644 --- a/StringUtils.h +++ b/StringUtils.h @@ -37,5 +37,5 @@ public: return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside } - static size_t find_nth(const std::string& haystack, size_t pos, char needle, size_t nth); + static size_t find_nth(const std::string& haystack, char needle, size_t nth); }; From 0914d3145d288fb75e276d7ed9295b9689b264e6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 09:50:51 +0100 Subject: [PATCH 025/201] #10 get rid of slow stringstream and add in place formating of string --- Log.h | 35 ++++++++++++++++++----------------- StringUtils.h | 13 ++++++++++++- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/Log.h b/Log.h index 26414c8..56a7c4c 100644 --- a/Log.h +++ b/Log.h @@ -19,11 +19,11 @@ #pragma once +#include #include #include #include #include -#include #include #include "StringUtils.h" @@ -36,45 +36,46 @@ private: static bool m_addedTargets; static std::recursive_mutex m_targetsMutex; - static void getTimeStamp(std::string & s); + static void getTimeStamp(std::string& s); - template static void formatLogMessage(std::string& output, LOG_SEVERITY severity, const std::string & f, Args... args) + template + static void formatLogMessage(std::string& output, LOG_SEVERITY severity, const std::string & f, Args... args) { assert(severity != LOG_NONE); - std::string severityStr; + std::string severityStr(" "); switch (severity) { case LOG_DEBUG: - severityStr = "DEBUG "; + severityStr.assign("DEBUG "); break; case LOG_ERROR: - severityStr = "ERROR "; + severityStr.assign("ERROR "); break; case LOG_FATAL: - severityStr = "FATAL "; + severityStr.assign("FATAL "); break; case LOG_INFO : - severityStr = "INFO "; + severityStr.assign("INFO "); break; case LOG_WARNING: - severityStr = "WARNING"; + severityStr.assign("WARNING"); break; case LOG_TRACE: - severityStr = "TRACE "; + severityStr.assign("TRACE "); break; default: break; } - std::string message = CStringUtils::string_format(f, args...); - boost::trim(message); - std::string timeUtc; - getTimeStamp(timeUtc); - std::stringstream s; - s << "[" << timeUtc << "] [" << severityStr << "] " << message << std::endl; + std::string timestamp; + getTimeStamp(timestamp); - output = s.str(); + std::string f2("[%s] [%s] "); + f2.append(f); + CStringUtils::string_format_in_place(output, f2, timestamp.c_str(), severityStr.c_str(), args...); + boost::trim_if(output, [](char c){ return c == '\n' || c == '\r' || c == ' ' || c == '\t'; }); + output.push_back('\n'); } public: diff --git a/StringUtils.h b/StringUtils.h index 2dadc82..3f8faef 100644 --- a/StringUtils.h +++ b/StringUtils.h @@ -30,12 +30,23 @@ class CStringUtils { public: template static std::string string_format( const std::string& format, Args ... args ) + { + std::string ret; + string_format_in_place(ret, format, args...); + return ret; + } + + template + static void string_format_in_place(std::string& output, const std::string& format, Args ... args ) { int size_s = std::snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0' if( size_s <= 0 ){ throw std::runtime_error( "Error during formatting." ); } + auto size = static_cast( size_s ); auto buf = std::make_unique( size ); std::snprintf( buf.get(), size, format.c_str(), args ... ); - return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside + + output.reserve(size); + output.assign(buf.get(), size - 1); // -1 because we do not need trailing '\0' } }; From b696b92da452bbe496802b9f2781300a6225bbb2 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 10:50:08 +0100 Subject: [PATCH 026/201] #10 Keep log file open --- LogFileTarget.cpp | 81 ++++++++++++++++++++++++++++++++++++----------- LogFileTarget.h | 7 ++++ 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/LogFileTarget.cpp b/LogFileTarget.cpp index a44dd35..f40dc3c 100644 --- a/LogFileTarget.cpp +++ b/LogFileTarget.cpp @@ -24,34 +24,79 @@ #include "LogFileTarget.h" +#define LOG_FILE_ROOT "dstargateway" + CLogFileTarget::CLogFileTarget(LOG_SEVERITY logLevel, const std::string & dir, bool rotate) : CLogTarget(logLevel), m_dir(dir), -m_rotate(rotate) +m_rotate(rotate), +m_file(), +m_day(0) { } -void CLogFileTarget::printLogInt(const std::string& msg) +CLogFileTarget::~CLogFileTarget() +{ + if(m_file.is_open()) { + m_file.close(); + } +} + +void CLogFileTarget::printLogIntFixed(const std::string& msg) +{ + if(m_file.is_open()) { + m_file << msg; + m_file.flush(); + return; + } + + std::string filename(m_dir); + if(filename[filename.length() - 1U] != '/') filename.push_back('/'); + filename.append(LOG_FILE_ROOT).append(".log"); + m_file.open(filename, std::ios::app); + + if(m_file.is_open()) { + printLogIntFixed(msg); + } + else { + std::cerr << "FAILED TO OPEN LOG FILE :" << filename; + } +} + +void CLogFileTarget::printLogIntRotate(const std::string& msg) { - // construct filename - std::string fileName(m_dir); - if(fileName[fileName.length() - 1U] != '/') fileName.push_back('/'); - fileName.append("dstargateway"); - - if(m_rotate) { - std::time_t now = std::time(0); - std::tm* now_tm = std::gmtime(&now); + std::time_t now = std::time(0); + std::tm* now_tm = std::gmtime(&now); + if(now_tm->tm_yday != m_day) { + m_day = now_tm->tm_yday; + if(m_file.is_open()) { + m_file.close(); + } + } + + if(!m_file.is_open()) { + std::string filename(m_dir); + if(filename[filename.length() - 1U] != '/') filename.push_back('/'); char buf[64]; std::strftime(buf, 42, "-%Y-%m-%d", now_tm); - fileName.append(std::string(buf)); + filename.append(LOG_FILE_ROOT).append(buf).append(".log"); + m_file.open(filename, std::ios::app); + if(!m_file.is_open()) { + std::cerr << "FAILED TO OPEN LOG FILE :" << filename; + } } - fileName.append(".log"); - std::ofstream file; - file.open(fileName, std::ios::app); - if(file.is_open()) { - file << msg; - file.close(); + if(m_file.is_open()) { + m_file << msg; + m_file.flush(); + return; } -} \ No newline at end of file +} +void CLogFileTarget::printLogInt(const std::string& msg) +{ + if(m_rotate) + printLogIntRotate(msg); + else + printLogIntFixed(msg); +} diff --git a/LogFileTarget.h b/LogFileTarget.h index 2a8ad1d..8df8c8b 100644 --- a/LogFileTarget.h +++ b/LogFileTarget.h @@ -19,6 +19,7 @@ #pragma once #include +#include #include "LogTarget.h" @@ -26,11 +27,17 @@ class CLogFileTarget : public CLogTarget { public: CLogFileTarget(LOG_SEVERITY logLevel, const std::string& directory, bool rotate); + ~CLogFileTarget(); protected: virtual void printLogInt(const std::string& msg); private: + void printLogIntRotate(const std::string& msg); + void printLogIntFixed(const std::string& msg); + std::string buildFileName(); std::string m_dir; bool m_rotate; + std::fstream m_file; + int m_day; }; \ No newline at end of file From 57b9bf828830e3ea97da611456b370a92673d346 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 14:55:33 +0100 Subject: [PATCH 027/201] Add .circleci/config.yml --- .circleci/config.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..89aa5dd --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,26 @@ +# Use the latest 2.1 version of CircleCI pipeline process engine. +# See: https://circleci.com/docs/2.0/configuration-reference +version: 2.1 + +# Define a job to be invoked later in a workflow. +# See: https://circleci.com/docs/2.0/configuration-reference/#jobs +jobs: + build-dstargateway: + # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. + # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor + docker: + - image: cimg/base:stable + # Add steps to the job + # See: https://circleci.com/docs/2.0/configuration-reference/#steps + steps: + - checkout + - run: + name: "make" + command: "make" + +# Invoke jobs via workflows +# See: https://circleci.com/docs/2.0/configuration-reference/#workflows +workflows: + dstar-gateway-workflow: + jobs: + - build-dstargateway From 9e7705b9403fbeae03209548d5ee94b3b43f31b6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 17:00:49 +0100 Subject: [PATCH 028/201] Updated config.yml --- .circleci/config.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 89aa5dd..5569809 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -15,7 +15,10 @@ jobs: steps: - checkout - run: - name: "make" + name: Install dependencies + command: sudo apt-get install libcurl4-openssl-dev libboost-dev + - run: + name: "Build" command: "make" # Invoke jobs via workflows From fc6ae1ba547be22c0ebea1e43122c4bf61694f1f Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 17:04:08 +0100 Subject: [PATCH 029/201] Updated config.yml --- .circleci/config.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 5569809..7f005cf 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -16,7 +16,9 @@ jobs: - checkout - run: name: Install dependencies - command: sudo apt-get install libcurl4-openssl-dev libboost-dev + command: | + sudo apt-get update + sudo apt-get install libcurl4-openssl-dev libboost-dev - run: name: "Build" command: "make" From 38b4d1eb26302f536188f5d6323fa02a94c73c13 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 17:16:04 +0100 Subject: [PATCH 030/201] Add some parallel to cicrcle ci --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7f005cf..4d5f364 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,7 +21,7 @@ jobs: sudo apt-get install libcurl4-openssl-dev libboost-dev - run: name: "Build" - command: "make" + command: "make -J 3" # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows From c870c748632dca18e95de46b9bfcba8caa387c16 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 17:17:15 +0100 Subject: [PATCH 031/201] Correct typo --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4d5f364..78a8970 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,7 +21,7 @@ jobs: sudo apt-get install libcurl4-openssl-dev libboost-dev - run: name: "Build" - command: "make -J 3" + command: "make -j 3" # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows From 1a0306ddf4121c333bb0e31b10844c8431a0b18e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 17:28:11 +0100 Subject: [PATCH 032/201] Start of APRS parsing for incoming messages --- APRSFrame.h | 36 +++++++++++++++++++++++++ APRSParser.cpp | 58 +++++++++++++++++++++++++++++++++++++++++ APRSParser.h | 31 ++++++++++++++++++++++ APRSReader.cpp | 32 +++++++++++++++++++++++ APRSReader.h | 33 +++++++++++++++++++++++ APRSWriterThread.cpp | 26 +++++++++++++----- APRSWriterThread.h | 8 +++--- ReadAPRSFrameCallback.h | 28 ++++++++++++++++++++ 8 files changed, 243 insertions(+), 9 deletions(-) create mode 100644 APRSFrame.h create mode 100644 APRSParser.cpp create mode 100644 APRSParser.h create mode 100644 APRSReader.cpp create mode 100644 APRSReader.h create mode 100644 ReadAPRSFrameCallback.h diff --git a/APRSFrame.h b/APRSFrame.h new file mode 100644 index 0000000..39494eb --- /dev/null +++ b/APRSFrame.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +// We only support these types for now +enum APRS_FRAME_TYPE { + APFT_UNKNOWN = 0, + APFT_MESSAGE, +}; + +typedef struct { + std::string m_source; + std::string m_dest; + std::vector m_path; + std::string m_body; + APRS_FRAME_TYPE m_type; +} TAPRSFrame; \ No newline at end of file diff --git a/APRSParser.cpp b/APRSParser.cpp new file mode 100644 index 0000000..d3ed20d --- /dev/null +++ b/APRSParser.cpp @@ -0,0 +1,58 @@ +/* + * 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 "APRSParser.h" + +bool CAPRSParser::parseFrame(const std::string& frameStr, TAPRSFrame& frame) +{ + frame.m_body.clear(); + frame.m_dest.clear(); + frame.m_path.clear(); + frame.m_source.clear(); + frame.m_type = APFT_UNKNOWN; + + if(!frameStr.empty()) + return false; + + auto pos = frameStr.find_first_of(':'); + if(pos == std::string::npos || pos == frameStr.length() - 1) + return false; + + auto header = frameStr.substr(0, pos); // contains sours, dest and path + auto body = frameStr.substr(pos +1); + + std::vector headerSplits; + boost::split(headerSplits, header, [](char c) { return c == ',' || c == '>';}); + + if(headerSplits.size() < 2) //we need at least source and dest to form a valid frame + return false; + + frame.m_source.assign(headerSplits[0]); + frame.m_dest.assign(headerSplits[1]); + + for(unsigned int i = 2; i < headerSplits.size(); i++) { + frame.m_path.push_back(headerSplits[i]); + } + + frame.m_body.assign(body); + + frame.m_type = body[0] == ':' ? APFT_MESSAGE : APFT_UNKNOWN; + + return true; +} + diff --git a/APRSParser.h b/APRSParser.h new file mode 100644 index 0000000..ede7c2c --- /dev/null +++ b/APRSParser.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +#include "APRSFrame.h" + +class CAPRSParser +{ +public: + //TODO 2022-01-02 move these to own class ? + static bool parseFrame(const std::string& frameStr, TAPRSFrame& frame); +}; \ No newline at end of file diff --git a/APRSReader.cpp b/APRSReader.cpp new file mode 100644 index 0000000..faec2e8 --- /dev/null +++ b/APRSReader.cpp @@ -0,0 +1,32 @@ +/* + * 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 "APRSReader.h" +#include "APRSFrame.h" +#include "APRSParser.h" + +CAPRSReader::CAPRSReader() +{ + +} + +bool CAPRSReader::readAprsFrame(const std::string& aprsFrame) +{ + +} \ No newline at end of file diff --git a/APRSReader.h b/APRSReader.h new file mode 100644 index 0000000..56781ba --- /dev/null +++ b/APRSReader.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#pragma once + +#include "ReadAPRSFrameCallback.h" + +class CAPRSReader : public CReadAPRSFrameCallback +{ +public: + CAPRSReader(); + bool readAprsFrame(const std::string& aprsFrame); + +private: + +}; + + diff --git a/APRSWriterThread.cpp b/APRSWriterThread.cpp index 796054c..aa2462b 100644 --- a/APRSWriterThread.cpp +++ b/APRSWriterThread.cpp @@ -43,7 +43,7 @@ m_exit(false), m_connected(false), m_reconnectTimer(1000U), m_tries(0U), -m_APRSReadCallback(NULL), +m_APRSReadCallback(), m_filter(""), m_clientName(FULL_PRODUCT_NAME) { @@ -70,7 +70,7 @@ m_exit(false), m_connected(false), m_reconnectTimer(1000U), m_tries(0U), -m_APRSReadCallback(NULL), +m_APRSReadCallback(), m_filter(filter), m_clientName(clientName) { @@ -88,6 +88,17 @@ m_clientName(clientName) CAPRSWriterThread::~CAPRSWriterThread() { + std::vector callBacksCopy; + callBacksCopy.assign(m_APRSReadCallback.begin(), m_APRSReadCallback.end()); + + m_APRSReadCallback.clear(); + + for(auto cb : callBacksCopy) { + delete cb; + } + + callBacksCopy.clear(); + m_username.clear(); m_password.clear(); } @@ -163,9 +174,11 @@ void* CAPRSWriterThread::Entry() CLog::logDebug("Received APRS Frame : %s", line.c_str()); if(length > 0 && line[0] != '#'//check if we have something and if that something is an APRS frame - && m_APRSReadCallback != NULL)//do we have someone wanting an APRS Frame? + && m_APRSReadCallback.size() > 0U)//do we have someone wanting an APRS Frame? { - m_APRSReadCallback(std::string(line)); + for(auto cb : m_APRSReadCallback) { + cb->readAprsFrame(line); + } } } @@ -193,9 +206,10 @@ void* CAPRSWriterThread::Entry() return NULL; } -void CAPRSWriterThread::setReadAPRSCallback(ReadAPRSFrameCallback cb) +void CAPRSWriterThread::addReadAPRSCallback(CReadAPRSFrameCallback * cb) { - m_APRSReadCallback = cb; + assert(cb != nullptr); + m_APRSReadCallback.push_back(cb); } void CAPRSWriterThread::write(const char* data) diff --git a/APRSWriterThread.h b/APRSWriterThread.h index aa07af2..2e21f9e 100644 --- a/APRSWriterThread.h +++ b/APRSWriterThread.h @@ -19,12 +19,14 @@ #ifndef APRSWriterThread_H #define APRSWriterThread_H +#include + #include "TCPReaderWriterClient.h" #include "RingBuffer.h" #include "Timer.h" #include "Thread.h" +#include "ReadAPRSFrameCallback.h" -typedef void (*ReadAPRSFrameCallback)(const std::string&); class CAPRSWriterThread : public CThread { public: @@ -44,7 +46,7 @@ public: void clock(unsigned int ms); - void setReadAPRSCallback(ReadAPRSFrameCallback cb); + void addReadAPRSCallback(CReadAPRSFrameCallback* cb); private: std::string m_username; @@ -56,7 +58,7 @@ private: bool m_connected; CTimer m_reconnectTimer; unsigned int m_tries; - ReadAPRSFrameCallback m_APRSReadCallback; + std::vector m_APRSReadCallback; std::string m_filter; std::string m_clientName; diff --git a/ReadAPRSFrameCallback.h b/ReadAPRSFrameCallback.h new file mode 100644 index 0000000..1b02dc3 --- /dev/null +++ b/ReadAPRSFrameCallback.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2021 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. + */ + +#pragma once + +#include + +class CReadAPRSFrameCallback +{ +public: + virtual ~CReadAPRSFrameCallback(){ } + virtual bool readAprsFrame(const std::string& aprsFrame) = 0; +}; From 1ac0e91085b27e2d522761c2acd7e8adb9be7741 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 17:34:39 +0100 Subject: [PATCH 033/201] Treat Warnings as error --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index d959810..97c6838 100644 --- a/Makefile +++ b/Makefile @@ -22,9 +22,9 @@ export DATA_DIR=/usr/local/share/dstargateway.d/ export LOG_DIR=/var/log/dstargateway/ # choose this if you want debugging help -CPPFLAGS=-g -ggdb -W -Wall -std=c++17 +CPPFLAGS=-g -ggdb -W -Wall -Werror -std=c++17 # or, you can choose this for a much smaller executable without debugging help -#CPPFLAGS=-W -Wall -std=c++17 +#CPPFLAGS=-W -Wall -Werror -std=c++17 LDFLAGS:=-lcurl -pthread From 38f45df4f715013c8aa93b8bb18a98ebc85df01c Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 17:37:05 +0100 Subject: [PATCH 034/201] Keep compiler happy --- APRSReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/APRSReader.cpp b/APRSReader.cpp index faec2e8..5eb293c 100644 --- a/APRSReader.cpp +++ b/APRSReader.cpp @@ -28,5 +28,5 @@ CAPRSReader::CAPRSReader() bool CAPRSReader::readAprsFrame(const std::string& aprsFrame) { - + return false; } \ No newline at end of file From 60fe1144a391f15c23a9ca5ee1914f027bc8972b Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 17:39:20 +0100 Subject: [PATCH 035/201] Crank up number of jobs --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 78a8970..0780b1f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,7 +21,7 @@ jobs: sudo apt-get install libcurl4-openssl-dev libboost-dev - run: name: "Build" - command: "make -j 3" + command: "make -j 8" # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows From 6f413665cce7931870ad97420178928ca926a5b1 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 17:40:39 +0100 Subject: [PATCH 036/201] Reduce number of jobs --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0780b1f..78a8970 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,7 +21,7 @@ jobs: sudo apt-get install libcurl4-openssl-dev libboost-dev - run: name: "Build" - command: "make -j 8" + command: "make -j 3" # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows From eaf116aa77bf274f3aeb00aa92a669536c5658bc Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 17:43:21 +0100 Subject: [PATCH 037/201] Keep compiler happy --- APRSReader.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/APRSReader.cpp b/APRSReader.cpp index 5eb293c..431f777 100644 --- a/APRSReader.cpp +++ b/APRSReader.cpp @@ -28,5 +28,6 @@ CAPRSReader::CAPRSReader() bool CAPRSReader::readAprsFrame(const std::string& aprsFrame) { + auto bla = aprsFrame; return false; } \ No newline at end of file From d4642d9274ee3c73de1028d2017a034c3aff79a0 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 19:27:03 +0100 Subject: [PATCH 038/201] add google test settings --- .vscode/settings.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 727ce82..d43f3db 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,5 +8,27 @@ ], "files.associations": { "new": "cpp" + }, + "editor.tokenColorCustomizations": { + "textMateRules": [ + { + "scope": "googletest.failed", + "settings": { + "foreground": "#f00" + } + }, + { + "scope": "googletest.passed", + "settings": { + "foreground": "#0f0" + } + }, + { + "scope": "googletest.run", + "settings": { + "foreground": "#0f0" + } + } + ] } } \ No newline at end of file From 4714bcb6b5e76e2d56b4a2754e55ce57e57c7222 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 19:32:37 +0100 Subject: [PATCH 039/201] Adds build task --- .vscode/tasks.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .vscode/tasks.json diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..7861bb7 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,17 @@ +{ + // See https://go.microsoft.com/fwlink/?LinkId=733558 + // for the documentation about the tasks.json format + "version": "2.0.0", + "tasks": [ + { + "label": "Build", + "type": "shell", + "command": "make", + "args": ["-j3"], + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} \ No newline at end of file From f11edfdfd8c1477e3512a542969a8e3635de99e5 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 19:50:28 +0100 Subject: [PATCH 040/201] Add tesks to build tests --- .vscode/tasks.json | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 7861bb7..f50a809 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -7,11 +7,25 @@ "label": "Build", "type": "shell", "command": "make", - "args": ["-j3"], + "args": [ + "-j3" + ], "group": { "kind": "build", "isDefault": true - } + }, + "problemMatcher": [] + }, + { + "label": "Build Tests", + "type": "shell", + "command": "make", + "args": [ + "-j3", + "tests" + ], + "group": "build", + "problemMatcher": [] } ] } \ No newline at end of file From 1395c4bc684cd80413d5da5f11986b20324e1c87 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 21:29:35 +0100 Subject: [PATCH 041/201] add dependency to google test --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 78a8970..db3efe0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,7 +18,7 @@ jobs: name: Install dependencies command: | sudo apt-get update - sudo apt-get install libcurl4-openssl-dev libboost-dev + sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev - run: name: "Build" command: "make -j 3" From 249af92976f7f7cde194e1725f0c18ee936f0228 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 21:29:55 +0100 Subject: [PATCH 042/201] Add defien to not compile main when building unittests --- DStarGatewayApp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DStarGatewayApp.cpp b/DStarGatewayApp.cpp index 6150d62..37e520a 100644 --- a/DStarGatewayApp.cpp +++ b/DStarGatewayApp.cpp @@ -41,6 +41,7 @@ #include "APRSGPSDIdFrameProvider.h" #include "APRSFixedIdFrameProvider.h" +#ifndef UNIT_TESTS int main(int argc, char *argv[]) { setbuf(stdout, NULL); @@ -69,6 +70,7 @@ int main(int argc, char *argv[]) return 0; } +#endif CDStarGatewayApp::CDStarGatewayApp(const std::string &configFile) : m_configFile(configFile), m_thread(NULL) { From cf6116fd7a7556b8f9876f491ebb6f9db52984e6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 21:30:27 +0100 Subject: [PATCH 043/201] Add tests --- .gitignore | 2 +- .vscode/launch.json | 24 +++++++++++++++++++ .vscode/settings.json | 6 ++++- .vscode/tasks.json | 10 ++++---- Makefile | 23 ++++++++++-------- Tests/Makefile | 25 ++++++++++++++++++++ Tests/TestTest.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 127 insertions(+), 17 deletions(-) create mode 100644 Tests/Makefile create mode 100644 Tests/TestTest.cpp diff --git a/.gitignore b/.gitignore index 522c725..32c2539 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,4 @@ Sandbox/* *.out *.app dstargateway - +Tests/dstargateway_tests diff --git a/.vscode/launch.json b/.vscode/launch.json index b2c785b..ef85a5f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -27,6 +27,30 @@ "ignoreFailures": true } ] + }, + { + "name": "Tests", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/Tests/dstargateway_tests", + "args": [ ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Activer l'impression en mode Pretty pour gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Définir la version désassemblage sur Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + ] } ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index d43f3db..a509b7e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -30,5 +30,9 @@ } } ] - } + }, + "gtest-adapter.debugConfig": [ + "Tests" + ], + "gtest-adapter.supportLocation": true } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index f50a809..2fa8b11 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -10,10 +10,7 @@ "args": [ "-j3" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] }, { @@ -24,7 +21,10 @@ "-j3", "tests" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] } ] diff --git a/Makefile b/Makefile index 97c6838..a768147 100644 --- a/Makefile +++ b/Makefile @@ -22,15 +22,15 @@ export DATA_DIR=/usr/local/share/dstargateway.d/ export LOG_DIR=/var/log/dstargateway/ # choose this if you want debugging help -CPPFLAGS=-g -ggdb -W -Wall -Werror -std=c++17 +export CPPFLAGS=-g -ggdb -W -Wall -Werror -std=c++17 # or, you can choose this for a much smaller executable without debugging help #CPPFLAGS=-W -Wall -Werror -std=c++17 - -LDFLAGS:=-lcurl -pthread +export CC=g++ +export LDFLAGS:=-lcurl -pthread ifeq ($(USE_GPSD), 1) -CPPFLAGS+= -DUSE_GPSD -LDFLAGS+= -lgps +export CPPFLAGS+= -DUSE_GPSD +export LDFLAGS+= -lgps endif SRCS = $(wildcard *.cpp) @@ -38,13 +38,13 @@ OBJS = $(SRCS:.cpp=.o) DEPS = $(SRCS:.cpp=.d) .PHONY: all -all: dstargateway +all: dstargateway tests dstargateway : GitVersion.h $(OBJS) - g++ $(CPPFLAGS) -o dstargateway $(OBJS) $(LDFLAGS) + $(CC) $(CPPFLAGS) -o dstargateway $(OBJS) $(LDFLAGS) %.o : %.cpp - g++ $(CPPFLAGS) -MMD -MD -c $< -o $@ + $(CC) $(CPPFLAGS) -MMD -MD -c $< -o $@ GitVersion.h : FORCE ifneq ("$(wildcard .git/index)","") @@ -66,7 +66,8 @@ endif .PHONY: clean clean: - $(RM) GitVersion.h $(OBJS) $(DEPS) dstargateway + @$(RM) GitVersion.h $(OBJS) $(DEPS) dstargateway + @$(MAKE) -C Tests clean -include $(DEPS) @@ -129,6 +130,8 @@ removehostfiles : @rm -f $(DATA_DIR)/DCS_Hosts.txt @rm -f $(DATA_DIR)/DPlus_Hosts.txt - +.PHONY tests: +tests : GitVersion.h $(OBJS) + $(MAKE) -C Tests tests FORCE: \ No newline at end of file diff --git a/Tests/Makefile b/Tests/Makefile new file mode 100644 index 0000000..18c1255 --- /dev/null +++ b/Tests/Makefile @@ -0,0 +1,25 @@ + +SRCS = $(wildcard *.cpp) $(wildcard ../*.cpp) +OBJS = $(SRCS:.cpp=.o) +DEPS = $(SRCS:.cpp=.d) + +.PHONY tests: +tests: rmdstargatewayapp $(OBJS) + $(CC) $(CPPFLAGS) -o dstargateway_tests $(OBJS) $(LDFLAGS) -lgtest -lgtest_main + +%.o : %.cpp + $(CC) $(CPPFLAGS) -DUNIT_TESTS -I../ -MMD -MD -c $< -o $@ + +-include $(DEPS) + +.PHONY clean : +clean : + @$(RM) $(OBJS) $(DEPS) dstargateway_tests + + +.PHONY rmdstargatewayapp : +rmdstargatewayapp: FORCE + @$(RM) ../DStarGatewayApp.o + @$(RM) ../DStarGatewayApp.d + +FORCE: \ No newline at end of file diff --git a/Tests/TestTest.cpp b/Tests/TestTest.cpp new file mode 100644 index 0000000..be6372e --- /dev/null +++ b/Tests/TestTest.cpp @@ -0,0 +1,54 @@ + + +#include + +#include + + + +// The fixture for testing class Foo. +class FooTest : public ::testing::Test { + protected: + // You can remove any or all of the following functions if their bodies would + // be empty. + + FooTest() { + // You can do set-up work for each test here. + } + + ~FooTest() override { + // You can do clean-up work that doesn't throw exceptions here. + } + + // If the constructor and destructor are not enough for setting up + // and cleaning up each test, you can define the following methods: + + void SetUp() override { + // Code here will be called immediately after the constructor (right + // before each test). + } + + void TearDown() override { + // Code here will be called immediately after each test (right + // before the destructor). + } + + // Class members declared here can be used by all tests in the test suite + // for Foo. +}; + +// Tests that the Foo::Bar() method does Abc. +TEST_F(FooTest, MethodBarDoesAbc) { + const std::string input_filepath = "this/package/testdata/myinputfile.dat"; + const std::string output_filepath = "this/package/testdata/myoutputfile.dat"; + + TAPRSFrame frame; + CAPRSParser::parseFrame("bla", frame); + + EXPECT_EQ(frame.m_type, APFT_MESSAGE); +} + +// Tests that Foo does Xyz. +TEST_F(FooTest, DoesXyz) { + // Exercises the Xyz feature of Foo. +} From 5f11a1255b94abe79eb3d0b34bc77a60883f973d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 21:39:23 +0100 Subject: [PATCH 044/201] Remove tests target from all --- .circleci/config.yml | 2 +- Makefile | 2 +- Tests/Makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index db3efe0..71f3720 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,7 +21,7 @@ jobs: sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev - run: name: "Build" - command: "make -j 3" + command: "make -j 3 dstargateway tests" # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows diff --git a/Makefile b/Makefile index a768147..e855986 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ OBJS = $(SRCS:.cpp=.o) DEPS = $(SRCS:.cpp=.d) .PHONY: all -all: dstargateway tests +all: dstargateway dstargateway : GitVersion.h $(OBJS) $(CC) $(CPPFLAGS) -o dstargateway $(OBJS) $(LDFLAGS) diff --git a/Tests/Makefile b/Tests/Makefile index 18c1255..c8d2dca 100644 --- a/Tests/Makefile +++ b/Tests/Makefile @@ -16,7 +16,7 @@ tests: rmdstargatewayapp $(OBJS) clean : @$(RM) $(OBJS) $(DEPS) dstargateway_tests - +# Again ugly trick to force rebuild of DStarGatewayApp .PHONY rmdstargatewayapp : rmdstargatewayapp: FORCE @$(RM) ../DStarGatewayApp.o From f1696c41afca631ab246a97c7af134dc4187ec12 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 21:51:07 +0100 Subject: [PATCH 045/201] Some more Tests stuff --- .circleci/config.yml | 7 +++++-- Makefile | 6 ++++-- Tests/Makefile | 9 +-------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 71f3720..4409f38 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,8 +20,11 @@ jobs: sudo apt-get update sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev - run: - name: "Build" - command: "make -j 3 dstargateway tests" + name: "Build App" + command: "make -j 3 dstargateway" + - run: + name: "Build Tests" + command: "make -j 3 tests" # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows diff --git a/Makefile b/Makefile index e855986..a0eab61 100644 --- a/Makefile +++ b/Makefile @@ -131,7 +131,9 @@ removehostfiles : @rm -f $(DATA_DIR)/DPlus_Hosts.txt .PHONY tests: -tests : GitVersion.h $(OBJS) - $(MAKE) -C Tests tests +tests : GitVersion.h + @$(RM) -f DStarGatewayApp.o + @$(RM) -f DStarGatewayApp.d + @$(MAKE) -C Tests tests FORCE: \ No newline at end of file diff --git a/Tests/Makefile b/Tests/Makefile index c8d2dca..155361a 100644 --- a/Tests/Makefile +++ b/Tests/Makefile @@ -4,7 +4,7 @@ OBJS = $(SRCS:.cpp=.o) DEPS = $(SRCS:.cpp=.d) .PHONY tests: -tests: rmdstargatewayapp $(OBJS) +tests: $(OBJS) $(CC) $(CPPFLAGS) -o dstargateway_tests $(OBJS) $(LDFLAGS) -lgtest -lgtest_main %.o : %.cpp @@ -16,10 +16,3 @@ tests: rmdstargatewayapp $(OBJS) clean : @$(RM) $(OBJS) $(DEPS) dstargateway_tests -# Again ugly trick to force rebuild of DStarGatewayApp -.PHONY rmdstargatewayapp : -rmdstargatewayapp: FORCE - @$(RM) ../DStarGatewayApp.o - @$(RM) ../DStarGatewayApp.d - -FORCE: \ No newline at end of file From 231bcc93944e189409f6a67793d8a4127b46859b Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 21:53:32 +0100 Subject: [PATCH 046/201] clarify weird stuff --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index a0eab61..79f9d87 100644 --- a/Makefile +++ b/Makefile @@ -132,6 +132,7 @@ removehostfiles : .PHONY tests: tests : GitVersion.h +# remove these to force tests makefile to rebuild them with -DUNIT_TESTS, otherwise we end up with 2 mains @$(RM) -f DStarGatewayApp.o @$(RM) -f DStarGatewayApp.d @$(MAKE) -C Tests tests From 64a56ea777949ea6198bbe2d55271f47cc1ba371 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 22:06:55 +0100 Subject: [PATCH 047/201] Add run tests --- .circleci/config.yml | 3 +++ Makefile | 5 ++++- Tests/Makefile | 7 ++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4409f38..7cfc309 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -25,6 +25,9 @@ jobs: - run: name: "Build Tests" command: "make -j 3 tests" + - run: + name: "Run Tests" + command: "make run-tests" # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows diff --git a/Makefile b/Makefile index 79f9d87..b6088c4 100644 --- a/Makefile +++ b/Makefile @@ -135,6 +135,9 @@ tests : GitVersion.h # remove these to force tests makefile to rebuild them with -DUNIT_TESTS, otherwise we end up with 2 mains @$(RM) -f DStarGatewayApp.o @$(RM) -f DStarGatewayApp.d - @$(MAKE) -C Tests tests + @$(MAKE) -C Tests dstargateway_tests + +.PHONY run-tests: + @$(MAKE) -C Tests run-tests FORCE: \ No newline at end of file diff --git a/Tests/Makefile b/Tests/Makefile index 155361a..6b393dc 100644 --- a/Tests/Makefile +++ b/Tests/Makefile @@ -3,8 +3,7 @@ SRCS = $(wildcard *.cpp) $(wildcard ../*.cpp) OBJS = $(SRCS:.cpp=.o) DEPS = $(SRCS:.cpp=.d) -.PHONY tests: -tests: $(OBJS) +dstargateway_tests: $(OBJS) $(CC) $(CPPFLAGS) -o dstargateway_tests $(OBJS) $(LDFLAGS) -lgtest -lgtest_main %.o : %.cpp @@ -12,7 +11,9 @@ tests: $(OBJS) -include $(DEPS) +.PHONY run-tests: dstargateway_tests + ./dstargateway_tests + .PHONY clean : clean : @$(RM) $(OBJS) $(DEPS) dstargateway_tests - From 56f6778e1add9eec743a030f2535f6a33e76cee5 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 22:14:10 +0100 Subject: [PATCH 048/201] extend workflow --- .circleci/config.yml | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7cfc309..54310a3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,6 +5,15 @@ version: 2.1 # Define a job to be invoked later in a workflow. # See: https://circleci.com/docs/2.0/configuration-reference/#jobs jobs: + install-deps: + docker: + - image: cimg/base:stable + steps: + - run: + name: Install dependencies + command: | + sudo apt-get update + sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev build-dstargateway: # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor @@ -14,24 +23,32 @@ jobs: # See: https://circleci.com/docs/2.0/configuration-reference/#steps steps: - checkout - - run: - name: Install dependencies - command: | - sudo apt-get update - sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev - run: name: "Build App" command: "make -j 3 dstargateway" + build-tests: + docker: + - image: cimg/base:stable + steps: + - checkout - run: name: "Build Tests" command: "make -j 3 tests" + run-tests: + docker: + - image: cimg/base:stable + steps: + - checkout - run: name: "Run Tests" command: "make run-tests" + # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows workflows: dstar-gateway-workflow: jobs: + - build-tests + - run-tests - build-dstargateway From a8cf4507d273a87224a719363c3f4445e56722f8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 22:15:26 +0100 Subject: [PATCH 049/201] Updated config.yml --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 54310a3..c5836eb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -27,7 +27,7 @@ jobs: name: "Build App" command: "make -j 3 dstargateway" build-tests: - docker: + docker: - image: cimg/base:stable steps: - checkout @@ -35,7 +35,7 @@ jobs: name: "Build Tests" command: "make -j 3 tests" run-tests: - docker: + docker: - image: cimg/base:stable steps: - checkout From 8e7675ba56beaf1b6f0f1c69fc9929360f6c334e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 22:18:20 +0100 Subject: [PATCH 050/201] yaml sucks --- .circleci/config.yml | 27 +++++---------------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c5836eb..7cfc309 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,15 +5,6 @@ version: 2.1 # Define a job to be invoked later in a workflow. # See: https://circleci.com/docs/2.0/configuration-reference/#jobs jobs: - install-deps: - docker: - - image: cimg/base:stable - steps: - - run: - name: Install dependencies - command: | - sudo apt-get update - sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev build-dstargateway: # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor @@ -23,32 +14,24 @@ jobs: # See: https://circleci.com/docs/2.0/configuration-reference/#steps steps: - checkout + - run: + name: Install dependencies + command: | + sudo apt-get update + sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev - run: name: "Build App" command: "make -j 3 dstargateway" - build-tests: - docker: - - image: cimg/base:stable - steps: - - checkout - run: name: "Build Tests" command: "make -j 3 tests" - run-tests: - docker: - - image: cimg/base:stable - steps: - - checkout - run: name: "Run Tests" command: "make run-tests" - # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows workflows: dstar-gateway-workflow: jobs: - - build-tests - - run-tests - build-dstargateway From 9920f427a70360e54c8a030d5009f8cef0e81804 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 22:19:34 +0100 Subject: [PATCH 051/201] Build app after tests --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7cfc309..7d8209a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,15 +19,15 @@ jobs: command: | sudo apt-get update sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev - - run: - name: "Build App" - command: "make -j 3 dstargateway" - run: name: "Build Tests" command: "make -j 3 tests" - run: name: "Run Tests" command: "make run-tests" + - run: + name: "Build App" + command: "make -j 3 dstargateway" # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows From 28d7f9753da2cf159fc9ba4c7aab624aa7320242 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 22:21:19 +0100 Subject: [PATCH 052/201] revert build app before tests --- .circleci/config.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7d8209a..e148e64 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,16 +19,15 @@ jobs: command: | sudo apt-get update sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev + - run: + name: "Build App" + command: "make -j 3 dstargateway" - run: name: "Build Tests" command: "make -j 3 tests" - run: name: "Run Tests" command: "make run-tests" - - run: - name: "Build App" - command: "make -j 3 dstargateway" - # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows workflows: From abcfb23db2395f8950b3b2ce56518cf1890985d8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 22:44:50 +0100 Subject: [PATCH 053/201] adjust include paths --- .vscode/c_cpp_properties.json | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .vscode/c_cpp_properties.json diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..a8a2c81 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,17 @@ +{ + "configurations": [ + { + "name": "Linux", + "includePath": [ + "${workspaceFolder}/**" + ], + "defines": [], + "compilerPath": "/bin/g++", + "cStandard": "gnu17", + "cppStandard": "gnu++17", + "intelliSenseMode": "linux-gcc-x64", + "configurationProvider": "ms-vscode.makefile-tools" + } + ], + "version": 4 +} \ No newline at end of file From fecd6633f7b07a37f4b2a812744efa3242ada14d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 2 Jan 2022 22:45:09 +0100 Subject: [PATCH 054/201] Add tests for APRSParser --- Tests/APRSParser_parseAPRSFrame_Tests.cpp | 38 ++++++++++++++++ Tests/TestTest.cpp | 54 ----------------------- 2 files changed, 38 insertions(+), 54 deletions(-) create mode 100644 Tests/APRSParser_parseAPRSFrame_Tests.cpp delete mode 100644 Tests/TestTest.cpp diff --git a/Tests/APRSParser_parseAPRSFrame_Tests.cpp b/Tests/APRSParser_parseAPRSFrame_Tests.cpp new file mode 100644 index 0000000..915fc3d --- /dev/null +++ b/Tests/APRSParser_parseAPRSFrame_Tests.cpp @@ -0,0 +1,38 @@ +/* + * 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 + +#include "../APRSParser.h" + +class APRSParser_parseAPRSFrame_Tests : public ::testing::Test { + +}; + +TEST_F(APRSParser_parseAPRSFrame_Tests, EmpyString) { + + TAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("", aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STRCASEEQ(aprsFrame.m_body.c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.m_dest.c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.m_source.c_str(), ""); + EXPECT_EQ(aprsFrame.m_type, APFT_UNKNOWN); + EXPECT_EQ(aprsFrame.m_path.size(), 0U); +} \ No newline at end of file diff --git a/Tests/TestTest.cpp b/Tests/TestTest.cpp deleted file mode 100644 index be6372e..0000000 --- a/Tests/TestTest.cpp +++ /dev/null @@ -1,54 +0,0 @@ - - -#include - -#include - - - -// The fixture for testing class Foo. -class FooTest : public ::testing::Test { - protected: - // You can remove any or all of the following functions if their bodies would - // be empty. - - FooTest() { - // You can do set-up work for each test here. - } - - ~FooTest() override { - // You can do clean-up work that doesn't throw exceptions here. - } - - // If the constructor and destructor are not enough for setting up - // and cleaning up each test, you can define the following methods: - - void SetUp() override { - // Code here will be called immediately after the constructor (right - // before each test). - } - - void TearDown() override { - // Code here will be called immediately after each test (right - // before the destructor). - } - - // Class members declared here can be used by all tests in the test suite - // for Foo. -}; - -// Tests that the Foo::Bar() method does Abc. -TEST_F(FooTest, MethodBarDoesAbc) { - const std::string input_filepath = "this/package/testdata/myinputfile.dat"; - const std::string output_filepath = "this/package/testdata/myoutputfile.dat"; - - TAPRSFrame frame; - CAPRSParser::parseFrame("bla", frame); - - EXPECT_EQ(frame.m_type, APFT_MESSAGE); -} - -// Tests that Foo does Xyz. -TEST_F(FooTest, DoesXyz) { - // Exercises the Xyz feature of Foo. -} From 775805eaf74f3718fb5369f421334a1699d7955b Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 3 Jan 2022 17:30:38 +0100 Subject: [PATCH 055/201] Move tests to sub folder --- Tests/{ => APRSParser}/APRSParser_parseAPRSFrame_Tests.cpp | 2 +- Tests/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename Tests/{ => APRSParser}/APRSParser_parseAPRSFrame_Tests.cpp (97%) diff --git a/Tests/APRSParser_parseAPRSFrame_Tests.cpp b/Tests/APRSParser/APRSParser_parseAPRSFrame_Tests.cpp similarity index 97% rename from Tests/APRSParser_parseAPRSFrame_Tests.cpp rename to Tests/APRSParser/APRSParser_parseAPRSFrame_Tests.cpp index 915fc3d..504bc26 100644 --- a/Tests/APRSParser_parseAPRSFrame_Tests.cpp +++ b/Tests/APRSParser/APRSParser_parseAPRSFrame_Tests.cpp @@ -18,7 +18,7 @@ #include -#include "../APRSParser.h" +#include "../../APRSParser.h" class APRSParser_parseAPRSFrame_Tests : public ::testing::Test { diff --git a/Tests/Makefile b/Tests/Makefile index 6b393dc..39c4504 100644 --- a/Tests/Makefile +++ b/Tests/Makefile @@ -1,5 +1,5 @@ -SRCS = $(wildcard *.cpp) $(wildcard ../*.cpp) +SRCS = $(wildcard *.cpp) $(wildcard ../*.cpp) $(wildcard */*.cpp) OBJS = $(SRCS:.cpp=.o) DEPS = $(SRCS:.cpp=.d) From 088259daaeb82986d14af9a28b2feab8a852102f Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 3 Jan 2022 18:41:55 +0100 Subject: [PATCH 056/201] rename test case file and add somre test cases --- ..._parseAPRSFrame_Tests.cpp => APRSFrame.cpp | 39 ++++---- APRSFrame.h | 18 +++- APRSParser.cpp | 76 +++++++++------ APRSParser.h | 6 +- Tests/APRSParser/parseAPRSFrame.cpp | 92 +++++++++++++++++++ 5 files changed, 184 insertions(+), 47 deletions(-) rename Tests/APRSParser/APRSParser_parseAPRSFrame_Tests.cpp => APRSFrame.cpp (54%) create mode 100644 Tests/APRSParser/parseAPRSFrame.cpp diff --git a/Tests/APRSParser/APRSParser_parseAPRSFrame_Tests.cpp b/APRSFrame.cpp similarity index 54% rename from Tests/APRSParser/APRSParser_parseAPRSFrame_Tests.cpp rename to APRSFrame.cpp index 504bc26..70ef101 100644 --- a/Tests/APRSParser/APRSParser_parseAPRSFrame_Tests.cpp +++ b/APRSFrame.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA + * 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 @@ -16,23 +16,30 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include +#include "APRSFrame.h" -#include "../../APRSParser.h" +CAPRSFrame::CAPRSFrame() : +m_source(), +m_destination(), +m_path(), +m_type(APFT_UNKNOWN) +{ -class APRSParser_parseAPRSFrame_Tests : public ::testing::Test { - -}; +} -TEST_F(APRSParser_parseAPRSFrame_Tests, EmpyString) { +CAPRSFrame::CAPRSFrame(const std::string& source, const std::string& destination, const std::vector& path, APRS_FRAME_TYPE type) : +m_source(source), +m_destination(destination), +m_path(), +m_type(type) +{ + m_path.assign(path.begin(), path.end()); +} - TAPRSFrame aprsFrame; - bool retVal = CAPRSParser::parseFrame("", aprsFrame); - - EXPECT_FALSE(retVal); - EXPECT_STRCASEEQ(aprsFrame.m_body.c_str(), ""); - EXPECT_STRCASEEQ(aprsFrame.m_dest.c_str(), ""); - EXPECT_STRCASEEQ(aprsFrame.m_source.c_str(), ""); - EXPECT_EQ(aprsFrame.m_type, APFT_UNKNOWN); - EXPECT_EQ(aprsFrame.m_path.size(), 0U); +void CAPRSFrame::clear() +{ + m_source.clear(); + m_destination.clear(); + m_path.clear(); + m_type = APFT_UNKNOWN; } \ No newline at end of file diff --git a/APRSFrame.h b/APRSFrame.h index 39494eb..d84a048 100644 --- a/APRSFrame.h +++ b/APRSFrame.h @@ -27,10 +27,22 @@ enum APRS_FRAME_TYPE { APFT_MESSAGE, }; -typedef struct { +class CAPRSFrame { +public: + CAPRSFrame(); + CAPRSFrame(const std::string& source, const std::string& destination, const std::vector& path, APRS_FRAME_TYPE type); + + void clear(); + std::string& getSource() { return m_source; } + std::string& getDestination() { return m_destination; } + std::vector& getPath() { return m_path; } + std::string& getBody() { return m_body; } + APRS_FRAME_TYPE& getType() { return m_type; } + +private: std::string m_source; - std::string m_dest; + std::string m_destination; std::vector m_path; std::string m_body; APRS_FRAME_TYPE m_type; -} TAPRSFrame; \ No newline at end of file +}; \ No newline at end of file diff --git a/APRSParser.cpp b/APRSParser.cpp index d3ed20d..d12076a 100644 --- a/APRSParser.cpp +++ b/APRSParser.cpp @@ -17,42 +17,66 @@ */ #include "APRSParser.h" +#include "Log.h" -bool CAPRSParser::parseFrame(const std::string& frameStr, TAPRSFrame& frame) +bool CAPRSParser::parseFrame(const std::string& frameStr, CAPRSFrame& frame) { - frame.m_body.clear(); - frame.m_dest.clear(); - frame.m_path.clear(); - frame.m_source.clear(); - frame.m_type = APFT_UNKNOWN; + frame.clear(); + bool ret = false; - if(!frameStr.empty()) - return false; + if(!frameStr.empty()) { + auto pos = frameStr.find_first_of(':'); + if(pos != std::string::npos && pos != frameStr.length() - 1) { + auto header = frameStr.substr(0, pos); // contains source, dest and path + auto body = frameStr.substr(pos +1); - auto pos = frameStr.find_first_of(':'); - if(pos == std::string::npos || pos == frameStr.length() - 1) - return false; + std::vector headerSplits; + boost::split(headerSplits, header, [](char c) { return c == ',' || c == '>';}); - auto header = frameStr.substr(0, pos); // contains sours, dest and path - auto body = frameStr.substr(pos +1); + //we need at least source and dest to form a valid frame, also headers shall not contain empty strings + if(headerSplits.size() >= 2 && std::none_of(headerSplits.begin(), headerSplits.end(), [](std::string s){ return s.empty(); })) { + frame.getSource().assign(headerSplits[0]); + frame.getDestination().assign(headerSplits[1]); - std::vector headerSplits; - boost::split(headerSplits, header, [](char c) { return c == ',' || c == '>';}); + for(unsigned int i = 2; i < headerSplits.size(); i++) { + frame.getPath().push_back(headerSplits[i]); + } - if(headerSplits.size() < 2) //we need at least source and dest to form a valid frame - return false; + frame.getBody().assign(body); - frame.m_source.assign(headerSplits[0]); - frame.m_dest.assign(headerSplits[1]); - - for(unsigned int i = 2; i < headerSplits.size(); i++) { - frame.m_path.push_back(headerSplits[i]); + setFrameType(frame); + if(frame.getType() == APFT_UNKNOWN) { + CLog::logInfo("Invalid or unsupported APRS frame : %s", frameStr); + } + else { + ret = true; + } + } + } } - frame.m_body.assign(body); + return ret; +} - frame.m_type = body[0] == ':' ? APFT_MESSAGE : APFT_UNKNOWN; +void CAPRSParser::setFrameType(CAPRSFrame& frame) +{ + APRS_FRAME_TYPE type = APFT_UNKNOWN; + std::string body(frame.getBody()); - return true; -} + if(!body.empty()) { + switch (body[0]) + { + case ':': + if(body[10] == ':') + type = APFT_MESSAGE; + break; + + default: + break; + } + } + frame.getType() = type; + if(type == APFT_UNKNOWN) + frame.clear(); +} \ No newline at end of file diff --git a/APRSParser.h b/APRSParser.h index ede7c2c..6d94f09 100644 --- a/APRSParser.h +++ b/APRSParser.h @@ -26,6 +26,8 @@ class CAPRSParser { public: - //TODO 2022-01-02 move these to own class ? - static bool parseFrame(const std::string& frameStr, TAPRSFrame& frame); + static bool parseFrame(const std::string& frameStr, CAPRSFrame& frame); + +private: + static void setFrameType(CAPRSFrame& frame); }; \ No newline at end of file diff --git a/Tests/APRSParser/parseAPRSFrame.cpp b/Tests/APRSParser/parseAPRSFrame.cpp new file mode 100644 index 0000000..2cb44d7 --- /dev/null +++ b/Tests/APRSParser/parseAPRSFrame.cpp @@ -0,0 +1,92 @@ +/* + * 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 + +#include "../../APRSParser.h" + +class APRSParser_parseAPRSFrame : public ::testing::Test { + +}; + +TEST_F(APRSParser_parseAPRSFrame, EmpyString) { + + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("", aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), ""); + EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); + EXPECT_EQ(aprsFrame.getPath().size(), 0U); +} + +TEST_F(APRSParser_parseAPRSFrame, NoSourceCallsign) { + + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame(">APRS::F4ABC Test Message", aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), ""); + EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); + EXPECT_EQ(aprsFrame.getPath().size(), 0U); +} + +TEST_F(APRSParser_parseAPRSFrame, NoDestCallsign) { + + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("N0CALL>::F4ABC Test Message", aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), ""); + EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); + EXPECT_EQ(aprsFrame.getPath().size(), 0U); +} + +TEST_F(APRSParser_parseAPRSFrame, CorrectMessageFrameWithDigipeater) { + + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("N0CALL>APRS,WIDE1-1,WIDE2-2::F4ABC :Test Message", aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ":F4ABC :Test Message"); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "N0CALL"); + EXPECT_EQ(aprsFrame.getType(), APFT_MESSAGE); + EXPECT_EQ(aprsFrame.getPath().size(), 2); + EXPECT_STREQ(aprsFrame.getPath()[0].c_str(), "WIDE1-1"); + EXPECT_STREQ(aprsFrame.getPath()[1].c_str(), "WIDE2-2"); +} + +TEST_F(APRSParser_parseAPRSFrame, CorrectMessageFrameWithoutDigipeater) { + + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("N0CALL>APRS::F4ABC :Test Message", aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ":F4ABC :Test Message"); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "N0CALL"); + EXPECT_EQ(aprsFrame.getType(), APFT_MESSAGE); + EXPECT_EQ(aprsFrame.getPath().size(), 0); +} \ No newline at end of file From cf4a824238e511d732ee3c484c24201adf35f80e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 3 Jan 2022 19:34:28 +0100 Subject: [PATCH 057/201] remove my call from example.cfg --- example.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example.cfg b/example.cfg index becc060..b83f0d6 100644 --- a/example.cfg +++ b/example.cfg @@ -164,7 +164,7 @@ maxDongles=5 [DPlus] enabled=true # There is no reason to disable this maxDongles=5 -login=F4FXL # defaults to gateway callsign +login= # defaults to gateway callsign [DCS] enabled=true # There is no reason to disable this From c7e5b5a655b978c93f7b78de272b4454bf128185 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 3 Jan 2022 19:50:19 +0100 Subject: [PATCH 058/201] add some more validation --- APRSFrame.cpp | 1 + APRSParser.cpp | 3 ++- Tests/APRSParser/parseAPRSFrame.cpp | 13 +++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/APRSFrame.cpp b/APRSFrame.cpp index 70ef101..f5e29e7 100644 --- a/APRSFrame.cpp +++ b/APRSFrame.cpp @@ -41,5 +41,6 @@ void CAPRSFrame::clear() m_source.clear(); m_destination.clear(); m_path.clear(); + m_body.clear(); m_type = APFT_UNKNOWN; } \ No newline at end of file diff --git a/APRSParser.cpp b/APRSParser.cpp index d12076a..4663b79 100644 --- a/APRSParser.cpp +++ b/APRSParser.cpp @@ -67,7 +67,8 @@ void CAPRSParser::setFrameType(CAPRSFrame& frame) switch (body[0]) { case ':': - if(body[10] == ':') + if(body[10] == ':' && std::all_of(body.begin() + 1, body.begin() + 10, + [](char c){ return c == ' ' || c == '-' || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); })) type = APFT_MESSAGE; break; diff --git a/Tests/APRSParser/parseAPRSFrame.cpp b/Tests/APRSParser/parseAPRSFrame.cpp index 2cb44d7..50c2bd1 100644 --- a/Tests/APRSParser/parseAPRSFrame.cpp +++ b/Tests/APRSParser/parseAPRSFrame.cpp @@ -89,4 +89,17 @@ TEST_F(APRSParser_parseAPRSFrame, CorrectMessageFrameWithoutDigipeater) { EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "N0CALL"); EXPECT_EQ(aprsFrame.getType(), APFT_MESSAGE); EXPECT_EQ(aprsFrame.getPath().size(), 0); +} + +TEST_F(APRSParser_parseAPRSFrame, InvalideMessageFrame) { + + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("N0CALL>APRS::F4ABC&@#$:Test Message", aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), ""); + EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); + EXPECT_EQ(aprsFrame.getPath().size(), 0U); } \ No newline at end of file From 0cc9f43bb8e3ba4c290d161ec965327d3899c6b6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 3 Jan 2022 22:34:01 +0100 Subject: [PATCH 059/201] #12 Add formater and start using it --- APRSFormater.cpp | 54 +++++++++++++ APRSFormater.h | 27 +++++++ APRSFrame.cpp | 4 +- APRSFrame.h | 4 +- APRSParser.cpp | 33 ++++++-- APRSParser.h | 1 + APRSWriter.cpp | 28 ++++--- StringUtils.h | 3 + Tests/APRSFormater/frameToString.cpp | 115 +++++++++++++++++++++++++++ Tests/APRSParser/parseAPRSFrame.cpp | 33 +++++++- 10 files changed, 278 insertions(+), 24 deletions(-) create mode 100644 APRSFormater.cpp create mode 100644 APRSFormater.h create mode 100644 Tests/APRSFormater/frameToString.cpp diff --git a/APRSFormater.cpp b/APRSFormater.cpp new file mode 100644 index 0000000..ecd1f68 --- /dev/null +++ b/APRSFormater.cpp @@ -0,0 +1,54 @@ +/* + * 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 + +#include "APRSFormater.h" +#include "Log.h" +#include "StringUtils.h" + +bool CAPRSFormater::frameToString(std::string& output, CAPRSFrame& frame) +{ + // make sur we have the minimal stuff to build a correct aprs string + if(frame.getSource().empty() + || frame.getDestination().empty() + || frame.getBody().empty()) { + CLog::logWarning("Invalid APRS frame, missing source, destination or body"); + return false; + } + + // std::string path(frame.getPath().size() > 0U ? "," : ""); + // for(auto pathItem : frame.getPath()) { + // path.append(boost::trim_copy(pathItem)).push_back(','); + // } + + // boost::trim_right_if(path, [](char c){ return c == ','; }); + + auto path = boost::join_if(frame.getPath(), ",", [](std::string s) { return !string_is_blank_or_empty(s); }); + + CStringUtils::string_format_in_place(output, "%s>%s%s%s:%s", + frame.getSource().c_str(), + frame.getDestination().c_str(), + path.empty() ? "" : ",", + path.c_str(), + frame.getBody().c_str()); + + return true; +} + diff --git a/APRSFormater.h b/APRSFormater.h new file mode 100644 index 0000000..c42bf0c --- /dev/null +++ b/APRSFormater.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#pragma once + +#include "APRSFrame.h" + +class CAPRSFormater +{ +public: + static bool frameToString(std::string& output, CAPRSFrame& frame); +}; \ No newline at end of file diff --git a/APRSFrame.cpp b/APRSFrame.cpp index f5e29e7..1f8724f 100644 --- a/APRSFrame.cpp +++ b/APRSFrame.cpp @@ -22,15 +22,17 @@ CAPRSFrame::CAPRSFrame() : m_source(), m_destination(), m_path(), +m_body(), m_type(APFT_UNKNOWN) { } -CAPRSFrame::CAPRSFrame(const std::string& source, const std::string& destination, const std::vector& path, APRS_FRAME_TYPE type) : +CAPRSFrame::CAPRSFrame(const std::string& source, const std::string& destination, const std::vector& path, const std::string& body, APRS_FRAME_TYPE type) : m_source(source), m_destination(destination), m_path(), +m_body(body), m_type(type) { m_path.assign(path.begin(), path.end()); diff --git a/APRSFrame.h b/APRSFrame.h index d84a048..c1b9137 100644 --- a/APRSFrame.h +++ b/APRSFrame.h @@ -25,12 +25,14 @@ enum APRS_FRAME_TYPE { APFT_UNKNOWN = 0, APFT_MESSAGE, + APFT_POSITION, + APFT_NMEA, }; class CAPRSFrame { public: CAPRSFrame(); - CAPRSFrame(const std::string& source, const std::string& destination, const std::vector& path, APRS_FRAME_TYPE type); + CAPRSFrame(const std::string& source, const std::string& destination, const std::vector& path, const std::string& body, APRS_FRAME_TYPE type); void clear(); std::string& getSource() { return m_source; } diff --git a/APRSParser.cpp b/APRSParser.cpp index 4663b79..b5ed46d 100644 --- a/APRSParser.cpp +++ b/APRSParser.cpp @@ -20,9 +20,13 @@ #include "Log.h" bool CAPRSParser::parseFrame(const std::string& frameStr, CAPRSFrame& frame) +{ + return parseFrame(frameStr, frame, false); +} +bool CAPRSParser::parseFrame(const std::string& frameStr, CAPRSFrame& frame, bool doNotEnforceFrameType) { frame.clear(); - bool ret = false; + bool ret = doNotEnforceFrameType; if(!frameStr.empty()) { auto pos = frameStr.find_first_of(':'); @@ -44,12 +48,14 @@ bool CAPRSParser::parseFrame(const std::string& frameStr, CAPRSFrame& frame) frame.getBody().assign(body); - setFrameType(frame); - if(frame.getType() == APFT_UNKNOWN) { - CLog::logInfo("Invalid or unsupported APRS frame : %s", frameStr); - } - else { - ret = true; + if(!doNotEnforceFrameType) { + setFrameType(frame); + if(frame.getType() == APFT_UNKNOWN) { + CLog::logInfo("Invalid or unsupported APRS frame : %s", frameStr); + } + else { + ret = true; + } } } } @@ -71,7 +77,18 @@ void CAPRSParser::setFrameType(CAPRSFrame& frame) [](char c){ return c == ' ' || c == '-' || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); })) type = APFT_MESSAGE; break; - + // case '!': + // if(body.length() >= 2U && body[1] == '!') { + // // This is ultimeter 200 weather station + // type = APFT_UNKNOWN; + // break; + // } else { + // type = APFT_POSITION; + // } + // case '=': + // case '/': + // case '@': + // break; default: break; } diff --git a/APRSParser.h b/APRSParser.h index 6d94f09..89d4b7e 100644 --- a/APRSParser.h +++ b/APRSParser.h @@ -27,6 +27,7 @@ class CAPRSParser { public: static bool parseFrame(const std::string& frameStr, CAPRSFrame& frame); + static bool parseFrame(const std::string& frameStr, CAPRSFrame& frame, bool doNotEnforceFrameType); private: static void setFrameType(CAPRSFrame& frame); diff --git a/APRSWriter.cpp b/APRSWriter.cpp index 9af5bc9..a301af5 100644 --- a/APRSWriter.cpp +++ b/APRSWriter.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include "StringUtils.h" #include "Log.h" @@ -28,6 +29,9 @@ #include "DStarDefines.h" #include "Defs.h" #include "Log.h" +#include "APRSFrame.h" +#include "APRSParser.h" +#include "APRSFormater.h" CAPRSWriter::CAPRSWriter(const std::string& hostname, unsigned int port, const std::string& gateway, const std::string& password, const std::string& address) : m_thread(NULL), @@ -127,26 +131,24 @@ void CAPRSWriter::writeData(const std::string& callsign, const CAMBEData& data) unsigned int length = collector->getData(SLOW_DATA_TYPE_GPS, buffer, 400U); std::string text((char*)buffer, length); - auto n = text.find(':'); - if (n == std::string::npos) { + CAPRSFrame frame; + if(!CAPRSParser::parseFrame(text, frame, true)) { collector->reset(); + CLog::logWarning("Failed to parse DPRS Frame : %s", text.c_str()); return; } - std::string header = text.substr(0, n); - std::string body = text.substr(n + 1U); - // If we already have a q-construct, don't send it on - n = header.find('q'); - if (n != std::string::npos) + if(std::any_of(frame.getPath().begin(), frame.getPath().end(), [] (std::string s) { return !s.empty() && s[0] == 'q'; })) { + CLog::logWarning("DPRS Frame already has q construct, not forwarding to APRS-IS: %s", text.c_str()); return; + } - // Remove the trailing \r - n = body.find('\r'); - if (n != std::string::npos) - body = body.substr(0, n); - - std::string output = CStringUtils::string_format("%s,qAR,%s-%s:%s", header.c_str(), entry->getCallsign().c_str(), entry->getBand().c_str(), body.c_str()); + frame.getPath().push_back("qAR"); + frame.getPath().push_back(CStringUtils::string_format("%s-%s", entry->getCallsign().c_str(), entry->getBand().c_str())); + + std::string output ; + CAPRSFormater::frameToString(output, frame); char ascii[500U]; ::memset(ascii, 0x00, 500U); diff --git a/StringUtils.h b/StringUtils.h index 55853b9..ccb7294 100644 --- a/StringUtils.h +++ b/StringUtils.h @@ -21,8 +21,11 @@ #include #include #include +#include #define string_right(s,l) (s.substr(s.length() - l, l)) +#define string_is_blank(s) (std::all_of(s.begin(), s.end(), [](char c) { return c == ' '; })) +#define string_is_blank_or_empty(s) (s.empty() || std::all_of(s.begin(), s.end(), [](char c) { return c == ' '; })) class CStringUtils { public: diff --git a/Tests/APRSFormater/frameToString.cpp b/Tests/APRSFormater/frameToString.cpp new file mode 100644 index 0000000..7b457e4 --- /dev/null +++ b/Tests/APRSFormater/frameToString.cpp @@ -0,0 +1,115 @@ +/* + * 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 + +#include "../../APRSFormater.h" + + class APRSFormater_frameToString : public ::testing::Test { + +}; + +TEST_F(APRSFormater_frameToString, EmptyFrame) { + + CAPRSFrame aprsFrame("", "", { }, "", APFT_UNKNOWN); + std::string output("This should be left untouched if the test succeeds"); + bool retVal = CAPRSFormater::frameToString(output, aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STREQ(output.c_str(), "This should be left untouched if the test succeeds"); +} + +TEST_F(APRSFormater_frameToString, SourceOnly) { + + CAPRSFrame aprsFrame("N0CALL", "", { }, "", APFT_UNKNOWN); + std::string output("This should be left untouched if the test succeeds"); + bool retVal = CAPRSFormater::frameToString(output, aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STREQ(output.c_str(), "This should be left untouched if the test succeeds"); +} + +TEST_F(APRSFormater_frameToString, DestinationOnly) { + + CAPRSFrame aprsFrame("", "APRS", { }, "", APFT_UNKNOWN); + std::string output("This should be left untouched if the test succeeds"); + bool retVal = CAPRSFormater::frameToString(output, aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STREQ(output.c_str(), "This should be left untouched if the test succeeds"); +} + +TEST_F(APRSFormater_frameToString, PathOnly) { + + CAPRSFrame aprsFrame("", "", { "WIDE1-1, WIDE2-1" }, "", APFT_UNKNOWN); + std::string output("This should be left untouched if the test succeeds"); + bool retVal = CAPRSFormater::frameToString(output, aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STREQ(output.c_str(), "This should be left untouched if the test succeeds"); +} + +TEST_F(APRSFormater_frameToString, BodyOnly) { + + CAPRSFrame aprsFrame("", "", { }, "Lorem Ipsum", APFT_UNKNOWN); + std::string output("This should be left untouched if the test succeeds"); + bool retVal = CAPRSFormater::frameToString(output, aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STREQ(output.c_str(), "This should be left untouched if the test succeeds"); +} + +TEST_F(APRSFormater_frameToString, CorrectWithoutPath) { + + CAPRSFrame aprsFrame("N0CALL", "APRS", { }, "Lorem Ipsum", APFT_UNKNOWN); + std::string output("This should NOT be left untouched if the test succeeds"); + bool retVal = CAPRSFormater::frameToString(output, aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STREQ(output.c_str(), "N0CALL>APRS:Lorem Ipsum"); +} + +TEST_F(APRSFormater_frameToString, CorrectWithPath) { + + CAPRSFrame aprsFrame("N0CALL", "APRS", { "WIDE1-1", "WIDE2-2" }, "Lorem Ipsum", APFT_UNKNOWN); + std::string output("This should be left untouched if the test succeeds"); + bool retVal = CAPRSFormater::frameToString(output, aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STREQ(output.c_str(), "N0CALL>APRS,WIDE1-1,WIDE2-2:Lorem Ipsum"); +} + +TEST_F(APRSFormater_frameToString, WithSomeEmptyPath) { + + CAPRSFrame aprsFrame("N0CALL", "APRS", { "WIDE1-1", "", "WIDE2-2" }, "Lorem Ipsum", APFT_UNKNOWN); + std::string output("This should be left untouched if the test succeeds"); + bool retVal = CAPRSFormater::frameToString(output, aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STREQ(output.c_str(), "N0CALL>APRS,WIDE1-1,WIDE2-2:Lorem Ipsum"); +} + +TEST_F(APRSFormater_frameToString, WithSomeBlankPath) { + + CAPRSFrame aprsFrame("N0CALL", "APRS", { "WIDE1-1", "", "WIDE2-2" }, "Lorem Ipsum", APFT_UNKNOWN); + std::string output("This should be left untouched if the test succeeds"); + bool retVal = CAPRSFormater::frameToString(output, aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STREQ(output.c_str(), "N0CALL>APRS,WIDE1-1,WIDE2-2:Lorem Ipsum"); +} \ No newline at end of file diff --git a/Tests/APRSParser/parseAPRSFrame.cpp b/Tests/APRSParser/parseAPRSFrame.cpp index 50c2bd1..2c0dd71 100644 --- a/Tests/APRSParser/parseAPRSFrame.cpp +++ b/Tests/APRSParser/parseAPRSFrame.cpp @@ -91,7 +91,7 @@ TEST_F(APRSParser_parseAPRSFrame, CorrectMessageFrameWithoutDigipeater) { EXPECT_EQ(aprsFrame.getPath().size(), 0); } -TEST_F(APRSParser_parseAPRSFrame, InvalideMessageFrame) { +TEST_F(APRSParser_parseAPRSFrame, InvalidMessageFrame) { CAPRSFrame aprsFrame; bool retVal = CAPRSParser::parseFrame("N0CALL>APRS::F4ABC&@#$:Test Message", aprsFrame); @@ -102,4 +102,35 @@ TEST_F(APRSParser_parseAPRSFrame, InvalideMessageFrame) { EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), ""); EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); EXPECT_EQ(aprsFrame.getPath().size(), 0U); +} + +TEST_F(APRSParser_parseAPRSFrame, ValidFrameDoNotEnforceType) { + + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("N0CALL>APRS,WIDE1-1,WIDE2-2:Lorem Ipsum", aprsFrame, true); + + EXPECT_TRUE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), "Lorem Ipsum"); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "N0CALL"); + EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); + EXPECT_EQ(aprsFrame.getPath().size(), 2); + EXPECT_STREQ(aprsFrame.getPath()[0].c_str(), "WIDE1-1"); + EXPECT_STREQ(aprsFrame.getPath()[1].c_str(), "WIDE2-2"); +} + +// + +TEST_F(APRSParser_parseAPRSFrame, ID51) { + + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("F4FXL-8>API51,DSTAR:!1234.51N/12345.42E[/A=000886QRV DStar\r\r\n", aprsFrame, true); + + EXPECT_TRUE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), "!4849.51N/00736.42E[/A=000886QRV DStar\r\r\n"); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "API51"); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "F4FXL-8"); + EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); + EXPECT_EQ(aprsFrame.getPath().size(), 1); + EXPECT_STREQ(aprsFrame.getPath()[0].c_str(), "DSTAR"); } \ No newline at end of file From 2b7dbc27aa1e1637b0e8b99023e421ff27a7bbad Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 3 Jan 2022 22:42:46 +0100 Subject: [PATCH 060/201] Add CircleCI to readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 03d5df7..c71067c 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ - [3.7. Configuring](#37-configuring) - [4. Contributing](#4-contributing) - [4.1. Work Flow](#41-work-flow) + - [4.2. Continuous Integration](#42-continuous-integration) - [5. Version History](#5-version-history) - [5.1. Version 0.5](#51-version-05) - [5.2. Version 0.4](#52-version-04) @@ -110,6 +111,10 @@ I Use [Git flow](https://danielkummer.github.io/git-flow-cheatsheet/) as my work - You have tested your code thoroughly - Compilation produces no warnings - Code formating rules are observed (these are very lousy though) +## 4.2. Continuous Integration +I have added some basic CI using CircleCI [![F4FXL](https://circleci.com/gh/F4FXL/DStarGateway.svg?style=svg)](https://app.circleci.com/pipelines/github/F4FXL/DStarGateway?filter=all) I am trying to rewrite the code so that it can be put into some Behavior Driven Development scheme. This is a long haul task and I'll try do do it on the go while changing/adding stuff. +the testing framwrok used is Google Test. + # 5. Version History ## 5.1. Version 0.5 - [Bugfix] Trying to connect to ghost ircDDB when no ircDDB is configured From e7c1abafd76e61be7109fdb319b387cd67ae880b Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 3 Jan 2022 22:48:28 +0100 Subject: [PATCH 061/201] Fix test --- Tests/APRSParser/parseAPRSFrame.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/APRSParser/parseAPRSFrame.cpp b/Tests/APRSParser/parseAPRSFrame.cpp index 2c0dd71..4f48e82 100644 --- a/Tests/APRSParser/parseAPRSFrame.cpp +++ b/Tests/APRSParser/parseAPRSFrame.cpp @@ -124,10 +124,10 @@ TEST_F(APRSParser_parseAPRSFrame, ValidFrameDoNotEnforceType) { TEST_F(APRSParser_parseAPRSFrame, ID51) { CAPRSFrame aprsFrame; - bool retVal = CAPRSParser::parseFrame("F4FXL-8>API51,DSTAR:!1234.51N/12345.42E[/A=000886QRV DStar\r\r\n", aprsFrame, true); + bool retVal = CAPRSParser::parseFrame("F4FXL-8>API51,DSTAR:!1234.56N/12345.67E[/A=000886QRV DStar\r\r\n", aprsFrame, true); EXPECT_TRUE(retVal); - EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), "!4849.51N/00736.42E[/A=000886QRV DStar\r\r\n"); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), "!1234.56N/12345.67E[/A=000886QRV DStar\r\r\n"); EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "API51"); EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "F4FXL-8"); EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); From 43304c48b7c6e5c63404ae89bb5b2c3a393cce21 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 4 Jan 2022 19:08:42 +0100 Subject: [PATCH 062/201] #13 add replacement for wxINT32_SWAP_ON_BE macro --- README.md | 1 + RemoteHandler.cpp | 1 + RemoteProtocolHandler.cpp | 18 ++++++++++-------- Tests/Utils/swap_endian.cpp | 33 +++++++++++++++++++++++++++++++++ Tests/Utils/swap_endian_be.cpp | 34 ++++++++++++++++++++++++++++++++++ Utils.h | 21 +++++++++++++++++++++ 6 files changed, 100 insertions(+), 8 deletions(-) create mode 100644 Tests/Utils/swap_endian.cpp create mode 100644 Tests/Utils/swap_endian_be.cpp diff --git a/README.md b/README.md index c71067c..488ce96 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ the testing framwrok used is Google Test. # 5. Version History ## 5.1. Version 0.5 +- [Bugfix] Remote control connection failed ([#13](https://github.com/F4FXL/DStarGateway/issues/13)) - [Bugfix] Trying to connect to ghost ircDDB when no ircDDB is configured ## 5.2. Version 0.4 - [Improvement] Add APRS status link feature ([#8](https://github.com/F4FXL/DStarGateway/issues/8)) diff --git a/RemoteHandler.cpp b/RemoteHandler.cpp index d4f4df2..7372e98 100644 --- a/RemoteHandler.cpp +++ b/RemoteHandler.cpp @@ -62,6 +62,7 @@ void CRemoteHandler::process() m_handler.sendRandom(m_random); break; case RPHT_HASH: { + CLog::logTrace("Read Hash %X", m_random); bool valid = m_handler.readHash(m_password, m_random); if (valid) { CLog::logInfo("Remote control user has logged in"); diff --git a/RemoteProtocolHandler.cpp b/RemoteProtocolHandler.cpp index e4857b2..0c6a026 100644 --- a/RemoteProtocolHandler.cpp +++ b/RemoteProtocolHandler.cpp @@ -25,6 +25,7 @@ #include "SHA256.h" #include "Utils.h" #include "StringUtils.h" +#include "Log.h" const unsigned int BUFFER_LENGTH = 2000U; @@ -226,7 +227,7 @@ bool CRemoteProtocolHandler::readLink(std::string& callsign, RECONNECT& reconnec int32_t temp; ::memcpy(&temp, m_inBuffer + 3U + LONG_CALLSIGN_LENGTH, sizeof(int32_t)); - reconnect = RECONNECT(CUtils::swap_endian(temp)); + reconnect = RECONNECT(CUtils::swap_endian_be(temp)); reflector = std::string((char*)(m_inBuffer + 3U + LONG_CALLSIGN_LENGTH + sizeof(int32_t)),LONG_CALLSIGN_LENGTH); @@ -245,7 +246,7 @@ bool CRemoteProtocolHandler::readUnlink(std::string& callsign, PROTOCOL& protoco int32_t temp; ::memcpy(&temp, m_inBuffer + 3U + LONG_CALLSIGN_LENGTH, sizeof(int32_t)); - protocol = PROTOCOL(CUtils::swap_endian(temp)); + protocol = PROTOCOL(CUtils::swap_endian_be(temp)); reflector = std::string((char*)(m_inBuffer + 3U + LONG_CALLSIGN_LENGTH + sizeof(int32_t)),LONG_CALLSIGN_LENGTH); @@ -315,7 +316,7 @@ bool CRemoteProtocolHandler::sendRepeater(const CRemoteRepeaterData& data) p[i] = data.getCallsign()[i]; p += LONG_CALLSIGN_LENGTH; - int32_t reconnect = CUtils::swap_endian(data.getReconnect()); + int32_t reconnect = CUtils::swap_endian_be(data.getReconnect()); ::memcpy(p, &reconnect, sizeof(int32_t)); p += sizeof(int32_t); @@ -332,19 +333,19 @@ bool CRemoteProtocolHandler::sendRepeater(const CRemoteRepeaterData& data) p[i] = link->getCallsign()[i]; p += LONG_CALLSIGN_LENGTH; - int32_t protocol = CUtils::swap_endian(link->getProtocol()); + int32_t protocol = CUtils::swap_endian_be(link->getProtocol()); ::memcpy(p, &protocol, sizeof(int32_t)); p += sizeof(int32_t); - int32_t linked = CUtils::swap_endian(link->isLinked()); + int32_t linked = CUtils::swap_endian_be(link->isLinked()); ::memcpy(p, &linked, sizeof(int32_t)); p += sizeof(int32_t); - int32_t direction = CUtils::swap_endian(link->getDirection()); + int32_t direction = CUtils::swap_endian_be(link->getDirection()); ::memcpy(p, &direction, sizeof(int32_t)); p += sizeof(int32_t); - int32_t dongle = CUtils::swap_endian(link->isDongle()); + int32_t dongle = CUtils::swap_endian_be(link->isDongle()); ::memcpy(p, &dongle, sizeof(int32_t)); p += sizeof(int32_t); } @@ -440,7 +441,8 @@ bool CRemoteProtocolHandler::sendRandom(uint32_t random) { ::memcpy(m_outBuffer + 0U, "RND", 3U); - uint32_t temp = CUtils::swap_endian(random); + CLog::logTrace("Send Random %X", random); + uint32_t temp = CUtils::swap_endian_be(random); ::memcpy(m_outBuffer + 3U, &temp, sizeof(uint32_t)); // CUtils::dump("Outgoing", m_outBuffer, 3U + sizeof(uint32_t)); diff --git a/Tests/Utils/swap_endian.cpp b/Tests/Utils/swap_endian.cpp new file mode 100644 index 0000000..767d10e --- /dev/null +++ b/Tests/Utils/swap_endian.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021 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 + +#include "../../Utils.h" + +class Utils_swap_endian : public ::testing::Test { + +}; + +TEST_F(Utils_swap_endian, SwapUINT32) { + uint32_t test = 0x12345678U; + + uint32_t res = CUtils::swap_endian(test); + + EXPECT_EQ(res, 0x78563412U); +} \ No newline at end of file diff --git a/Tests/Utils/swap_endian_be.cpp b/Tests/Utils/swap_endian_be.cpp new file mode 100644 index 0000000..7099a0e --- /dev/null +++ b/Tests/Utils/swap_endian_be.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 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 + +#include "../../Utils.h" + +class Utils_swap_endian_be : public ::testing::Test { + +}; + +// This test will fail on big endian systems.... +TEST_F(Utils_swap_endian_be, SwapUINT32_be) { + uint32_t test = 0x12345678U; + + uint32_t res = CUtils::swap_endian_be(test); + + EXPECT_EQ(res, 0x12345678U); +} \ No newline at end of file diff --git a/Utils.h b/Utils.h index 61fa0fb..0e60527 100644 --- a/Utils.h +++ b/Utils.h @@ -66,4 +66,25 @@ public: return dest.u; } + + // https://stackoverflow.com/questions/1001307/detecting-endianness-programmatically-in-a-c-program + static bool is_big_endian() + { + union { + uint32_t i; + char c[4]; + } bint = {0x01020304}; + + return bint.c[0] == 1; + } + + // Ersatz for macro wxINT32_SWAP_ON_BE + template + static T swap_endian_be(T u) + { + if(is_big_endian()) + return swap_endian(u); + + return u; + } }; From 9a9790f30ee4a87bca07d85bc063959a97fc8f72 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 4 Jan 2022 20:19:53 +0100 Subject: [PATCH 063/201] #13 clean up --- SlowDataCollector.cpp | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/SlowDataCollector.cpp b/SlowDataCollector.cpp index b651ae7..004226e 100644 --- a/SlowDataCollector.cpp +++ b/SlowDataCollector.cpp @@ -69,24 +69,6 @@ bool CSlowDataCollector::writeData(const unsigned char* data) break; } - // unsigned char rxDataType = (m_buffer[0] & SLOW_DATA_TYPE_MASK); - - // switch (rxDataType) - // { - // case SLOW_DATA_TYPE_MASK: CLog::logDebug("SLOW_DATA_TYPE_MASK "); break; - // case SLOW_DATA_TYPE_GPS: CLog::logDebug("SLOW_DATA_TYPE_GPS "); break; - // case SLOW_DATA_TYPE_TEXT: CLog::logDebug("SLOW_DATA_TYPE_TEXT "); break; - // case SLOW_DATA_TYPE_HEADER: CLog::logDebug("SLOW_DATA_TYPE_HEADER "); break; - // case SLOW_DATA_TYPE_MESSAGE: CLog::logDebug("SLOW_DATA_TYPE_MESSAGE "); break; - // case SLOW_DATA_TYPE_FAST_DATA1: CLog::logDebug("SLOW_DATA_TYPE_FAST_DATA1 "); break; - // case SLOW_DATA_TYPE_FAST_DATA2: CLog::logDebug("SLOW_DATA_TYPE_FAST_DATA2 "); break; - // case SLOW_DATA_TYPE_SQUELCH: CLog::logDebug("SLOW_DATA_TYPE_SQUELCH "); break; - // case SLOW_DATA_LENGTH_MASK: CLog::logDebug("SLOW_DATA_LENGTH_MASK "); break; - // default: - // CLog::logDebug("!!!!!!!!!!!!!!! %X", rxDataType); - // break; - // }; - if((m_buffer[0] & SLOW_DATA_TYPE_MASK) == m_slowDataType) return addData(m_buffer + 1U); From 8cf946e4e9e58b5abb139ea68c9470e67f647e8d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Jan 2022 16:52:36 +0100 Subject: [PATCH 064/201] Always build with GPS d --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e148e64..c0f8117 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,10 +21,10 @@ jobs: sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev - run: name: "Build App" - command: "make -j 3 dstargateway" + command: "make -j 3 dstargateway USE_GPSD=1" - run: name: "Build Tests" - command: "make -j 3 tests" + command: "make -j 3 tests USE_GPSD=1" - run: name: "Run Tests" command: "make run-tests" From afc3d11621f9e42d71deab777ec3611ef4bcc50a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Jan 2022 16:54:45 +0100 Subject: [PATCH 065/201] also install libgps as prerequisite --- .vscode/tasks.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2fa8b11..f50a809 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -10,7 +10,10 @@ "args": [ "-j3" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] }, { @@ -21,10 +24,7 @@ "-j3", "tests" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] } ] From c9ac1e7a51e2065c11e29b3daa196787959ea58d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Jan 2022 16:56:21 +0100 Subject: [PATCH 066/201] Add libgps-dev --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c0f8117..ac19a68 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -18,7 +18,7 @@ jobs: name: Install dependencies command: | sudo apt-get update - sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev + sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev libgps-dev - run: name: "Build App" command: "make -j 3 dstargateway USE_GPSD=1" From 525dccec6cf6b5be824d2e81b8cb5e78a2f4c440 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Jan 2022 17:46:27 +0100 Subject: [PATCH 067/201] Change task to build with GPSD --- .vscode/tasks.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index f50a809..74133c5 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -8,7 +8,7 @@ "type": "shell", "command": "make", "args": [ - "-j3" + "-j3", "USE_GPSD=1" ], "group": { "kind": "build", From 0b6d9e560e9aff697e49c975bda0c15e0b72df36 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Jan 2022 17:47:07 +0100 Subject: [PATCH 068/201] #12 Improve Writeline --- TCPReaderWriterClient.cpp | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/TCPReaderWriterClient.cpp b/TCPReaderWriterClient.cpp index e21da7a..624cb51 100644 --- a/TCPReaderWriterClient.cpp +++ b/TCPReaderWriterClient.cpp @@ -201,19 +201,15 @@ bool CTCPReaderWriterClient::write(const unsigned char* buffer, unsigned int len bool CTCPReaderWriterClient::writeLine(const std::string& line) { - std::string lineCopy(line); - if(lineCopy.size() > 0 && lineCopy.at(lineCopy.size() - 1) != '\n') - lineCopy.push_back('\n'); - - //stupidly write one char after the other - size_t len = lineCopy.size(); - bool result = true; - for(size_t i = 0; i < len && result; i++){ - unsigned char c = lineCopy.at(i); - result = write(&c , 1); - } + if(line.empty()) + return true; + + bool ret = write((unsigned char *)line.c_str(), line.length()); + + if(line[line.length() - 1] != '\n')//make sure we send a newline + ret = writeLine("\n") && ret; - return result; + return ret; } void CTCPReaderWriterClient::close() From 59f7e51701c953909f4b743450a4457597b3a71d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Jan 2022 17:47:24 +0100 Subject: [PATCH 069/201] #13 use APRSFrame everywhere --- APRSFixedIdFrameProvider.cpp | 23 ++++++++++++++------- APRSFixedIdFrameProvider.h | 2 +- APRSFrame.h | 2 ++ APRSGPSDIdFrameProvider.cpp | 36 ++++++++++++++++++--------------- APRSGPSDIdFrameProvider.h | 2 +- APRSIdFrameProvider.cpp | 2 +- APRSIdFrameProvider.h | 5 +++-- APRSWriter.cpp | 28 ++++++++++++++------------ APRSWriterThread.cpp | 39 ++++++++++++++++++------------------ APRSWriterThread.h | 5 +++-- ReadAPRSFrameCallback.h | 4 +++- RingBuffer.h | 2 -- 12 files changed, 85 insertions(+), 65 deletions(-) diff --git a/APRSFixedIdFrameProvider.cpp b/APRSFixedIdFrameProvider.cpp index c75cbe9..9434175 100644 --- a/APRSFixedIdFrameProvider.cpp +++ b/APRSFixedIdFrameProvider.cpp @@ -29,7 +29,7 @@ CAPRSIdFrameProvider(20U) // Initial timeout of 20 seconds } -bool CAPRSFixedIdFrameProvider::buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * entry, std::vector& frames) +bool CAPRSFixedIdFrameProvider::buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * entry, std::vector& frames) { if (entry == nullptr) return false; @@ -107,24 +107,33 @@ bool CAPRSFixedIdFrameProvider::buildAPRSFramesInt(const std::string& gateway, c boost::replace_all(lat, ",", "."); boost::replace_all(lon, ",", "."); - std::string output = CStringUtils::string_format("%s-S>APD5T1,TCPIP*,qAC,%s-GS:;%-7s%-2s*%02d%02d%02dz%s%cD%s%caRNG%04.0lf/A=%06.0lf %s %s\r\n", - gateway.c_str(), gateway.c_str(), entry->getCallsign().c_str(), entry->getBand().c_str(), + std::string body = CStringUtils::string_format(";%-7s%-2s*%02d%02d%02dz%s%cD%s%caRNG%04.0lf/A=%06.0lf %s %s\r\n", + entry->getCallsign().c_str(), entry->getBand().c_str(), tm->tm_mday, tm->tm_hour, tm->tm_min, lat.c_str(), (entry->getLatitude() < 0.0F) ? 'S' : 'N', lon.c_str(), (entry->getLongitude() < 0.0F) ? 'W' : 'E', entry->getRange() * 0.6214, entry->getAGL() * 3.28, band.c_str(), desc.c_str()); + CAPRSFrame * frame = new CAPRSFrame(gateway + "-S", + "APD5T1", + { "TCPIP*", "qAC" , gateway + "-GS" }, + body, APFT_OBJECT); - frames.push_back(output); + frames.push_back(frame); if (entry->getBand().length() == 1U) { - output = CStringUtils::string_format("%s-%s>APD5T2,TCPIP*,qAC,%s-%sS:!%s%cD%s%c&RNG%04.0lf/A=%06.0lf %s %s\r\n", - entry->getCallsign().c_str(), entry->getBand().c_str(), entry->getCallsign().c_str(), entry->getBand().c_str(), + body = CStringUtils::string_format("!%s%cD%s%c&RNG%04.0lf/A=%06.0lf %s %s\r\n", lat.c_str(), (entry->getLatitude() < 0.0F) ? 'S' : 'N', lon.c_str(), (entry->getLongitude() < 0.0F) ? 'W' : 'E', entry->getRange() * 0.6214, entry->getAGL() * 3.28, band.c_str(), desc.c_str()); - frames.push_back(output); + frame = new CAPRSFrame(entry->getCallsign() + "-" + entry->getBand(), + "APD5T2", + { "TCPIP*", "qAC", entry->getCallsign() + "-" + entry->getBand() + "S"}, + body, APFT_POSITION); + + + frames.push_back(frame); } setTimeout(20U * 60U);//20 minutes, plenty enough for fixed diff --git a/APRSFixedIdFrameProvider.h b/APRSFixedIdFrameProvider.h index d3bbc3d..8fa7032 100644 --- a/APRSFixedIdFrameProvider.h +++ b/APRSFixedIdFrameProvider.h @@ -26,5 +26,5 @@ public: CAPRSFixedIdFrameProvider(); protected: - virtual bool buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * aprsEntry, std::vector& frames); + virtual bool buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * aprsEntry, std::vector& frames); }; diff --git a/APRSFrame.h b/APRSFrame.h index c1b9137..6105821 100644 --- a/APRSFrame.h +++ b/APRSFrame.h @@ -27,6 +27,8 @@ enum APRS_FRAME_TYPE { APFT_MESSAGE, APFT_POSITION, APFT_NMEA, + APFT_STATUS, + APFT_OBJECT }; class CAPRSFrame { diff --git a/APRSGPSDIdFrameProvider.cpp b/APRSGPSDIdFrameProvider.cpp index 3a02916..f67f634 100644 --- a/APRSGPSDIdFrameProvider.cpp +++ b/APRSGPSDIdFrameProvider.cpp @@ -16,7 +16,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifdef USE_DGPS +#ifdef USE_GPSD #include #include @@ -56,7 +56,7 @@ void CAPRSGPSDIdFrameProvider::close() } } -bool CAPRSGPSDIdFrameProvider::buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * entry, std::vector& frames) +bool CAPRSGPSDIdFrameProvider::buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * entry, std::vector& frames) { if(!m_hasConnection) { this->start(); @@ -169,40 +169,44 @@ bool CAPRSGPSDIdFrameProvider::buildAPRSFramesInt(const std::string& gateway, co boost::replace_all(lat, ",", "."); boost::replace_all(lon, ",", "."); - std::string output1 = CStringUtils::string_format("%s-S>APD5T1,TCPIP*,qAC,%s-GS:;%-7s%-2s*%02d%02d%02dz%s%cD%s%ca/A=%06.0lf", - gateway.c_str(), gateway.c_str(), entry->getCallsign().c_str(), entry->getBand().c_str(), + std::string body = CStringUtils::string_format(";%-7s%-2s*%02d%02d%02dz%s%cD%s%ca/A=%06.0lf", + entry->getCallsign().c_str(), entry->getBand().c_str(), tm->tm_mday, tm->tm_hour, tm->tm_min, lat.c_str(), (rawLatitude < 0.0) ? 'S' : 'N', lon.c_str(), (rawLongitude < 0.0) ? 'W' : 'E', rawAltitude * 3.28); - std::string output2; if (bearingSet && velocitySet) - output2 = CStringUtils::string_format("%03.0lf/%03.0lf", rawBearing, rawVelocity * 0.539957F); + body.append(CStringUtils::string_format("%03.0lf/%03.0lf", rawBearing, rawVelocity * 0.539957F)); - std::string output3; - output3 = CStringUtils::string_format("RNG%04.0lf %s %s\r\n", entry->getRange() * 0.6214, band.c_str(), desc.c_str()); + body.append(CStringUtils::string_format("RNG%04.0lf %s %s\r\n", entry->getRange() * 0.6214, band.c_str(), desc.c_str())); - CLog::logDebug("APRS ==> %s%s%s", output1.c_str(), output2.c_str(), output3.c_str()); - frames.push_back(output1.append(output2).append(output3)); + CAPRSFrame * frame = new CAPRSFrame(gateway + "-S", + "APD5T1", + { "TCPIP*", "qAC" , gateway + "-GS" }, + body, APFT_OBJECT); + + + frames.push_back(frame); if (entry->getBand().length() == 1U) { if (altitudeSet) - output1 = CStringUtils::string_format("%s-%s>APD5T2,TCPIP*,qAC,%s-%sS:!%s%cD%s%c&/A=%06.0lf", - entry->getCallsign().c_str(), entry->getBand().c_str(), entry->getCallsign().c_str(), entry->getBand().c_str(), + body = CStringUtils::string_format("%s%cD%s%c&/A=%06.0lf", lat.c_str(), (rawLatitude < 0.0) ? 'S' : 'N', lon.c_str(), (rawLongitude < 0.0) ? 'W' : 'E', rawAltitude * 3.28); else - output1 = CStringUtils::string_format("%s-%s>APD5T2,TCPIP*,qAC,%s-%sS:!%s%cD%s%c&", - entry->getCallsign().c_str(), entry->getBand().c_str(), entry->getCallsign().c_str(), entry->getBand().c_str(), + body = CStringUtils::string_format("!%s%cD%s%c&", lat.c_str(), (rawLatitude < 0.0) ? 'S' : 'N', lon.c_str(), (rawLongitude < 0.0) ? 'W' : 'E'); - CLog::logDebug("APRS ==> %s%s%s", output1.c_str(), output2.c_str(), output3.c_str()); + frame = new CAPRSFrame(gateway, + "APD5T2", + { "TCPIP*", "qAC" , gateway + "-GS" }, + body, APFT_POSITION); - frames.push_back(output1.append(output2).append(output3)); + frames.push_back(frame); } setTimeout(60U * 5U);//5 Minutes is plenty enough we aint an APRS tracker ! diff --git a/APRSGPSDIdFrameProvider.h b/APRSGPSDIdFrameProvider.h index 77ca4b9..e982f9b 100644 --- a/APRSGPSDIdFrameProvider.h +++ b/APRSGPSDIdFrameProvider.h @@ -35,7 +35,7 @@ public: virtual void close(); protected: - virtual bool buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * aprsEntry, std::vector& frames); + virtual bool buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * aprsEntry, std::vector& frames); private: std::string m_gpsdAddress; diff --git a/APRSIdFrameProvider.cpp b/APRSIdFrameProvider.cpp index 503720a..3637f9d 100644 --- a/APRSIdFrameProvider.cpp +++ b/APRSIdFrameProvider.cpp @@ -31,7 +31,7 @@ CAPRSIdFrameProvider::~CAPRSIdFrameProvider() } -bool CAPRSIdFrameProvider::buildAPRSFrames(const std::string& gateway, const CAPRSEntry * entry, std::vector & frames) +bool CAPRSIdFrameProvider::buildAPRSFrames(const std::string& gateway, const CAPRSEntry * entry, std::vector & frames) { assert(entry != nullptr); diff --git a/APRSIdFrameProvider.h b/APRSIdFrameProvider.h index f83deb7..48917ee 100644 --- a/APRSIdFrameProvider.h +++ b/APRSIdFrameProvider.h @@ -22,6 +22,7 @@ #include "Timer.h" #include "APRSEntry.h" +#include "APRSFrame.h" class CAPRSIdFrameProvider { @@ -29,14 +30,14 @@ public: CAPRSIdFrameProvider(unsigned int timeOut); virtual ~CAPRSIdFrameProvider(); - bool buildAPRSFrames(const std::string& gateway, const CAPRSEntry * aprsEntry, std::vector& frames); + bool buildAPRSFrames(const std::string& gateway, const CAPRSEntry * aprsEntry, std::vector& frames); void clock(unsigned int ms) { m_timer.clock(ms); } bool wantsToSend(); virtual void start() { }; virtual void close() { }; protected: - virtual bool buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * aprsEntry, std::vector& frames) = 0; + virtual bool buildAPRSFramesInt(const std::string& gateway, const CAPRSEntry * aprsEntry, std::vector& frames) = 0; void setTimeout(unsigned int timeout) { diff --git a/APRSWriter.cpp b/APRSWriter.cpp index a301af5..cc122ee 100644 --- a/APRSWriter.cpp +++ b/APRSWriter.cpp @@ -32,6 +32,7 @@ #include "APRSFrame.h" #include "APRSParser.h" #include "APRSFormater.h" +#include "APRSUtils.h" CAPRSWriter::CAPRSWriter(const std::string& hostname, unsigned int port, const std::string& gateway, const std::string& password, const std::string& address) : m_thread(NULL), @@ -150,12 +151,7 @@ void CAPRSWriter::writeData(const std::string& callsign, const CAMBEData& data) std::string output ; CAPRSFormater::frameToString(output, frame); - char ascii[500U]; - ::memset(ascii, 0x00, 500U); - for (unsigned int i = 0U; i < output.length(); i++) - ascii[i] = output[i]; - - m_thread->write(ascii); + m_thread->write(frame); collector->reset(); } @@ -198,17 +194,22 @@ void CAPRSWriter::sendStatusFrame(CAPRSEntry * entry) if(!m_thread->isConnected()) return; + auto linkStatus = entry->getStatus(); std::string body = boost::trim_copy(linkStatus.getStatus()); if(body[0] != '>') - body = '>' + body; + body.insert(0, ">"); - std::string output = CStringUtils::string_format("%s-%s>APD5T3,TCPIP*,qAC,%s-%sS:%s\r\n", - entry->getCallsign().c_str(), entry->getBand().c_str(), entry->getCallsign().c_str(), entry->getBand().c_str(), - body.c_str()); + std::string sourCall = entry->getCallsign() + '-' + entry->getBand(); + + CAPRSFrame frame(sourCall, + "APD5T3", + { "TCPIP*", "qAC", sourCall + "S" }, + linkStatus.getStatus(), + APFT_STATUS); - m_thread->write(output.c_str()); + m_thread->write(frame); } @@ -217,10 +218,11 @@ void CAPRSWriter::sendIdFrames() if(m_thread->isConnected()) { for(auto entry : m_array) { - std::vector frames; + std::vector frames; if(m_idFrameProvider->buildAPRSFrames(m_gateway, entry.second, frames)) { for(auto frame : frames) { - m_thread->write(frame.c_str()); + m_thread->write(*frame); + delete frame; } } } diff --git a/APRSWriterThread.cpp b/APRSWriterThread.cpp index aa2462b..c029957 100644 --- a/APRSWriterThread.cpp +++ b/APRSWriterThread.cpp @@ -27,6 +27,8 @@ #include "Defs.h" #include "Log.h" #include "Version.h" +#include "APRSFormater.h" +#include "APRSParser.h" // #define DUMP_TX @@ -139,22 +141,17 @@ void* CAPRSWriterThread::Entry() m_tries = 0U; if(!m_queue.empty()){ - char* p = m_queue.getData(); + auto frameStr = m_queue.getData(); - std::string text(p); - CLog::logInfo("APRS ==> %s", text.c_str()); + CLog::logInfo("APRS ==> %s", frameStr.c_str()); - ::strcat(p, "\r\n"); - - bool ret = m_socket.write((unsigned char*)p, ::strlen(p)); + bool ret = m_socket.writeLine(frameStr); if (!ret) { m_connected = false; m_socket.close(); CLog::logInfo("Connection to the APRS thread has failed"); startReconnectionTimer(); } - - delete[] p; } { std::string line; @@ -176,8 +173,12 @@ void* CAPRSWriterThread::Entry() if(length > 0 && line[0] != '#'//check if we have something and if that something is an APRS frame && m_APRSReadCallback.size() > 0U)//do we have someone wanting an APRS Frame? { - for(auto cb : m_APRSReadCallback) { - cb->readAprsFrame(line); + CAPRSFrame readFrame; + if(CAPRSParser::parseFrame(line, readFrame)) { + for(auto cb : m_APRSReadCallback) { + CAPRSFrame f(readFrame); + cb->readAprsFrame(f); + } } } } @@ -189,8 +190,8 @@ void* CAPRSWriterThread::Entry() m_socket.close(); while (!m_queue.empty()) { - char* p = m_queue.getData(); - delete[] p; + auto s = m_queue.getData(); + s.clear(); } } catch (std::exception& e) { @@ -212,19 +213,19 @@ void CAPRSWriterThread::addReadAPRSCallback(CReadAPRSFrameCallback * cb) m_APRSReadCallback.push_back(cb); } -void CAPRSWriterThread::write(const char* data) +void CAPRSWriterThread::write(CAPRSFrame& frame) { - assert(data != NULL); - if (!m_connected) return; - unsigned int len = ::strlen(data); + std::string frameString; + if(CAPRSFormater::frameToString(frameString, frame)) { - char* p = new char[len + 5U]; - ::strcpy(p, data); + boost::trim_if(frameString, [] (char c) { return c == '\r' || c == '\n'; }); // trim all CRLF, we will add our own, just to make sure we get rid of any garbage that might come from slow data + frameString.append("\r\n"); - m_queue.addData(p); + m_queue.addData(frameString); + } } bool CAPRSWriterThread::isConnected() const diff --git a/APRSWriterThread.h b/APRSWriterThread.h index 2e21f9e..bc58ba4 100644 --- a/APRSWriterThread.h +++ b/APRSWriterThread.h @@ -26,6 +26,7 @@ #include "Timer.h" #include "Thread.h" #include "ReadAPRSFrameCallback.h" +#include "APRSFrame.h" class CAPRSWriterThread : public CThread { @@ -38,7 +39,7 @@ public: bool isConnected() const; - void write(const char* data); + void write(CAPRSFrame& data); void* Entry(); @@ -53,7 +54,7 @@ private: std::string m_password; std::string m_ssid; CTCPReaderWriterClient m_socket; - CRingBuffer m_queue; + CRingBuffer m_queue; bool m_exit; bool m_connected; CTimer m_reconnectTimer; diff --git a/ReadAPRSFrameCallback.h b/ReadAPRSFrameCallback.h index 1b02dc3..9a93193 100644 --- a/ReadAPRSFrameCallback.h +++ b/ReadAPRSFrameCallback.h @@ -20,9 +20,11 @@ #include +#include "APRSFrame.h" + class CReadAPRSFrameCallback { public: virtual ~CReadAPRSFrameCallback(){ } - virtual bool readAprsFrame(const std::string& aprsFrame) = 0; + virtual bool readAprsFrame(CAPRSFrame& aprsFrame) = 0; }; diff --git a/RingBuffer.h b/RingBuffer.h index 3182382..1ff2ab4 100644 --- a/RingBuffer.h +++ b/RingBuffer.h @@ -36,8 +36,6 @@ public: assert(length > 0U); m_buffer = new T[length]; - - ::memset(m_buffer, 0x00, length * sizeof(T)); } ~CRingBuffer() From c3dfa420974290b590a05c60d513aa9c122b3821 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Jan 2022 17:52:47 +0100 Subject: [PATCH 070/201] #12 fix invalid status frame --- APRSWriter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/APRSWriter.cpp b/APRSWriter.cpp index cc122ee..bfb948e 100644 --- a/APRSWriter.cpp +++ b/APRSWriter.cpp @@ -206,7 +206,7 @@ void CAPRSWriter::sendStatusFrame(CAPRSEntry * entry) CAPRSFrame frame(sourCall, "APD5T3", { "TCPIP*", "qAC", sourCall + "S" }, - linkStatus.getStatus(), + body, APFT_STATUS); m_thread->write(frame); From 84be5d84439464e571108395d254b5d105abd053 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Jan 2022 17:57:27 +0100 Subject: [PATCH 071/201] Also run tests with gpsd --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ac19a68..0502fb1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -27,7 +27,7 @@ jobs: command: "make -j 3 tests USE_GPSD=1" - run: name: "Run Tests" - command: "make run-tests" + command: "make run-tests USE_GPSD=1" # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows workflows: From 5e1cfb4d2c8c8e325a909aac35ebe5762de2f421 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Jan 2022 20:10:45 +0100 Subject: [PATCH 072/201] remove newline --- NMEASentenceCollector.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/NMEASentenceCollector.cpp b/NMEASentenceCollector.cpp index 2685625..b368060 100644 --- a/NMEASentenceCollector.cpp +++ b/NMEASentenceCollector.cpp @@ -86,8 +86,7 @@ unsigned int CNMEASentenceCollector::getDataInt(unsigned char * data, unsigned i CAPRSUtils::dstarCallsignToAPRS(fromCall); std::string aprsFrame(fromCall); aprsFrame.append("-5>GPS30,DSTAR*:") - .append(nmea) - .append("\r\n"); + .append(nmea); auto aprsFrameLen = aprsFrame.length(); if(length < aprsFrameLen) { From 6a7cf1a8df2c78492fa3b9b3c66c6573a082c8d9 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Jan 2022 20:11:18 +0100 Subject: [PATCH 073/201] #12 add some more frame types --- .vscode/tasks.json | 6 +- APRSFrame.h | 3 +- APRSParser.cpp | 125 +++++++++++++++++++--------- APRSParser.h | 5 +- APRSWriter.cpp | 2 +- Tests/APRSParser/parseAPRSFrame.cpp | 19 +---- 6 files changed, 96 insertions(+), 64 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 74133c5..2dc1e81 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -8,7 +8,8 @@ "type": "shell", "command": "make", "args": [ - "-j3", "USE_GPSD=1" + "-j3", + "USE_GPSD=1" ], "group": { "kind": "build", @@ -22,7 +23,8 @@ "command": "make", "args": [ "-j3", - "tests" + "tests", + "USE_GPSD=1" ], "group": "build", "problemMatcher": [] diff --git a/APRSFrame.h b/APRSFrame.h index 6105821..6c50eee 100644 --- a/APRSFrame.h +++ b/APRSFrame.h @@ -28,7 +28,8 @@ enum APRS_FRAME_TYPE { APFT_POSITION, APFT_NMEA, APFT_STATUS, - APFT_OBJECT + APFT_OBJECT, + APFT_WX }; class CAPRSFrame { diff --git a/APRSParser.cpp b/APRSParser.cpp index b5ed46d..cdd7b5a 100644 --- a/APRSParser.cpp +++ b/APRSParser.cpp @@ -21,12 +21,8 @@ bool CAPRSParser::parseFrame(const std::string& frameStr, CAPRSFrame& frame) { - return parseFrame(frameStr, frame, false); -} -bool CAPRSParser::parseFrame(const std::string& frameStr, CAPRSFrame& frame, bool doNotEnforceFrameType) -{ frame.clear(); - bool ret = doNotEnforceFrameType; + bool ret = false; if(!frameStr.empty()) { auto pos = frameStr.find_first_of(':'); @@ -48,14 +44,9 @@ bool CAPRSParser::parseFrame(const std::string& frameStr, CAPRSFrame& frame, boo frame.getBody().assign(body); - if(!doNotEnforceFrameType) { - setFrameType(frame); - if(frame.getType() == APFT_UNKNOWN) { - CLog::logInfo("Invalid or unsupported APRS frame : %s", frameStr); - } - else { - ret = true; - } + ret = parseInt(frame); + if(!ret) { + frame.clear(); } } } @@ -64,37 +55,89 @@ bool CAPRSParser::parseFrame(const std::string& frameStr, CAPRSFrame& frame, boo return ret; } -void CAPRSParser::setFrameType(CAPRSFrame& frame) +bool CAPRSParser::parseInt(CAPRSFrame& frame) { APRS_FRAME_TYPE type = APFT_UNKNOWN; - std::string body(frame.getBody()); + unsigned char typeChar = frame.getBody()[0]; + std::string body(frame.getBody().substr(1));//strip the type char for processing purposes + + if(body.empty()) + return false; - if(!body.empty()) { - switch (body[0]) - { - case ':': - if(body[10] == ':' && std::all_of(body.begin() + 1, body.begin() + 10, - [](char c){ return c == ' ' || c == '-' || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); })) - type = APFT_MESSAGE; - break; - // case '!': - // if(body.length() >= 2U && body[1] == '!') { - // // This is ultimeter 200 weather station - // type = APFT_UNKNOWN; - // break; - // } else { - // type = APFT_POSITION; - // } - // case '=': - // case '/': - // case '@': - // break; - default: - break; - } - } + switch (typeChar) + { + case '!': + if(body[0] == '!') { + // This is ultimeter 200 weather station + return false; + } + [[fallthrough]]; + case '=': + case '/': + case '@': + { + if(body.length() < 10) return false;//enough chars to have a chance to parse it ? + /* Normal or compressed location packet, with or without + * timestamp, with or without messaging capability + * + * ! and / have messaging, / and @ have a prepended timestamp + */ + type = APFT_POSITION; + if(typeChar == '/' || typeChar== '@')//With a prepended timestamp, jump over it. + body = body.substr(7U); + auto posChar = body[0]; + if(valid_sym_table_compressed(posChar)//Compressed format + && body.length() >= 13){//we need at least 13 char + //icom unsupported, ignore for now + return false;//parse_aprs_compressed(pb, body, body_end); + } + else if(posChar >= '0' && posChar <= '9' //Normal uncompressed format + && body.length() >=19){//we need at least 19 chars for it to be valid + + // if(ensureIsIcomCompatible(packet)) + // return Parse(packet.Raw(), packet); + } + } + break; + case '$' : + if(body.length() > 10) { + type = APFT_NMEA; + } + break; + case ':': + if(body[9] == ':' && std::all_of(body.begin(), body.begin() + 9, + [](char c){ return c == ' ' || c == '-' || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); })) + type = APFT_MESSAGE; + break; + case '>': + type = APFT_STATUS; + break; + case '#': /* Peet Bros U-II Weather Station */ + case '*': /* Peet Bros U-I Weather Station */ + case '_': /* Weather report without position */ + type = APFT_WX; + break; + case '{': + type = APFT_UNKNOWN; // + break; + default: + type = APFT_UNKNOWN; + break; + } + frame.getType() = type; - if(type == APFT_UNKNOWN) - frame.clear(); + return type != APFT_UNKNOWN; +} + +bool CAPRSParser::valid_sym_table_compressed(unsigned char c) +{ + return (c == '/' || c == '\\' || (c >= 0x41 && c <= 0x5A) + || (c >= 0x61 && c <= 0x6A)); /* [\/\\A-Za-j] */ +} + +bool CAPRSParser::valid_sym_table_uncompressed(unsigned char c) +{ + return (c == '/' || c == '\\' || (c >= 0x41 && c <= 0x5A) + || (c >= 0x30 && c <= 0x39)); /* [\/\\A-Z0-9] */ } \ No newline at end of file diff --git a/APRSParser.h b/APRSParser.h index 89d4b7e..6414ffb 100644 --- a/APRSParser.h +++ b/APRSParser.h @@ -27,8 +27,9 @@ class CAPRSParser { public: static bool parseFrame(const std::string& frameStr, CAPRSFrame& frame); - static bool parseFrame(const std::string& frameStr, CAPRSFrame& frame, bool doNotEnforceFrameType); private: - static void setFrameType(CAPRSFrame& frame); + static bool parseInt(CAPRSFrame& frame); + static bool valid_sym_table_compressed(unsigned char c); + static bool valid_sym_table_uncompressed(unsigned char c); }; \ No newline at end of file diff --git a/APRSWriter.cpp b/APRSWriter.cpp index bfb948e..4e2d1ce 100644 --- a/APRSWriter.cpp +++ b/APRSWriter.cpp @@ -133,7 +133,7 @@ void CAPRSWriter::writeData(const std::string& callsign, const CAMBEData& data) std::string text((char*)buffer, length); CAPRSFrame frame; - if(!CAPRSParser::parseFrame(text, frame, true)) { + if(!CAPRSParser::parseFrame(text, frame)) { collector->reset(); CLog::logWarning("Failed to parse DPRS Frame : %s", text.c_str()); return; diff --git a/Tests/APRSParser/parseAPRSFrame.cpp b/Tests/APRSParser/parseAPRSFrame.cpp index 4f48e82..0263348 100644 --- a/Tests/APRSParser/parseAPRSFrame.cpp +++ b/Tests/APRSParser/parseAPRSFrame.cpp @@ -104,33 +104,18 @@ TEST_F(APRSParser_parseAPRSFrame, InvalidMessageFrame) { EXPECT_EQ(aprsFrame.getPath().size(), 0U); } -TEST_F(APRSParser_parseAPRSFrame, ValidFrameDoNotEnforceType) { - - CAPRSFrame aprsFrame; - bool retVal = CAPRSParser::parseFrame("N0CALL>APRS,WIDE1-1,WIDE2-2:Lorem Ipsum", aprsFrame, true); - - EXPECT_TRUE(retVal); - EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), "Lorem Ipsum"); - EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); - EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "N0CALL"); - EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); - EXPECT_EQ(aprsFrame.getPath().size(), 2); - EXPECT_STREQ(aprsFrame.getPath()[0].c_str(), "WIDE1-1"); - EXPECT_STREQ(aprsFrame.getPath()[1].c_str(), "WIDE2-2"); -} - // TEST_F(APRSParser_parseAPRSFrame, ID51) { CAPRSFrame aprsFrame; - bool retVal = CAPRSParser::parseFrame("F4FXL-8>API51,DSTAR:!1234.56N/12345.67E[/A=000886QRV DStar\r\r\n", aprsFrame, true); + bool retVal = CAPRSParser::parseFrame("F4FXL-8>API51,DSTAR:!1234.56N/12345.67E[/A=000886QRV DStar\r\r\n", aprsFrame); EXPECT_TRUE(retVal); EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), "!1234.56N/12345.67E[/A=000886QRV DStar\r\r\n"); EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "API51"); EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "F4FXL-8"); - EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); + EXPECT_EQ(aprsFrame.getType(), APFT_POSITION); EXPECT_EQ(aprsFrame.getPath().size(), 1); EXPECT_STREQ(aprsFrame.getPath()[0].c_str(), "DSTAR"); } \ No newline at end of file From 6fae94217b04c2fef8f79ada5baba82858ce1297 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Jan 2022 20:15:06 +0100 Subject: [PATCH 074/201] #12 rename variable --- APRSWriterThread.cpp | 14 +++++++------- APRSWriterThread.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/APRSWriterThread.cpp b/APRSWriterThread.cpp index c029957..6b39111 100644 --- a/APRSWriterThread.cpp +++ b/APRSWriterThread.cpp @@ -45,7 +45,7 @@ m_exit(false), m_connected(false), m_reconnectTimer(1000U), m_tries(0U), -m_APRSReadCallback(), +m_APRSReadCallbacks(), m_filter(""), m_clientName(FULL_PRODUCT_NAME) { @@ -72,7 +72,7 @@ m_exit(false), m_connected(false), m_reconnectTimer(1000U), m_tries(0U), -m_APRSReadCallback(), +m_APRSReadCallbacks(), m_filter(filter), m_clientName(clientName) { @@ -91,9 +91,9 @@ m_clientName(clientName) CAPRSWriterThread::~CAPRSWriterThread() { std::vector callBacksCopy; - callBacksCopy.assign(m_APRSReadCallback.begin(), m_APRSReadCallback.end()); + callBacksCopy.assign(m_APRSReadCallbacks.begin(), m_APRSReadCallbacks.end()); - m_APRSReadCallback.clear(); + m_APRSReadCallbacks.clear(); for(auto cb : callBacksCopy) { delete cb; @@ -171,11 +171,11 @@ void* CAPRSWriterThread::Entry() CLog::logDebug("Received APRS Frame : %s", line.c_str()); if(length > 0 && line[0] != '#'//check if we have something and if that something is an APRS frame - && m_APRSReadCallback.size() > 0U)//do we have someone wanting an APRS Frame? + && m_APRSReadCallbacks.size() > 0U)//do we have someone wanting an APRS Frame? { CAPRSFrame readFrame; if(CAPRSParser::parseFrame(line, readFrame)) { - for(auto cb : m_APRSReadCallback) { + for(auto cb : m_APRSReadCallbacks) { CAPRSFrame f(readFrame); cb->readAprsFrame(f); } @@ -210,7 +210,7 @@ void* CAPRSWriterThread::Entry() void CAPRSWriterThread::addReadAPRSCallback(CReadAPRSFrameCallback * cb) { assert(cb != nullptr); - m_APRSReadCallback.push_back(cb); + m_APRSReadCallbacks.push_back(cb); } void CAPRSWriterThread::write(CAPRSFrame& frame) diff --git a/APRSWriterThread.h b/APRSWriterThread.h index bc58ba4..e76b20f 100644 --- a/APRSWriterThread.h +++ b/APRSWriterThread.h @@ -59,7 +59,7 @@ private: bool m_connected; CTimer m_reconnectTimer; unsigned int m_tries; - std::vector m_APRSReadCallback; + std::vector m_APRSReadCallbacks; std::string m_filter; std::string m_clientName; From c56c42d28375c1e8ff0029827a745e09a993ec69 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 5 Jan 2022 20:32:01 +0100 Subject: [PATCH 075/201] #13 rename APRSWriter -> APRSHandler --- APRSWriter.cpp => APRSHandler.cpp | 26 +++++++++++++------------- APRSWriter.h => APRSHandler.h | 11 ++++------- DStarGatewayApp.cpp | 4 ++-- DStarGatewayThread.cpp | 2 +- DStarGatewayThread.h | 6 +++--- RepeaterHandler.cpp | 4 ++-- RepeaterHandler.h | 6 +++--- 7 files changed, 28 insertions(+), 31 deletions(-) rename APRSWriter.cpp => APRSHandler.cpp (85%) rename APRSWriter.h => APRSHandler.h (89%) diff --git a/APRSWriter.cpp b/APRSHandler.cpp similarity index 85% rename from APRSWriter.cpp rename to APRSHandler.cpp index 4e2d1ce..c36e470 100644 --- a/APRSWriter.cpp +++ b/APRSHandler.cpp @@ -25,7 +25,7 @@ #include "StringUtils.h" #include "Log.h" -#include "APRSWriter.h" +#include "APRSHandler.h" #include "DStarDefines.h" #include "Defs.h" #include "Log.h" @@ -34,7 +34,7 @@ #include "APRSFormater.h" #include "APRSUtils.h" -CAPRSWriter::CAPRSWriter(const std::string& hostname, unsigned int port, const std::string& gateway, const std::string& password, const std::string& address) : +CAPRSHandler::CAPRSHandler(const std::string& hostname, unsigned int port, const std::string& gateway, const std::string& password, const std::string& address) : m_thread(NULL), m_gateway(), m_address(), @@ -54,7 +54,7 @@ m_idFrameProvider(nullptr) boost::trim(m_gateway); } -CAPRSWriter::~CAPRSWriter() +CAPRSHandler::~CAPRSHandler() { for(auto it = m_array.begin(); it != m_array.end(); it++) { delete it->second; @@ -63,7 +63,7 @@ CAPRSWriter::~CAPRSWriter() m_array.clear(); } -void CAPRSWriter::setPort(const std::string& callsign, const std::string& band, double frequency, double offset, double range, double latitude, double longitude, double agl) +void CAPRSHandler::setPort(const std::string& callsign, const std::string& band, double frequency, double offset, double range, double latitude, double longitude, double agl) { std::string temp = callsign; temp.resize(LONG_CALLSIGN_LENGTH - 1U, ' '); @@ -72,12 +72,12 @@ void CAPRSWriter::setPort(const std::string& callsign, const std::string& band, m_array[temp] = new CAPRSEntry(callsign, band, frequency, offset, range, latitude, longitude, agl); } -bool CAPRSWriter::open() +bool CAPRSHandler::open() { return m_thread->start(); } -void CAPRSWriter::writeHeader(const std::string& callsign, const CHeaderData& header) +void CAPRSHandler::writeHeader(const std::string& callsign, const CHeaderData& header) { CAPRSEntry* entry = m_array[callsign]; if (entry == NULL) { @@ -92,7 +92,7 @@ void CAPRSWriter::writeHeader(const std::string& callsign, const CHeaderData& he collector->writeHeader(header.getMyCall1()); } -void CAPRSWriter::writeData(const std::string& callsign, const CAMBEData& data) +void CAPRSHandler::writeData(const std::string& callsign, const CAMBEData& data) { if (data.isEnd()) return; @@ -156,7 +156,7 @@ void CAPRSWriter::writeData(const std::string& callsign, const CAMBEData& data) collector->reset(); } -void CAPRSWriter::writeStatus(const std::string& callsign, const std::string status) +void CAPRSHandler::writeStatus(const std::string& callsign, const std::string status) { CAPRSEntry* entry = m_array[callsign]; if (entry == NULL) { @@ -167,7 +167,7 @@ void CAPRSWriter::writeStatus(const std::string& callsign, const std::string sta entry->getStatus().setStatus(status); } -void CAPRSWriter::clock(unsigned int ms) +void CAPRSHandler::clock(unsigned int ms) { m_thread->clock(ms); @@ -187,7 +187,7 @@ void CAPRSWriter::clock(unsigned int ms) } } -void CAPRSWriter::sendStatusFrame(CAPRSEntry * entry) +void CAPRSHandler::sendStatusFrame(CAPRSEntry * entry) { assert(entry != nullptr); @@ -213,7 +213,7 @@ void CAPRSWriter::sendStatusFrame(CAPRSEntry * entry) } -void CAPRSWriter::sendIdFrames() +void CAPRSHandler::sendIdFrames() { if(m_thread->isConnected()) { @@ -229,12 +229,12 @@ void CAPRSWriter::sendIdFrames() } } -bool CAPRSWriter::isConnected() const +bool CAPRSHandler::isConnected() const { return m_thread->isConnected(); } -void CAPRSWriter::close() +void CAPRSHandler::close() { if(m_idFrameProvider != nullptr) { m_idFrameProvider->close(); diff --git a/APRSWriter.h b/APRSHandler.h similarity index 89% rename from APRSWriter.h rename to APRSHandler.h index 3543930..9cfa671 100644 --- a/APRSWriter.h +++ b/APRSHandler.h @@ -17,8 +17,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef APRSWriter_H -#define APRSWriter_H +#pragma once #include "Defs.h" @@ -36,10 +35,10 @@ #include "Timer.h" #include "APRSIdFrameProvider.h" -class CAPRSWriter { +class CAPRSHandler { public: - CAPRSWriter(const std::string& hostname, unsigned int port, const std::string& gateway, const std::string& password, const std::string& address); - ~CAPRSWriter(); + CAPRSHandler(const std::string& hostname, unsigned int port, const std::string& gateway, const std::string& password, const std::string& address); + ~CAPRSHandler(); bool open(); @@ -71,5 +70,3 @@ private: void sendStatusFrame(CAPRSEntry * entrry); }; -#endif - diff --git a/DStarGatewayApp.cpp b/DStarGatewayApp.cpp index 37e520a..3a8ae42 100644 --- a/DStarGatewayApp.cpp +++ b/DStarGatewayApp.cpp @@ -133,9 +133,9 @@ bool CDStarGatewayApp::createThread() // Setup APRS TAPRS aprsConfig; config.getAPRS(aprsConfig); - CAPRSWriter * aprsWriter = NULL; + CAPRSHandler * aprsWriter = NULL; if(aprsConfig.enabled && !aprsConfig.password.empty()) { - aprsWriter = new CAPRSWriter(aprsConfig.hostname, aprsConfig.port, gatewayConfig.callsign, aprsConfig.password, gatewayConfig.address); + aprsWriter = new CAPRSHandler(aprsConfig.hostname, aprsConfig.port, gatewayConfig.callsign, aprsConfig.password, gatewayConfig.address); if(aprsWriter->open()) { #ifdef USE_GPSD CAPRSIdFrameProvider * idFrameProvider = aprsConfig.m_positionSource == POSSRC_GPSD ? (CAPRSIdFrameProvider *)new CAPRSGPSDIdFrameProvider(gpsdConfig.m_address, gpsdConfig.m_port) diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index 23aa7a2..8c12a6f 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -638,7 +638,7 @@ void CDStarGatewayThread::setLog(bool enabled) m_logEnabled = enabled; } -void CDStarGatewayThread::setAPRSWriter(CAPRSWriter* writer) +void CDStarGatewayThread::setAPRSWriter(CAPRSHandler* writer) { m_aprsWriter = writer; } diff --git a/DStarGatewayThread.h b/DStarGatewayThread.h index 6b5d912..d90dd26 100644 --- a/DStarGatewayThread.h +++ b/DStarGatewayThread.h @@ -32,7 +32,7 @@ #include "RemoteHandler.h" #include "CacheManager.h" #include "CallsignList.h" -#include "APRSWriter.h" +#include "APRSHandler.h" #include "IRCDDB.h" #include "Timer.h" #include "Defs.h" @@ -72,7 +72,7 @@ virtual void addRepeater(const std::string& callsign, const std::string& band, c virtual void setCCS(bool enabled, const std::string& host); #endif virtual void setLog(bool enabled); - virtual void setAPRSWriter(CAPRSWriter* writer); + virtual void setAPRSWriter(CAPRSHandler* writer); virtual void setInfoEnabled(bool enabled); virtual void setEchoEnabled(bool enabled); virtual void setDTMFEnabled(bool enabled); @@ -109,7 +109,7 @@ private: #if defined(ENABLE_NAT_TRAVERSAL) CNatTraversalHandler* m_natTraversal; #endif - CAPRSWriter* m_aprsWriter; + CAPRSHandler* m_aprsWriter; CIRCDDB* m_irc; CCacheManager m_cache; TEXT_LANG m_language; diff --git a/RepeaterHandler.cpp b/RepeaterHandler.cpp index 13635b3..acd05ea 100644 --- a/RepeaterHandler.cpp +++ b/RepeaterHandler.cpp @@ -59,7 +59,7 @@ bool CRepeaterHandler::m_dtmfEnabled = true; CHeaderLogger* CRepeaterHandler::m_headerLogger = NULL; -CAPRSWriter* CRepeaterHandler::m_aprsWriter = NULL; +CAPRSHandler* CRepeaterHandler::m_aprsWriter = NULL; CCallsignList* CRepeaterHandler::m_restrictList = NULL; @@ -366,7 +366,7 @@ void CRepeaterHandler::setHeaderLogger(CHeaderLogger* logger) m_headerLogger = logger; } -void CRepeaterHandler::setAPRSWriter(CAPRSWriter* writer) +void CRepeaterHandler::setAPRSWriter(CAPRSHandler* writer) { m_aprsWriter = writer; } diff --git a/RepeaterHandler.h b/RepeaterHandler.h index 229b09c..449d34c 100644 --- a/RepeaterHandler.h +++ b/RepeaterHandler.h @@ -48,7 +48,7 @@ #include "CCSHandler.h" #endif #include "StatusData.h" -#include "APRSWriter.h" +#include "APRSHandler.h" #include "HeardData.h" #include "AudioUnit.h" #include "EchoUnit.h" @@ -82,7 +82,7 @@ public: static void setDPlusEnabled(bool enabled); static void setDCSEnabled(bool enabled); static void setHeaderLogger(CHeaderLogger* logger); - static void setAPRSWriter(CAPRSWriter* writer); + static void setAPRSWriter(CAPRSHandler* writer); static void setInfoEnabled(bool enabled); static void setEchoEnabled(bool enabled); static void setDTMFEnabled(bool enabled); @@ -178,7 +178,7 @@ private: static CHeaderLogger* m_headerLogger; - static CAPRSWriter* m_aprsWriter; + static CAPRSHandler* m_aprsWriter; static CCallsignList* m_whiteList; static CCallsignList* m_blackList; From e0ea97d8fc9633c60333e4bbe79947f9e98c5125 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 6 Jan 2022 07:58:11 +0100 Subject: [PATCH 076/201] Rename IRCDDBGatewaysStatusData -> DStarGetwayStatusData --- DStarGatewayStatusData.cpp | 22 +++++++++++----------- DStarGatewayStatusData.h | 6 +++--- DStarGatewayThread.cpp | 8 ++++---- DStarGatewayThread.h | 2 +- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/DStarGatewayStatusData.cpp b/DStarGatewayStatusData.cpp index 0798788..c3337ee 100644 --- a/DStarGatewayStatusData.cpp +++ b/DStarGatewayStatusData.cpp @@ -21,17 +21,17 @@ #include "DStarGatewayStatusData.h" -CIRCDDBGatewayStatusData::CIRCDDBGatewayStatusData(IRCDDB_STATUS ircDDBStatus, bool dprsStatus) : +CDStarGatewayStatusData::CDStarGatewayStatusData(IRCDDB_STATUS ircDDBStatus, bool dprsStatus) : m_ircDDBStatus(ircDDBStatus), m_dprsStatus(dprsStatus) { } -CIRCDDBGatewayStatusData::~CIRCDDBGatewayStatusData() +CDStarGatewayStatusData::~CDStarGatewayStatusData() { } -void CIRCDDBGatewayStatusData::setRepeater(unsigned int n, const std::string& callsign, LINK_STATUS linkStatus, const std::string& linkCallsign, const std::string& incoming) +void CDStarGatewayStatusData::setRepeater(unsigned int n, const std::string& callsign, LINK_STATUS linkStatus, const std::string& linkCallsign, const std::string& incoming) { assert(n < 4U); @@ -41,50 +41,50 @@ void CIRCDDBGatewayStatusData::setRepeater(unsigned int n, const std::string& ca m_incoming[n] = incoming; } -void CIRCDDBGatewayStatusData::setDongles(const std::string& dongles) +void CDStarGatewayStatusData::setDongles(const std::string& dongles) { m_dongles = dongles; } -IRCDDB_STATUS CIRCDDBGatewayStatusData::getIrcDDBStatus() const +IRCDDB_STATUS CDStarGatewayStatusData::getIrcDDBStatus() const { return m_ircDDBStatus; } -bool CIRCDDBGatewayStatusData::getDPRSStatus() const +bool CDStarGatewayStatusData::getDPRSStatus() const { return m_dprsStatus; } -std::string CIRCDDBGatewayStatusData::getCallsign(unsigned int n) const +std::string CDStarGatewayStatusData::getCallsign(unsigned int n) const { assert(n < 4U); return m_callsign[n]; } -LINK_STATUS CIRCDDBGatewayStatusData::getLinkStatus(unsigned int n) const +LINK_STATUS CDStarGatewayStatusData::getLinkStatus(unsigned int n) const { assert(n < 4U); return m_linkStatus[n]; } -std::string CIRCDDBGatewayStatusData::getLinkCallsign(unsigned int n) const +std::string CDStarGatewayStatusData::getLinkCallsign(unsigned int n) const { assert(n < 4U); return m_linkCallsign[n]; } -std::string CIRCDDBGatewayStatusData::getIncoming(unsigned int n) const +std::string CDStarGatewayStatusData::getIncoming(unsigned int n) const { assert(n < 4U); return m_incoming[n]; } -std::string CIRCDDBGatewayStatusData::getDongles() const +std::string CDStarGatewayStatusData::getDongles() const { return m_dongles; } diff --git a/DStarGatewayStatusData.h b/DStarGatewayStatusData.h index 7768b16..5291508 100644 --- a/DStarGatewayStatusData.h +++ b/DStarGatewayStatusData.h @@ -22,10 +22,10 @@ #include "Defs.h" -class CIRCDDBGatewayStatusData { +class CDStarGatewayStatusData { public: - CIRCDDBGatewayStatusData(IRCDDB_STATUS ircDDBStatus, bool dprsStatus); - ~CIRCDDBGatewayStatusData(); + CDStarGatewayStatusData(IRCDDB_STATUS ircDDBStatus, bool dprsStatus); + ~CDStarGatewayStatusData(); void setRepeater(unsigned int n, const std::string& callsign, LINK_STATUS linkStatus, const std::string& linkCallsign, const std::string& incoming); diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index 8c12a6f..b05a151 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -424,10 +424,10 @@ void* CDStarGatewayThread::Entry() } catch (std::exception& e) { std::string message(e.what()); - CLog::logError("Exception raised in the main thread - \"%s\"", message.c_str()); + CLog::logFatal("Exception raised in the main thread - \"%s\"", message.c_str()); } catch (...) { - CLog::logError("Unknown exception raised in the main thread"); + CLog::logFatal("Unknown exception raised in the main thread"); } CLog::logInfo("Stopping the ircDDB Gateway thread"); @@ -1203,13 +1203,13 @@ void CDStarGatewayThread::writeStatus() file.close(); } -CIRCDDBGatewayStatusData* CDStarGatewayThread::getStatus() const +CDStarGatewayStatusData* CDStarGatewayThread::getStatus() const { bool aprsStatus = false; if (m_aprsWriter != NULL) aprsStatus = m_aprsWriter->isConnected(); - CIRCDDBGatewayStatusData* status = new CIRCDDBGatewayStatusData(m_lastStatus, aprsStatus); + CDStarGatewayStatusData* status = new CDStarGatewayStatusData(m_lastStatus, aprsStatus); for (unsigned int i = 0U; i < 4U; i++) { std::string callsign, linkCallsign; diff --git a/DStarGatewayThread.h b/DStarGatewayThread.h index d90dd26..5203a68 100644 --- a/DStarGatewayThread.h +++ b/DStarGatewayThread.h @@ -83,7 +83,7 @@ virtual void addRepeater(const std::string& callsign, const std::string& band, c virtual void setBlackList(CCallsignList* list); virtual void setRestrictList(CCallsignList* list); - virtual CIRCDDBGatewayStatusData* getStatus() const; + virtual CDStarGatewayStatusData* getStatus() const; virtual void kill(); From 51748fda299ef69fd45add3c3e7e631b922c2c3e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 6 Jan 2022 07:58:33 +0100 Subject: [PATCH 077/201] #12 move calcCRC to APRSUtils --- APRSUtils.cpp | 23 +++++++++++++++++++++++ APRSUtils.h | 1 + GPSACollector.cpp | 26 ++------------------------ 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/APRSUtils.cpp b/APRSUtils.cpp index 3d0839d..fdb65c2 100644 --- a/APRSUtils.cpp +++ b/APRSUtils.cpp @@ -31,4 +31,27 @@ void CAPRSUtils::dstarCallsignToAPRS(std::string& dstarCallsign) } boost::replace_all(dstarCallsign, " ", "-");//replace remaining blank with a - } +} + +unsigned int CAPRSUtils::calcIcomCRC(const std::string& gpsa) +{ + unsigned int icomcrc = 0xFFFFU; + + auto length = gpsa.length(); + for (unsigned int j = 10U; j < length; j++) { + unsigned char ch = (unsigned char)gpsa[j]; + + for (unsigned int i = 0U; i < 8U; i++) { + bool xorflag = (((icomcrc ^ ch) & 0x01U) == 0x01U); + + icomcrc >>= 1; + + if (xorflag) + icomcrc ^= 0x8408U; + + ch >>= 1; + } + } + + return ~icomcrc & 0xFFFFU; } \ No newline at end of file diff --git a/APRSUtils.h b/APRSUtils.h index 2ad53d3..517e3d9 100644 --- a/APRSUtils.h +++ b/APRSUtils.h @@ -24,4 +24,5 @@ class CAPRSUtils { public: static void dstarCallsignToAPRS(std::string& dstarCallsign); + static unsigned int calcIcomCRC(const std::string& gpsa); }; \ No newline at end of file diff --git a/GPSACollector.cpp b/GPSACollector.cpp index d6c7b3f..fd539b8 100644 --- a/GPSACollector.cpp +++ b/GPSACollector.cpp @@ -25,6 +25,7 @@ #include "GPSACollector.h" #include "StringUtils.h" #include "Log.h" +#include "APRSUtils.h" const unsigned int APRS_CSUM_LENGTH = 4U; @@ -44,36 +45,13 @@ bool CGPSACollector::isValidGPSA(const std::string& gpsa) if(gpsa.length() < 10U || !boost::starts_with(gpsa, "$$CRC")) return false; - auto csum = calcCRC(gpsa); + auto csum = CAPRSUtils::calcIcomCRC(gpsa); auto csumStr = CStringUtils::string_format("%04X", csum); auto expectedCsum = gpsa.substr(5U, APRS_CSUM_LENGTH); bool res = ::strcasecmp(csumStr.c_str(), expectedCsum.c_str()) == 0; return res; } -unsigned int CGPSACollector::calcCRC(const std::string& gpsa) -{ - unsigned int icomcrc = 0xFFFFU; - - auto length = gpsa.length(); - for (unsigned int j = 10U; j < length; j++) { - unsigned char ch = (unsigned char)gpsa[j]; - - for (unsigned int i = 0U; i < 8U; i++) { - bool xorflag = (((icomcrc ^ ch) & 0x01U) == 0x01U); - - icomcrc >>= 1; - - if (xorflag) - icomcrc ^= 0x8408U; - - ch >>= 1; - } - } - - return ~icomcrc & 0xFFFFU; -} - unsigned int CGPSACollector::getDataInt(unsigned char * data, unsigned int length) { if(data == nullptr || length == 0U || getSentence().empty()) From a969590099d49b8272fd4ac6a9fd8f97d01cafdd Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 6 Jan 2022 08:19:08 +0100 Subject: [PATCH 078/201] #2 Rename APRSReader -> APRSUnit --- APRSReader.cpp => APRSUnit.cpp | 6 +++--- APRSReader.h => APRSUnit.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename APRSReader.cpp => APRSUnit.cpp (88%) rename APRSReader.h => APRSUnit.h (93%) diff --git a/APRSReader.cpp b/APRSUnit.cpp similarity index 88% rename from APRSReader.cpp rename to APRSUnit.cpp index 431f777..55de1bf 100644 --- a/APRSReader.cpp +++ b/APRSUnit.cpp @@ -17,16 +17,16 @@ */ -#include "APRSReader.h" +#include "APRSUnit.h" #include "APRSFrame.h" #include "APRSParser.h" -CAPRSReader::CAPRSReader() +CAPRSUnit::CAPRSUnit() { } -bool CAPRSReader::readAprsFrame(const std::string& aprsFrame) +bool CAPRSUnit::readAprsFrame(const std::string& aprsFrame) { auto bla = aprsFrame; return false; diff --git a/APRSReader.h b/APRSUnit.h similarity index 93% rename from APRSReader.h rename to APRSUnit.h index 56781ba..dbeb634 100644 --- a/APRSReader.h +++ b/APRSUnit.h @@ -20,10 +20,10 @@ #include "ReadAPRSFrameCallback.h" -class CAPRSReader : public CReadAPRSFrameCallback +class CAPRSUnit : public CReadAPRSFrameCallback { public: - CAPRSReader(); + CAPRSUnit(); bool readAprsFrame(const std::string& aprsFrame); private: From c512e2894a2afde1147edcb0e012d185e6b8e260 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 6 Jan 2022 08:26:38 +0100 Subject: [PATCH 079/201] #12 Rename APRSWriterThread -> APRSHandlerThread --- APRSHandler.cpp | 2 +- APRSHandler.h | 4 +-- APRSWriterThread.cpp => APRSHandlerThread.cpp | 26 +++++++++---------- APRSWriterThread.h => APRSHandlerThread.h | 8 +++--- 4 files changed, 20 insertions(+), 20 deletions(-) rename APRSWriterThread.cpp => APRSHandlerThread.cpp (88%) rename APRSWriterThread.h => APRSHandlerThread.h (79%) diff --git a/APRSHandler.cpp b/APRSHandler.cpp index c36e470..9dcc2b3 100644 --- a/APRSHandler.cpp +++ b/APRSHandler.cpp @@ -47,7 +47,7 @@ m_idFrameProvider(nullptr) assert(!gateway.empty()); assert(!password.empty()); - m_thread = new CAPRSWriterThread(gateway, password, address, hostname, port); + m_thread = new CAPRSHandlerThread(gateway, password, address, hostname, port); m_gateway = gateway; m_gateway = m_gateway.substr(0, LONG_CALLSIGN_LENGTH - 1U); diff --git a/APRSHandler.h b/APRSHandler.h index 9cfa671..bd5ff4e 100644 --- a/APRSHandler.h +++ b/APRSHandler.h @@ -26,7 +26,7 @@ #include "APRSEntry.h" -#include "APRSWriterThread.h" +#include "APRSHandlerThread.h" #include "UDPReaderWriter.h" #include "APRSCollector.h" #include "DStarDefines.h" @@ -59,7 +59,7 @@ public: void close(); private: - CAPRSWriterThread* m_thread; + CAPRSHandlerThread* m_thread; std::string m_gateway; in_addr m_address; unsigned int m_port; diff --git a/APRSWriterThread.cpp b/APRSHandlerThread.cpp similarity index 88% rename from APRSWriterThread.cpp rename to APRSHandlerThread.cpp index 6b39111..aa1438b 100644 --- a/APRSWriterThread.cpp +++ b/APRSHandlerThread.cpp @@ -21,7 +21,7 @@ #include #include -#include "APRSWriterThread.h" +#include "APRSHandlerThread.h" #include "DStarDefines.h" #include "Utils.h" #include "Defs.h" @@ -34,7 +34,7 @@ const unsigned int APRS_TIMEOUT = 10U; -CAPRSWriterThread::CAPRSWriterThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port) : +CAPRSHandlerThread::CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port) : CThread(), m_username(callsign), m_password(password), @@ -61,7 +61,7 @@ m_clientName(FULL_PRODUCT_NAME) m_ssid = m_ssid.substr(LONG_CALLSIGN_LENGTH - 1U, 1); } -CAPRSWriterThread::CAPRSWriterThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port, const std::string& filter, const std::string& clientName) : +CAPRSHandlerThread::CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port, const std::string& filter, const std::string& clientName) : CThread(), m_username(callsign), m_password(password), @@ -88,7 +88,7 @@ m_clientName(clientName) m_ssid = m_ssid.substr(LONG_CALLSIGN_LENGTH - 1U, 1); } -CAPRSWriterThread::~CAPRSWriterThread() +CAPRSHandlerThread::~CAPRSHandlerThread() { std::vector callBacksCopy; callBacksCopy.assign(m_APRSReadCallbacks.begin(), m_APRSReadCallbacks.end()); @@ -105,7 +105,7 @@ CAPRSWriterThread::~CAPRSWriterThread() m_password.clear(); } -bool CAPRSWriterThread::start() +bool CAPRSHandlerThread::start() { Create(); Run(); @@ -113,7 +113,7 @@ bool CAPRSWriterThread::start() return true; } -void* CAPRSWriterThread::Entry() +void* CAPRSHandlerThread::Entry() { CLog::logInfo("Starting the APRS Writer thread"); @@ -207,13 +207,13 @@ void* CAPRSWriterThread::Entry() return NULL; } -void CAPRSWriterThread::addReadAPRSCallback(CReadAPRSFrameCallback * cb) +void CAPRSHandlerThread::addReadAPRSCallback(CReadAPRSFrameCallback * cb) { assert(cb != nullptr); m_APRSReadCallbacks.push_back(cb); } -void CAPRSWriterThread::write(CAPRSFrame& frame) +void CAPRSHandlerThread::write(CAPRSFrame& frame) { if (!m_connected) return; @@ -228,24 +228,24 @@ void CAPRSWriterThread::write(CAPRSFrame& frame) } } -bool CAPRSWriterThread::isConnected() const +bool CAPRSHandlerThread::isConnected() const { return m_connected; } -void CAPRSWriterThread::stop() +void CAPRSHandlerThread::stop() { m_exit = true; Wait(); } -void CAPRSWriterThread::clock(unsigned int ms) +void CAPRSHandlerThread::clock(unsigned int ms) { m_reconnectTimer.clock(ms); } -bool CAPRSWriterThread::connect() +bool CAPRSHandlerThread::connect() { bool ret = m_socket.open(); if (!ret) @@ -295,7 +295,7 @@ bool CAPRSWriterThread::connect() return true; } -void CAPRSWriterThread::startReconnectionTimer() +void CAPRSHandlerThread::startReconnectionTimer() { // Clamp at a ten minutes reconnect time m_tries++; diff --git a/APRSWriterThread.h b/APRSHandlerThread.h similarity index 79% rename from APRSWriterThread.h rename to APRSHandlerThread.h index e76b20f..a483b41 100644 --- a/APRSWriterThread.h +++ b/APRSHandlerThread.h @@ -29,11 +29,11 @@ #include "APRSFrame.h" -class CAPRSWriterThread : public CThread { +class CAPRSHandlerThread : public CThread { public: - CAPRSWriterThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port); - CAPRSWriterThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port, const std::string& filter, const std::string& clientName); - virtual ~CAPRSWriterThread(); + CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port); + CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port, const std::string& filter, const std::string& clientName); + virtual ~CAPRSHandlerThread(); bool start(); From 11b9469f45b35004c9f0c9956131185f07e0fd75 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 6 Jan 2022 22:22:36 +0100 Subject: [PATCH 080/201] #12 add destructor --- APRSFrame.cpp | 5 +++++ APRSFrame.h | 1 + 2 files changed, 6 insertions(+) diff --git a/APRSFrame.cpp b/APRSFrame.cpp index 1f8724f..a28ba4c 100644 --- a/APRSFrame.cpp +++ b/APRSFrame.cpp @@ -38,6 +38,11 @@ m_type(type) m_path.assign(path.begin(), path.end()); } +CAPRSFrame::~CAPRSFrame() +{ + m_path.clear(); +} + void CAPRSFrame::clear() { m_source.clear(); diff --git a/APRSFrame.h b/APRSFrame.h index 6c50eee..2fc790c 100644 --- a/APRSFrame.h +++ b/APRSFrame.h @@ -36,6 +36,7 @@ class CAPRSFrame { public: CAPRSFrame(); CAPRSFrame(const std::string& source, const std::string& destination, const std::vector& path, const std::string& body, APRS_FRAME_TYPE type); + ~CAPRSFrame(); void clear(); std::string& getSource() { return m_source; } From 707491d836070d49920714a2a5f8af5b89674ce0 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 6 Jan 2022 22:23:25 +0100 Subject: [PATCH 081/201] #12 add APRSUnit and callbacks --- APRSHandler.cpp | 7 +++- APRSHandler.h | 2 + APRSHandlerThread.cpp | 16 +++---- APRSHandlerThread.h | 6 +-- APRSUnit.cpp | 93 ++++++++++++++++++++++++++++++++++++++--- APRSUnit.h | 28 ++++++++++--- APRSUtils.cpp | 4 +- APRSUtils.h | 2 +- ReadAPRSFrameCallback.h | 7 ++-- RepeaterHandler.cpp | 15 +++++++ RepeaterHandler.h | 9 +++- 11 files changed, 157 insertions(+), 32 deletions(-) diff --git a/APRSHandler.cpp b/APRSHandler.cpp index 9dcc2b3..1ebedd9 100644 --- a/APRSHandler.cpp +++ b/APRSHandler.cpp @@ -47,7 +47,7 @@ m_idFrameProvider(nullptr) assert(!gateway.empty()); assert(!password.empty()); - m_thread = new CAPRSHandlerThread(gateway, password, address, hostname, port); + m_thread = new CAPRSHandlerThread(gateway, password, address, hostname, port, "m/20"); m_gateway = gateway; m_gateway = m_gateway.substr(0, LONG_CALLSIGN_LENGTH - 1U); @@ -244,3 +244,8 @@ void CAPRSHandler::close() m_thread->stop(); } + +void CAPRSHandler::addReadAPRSCallback(IReadAPRSFrameCallback* cb) +{ + m_thread->addReadAPRSCallback(cb); +} diff --git a/APRSHandler.h b/APRSHandler.h index bd5ff4e..743ad37 100644 --- a/APRSHandler.h +++ b/APRSHandler.h @@ -58,6 +58,8 @@ public: void close(); + void addReadAPRSCallback(IReadAPRSFrameCallback* cb); + private: CAPRSHandlerThread* m_thread; std::string m_gateway; diff --git a/APRSHandlerThread.cpp b/APRSHandlerThread.cpp index aa1438b..2c84c65 100644 --- a/APRSHandlerThread.cpp +++ b/APRSHandlerThread.cpp @@ -46,7 +46,7 @@ m_connected(false), m_reconnectTimer(1000U), m_tries(0U), m_APRSReadCallbacks(), -m_filter(""), +m_filter(), m_clientName(FULL_PRODUCT_NAME) { assert(!callsign.empty()); @@ -61,7 +61,7 @@ m_clientName(FULL_PRODUCT_NAME) m_ssid = m_ssid.substr(LONG_CALLSIGN_LENGTH - 1U, 1); } -CAPRSHandlerThread::CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port, const std::string& filter, const std::string& clientName) : +CAPRSHandlerThread::CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port, const std::string& filter) : CThread(), m_username(callsign), m_password(password), @@ -74,7 +74,7 @@ m_reconnectTimer(1000U), m_tries(0U), m_APRSReadCallbacks(), m_filter(filter), -m_clientName(clientName) +m_clientName(FULL_PRODUCT_NAME) { assert(!callsign.empty()); assert(!password.empty()); @@ -90,15 +90,11 @@ m_clientName(clientName) CAPRSHandlerThread::~CAPRSHandlerThread() { - std::vector callBacksCopy; + std::vector callBacksCopy; callBacksCopy.assign(m_APRSReadCallbacks.begin(), m_APRSReadCallbacks.end()); m_APRSReadCallbacks.clear(); - for(auto cb : callBacksCopy) { - delete cb; - } - callBacksCopy.clear(); m_username.clear(); @@ -177,7 +173,7 @@ void* CAPRSHandlerThread::Entry() if(CAPRSParser::parseFrame(line, readFrame)) { for(auto cb : m_APRSReadCallbacks) { CAPRSFrame f(readFrame); - cb->readAprsFrame(f); + cb->readAPRSFrame(f); } } } @@ -207,7 +203,7 @@ void* CAPRSHandlerThread::Entry() return NULL; } -void CAPRSHandlerThread::addReadAPRSCallback(CReadAPRSFrameCallback * cb) +void CAPRSHandlerThread::addReadAPRSCallback(IReadAPRSFrameCallback * cb) { assert(cb != nullptr); m_APRSReadCallbacks.push_back(cb); diff --git a/APRSHandlerThread.h b/APRSHandlerThread.h index a483b41..73642ba 100644 --- a/APRSHandlerThread.h +++ b/APRSHandlerThread.h @@ -32,7 +32,7 @@ class CAPRSHandlerThread : public CThread { public: CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port); - CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port, const std::string& filter, const std::string& clientName); + CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port, const std::string& filter); virtual ~CAPRSHandlerThread(); bool start(); @@ -47,7 +47,7 @@ public: void clock(unsigned int ms); - void addReadAPRSCallback(CReadAPRSFrameCallback* cb); + void addReadAPRSCallback(IReadAPRSFrameCallback* cb); private: std::string m_username; @@ -59,7 +59,7 @@ private: bool m_connected; CTimer m_reconnectTimer; unsigned int m_tries; - std::vector m_APRSReadCallbacks; + std::vector m_APRSReadCallbacks; std::string m_filter; std::string m_clientName; diff --git a/APRSUnit.cpp b/APRSUnit.cpp index 55de1bf..b46a598 100644 --- a/APRSUnit.cpp +++ b/APRSUnit.cpp @@ -16,18 +16,99 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include "APRSUnit.h" -#include "APRSFrame.h" -#include "APRSParser.h" +#include "APRSFormater.h" +#include "StringUtils.h" +#include "APRSUtils.h" +#include "SlowDataEncoder.h" -CAPRSUnit::CAPRSUnit() +CAPRSUnit::CAPRSUnit(IRepeaterCallback * repeaterHandler) : +m_frameBuffer(20U), +m_status(APS_IDLE), +m_repeaterHandler(repeaterHandler), +m_headerData(nullptr), +m_timer(1000U, 2U) { + m_timer.start(); +} + +void CAPRSUnit::writeFrame(CAPRSFrame& frame) +{ + auto frameCopy = new CAPRSFrame(frame); + frameCopy->getPath().clear();//path is of no use for us, just clear it + m_frameBuffer.push_back(frameCopy); } -bool CAPRSUnit::readAprsFrame(const std::string& aprsFrame) +void CAPRSUnit::clock(unsigned int ms) { - auto bla = aprsFrame; - return false; + m_timer.clock(ms); + if(m_status == APS_IDLE && !m_frameBuffer.empty() && m_timer.hasExpired()) { + auto frame = m_frameBuffer.front(); + + m_id = CHeaderData::createId(); + + m_headerData = new CHeaderData(); + m_headerData->setMyCall1(frame->getSource()); + m_headerData->setMyCall2("APRS"); + m_headerData->setYourCall("CQCQCQ "); + m_headerData->setId(m_id); + + m_repeaterHandler->process(*m_headerData, DIR_INCOMING, AS_INFO); + + m_status = APS_TRANSMIT; + } + + if(m_status == APS_TRANSMIT && !m_frameBuffer.empty()) + { + auto frame = m_frameBuffer.front(); + std::string frameString; + CAPRSFormater::frameToString(frameString, *frame); + boost::trim_right_if(frameString, [](char c) { return c == '\n' || c == '\r'; }); + frameString.push_back('\r'); + + std::string crc = CStringUtils::string_format("$$CRC%04X", CAPRSUtils::calcGPSAIcomCRC(frameString)); + frameString.insert(0, crc); + + CSlowDataEncoder encoder; + encoder.setHeaderData(*m_headerData); + encoder.setGPSData(frameString); + encoder.setTextData("APRS to DPRS"); + + CAMBEData data; + data.setId(m_id); + + unsigned int out = 0U; + unsigned int dataOut = 0U; + unsigned int needed = (encoder.getInterleavedDataLength() / (DATA_FRAME_LENGTH_BYTES)) * 2U; + unsigned char buffer[DV_FRAME_LENGTH_BYTES]; + + while (dataOut < needed) { + data.setSeq(out); + + ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); + + // Insert sync bytes when the sequence number is zero, slow data otherwise + if (out == 0U) { + ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); + } else { + encoder.getInterleavedData(buffer + VOICE_FRAME_LENGTH_BYTES); + dataOut++; + } + + data.setData(buffer, DV_FRAME_LENGTH_BYTES); + + m_repeaterHandler->process(data, DIR_INCOMING, AS_INFO); + out++; + + if (out == 21U) out = 0U; + } + + m_frameBuffer.pop_front(); + delete frame; + m_status = APS_IDLE; + m_timer.start(); + } } \ No newline at end of file diff --git a/APRSUnit.h b/APRSUnit.h index dbeb634..454c4cd 100644 --- a/APRSUnit.h +++ b/APRSUnit.h @@ -18,16 +18,34 @@ #pragma once -#include "ReadAPRSFrameCallback.h" +#include +#include -class CAPRSUnit : public CReadAPRSFrameCallback +#include "APRSFrame.h" +#include "RepeaterCallback.h" +#include "Timer.h" + +enum APRSUNIT_STATUS { + APS_IDLE, + APS_WAIT, + APS_TRANSMIT +}; + +class CAPRSUnit { public: - CAPRSUnit(); - bool readAprsFrame(const std::string& aprsFrame); + CAPRSUnit(IRepeaterCallback * repeaterHandler); + void writeFrame(CAPRSFrame& aprsFrame); + void clock(unsigned ms); private: - + // CRingBuffer m_frameBuffer; + boost::circular_buffer m_frameBuffer; + APRSUNIT_STATUS m_status; + IRepeaterCallback * m_repeaterHandler; + unsigned int m_id; + CHeaderData * m_headerData; + CTimer m_timer; }; diff --git a/APRSUtils.cpp b/APRSUtils.cpp index fdb65c2..2309344 100644 --- a/APRSUtils.cpp +++ b/APRSUtils.cpp @@ -33,7 +33,7 @@ void CAPRSUtils::dstarCallsignToAPRS(std::string& dstarCallsign) } } -unsigned int CAPRSUtils::calcIcomCRC(const std::string& gpsa) +unsigned int CAPRSUtils::calcGPSAIcomCRC(const std::string& gpsa) { unsigned int icomcrc = 0xFFFFU; @@ -54,4 +54,4 @@ unsigned int CAPRSUtils::calcIcomCRC(const std::string& gpsa) } return ~icomcrc & 0xFFFFU; -} \ No newline at end of file +} diff --git a/APRSUtils.h b/APRSUtils.h index 517e3d9..9455ac9 100644 --- a/APRSUtils.h +++ b/APRSUtils.h @@ -24,5 +24,5 @@ class CAPRSUtils { public: static void dstarCallsignToAPRS(std::string& dstarCallsign); - static unsigned int calcIcomCRC(const std::string& gpsa); + static unsigned int calcGPSAIcomCRC(const std::string& gpsa); }; \ No newline at end of file diff --git a/ReadAPRSFrameCallback.h b/ReadAPRSFrameCallback.h index 9a93193..9ce37d3 100644 --- a/ReadAPRSFrameCallback.h +++ b/ReadAPRSFrameCallback.h @@ -19,12 +19,13 @@ #pragma once #include +#include #include "APRSFrame.h" -class CReadAPRSFrameCallback +class IReadAPRSFrameCallback { public: - virtual ~CReadAPRSFrameCallback(){ } - virtual bool readAprsFrame(CAPRSFrame& aprsFrame) = 0; + virtual void readAPRSFrame(CAPRSFrame& aprsFrame) = 0; }; + diff --git a/RepeaterHandler.cpp b/RepeaterHandler.cpp index acd05ea..e7638d9 100644 --- a/RepeaterHandler.cpp +++ b/RepeaterHandler.cpp @@ -226,6 +226,7 @@ m_heardTimer(1000U, 0U, 100U) // 100ms m_echo = new CEchoUnit(this, callsign); m_infoAudio = new CAudioUnit(this, callsign); m_version = new CVersionUnit(this, callsign); + m_aprsUnit = new CAPRSUnit(this); #ifdef USE_DRATS if (dratsEnabled) { @@ -1416,6 +1417,9 @@ void CRepeaterHandler::clockInt(unsigned int ms) m_echo->clock(ms); m_version->clock(ms); + if(m_aprsUnit != nullptr) + m_aprsUnit->clock(ms); + m_linkReconnectTimer.clock(ms); m_watchdogTimer.clock(ms); m_queryTimer.clock(ms); @@ -2422,6 +2426,10 @@ void CRepeaterHandler::startupInt() m_irc->rptrQTH(callsign, m_latitude, m_longitude, m_description1, m_description2, m_url); } + if(m_aprsWriter != nullptr) { + m_aprsWriter->addReadAPRSCallback(this); + } + #ifdef USE_CCS m_ccsHandler = new CCCSHandler(this, m_rptCallsign, m_index + 1U, m_latitude, m_longitude, m_frequency, m_offset, m_description1, m_description2, m_url, CCS_PORT + m_index); #endif @@ -3069,6 +3077,13 @@ void CRepeaterHandler::triggerInfo() } } +void CRepeaterHandler::readAPRSFrame(CAPRSFrame& frame) +{ + if(m_aprsUnit != nullptr) { + m_aprsUnit->writeFrame(frame); + } +} + #ifdef USE_CCS bool CRepeaterHandler::isCCSCommand(const std::string& command) const { diff --git a/RepeaterHandler.h b/RepeaterHandler.h index 449d34c..678e383 100644 --- a/RepeaterHandler.h +++ b/RepeaterHandler.h @@ -58,11 +58,13 @@ #include "Timer.h" #include "DTMF.h" #include "Defs.h" +#include "ReadAPRSFrameCallback.h" +#include "APRSUnit.h" #include -class CRepeaterHandler : public IRepeaterCallback, public IReflectorCallback, public ICCSCallback { +class CRepeaterHandler : public IRepeaterCallback, public IReflectorCallback, public ICCSCallback, public IReadAPRSFrameCallback { public: static void initialise(unsigned int maxRepeaters); @@ -142,6 +144,8 @@ public: virtual void ccsLinkFailed(const std::string& dtmf, DIRECTION direction); virtual void ccsLinkEnded(const std::string& callsign, DIRECTION direction); + virtual void readAPRSFrame(CAPRSFrame& frame); + protected: #ifdef USE_DRATS CRepeaterHandler(const std::string& callsign, const std::string& band, const std::string& address, unsigned int port, HW_TYPE hwType, const std::string& reflector, bool atStartup, RECONNECT reconnect, bool dratsEnabled, double frequency, double offset, double range, double latitude, double longitude, double agl, const std::string& description1, const std::string& description2, const std::string& url, IRepeaterProtocolHandler* handler, unsigned char band1, unsigned char band2, unsigned char band3); @@ -275,6 +279,9 @@ private: // Version information CVersionUnit* m_version; + // APRS to DPRS + CAPRSUnit* m_aprsUnit; + #ifdef USE_DRATS // D-RATS handler CDRATSServer* m_drats; From 30e8be7ea78330e275468e6cd490c0a119577ab7 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 6 Jan 2022 22:24:47 +0100 Subject: [PATCH 082/201] #12 #9 continue RSMS1A reverse engineering --- GPSACollector.cpp | 2 +- RSMS1AMessageBuilder.cpp | 86 +++++++++++++++++++++ RSMS1AMessageBuilder.h | 37 +++++++++ RSMS1AMessageCollector.cpp | 4 + Tests/RSMS1AMessageBuilder/buildMessage.cpp | 61 +++++++++++++++ 5 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 RSMS1AMessageBuilder.cpp create mode 100644 RSMS1AMessageBuilder.h create mode 100644 Tests/RSMS1AMessageBuilder/buildMessage.cpp diff --git a/GPSACollector.cpp b/GPSACollector.cpp index fd539b8..df04ab0 100644 --- a/GPSACollector.cpp +++ b/GPSACollector.cpp @@ -45,7 +45,7 @@ bool CGPSACollector::isValidGPSA(const std::string& gpsa) if(gpsa.length() < 10U || !boost::starts_with(gpsa, "$$CRC")) return false; - auto csum = CAPRSUtils::calcIcomCRC(gpsa); + auto csum = CAPRSUtils::calcGPSAIcomCRC(gpsa); auto csumStr = CStringUtils::string_format("%04X", csum); auto expectedCsum = gpsa.substr(5U, APRS_CSUM_LENGTH); bool res = ::strcasecmp(csumStr.c_str(), expectedCsum.c_str()) == 0; diff --git a/RSMS1AMessageBuilder.cpp b/RSMS1AMessageBuilder.cpp new file mode 100644 index 0000000..53a91ef --- /dev/null +++ b/RSMS1AMessageBuilder.cpp @@ -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 "RSMS1AMessageBuilder.h" +#include "StringUtils.h" + +std::vector CRSMS1AMessageBuilder::m_charsToEscape = {-17, 0, 17, 19, -2, -25, 26, -3, -1, 36, 13, 44}; + +void CRSMS1AMessageBuilder::buildMessage(std::string& message, const std::string& sender, const std::string& recipient, const std::string body) +{ + + std::string bodyTmp(body); + auto bodyCrc = calculateBodyCRC(body); + bodyTmp.push_back(bodyCrc); + escapeBody(bodyTmp, std::string(bodyTmp)); + + std::string header = CStringUtils::string_format("%s,%s,0011", sender.c_str(), recipient.c_str()); + char c1, c2; + calcMsgIcomCRC(header, c1, c2); + header.push_back(c1); + header.push_back(c2); + message = "$$Msg," + header + bodyTmp + '\n'; +} + +char CRSMS1AMessageBuilder::calculateBodyCRC(const std::string& body) +{ + if(body.length() == 1) + return body[0]; + + int num = 0; + for(auto c : body) { + num += c; + } + + return (char)((num & 255) /*- 128*/); +} + +void CRSMS1AMessageBuilder::escapeBody(std::string output, const std::string& body) +{ + output.clear(); + for(char c : body) { + if(std::find(m_charsToEscape.begin(), m_charsToEscape.end(), c) != m_charsToEscape.end()) { + output.push_back(-17); + } + output.push_back(c); + } +} + +void CRSMS1AMessageBuilder::calcMsgIcomCRC(const std::string& msg, char& c1, char& c2) +{ + int num = 0; + for(unsigned int i = 0U; i < msg.length(); i++) { + num += msg[i]; + } + + c1 = doWhatever((char)((num >> 4) & 15)); + c2 = doWhatever((char)(num & 15)); +} + +char CRSMS1AMessageBuilder::doWhatever(char b2) { + int i; + int i2 = b2 & 255; + if (i2 >= 0 && i2 <= 9) { + i = b2 + 48; + } else if (10 > i2 || i2 > 15) { + return 0; + } else { + i = b2 + 55; + } + return (char) i; +} \ No newline at end of file diff --git a/RSMS1AMessageBuilder.h b/RSMS1AMessageBuilder.h new file mode 100644 index 0000000..d73f748 --- /dev/null +++ b/RSMS1AMessageBuilder.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#pragma once + +#include +#include + +class CRSMS1AMessageBuilder +{ +public: + static void buildMessage(std::string& message, const std::string& sender, const std::string& recipient, const std::string body); + +private: + static void calcMsgIcomCRC(const std::string& msg, char& c1, char& c2); + static void escapeBody(std::string output, const std::string& body); + static void escapeBytes(std::vector output, const std::vector input); + static char calculateBodyCRC(const std::string& body); + static char doWhatever(char b2); + + static std::vector m_charsToEscape; +}; \ No newline at end of file diff --git a/RSMS1AMessageCollector.cpp b/RSMS1AMessageCollector.cpp index f9cafe6..bb30923 100644 --- a/RSMS1AMessageCollector.cpp +++ b/RSMS1AMessageCollector.cpp @@ -57,6 +57,10 @@ bool CRSMS1AMessageCollector::isValidMsg(const std::string& msg) bool ret = splits.size() >= 4 && !splits[1].empty() && !splits[2].empty(); + + CUtils::dump("RS-MS1A:", (unsigned char *)msg.c_str(), msg.length() + 1U); + CLog::logDebug("RS-MS1A: %s", msg.c_str()); + return ret; //TODO 2022-01-01 figure out what the heck it is about thic strange CRCs diff --git a/Tests/RSMS1AMessageBuilder/buildMessage.cpp b/Tests/RSMS1AMessageBuilder/buildMessage.cpp new file mode 100644 index 0000000..8ed29ab --- /dev/null +++ b/Tests/RSMS1AMessageBuilder/buildMessage.cpp @@ -0,0 +1,61 @@ +/* + * 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 + +#include "../../RSMS1AMessageBuilder.h" + +namespace RSMS1AMessageBuilder +{ + + class RSMS1AMessageBuilder_buildMessage : public ::testing::Test { + + }; + + TEST_F(RSMS1AMessageBuilder_buildMessage, testABC) + { + std::string message; + CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "ABC"); + + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118ABCF\n"); + } + + TEST_F(RSMS1AMessageBuilder_buildMessage, testA) + { + std::string message; + CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "A"); + + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118AA\n"); + } + + TEST_F(RSMS1AMessageBuilder_buildMessage, testAA) + { + std::string message; + CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "AA"); + + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118AA\02\n"); + } + + TEST_F(RSMS1AMessageBuilder_buildMessage, testSalutCommentVasTu) + { + std::string message; + CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "Salut, comment vas tu?"); + + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118Saluto, comment vas tu?\x7A\n"); + } +}; \ No newline at end of file From 8b7fbd22d370bd6ebd1b91afcbfbc788ea7c9d69 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 6 Jan 2022 22:25:21 +0100 Subject: [PATCH 083/201] file assoc --- .vscode/settings.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a509b7e..a75b395 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,7 +7,16 @@ } ], "files.associations": { - "new": "cpp" + "new": "cpp", + "type_traits": "cpp", + "array": "cpp", + "*.tcc": "cpp", + "chrono": "cpp", + "deque": "cpp", + "list": "cpp", + "vector": "cpp", + "optional": "cpp", + "stop_token": "cpp" }, "editor.tokenColorCustomizations": { "textMateRules": [ From 6cc1a50c79d5398d0f863dbcafd67de6e2319a89 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 6 Jan 2022 22:25:34 +0100 Subject: [PATCH 084/201] change default task --- .vscode/tasks.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2dc1e81..ab94961 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -11,10 +11,7 @@ "-j3", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] }, { @@ -26,7 +23,10 @@ "tests", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] } ] From a9953aec29eea075f72e3bb40358f238c555458d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 7 Jan 2022 06:38:46 +0100 Subject: [PATCH 085/201] #9 #12 fix escaping and checksum calculation --- RSMS1AMessageBuilder.cpp | 12 ++++------ RSMS1AMessageBuilder.h | 2 +- Tests/RSMS1AMessageBuilder/buildMessage.cpp | 26 +++++++++++++++++---- 3 files changed, 27 insertions(+), 13 deletions(-) diff --git a/RSMS1AMessageBuilder.cpp b/RSMS1AMessageBuilder.cpp index 53a91ef..2351d97 100644 --- a/RSMS1AMessageBuilder.cpp +++ b/RSMS1AMessageBuilder.cpp @@ -23,11 +23,9 @@ std::vector CRSMS1AMessageBuilder::m_charsToEscape = {-17, 0, 17, 19, -2, void CRSMS1AMessageBuilder::buildMessage(std::string& message, const std::string& sender, const std::string& recipient, const std::string body) { - - std::string bodyTmp(body); auto bodyCrc = calculateBodyCRC(body); - bodyTmp.push_back(bodyCrc); - escapeBody(bodyTmp, std::string(bodyTmp)); + std::string bodyTmp; + escapeBody(bodyTmp, body + bodyCrc); std::string header = CStringUtils::string_format("%s,%s,0011", sender.c_str(), recipient.c_str()); char c1, c2; @@ -47,15 +45,15 @@ char CRSMS1AMessageBuilder::calculateBodyCRC(const std::string& body) num += c; } - return (char)((num & 255) /*- 128*/); + return (char)((num & 255) - 128); } -void CRSMS1AMessageBuilder::escapeBody(std::string output, const std::string& body) +void CRSMS1AMessageBuilder::escapeBody(std::string& output, const std::string& body) { output.clear(); for(char c : body) { if(std::find(m_charsToEscape.begin(), m_charsToEscape.end(), c) != m_charsToEscape.end()) { - output.push_back(-17); + output.push_back('o'); } output.push_back(c); } diff --git a/RSMS1AMessageBuilder.h b/RSMS1AMessageBuilder.h index d73f748..4819fde 100644 --- a/RSMS1AMessageBuilder.h +++ b/RSMS1AMessageBuilder.h @@ -28,7 +28,7 @@ public: private: static void calcMsgIcomCRC(const std::string& msg, char& c1, char& c2); - static void escapeBody(std::string output, const std::string& body); + static void escapeBody(std::string& output, const std::string& body); static void escapeBytes(std::vector output, const std::vector input); static char calculateBodyCRC(const std::string& body); static char doWhatever(char b2); diff --git a/Tests/RSMS1AMessageBuilder/buildMessage.cpp b/Tests/RSMS1AMessageBuilder/buildMessage.cpp index 8ed29ab..17b2550 100644 --- a/Tests/RSMS1AMessageBuilder/buildMessage.cpp +++ b/Tests/RSMS1AMessageBuilder/buildMessage.cpp @@ -27,7 +27,7 @@ namespace RSMS1AMessageBuilder }; - TEST_F(RSMS1AMessageBuilder_buildMessage, testABC) + TEST_F(RSMS1AMessageBuilder_buildMessage, ABC) { std::string message; CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "ABC"); @@ -35,7 +35,7 @@ namespace RSMS1AMessageBuilder EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118ABCF\n"); } - TEST_F(RSMS1AMessageBuilder_buildMessage, testA) + TEST_F(RSMS1AMessageBuilder_buildMessage, A) { std::string message; CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "A"); @@ -43,7 +43,7 @@ namespace RSMS1AMessageBuilder EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118AA\n"); } - TEST_F(RSMS1AMessageBuilder_buildMessage, testAA) + TEST_F(RSMS1AMessageBuilder_buildMessage, AA) { std::string message; CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "AA"); @@ -51,11 +51,27 @@ namespace RSMS1AMessageBuilder EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118AA\02\n"); } - TEST_F(RSMS1AMessageBuilder_buildMessage, testSalutCommentVasTu) + TEST_F(RSMS1AMessageBuilder_buildMessage, SalutCommentVasTu) { std::string message; CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "Salut, comment vas tu?"); - EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118Saluto, comment vas tu?\x7A\n"); + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118Saluto, comment vas tu?z\n"); + } + + TEST_F(RSMS1AMessageBuilder_buildMessage, escapeComma) + { + std::string message; + CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", ","); + + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118o,o,\n"); + } + + TEST_F(RSMS1AMessageBuilder_buildMessage, INeedMoreDollars) + { + std::string message; + CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "I need more $$$$"); + + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118I need more o$o$o$o$\x08\n"); } }; \ No newline at end of file From d0f8f07f777408cc2d6f2ca12f61fefab41ca041 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 7 Jan 2022 13:15:33 +0100 Subject: [PATCH 086/201] Add sudo where sudo is needed --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 488ce96..6505de2 100644 --- a/README.md +++ b/README.md @@ -72,11 +72,11 @@ git checkout develop ## 3.4. Prerequisites and dependencies Before first time building you need to install dependencies and prerequisites ``` -apt install build-essential libcurl4-openssl-dev libboost-dev +sudo apt install build-essential libcurl4-openssl-dev libboost-dev ``` If you are going to build with gpsd support, also install libgps-dev ``` -apt install libgps-dev +sudo apt install libgps-dev ``` ## 3.5. Building Regular building From bfd95ad426902e714ccc1180d47c85a4b3607907 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 7 Jan 2022 13:21:40 +0100 Subject: [PATCH 087/201] #9 only dumpif ok --- RSMS1AMessageCollector.cpp | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/RSMS1AMessageCollector.cpp b/RSMS1AMessageCollector.cpp index bb30923..d0a2ade 100644 --- a/RSMS1AMessageCollector.cpp +++ b/RSMS1AMessageCollector.cpp @@ -58,8 +58,12 @@ bool CRSMS1AMessageCollector::isValidMsg(const std::string& msg) && !splits[1].empty() && !splits[2].empty(); - CUtils::dump("RS-MS1A:", (unsigned char *)msg.c_str(), msg.length() + 1U); - CLog::logDebug("RS-MS1A: %s", msg.c_str()); + if(ret) { + CUtils::dump("RS-MS1A:", (unsigned char *)msg.c_str(), msg.length() + 1U); + CLog::logDebug("RS-MS1A: %s", msg.c_str()); + + + } return ret; @@ -78,32 +82,6 @@ bool CRSMS1AMessageCollector::isValidMsg(const std::string& msg) // return res; } -unsigned int CRSMS1AMessageCollector::calcCRC(const std::string& gpsa, unsigned int start, unsigned int length) -{ - unsigned int icomcrc = 0xFFFFU; - auto end = start + length; - if(end > gpsa.length()) { - end = gpsa.length(); - } - - for (unsigned int j = start; j < end; j++) { - unsigned char ch = (unsigned char)gpsa[j]; - - for (unsigned int i = 0U; i < 8U; i++) { - bool xorflag = (((icomcrc ^ ch) & 0x01U) == 0x01U); - - icomcrc >>= 1; - - if (xorflag) - icomcrc ^= 0x8408U; - - ch >>= 1; - } - } - - return ~icomcrc & 0xFFFFU; -} - unsigned int CRSMS1AMessageCollector::getDataInt(unsigned char * data, unsigned int length) { if(data == nullptr || length == 0U || getSentence().empty()) From 54deb908fad7633124d15e43640a79eadf6de950 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 7 Jan 2022 14:18:02 +0100 Subject: [PATCH 088/201] Do not rely on strtok for key/value parsing fixes #14 --- Config.cpp | 26 +++++------------ Config.h | 2 +- README.md | 1 + Tests/Config/getValue.cpp | 57 ++++++++++++++++++++++++++++++++++++ Tests/Config/load.cpp | 61 +++++++++++++++++++++++++++++++++++++++ Tests/Config/test.cfg | 4 +++ 6 files changed, 131 insertions(+), 20 deletions(-) create mode 100644 Tests/Config/getValue.cpp create mode 100644 Tests/Config/load.cpp create mode 100644 Tests/Config/test.cfg diff --git a/Config.cpp b/Config.cpp index c421da2..ffe8468 100644 --- a/Config.cpp +++ b/Config.cpp @@ -43,7 +43,7 @@ bool CConfig::load() std::ifstream file; file.open(m_filename, std::ios::in); if(!file.is_open()) { - CLog::logError("Failed to open configuration file %s", m_filename); + CLog::logError("Failed to open configuration file %s", m_filename.c_str()); return false; } @@ -93,28 +93,16 @@ void CConfig::stripComment(std::string& s) const free(sdup);// could we use delete sdup here? } -TConfigValue * CConfig::readKeyAndValue(const std::string s) const +TConfigValue * CConfig::readKeyAndValue(const std::string& s) const { TConfigValue* res = nullptr; - - char * sdup = strdup(boost::trim_copy(s).c_str()); - - char * keyPtr = strtok(sdup, "="); - std::string key(keyPtr != nullptr ? keyPtr : ""); - - boost::trim(key); - - if(!key.empty()) { - char * valuePtr = strtok(nullptr, "="); - std::string value(valuePtr != nullptr? valuePtr : ""); - + auto sCopy = boost::trim_copy(s); + auto equalPos = sCopy.find_first_of('='); + if(equalPos != std::string::npos) { res = new TConfigValue; - res->m_key = key; - res->m_value = boost::trim_copy(value); + res->m_key.assign(sCopy.substr(0, equalPos)); + res->m_value.assign(sCopy.substr(equalPos + 1)); } - - free(sdup);// could we use delete sdup here? - return res; } diff --git a/Config.h b/Config.h index d25bca6..aabf432 100644 --- a/Config.h +++ b/Config.h @@ -106,7 +106,7 @@ public: private: void stripComment(std::string& s) const; - TConfigValue * readKeyAndValue(const std::string s) const; + TConfigValue * readKeyAndValue(const std::string& s) const; TConfigValue * lookupValue(const std::string& section, const std::string& key) const; std::string m_filename; diff --git a/README.md b/README.md index 6505de2..fe31074 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ the testing framwrok used is Google Test. # 5. Version History ## 5.1. Version 0.5 +- [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] Trying to connect to ghost ircDDB when no ircDDB is configured ## 5.2. Version 0.4 diff --git a/Tests/Config/getValue.cpp b/Tests/Config/getValue.cpp new file mode 100644 index 0000000..5df3883 --- /dev/null +++ b/Tests/Config/getValue.cpp @@ -0,0 +1,57 @@ +/* + * 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 +#include +#include + +#include "../../Config.h" + +namespace ConfigTests +{ + + class Config_getValue : public ::testing::Test + { + protected: + std::string m_configPath; + + void SetUp() override + { + char buf[2048]; + auto size = ::readlink("/proc/self/exe", buf, 2048); + if(size > 0) { + m_configPath.assign(buf, size); + auto lastSlashPos = m_configPath.find_last_of('/'); + m_configPath.resize(lastSlashPos); + m_configPath.append("/Config/test.cfg"); + } + } + }; + + TEST_F(Config_getValue, getURL) + { + CConfig config(m_configPath); + + bool ret = config.load(); + std::string value; + config.getValue("[XLX]", "hostfileUrl", value, 0U, 2048U, "http://www.f4fxl.org?src=github"); + + EXPECT_TRUE(ret); + EXPECT_STREQ(value.c_str(), "http://xlxapi.rlx.lu/api.php?do=GetXLXDMRMaster"); + } +} \ No newline at end of file diff --git a/Tests/Config/load.cpp b/Tests/Config/load.cpp new file mode 100644 index 0000000..e03cea6 --- /dev/null +++ b/Tests/Config/load.cpp @@ -0,0 +1,61 @@ +/* + * 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 +#include +#include + +#include "../../Config.h" + +namespace ConfigTests +{ + + class Config_load : public ::testing::Test + { + protected: + std::string m_configPath; + + void SetUp() override + { + char buf[2048]; + auto size = ::readlink("/proc/self/exe", buf, 2048); + if(size > 0) { + m_configPath.assign(buf, size); + auto lastSlashPos = m_configPath.find_last_of('/'); + m_configPath.resize(lastSlashPos); + m_configPath.append("/Config/test.cfg"); + } + } + }; + + TEST_F(Config_load, fileExist) + { + CConfig config(m_configPath); + + bool ret = config.load(); + EXPECT_TRUE(ret); + } + + TEST_F(Config_load, fileDoesNotExist) + { + CConfig config("/this/file/does/not/exist/and/if/exists/we/have/a/serious/issue"); + + bool ret = config.load(); + EXPECT_FALSE(ret); + } +} \ No newline at end of file diff --git a/Tests/Config/test.cfg b/Tests/Config/test.cfg new file mode 100644 index 0000000..c7b9920 --- /dev/null +++ b/Tests/Config/test.cfg @@ -0,0 +1,4 @@ +[XLX] +hostfileUrl=http://xlxapi.rlx.lu/api.php?do=GetXLXDMRMaster + + From 18bb1f365b7cf2fd867a698b2488dabf34f9d00f Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 7 Jan 2022 21:23:21 +0100 Subject: [PATCH 089/201] #9 add message crc checks, fix check calculation --- RSMS1AMessageBuilder.cpp | 81 ++++++++++++++++++++- RSMS1AMessageBuilder.h | 8 ++ RSMS1AMessageCollector.cpp | 74 +++---------------- Tests/RSMS1AMessageBuilder/buildMessage.cpp | 21 ++++-- Tests/RSMS1AMessageBuilder/parseMessage.cpp | 67 +++++++++++++++++ 5 files changed, 178 insertions(+), 73 deletions(-) create mode 100644 Tests/RSMS1AMessageBuilder/parseMessage.cpp diff --git a/RSMS1AMessageBuilder.cpp b/RSMS1AMessageBuilder.cpp index 2351d97..8d46f9b 100644 --- a/RSMS1AMessageBuilder.cpp +++ b/RSMS1AMessageBuilder.cpp @@ -16,6 +16,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include + #include "RSMS1AMessageBuilder.h" #include "StringUtils.h" @@ -25,14 +27,14 @@ void CRSMS1AMessageBuilder::buildMessage(std::string& message, const std::string { auto bodyCrc = calculateBodyCRC(body); std::string bodyTmp; - escapeBody(bodyTmp, body + bodyCrc); + escapeBody(bodyTmp, body + (char)bodyCrc); std::string header = CStringUtils::string_format("%s,%s,0011", sender.c_str(), recipient.c_str()); char c1, c2; calcMsgIcomCRC(header, c1, c2); header.push_back(c1); header.push_back(c2); - message = "$$Msg," + header + bodyTmp + '\n'; + message = "$$Msg," + header + bodyTmp + '\r'; } char CRSMS1AMessageBuilder::calculateBodyCRC(const std::string& body) @@ -40,12 +42,16 @@ char CRSMS1AMessageBuilder::calculateBodyCRC(const std::string& body) if(body.length() == 1) return body[0]; - int num = 0; + unsigned int num = 0; for(auto c : body) { num += c; } - return (char)((num & 255) - 128); + auto res = (num & 255); + if(res >= 128) + res -= 128; + + return (char)res; } void CRSMS1AMessageBuilder::escapeBody(std::string& output, const std::string& body) @@ -81,4 +87,71 @@ char CRSMS1AMessageBuilder::doWhatever(char b2) { i = b2 + 55; } return (char) i; +} + +RSMS1A_PARSE_STATUS CRSMS1AMessageBuilder::parseMessage(std::string& sender, std::string& recipient, std::string& body, const std::string& message) +{ + sender.clear(); + recipient.clear(); + body.clear(); + + if(!boost::starts_with(message, "$$Msg,")) + return RSMS_FAIL; + + auto firstCommaPos = message.find_first_of(','); + if(firstCommaPos == std::string::npos || (firstCommaPos + 1) >= message.length()) + return RSMS_FAIL; + + auto secondCommaPos = message.find_first_of(',', firstCommaPos + 1); + if(secondCommaPos == std::string::npos || (secondCommaPos + 1) >= message.length()) + return RSMS_FAIL; + + auto thirdCommaPos = message.find_first_of(',', secondCommaPos + 1); + if(thirdCommaPos == std::string::npos || (thirdCommaPos + 1 + 6) >= message.length()) + return RSMS_FAIL; + + sender.assign(message.substr(firstCommaPos + 1, secondCommaPos - firstCommaPos - 1)); + recipient.assign(message.substr(secondCommaPos + 1, thirdCommaPos - secondCommaPos - 1)); + body.assign(message.substr(thirdCommaPos + 1 + 6)); + unescapeBody(body, std::string(body)); + if(body.length() >= 2U) body.resize(body.length() - 2U); + + // build a message out of what we received in order to check if all checksums matches + // use only header of message to match checksum + std::string messagecheck; + buildMessage(messagecheck, sender, recipient, " "); + messagecheck.resize(messagecheck.length() - 3U);// get rid of body, body check byte and trailing \r + + if(messagecheck != message.substr(0, messagecheck.length())) { + sender.clear(); + recipient.clear(); + body.clear(); + return RSMS_FAIL; // we do not allow any errors in message header + } + + //rebuild complete messsage with body + buildMessage(messagecheck, sender, recipient, body); + if(messagecheck != message) + return RSMS_ERRONEOUS_MSG; // we allow erros to occur in the message body + + return RSMS_OK; +} + +void CRSMS1AMessageBuilder::unescapeBody(std::string& output, const std::string& body) +{ + output.clear(); + if(body.empty()) + return; + + for(unsigned int i = 0U; i < body.length(); i++) { + auto c = body[i]; + auto next = body[i + 1U]; + if(c == 'o' && std::find(m_charsToEscape.begin(), m_charsToEscape.end(), next) != m_charsToEscape.end()) { + output.push_back(next); + i++; + continue; + } + + output.push_back(c); + } } \ No newline at end of file diff --git a/RSMS1AMessageBuilder.h b/RSMS1AMessageBuilder.h index 4819fde..2b13d4b 100644 --- a/RSMS1AMessageBuilder.h +++ b/RSMS1AMessageBuilder.h @@ -21,14 +21,22 @@ #include #include +enum RSMS1A_PARSE_STATUS { + RSMS_FAIL, + RSMS_ERRONEOUS_MSG, + RSMS_OK +}; + class CRSMS1AMessageBuilder { public: static void buildMessage(std::string& message, const std::string& sender, const std::string& recipient, const std::string body); + static RSMS1A_PARSE_STATUS parseMessage(std::string& sender, std::string& recipient, std::string& body, const std::string& message); private: static void calcMsgIcomCRC(const std::string& msg, char& c1, char& c2); static void escapeBody(std::string& output, const std::string& body); + static void unescapeBody(std::string& output, const std::string& body); static void escapeBytes(std::vector output, const std::vector input); static char calculateBodyCRC(const std::string& body); static char doWhatever(char b2); diff --git a/RSMS1AMessageCollector.cpp b/RSMS1AMessageCollector.cpp index d0a2ade..fe91dfc 100644 --- a/RSMS1AMessageCollector.cpp +++ b/RSMS1AMessageCollector.cpp @@ -30,6 +30,7 @@ #include "Log.h" #include "Utils.h" #include "APRSUtils.h" +#include "RSMS1AMessageBuilder.h" const unsigned int APRS_CSUM_LENGTH = 4U; @@ -47,39 +48,8 @@ bool CRSMS1AMessageCollector::isValidSentence(const std::string& sentence) bool CRSMS1AMessageCollector::isValidMsg(const std::string& msg) { - if(msg.empty() || !boost::starts_with(msg, "$$Msg")) - return false; - - // CUtils::dump("RS-MS1A:", (unsigned char *)msg.c_str(), msg.length()); - std::vector splits; - boost::split(splits, msg, boost::is_any_of(",")); - - bool ret = splits.size() >= 4 - && !splits[1].empty() - && !splits[2].empty(); - - if(ret) { - CUtils::dump("RS-MS1A:", (unsigned char *)msg.c_str(), msg.length() + 1U); - CLog::logDebug("RS-MS1A: %s", msg.c_str()); - - - } - - return ret; - - //TODO 2022-01-01 figure out what the heck it is about thic strange CRCs - - // CUtils::dump("RS-MS1A:", (unsigned char *)gpsa.c_str(), gpsa.length() + 1U); - // CLog::logDebug("RS-MS1A: %s", gpsa.c_str()); - - // auto thirdCommaPos = CStringUtils::find_nth(gpsa, 0U, ',', 3); - // auto csum = calcCRC(gpsa, thirdCommaPos + 6 + 1, gpsa.length() - thirdCommaPos - 2U - 6U); - // auto csumStr = CStringUtils::string_format("%06X", csum); - // CLog::logDebug("RS-MS1A CRC: %s", csumStr.c_str()); - - // auto expectedCsum = gpsa.substr(5U, APRS_CSUM_LENGTH); - // bool res = ::strcasecmp(csumStr.c_str(), expectedCsum.c_str()) == 0; - // return res; + // checking validity involves parsing, so we do minumum checks here. Big chekc done in getDataInt + return !msg.empty() && boost::starts_with(msg, "$$Msg"); } unsigned int CRSMS1AMessageCollector::getDataInt(unsigned char * data, unsigned int length) @@ -87,40 +57,18 @@ unsigned int CRSMS1AMessageCollector::getDataInt(unsigned char * data, unsigned if(data == nullptr || length == 0U || getSentence().empty()) return 0U; - auto sentence = getSentence(); - - std::vector splits; - boost::split(splits, sentence, boost::is_any_of(",")); + std::string sender, recipient, body, sentence; + sentence = getSentence(); + auto parseRes = CRSMS1AMessageBuilder::parseMessage(sender, recipient, body, sentence); + + CUtils::dump(CStringUtils::string_format("RS-MS1A Message parsed with result %s", parseRes == RSMS_OK ? "OK" : (parseRes == RSMS_ERRONEOUS_MSG ? "Error in msg body" : "failed")).c_str(), + (unsigned char *)sentence.c_str(), sentence.length()); - bool ret = splits.size() >= 4 - && !splits[1].empty() - && !splits[2].empty(); - if(!ret) { + if(parseRes == RSMS_FAIL) return 0U; - } - - auto sender = splits[1]; - auto recipient = CUtils::ToUpper(splits[2]); - - for(unsigned int i = 0;i < 3; i++) { - splits.erase(splits.begin()); - } - - auto message = boost::join(splits, ","); - if(message.length() > 6) - message = message.substr(6); auto seqNum = rand() % 0xFFFFFU; - - CAPRSUtils::dstarCallsignToAPRS(sender); - CAPRSUtils::dstarCallsignToAPRS(recipient); - recipient.resize(9, ' '); - message.resize(std::max(0 , ((int)message.length()) - 2)); - - //unescape commas in message body - boost::replace_all(message, "o,", ","); - - auto aprsFrame = CStringUtils::string_format("%s-5>APDPRS,DSTAR*::%s:%s{%05X\r\n", sender.c_str(), recipient.c_str(), message.c_str(), seqNum); + auto aprsFrame = CStringUtils::string_format("%s-5>APDPRS,DSTAR*::%s:%s{%05X", sender.c_str(), recipient.c_str(), body.c_str(), seqNum); auto aprsFrameLen = aprsFrame.length(); diff --git a/Tests/RSMS1AMessageBuilder/buildMessage.cpp b/Tests/RSMS1AMessageBuilder/buildMessage.cpp index 17b2550..6312e71 100644 --- a/Tests/RSMS1AMessageBuilder/buildMessage.cpp +++ b/Tests/RSMS1AMessageBuilder/buildMessage.cpp @@ -32,7 +32,7 @@ namespace RSMS1AMessageBuilder std::string message; CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "ABC"); - EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118ABCF\n"); + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118ABCF\r"); } TEST_F(RSMS1AMessageBuilder_buildMessage, A) @@ -40,7 +40,7 @@ namespace RSMS1AMessageBuilder std::string message; CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "A"); - EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118AA\n"); + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118AA\r"); } TEST_F(RSMS1AMessageBuilder_buildMessage, AA) @@ -48,7 +48,7 @@ namespace RSMS1AMessageBuilder std::string message; CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "AA"); - EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118AA\02\n"); + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118AA\02\r"); } TEST_F(RSMS1AMessageBuilder_buildMessage, SalutCommentVasTu) @@ -56,7 +56,7 @@ namespace RSMS1AMessageBuilder std::string message; CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "Salut, comment vas tu?"); - EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118Saluto, comment vas tu?z\n"); + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118Saluto, comment vas tu?z\r"); } TEST_F(RSMS1AMessageBuilder_buildMessage, escapeComma) @@ -64,7 +64,7 @@ namespace RSMS1AMessageBuilder std::string message; CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", ","); - EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118o,o,\n"); + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118o,o,\r"); } TEST_F(RSMS1AMessageBuilder_buildMessage, INeedMoreDollars) @@ -72,6 +72,15 @@ namespace RSMS1AMessageBuilder std::string message; CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL", "I need more $$$$"); - EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118I need more o$o$o$o$\x08\n"); + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL,001118I need more o$o$o$o$\x08\r"); + } + + //"$$Msg,KC3FRA,F4FXL 7,00116Fhello\024\r" + TEST_F(RSMS1AMessageBuilder_buildMessage, hello) + { + std::string message; + CRSMS1AMessageBuilder::buildMessage(message, "KC3FRA", "F4FXL 7", "hello"); + + EXPECT_STREQ(message.c_str(), "$$Msg,KC3FRA,F4FXL 7,00116Fhello\024\r"); } }; \ No newline at end of file diff --git a/Tests/RSMS1AMessageBuilder/parseMessage.cpp b/Tests/RSMS1AMessageBuilder/parseMessage.cpp new file mode 100644 index 0000000..ea155ac --- /dev/null +++ b/Tests/RSMS1AMessageBuilder/parseMessage.cpp @@ -0,0 +1,67 @@ +/* + * 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 + +#include "../../RSMS1AMessageBuilder.h" + +namespace RSMS1AMessageBuilder +{ + class RSMS1AMessageBuilder_parseMessage : public ::testing::Test { + + }; + + TEST_F(RSMS1AMessageBuilder_parseMessage, NoError) + { + std::string message = "$$Msg,KC3FRA,F4FXL,001118Saluto, comment vas tu?z\r"; + std::string sender, recipient, body; + + auto ret = CRSMS1AMessageBuilder::parseMessage(sender, recipient, body, message); + + EXPECT_EQ(ret, RSMS_OK); + EXPECT_STREQ(sender.c_str(), "KC3FRA"); + EXPECT_STREQ(recipient.c_str(), "F4FXL"); + EXPECT_STREQ(body.c_str(), "Salut, comment vas tu?"); + } + + TEST_F(RSMS1AMessageBuilder_parseMessage, ErrorInMessage) + { + std::string message = "$$Msg,KC3FRA,F4FXL,001118Saluto, comlent vas tu?z\r"; + std::string sender, recipient, body; + + auto ret = CRSMS1AMessageBuilder::parseMessage(sender, recipient, body, message); + + EXPECT_EQ(ret, RSMS_ERRONEOUS_MSG); + EXPECT_STREQ(sender.c_str(), "KC3FRA"); + EXPECT_STREQ(recipient.c_str(), "F4FXL"); + EXPECT_STREQ(body.c_str(), "Salut, comlent vas tu?"); + } + + TEST_F(RSMS1AMessageBuilder_parseMessage, ErrorInHeader) + { + std::string message = "$$Msg,KC3FRB,F4FXL,001118Saluto, comment vas tu?z\r"; + std::string sender, recipient, body; + + auto ret = CRSMS1AMessageBuilder::parseMessage(sender, recipient, body, message); + + EXPECT_EQ(ret, RSMS_FAIL); + EXPECT_STREQ(sender.c_str(), ""); + EXPECT_STREQ(recipient.c_str(), ""); + EXPECT_STREQ(body.c_str(), ""); + } +}; \ No newline at end of file From a54eb90b273025789564032a73c9de060f4ae65d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 7 Jan 2022 22:58:07 +0100 Subject: [PATCH 090/201] #9 make every sign explicit --- RSMS1AMessageBuilder.cpp | 24 ++++++++++++------------ RSMS1AMessageBuilder.h | 8 ++++---- Tests/Utils/swap_endian_be.cpp | 13 ++++++++++++- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/RSMS1AMessageBuilder.cpp b/RSMS1AMessageBuilder.cpp index 8d46f9b..e7d3d34 100644 --- a/RSMS1AMessageBuilder.cpp +++ b/RSMS1AMessageBuilder.cpp @@ -21,7 +21,7 @@ #include "RSMS1AMessageBuilder.h" #include "StringUtils.h" -std::vector CRSMS1AMessageBuilder::m_charsToEscape = {-17, 0, 17, 19, -2, -25, 26, -3, -1, 36, 13, 44}; +std::vector CRSMS1AMessageBuilder::m_charsToEscape = {-17, 0, 17, 19, -2, -25, 26, -3, -1, 36, 13, 44}; void CRSMS1AMessageBuilder::buildMessage(std::string& message, const std::string& sender, const std::string& recipient, const std::string body) { @@ -30,28 +30,28 @@ void CRSMS1AMessageBuilder::buildMessage(std::string& message, const std::string escapeBody(bodyTmp, body + (char)bodyCrc); std::string header = CStringUtils::string_format("%s,%s,0011", sender.c_str(), recipient.c_str()); - char c1, c2; + signed char c1, c2; calcMsgIcomCRC(header, c1, c2); header.push_back(c1); header.push_back(c2); message = "$$Msg," + header + bodyTmp + '\r'; } -char CRSMS1AMessageBuilder::calculateBodyCRC(const std::string& body) +signed char CRSMS1AMessageBuilder::calculateBodyCRC(const std::string& body) { if(body.length() == 1) return body[0]; - unsigned int num = 0; - for(auto c : body) { + signed int num = 0; + for(signed char c : body) { num += c; } - auto res = (num & 255); + signed int res = (num & 255); if(res >= 128) res -= 128; - return (char)res; + return (signed char)res; } void CRSMS1AMessageBuilder::escapeBody(std::string& output, const std::string& body) @@ -65,18 +65,18 @@ void CRSMS1AMessageBuilder::escapeBody(std::string& output, const std::string& b } } -void CRSMS1AMessageBuilder::calcMsgIcomCRC(const std::string& msg, char& c1, char& c2) +void CRSMS1AMessageBuilder::calcMsgIcomCRC(const std::string& msg, signed char& c1, signed char& c2) { int num = 0; for(unsigned int i = 0U; i < msg.length(); i++) { num += msg[i]; } - c1 = doWhatever((char)((num >> 4) & 15)); - c2 = doWhatever((char)(num & 15)); + c1 = doWhatever((signed char)((num >> 4) & 15)); + c2 = doWhatever((signed char)(num & 15)); } -char CRSMS1AMessageBuilder::doWhatever(char b2) { +signed char CRSMS1AMessageBuilder::doWhatever(signed char b2) { int i; int i2 = b2 & 255; if (i2 >= 0 && i2 <= 9) { @@ -86,7 +86,7 @@ char CRSMS1AMessageBuilder::doWhatever(char b2) { } else { i = b2 + 55; } - return (char) i; + return (signed char) i; } RSMS1A_PARSE_STATUS CRSMS1AMessageBuilder::parseMessage(std::string& sender, std::string& recipient, std::string& body, const std::string& message) diff --git a/RSMS1AMessageBuilder.h b/RSMS1AMessageBuilder.h index 2b13d4b..142c0e2 100644 --- a/RSMS1AMessageBuilder.h +++ b/RSMS1AMessageBuilder.h @@ -34,12 +34,12 @@ public: static RSMS1A_PARSE_STATUS parseMessage(std::string& sender, std::string& recipient, std::string& body, const std::string& message); private: - static void calcMsgIcomCRC(const std::string& msg, char& c1, char& c2); + static void calcMsgIcomCRC(const std::string& msg, signed char& c1, signed char& c2); static void escapeBody(std::string& output, const std::string& body); static void unescapeBody(std::string& output, const std::string& body); static void escapeBytes(std::vector output, const std::vector input); - static char calculateBodyCRC(const std::string& body); - static char doWhatever(char b2); + static signed char calculateBodyCRC(const std::string& body); + static signed char doWhatever(signed char b2); - static std::vector m_charsToEscape; + static std::vector m_charsToEscape; }; \ No newline at end of file diff --git a/Tests/Utils/swap_endian_be.cpp b/Tests/Utils/swap_endian_be.cpp index 7099a0e..8e3a817 100644 --- a/Tests/Utils/swap_endian_be.cpp +++ b/Tests/Utils/swap_endian_be.cpp @@ -19,6 +19,8 @@ #include #include "../../Utils.h" +#include "../../StringUtils.h" +#include "../../Log.h" class Utils_swap_endian_be : public ::testing::Test { @@ -31,4 +33,13 @@ TEST_F(Utils_swap_endian_be, SwapUINT32_be) { uint32_t res = CUtils::swap_endian_be(test); EXPECT_EQ(res, 0x12345678U); -} \ No newline at end of file +} + + +TEST_F(Utils_swap_endian_be, blabla) { + std::vector charsToEscape = {-17, 0, 17, 19, 128-2, -25, 26, 128-3, -1, 36, 13, 44}; + + for(unsigned int i = 1U; i < charsToEscape.size(); i++) { + CLog::logDebug("%08x - %08x", charsToEscape[i], (unsigned char)charsToEscape[i]); + } +} From 6bd5b2dfc6472446a80bfd52b66384dccf8a0de4 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 7 Jan 2022 23:15:42 +0100 Subject: [PATCH 091/201] #9 correctly format source and dest callsigns --- RSMS1AMessageCollector.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RSMS1AMessageCollector.cpp b/RSMS1AMessageCollector.cpp index fe91dfc..03c36dd 100644 --- a/RSMS1AMessageCollector.cpp +++ b/RSMS1AMessageCollector.cpp @@ -67,6 +67,10 @@ unsigned int CRSMS1AMessageCollector::getDataInt(unsigned char * data, unsigned if(parseRes == RSMS_FAIL) return 0U; + CAPRSUtils::dstarCallsignToAPRS(sender); + CAPRSUtils::dstarCallsignToAPRS(recipient); + recipient.resize(9U, ' '); + auto seqNum = rand() % 0xFFFFFU; auto aprsFrame = CStringUtils::string_format("%s-5>APDPRS,DSTAR*::%s:%s{%05X", sender.c_str(), recipient.c_str(), body.c_str(), seqNum); From 9497bf9ba0691d06db31a233df44dd4785bcb81a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 7 Jan 2022 23:26:25 +0100 Subject: [PATCH 092/201] #9 exit if did not collect any data --- APRSHandler.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/APRSHandler.cpp b/APRSHandler.cpp index 1ebedd9..c8539fc 100644 --- a/APRSHandler.cpp +++ b/APRSHandler.cpp @@ -130,6 +130,11 @@ void CAPRSHandler::writeData(const std::string& callsign, const CAMBEData& data) } unsigned int length = collector->getData(SLOW_DATA_TYPE_GPS, buffer, 400U); + + if(length == 0U) { + return; + } + std::string text((char*)buffer, length); CAPRSFrame frame; From dd1fc8f14c9592322f8d65ebdf91edef11e226b1 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 8 Jan 2022 16:59:08 +0100 Subject: [PATCH 093/201] Add debug config --- .circleci/config.yml | 24 ++++++++++++++++++++++++ Makefile | 6 +++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e148e64..330d480 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,6 +5,29 @@ version: 2.1 # Define a job to be invoked later in a workflow. # See: https://circleci.com/docs/2.0/configuration-reference/#jobs jobs: + build-dstargateway-debug: + # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. + # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor + docker: + - image: cimg/base:stable + # Add steps to the job + # See: https://circleci.com/docs/2.0/configuration-reference/#steps + steps: + - checkout + - run: + name: Install dependencies + command: | + sudo apt-get update + sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev + - run: + name: "Build App" + command: "make ENABLE_DEBUG=1 -j 3 dstargateway" + - run: + name: "Build Tests" + command: "make ENABLE_DEBUG=1 -j 3 tests" + - run: + name: "Run Tests" + command: "make ENABLE_DEBUG=1 run-tests" build-dstargateway: # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor @@ -33,4 +56,5 @@ jobs: workflows: dstar-gateway-workflow: jobs: + - build-dstargateway-debug - build-dstargateway diff --git a/Makefile b/Makefile index b6088c4..973fbaa 100644 --- a/Makefile +++ b/Makefile @@ -21,10 +21,14 @@ export CFG_DIR=/usr/local/etc/ export DATA_DIR=/usr/local/share/dstargateway.d/ export LOG_DIR=/var/log/dstargateway/ +ifeq ($(ENABLE_DEBUG), 1) # choose this if you want debugging help export CPPFLAGS=-g -ggdb -W -Wall -Werror -std=c++17 +else # or, you can choose this for a much smaller executable without debugging help -#CPPFLAGS=-W -Wall -Werror -std=c++17 +CPPFLAGS=-W -O3 -Wall -Werror -std=c++17 +endif + export CC=g++ export LDFLAGS:=-lcurl -pthread From d97aafd44673cbb0f69cb90aed2ec5fb79773f84 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 8 Jan 2022 17:03:37 +0100 Subject: [PATCH 094/201] buidl from clean --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 330d480..3f0951c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,7 +21,7 @@ jobs: sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev - run: name: "Build App" - command: "make ENABLE_DEBUG=1 -j 3 dstargateway" + command: "make ENABLE_DEBUG=1 -j 3 clean dstargateway" - run: name: "Build Tests" command: "make ENABLE_DEBUG=1 -j 3 tests" @@ -44,7 +44,7 @@ jobs: sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev - run: name: "Build App" - command: "make -j 3 dstargateway" + command: "make -j 3 clean dstargateway" - run: name: "Build Tests" command: "make -j 3 tests" From b85705de20a3f9e2924aca38feb1379146576aa8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 8 Jan 2022 17:10:57 +0100 Subject: [PATCH 095/201] Back to one job --- .circleci/config.yml | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3f0951c..af8345a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ version: 2.1 # Define a job to be invoked later in a workflow. # See: https://circleci.com/docs/2.0/configuration-reference/#jobs jobs: - build-dstargateway-debug: + build-dstargateway: # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor docker: @@ -21,40 +21,16 @@ jobs: sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev - run: name: "Build App" - command: "make ENABLE_DEBUG=1 -j 3 clean dstargateway" + command: "make ENABLE_DEBUG=1 -j 3 dstargateway" - run: name: "Build Tests" command: "make ENABLE_DEBUG=1 -j 3 tests" - run: name: "Run Tests" command: "make ENABLE_DEBUG=1 run-tests" - build-dstargateway: - # Specify the execution environment. You can specify an image from Dockerhub or use one of our Convenience Images from CircleCI's Developer Hub. - # See: https://circleci.com/docs/2.0/configuration-reference/#docker-machine-macos-windows-executor - docker: - - image: cimg/base:stable - # Add steps to the job - # See: https://circleci.com/docs/2.0/configuration-reference/#steps - steps: - - checkout - - run: - name: Install dependencies - command: | - sudo apt-get update - sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev - - run: - name: "Build App" - command: "make -j 3 clean dstargateway" - - run: - name: "Build Tests" - command: "make -j 3 tests" - - run: - name: "Run Tests" - command: "make run-tests" # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows workflows: dstar-gateway-workflow: jobs: - - build-dstargateway-debug - build-dstargateway From edd9870412ee49621aac1e198a12ee3886e285c8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 8 Jan 2022 17:11:28 +0100 Subject: [PATCH 096/201] disbale debug --- .circleci/config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index af8345a..e148e64 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,13 +21,13 @@ jobs: sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev - run: name: "Build App" - command: "make ENABLE_DEBUG=1 -j 3 dstargateway" + command: "make -j 3 dstargateway" - run: name: "Build Tests" - command: "make ENABLE_DEBUG=1 -j 3 tests" + command: "make -j 3 tests" - run: name: "Run Tests" - command: "make ENABLE_DEBUG=1 run-tests" + command: "make run-tests" # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows workflows: From ccce139bd013fc9c989e7535d99696445d865ce9 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 8 Jan 2022 17:14:02 +0100 Subject: [PATCH 097/201] Add debug to tasks --- .vscode/tasks.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2fa8b11..8b078ce 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -8,7 +8,7 @@ "type": "shell", "command": "make", "args": [ - "-j3" + "-j3", "ENABLE_DEBUG=1" ], "group": "build", "problemMatcher": [] @@ -19,7 +19,7 @@ "command": "make", "args": [ "-j3", - "tests" + "tests", "ENABLE_DEBUG=1" ], "group": { "kind": "build", From f17518d7238041f7357b7d7b2ffbcfd5edd54dc9 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 8 Jan 2022 18:22:47 +0100 Subject: [PATCH 098/201] remove tests from default build task --- .vscode/tasks.json | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 37a88a4..168ca95 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -9,11 +9,13 @@ "command": "make", "args": [ "-j3", - "tests", "ENABLE_DEBUG=1", - "USE_GPSD=1", + "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] }, { @@ -24,12 +26,9 @@ "-j3", "tests", "ENABLE_DEBUG=1", - "USE_GPSD=1", + "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] } ] From f18452ddfa04a2a774706e5c4f4fc2a17f3fa7b1 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 8 Jan 2022 19:45:46 +0100 Subject: [PATCH 099/201] #9 clean up --- APRSFormater.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/APRSFormater.cpp b/APRSFormater.cpp index ecd1f68..359ca3e 100644 --- a/APRSFormater.cpp +++ b/APRSFormater.cpp @@ -33,13 +33,6 @@ bool CAPRSFormater::frameToString(std::string& output, CAPRSFrame& frame) return false; } - // std::string path(frame.getPath().size() > 0U ? "," : ""); - // for(auto pathItem : frame.getPath()) { - // path.append(boost::trim_copy(pathItem)).push_back(','); - // } - - // boost::trim_right_if(path, [](char c){ return c == ','; }); - auto path = boost::join_if(frame.getPath(), ",", [](std::string s) { return !string_is_blank_or_empty(s); }); CStringUtils::string_format_in_place(output, "%s>%s%s%s:%s", From 7f3058155ccfd764e08e4c2c99d77d30cf161bb6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 9 Jan 2022 07:00:28 +0100 Subject: [PATCH 100/201] update file assocs --- .vscode/settings.json | 57 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a75b395..f39f63c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -16,7 +16,62 @@ "list": "cpp", "vector": "cpp", "optional": "cpp", - "stop_token": "cpp" + "stop_token": "cpp", + "any": "cpp", + "bitset": "cpp", + "memory": "cpp", + "random": "cpp", + "future": "cpp", + "memory_resource": "cpp", + "ranges": "cpp", + "mutex": "cpp", + "condition_variable": "cpp", + "forward_list": "cpp", + "map": "cpp", + "set": "cpp", + "string": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "algorithm": "cpp", + "cctype": "cpp", + "cstddef": "cpp", + "cstdlib": "cpp", + "cwchar": "cpp", + "atomic": "cpp", + "bit": "cpp", + "compare": "cpp", + "cstdint": "cpp", + "exception": "cpp", + "functional": "cpp", + "iterator": "cpp", + "string_view": "cpp", + "tuple": "cpp", + "utility": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "limits": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "typeinfo": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "complex": "cpp", + "concepts": "cpp", + "cstdio": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwctype": "cpp", + "istream": "cpp", + "numbers": "cpp", + "ratio": "cpp", + "semaphore": "cpp", + "streambuf": "cpp", + "system_error": "cpp", + "thread": "cpp", + "typeindex": "cpp", + "variant": "cpp" }, "editor.tokenColorCustomizations": { "textMateRules": [ From 27ce54004670fda527d82b237b00d24bb9935053 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 9 Jan 2022 07:57:27 +0100 Subject: [PATCH 101/201] #9 APRS stuff always uses strings, fix messages not being sent along with GPS --- APRSCollector.cpp | 35 ++++++++++--- APRSCollector.h | 7 ++- APRSEntry.cpp | 1 + APRSHandler.cpp | 53 +++++++------------ APRSHandlerThread.cpp | 2 +- GPSACollector.cpp | 23 ++++++-- GPSACollector.h | 1 + NMEASentenceCollector.cpp | 32 ++++++++---- NMEASentenceCollector.h | 1 + RSMS1AMessageCollector.cpp | 42 +++++++++------ RSMS1AMessageCollector.h | 1 + SentenceCollector.h | 1 + SlowDataCollector.cpp | 6 ++- SlowDataCollector.h | 21 +++++++- SlowDataCollectorThrottle.cpp | 98 +++++++++++++++++++++++++++++++++++ SlowDataCollectorThrottle.h | 46 ++++++++++++++++ 16 files changed, 296 insertions(+), 74 deletions(-) create mode 100644 SlowDataCollectorThrottle.cpp create mode 100644 SlowDataCollectorThrottle.h diff --git a/APRSCollector.cpp b/APRSCollector.cpp index 9f10a18..99fda5f 100644 --- a/APRSCollector.cpp +++ b/APRSCollector.cpp @@ -28,6 +28,7 @@ #include "NMEASentenceCollector.h" #include "GPSACollector.h" #include "RSMS1AMessageCollector.h" +#include "SlowDataCollectorThrottle.h" const unsigned int APRS_CSUM_LENGTH = 4U; const unsigned int APRS_DATA_LENGTH = 300U; @@ -39,14 +40,14 @@ const char APRS_SYMBOL = 'K'; CAPRSCollector::CAPRSCollector() : m_collectors() { - m_collectors.push_back(new CRSMS1AMessageCollector()); - m_collectors.push_back(new CGPSACollector()); - m_collectors.push_back(new CNMEASentenceCollector("$GPRMC")); - m_collectors.push_back(new CNMEASentenceCollector("$GPGGA")); - m_collectors.push_back(new CNMEASentenceCollector("$GPGLL")); - m_collectors.push_back(new CNMEASentenceCollector("$GPVTG")); - m_collectors.push_back(new CNMEASentenceCollector("$GPGSA")); - m_collectors.push_back(new CNMEASentenceCollector("$GPGSV")); + m_collectors.push_back(new CRSMS1AMessageCollector()); // we do not throttle messages, they have highest priority ! + m_collectors.push_back(new CSlowDataCollectorThrottle(new CGPSACollector(), 10U)); + m_collectors.push_back(new CSlowDataCollectorThrottle(new CNMEASentenceCollector("$GPGGA"), 10U)); + m_collectors.push_back(new CSlowDataCollectorThrottle(new CNMEASentenceCollector("$GPGLL"), 10U)); + m_collectors.push_back(new CSlowDataCollectorThrottle(new CNMEASentenceCollector("$GPVTG"), 10U)); + m_collectors.push_back(new CSlowDataCollectorThrottle(new CNMEASentenceCollector("$GPRMC"), 10U)); + m_collectors.push_back(new CSlowDataCollectorThrottle(new CNMEASentenceCollector("$GPGSA"), 10U)); + m_collectors.push_back(new CSlowDataCollectorThrottle(new CNMEASentenceCollector("$GPGSV"), 10U)); } CAPRSCollector::~CAPRSCollector() @@ -99,3 +100,21 @@ unsigned int CAPRSCollector::getData(unsigned char dataType, unsigned char* data } return 0U; } + +void CAPRSCollector::getData(std::function dataHandler) +{ + for(auto collector : m_collectors) { + std::string data; + if(collector->getData(data)) { + dataHandler(data); + collector->reset(); + } + } +} + +void CAPRSCollector::clock(unsigned int ms) +{ + for(auto collector : m_collectors) { + collector->clock(ms); + } +} \ No newline at end of file diff --git a/APRSCollector.h b/APRSCollector.h index 27d4eba..2f955bf 100644 --- a/APRSCollector.h +++ b/APRSCollector.h @@ -21,6 +21,7 @@ #define APRSCollector_H #include +#include #include "SlowDataCollector.h" #include "Defs.h" @@ -47,9 +48,13 @@ public: void sync(); unsigned int getData(unsigned char dataType, unsigned char* data, unsigned int length); + + void getData(std::function dataHandler); + + void clock(unsigned int ms); private: - std::vector m_collectors; + std::vector m_collectors; }; #endif diff --git a/APRSEntry.cpp b/APRSEntry.cpp index 2d1c3d3..13d1b1a 100644 --- a/APRSEntry.cpp +++ b/APRSEntry.cpp @@ -106,6 +106,7 @@ void CAPRSEntry::clock(unsigned int ms) { m_linkStatus.clock(ms); m_timer.clock(ms); + m_collector->clock(ms); } bool CAPRSEntry::isOK() diff --git a/APRSHandler.cpp b/APRSHandler.cpp index c8539fc..dcf275f 100644 --- a/APRSHandler.cpp +++ b/APRSHandler.cpp @@ -122,43 +122,28 @@ void CAPRSHandler::writeData(const std::string& callsign, const CAMBEData& data) return; } - // Check the transmission timer - bool ok = entry->isOK(); - if (!ok) { - collector->reset(); - return; - } - - unsigned int length = collector->getData(SLOW_DATA_TYPE_GPS, buffer, 400U); - - if(length == 0U) { - return; - } - - std::string text((char*)buffer, length); - - CAPRSFrame frame; - if(!CAPRSParser::parseFrame(text, frame)) { - collector->reset(); - CLog::logWarning("Failed to parse DPRS Frame : %s", text.c_str()); - return; - } - - // If we already have a q-construct, don't send it on - if(std::any_of(frame.getPath().begin(), frame.getPath().end(), [] (std::string s) { return !s.empty() && s[0] == 'q'; })) { - CLog::logWarning("DPRS Frame already has q construct, not forwarding to APRS-IS: %s", text.c_str()); - return; - } + collector->getData([=](const std::string& text) + { + CAPRSFrame frame; + if(!CAPRSParser::parseFrame(text, frame)) { + CLog::logWarning("Failed to parse DPRS Frame : %s", text.c_str()); + return; + } - frame.getPath().push_back("qAR"); - frame.getPath().push_back(CStringUtils::string_format("%s-%s", entry->getCallsign().c_str(), entry->getBand().c_str())); - - std::string output ; - CAPRSFormater::frameToString(output, frame); + // If we already have a q-construct, don't send it on + if(std::any_of(frame.getPath().begin(), frame.getPath().end(), [] (std::string s) { return !s.empty() && s[0] == 'q'; })) { + CLog::logWarning("DPRS Frame already has q construct, not forwarding to APRS-IS: %s", text.c_str()); + return; + } - m_thread->write(frame); + frame.getPath().push_back("qAR"); + frame.getPath().push_back(CStringUtils::string_format("%s-%s", entry->getCallsign().c_str(), entry->getBand().c_str())); + + std::string output ; + CAPRSFormater::frameToString(output, frame); - collector->reset(); + m_thread->write(frame); + }); } void CAPRSHandler::writeStatus(const std::string& callsign, const std::string status) diff --git a/APRSHandlerThread.cpp b/APRSHandlerThread.cpp index 2c84c65..7b410a3 100644 --- a/APRSHandlerThread.cpp +++ b/APRSHandlerThread.cpp @@ -216,8 +216,8 @@ void CAPRSHandlerThread::write(CAPRSFrame& frame) std::string frameString; if(CAPRSFormater::frameToString(frameString, frame)) { - boost::trim_if(frameString, [] (char c) { return c == '\r' || c == '\n'; }); // trim all CRLF, we will add our own, just to make sure we get rid of any garbage that might come from slow data + CLog::logTrace("Queued APRS Frame : %s", frameString.c_str()); frameString.append("\r\n"); m_queue.addData(frameString); diff --git a/GPSACollector.cpp b/GPSACollector.cpp index df04ab0..3774713 100644 --- a/GPSACollector.cpp +++ b/GPSACollector.cpp @@ -54,14 +54,14 @@ bool CGPSACollector::isValidGPSA(const std::string& gpsa) unsigned int CGPSACollector::getDataInt(unsigned char * data, unsigned int length) { - if(data == nullptr || length == 0U || getSentence().empty()) + if(data == nullptr || length == 0U) return 0U; - auto aprsFrame = getSentence(); - if(aprsFrame.length() < 11U) + std::string aprsFrame; + + if(!getDataInt(aprsFrame)) return 0U; - aprsFrame = aprsFrame.substr(10).append("\r\n"); auto aprsFrameLen = aprsFrame.length(); if(length < aprsFrameLen) { @@ -74,4 +74,19 @@ unsigned int CGPSACollector::getDataInt(unsigned char * data, unsigned int lengt } return aprsFrameLen; +} + +bool CGPSACollector::getDataInt(std::string& data) +{ + if(getSentence().empty()) + return false; + + data.clear(); + auto aprsFrame = getSentence(); + if(aprsFrame.length() < 11U)//do we have enough data beyond CRC? + return false; + + data = aprsFrame.substr(10); + + return true; } \ No newline at end of file diff --git a/GPSACollector.h b/GPSACollector.h index 056c0ba..2f6d23c 100644 --- a/GPSACollector.h +++ b/GPSACollector.h @@ -30,6 +30,7 @@ public: protected: unsigned int getDataInt(unsigned char * data, unsigned int length); + bool getDataInt(std::string& data); bool isValidSentence(const std::string& sentence); private: diff --git a/NMEASentenceCollector.cpp b/NMEASentenceCollector.cpp index b368060..9caa630 100644 --- a/NMEASentenceCollector.cpp +++ b/NMEASentenceCollector.cpp @@ -76,17 +76,12 @@ unsigned char CNMEASentenceCollector::calcXOR(const std::string& nmea) unsigned int CNMEASentenceCollector::getDataInt(unsigned char * data, unsigned int length) { - if(data == nullptr || length == 0U || getMyCall().empty() || getSentence().empty()) + if(data == nullptr || length == 0U) return 0U; - auto nmea = getSentence(); - fixUpNMEATimeStamp(nmea); - - std::string fromCall = getMyCall(); - CAPRSUtils::dstarCallsignToAPRS(fromCall); - std::string aprsFrame(fromCall); - aprsFrame.append("-5>GPS30,DSTAR*:") - .append(nmea); + std::string aprsFrame; + if(!getDataInt(aprsFrame)) + return 0U; auto aprsFrameLen = aprsFrame.length(); if(length < aprsFrameLen) { @@ -101,6 +96,25 @@ unsigned int CNMEASentenceCollector::getDataInt(unsigned char * data, unsigned i return aprsFrameLen; } +bool CNMEASentenceCollector::getDataInt(std::string& data) +{ + if(getMyCall().empty() || getSentence().empty()) + return false; + + data.clear(); + auto nmea = getSentence(); + fixUpNMEATimeStamp(nmea); + + std::string fromCall = getMyCall(); + CAPRSUtils::dstarCallsignToAPRS(fromCall); + std::string aprsFrame(fromCall); + aprsFrame.append("-5>GPS30,DSTAR*:") + .append(nmea); + + data.assign(aprsFrame); + return true; +} + // When set on manual position Icom radios send 000000.00 as NMEA timestamps // this is a dirty hack to correct this issue. Actually I am not sure about APRS // software being peeky about this except APRS.fi diff --git a/NMEASentenceCollector.h b/NMEASentenceCollector.h index 6368fb5..d6726c5 100644 --- a/NMEASentenceCollector.h +++ b/NMEASentenceCollector.h @@ -30,6 +30,7 @@ public: protected: unsigned int getDataInt(unsigned char * data, unsigned int length); + bool getDataInt(std::string& data); bool isValidSentence(const std::string& sentence); private: diff --git a/RSMS1AMessageCollector.cpp b/RSMS1AMessageCollector.cpp index 03c36dd..81ae9ca 100644 --- a/RSMS1AMessageCollector.cpp +++ b/RSMS1AMessageCollector.cpp @@ -54,9 +54,32 @@ bool CRSMS1AMessageCollector::isValidMsg(const std::string& msg) unsigned int CRSMS1AMessageCollector::getDataInt(unsigned char * data, unsigned int length) { - if(data == nullptr || length == 0U || getSentence().empty()) + if(data == nullptr || length == 0U) return 0U; + std::string aprsFrame; + if(!getDataInt(aprsFrame)) + return 0U; + + auto aprsFrameLen = aprsFrame.length(); + + if(length < aprsFrameLen) { + CLog::logDebug("Not enough space to copy RSMS1A message frame"); + return 0U; + } + + for(unsigned int i = 0U; i < aprsFrameLen; i++){ + data[i] = aprsFrame[i]; + } + + return aprsFrameLen; +} + +bool CRSMS1AMessageCollector::getDataInt(std::string& data) +{ + if(getSentence().empty()) + return false; + std::string sender, recipient, body, sentence; sentence = getSentence(); auto parseRes = CRSMS1AMessageBuilder::parseMessage(sender, recipient, body, sentence); @@ -65,25 +88,14 @@ unsigned int CRSMS1AMessageCollector::getDataInt(unsigned char * data, unsigned (unsigned char *)sentence.c_str(), sentence.length()); if(parseRes == RSMS_FAIL) - return 0U; + return false; CAPRSUtils::dstarCallsignToAPRS(sender); CAPRSUtils::dstarCallsignToAPRS(recipient); recipient.resize(9U, ' '); auto seqNum = rand() % 0xFFFFFU; - auto aprsFrame = CStringUtils::string_format("%s-5>APDPRS,DSTAR*::%s:%s{%05X", sender.c_str(), recipient.c_str(), body.c_str(), seqNum); + CStringUtils::string_format_in_place(data, "%s-5>APDPRS,DSTAR*::%s:%s{%05X", sender.c_str(), recipient.c_str(), body.c_str(), seqNum); - auto aprsFrameLen = aprsFrame.length(); - - if(length < aprsFrameLen) { - CLog::logDebug("Not enough space to copy GPS-A APRS frame"); - return 0U; - } - - for(unsigned int i = 0U; i < aprsFrameLen; i++){ - data[i] = aprsFrame[i]; - } - - return aprsFrameLen; + return true; } \ No newline at end of file diff --git a/RSMS1AMessageCollector.h b/RSMS1AMessageCollector.h index c7bbe24..f741e92 100644 --- a/RSMS1AMessageCollector.h +++ b/RSMS1AMessageCollector.h @@ -30,6 +30,7 @@ public: protected: unsigned int getDataInt(unsigned char * data, unsigned int length); + bool getDataInt(std::string& data); bool isValidSentence(const std::string& sentence); private: diff --git a/SentenceCollector.h b/SentenceCollector.h index d8a6c3d..2c3b1b9 100644 --- a/SentenceCollector.h +++ b/SentenceCollector.h @@ -32,6 +32,7 @@ protected: bool addData(const unsigned char * data); virtual unsigned int getDataInt(unsigned char * data, unsigned int length) = 0; + virtual bool getDataInt(std::string& data) = 0; static void dstarCallsignToAPRS(std::string& call); std::string getSentence(); diff --git a/SlowDataCollector.cpp b/SlowDataCollector.cpp index 004226e..b9caad0 100644 --- a/SlowDataCollector.cpp +++ b/SlowDataCollector.cpp @@ -85,10 +85,14 @@ unsigned int CSlowDataCollector::getData(unsigned char * data, unsigned int leng return getDataInt(data, length); } +bool CSlowDataCollector::getData(std::string& data) +{ + return getDataInt(data); +} + void CSlowDataCollector::reset() { m_state = SS_FIRST; - m_myCall.clear(); resetInt(); } diff --git a/SlowDataCollector.h b/SlowDataCollector.h index 03d4de1..f2389f9 100644 --- a/SlowDataCollector.h +++ b/SlowDataCollector.h @@ -24,7 +24,23 @@ #include "DStarDefines.h" #include "Defs.h" -class CSlowDataCollector +class ISlowDataCollector +{ +public: + virtual ~ISlowDataCollector() { } ; + + virtual std::string getMyCall() const = 0; + virtual void setMyCall(const std::string& mycall) = 0; + virtual bool writeData(const unsigned char* data) = 0; + virtual void sync() = 0; + virtual unsigned int getData(unsigned char* data, unsigned int length) = 0; + virtual bool getData(std::string& data) = 0; + virtual void reset() = 0; + virtual unsigned char getDataType() = 0; + virtual void clock(unsigned int ms) = 0; +}; + +class CSlowDataCollector : public ISlowDataCollector { public: CSlowDataCollector(unsigned char slowDataType); @@ -35,12 +51,15 @@ public: bool writeData(const unsigned char* data); void sync(); unsigned int getData(unsigned char* data, unsigned int length); + bool getData(std::string& data); void reset(); unsigned char getDataType(); + void clock(unsigned int) { }; protected: virtual bool addData(const unsigned char* data) = 0; virtual unsigned int getDataInt(unsigned char* data, unsigned int length) = 0; + virtual bool getDataInt(std::string& data) = 0; virtual void resetInt() { } private: diff --git a/SlowDataCollectorThrottle.cpp b/SlowDataCollectorThrottle.cpp new file mode 100644 index 0000000..8d97fe1 --- /dev/null +++ b/SlowDataCollectorThrottle.cpp @@ -0,0 +1,98 @@ +/* + * 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 + +#include "SlowDataCollectorThrottle.h" + +CSlowDataCollectorThrottle::CSlowDataCollectorThrottle(ISlowDataCollector* collector, unsigned int timeout) : +m_collector(collector), +m_timer(1000U, timeout), +m_isFirst(true) +{ + assert(collector != nullptr); +} + +CSlowDataCollectorThrottle::~CSlowDataCollectorThrottle() +{ + delete m_collector; +} + +std::string CSlowDataCollectorThrottle::getMyCall() const +{ + return m_collector->getMyCall(); +} + +void CSlowDataCollectorThrottle::setMyCall(const std::string& mycall) +{ + m_isFirst = true; + m_collector->setMyCall(mycall); +} +bool CSlowDataCollectorThrottle::writeData(const unsigned char* data) +{ + m_isComplete = false; + bool complete = m_collector->writeData(data); + if(complete){ + if(m_isFirst) { + m_isFirst = false; + m_isComplete = true; + m_timer.start(); + return true; + } + + if(m_timer.hasExpired()) { + m_isComplete = true; + m_timer.start(); + return true; + } + } + + return false; +} +void CSlowDataCollectorThrottle::sync() +{ + m_collector->sync(); +} +unsigned int CSlowDataCollectorThrottle::getData(unsigned char* data, unsigned int length) +{ + if(m_isComplete) + return m_collector->getData(data, length); + + return 0U; +} +bool CSlowDataCollectorThrottle::getData(std::string& data) +{ + if(m_isComplete) + return m_collector->getData(data); + + return false; +} +void CSlowDataCollectorThrottle::reset() +{ + m_timer.start(); + m_collector->reset(); +} +unsigned char CSlowDataCollectorThrottle::getDataType() +{ + return m_collector->getDataType(); +} + +void CSlowDataCollectorThrottle::clock(unsigned int ms) +{ + m_timer.clock(ms); +} \ No newline at end of file diff --git a/SlowDataCollectorThrottle.h b/SlowDataCollectorThrottle.h new file mode 100644 index 0000000..f7fbd23 --- /dev/null +++ b/SlowDataCollectorThrottle.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include "SlowDataCollector.h" +#include "Timer.h" + +class CSlowDataCollectorThrottle : public ISlowDataCollector +{ +public: + CSlowDataCollectorThrottle(ISlowDataCollector* collector, unsigned int timeout); + ~CSlowDataCollectorThrottle(); + std::string getMyCall() const; + void setMyCall(const std::string& mycall); + bool writeData(const unsigned char* data); + void sync(); + unsigned int getData(unsigned char* data, unsigned int length); + bool getData(std::string& data); + void reset(); + unsigned char getDataType(); + void clock(unsigned int ms); + +private: + ISlowDataCollector* m_collector; + CTimer m_timer; + bool m_isFirst; + bool m_isComplete; +}; \ No newline at end of file From 4b7dead48367b3c14c607ddba38952d46ee8218e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 9 Jan 2022 08:04:45 +0100 Subject: [PATCH 102/201] #9 Do not block on read for 10 seconds --- APRSHandlerThread.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/APRSHandlerThread.cpp b/APRSHandlerThread.cpp index 7b410a3..aab86cb 100644 --- a/APRSHandlerThread.cpp +++ b/APRSHandlerThread.cpp @@ -33,6 +33,7 @@ // #define DUMP_TX const unsigned int APRS_TIMEOUT = 10U; +const unsigned int APRS_READ_TIMEOUT = 1U; CAPRSHandlerThread::CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port) : CThread(), @@ -151,7 +152,7 @@ void* CAPRSHandlerThread::Entry() } { std::string line; - int length = m_socket.readLine(line, APRS_TIMEOUT); + int length = m_socket.readLine(line, APRS_READ_TIMEOUT); /*if (length == 0) CLog::logWarning(("No response from the APRS server after %u seconds", APRS_TIMEOUT);*/ From 25a439d16c7c588c52b1182a1e7252ec4f471c38 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 9 Jan 2022 18:09:42 +0100 Subject: [PATCH 103/201] #9 Handle keeap alives from server --- APRSHandlerThread.cpp | 28 ++++++++++++++++------------ APRSHandlerThread.h | 1 + 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/APRSHandlerThread.cpp b/APRSHandlerThread.cpp index aab86cb..bd67dcd 100644 --- a/APRSHandlerThread.cpp +++ b/APRSHandlerThread.cpp @@ -34,6 +34,7 @@ const unsigned int APRS_TIMEOUT = 10U; const unsigned int APRS_READ_TIMEOUT = 1U; +const unsigned int APRS_KEEP_ALIVE_TIMEOUT = 60U; CAPRSHandlerThread::CAPRSHandlerThread(const std::string& callsign, const std::string& password, const std::string& address, const std::string& hostname, unsigned int port) : CThread(), @@ -45,6 +46,7 @@ m_queue(20U), m_exit(false), m_connected(false), m_reconnectTimer(1000U), +m_keepAliveTimer(1000U, APRS_KEEP_ALIVE_TIMEOUT), m_tries(0U), m_APRSReadCallbacks(), m_filter(), @@ -72,6 +74,7 @@ m_queue(20U), m_exit(false), m_connected(false), m_reconnectTimer(1000U), +m_keepAliveTimer(1000U, APRS_KEEP_ALIVE_TIMEOUT), m_tries(0U), m_APRSReadCallbacks(), m_filter(filter), @@ -121,6 +124,7 @@ void* CAPRSHandlerThread::Entry() } try { + m_keepAliveTimer.start(); while (!m_exit) { if (!m_connected) { if (m_reconnectTimer.isRunning() && m_reconnectTimer.hasExpired()) { @@ -131,6 +135,9 @@ void* CAPRSHandlerThread::Entry() CLog::logInfo("Reconnect attempt to the APRS server has failed"); startReconnectionTimer(); } + else { + m_keepAliveTimer.start(); + } } } @@ -154,22 +161,18 @@ void* CAPRSHandlerThread::Entry() std::string line; int length = m_socket.readLine(line, APRS_READ_TIMEOUT); - /*if (length == 0) - CLog::logWarning(("No response from the APRS server after %u seconds", APRS_TIMEOUT);*/ - - if (length < 0) { + if (length < 0 || m_keepAliveTimer.hasExpired()) { m_connected = false; m_socket.close(); CLog::logError("Error when reading from the APRS server"); startReconnectionTimer(); } - - if(line.length() > 0 && line[0] != '#') - CLog::logDebug("Received APRS Frame : %s", line.c_str()); - - if(length > 0 && line[0] != '#'//check if we have something and if that something is an APRS frame - && m_APRSReadCallbacks.size() > 0U)//do we have someone wanting an APRS Frame? - { + else if(length > 0 && line[0] == '#') { + m_keepAliveTimer.start(); + } + else if(line.length() > 0 && line[0] != '#') { + m_keepAliveTimer.start(); + CLog::logDebug("APRS <== %s", line.c_str()); CAPRSFrame readFrame; if(CAPRSParser::parseFrame(line, readFrame)) { for(auto cb : m_APRSReadCallbacks) { @@ -179,7 +182,6 @@ void* CAPRSHandlerThread::Entry() } } } - } } @@ -240,10 +242,12 @@ void CAPRSHandlerThread::stop() void CAPRSHandlerThread::clock(unsigned int ms) { m_reconnectTimer.clock(ms); + m_keepAliveTimer.clock(ms); } bool CAPRSHandlerThread::connect() { + m_socket.close(); bool ret = m_socket.open(); if (!ret) return false; diff --git a/APRSHandlerThread.h b/APRSHandlerThread.h index 73642ba..01410de 100644 --- a/APRSHandlerThread.h +++ b/APRSHandlerThread.h @@ -58,6 +58,7 @@ private: bool m_exit; bool m_connected; CTimer m_reconnectTimer; + CTimer m_keepAliveTimer; unsigned int m_tries; std::vector m_APRSReadCallbacks; std::string m_filter; From 761fca2a46347b5fe639e11b622f718e2fc9bd01 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 9 Jan 2022 18:27:05 +0100 Subject: [PATCH 104/201] #9 rename namespace --- Tests/RSMS1AMessageBuilder/buildMessage.cpp | 2 +- Tests/RSMS1AMessageBuilder/parseMessage.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/RSMS1AMessageBuilder/buildMessage.cpp b/Tests/RSMS1AMessageBuilder/buildMessage.cpp index 6312e71..aefcb68 100644 --- a/Tests/RSMS1AMessageBuilder/buildMessage.cpp +++ b/Tests/RSMS1AMessageBuilder/buildMessage.cpp @@ -20,7 +20,7 @@ #include "../../RSMS1AMessageBuilder.h" -namespace RSMS1AMessageBuilder +namespace RSMS1AMessageBuilderTests { class RSMS1AMessageBuilder_buildMessage : public ::testing::Test { diff --git a/Tests/RSMS1AMessageBuilder/parseMessage.cpp b/Tests/RSMS1AMessageBuilder/parseMessage.cpp index ea155ac..5e1c82d 100644 --- a/Tests/RSMS1AMessageBuilder/parseMessage.cpp +++ b/Tests/RSMS1AMessageBuilder/parseMessage.cpp @@ -20,7 +20,7 @@ #include "../../RSMS1AMessageBuilder.h" -namespace RSMS1AMessageBuilder +namespace RSMS1AMessageBuilderTests { class RSMS1AMessageBuilder_parseMessage : public ::testing::Test { From da924acb7ca500b8667e3e6595985b18751b0481 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 9 Jan 2022 22:19:42 +0100 Subject: [PATCH 105/201] #9 It works ! Still need to figure out interleaved data and acks --- APRSUnit.cpp | 88 +++++++++++++++++---------------- APRSUnit.h | 9 +++- APRStoDPRS.cpp | 68 +++++++++++++++++++++++++ APRStoDPRS.h | 33 +++++++++++++ Tests/APRStoDPRS/aprsToDPRS.cpp | 64 ++++++++++++++++++++++++ 5 files changed, 218 insertions(+), 44 deletions(-) create mode 100644 APRStoDPRS.cpp create mode 100644 APRStoDPRS.h create mode 100644 Tests/APRStoDPRS/aprsToDPRS.cpp diff --git a/APRSUnit.cpp b/APRSUnit.cpp index b46a598..4dd4b1f 100644 --- a/APRSUnit.cpp +++ b/APRSUnit.cpp @@ -21,15 +21,20 @@ #include "APRSUnit.h" #include "APRSFormater.h" #include "StringUtils.h" -#include "APRSUtils.h" -#include "SlowDataEncoder.h" +#include "APRStoDPRS.h" CAPRSUnit::CAPRSUnit(IRepeaterCallback * repeaterHandler) : m_frameBuffer(20U), m_status(APS_IDLE), m_repeaterHandler(repeaterHandler), m_headerData(nullptr), -m_timer(1000U, 2U) +m_slowData(nullptr), +m_out(0U), +m_seq(0U), +m_totalNeeded(0U), +m_timer(1000U, 2U), +m_dprs(), +m_start() { m_timer.start(); } @@ -40,75 +45,72 @@ void CAPRSUnit::writeFrame(CAPRSFrame& frame) frameCopy->getPath().clear();//path is of no use for us, just clear it m_frameBuffer.push_back(frameCopy); + m_timer.start(); } void CAPRSUnit::clock(unsigned int ms) { m_timer.clock(ms); if(m_status == APS_IDLE && !m_frameBuffer.empty() && m_timer.hasExpired()) { + m_status = APS_TRANSMIT; auto frame = m_frameBuffer.front(); + m_frameBuffer.pop_front(); - m_id = CHeaderData::createId(); + m_headerData = new CHeaderData(); + CAPRSToDPRS::aprsToDPRS(m_dprs, *m_headerData, *frame); - m_headerData = new CHeaderData(); - m_headerData->setMyCall1(frame->getSource()); - m_headerData->setMyCall2("APRS"); - m_headerData->setYourCall("CQCQCQ "); - m_headerData->setId(m_id); + m_slowData = new CSlowDataEncoder(); + // icom rs-ms1 seem to not support messaiging mixed with other slow data + // send the message on its own for now + // m_slowData->setHeaderData(*m_headerData); + m_slowData->setGPSData(m_dprs); + // m_slowData->setTextData("APRS to DPRS"); - m_repeaterHandler->process(*m_headerData, DIR_INCOMING, AS_INFO); - - m_status = APS_TRANSMIT; - } + m_totalNeeded = (m_slowData->getInterleavedDataLength() / (DATA_FRAME_LENGTH_BYTES)) * 2U; - if(m_status == APS_TRANSMIT && !m_frameBuffer.empty()) - { - auto frame = m_frameBuffer.front(); - std::string frameString; - CAPRSFormater::frameToString(frameString, *frame); - boost::trim_right_if(frameString, [](char c) { return c == '\n' || c == '\r'; }); - frameString.push_back('\r'); + m_repeaterHandler->process(*m_headerData, DIR_INCOMING, AS_INFO); - std::string crc = CStringUtils::string_format("$$CRC%04X", CAPRSUtils::calcGPSAIcomCRC(frameString)); - frameString.insert(0, crc); + m_out = 0U; + m_seq = 0U; - CSlowDataEncoder encoder; - encoder.setHeaderData(*m_headerData); - encoder.setGPSData(frameString); - encoder.setTextData("APRS to DPRS"); + m_start = std::chrono::high_resolution_clock::now(); + return; + } - CAMBEData data; - data.setId(m_id); + if(m_status == APS_TRANSMIT) { + unsigned int needed = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - m_start).count(); + needed /= DSTAR_FRAME_TIME_MS; - unsigned int out = 0U; - unsigned int dataOut = 0U; - unsigned int needed = (encoder.getInterleavedDataLength() / (DATA_FRAME_LENGTH_BYTES)) * 2U; unsigned char buffer[DV_FRAME_LENGTH_BYTES]; - while (dataOut < needed) { - data.setSeq(out); + while (m_out < needed && m_out < m_totalNeeded) { + CAMBEData data; + data.setId(m_headerData->getId()); + data.setSeq(m_seq); + if(m_out == m_totalNeeded - 1U) + data.setEnd(true); ::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES); // Insert sync bytes when the sequence number is zero, slow data otherwise - if (out == 0U) { + if (m_seq == 0U) { ::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES); } else { - encoder.getInterleavedData(buffer + VOICE_FRAME_LENGTH_BYTES); - dataOut++; + m_slowData->getInterleavedData(buffer + VOICE_FRAME_LENGTH_BYTES); + m_out++; } data.setData(buffer, DV_FRAME_LENGTH_BYTES); - m_repeaterHandler->process(data, DIR_INCOMING, AS_INFO); - out++; - if (out == 21U) out = 0U; + m_seq++; + if (m_seq == 21U) m_seq = 0U; } - m_frameBuffer.pop_front(); - delete frame; - m_status = APS_IDLE; - m_timer.start(); + if(m_out >= m_totalNeeded) { + m_status = APS_IDLE; + delete m_headerData; + delete m_slowData; + } } } \ No newline at end of file diff --git a/APRSUnit.h b/APRSUnit.h index 454c4cd..466f6d5 100644 --- a/APRSUnit.h +++ b/APRSUnit.h @@ -20,10 +20,12 @@ #include #include +#include #include "APRSFrame.h" #include "RepeaterCallback.h" #include "Timer.h" +#include "SlowDataEncoder.h" enum APRSUNIT_STATUS { APS_IDLE, @@ -43,9 +45,14 @@ private: boost::circular_buffer m_frameBuffer; APRSUNIT_STATUS m_status; IRepeaterCallback * m_repeaterHandler; - unsigned int m_id; CHeaderData * m_headerData; + CSlowDataEncoder * m_slowData; + unsigned int m_out; + unsigned int m_seq; + unsigned int m_totalNeeded; CTimer m_timer; + std::string m_dprs; + std::chrono::high_resolution_clock::time_point m_start; }; diff --git a/APRStoDPRS.cpp b/APRStoDPRS.cpp new file mode 100644 index 0000000..423932f --- /dev/null +++ b/APRStoDPRS.cpp @@ -0,0 +1,68 @@ +/* + * 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 + +#include "APRStoDPRS.h" +#include "Log.h" +#include "RSMS1AMessageBuilder.h" + +bool CAPRSToDPRS::aprsToDPRS(std::string& dprs, CHeaderData& header, CAPRSFrame& frame) +{ + dprs.clear(); + switch (frame.getType()) + { + case APFT_MESSAGE : + return messageToDPRS(dprs, header, frame); + default: + break; + } + + return false; +} + +bool CAPRSToDPRS::messageToDPRS(std::string& dprs, CHeaderData& header, CAPRSFrame& frame) +{ + auto frameBody = frame.getBody(); + if(frameBody.length() < 11 || frameBody[0] != ':' || frameBody[10] != ':') { + CLog::logDebug("Invalid APRS message body : %s", frameBody.c_str()); + return false; + } + + // extract recipient + auto recipient = boost::trim_copy(frameBody.substr(1, 9)); + if(recipient.length() == 0U) { + CLog::logDebug("APRS message has no recipient"); + return false; + } + auto dashPos = recipient.find_first_of('-'); + if(dashPos != std::string::npos) + recipient = recipient.substr(0, dashPos); + + + auto messageBody = boost::trim_copy(frameBody.substr(11)); + + header.setId(header.createId()); + header.setMyCall1(frame.getSource()); + header.setMyCall2("MSG"); + header.setYourCall(recipient); + + CRSMS1AMessageBuilder::buildMessage(dprs, frame.getSource(), recipient, messageBody); + + return true; +} \ No newline at end of file diff --git a/APRStoDPRS.h b/APRStoDPRS.h new file mode 100644 index 0000000..2e185d7 --- /dev/null +++ b/APRStoDPRS.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include "HeaderData.h" +#include "APRSFrame.h" + +class CAPRSToDPRS +{ +public: + static bool aprsToDPRS(std::string& dprs, CHeaderData& header, CAPRSFrame& frame); + +private: + static bool messageToDPRS(std::string& drps, CHeaderData& header, CAPRSFrame& frame); +}; \ No newline at end of file diff --git a/Tests/APRStoDPRS/aprsToDPRS.cpp b/Tests/APRStoDPRS/aprsToDPRS.cpp new file mode 100644 index 0000000..94f8b29 --- /dev/null +++ b/Tests/APRStoDPRS/aprsToDPRS.cpp @@ -0,0 +1,64 @@ +/* + * 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 + +#include "../../APRStoDPRS.h" + +namespace APRStoDPRSTests +{ + class APRStoDPRS_aprsToDPRS : public ::testing::Test { + + }; + + TEST_F(APRStoDPRS_aprsToDPRS, validMessage) + { + CAPRSFrame frame("KC3FRA", "APRS", {"WIDE1-1", "WIDE2-2"}, ":F4FXL :Salut, comment vas tu?", APFT_MESSAGE); + + std::string dprs; + CHeaderData header; + bool ret = CAPRSToDPRS::aprsToDPRS(dprs, header, frame); + + EXPECT_TRUE(ret); + EXPECT_STREQ(dprs.c_str(), "$$Msg,KC3FRA,F4FXL,001118Saluto, comment vas tu?z\r"); + } + + TEST_F(APRStoDPRS_aprsToDPRS, validMessageRecipientWithSSID) + { + CAPRSFrame frame("KC3FRA", "APRS", {"WIDE1-1", "WIDE2-2"}, ":F4FXL-7 :Salut, comment vas tu?", APFT_MESSAGE); + + std::string dprs; + CHeaderData header; + bool ret = CAPRSToDPRS::aprsToDPRS(dprs, header, frame); + + EXPECT_TRUE(ret); + EXPECT_STREQ(dprs.c_str(), "$$Msg,KC3FRA,F4FXL,001118Saluto, comment vas tu?z\r"); + } + + TEST_F(APRStoDPRS_aprsToDPRS, emptyRecipient) + { + CAPRSFrame frame("KC3FRA", "APRS", {"WIDE1-1", "WIDE2-2"}, ": :Salut, comment vas tu?", APFT_MESSAGE); + + std::string dprs; + CHeaderData header; + bool ret = CAPRSToDPRS::aprsToDPRS(dprs, header, frame); + + EXPECT_FALSE(ret); + EXPECT_STREQ(dprs.c_str(), ""); + } +} From 5bcaef8f7a1b1d8a1c03b9992c2f795af103b93f Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 10 Jan 2022 20:18:47 +0100 Subject: [PATCH 106/201] #9 Add more logging --- APRSHandlerThread.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/APRSHandlerThread.cpp b/APRSHandlerThread.cpp index bd67dcd..b13e99b 100644 --- a/APRSHandlerThread.cpp +++ b/APRSHandlerThread.cpp @@ -127,9 +127,11 @@ void* CAPRSHandlerThread::Entry() m_keepAliveTimer.start(); while (!m_exit) { if (!m_connected) { + Sleep(100U); if (m_reconnectTimer.isRunning() && m_reconnectTimer.hasExpired()) { m_reconnectTimer.stop(); + CLog::logDebug("Trying to reconnect to the APRS server"); m_connected = connect(); if (!m_connected) { CLog::logInfo("Reconnect attempt to the APRS server has failed"); @@ -153,7 +155,7 @@ void* CAPRSHandlerThread::Entry() if (!ret) { m_connected = false; m_socket.close(); - CLog::logInfo("Connection to the APRS thread has failed"); + CLog::logInfo("Error when writing to the APRS server"); startReconnectionTimer(); } } @@ -284,7 +286,7 @@ bool CAPRSHandlerThread::connect() return false; } if (length < 0) { - CLog::logInfo("Error when reading from the APRS server"); + CLog::logInfo("Error when reading from the APRS server (connect)"); m_socket.close(); return false; } @@ -303,6 +305,8 @@ void CAPRSHandlerThread::startReconnectionTimer() if (m_tries > 10U) m_tries = 10U; + CLog::logDebug("Next APRS reconnection try in %u minute", m_tries); + m_reconnectTimer.setTimeout(m_tries * 60U); m_reconnectTimer.start(); } From eada741467a8e346ce03e2e9321aefa8616ad822 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 11 Jan 2022 20:07:07 +0100 Subject: [PATCH 107/201] remove test filter --- APRSHandler.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/APRSHandler.cpp b/APRSHandler.cpp index dcf275f..4d6b81a 100644 --- a/APRSHandler.cpp +++ b/APRSHandler.cpp @@ -47,7 +47,7 @@ m_idFrameProvider(nullptr) assert(!gateway.empty()); assert(!password.empty()); - m_thread = new CAPRSHandlerThread(gateway, password, address, hostname, port, "m/20"); + m_thread = new CAPRSHandlerThread(gateway, password, address, hostname, port); m_gateway = gateway; m_gateway = m_gateway.substr(0, LONG_CALLSIGN_LENGTH - 1U); From e4e4056af0f44080bf0243535416849d5c28110e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 12 Jan 2022 22:31:27 +0100 Subject: [PATCH 108/201] #9 remove debug log --- GPSACollector.cpp | 1 + RSMS1AMessageCollector.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/GPSACollector.cpp b/GPSACollector.cpp index 3774713..ccbe4a6 100644 --- a/GPSACollector.cpp +++ b/GPSACollector.cpp @@ -37,6 +37,7 @@ CSentenceCollector(SLOW_DATA_TYPE_GPS, "$$CRC", '\x0D') bool CGPSACollector::isValidSentence(const std::string& sentence) { + CLog::logDebug("GPSA"); return isValidGPSA(sentence); } diff --git a/RSMS1AMessageCollector.cpp b/RSMS1AMessageCollector.cpp index 81ae9ca..aa62ee7 100644 --- a/RSMS1AMessageCollector.cpp +++ b/RSMS1AMessageCollector.cpp @@ -48,6 +48,7 @@ bool CRSMS1AMessageCollector::isValidSentence(const std::string& sentence) bool CRSMS1AMessageCollector::isValidMsg(const std::string& msg) { + CLog::logDebug("RS-MS1A"); // checking validity involves parsing, so we do minumum checks here. Big chekc done in getDataInt return !msg.empty() && boost::starts_with(msg, "$$Msg"); } From 686134060d17b929c8d2a0497b936cc157cde2e8 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 12 Jan 2022 22:31:44 +0100 Subject: [PATCH 109/201] #9 clean up --- APRSCollector.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/APRSCollector.cpp b/APRSCollector.cpp index 99fda5f..afba4d0 100644 --- a/APRSCollector.cpp +++ b/APRSCollector.cpp @@ -30,13 +30,6 @@ #include "RSMS1AMessageCollector.h" #include "SlowDataCollectorThrottle.h" -const unsigned int APRS_CSUM_LENGTH = 4U; -const unsigned int APRS_DATA_LENGTH = 300U; -const unsigned int SLOW_DATA_BLOCK_LENGTH = 6U; - -const char APRS_OVERLAY = '\\'; -const char APRS_SYMBOL = 'K'; - CAPRSCollector::CAPRSCollector() : m_collectors() { @@ -68,6 +61,7 @@ void CAPRSCollector::writeHeader(const std::string& callsign) bool CAPRSCollector::writeData(const unsigned char* data) { bool ret = false; + for(auto collector : m_collectors) { bool ret2 = collector->writeData(data); ret = ret || ret2; From 1314cde26aac3c03e74aa102e32db6cad50bbaae Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 12 Jan 2022 22:32:05 +0100 Subject: [PATCH 110/201] #9 clean up --- APRStoDPRS.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/APRStoDPRS.cpp b/APRStoDPRS.cpp index 423932f..8b524a1 100644 --- a/APRStoDPRS.cpp +++ b/APRStoDPRS.cpp @@ -46,7 +46,7 @@ bool CAPRSToDPRS::messageToDPRS(std::string& dprs, CHeaderData& header, CAPRSFra // extract recipient auto recipient = boost::trim_copy(frameBody.substr(1, 9)); - if(recipient.length() == 0U) { + if(recipient.empty()) { CLog::logDebug("APRS message has no recipient"); return false; } @@ -54,7 +54,7 @@ bool CAPRSToDPRS::messageToDPRS(std::string& dprs, CHeaderData& header, CAPRSFra if(dashPos != std::string::npos) recipient = recipient.substr(0, dashPos); - + //extract message body auto messageBody = boost::trim_copy(frameBody.substr(11)); header.setId(header.createId()); From 2e64428ccd341a7734f505fe1ec530de434ca3fe Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 12 Jan 2022 22:33:03 +0100 Subject: [PATCH 111/201] #9 fix interleaved data, still need a proper unittest --- APRSUnit.cpp | 7 +++---- SlowDataEncoder.cpp | 33 ++++++++++++++++++--------------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/APRSUnit.cpp b/APRSUnit.cpp index 4dd4b1f..49e7f4b 100644 --- a/APRSUnit.cpp +++ b/APRSUnit.cpp @@ -60,11 +60,10 @@ void CAPRSUnit::clock(unsigned int ms) CAPRSToDPRS::aprsToDPRS(m_dprs, *m_headerData, *frame); m_slowData = new CSlowDataEncoder(); - // icom rs-ms1 seem to not support messaiging mixed with other slow data - // send the message on its own for now - // m_slowData->setHeaderData(*m_headerData); + + m_slowData->setHeaderData(*m_headerData); m_slowData->setGPSData(m_dprs); - // m_slowData->setTextData("APRS to DPRS"); + m_slowData->setTextData("APRS to DPRS"); m_totalNeeded = (m_slowData->getInterleavedDataLength() / (DATA_FRAME_LENGTH_BYTES)) * 2U; diff --git a/SlowDataEncoder.cpp b/SlowDataEncoder.cpp index 2dd3953..54be29b 100644 --- a/SlowDataEncoder.cpp +++ b/SlowDataEncoder.cpp @@ -17,6 +17,7 @@ #include "SlowDataEncoder.h" #include "CCITTChecksum.h" #include "DStarDefines.h" +#include "Utils.h" const unsigned int SLOW_DATA_BLOCK_SIZE = 6U; @@ -130,14 +131,14 @@ void CSlowDataEncoder::getInterleavedData(unsigned char* data) getHeaderData(data); else { buildInterleavedData(); - getData(m_interleavedData, data, m_interleavedPtr, m_gpsDataFullSize); + getData(m_interleavedData, data, m_interleavedPtr, m_interleavedDataFullSize); } } void CSlowDataEncoder::buildInterleavedData() { //first build interleaved data if we do not have it - if(!m_interleavedData) + if(m_interleavedData == nullptr) { getInterleavedDataLength(); m_interleavedData = new unsigned char[m_interleavedDataFullSize]; @@ -145,36 +146,38 @@ void CSlowDataEncoder::buildInterleavedData() unsigned int textPtr = 0U; unsigned int gpsPtr = 0U; - unsigned int headerPtr = 0U; //now proceed with data copying, according to this document http://www.qsl.net/kb9mwr/projects/dv/dstar/Slow%20Data.pdf - if(m_textData && m_gpsData){ - for(unsigned int interleavedPtr = 0; interleavedPtr < m_interleavedDataFullSize; interleavedPtr += SLOW_DATA_BLOCK_SIZE){ + if(m_textData != nullptr && m_gpsData != nullptr){ + unsigned int interleavedPtr = 0; + while(textPtr < TEXT_SIZE || gpsPtr < m_gpsDataSize){ if(textPtr < TEXT_SIZE && ((interleavedPtr / SLOW_DATA_BLOCK_SIZE) & 0x01U) == 0) { ::memcpy(m_interleavedData + interleavedPtr, m_textData + textPtr, SLOW_DATA_BLOCK_SIZE); textPtr += SLOW_DATA_BLOCK_SIZE; } - else if(gpsPtr < m_gpsDataSize){ + else if(gpsPtr < m_gpsDataSize) { ::memcpy(m_interleavedData + interleavedPtr, m_gpsData + gpsPtr, SLOW_DATA_BLOCK_SIZE); gpsPtr += SLOW_DATA_BLOCK_SIZE; } - else if(m_headerData && headerPtr < HEADER_SIZE){ - ::memcpy(m_interleavedData + interleavedPtr, m_headerData + headerPtr, SLOW_DATA_BLOCK_SIZE); - headerPtr += SLOW_DATA_BLOCK_SIZE; - } + interleavedPtr += SLOW_DATA_BLOCK_SIZE; + } + + if(m_headerData != nullptr) { + //append header dat in one block at the end + ::memcpy(m_interleavedData + interleavedPtr, m_headerData, HEADER_SIZE); } } - else if(m_textData && !m_gpsData && m_headerData){ + else if(m_textData != nullptr && m_gpsData == nullptr && m_headerData != nullptr){ //according to above doc, header and text are not interleaved, just on after the other. filler bytes between resync bytes. ::memcpy(m_interleavedData, m_textData, SLOW_DATA_FULL_BLOCK_SIZE); ::memcpy(m_interleavedData + SLOW_DATA_FULL_BLOCK_SIZE, m_headerData, SLOW_DATA_FULL_BLOCK_SIZE); } - else if(!m_textData && m_gpsData && m_headerData){ + else if(m_textData == nullptr && m_gpsData != nullptr && m_headerData != nullptr){ //could not find any spec about this particular case, let's put the data one after the other ::memcpy(m_interleavedData, m_gpsData, SLOW_DATA_FULL_BLOCK_SIZE); - ::memcpy(m_interleavedData + SLOW_DATA_FULL_BLOCK_SIZE, m_headerData, SLOW_DATA_FULL_BLOCK_SIZE); + ::memcpy(m_interleavedData + SLOW_DATA_FULL_BLOCK_SIZE, m_headerData, HEADER_SIZE); } } } @@ -347,8 +350,8 @@ void CSlowDataEncoder::setGPSData(const std::string& gpsData) m_gpsData = new unsigned char[m_gpsDataFullSize]; ::memset(m_gpsData, 'f', m_gpsDataFullSize); - for(gpsDataPos = 0; gpsDataPos < m_gpsDataFullSize;){ - unsigned int dataLen = gpsDataStrLen - strPos < 5U ? gpsDataStrLen - strPos : 5U; + for(gpsDataPos = 0; gpsDataPos < m_gpsDataSize;){ + unsigned int dataLen = gpsDataStrLen - strPos< 5U ? gpsDataStrLen - strPos : 5U; m_gpsData[gpsDataPos++] = SLOW_DATA_TYPE_GPS | dataLen; for(unsigned int i = 0U; i < dataLen; i++){ From b9510f764d8485e7bc1887222b524b2625ce9a36 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 13 Jan 2022 07:57:59 +0100 Subject: [PATCH 112/201] #9 make setGPSData a ltillt bit more readable --- SlowDataEncoder.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/SlowDataEncoder.cpp b/SlowDataEncoder.cpp index 54be29b..56442e3 100644 --- a/SlowDataEncoder.cpp +++ b/SlowDataEncoder.cpp @@ -17,7 +17,9 @@ #include "SlowDataEncoder.h" #include "CCITTChecksum.h" #include "DStarDefines.h" -#include "Utils.h" + +// Only works for positive numbers +#define roundUpToMultipleOf(n, m)(((n + m - 1) / m) * m) const unsigned int SLOW_DATA_BLOCK_SIZE = 6U; @@ -137,7 +139,7 @@ void CSlowDataEncoder::getInterleavedData(unsigned char* data) void CSlowDataEncoder::buildInterleavedData() { - //first build interleaved data if we do not have it + //first build interleaved data if we do not h(x + multiple - 1 - (x % multiple))ave it if(m_interleavedData == nullptr) { getInterleavedDataLength(); @@ -177,7 +179,7 @@ void CSlowDataEncoder::buildInterleavedData() else if(m_textData == nullptr && m_gpsData != nullptr && m_headerData != nullptr){ //could not find any spec about this particular case, let's put the data one after the other ::memcpy(m_interleavedData, m_gpsData, SLOW_DATA_FULL_BLOCK_SIZE); - ::memcpy(m_interleavedData + SLOW_DATA_FULL_BLOCK_SIZE, m_headerData, HEADER_SIZE); + ::memcpy(m_interleavedData + SLOW_DATA_FULL_BLOCK_SIZE, m_headerData, SLOW_DATA_FULL_BLOCK_SIZE); } } } @@ -187,9 +189,9 @@ unsigned int CSlowDataEncoder::getInterleavedDataLength() //calculate size (including filler bytes); m_interleavedDataFullSize = 0U; if(m_textData) m_interleavedDataFullSize += TEXT_SIZE; - if(m_headerData) m_interleavedDataFullSize += HEADER_SIZE; - if(m_gpsData) m_interleavedDataFullSize += m_gpsDataSize; - m_interleavedDataFullSize = SLOW_DATA_FULL_BLOCK_SIZE * (1U + ((m_interleavedDataFullSize - 1U) / SLOW_DATA_FULL_BLOCK_SIZE)); + if(m_headerData) m_interleavedDataFullSize += SLOW_DATA_BLOCK_SIZE; + if(m_gpsData) m_interleavedDataFullSize += m_gpsDataFullSize; + m_interleavedDataFullSize = roundUpToMultipleOf(m_interleavedDataFullSize, SLOW_DATA_FULL_BLOCK_SIZE); //SLOW_DATA_FULL_BLOCK_SIZE * (1U + ((m_interleavedDataFullSize - 1U) / SLOW_DATA_FULL_BLOCK_SIZE)); return m_interleavedDataFullSize; } @@ -343,9 +345,9 @@ void CSlowDataEncoder::setGPSData(const std::string& gpsData) if((gpsDataStrLen = gpsData.size()) > 0){ unsigned int gpsDataPos; unsigned int strPos = 0; - m_gpsDataSize = 1U + ((gpsDataStrLen - 1U) / 6U);//to make room for the type bytes - m_gpsDataSize += gpsDataStrLen; - m_gpsDataFullSize = SLOW_DATA_FULL_BLOCK_SIZE * (1U + ((m_gpsDataSize - 1U) / SLOW_DATA_FULL_BLOCK_SIZE)); + unsigned int typeBytesCount = 1U + ((gpsDataStrLen - 1U) / SLOW_DATA_BLOCK_SIZE);//to make room for the type bytes + m_gpsDataSize = typeBytesCount + gpsDataStrLen; + m_gpsDataFullSize = roundUpToMultipleOf(m_gpsDataSize, SLOW_DATA_FULL_BLOCK_SIZE); m_gpsData = new unsigned char[m_gpsDataFullSize]; ::memset(m_gpsData, 'f', m_gpsDataFullSize); From 51101c00592a3a6c86497b6224974b0c4dfc4c19 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 13 Jan 2022 07:58:24 +0100 Subject: [PATCH 113/201] #9 add slow data GPS data tests --- .vscode/tasks.json | 10 ++--- Tests/SlowDataEncoder/GPSData.cpp | 75 +++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 5 deletions(-) create mode 100644 Tests/SlowDataEncoder/GPSData.cpp diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 168ca95..ac3f100 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,10 +12,7 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] }, { @@ -28,7 +25,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] } ] diff --git a/Tests/SlowDataEncoder/GPSData.cpp b/Tests/SlowDataEncoder/GPSData.cpp new file mode 100644 index 0000000..47b3185 --- /dev/null +++ b/Tests/SlowDataEncoder/GPSData.cpp @@ -0,0 +1,75 @@ +/* + * 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 + +#include "../../SlowDataEncoder.h" +#include "../../DStarDefines.h" + +namespace SlowDataEncoderTests +{ + class SlowDataEncoder_gpsData : public ::testing::Test { + + }; + + TEST_F(SlowDataEncoder_gpsData, gpsDataCorrectlySet) + { + CSlowDataEncoder encoder; + encoder.setGPSData("ABCDEFGHIJKLMN"); + + unsigned char buffer[6U]; + + encoder.getGPSData(buffer); + encoder.getGPSData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'A'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'B'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'C'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'D'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'E'); + + encoder.getGPSData(buffer); + encoder.getGPSData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'F'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'I'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'J'); + + encoder.getGPSData(buffer); + encoder.getGPSData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x4U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'K'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'L'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'M'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'N'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + + for(unsigned int i = 18; i < 60U; i+= 6U) { + encoder.getGPSData(buffer); + encoder.getGPSData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + } + } +} \ No newline at end of file From d4f7a62baf1932e1d133fdf39f7c2962383fbfca Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 13 Jan 2022 11:06:06 +0100 Subject: [PATCH 114/201] #9 test 2 times to make sure internal pointer goes back to start --- Tests/SlowDataEncoder/GPSData.cpp | 70 ++++++++++++++++--------------- 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/Tests/SlowDataEncoder/GPSData.cpp b/Tests/SlowDataEncoder/GPSData.cpp index 47b3185..4e46e07 100644 --- a/Tests/SlowDataEncoder/GPSData.cpp +++ b/Tests/SlowDataEncoder/GPSData.cpp @@ -31,45 +31,47 @@ namespace SlowDataEncoderTests { CSlowDataEncoder encoder; encoder.setGPSData("ABCDEFGHIJKLMN"); + + for(unsigned int testCount = 0U; testCount < 2U; testCount++) { + unsigned char buffer[6U]; - unsigned char buffer[6U]; - - encoder.getGPSData(buffer); - encoder.getGPSData(buffer + 3); - EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); - EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'A'); - EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'B'); - EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'C'); - EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'D'); - EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'E'); - - encoder.getGPSData(buffer); - encoder.getGPSData(buffer + 3); - EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); - EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'F'); - EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); - EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); - EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'I'); - EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'J'); + encoder.getGPSData(buffer); + encoder.getGPSData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'A'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'B'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'C'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'D'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'E'); - encoder.getGPSData(buffer); - encoder.getGPSData(buffer + 3); - EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x4U); - EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'K'); - EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'L'); - EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'M'); - EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'N'); - EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + encoder.getGPSData(buffer); + encoder.getGPSData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'F'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'I'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'J'); - for(unsigned int i = 18; i < 60U; i+= 6U) { encoder.getGPSData(buffer); encoder.getGPSData(buffer + 3); - EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); - EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); - EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); - EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); - EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x4U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'K'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'L'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'M'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'N'); EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + + for(unsigned int i = 18; i < 60U; i+= 6U) { + encoder.getGPSData(buffer); + encoder.getGPSData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + } } } -} \ No newline at end of file +} From 80ee8d40daefbbbfe5eb7daec01d2bac88585b0d Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 13 Jan 2022 15:09:46 +0100 Subject: [PATCH 115/201] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fe31074..c087b34 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ I Use [Git flow](https://danielkummer.github.io/git-flow-cheatsheet/) as my work - Code formating rules are observed (these are very lousy though) ## 4.2. Continuous Integration I have added some basic CI using CircleCI [![F4FXL](https://circleci.com/gh/F4FXL/DStarGateway.svg?style=svg)](https://app.circleci.com/pipelines/github/F4FXL/DStarGateway?filter=all) I am trying to rewrite the code so that it can be put into some Behavior Driven Development scheme. This is a long haul task and I'll try do do it on the go while changing/adding stuff. -the testing framwrok used is Google Test. +the testing framwework used is Google Test. # 5. Version History ## 5.1. Version 0.5 From 7602c29f48e06b9fb46aaead9fae5907f5d40df1 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 13 Jan 2022 17:21:57 +0100 Subject: [PATCH 116/201] #9 Add test for text data --- Tests/SlowDataEncoder/GPSData.cpp | 1 + Tests/SlowDataEncoder/TextData.cpp | 87 ++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 Tests/SlowDataEncoder/TextData.cpp diff --git a/Tests/SlowDataEncoder/GPSData.cpp b/Tests/SlowDataEncoder/GPSData.cpp index 4e46e07..21bc48f 100644 --- a/Tests/SlowDataEncoder/GPSData.cpp +++ b/Tests/SlowDataEncoder/GPSData.cpp @@ -62,6 +62,7 @@ namespace SlowDataEncoderTests EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'N'); EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + // all the remaining data shall be filled with 'f' for(unsigned int i = 18; i < 60U; i+= 6U) { encoder.getGPSData(buffer); encoder.getGPSData(buffer + 3); diff --git a/Tests/SlowDataEncoder/TextData.cpp b/Tests/SlowDataEncoder/TextData.cpp new file mode 100644 index 0000000..b2ba775 --- /dev/null +++ b/Tests/SlowDataEncoder/TextData.cpp @@ -0,0 +1,87 @@ +/* + * 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 + +#include "../../SlowDataEncoder.h" +#include "../../DStarDefines.h" + +namespace SlowDataEncoderTests +{ + class SlowDataEncoder_textData : public ::testing::Test { + + }; + + TEST_F(SlowDataEncoder_textData, textDataCorrectlySet) + { + CSlowDataEncoder encoder; + encoder.setTextData("ABCDEFG"); + + for(unsigned int testCount = 0U; testCount < 2U; testCount++) { + unsigned char buffer[6U]; + + encoder.getTextData(buffer); + encoder.getTextData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x0U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'A'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'B'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'C'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'D'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'E'); + + encoder.getTextData(buffer); + encoder.getTextData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x1U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'F'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getTextData(buffer); + encoder.getTextData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x2U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getTextData(buffer); + encoder.getTextData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x3U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + // all the remaining data shall be filled with 'f' + for(unsigned int i = 24; i < 60U; i+= 6U) { + encoder.getTextData(buffer); + encoder.getTextData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + } + } + } +} From 4b4cea612f739389049ed37295337c81bef71d8c Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 13 Jan 2022 17:58:40 +0100 Subject: [PATCH 117/201] #9 add test for header data --- Tests/SlowDataEncoder/HeaderData.cpp | 139 +++++++++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 Tests/SlowDataEncoder/HeaderData.cpp diff --git a/Tests/SlowDataEncoder/HeaderData.cpp b/Tests/SlowDataEncoder/HeaderData.cpp new file mode 100644 index 0000000..03d8204 --- /dev/null +++ b/Tests/SlowDataEncoder/HeaderData.cpp @@ -0,0 +1,139 @@ +/* + * 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 + +#include "../../SlowDataEncoder.h" +#include "../../DStarDefines.h" + +namespace SlowDataEncoderTests +{ + class SlowDataEncoder_headerData : public ::testing::Test { + + }; + + TEST_F(SlowDataEncoder_headerData, textDataCorrectlySet) + { + CHeaderData header; + header.setFlags('1', '2', '3'); + header.setMyCall1("F4FXL"); + header.setMyCall2("5100"); + header.setYourCall("CQCQCQ"); + header.setRptCall1("F5ZEE B"); + header.setRptCall2("F5ZEE G"); + + CSlowDataEncoder encoder; + encoder.setHeaderData(header); + + for(unsigned int testCount = 0U; testCount < 2U; testCount++) { + unsigned char buffer[6U]; + + encoder.getHeaderData(buffer); + encoder.getHeaderData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, '1'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, '2'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, '3'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'F'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, '5'); + + encoder.getHeaderData(buffer); + encoder.getHeaderData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'Z'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'E'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'E'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getHeaderData(buffer); + encoder.getHeaderData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'F'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, '5'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'Z'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'E'); + + encoder.getHeaderData(buffer); + encoder.getHeaderData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'E'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'B'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'C'); + + encoder.getHeaderData(buffer); + encoder.getHeaderData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'Q'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'C'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'Q'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'C'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'Q'); + + encoder.getHeaderData(buffer); + encoder.getHeaderData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'F'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, '4'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'F'); + + encoder.getHeaderData(buffer); + encoder.getHeaderData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'X'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'L'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getHeaderData(buffer); + encoder.getHeaderData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, '5'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, '1'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, '0'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, '0'); + EXPECT_NE(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); // we do not check the actual result of the CRC, we just make sure is inot 'f' + + encoder.getHeaderData(buffer); + encoder.getHeaderData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x1U); + EXPECT_NE(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); // done with crc check, remaining shall be filled with 'f' + + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + + encoder.getHeaderData(buffer); + encoder.getHeaderData(buffer + 3); + // all the remaining data shall be filled with 'f' + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + } + } +} From 30e48938d51abc8d05f68f327e58d9f0fde48ecd Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 13 Jan 2022 18:29:07 +0100 Subject: [PATCH 118/201] #9 fix test name --- Tests/SlowDataEncoder/HeaderData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/SlowDataEncoder/HeaderData.cpp b/Tests/SlowDataEncoder/HeaderData.cpp index 03d8204..a3d253c 100644 --- a/Tests/SlowDataEncoder/HeaderData.cpp +++ b/Tests/SlowDataEncoder/HeaderData.cpp @@ -27,7 +27,7 @@ namespace SlowDataEncoderTests }; - TEST_F(SlowDataEncoder_headerData, textDataCorrectlySet) + TEST_F(SlowDataEncoder_headerData, headerDataCorrectlySet) { CHeaderData header; header.setFlags('1', '2', '3'); From eee1c223bc81693508bb97cd5e85178192cee433 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 13 Jan 2022 18:29:31 +0100 Subject: [PATCH 119/201] #9 add interleave data tests, fix lenght calculation --- SlowDataEncoder.cpp | 2 +- Tests/SlowDataEncoder/InterleavedData.cpp | 354 ++++++++++++++++++++++ 2 files changed, 355 insertions(+), 1 deletion(-) create mode 100644 Tests/SlowDataEncoder/InterleavedData.cpp diff --git a/SlowDataEncoder.cpp b/SlowDataEncoder.cpp index 56442e3..a1aa75f 100644 --- a/SlowDataEncoder.cpp +++ b/SlowDataEncoder.cpp @@ -190,7 +190,7 @@ unsigned int CSlowDataEncoder::getInterleavedDataLength() m_interleavedDataFullSize = 0U; if(m_textData) m_interleavedDataFullSize += TEXT_SIZE; if(m_headerData) m_interleavedDataFullSize += SLOW_DATA_BLOCK_SIZE; - if(m_gpsData) m_interleavedDataFullSize += m_gpsDataFullSize; + if(m_gpsData) m_interleavedDataFullSize += m_gpsDataSize; m_interleavedDataFullSize = roundUpToMultipleOf(m_interleavedDataFullSize, SLOW_DATA_FULL_BLOCK_SIZE); //SLOW_DATA_FULL_BLOCK_SIZE * (1U + ((m_interleavedDataFullSize - 1U) / SLOW_DATA_FULL_BLOCK_SIZE)); return m_interleavedDataFullSize; } diff --git a/Tests/SlowDataEncoder/InterleavedData.cpp b/Tests/SlowDataEncoder/InterleavedData.cpp new file mode 100644 index 0000000..a9c79be --- /dev/null +++ b/Tests/SlowDataEncoder/InterleavedData.cpp @@ -0,0 +1,354 @@ +/* + * 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 + +#include "../../SlowDataEncoder.h" +#include "../../DStarDefines.h" + +namespace SlowDataEncoderTests +{ + class SlowDataEncoder_interleavedData : public ::testing::Test { + + }; + + TEST_F(SlowDataEncoder_interleavedData, gpsAndTextData) + { + //here we only test for correct interleaving + CSlowDataEncoder encoder; + encoder.setTextData("TTTTTT"); // 6 times T + encoder.setGPSData("GGGGGGGGGGGGGGGGGGGGGG"); // 22 times G + + auto dataLen = encoder.getInterleavedDataLength(); + + EXPECT_EQ(dataLen, 60);// including data type bytes we need 54 (20 + 5 + 22 + 6) bytes, this shall be rounded up to next block size multiple, in this case 60 + + for(unsigned int testCount = 0U; testCount < 2U; testCount++) { + unsigned char buffer[6U]; + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x0U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'T'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'T'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'T'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'T'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'T'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'G'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'G'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x1U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'T'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'G'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'G'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x2U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'G'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'G'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x3U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'G'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'G'); + + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x2U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + + //remaining shall only be 'f" + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + } + } + + TEST_F(SlowDataEncoder_interleavedData, onlyGPSData) + { + CSlowDataEncoder encoder; + encoder.setGPSData("ABCDEFGHIJKLMN"); + + for(unsigned int testCount = 0U; testCount < 2U; testCount++) { + unsigned char buffer[6U]; + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'A'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'B'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'C'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'D'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'E'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'F'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'I'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'J'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x4U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'K'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'L'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'M'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'N'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + + // all the remaining data shall be filled with 'f' + for(unsigned int i = 18; i < 60U; i+= 6U) { + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + } + } + } + + TEST_F(SlowDataEncoder_interleavedData, onlyTextData) + { + CSlowDataEncoder encoder; + encoder.setTextData("ABCDEFG"); + + for(unsigned int testCount = 0U; testCount < 2U; testCount++) { + unsigned char buffer[6U]; + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x0U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'A'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'B'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'C'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'D'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'E'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x1U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'F'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x2U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x3U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + // all the remaining data shall be filled with 'f' + for(unsigned int i = 24; i < 60U; i+= 6U) { + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + } + } + } + + TEST_F(SlowDataEncoder_interleavedData, onlyHeaderData) + { + CHeaderData header; + header.setFlags('1', '2', '3'); + header.setMyCall1("F4FXL"); + header.setMyCall2("5100"); + header.setYourCall("CQCQCQ"); + header.setRptCall1("F5ZEE B"); + header.setRptCall2("F5ZEE G"); + + CSlowDataEncoder encoder; + encoder.setHeaderData(header); + + for(unsigned int testCount = 0U; testCount < 2U; testCount++) { + unsigned char buffer[6U]; + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, '1'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, '2'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, '3'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'F'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, '5'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'Z'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'E'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'E'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'F'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, '5'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'Z'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'E'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'E'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'B'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'C'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'Q'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'C'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'Q'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'C'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'Q'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'F'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, '4'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'F'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'X'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'L'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, '5'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, '1'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, '0'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, '0'); + EXPECT_NE(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); // we do not check the actual result of the CRC, we just make sure is inot 'f' + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x1U); + EXPECT_NE(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); // done with crc check, remaining shall be filled with 'f' + + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + // all the remaining data shall be filled with 'f' + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + } + } +} From 5fc9a90156d4de536a9a1397e11ed9169afcbce0 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 13 Jan 2022 20:05:51 +0100 Subject: [PATCH 120/201] #9 fix interleved data length and add more tests --- SlowDataEncoder.cpp | 4 +- Tests/SlowDataEncoder/InterleavedData.cpp | 511 ++++++++++++++++++++++ 2 files changed, 513 insertions(+), 2 deletions(-) diff --git a/SlowDataEncoder.cpp b/SlowDataEncoder.cpp index a1aa75f..f519ee6 100644 --- a/SlowDataEncoder.cpp +++ b/SlowDataEncoder.cpp @@ -168,7 +168,7 @@ void CSlowDataEncoder::buildInterleavedData() if(m_headerData != nullptr) { //append header dat in one block at the end - ::memcpy(m_interleavedData + interleavedPtr, m_headerData, HEADER_SIZE); + ::memcpy(m_interleavedData + roundUpToMultipleOf(interleavedPtr, SLOW_DATA_FULL_BLOCK_SIZE), m_headerData, HEADER_SIZE); } } else if(m_textData != nullptr && m_gpsData == nullptr && m_headerData != nullptr){ @@ -189,7 +189,7 @@ unsigned int CSlowDataEncoder::getInterleavedDataLength() //calculate size (including filler bytes); m_interleavedDataFullSize = 0U; if(m_textData) m_interleavedDataFullSize += TEXT_SIZE; - if(m_headerData) m_interleavedDataFullSize += SLOW_DATA_BLOCK_SIZE; + if(m_headerData) m_interleavedDataFullSize += SLOW_DATA_FULL_BLOCK_SIZE; // the is because header data is transmitted as one contiguous block. Unused bytes fileld with 'f' if(m_gpsData) m_interleavedDataFullSize += m_gpsDataSize; m_interleavedDataFullSize = roundUpToMultipleOf(m_interleavedDataFullSize, SLOW_DATA_FULL_BLOCK_SIZE); //SLOW_DATA_FULL_BLOCK_SIZE * (1U + ((m_interleavedDataFullSize - 1U) / SLOW_DATA_FULL_BLOCK_SIZE)); return m_interleavedDataFullSize; diff --git a/Tests/SlowDataEncoder/InterleavedData.cpp b/Tests/SlowDataEncoder/InterleavedData.cpp index a9c79be..0651b15 100644 --- a/Tests/SlowDataEncoder/InterleavedData.cpp +++ b/Tests/SlowDataEncoder/InterleavedData.cpp @@ -17,6 +17,7 @@ */ #include +#include #include "../../SlowDataEncoder.h" #include "../../DStarDefines.h" @@ -27,6 +28,510 @@ namespace SlowDataEncoderTests }; + TEST_F(SlowDataEncoder_interleavedData, gpsAndHeaderData) + { + // Header is never interleaved, text and header are sent as two blocks + CHeaderData header; + unsigned char headerData[RADIO_HEADER_LENGTH_BYTES]; + ::memset(headerData, 'H', RADIO_HEADER_LENGTH_BYTES); + header.setData(headerData, RADIO_HEADER_LENGTH_BYTES, false); + + //here we only test for correct interleaving + CSlowDataEncoder encoder; + encoder.setGPSData("GGGGGGGG"); // 8 times G + encoder.setHeaderData(header); + + for(unsigned int i = 0U; i < 2U; i++) { + unsigned char buffer[6U]; + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'G'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'G'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x3U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'G'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + + // all the remaining data shall be filled with 'f' until next block + for(unsigned int j = 12; j < 60U; j+= 6U) { + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + } + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_NE(buffer[5] ^ SCRAMBLER_BYTE3, 'f');// this is checksum byte, just make sure is is not 'f' + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x1U); + EXPECT_NE(buffer[1] ^ SCRAMBLER_BYTE2, 'f');// this is checksum byte, just make sure is is not 'f' + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + + //remaining data is only 'f' + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + } + } + + TEST_F(SlowDataEncoder_interleavedData, textAndHeaderData) + { + // Header is never interleaved, text and header are sent as two blocks + CHeaderData header; + unsigned char headerData[RADIO_HEADER_LENGTH_BYTES]; + ::memset(headerData, 'H', RADIO_HEADER_LENGTH_BYTES); + header.setData(headerData, RADIO_HEADER_LENGTH_BYTES, false); + + //here we only test for correct interleaving + CSlowDataEncoder encoder; + encoder.setTextData("TTTTTT"); // 6 times T + encoder.setHeaderData(header); + + auto dataLen = encoder.getInterleavedDataLength(); + EXPECT_EQ(dataLen, 120); //2* 60 + + for(unsigned int testCount = 0U; testCount < 2U; testCount++) { + unsigned char buffer[6U]; + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x0U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'T'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'T'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'T'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'T'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'T'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x1U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'T'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x2U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x3U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + // all the remaining data shall be filled with 'f' until next block + for(unsigned int j = 24; j < 60U; j+= 6U) { + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + } + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_NE(buffer[5] ^ SCRAMBLER_BYTE3, 'f');// this is checksum byte, just make sure is is not 'f' + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x1U); + EXPECT_NE(buffer[1] ^ SCRAMBLER_BYTE2, 'f');// this is checksum byte, just make sure is is not 'f' + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + + //remaining data is only 'f' + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + } + } + + TEST_F(SlowDataEncoder_interleavedData, gpsTextAndHeaderData) + { + CHeaderData header; + unsigned char headerData[RADIO_HEADER_LENGTH_BYTES]; + ::memset(headerData, 'H', RADIO_HEADER_LENGTH_BYTES); + header.setData(headerData, RADIO_HEADER_LENGTH_BYTES, false); + + //here we only test for correct interleaving + CSlowDataEncoder encoder; + encoder.setTextData("TTTTTT"); // 6 times T + encoder.setGPSData("GGGGGGGGGGGGGGGGGGGGGG"); // 22 times G + encoder.setHeaderData(header); + + auto dataLen = encoder.getInterleavedDataLength(); + + EXPECT_EQ(dataLen, 120);// including data type bytes we need 54 (20 + 5 + 22 + 6) bytes, this shall be rounded up to next block size multiple, in this case 60 + + for(unsigned int testCount = 0U; testCount < 2U; testCount++) { + unsigned char buffer[6U]; + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x0U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'T'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'T'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'T'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'T'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'T'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'G'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'G'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x1U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'T'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'G'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'G'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x2U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'G'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'G'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_TEXT | 0x3U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, ' '); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, ' '); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, ' '); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, ' '); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'G'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'G'); + + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_GPS | 0x2U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'G'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'G'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + + // header is not interleaved, attached as one contiguous block, but it only starts at the nex block + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'H'); + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x5U); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'H'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'H'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'H'); + EXPECT_NE(buffer[5] ^ SCRAMBLER_BYTE3, 'f');// this is checksum byte, just make sure is is not 'f' + + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, SLOW_DATA_TYPE_HEADER | 0x1U); + EXPECT_NE(buffer[1] ^ SCRAMBLER_BYTE2, 'f');// this is checksum byte, just make sure is is not 'f' + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + + //remaining data is only 'f' + encoder.getInterleavedData(buffer); + encoder.getInterleavedData(buffer + 3); + EXPECT_EQ(buffer[0] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[1] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[2] ^ SCRAMBLER_BYTE3, 'f'); + EXPECT_EQ(buffer[3] ^ SCRAMBLER_BYTE1, 'f'); + EXPECT_EQ(buffer[4] ^ SCRAMBLER_BYTE2, 'f'); + EXPECT_EQ(buffer[5] ^ SCRAMBLER_BYTE3, 'f'); + } + } + TEST_F(SlowDataEncoder_interleavedData, gpsAndTextData) { //here we only test for correct interleaving @@ -139,6 +644,9 @@ namespace SlowDataEncoderTests { CSlowDataEncoder encoder; encoder.setGPSData("ABCDEFGHIJKLMN"); + + auto dataLen = encoder.getInterleavedDataLength(); + EXPECT_EQ(dataLen, 60); for(unsigned int testCount = 0U; testCount < 2U; testCount++) { unsigned char buffer[6U]; @@ -188,6 +696,9 @@ namespace SlowDataEncoderTests { CSlowDataEncoder encoder; encoder.setTextData("ABCDEFG"); + + auto dataLen = encoder.getInterleavedDataLength(); + EXPECT_EQ(dataLen, 60); for(unsigned int testCount = 0U; testCount < 2U; testCount++) { unsigned char buffer[6U]; From 9d7c1ade08d63f31f22b722c745c5f7215dbb073 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 13 Jan 2022 21:03:14 +0100 Subject: [PATCH 121/201] #9 clean up log debug --- GPSACollector.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/GPSACollector.cpp b/GPSACollector.cpp index ccbe4a6..3774713 100644 --- a/GPSACollector.cpp +++ b/GPSACollector.cpp @@ -37,7 +37,6 @@ CSentenceCollector(SLOW_DATA_TYPE_GPS, "$$CRC", '\x0D') bool CGPSACollector::isValidSentence(const std::string& sentence) { - CLog::logDebug("GPSA"); return isValidGPSA(sentence); } From 30d74f1f10434d30465109badaa8717f698cb4e6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Thu, 13 Jan 2022 21:05:04 +0100 Subject: [PATCH 122/201] #9 set text for message, improve tests --- .vscode/tasks.json | 10 +++++----- APRSUnit.cpp | 8 ++++---- APRSUnit.h | 1 - APRStoDPRS.cpp | 11 ++++++++--- APRStoDPRS.h | 5 +++-- Tests/APRStoDPRS/aprsToDPRS.cpp | 24 ++++++++++++++++++------ 6 files changed, 38 insertions(+), 21 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index ac3f100..168ca95 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,7 +12,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] }, { @@ -25,10 +28,7 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] } ] diff --git a/APRSUnit.cpp b/APRSUnit.cpp index 49e7f4b..3fe066b 100644 --- a/APRSUnit.cpp +++ b/APRSUnit.cpp @@ -33,7 +33,6 @@ m_out(0U), m_seq(0U), m_totalNeeded(0U), m_timer(1000U, 2U), -m_dprs(), m_start() { m_timer.start(); @@ -57,13 +56,14 @@ void CAPRSUnit::clock(unsigned int ms) m_frameBuffer.pop_front(); m_headerData = new CHeaderData(); - CAPRSToDPRS::aprsToDPRS(m_dprs, *m_headerData, *frame); + std::string dprs, text; + CAPRSToDPRS::aprsToDPRS(dprs, text, *m_headerData, *frame); m_slowData = new CSlowDataEncoder(); m_slowData->setHeaderData(*m_headerData); - m_slowData->setGPSData(m_dprs); - m_slowData->setTextData("APRS to DPRS"); + m_slowData->setGPSData(dprs); + m_slowData->setTextData(text); m_totalNeeded = (m_slowData->getInterleavedDataLength() / (DATA_FRAME_LENGTH_BYTES)) * 2U; diff --git a/APRSUnit.h b/APRSUnit.h index 466f6d5..bc7a595 100644 --- a/APRSUnit.h +++ b/APRSUnit.h @@ -51,7 +51,6 @@ private: unsigned int m_seq; unsigned int m_totalNeeded; CTimer m_timer; - std::string m_dprs; std::chrono::high_resolution_clock::time_point m_start; }; diff --git a/APRStoDPRS.cpp b/APRStoDPRS.cpp index 8b524a1..d238a2f 100644 --- a/APRStoDPRS.cpp +++ b/APRStoDPRS.cpp @@ -22,13 +22,16 @@ #include "Log.h" #include "RSMS1AMessageBuilder.h" -bool CAPRSToDPRS::aprsToDPRS(std::string& dprs, CHeaderData& header, CAPRSFrame& frame) + + +bool CAPRSToDPRS::aprsToDPRS(std::string& dprs, std::string& text, CHeaderData& header, CAPRSFrame& frame) { dprs.clear(); + text.clear(); switch (frame.getType()) { case APFT_MESSAGE : - return messageToDPRS(dprs, header, frame); + return messageToDPRS(dprs, text, header, frame); default: break; } @@ -36,7 +39,7 @@ bool CAPRSToDPRS::aprsToDPRS(std::string& dprs, CHeaderData& header, CAPRSFrame& return false; } -bool CAPRSToDPRS::messageToDPRS(std::string& dprs, CHeaderData& header, CAPRSFrame& frame) +bool CAPRSToDPRS::messageToDPRS(std::string& dprs, std::string& text, CHeaderData& header, CAPRSFrame& frame) { auto frameBody = frame.getBody(); if(frameBody.length() < 11 || frameBody[0] != ':' || frameBody[10] != ':') { @@ -64,5 +67,7 @@ bool CAPRSToDPRS::messageToDPRS(std::string& dprs, CHeaderData& header, CAPRSFra CRSMS1AMessageBuilder::buildMessage(dprs, frame.getSource(), recipient, messageBody); + text = messageBody; + return true; } \ No newline at end of file diff --git a/APRStoDPRS.h b/APRStoDPRS.h index 2e185d7..05191c0 100644 --- a/APRStoDPRS.h +++ b/APRStoDPRS.h @@ -19,6 +19,7 @@ #pragma once #include +#include #include "HeaderData.h" #include "APRSFrame.h" @@ -26,8 +27,8 @@ class CAPRSToDPRS { public: - static bool aprsToDPRS(std::string& dprs, CHeaderData& header, CAPRSFrame& frame); + static bool aprsToDPRS(std::string& dprs, std::string& text, CHeaderData& header, CAPRSFrame& frame); private: - static bool messageToDPRS(std::string& drps, CHeaderData& header, CAPRSFrame& frame); + static bool messageToDPRS(std::string& dprs, std::string& text, CHeaderData& header, CAPRSFrame& frame); }; \ No newline at end of file diff --git a/Tests/APRStoDPRS/aprsToDPRS.cpp b/Tests/APRStoDPRS/aprsToDPRS.cpp index 94f8b29..872d3a0 100644 --- a/Tests/APRStoDPRS/aprsToDPRS.cpp +++ b/Tests/APRStoDPRS/aprsToDPRS.cpp @@ -30,35 +30,47 @@ namespace APRStoDPRSTests { CAPRSFrame frame("KC3FRA", "APRS", {"WIDE1-1", "WIDE2-2"}, ":F4FXL :Salut, comment vas tu?", APFT_MESSAGE); - std::string dprs; + std::string dprs, text; CHeaderData header; - bool ret = CAPRSToDPRS::aprsToDPRS(dprs, header, frame); + bool ret = CAPRSToDPRS::aprsToDPRS(dprs, text, header, frame); EXPECT_TRUE(ret); EXPECT_STREQ(dprs.c_str(), "$$Msg,KC3FRA,F4FXL,001118Saluto, comment vas tu?z\r"); + EXPECT_STREQ(text.c_str(), "Salut, comment vas tu?"); + EXPECT_STREQ(header.getMyCall1().c_str(), "KC3FRA "); + EXPECT_STREQ(header.getMyCall2().c_str(), "MSG "); + EXPECT_STREQ(header.getYourCall().c_str(), "F4FXL "); } TEST_F(APRStoDPRS_aprsToDPRS, validMessageRecipientWithSSID) { CAPRSFrame frame("KC3FRA", "APRS", {"WIDE1-1", "WIDE2-2"}, ":F4FXL-7 :Salut, comment vas tu?", APFT_MESSAGE); - std::string dprs; + std::string dprs, text; CHeaderData header; - bool ret = CAPRSToDPRS::aprsToDPRS(dprs, header, frame); + bool ret = CAPRSToDPRS::aprsToDPRS(dprs, text, header, frame); EXPECT_TRUE(ret); EXPECT_STREQ(dprs.c_str(), "$$Msg,KC3FRA,F4FXL,001118Saluto, comment vas tu?z\r"); + EXPECT_STREQ(text.c_str(), "Salut, comment vas tu?"); + EXPECT_STREQ(header.getMyCall1().c_str(), "KC3FRA "); + EXPECT_STREQ(header.getMyCall2().c_str(), "MSG "); + EXPECT_STREQ(header.getYourCall().c_str(), "F4FXL "); } TEST_F(APRStoDPRS_aprsToDPRS, emptyRecipient) { CAPRSFrame frame("KC3FRA", "APRS", {"WIDE1-1", "WIDE2-2"}, ": :Salut, comment vas tu?", APFT_MESSAGE); - std::string dprs; + std::string dprs, text; CHeaderData header; - bool ret = CAPRSToDPRS::aprsToDPRS(dprs, header, frame); + bool ret = CAPRSToDPRS::aprsToDPRS(dprs, text, header, frame); EXPECT_FALSE(ret); EXPECT_STREQ(dprs.c_str(), ""); + EXPECT_STREQ(text.c_str(), ""); + EXPECT_STREQ(header.getMyCall1().c_str(), " "); + EXPECT_STREQ(header.getMyCall2().c_str(), " "); + EXPECT_STREQ(header.getYourCall().c_str(), " "); } } From 0db54e5026e629cbbdddebe938c92d8b1c9e93bf Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 14 Jan 2022 17:20:00 +0100 Subject: [PATCH 123/201] #9 add telemetry parsing --- .vscode/tasks.json | 10 +- APRSFrame.h | 3 +- APRSParser.cpp | 21 ++- Tests/APRSParser/parseAPRSFrame.cpp | 276 ++++++++++++++++++---------- 4 files changed, 204 insertions(+), 106 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 168ca95..ac3f100 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,10 +12,7 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] }, { @@ -28,7 +25,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] } ] diff --git a/APRSFrame.h b/APRSFrame.h index 2fc790c..ca6ec85 100644 --- a/APRSFrame.h +++ b/APRSFrame.h @@ -29,7 +29,8 @@ enum APRS_FRAME_TYPE { APFT_NMEA, APFT_STATUS, APFT_OBJECT, - APFT_WX + APFT_WX, + APFT_TELEMETRY }; class CAPRSFrame { diff --git a/APRSParser.cpp b/APRSParser.cpp index cdd7b5a..0eeaabd 100644 --- a/APRSParser.cpp +++ b/APRSParser.cpp @@ -106,9 +106,21 @@ bool CAPRSParser::parseInt(CAPRSFrame& frame) } break; case ':': - if(body[9] == ':' && std::all_of(body.begin(), body.begin() + 9, - [](char c){ return c == ' ' || c == '-' || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); })) + // we have either message or telemetry labels or telemetry EQNS + if(body[9] == ':' + && std::all_of(body.begin(), body.begin() + 9, [](char c){ return c == ' ' || c == '-' || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); })) { type = APFT_MESSAGE; + + //If reciepient is same as source and we donot have a sequence number at the end of message, Then it is telemetry + if(body.find(frame.getSource()) == 0U) { + auto eqnsPos = body.find("EQNS."); + auto parmPos = body.find("PARM."); + auto seqNumPos = body.find_last_of('{'); + if((eqnsPos == 10U || parmPos == 10U) && seqNumPos == std::string::npos) { + type = APFT_TELEMETRY; + } + } + } break; case '>': type = APFT_STATUS; @@ -121,6 +133,11 @@ bool CAPRSParser::parseInt(CAPRSFrame& frame) case '{': type = APFT_UNKNOWN; // break; + case 'T': + if(body[0] == '#') { + type = APFT_TELEMETRY; + } + break; default: type = APFT_UNKNOWN; break; diff --git a/Tests/APRSParser/parseAPRSFrame.cpp b/Tests/APRSParser/parseAPRSFrame.cpp index 0263348..fdead96 100644 --- a/Tests/APRSParser/parseAPRSFrame.cpp +++ b/Tests/APRSParser/parseAPRSFrame.cpp @@ -20,102 +20,182 @@ #include "../../APRSParser.h" -class APRSParser_parseAPRSFrame : public ::testing::Test { - -}; - -TEST_F(APRSParser_parseAPRSFrame, EmpyString) { - - CAPRSFrame aprsFrame; - bool retVal = CAPRSParser::parseFrame("", aprsFrame); - - EXPECT_FALSE(retVal); - EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ""); - EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), ""); - EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), ""); - EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); - EXPECT_EQ(aprsFrame.getPath().size(), 0U); -} - -TEST_F(APRSParser_parseAPRSFrame, NoSourceCallsign) { - - CAPRSFrame aprsFrame; - bool retVal = CAPRSParser::parseFrame(">APRS::F4ABC Test Message", aprsFrame); - - EXPECT_FALSE(retVal); - EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ""); - EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), ""); - EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), ""); - EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); - EXPECT_EQ(aprsFrame.getPath().size(), 0U); +namespace APRSParserTests +{ + class APRSParser_parseAPRSFrame : public ::testing::Test { + + }; + + TEST_F(APRSParser_parseAPRSFrame, EmpyString) + { + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("", aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), ""); + EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); + EXPECT_EQ(aprsFrame.getPath().size(), 0U); + } + + TEST_F(APRSParser_parseAPRSFrame, NoSourceCallsign) + { + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame(">APRS::F4ABC Test Message", aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), ""); + EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); + EXPECT_EQ(aprsFrame.getPath().size(), 0U); + } + + TEST_F(APRSParser_parseAPRSFrame, NoDestCallsign) + { + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("N0CALL>::F4ABC Test Message", aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), ""); + EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); + EXPECT_EQ(aprsFrame.getPath().size(), 0U); + } + + TEST_F(APRSParser_parseAPRSFrame, CorrectMessageFrameWithDigipeater) + { + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("N0CALL>APRS,WIDE1-1,WIDE2-2::F4ABC :Test Message", aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ":F4ABC :Test Message"); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "N0CALL"); + EXPECT_EQ(aprsFrame.getType(), APFT_MESSAGE); + EXPECT_EQ(aprsFrame.getPath().size(), 2); + EXPECT_STREQ(aprsFrame.getPath()[0].c_str(), "WIDE1-1"); + EXPECT_STREQ(aprsFrame.getPath()[1].c_str(), "WIDE2-2"); + } + + TEST_F(APRSParser_parseAPRSFrame, CorrectMessageFrameWithoutDigipeater) + { + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("N0CALL>APRS::F4ABC :Test Message", aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ":F4ABC :Test Message"); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "N0CALL"); + EXPECT_EQ(aprsFrame.getType(), APFT_MESSAGE); + EXPECT_EQ(aprsFrame.getPath().size(), 0); + } + + TEST_F(APRSParser_parseAPRSFrame, InvalidMessageFrame) + { + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("N0CALL>APRS::F4ABC&@#$:Test Message", aprsFrame); + + EXPECT_FALSE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), ""); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), ""); + EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); + EXPECT_EQ(aprsFrame.getPath().size(), 0U); + } + + TEST_F(APRSParser_parseAPRSFrame, ID51) + { + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("F4FXL-8>API51,DSTAR:!1234.56N/12345.67E[/A=000886QRV DStar\r\r\n", aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), "!1234.56N/12345.67E[/A=000886QRV DStar\r\r\n"); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "API51"); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "F4FXL-8"); + EXPECT_EQ(aprsFrame.getType(), APFT_POSITION); + EXPECT_EQ(aprsFrame.getPath().size(), 1); + EXPECT_STREQ(aprsFrame.getPath()[0].c_str(), "DSTAR"); + } + + TEST_F(APRSParser_parseAPRSFrame, telemetryLabels) + { + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("F5ZEE-C>APRS::F5ZEE-C :PARM.PA Temp", aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ":F5ZEE-C :PARM.PA Temp"); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "F5ZEE-C"); + EXPECT_EQ(aprsFrame.getType(), APFT_TELEMETRY); + EXPECT_EQ(aprsFrame.getPath().size(), 0); + } + + TEST_F(APRSParser_parseAPRSFrame, telemetryEQNS) + { + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("F5ZEE-C>APRS::F5ZEE-C :EQNS.0,0.16016,-40,0,0,0,0,0,0,0,0,0,0,0,0", aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ":F5ZEE-C :EQNS.0,0.16016,-40,0,0,0,0,0,0,0,0,0,0,0,0"); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "F5ZEE-C"); + EXPECT_EQ(aprsFrame.getType(), APFT_TELEMETRY); + EXPECT_EQ(aprsFrame.getPath().size(), 0); + } + + TEST_F(APRSParser_parseAPRSFrame, telemetryEQNSWithSeqnum) + { + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("F5ZEE-C>APRS::F5ZEE-C :EQNS.0,0.16016,-40,0,0,0,0,0,0,0,0,0,0,0,0{ABCD", aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ":F5ZEE-C :EQNS.0,0.16016,-40,0,0,0,0,0,0,0,0,0,0,0,0{ABCD"); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "F5ZEE-C"); + EXPECT_EQ(aprsFrame.getType(), APFT_MESSAGE); + EXPECT_EQ(aprsFrame.getPath().size(), 0); + } + + + TEST_F(APRSParser_parseAPRSFrame, telemetryReport) + { + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("F5ZEE-C>APRS:T#581,342,000,000,000,000,00000000", aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), "T#581,342,000,000,000,000,00000000"); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "F5ZEE-C"); + EXPECT_EQ(aprsFrame.getType(), APFT_TELEMETRY); + EXPECT_EQ(aprsFrame.getPath().size(), 0); + } + + TEST_F(APRSParser_parseAPRSFrame, messageToSelf) + { + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("F4ABC>APRS::F4ABC :Test Message{ABCD", aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ":F4ABC :Test Message{ABCD"); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "F4ABC"); + EXPECT_EQ(aprsFrame.getType(), APFT_MESSAGE); + EXPECT_EQ(aprsFrame.getPath().size(), 0); + } + + TEST_F(APRSParser_parseAPRSFrame, messageToSelfNoSeqNum) + { + CAPRSFrame aprsFrame; + bool retVal = CAPRSParser::parseFrame("F4ABC>APRS::F4ABC :Test Message", aprsFrame); + + EXPECT_TRUE(retVal); + EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ":F4ABC :Test Message"); + EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); + EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "F4ABC"); + EXPECT_EQ(aprsFrame.getType(), APFT_MESSAGE); + EXPECT_EQ(aprsFrame.getPath().size(), 0); + } } - -TEST_F(APRSParser_parseAPRSFrame, NoDestCallsign) { - - CAPRSFrame aprsFrame; - bool retVal = CAPRSParser::parseFrame("N0CALL>::F4ABC Test Message", aprsFrame); - - EXPECT_FALSE(retVal); - EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ""); - EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), ""); - EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), ""); - EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); - EXPECT_EQ(aprsFrame.getPath().size(), 0U); -} - -TEST_F(APRSParser_parseAPRSFrame, CorrectMessageFrameWithDigipeater) { - - CAPRSFrame aprsFrame; - bool retVal = CAPRSParser::parseFrame("N0CALL>APRS,WIDE1-1,WIDE2-2::F4ABC :Test Message", aprsFrame); - - EXPECT_TRUE(retVal); - EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ":F4ABC :Test Message"); - EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); - EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "N0CALL"); - EXPECT_EQ(aprsFrame.getType(), APFT_MESSAGE); - EXPECT_EQ(aprsFrame.getPath().size(), 2); - EXPECT_STREQ(aprsFrame.getPath()[0].c_str(), "WIDE1-1"); - EXPECT_STREQ(aprsFrame.getPath()[1].c_str(), "WIDE2-2"); -} - -TEST_F(APRSParser_parseAPRSFrame, CorrectMessageFrameWithoutDigipeater) { - - CAPRSFrame aprsFrame; - bool retVal = CAPRSParser::parseFrame("N0CALL>APRS::F4ABC :Test Message", aprsFrame); - - EXPECT_TRUE(retVal); - EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ":F4ABC :Test Message"); - EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "APRS"); - EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "N0CALL"); - EXPECT_EQ(aprsFrame.getType(), APFT_MESSAGE); - EXPECT_EQ(aprsFrame.getPath().size(), 0); -} - -TEST_F(APRSParser_parseAPRSFrame, InvalidMessageFrame) { - - CAPRSFrame aprsFrame; - bool retVal = CAPRSParser::parseFrame("N0CALL>APRS::F4ABC&@#$:Test Message", aprsFrame); - - EXPECT_FALSE(retVal); - EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), ""); - EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), ""); - EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), ""); - EXPECT_EQ(aprsFrame.getType(), APFT_UNKNOWN); - EXPECT_EQ(aprsFrame.getPath().size(), 0U); -} - -// - -TEST_F(APRSParser_parseAPRSFrame, ID51) { - - CAPRSFrame aprsFrame; - bool retVal = CAPRSParser::parseFrame("F4FXL-8>API51,DSTAR:!1234.56N/12345.67E[/A=000886QRV DStar\r\r\n", aprsFrame); - - EXPECT_TRUE(retVal); - EXPECT_STRCASEEQ(aprsFrame.getBody().c_str(), "!1234.56N/12345.67E[/A=000886QRV DStar\r\r\n"); - EXPECT_STRCASEEQ(aprsFrame.getDestination().c_str(), "API51"); - EXPECT_STRCASEEQ(aprsFrame.getSource().c_str(), "F4FXL-8"); - EXPECT_EQ(aprsFrame.getType(), APFT_POSITION); - EXPECT_EQ(aprsFrame.getPath().size(), 1); - EXPECT_STREQ(aprsFrame.getPath()[0].c_str(), "DSTAR"); -} \ No newline at end of file From a373488b6abbb95904a9ba0466e474d8732693a2 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 14 Jan 2022 17:50:14 +0100 Subject: [PATCH 124/201] #9 update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c087b34..7cb4184 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ the testing framwework used is Google Test. # 5. Version History ## 5.1. Version 0.5 +- [Improvement] Add forwarding of RS-MS1A messages to APRS-IS ([#9](https://github.com/F4FXL/DStarGateway/issues/9)) - [Bugfix] Failed to download XLX Hosts when URL contains a = sign ([#14](https://github.com/F4FXL/DStarGateway/issues/14)) - [Bugfix] Remote control connection failed ([#13](https://github.com/F4FXL/DStarGateway/issues/13)) - [Bugfix] Trying to connect to ghost ircDDB when no ircDDB is configured From 17268c243fa5b19bc2c011d5835b6a973ef2fd20 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 14 Jan 2022 17:55:53 +0100 Subject: [PATCH 125/201] #9 update readem --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7cb4184..9b75943 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ - [1. Introduction](#1-introduction) - [2. Current State](#2-current-state) - [2.1. Code sanity](#21-code-sanity) - - [2.2. Code Credit](#22-code-credit) - - [2.3. Features](#23-features) + - [2.2. Code Credits](#22-code-credits) + - [2.3. Thanks](#23-thanks) + - [2.4. Features](#24-features) - [3. Building and installing](#3-building-and-installing) - [3.1. Initial setup](#31-initial-setup) - [3.2. Get latest stable version (recommended)](#32-get-latest-stable-version-recommended) @@ -34,11 +35,14 @@ The current code is working, yet ugly IMHO as it is a mix of C and C++ of variou The code has also been amended to no longer rely on compiler defines for paths like log or data. These can be set in configuration file. Quite a few classes are more or less copy/paste from each other some sanitization by using base classes or template classes would greatly improve code maintainibility. Maybe one day ;) -## 2.2. Code Credit +## 2.2. Code Credits - Jonathan Naylor G4KLX (The original author of [ircddbGateway](https://github.com/g4klx/ircDDBGateway)) - Thomas A. Early N7TAE (Code taken from his [smart-group](https://github.com/n7tae/smart-group-server) software) - Geoffrey Merck F4FXL / KC3FRA [That's me !](https://github.com/F4FXL/) -## 2.3. Features +## 2.3. Thanks +- Cyrille F1MHV / DF1CHB for the testing +- Jonathan Naylor G4KLX for all the work ahead +## 2.4. Features All the features found in ircddbGateway are supposed to be working. I have mixed feelings about putting these back in or not. Features that where left out : From 7127996a6cf7bdab4150fb0ace1c6477344ef008 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 14 Jan 2022 21:49:41 +0100 Subject: [PATCH 126/201] #5 properly name IRC member variables --- IRCDDBApp.cpp | 292 ++++++++++++++++++++++---------------------- IRCMessage.cpp | 62 +++++----- IRCMessage.h | 10 +- IRCMessageQueue.cpp | 10 +- IRCMessageQueue.h | 2 +- IRCProtocol.cpp | 110 ++++++++--------- IRCReceiver.cpp | 20 +-- 7 files changed, 253 insertions(+), 253 deletions(-) diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index 2731fb0..7be8857 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -35,11 +35,11 @@ along with this program. If not, see . class IRCDDBAppUserObject { public: - std::string nick; - std::string name; - std::string host; - bool op; - unsigned int usn; + std::string m_nick; + std::string m_name; + std::string m_host; + bool m_op; + unsigned int m_usn; IRCDDBAppUserObject() { @@ -48,20 +48,20 @@ public: IRCDDBAppUserObject(const std::string& n, const std::string& nm, const std::string& h) { - nick = n; - name = nm; - host = h; - op = false; - usn = 0; + m_nick = n; + m_name = nm; + m_host = h; + m_op = false; + m_usn = 0; } }; class IRCDDBAppRptrObject { public: - std::string arearp_cs; - time_t lastChanged; - std::string zonerp_cs; + std::string m_arearp_cs; + time_t m_lastChanged; + std::string m_zonerp_cs; IRCDDBAppRptrObject () { @@ -69,9 +69,9 @@ public: IRCDDBAppRptrObject (time_t &dt, std::string& repeaterCallsign, std::string& gatewayCallsign, time_t &maxTime) { - arearp_cs = repeaterCallsign; - lastChanged = dt; - zonerp_cs = gatewayCallsign; + m_arearp_cs = repeaterCallsign; + m_lastChanged = dt; + m_zonerp_cs = gatewayCallsign; if (dt > maxTime) maxTime = dt; @@ -82,10 +82,10 @@ class IRCDDBAppPrivate { public: IRCDDBAppPrivate() - : tablePattern("^[0-9]$") - , datePattern("^20[0-9][0-9]-((1[0-2])|(0[1-9]))-((3[01])|([12][0-9])|(0[1-9]))$") - , timePattern("^((2[0-3])|([01][0-9])):[0-5][0-9]:[0-5][0-9]$") - , dbPattern("^[0-9A-Z_]{8}$") + : m_tablePattern("^[0-9]$") + , m_datePattern("^20[0-9][0-9]-((1[0-2])|(0[1-9]))-((3[01])|([12][0-9])|(0[1-9]))$") + , m_timePattern("^((2[0-3])|([01][0-9])):[0-5][0-9]:[0-5][0-9]$") + , m_dbPattern("^[0-9A-Z_]{8}$") { } @@ -97,35 +97,35 @@ public: IRCMessageQueue *sendQ; IRCMessageQueue replyQ; - std::string currentServer; - std::string myNick; - std::string updateChannel; - std::string channelTopic; - std::string bestServer; + std::string m_currentServer; + std::string m_myNick; + std::string m_updateChannel; + std::string m_channelTopic; + std::string m_bestServer; - std::regex tablePattern; - std::regex datePattern; - std::regex timePattern; - std::regex dbPattern; + std::regex m_tablePattern; + std::regex m_datePattern; + std::regex m_timePattern; + std::regex m_dbPattern; - bool initReady; - bool terminateThread; + bool m_initReady; + bool m_terminateThread; - std::map user; - std::mutex userMapMutex; + std::map m_userMap; + std::mutex m_userMapMutex; - std::map rptrMap; - std::mutex rptrMapMutex; + std::map m_rptrMap; + std::mutex m_rptrMapMutex; - std::map moduleQRG; - std::mutex moduleQRGMutex; + std::map m_moduleQRG; + std::mutex m_moduleQRGMutex; - std::map moduleQTH; - std::map moduleURL; - std::mutex moduleQTHURLMutex; + std::map m_moduleQTH; + std::map m_moduleURL; + std::mutex m_moduleQTHURLMutex; - std::map moduleWD; - std::mutex moduleWDMutex; + std::map m_moduleWD; + std::mutex m_moduleWDMutex; }; IRCDDBApp::IRCDDBApp(const std::string& u_chan) @@ -133,17 +133,17 @@ IRCDDBApp::IRCDDBApp(const std::string& u_chan) , m_maxTime((time_t)950000000) //februray 2000 { d->sendQ = NULL; - d->initReady = false; + d->m_initReady = false; userListReset(); d->state = 0; d->timer = 0; - d->myNick = std::string("none"); + d->m_myNick = std::string("none"); - d->updateChannel = u_chan; + d->m_updateChannel = u_chan; - d->terminateThread = false; + d->m_terminateThread = false; } IRCDDBApp::~IRCDDBApp() @@ -177,11 +177,11 @@ void IRCDDBApp::rptrQTH(const std::string& callsign, double latitude, double lon CUtils::ReplaceChar(d2, ' ', '_'); CUtils::ReplaceChar(cs, ' ', '_'); - std::lock_guard lochQTHURL(d->moduleQTHURLMutex); + std::lock_guard lochQTHURL(d->m_moduleQTHURLMutex); - d->moduleQTH[cs] = cs + std::string(" ") + pos + std::string(" ") + d1 + std::string(" ") + d2; + d->m_moduleQTH[cs] = cs + std::string(" ") + pos + std::string(" ") + d1 + std::string(" ") + d2; - CLog::logInfo("QTH: %s\n", d->moduleQTH[cs].c_str()); + CLog::logInfo("QTH: %s\n", d->m_moduleQTH[cs].c_str()); std::string url = infoURL; @@ -190,8 +190,8 @@ void IRCDDBApp::rptrQTH(const std::string& callsign, double latitude, double lon url.erase(sm.position(0), sm.length()); if (url.size()) { - d->moduleURL[cs] = cs + std::string(" ") + url; - CLog::logInfo("URL: %s\n", d->moduleURL[cs].c_str()); + d->m_moduleURL[cs] = cs + std::string(" ") + url; + CLog::logInfo("URL: %s\n", d->m_moduleURL[cs].c_str()); } d->infoTimer = 5; // send info in 5 seconds @@ -207,9 +207,9 @@ void IRCDDBApp::rptrQRG(const std::string& callsign, double txFrequency, double std::string f(fstr); CUtils::ReplaceChar(f, ',', '.'); - std::lock_guard lockModuleQRG(d->moduleQRGMutex); - d->moduleQRG[cs] = cs + std::string(" ") + f; - CLog::logInfo("QRG: %s\n", d->moduleQRG[cs].c_str()); + std::lock_guard lockModuleQRG(d->m_moduleQRGMutex); + d->m_moduleQRG[cs] = cs + std::string(" ") + f; + CLog::logInfo("QRG: %s\n", d->m_moduleQRG[cs].c_str()); d->infoTimer = 5; // send info in 5 seconds } @@ -227,8 +227,8 @@ void IRCDDBApp::kickWatchdog(const std::string& callsign, const std::string& s) std::string cs = callsign; CUtils::ReplaceChar(cs, ' ', '_'); - std::lock_guard lockModuleWD(d->moduleWDMutex); - d->moduleWD[cs] = cs + std::string(" ") + text; + std::lock_guard lockModuleWD(d->m_moduleWDMutex); + d->m_moduleWD[cs] = cs + std::string(" ") + text; d->wdTimer = 60; } } @@ -267,13 +267,13 @@ IRCMessage *IRCDDBApp::getReplyMessage() void IRCDDBApp::startWork() { - d->terminateThread = false; + d->m_terminateThread = false; m_future = std::async(std::launch::async, &IRCDDBApp::Entry, this); } void IRCDDBApp::stopWork() { - d->terminateThread = true; + d->m_terminateThread = true; m_future.get(); } @@ -286,10 +286,10 @@ unsigned int IRCDDBApp::calculateUsn(const std::string& nick) for (int i = 1; i <= 4; i++) { std::string ircUser = lnick + std::to_string(i); - if (d->user.count(ircUser) == 1) { - IRCDDBAppUserObject obj = d->user[ircUser]; - if (obj.usn > maxUsn) - maxUsn = obj.usn; + if (d->m_userMap.count(ircUser) == 1) { + IRCDDBAppUserObject obj = d->m_userMap[ircUser]; + if (obj.m_usn > maxUsn) + maxUsn = obj.m_usn; } } return maxUsn + 1; @@ -297,17 +297,17 @@ unsigned int IRCDDBApp::calculateUsn(const std::string& nick) void IRCDDBApp::userJoin(const std::string& nick, const std::string& name, const std::string& host) { - std::lock_guard lockUserMap(d->userMapMutex); + std::lock_guard lockUserMap(d->m_userMapMutex); std::string lnick = nick; CUtils::ToLower(lnick); IRCDDBAppUserObject u(lnick, name, host); - u.usn = calculateUsn(lnick); + u.m_usn = calculateUsn(lnick); - d->user[lnick] = u; + d->m_userMap[lnick] = u; - if (d->initReady) { + if (d->m_initReady) { std::string::size_type hyphenPos = nick.find('-'); if ((hyphenPos >= 4) && (hyphenPos <= 6)) { @@ -329,25 +329,25 @@ void IRCDDBApp::userLeave(const std::string& nick) std::string lnick = nick; CUtils::ToLower(lnick); - std::lock_guard lockUserMap(d->userMapMutex); - d->user.erase(lnick); + std::lock_guard lockUserMap(d->m_userMapMutex); + d->m_userMap.erase(lnick); - if (d->currentServer.size()) { - if (d->user.count(d->myNick) != 1) { + if (d->m_currentServer.size()) { + if (d->m_userMap.count(d->m_myNick) != 1) { CLog::logInfo("IRCDDBApp::userLeave: could not find own nick\n"); return; } - IRCDDBAppUserObject me = d->user[d->myNick]; + IRCDDBAppUserObject me = d->m_userMap[d->m_myNick]; - if (me.op == false) { + if (me.m_op == false) { // if I am not op, then look for new server - if (0 == d->currentServer.compare(lnick)) { - // currentServer = null; + if (0 == d->m_currentServer.compare(lnick)) { + // m_currentServer = null; d->state = 2; // choose new server d->timer = 200; - d->initReady = false; + d->m_initReady = false; } } } @@ -355,39 +355,39 @@ void IRCDDBApp::userLeave(const std::string& nick) void IRCDDBApp::userListReset() { - std::lock_guard lockUserMap(d->userMapMutex); - d->user.clear(); + std::lock_guard lockUserMap(d->m_userMapMutex); + d->m_userMap.clear(); } void IRCDDBApp::setCurrentNick(const std::string& nick) { - d->myNick = nick; + d->m_myNick = nick; CLog::logInfo("IRCDDBApp::setCurrentNick %s\n", nick.c_str()); } void IRCDDBApp::setBestServer(const std::string& ircUser) { - d->bestServer = ircUser; + d->m_bestServer = ircUser; CLog::logInfo("IRCDDBApp::setBestServer %s\n", ircUser.c_str()); } void IRCDDBApp::setTopic(const std::string& topic) { - d->channelTopic = topic; + d->m_channelTopic = topic; } bool IRCDDBApp::findServerUser() { bool found = false; - std::lock_guard lockUserMap(d->userMapMutex); + std::lock_guard lockUserMap(d->m_userMapMutex); std::map::iterator it; - for (it = d->user.begin(); it != d->user.end(); ++it) { + for (it = d->m_userMap.begin(); it != d->m_userMap.end(); ++it) { IRCDDBAppUserObject u = it->second; - if (0==u.nick.compare(0, 2, "s-") && u.op && d->myNick.compare(u.nick) && 0==u.nick.compare(d->bestServer)) { - d->currentServer = u.nick; + if (0==u.m_nick.compare(0, 2, "s-") && u.m_op && d->m_myNick.compare(u.m_nick) && 0==u.m_nick.compare(d->m_bestServer)) { + d->m_currentServer = u.m_nick; found = true; break; } @@ -397,12 +397,12 @@ bool IRCDDBApp::findServerUser() return true; } - if (8 == d->bestServer.size()) { - for (it = d->user.begin(); it != d->user.end(); ++it) { + if (8 == d->m_bestServer.size()) { + for (it = d->m_userMap.begin(); it != d->m_userMap.end(); ++it) { IRCDDBAppUserObject u = it->second; - if (0==u.nick.compare(d->bestServer.substr(0,7)) && u.op && d->myNick.compare(u.nick) ) { - d->currentServer = u.nick; + if (0==u.m_nick.compare(d->m_bestServer.substr(0,7)) && u.m_op && d->m_myNick.compare(u.m_nick) ) { + d->m_currentServer = u.m_nick; found = true; break; } @@ -413,10 +413,10 @@ bool IRCDDBApp::findServerUser() return true; } - for (it = d->user.begin(); it != d->user.end(); ++it) { + for (it = d->m_userMap.begin(); it != d->m_userMap.end(); ++it) { IRCDDBAppUserObject u = it->second; - if (0==u.nick.compare(0, 2, "s-") && u.op && d->myNick.compare(u.nick)) { - d->currentServer = u.nick; + if (0==u.m_nick.compare(0, 2, "s-") && u.m_op && d->m_myNick.compare(u.m_nick)) { + d->m_currentServer = u.m_nick; found = true; break; } @@ -426,13 +426,13 @@ bool IRCDDBApp::findServerUser() void IRCDDBApp::userChanOp(const std::string& nick, bool op) { - std::lock_guard lockUserMap(d->userMapMutex); + std::lock_guard lockUserMap(d->m_userMapMutex); std::string lnick = nick; CUtils::ToLower(lnick); - if (d->user.count(lnick) == 1) - d->user[lnick].op = op; + if (d->m_userMap.count(lnick) == 1) + d->m_userMap[lnick].m_op = op; } static const int numberOfTables = 2; @@ -446,16 +446,16 @@ std::string IRCDDBApp::getIPAddress(std::string& zonerp_cs) CUtils::ToLower(gw); CUtils::Trim(gw); - std::lock_guard lockUserMap(d->userMapMutex); + std::lock_guard lockUserMap(d->m_userMapMutex); for (int j=1; j <= 4; j++) { std::string ircUser = gw + std::string("-") + std::to_string(j); - if (d->user.count(ircUser) == 1) { - IRCDDBAppUserObject o = d->user[ircUser]; + if (d->m_userMap.count(ircUser) == 1) { + IRCDDBAppUserObject o = d->m_userMap[ircUser]; - if (o.usn >= max_usn) { - max_usn = o.usn; - ipAddr = o.host.c_str(); + if (o.m_usn >= max_usn) { + max_usn = o.m_usn; + ipAddr = o.m_host.c_str(); } } } @@ -509,7 +509,7 @@ static void findReflector(const std::string& rptrCall, IRCDDBAppPrivate *d) bool IRCDDBApp::findRepeater(const std::string& rptrCall) { - if (0==rptrCall.compare(0, 3, "XRF") || 0==rptrCall.compare(0, 3, "REF")) { + if (0==rptrCall.compare(0, 3, "XRF") || 0==rptrCall.compare(0, 3, "REF") || 0==rptrCall.compare(0, 3, "DCS") || 0==rptrCall.compare(0, 3, "XLX") ) { findReflector(rptrCall, d); return true; } @@ -519,15 +519,15 @@ bool IRCDDBApp::findRepeater(const std::string& rptrCall) std::string s("NONE"); std::string zonerp_cs; - std::lock_guard lockRptrMap(d->rptrMapMutex); + std::lock_guard lockRptrMap(d->m_rptrMapMutex); - if (1 == d->rptrMap.count(arearp_cs)) { - IRCDDBAppRptrObject o = d->rptrMap[arearp_cs]; - zonerp_cs = o.zonerp_cs; + if (1 == d->m_rptrMap.count(arearp_cs)) { + IRCDDBAppRptrObject o = d->m_rptrMap[arearp_cs]; + zonerp_cs = o.m_zonerp_cs; CUtils::ReplaceChar(zonerp_cs, '_', ' '); zonerp_cs.resize(7, ' '); zonerp_cs.push_back('G'); - s = o.zonerp_cs; + s = o.m_zonerp_cs; } IRCMessage * m2 = new IRCMessage("IDRT_REPEATER"); @@ -542,7 +542,7 @@ bool IRCDDBApp::findRepeater(const std::string& rptrCall) void IRCDDBApp::sendDStarGatewayInfo(const std::string &subcommand, const std::vector &pars) { IRCMessageQueue *q = getSendQ(); - std::string srv(d->currentServer); + std::string srv(d->m_currentServer); if (srv.size() && d->state>=6 && q) { std::string command("DStarGateway "); command.append(subcommand); @@ -582,7 +582,7 @@ bool IRCDDBApp::sendHeard(const std::string& myCall, const std::string& myCallEx bool statsMsg = (tx_stats.size() > 0); - std::string srv(d->currentServer); + std::string srv(d->m_currentServer); IRCMessageQueue *q = getSendQ(); if (srv.size() && d->state>=6 && q) { @@ -616,7 +616,7 @@ bool IRCDDBApp::sendHeard(const std::string& myCall, const std::string& myCallEx bool IRCDDBApp::findUser(const std::string& usrCall) { - std::string srv(d->currentServer); + std::string srv(d->m_currentServer); IRCMessageQueue *q = getSendQ(); if (srv.size()>0 && d->state>=6 && q) { @@ -637,7 +637,7 @@ bool IRCDDBApp::findUser(const std::string& usrCall) void IRCDDBApp::msgChannel(IRCMessage *m) { if (0==m->getPrefixNick().compare(0, 2, "s-") && m->numParams>=2) // server msg - doUpdate(m->params[1]); + doUpdate(m->m_params[1]); } void IRCDDBApp::doNotFound(std::string& msg, std::string& retval) @@ -651,7 +651,7 @@ void IRCDDBApp::doNotFound(std::string& msg, std::string& retval) std::string tk = tkz.front(); tkz.erase(tkz.begin()); - if (std::regex_match(tk, d->tablePattern)) { + if (std::regex_match(tk, d->m_tablePattern)) { tableID = std::stoi(tk); if (tableID<0 || tableID>=numberOfTables) { @@ -667,7 +667,7 @@ void IRCDDBApp::doNotFound(std::string& msg, std::string& retval) } if (0 == tableID) { - if (! std::regex_match(tk, d->dbPattern)) + if (! std::regex_match(tk, d->m_dbPattern)) return; // no valid key retval = tk; } @@ -683,7 +683,7 @@ void IRCDDBApp::doUpdate(std::string& msg) std::string tk = tkz.front(); tkz.erase(tkz.begin()); - if (std::regex_match(tk, d->tablePattern)) { + if (std::regex_match(tk, d->m_tablePattern)) { tableID = std::stoi(tk); if ((tableID < 0) || (tableID >= numberOfTables)) { CLog::logInfo("invalid table ID %d\n", tableID); @@ -697,13 +697,13 @@ void IRCDDBApp::doUpdate(std::string& msg) tkz.erase(tkz.begin()); } - if (std::regex_match(tk, d->datePattern)) { + if (std::regex_match(tk, d->m_datePattern)) { if (tkz.empty()) return; // nothing after date string std::string timeToken = tkz.front(); // time token tkz.erase(tkz.begin()); - if (! std::regex_match(timeToken, d->timePattern)) + if (! std::regex_match(timeToken, d->m_timePattern)) return; // no time string after date string time_t dt = CUtils::parseTime(tk + std::string(" ") + timeToken); @@ -715,7 +715,7 @@ void IRCDDBApp::doUpdate(std::string& msg) std::string key = tkz.front(); tkz.erase(tkz.begin()); - if (! std::regex_match(key, d->dbPattern)) + if (! std::regex_match(key, d->m_dbPattern)) return; // no valid key if (tkz.empty()) @@ -724,15 +724,15 @@ void IRCDDBApp::doUpdate(std::string& msg) std::string value = tkz.front(); tkz.erase(tkz.begin()); - if (! std::regex_match(value, d->dbPattern)) + if (! std::regex_match(value, d->m_dbPattern)) return; // no valid key if (tableID == 1) { - std::lock_guard lockRptrMap(d->rptrMapMutex); + std::lock_guard lockRptrMap(d->m_rptrMapMutex); IRCDDBAppRptrObject newRptr(dt, key, value, m_maxTime); - d->rptrMap[key] = newRptr; + d->m_rptrMap[key] = newRptr; - if (d->initReady) { + if (d->m_initReady) { std::string arearp_cs(key); std::string zonerp_cs(value); CUtils::ReplaceChar(arearp_cs, '_', ' '); @@ -746,8 +746,8 @@ void IRCDDBApp::doUpdate(std::string& msg) m2->addParam(getIPAddress(value)); d->replyQ.putMessage(m2); } - } else if (0==tableID && d->initReady) { - std::lock_guard lockRptrMap(d->rptrMapMutex); + } else if (0==tableID && d->m_initReady) { + std::lock_guard lockRptrMap(d->m_rptrMapMutex); std::string userCallsign(key); std::string arearp_cs(value); std::string zonerp_cs; @@ -755,13 +755,13 @@ void IRCDDBApp::doUpdate(std::string& msg) CUtils::ReplaceChar(userCallsign, '_', ' '); CUtils::ReplaceChar(arearp_cs, '_', ' '); - if (1 == d->rptrMap.count(value)) { - IRCDDBAppRptrObject o = d->rptrMap[value]; - zonerp_cs = o.zonerp_cs; + if (1 == d->m_rptrMap.count(value)) { + IRCDDBAppRptrObject o = d->m_rptrMap[value]; + zonerp_cs = o.m_zonerp_cs; CUtils::ReplaceChar(zonerp_cs, '_', ' '); zonerp_cs.resize(7, ' '); zonerp_cs.push_back('G'); - ip_addr = getIPAddress(o.zonerp_cs); + ip_addr = getIPAddress(o.m_zonerp_cs); } IRCMessage *m2 = new IRCMessage("IDRT_USER"); @@ -793,7 +793,7 @@ static std::string getTableIDString(int tableID, bool spaceBeforeNumber) void IRCDDBApp::msgQuery(IRCMessage *m) { if (0==m->getPrefixNick().compare(0, 2, "s-") && m->numParams>=2) { // server msg - std::string msg(m->params[1]); + std::string msg(m->m_params[1]); std::vector tkz = CUtils::stringTokenizer(msg); if (tkz.empty()) @@ -870,7 +870,7 @@ static bool needsDatabaseUpdate(int tableID) void IRCDDBApp::Entry() { int sendlistTableID = 0; - while (!d->terminateThread) { + while (!d->m_terminateThread) { if (d->timer > 0) d->timer--; switch(d->state) { @@ -923,7 +923,7 @@ void IRCDDBApp::Entry() d->state = 10; // disconnect DB else { if (needsDatabaseUpdate(sendlistTableID)) { - IRCMessage *m = new IRCMessage(d->currentServer, std::string("SENDLIST") + getTableIDString(sendlistTableID, true) + std::string(" ") + getLastEntryTime(sendlistTableID)); + IRCMessage *m = new IRCMessage(d->m_currentServer, std::string("SENDLIST") + getTableIDString(sendlistTableID, true) + std::string(" ") + getLastEntryTime(sendlistTableID)); IRCMessageQueue *q = getSendQ(); if (q) q->putMessage(m); @@ -952,7 +952,7 @@ void IRCDDBApp::Entry() else { CLog::logInfo( "IRCDDBApp: state=6 initialization completed\n"); d->infoTimer = 2; - d->initReady = true; + d->m_initReady = true; d->state = 7; } break; @@ -966,35 +966,35 @@ void IRCDDBApp::Entry() if (0 == d->infoTimer) { { // Scope for mutext locking - std::lock_guard lochQTHURL(d->moduleQTHURLMutex); - for (auto it = d->moduleQTH.begin(); it != d->moduleQTH.end(); ++it) { + std::lock_guard lochQTHURL(d->m_moduleQTHURLMutex); + for (auto it = d->m_moduleQTH.begin(); it != d->m_moduleQTH.end(); ++it) { std::string value = it->second; - IRCMessage *m = new IRCMessage(d->currentServer, std::string("IRCDDB RPTRQTH: ") + value); + IRCMessage *m = new IRCMessage(d->m_currentServer, std::string("IRCDDB RPTRQTH: ") + value); IRCMessageQueue *q = getSendQ(); if (q != NULL) q->putMessage(m); } - d->moduleQTH.clear(); + d->m_moduleQTH.clear(); - for (auto it = d->moduleURL.begin(); it != d->moduleURL.end(); ++it) { + for (auto it = d->m_moduleURL.begin(); it != d->m_moduleURL.end(); ++it) { std::string value = it->second; - IRCMessage *m = new IRCMessage(d->currentServer, std::string("IRCDDB RPTRURL: ") + value); + IRCMessage *m = new IRCMessage(d->m_currentServer, std::string("IRCDDB RPTRURL: ") + value); IRCMessageQueue *q = getSendQ(); if (q != NULL) q->putMessage(m); } - d->moduleURL.clear(); + d->m_moduleURL.clear(); } - std::lock_guard lockModuleQRG(d->moduleQRGMutex); - for (auto it = d->moduleQRG.begin(); it != d->moduleQRG.end(); ++it) { + std::lock_guard lockModuleQRG(d->m_moduleQRGMutex); + for (auto it = d->m_moduleQRG.begin(); it != d->m_moduleQRG.end(); ++it) { std::string value = it->second; - IRCMessage* m = new IRCMessage(d->currentServer, std::string("IRCDDB RPTRQRG: ") + value); + IRCMessage* m = new IRCMessage(d->m_currentServer, std::string("IRCDDB RPTRQRG: ") + value); IRCMessageQueue* q = getSendQ(); if (q != NULL) q->putMessage(m); } - d->moduleQRG.clear(); + d->m_moduleQRG.clear(); } } @@ -1002,16 +1002,16 @@ void IRCDDBApp::Entry() d->wdTimer--; if (0 == d->wdTimer) { - std::lock_guard lockModuleWD(d->moduleWDMutex); + std::lock_guard lockModuleWD(d->m_moduleWDMutex); - for (auto it = d->moduleWD.begin(); it != d->moduleWD.end(); ++it) { + for (auto it = d->m_moduleWD.begin(); it != d->m_moduleWD.end(); ++it) { std::string value = it->second; - IRCMessage *m = new IRCMessage(d->currentServer, std::string("IRCDDB RPTRSW: ") + value); + IRCMessage *m = new IRCMessage(d->m_currentServer, std::string("IRCDDB RPTRSW: ") + value); IRCMessageQueue *q = getSendQ(); if (q) q->putMessage(m); } - d->moduleWD.clear(); + d->m_moduleWD.clear(); } } break; @@ -1020,7 +1020,7 @@ void IRCDDBApp::Entry() // disconnect db d->state = 0; d->timer = 0; - d->initReady = false; + d->m_initReady = false; break; } std::this_thread::sleep_for(std::chrono::seconds(1)); diff --git a/IRCMessage.cpp b/IRCMessage.cpp index 8f6fb08..f8e407f 100644 --- a/IRCMessage.cpp +++ b/IRCMessage.cpp @@ -25,23 +25,23 @@ along with this program. If not, see . IRCMessage::IRCMessage() { numParams = 0; - prefixParsed = false; + m_prefixParsed = false; } IRCMessage::IRCMessage(const std::string& toNick, const std::string& msg) { - command.assign("PRIVMSG"); + m_command.assign("PRIVMSG"); numParams = 2; - params.push_back(toNick); - params.push_back(msg); - prefixParsed = false; + m_params.push_back(toNick); + m_params.push_back(msg); + m_prefixParsed = false; } IRCMessage::IRCMessage(const std::string& cmd) { - command = cmd; + m_command = cmd; numParams = 0; - prefixParsed = false; + m_prefixParsed = false; } IRCMessage::~IRCMessage() @@ -51,79 +51,79 @@ IRCMessage::~IRCMessage() void IRCMessage::addParam(const std::string& p) { - params.push_back(p); - numParams = params.size(); + m_params.push_back(p); + numParams = m_params.size(); } int IRCMessage::getParamCount() { - return params.size(); + return m_params.size(); } std::string IRCMessage::getParam(int pos) { - return params[pos]; + return m_params[pos]; } std::string IRCMessage::getCommand() { - return command; + return m_command; } bool IRCMessage::parsePrefix() { - std::string::size_type p1 = prefix.find('!'); + std::string::size_type p1 = m_prefix.find('!'); if (std::string::npos == p1) return false; - std::string::size_type p2 = prefix.find('@'); + std::string::size_type p2 = m_prefix.find('@'); if (std::string::npos == p2) return false; - prefixComponents.push_back(prefix.substr(0, p1)); - prefixComponents.push_back(prefix.substr(p1+1, p2-p1-1)); - prefixComponents.push_back(prefix.substr(p2 + 1)); + m_prefixComponents.push_back(m_prefix.substr(0, p1)); + m_prefixComponents.push_back(m_prefix.substr(p1+1, p2-p1-1)); + m_prefixComponents.push_back(m_prefix.substr(p2 + 1)); return true; } std::string& IRCMessage::getPrefixNick() { - if (!prefixParsed) - prefixParsed = parsePrefix(); + if (!m_prefixParsed) + m_prefixParsed = parsePrefix(); - return prefixParsed ? prefixComponents[0] : prefix; + return m_prefixParsed ? m_prefixComponents[0] : m_prefix; } std::string& IRCMessage::getPrefixName() { - if (!prefixParsed) - prefixParsed = parsePrefix(); + if (!m_prefixParsed) + m_prefixParsed = parsePrefix(); - return prefixParsed ? prefixComponents[1] : prefix; + return m_prefixParsed ? m_prefixComponents[1] : m_prefix; } std::string& IRCMessage::getPrefixHost() { - if (!prefixParsed) - prefixParsed = parsePrefix(); + if (!m_prefixParsed) + m_prefixParsed = parsePrefix(); - return prefixParsed ? prefixComponents[2] : prefix; + return m_prefixParsed ? m_prefixComponents[2] : m_prefix; } void IRCMessage::composeMessage(std::string& output) { std::string o; - if (prefix.size() > 0) - o = std::string(":") + prefix + std::string(" "); + if (m_prefix.size() > 0) + o = std::string(":") + m_prefix + std::string(" "); - o.append(command); + o.append(m_command); for (int i=0; i < numParams; i++) { if (i == (numParams - 1)) - o.append(std::string(" :") + params[i]); + o.append(std::string(" :") + m_params[i]); else - o.append(std::string(" ") + params[i]); + o.append(std::string(" ") + m_params[i]); } o.append(std::string("\r\n")); diff --git a/IRCMessage.h b/IRCMessage.h index e157405..bb7df32 100644 --- a/IRCMessage.h +++ b/IRCMessage.h @@ -32,9 +32,9 @@ public: IRCMessage(const std::string& command); ~IRCMessage(); - std::string prefix; - std::string command; - std::vector params; + std::string m_prefix; + std::string m_command; + std::vector m_params; int numParams; std::string& getPrefixNick(); @@ -49,6 +49,6 @@ public: private: bool parsePrefix(); - std::vector prefixComponents; - bool prefixParsed; + std::vector m_prefixComponents; + bool m_prefixParsed; }; diff --git a/IRCMessageQueue.cpp b/IRCMessageQueue.cpp index 035e903..eea7d09 100644 --- a/IRCMessageQueue.cpp +++ b/IRCMessageQueue.cpp @@ -33,7 +33,7 @@ IRCMessageQueue::IRCMessageQueue() IRCMessageQueue::~IRCMessageQueue() { - std::lock_guard lockAccessQueue(accessMutex); + std::lock_guard lockAccessQueue(m_accessMutex); while (! m_queue.empty()) { delete m_queue.front(); m_queue.pop(); @@ -52,7 +52,7 @@ void IRCMessageQueue::signalEOF() bool IRCMessageQueue::messageAvailable() { - std::lock_guard lockAccessQueue(accessMutex); + std::lock_guard lockAccessQueue(m_accessMutex); bool retv = ! m_queue.empty(); return retv; @@ -60,14 +60,14 @@ bool IRCMessageQueue::messageAvailable() IRCMessage *IRCMessageQueue::peekFirst() { - std::lock_guard lockAccessQueue(accessMutex); + std::lock_guard lockAccessQueue(m_accessMutex); IRCMessage *msg = m_queue.empty() ? NULL : m_queue.front(); return msg; } IRCMessage *IRCMessageQueue::getMessage() { - std::lock_guard lockAccessQueue(accessMutex); + std::lock_guard lockAccessQueue(m_accessMutex); IRCMessage *msg = m_queue.empty() ? NULL : m_queue.front(); if (msg) m_queue.pop(); @@ -77,7 +77,7 @@ IRCMessage *IRCMessageQueue::getMessage() void IRCMessageQueue::putMessage(IRCMessage *m) { - std::lock_guard lockAccessQueue(accessMutex); + std::lock_guard lockAccessQueue(m_accessMutex); m_queue.push(m); } diff --git a/IRCMessageQueue.h b/IRCMessageQueue.h index 3ab656b..4a97caf 100644 --- a/IRCMessageQueue.h +++ b/IRCMessageQueue.h @@ -46,7 +46,7 @@ public: private: bool m_eof; - std::mutex accessMutex; + std::mutex m_accessMutex; std::queue m_queue; }; diff --git a/IRCProtocol.cpp b/IRCProtocol.cpp index 0c43b50..dd74135 100644 --- a/IRCProtocol.cpp +++ b/IRCProtocol.cpp @@ -92,26 +92,26 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) while (recvQ->messageAvailable()) { IRCMessage *m = recvQ->getMessage(); - if (0 == m->command.compare("004")) { + if (0 == m->m_command.compare("004")) { if (4 == m_state) { - if (m->params.size() > 1) { + if (m->m_params.size() > 1) { std::regex serverNamePattern("^grp[1-9]s[1-9].ircDDB$"); - if (std::regex_match(m->params[1], serverNamePattern)) - m_app->setBestServer(std::string("s-") + m->params[1].substr(0,6)); + if (std::regex_match(m->m_params[1], serverNamePattern)) + m_app->setBestServer(std::string("s-") + m->m_params[1].substr(0,6)); } m_state = 5; // next: JOIN m_app->setCurrentNick(m_currentNick); } - } else if (0 == m->command.compare("PING")) { + } else if (0 == m->m_command.compare("PING")) { IRCMessage *m2 = new IRCMessage(); - m2->command = std::string("PONG"); - if (m->params.size() > 0) { + m2->m_command = std::string("PONG"); + if (m->m_params.size() > 0) { m2->numParams = 1; - m2->params.push_back(m->params[0]); + m2->m_params.push_back(m->m_params[0]); } sendQ -> putMessage(m2); - } else if (0 == m->command.compare("JOIN")) { - if (m->numParams>=1 && 0==m->params[0].compare(m_channel)) { + } else if (0 == m->m_command.compare("JOIN")) { + if (m->numParams>=1 && 0==m->m_params[0].compare(m_channel)) { if (0==m->getPrefixNick().compare(m_currentNick) && 6==m_state) { if (m_debugChannel.size()) m_state = 7; // next: join debug_channel @@ -121,69 +121,69 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) m_app->userJoin(m->getPrefixNick(), m->getPrefixName(), m->getPrefixHost()); } - if (m->numParams>=1 && 0==m->params[0].compare(m_debugChannel)) { + if (m->numParams>=1 && 0==m->m_params[0].compare(m_debugChannel)) { if (0==m->getPrefixNick().compare(m_currentNick) && 8==m_state) m_state = 10; // next: WHO * } - } else if (0 == m->command.compare("PONG")) { + } else if (0 == m->m_command.compare("PONG")) { if (12 == m_state) { m_timer = m_pingTimer; m_state = 11; } - } else if (0 == m->command.compare("PART")) { - if (m->numParams>=1 && 0==m->params[0].compare(m_channel)) { + } else if (0 == m->m_command.compare("PART")) { + if (m->numParams>=1 && 0==m->m_params[0].compare(m_channel)) { if (m_app != NULL) m_app->userLeave(m->getPrefixNick()); } - } else if (0 == m->command.compare("KICK")) { - if (m->numParams>=2 && 0==m->params[0].compare(m_channel)) { - if (0 == m->params[1].compare(m_currentNick)) { + } else if (0 == m->m_command.compare("KICK")) { + if (m->numParams>=2 && 0==m->m_params[0].compare(m_channel)) { + if (0 == m->m_params[1].compare(m_currentNick)) { // i was kicked!! delete m; return false; } else if (m_app) - m_app->userLeave(m->params[1]); + m_app->userLeave(m->m_params[1]); } - } else if (0 == m->command.compare("QUIT")) { + } else if (0 == m->m_command.compare("QUIT")) { if (m_app) m_app->userLeave(m->getPrefixNick()); - } else if (0 == m->command.compare("MODE")) { - if (m->numParams>=3 && 0==m->params[0].compare(m_channel)) { + } else if (0 == m->m_command.compare("MODE")) { + if (m->numParams>=3 && 0==m->m_params[0].compare(m_channel)) { if (m_app) { - std::string mode = m->params[1]; + std::string mode = m->m_params[1]; for (size_t i=1; inumParams>=i+2; i++) { if ('o' == mode[i]) { if ('+' == mode[0]) - m_app->userChanOp(m->params[i+1], true); + m_app->userChanOp(m->m_params[i+1], true); else if ('-' == mode[0]) - m_app->userChanOp(m->params[i+1], false); + m_app->userChanOp(m->m_params[i+1], false); } } // for } } - } else if (0 == m->command.compare("PRIVMSG")) { + } else if (0 == m->m_command.compare("PRIVMSG")) { if (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); - else if (0 == m->params[0].compare(m_currentNick) && m_app) + else if (0 == m->m_params[0].compare(m_currentNick) && m_app) m_app->msgQuery(m); } - } else if (0 == m->command.compare("352")) { // WHO list - if (m->numParams>=7 && 0==m->params[0].compare(m_currentNick) && 0==m->params[1].compare(m_channel)) { + } else if (0 == m->m_command.compare("352")) { // WHO list + if (m->numParams>=7 && 0==m->m_params[0].compare(m_currentNick) && 0==m->m_params[1].compare(m_channel)) { if (m_app) { - m_app->userJoin(m->params[5], m->params[2], m->params[3]); - m_app->userChanOp(m->params[5], 0==m->params[6].compare("H@")); + m_app->userJoin(m->m_params[5], m->m_params[2], m->m_params[3]); + m_app->userChanOp(m->m_params[5], 0==m->m_params[6].compare("H@")); } } - } else if (0 == m->command.compare("433")) { // nick collision + } else if (0 == m->m_command.compare("433")) { // nick collision if (2 == m_state) { m_state = 3; // nick collision, choose new nick m_timer = 10; // wait 5 seconds.. } - } else if (0==m->command.compare("332") || 0==m->command.compare("TOPIC")) { // topic - if (2==m->numParams && m_app && 0==m->params[0].compare(m_channel)) - m_app->setTopic(m->params[1]); + } else if (0==m->m_command.compare("332") || 0==m->m_command.compare("TOPIC")) { // topic + if (2==m->numParams && m_app && 0==m->m_params[0].compare(m_channel)) + m_app->setTopic(m->m_params[1]); } delete m; @@ -193,15 +193,15 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) switch (m_state) { case 1: m = new IRCMessage(); - m->command = std::string("PASS"); + m->m_command = std::string("PASS"); m->numParams = 1; - m->params.push_back(m_password); + m->m_params.push_back(m_password); sendQ->putMessage(m); m = new IRCMessage(); - m->command = std::string("NICK"); + m->m_command = std::string("NICK"); m->numParams = 1; - m->params.push_back(m_currentNick); + m->m_params.push_back(m_currentNick); sendQ->putMessage(m); m_timer = 10; // wait for possible nick collision message @@ -211,12 +211,12 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) case 2: if (0 == m_timer) { m = new IRCMessage(); - m->command = std::string("USER"); + m->m_command = std::string("USER"); m->numParams = 4; - m->params.push_back(m_name); - m->params.push_back(std::string("0")); - m->params.push_back(std::string("*")); - m->params.push_back(m_versionInfo); + m->m_params.push_back(m_name); + m->m_params.push_back(std::string("0")); + m->m_params.push_back(std::string("*")); + m->m_params.push_back(m_versionInfo); sendQ->putMessage(m); m_timer = 30; @@ -228,9 +228,9 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) if (0 == m_timer) { chooseNewNick(); m = new IRCMessage(); - m->command = std::string("NICK"); + m->m_command = std::string("NICK"); m->numParams = 1; - m->params.push_back(m_currentNick); + m->m_params.push_back(m_currentNick); sendQ->putMessage(m); m_timer = 10; // wait for possible nick collision message @@ -245,9 +245,9 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) case 5: m = new IRCMessage(); - m->command = std::string("JOIN"); + m->m_command = std::string("JOIN"); m->numParams = 1; - m->params.push_back(m_channel); + m->m_params.push_back(m_channel); sendQ->putMessage(m); m_timer = 30; @@ -264,9 +264,9 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) return false; // this state cannot be processed if there is no debug_channel m = new IRCMessage(); - m->command = std::string("JOIN"); + m->m_command = std::string("JOIN"); m->numParams = 1; - m->params.push_back(m_debugChannel); + m->m_params.push_back(m_debugChannel); sendQ->putMessage(m); m_timer = 30; @@ -280,10 +280,10 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) case 10: m = new IRCMessage(); - m->command = std::string("WHO"); + m->m_command = std::string("WHO"); m->numParams = 2; - m->params.push_back(m_channel); - m->params.push_back(std::string("*")); + m->m_params.push_back(m_channel); + m->m_params.push_back(std::string("*")); sendQ->putMessage(m); m_timer = m_pingTimer; @@ -296,9 +296,9 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) case 11: if (0 == m_timer) { m = new IRCMessage(); - m->command = std::string("PING"); + m->m_command = std::string("PING"); m->numParams = 1; - m->params.push_back(m_currentNick); + m->m_params.push_back(m_currentNick); sendQ->putMessage(m); m_timer = m_pingTimer; diff --git a/IRCReceiver.cpp b/IRCReceiver.cpp index b23128b..5e6bfed 100644 --- a/IRCReceiver.cpp +++ b/IRCReceiver.cpp @@ -114,27 +114,27 @@ void IRCReceiver::Entry() switch (state) { case 0: // command if (b == ':') - state = 1; // prefix + state = 1; // m_prefix else if (b != ' ') { - m->command.push_back(b); + m->m_command.push_back(b); state = 2; // command } break; - case 1: // prefix + case 1: // m_prefix if (b == ' ') state = 2; // command is next else - m->prefix.push_back(b); + m->m_prefix.push_back(b); break; case 2: if (b == ' ') { state = 3; // params are next m->numParams = 1; - m->params.push_back(std::string("")); + m->m_params.push_back(std::string("")); } else - m->command.push_back(b); + m->m_command.push_back(b); break; case 3: @@ -142,15 +142,15 @@ void IRCReceiver::Entry() m->numParams++; if (m->numParams >= 15) state = 5; // ignore the rest - m->params.push_back(std::string("")); - } else if (b==':' && m->params[m->numParams-1].size()==0) + m->m_params.push_back(std::string("")); + } else if (b==':' && m->m_params[m->numParams-1].size()==0) state = 4; // rest of line is this param else - m->params[m->numParams-1].push_back(b); + m->m_params[m->numParams-1].push_back(b); break; case 4: - m->params[m->numParams-1].push_back(b); + m->m_params[m->numParams-1].push_back(b); break; } // switch } From 1be24fa41d09d6c9192e88d459aa0f64f766bf22 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 15 Jan 2022 11:03:02 +0100 Subject: [PATCH 127/201] #5 More renaming --- IRCDDB.h | 2 + IRCDDBApp.cpp | 134 +++++++++++++++++++++--------------------- IRCDDBClient.cpp | 8 +++ IRCDDBClient.h | 2 + IRCDDBMultiClient.cpp | 6 +- IRCDDBMultiClient.h | 1 + 6 files changed, 85 insertions(+), 68 deletions(-) diff --git a/IRCDDB.h b/IRCDDB.h index 8f31825..72e8c9a 100644 --- a/IRCDDB.h +++ b/IRCDDB.h @@ -135,6 +135,8 @@ public: virtual bool receiveUser(std::string& userCallsign, std::string& repeaterCallsign, std::string& gatewayCallsign, std::string& address, std::string& timeStamp) = 0; virtual void close() = 0; // Implictely kills any threads in the IRC code + + virtual void queryUsers() = 0; }; typedef std::vector CIRCDDB_Array; diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index 7be8857..d03b786 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -89,13 +89,13 @@ public: { } - int state; - int timer; - int infoTimer; - int wdTimer; + int m_state; + int m_timer; + int m_infoTimer; + int m_wdTimer; - IRCMessageQueue *sendQ; - IRCMessageQueue replyQ; + IRCMessageQueue *m_sendQ; + IRCMessageQueue m_replyQ; std::string m_currentServer; std::string m_myNick; @@ -132,13 +132,13 @@ IRCDDBApp::IRCDDBApp(const std::string& u_chan) : d(new IRCDDBAppPrivate) , m_maxTime((time_t)950000000) //februray 2000 { - d->sendQ = NULL; + d->m_sendQ = NULL; d->m_initReady = false; userListReset(); - d->state = 0; - d->timer = 0; + d->m_state = 0; + d->m_timer = 0; d->m_myNick = std::string("none"); d->m_updateChannel = u_chan; @@ -148,7 +148,7 @@ IRCDDBApp::IRCDDBApp(const std::string& u_chan) IRCDDBApp::~IRCDDBApp() { - delete d->sendQ; + delete d->m_sendQ; delete d; } @@ -194,7 +194,7 @@ void IRCDDBApp::rptrQTH(const std::string& callsign, double latitude, double lon CLog::logInfo("URL: %s\n", d->m_moduleURL[cs].c_str()); } - d->infoTimer = 5; // send info in 5 seconds + d->m_infoTimer = 5; // send info in 5 seconds } void IRCDDBApp::rptrQRG(const std::string& callsign, double txFrequency, double duplexShift, double range, double agl) @@ -211,7 +211,7 @@ void IRCDDBApp::rptrQRG(const std::string& callsign, double txFrequency, double d->m_moduleQRG[cs] = cs + std::string(" ") + f; CLog::logInfo("QRG: %s\n", d->m_moduleQRG[cs].c_str()); - d->infoTimer = 5; // send info in 5 seconds + d->m_infoTimer = 5; // send info in 5 seconds } void IRCDDBApp::kickWatchdog(const std::string& callsign, const std::string& s) @@ -229,18 +229,18 @@ void IRCDDBApp::kickWatchdog(const std::string& callsign, const std::string& s) std::lock_guard lockModuleWD(d->m_moduleWDMutex); d->m_moduleWD[cs] = cs + std::string(" ") + text; - d->wdTimer = 60; + d->m_wdTimer = 60; } } int IRCDDBApp::getConnectionState() { - return d->state; + return d->m_state; } IRCDDB_RESPONSE_TYPE IRCDDBApp::getReplyMessageType() { - IRCMessage *m = d->replyQ.peekFirst(); + IRCMessage *m = d->m_replyQ.peekFirst(); if (m == NULL) return IDRT_NONE; @@ -262,7 +262,7 @@ IRCDDB_RESPONSE_TYPE IRCDDBApp::getReplyMessageType() IRCMessage *IRCDDBApp::getReplyMessage() { - return d->replyQ.getMessage(); + return d->m_replyQ.getMessage(); } void IRCDDBApp::startWork() @@ -319,7 +319,7 @@ void IRCDDBApp::userJoin(const std::string& nick, const std::string& name, const IRCMessage *m2 = new IRCMessage("IDRT_GATEWAY"); m2->addParam(gatewayCallsign); m2->addParam(host); - d->replyQ.putMessage(m2); + d->m_replyQ.putMessage(m2); } } } @@ -345,8 +345,8 @@ void IRCDDBApp::userLeave(const std::string& nick) if (0 == d->m_currentServer.compare(lnick)) { // m_currentServer = null; - d->state = 2; // choose new server - d->timer = 200; + d->m_state = 2; // choose new server + d->m_timer = 200; d->m_initReady = false; } } @@ -469,7 +469,7 @@ bool IRCDDBApp::findGateway(const std::string& gwCall) IRCMessage *m2 = new IRCMessage("IDRT_GATEWAY"); m2->addParam(gwCall); m2->addParam(getIPAddress(s)); - d->replyQ.putMessage(m2); + d->m_replyQ.putMessage(m2); return true; } @@ -504,7 +504,7 @@ static void findReflector(const std::string& rptrCall, IRCDDBAppPrivate *d) m2->addParam(rptrCall); m2->addParam(zonerp_cs); m2->addParam(ipAddr); - d->replyQ.putMessage(m2); + d->m_replyQ.putMessage(m2); } bool IRCDDBApp::findRepeater(const std::string& rptrCall) @@ -534,7 +534,7 @@ bool IRCDDBApp::findRepeater(const std::string& rptrCall) m2->addParam(rptrCall); m2->addParam(zonerp_cs); m2->addParam(getIPAddress(s)); - d->replyQ.putMessage(m2); + d->m_replyQ.putMessage(m2); return true; } @@ -543,7 +543,7 @@ void IRCDDBApp::sendDStarGatewayInfo(const std::string &subcommand, const std::v { IRCMessageQueue *q = getSendQ(); std::string srv(d->m_currentServer); - if (srv.size() && d->state>=6 && q) { + if (srv.size() && d->m_state>=6 && q) { std::string command("DStarGateway "); command.append(subcommand); for (auto it=pars.begin(); it!=pars.end(); it++) { @@ -585,7 +585,7 @@ bool IRCDDBApp::sendHeard(const std::string& myCall, const std::string& myCallEx std::string srv(d->m_currentServer); IRCMessageQueue *q = getSendQ(); - if (srv.size() && d->state>=6 && q) { + if (srv.size() && d->m_state>=6 && q) { std::string cmd("UPDATE "); cmd += CUtils::getCurrentTime(); @@ -619,7 +619,7 @@ bool IRCDDBApp::findUser(const std::string& usrCall) std::string srv(d->m_currentServer); IRCMessageQueue *q = getSendQ(); - if (srv.size()>0 && d->state>=6 && q) { + if (srv.size()>0 && d->m_state>=6 && q) { std::string usr(usrCall); CUtils::ReplaceChar(usr, ' ', '_'); IRCMessage * m =new IRCMessage(srv, std::string("FIND ") + usr); @@ -629,7 +629,7 @@ bool IRCDDBApp::findUser(const std::string& usrCall) m2->addParam(usrCall); for (int i=0; i<4; i++) m2->addParam(std::string("")); - d->replyQ.putMessage(m2); + d->m_replyQ.putMessage(m2); } return true; } @@ -744,7 +744,7 @@ void IRCDDBApp::doUpdate(std::string& msg) m2->addParam(arearp_cs); m2->addParam(zonerp_cs); m2->addParam(getIPAddress(value)); - d->replyQ.putMessage(m2); + d->m_replyQ.putMessage(m2); } } else if (0==tableID && d->m_initReady) { std::lock_guard lockRptrMap(d->m_rptrMapMutex); @@ -770,7 +770,7 @@ void IRCDDBApp::doUpdate(std::string& msg) m2->addParam(zonerp_cs); m2->addParam(ip_addr); m2->addParam(tk + std::string(" ") + timeToken); - d->replyQ.putMessage(m2); + d->m_replyQ.putMessage(m2); } } } @@ -812,11 +812,11 @@ void IRCDDBApp::msgQuery(IRCMessage *m) } doUpdate(restOfLine); } else if (0 == cmd.compare("LIST_END")) { - if (5 == d->state) // if in sendlist processing state - d->state = 3; // get next table + if (5 == d->m_state) // if in sendlist processing state + d->m_state = 3; // get next table } else if (0 == cmd.compare("LIST_MORE")) { - if (5 == d->state) // if in sendlist processing state - d->state = 4; // send next SENDLIST + if (5 == d->m_state) // if in sendlist processing state + d->m_state = 4; // send next SENDLIST } else if (0 == cmd.compare("NOT_FOUND")) { std::string callsign; std::string restOfLine; @@ -834,7 +834,7 @@ void IRCDDBApp::msgQuery(IRCMessage *m) m2->addParam(callsign); for (int i=0; i<4; i++) m2->addParam(std::string("")); - d->replyQ.putMessage(m2); + d->m_replyQ.putMessage(m2); } } } @@ -842,12 +842,12 @@ void IRCDDBApp::msgQuery(IRCMessage *m) void IRCDDBApp::setSendQ(IRCMessageQueue *s) { - d->sendQ = s; + d->m_sendQ = s; } IRCMessageQueue *IRCDDBApp::getSendQ() { - return d->sendQ; + return d->m_sendQ; } std::string IRCDDBApp::getLastEntryTime(int tableID) @@ -871,29 +871,29 @@ void IRCDDBApp::Entry() { int sendlistTableID = 0; while (!d->m_terminateThread) { - if (d->timer > 0) - d->timer--; - switch(d->state) { + if (d->m_timer > 0) + d->m_timer--; + switch(d->m_state) { case 0: // wait for network to start if (getSendQ()) - d->state = 1; + d->m_state = 1; break; case 1: // connect to db - d->state = 2; - d->timer = 200; + d->m_state = 2; + d->m_timer = 200; break; case 2: // choose server CLog::logInfo("IRCDDBApp: state=2 choose new 's-'-user\n"); if (NULL == getSendQ()) - d->state = 10; + d->m_state = 10; else { if (findServerUser()) { sendlistTableID = numberOfTables; - d->state = 3; // next: send "SENDLIST" - } else if (0 == d->timer) { - d->state = 10; + d->m_state = 3; // next: send "SENDLIST" + } else if (0 == d->m_timer) { + d->m_state = 10; IRCMessage *m = new IRCMessage("QUIT"); m->addParam("no op user with 's-' found."); IRCMessageQueue *q = getSendQ(); @@ -905,39 +905,39 @@ void IRCDDBApp::Entry() case 3: if (NULL == getSendQ()) - d->state = 10; // disconnect DB + d->m_state = 10; // disconnect DB else { sendlistTableID--; if (sendlistTableID < 0) - d->state = 6; // end of sendlist + d->m_state = 6; // end of sendlist else { CLog::logInfo("IRCDDBApp: state=3 tableID=%d\n", sendlistTableID); - d->state = 4; // send "SENDLIST" - d->timer = 900; // 15 minutes max for update + d->m_state = 4; // send "SENDLIST" + d->m_timer = 900; // 15 minutes max for update } } break; case 4: if (NULL == getSendQ()) - d->state = 10; // disconnect DB + d->m_state = 10; // disconnect DB else { if (needsDatabaseUpdate(sendlistTableID)) { IRCMessage *m = new IRCMessage(d->m_currentServer, std::string("SENDLIST") + getTableIDString(sendlistTableID, true) + std::string(" ") + getLastEntryTime(sendlistTableID)); IRCMessageQueue *q = getSendQ(); if (q) q->putMessage(m); - d->state = 5; // wait for answers + d->m_state = 5; // wait for answers } else - d->state = 3; // don't send SENDLIST for this table, go to next table + d->m_state = 3; // don't send SENDLIST for this table, go to next table } break; case 5: // sendlist processing if (NULL == getSendQ()) - d->state = 10; // disconnect DB - else if (0 == d->timer) { - d->state = 10; // disconnect DB + d->m_state = 10; // disconnect DB + else if (0 == d->m_timer) { + d->m_state = 10; // disconnect DB IRCMessage *m = new IRCMessage("QUIT"); m->addParam("timeout SENDLIST"); IRCMessageQueue *q = getSendQ(); @@ -948,23 +948,23 @@ void IRCDDBApp::Entry() case 6: if (NULL == getSendQ()) - d->state = 10; // disconnect DB + d->m_state = 10; // disconnect DB else { CLog::logInfo( "IRCDDBApp: state=6 initialization completed\n"); - d->infoTimer = 2; + d->m_infoTimer = 2; d->m_initReady = true; - d->state = 7; + d->m_state = 7; } break; case 7: // standby state after initialization if (NULL == getSendQ()) - d->state = 10; // disconnect DB + d->m_state = 10; // disconnect DB - if (d->infoTimer > 0) { - d->infoTimer--; + if (d->m_infoTimer > 0) { + d->m_infoTimer--; - if (0 == d->infoTimer) { + if (0 == d->m_infoTimer) { { // Scope for mutext locking std::lock_guard lochQTHURL(d->m_moduleQTHURLMutex); for (auto it = d->m_moduleQTH.begin(); it != d->m_moduleQTH.end(); ++it) { @@ -998,10 +998,10 @@ void IRCDDBApp::Entry() } } - if (d->wdTimer > 0) { - d->wdTimer--; + if (d->m_wdTimer > 0) { + d->m_wdTimer--; - if (0 == d->wdTimer) { + if (0 == d->m_wdTimer) { std::lock_guard lockModuleWD(d->m_moduleWDMutex); for (auto it = d->m_moduleWD.begin(); it != d->m_moduleWD.end(); ++it) { @@ -1018,8 +1018,8 @@ void IRCDDBApp::Entry() case 10: // disconnect db - d->state = 0; - d->timer = 0; + d->m_state = 0; + d->m_timer = 0; d->m_initReady = false; break; } diff --git a/IRCDDBClient.cpp b/IRCDDBClient.cpp index bf5130a..d4becd1 100644 --- a/IRCDDBClient.cpp +++ b/IRCDDBClient.cpp @@ -272,6 +272,7 @@ bool CIRCDDBClient::findUser(const std::string& userCallsign) CLog::logDebug("CIRCDDBClient::findUser:userCall='%s' len != 8\n", userCallsign.c_str()); return false; } + CLog::logTrace("IRC Find user %s", userCallsign.c_str()); std::string usr(userCallsign); CUtils::ToUpper(usr); return d->app->findUser(usr); @@ -398,6 +399,9 @@ bool CIRCDDBClient::receiveUser(std::string& userCallsign, std::string& repeater gatewayCallsign = m->getParam(2); address = m->getParam(3); timeStamp = m->getParam(4); + + CLog::logTrace("IRC Receive User %s %s %s %s %s", userCallsign.c_str(), repeaterCallsign.c_str(), gatewayCallsign.c_str(), address.c_str(), timeStamp.c_str()); + delete m; return true; } @@ -408,3 +412,7 @@ void CIRCDDBClient::close() // Implictely kills any threads in the IRC code d->app -> stopWork(); } + +void CIRCDDBClient::queryUsers() +{ +} diff --git a/IRCDDBClient.h b/IRCDDBClient.h index a41cfab..e33a3f0 100644 --- a/IRCDDBClient.h +++ b/IRCDDBClient.h @@ -130,6 +130,8 @@ public: void close(); // Implictely kills any threads in the IRC code + void queryUsers(); + private: struct CIRCDDBClientPrivate * const d; bool m_isQuadNet; diff --git a/IRCDDBMultiClient.cpp b/IRCDDBMultiClient.cpp index 7d76424..d4f2ead 100644 --- a/IRCDDBMultiClient.cpp +++ b/IRCDDBMultiClient.cpp @@ -244,7 +244,7 @@ IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType() } } - IRCDDB_RESPONSE_TYPE result = IDRT_NONE; + IRCDDB_RESPONSE_TYPE result = IDRT_NONE; m_responseQueueLock.lock(); if (m_responseQueue.size() != 0) result = m_responseQueue[0]->getType(); @@ -372,3 +372,7 @@ CIRCDDBMultiClientQuery_HashMap * CIRCDDBMultiClient::getQueriesHashMap(IRCDDB_R } +void CIRCDDBMultiClient::queryUsers() +{ + +} \ No newline at end of file diff --git a/IRCDDBMultiClient.h b/IRCDDBMultiClient.h index 172b529..44a18cd 100644 --- a/IRCDDBMultiClient.h +++ b/IRCDDBMultiClient.h @@ -157,6 +157,7 @@ public: virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address, std::string & timeStamp); virtual void sendDStarGatewayInfo(const std::string subcommand, const std::vector parms); virtual void close(); + virtual void queryUsers(); // From 0d0efba655aaba8d77323aa60c18e5d6998c4996 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 15 Jan 2022 17:33:17 +0100 Subject: [PATCH 128/201] #5 Reeanbale NatTraversal --- .vscode/settings.json | 15 ++++++++++++++- .vscode/tasks.json | 16 +++++++++------- DStarGatewayThread.cpp | 1 + G2Handler.cpp | 2 ++ G2ProtocolHandler.cpp | 32 ++++++++++++++++++++++---------- G2ProtocolHandler.h | 3 ++- IRCDDBApp.cpp | 2 ++ IRCDDBApp.h | 2 ++ IRCDDBClient.cpp | 2 +- NatTraversalHandler.cpp | 11 +++++------ NatTraversalHandler.h | 17 +++++++---------- 11 files changed, 67 insertions(+), 36 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index a509b7e..246b6b6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,7 +7,20 @@ } ], "files.associations": { - "new": "cpp" + "new": "cpp", + "exception": "cpp", + "*.tcc": "cpp", + "typeinfo": "cpp", + "limits": "cpp", + "tuple": "cpp", + "bitset": "cpp", + "fstream": "cpp", + "istream": "cpp", + "mutex": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stop_token": "cpp", + "streambuf": "cpp" }, "editor.tokenColorCustomizations": { "textMateRules": [ diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 8b078ce..41425c5 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -8,9 +8,13 @@ "type": "shell", "command": "make", "args": [ - "-j3", "ENABLE_DEBUG=1" + "-j3", + "ENABLE_DEBUG=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] }, { @@ -19,12 +23,10 @@ "command": "make", "args": [ "-j3", - "tests", "ENABLE_DEBUG=1" + "tests", + "ENABLE_DEBUG=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] } ] diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index 23aa7a2..550e19f 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -733,6 +733,7 @@ void CDStarGatewayThread::processIrcDDB() m_statusTimer2.start(); } + // Process incoming ircDDB messages, updating the caches for (;;) { IRCDDB_RESPONSE_TYPE type = m_irc->getMessageType(); diff --git a/G2Handler.cpp b/G2Handler.cpp index a767d42..8cbede5 100644 --- a/G2Handler.cpp +++ b/G2Handler.cpp @@ -206,3 +206,5 @@ bool CG2Handler::clockInt(unsigned int ms) return false; } + + diff --git a/G2ProtocolHandler.cpp b/G2ProtocolHandler.cpp index 8047c89..df3fa0e 100644 --- a/G2ProtocolHandler.cpp +++ b/G2ProtocolHandler.cpp @@ -41,7 +41,7 @@ m_port(0U) CG2ProtocolHandler::~CG2ProtocolHandler() { delete[] m_buffer; - portmap.clear(); + m_portmap.clear(); } bool CG2ProtocolHandler::open() @@ -59,8 +59,8 @@ bool CG2ProtocolHandler::writeHeader(const CHeaderData& header) #endif in_addr addr = header.getYourAddress(); - auto found = portmap.find(addr.s_addr); - unsigned int port = (portmap.end()==found) ? header.getYourPort() : found->second; + auto found = m_portmap.find(addr.s_addr); + unsigned int port = (m_portmap.end()==found) ? header.getYourPort() : found->second; for (unsigned int i = 0U; i < 5U; i++) { bool res = m_socket.write(buffer, length, addr, port); @@ -81,8 +81,8 @@ bool CG2ProtocolHandler::writeAMBE(const CAMBEData& data) #endif in_addr addr = data.getYourAddress(); - auto found = portmap.find(addr.s_addr); - unsigned int port = (portmap.end()==found) ? data.getYourPort() : found->second; + auto found = m_portmap.find(addr.s_addr); + unsigned int port = (m_portmap.end()==found) ? data.getYourPort() : found->second; return m_socket.write(buffer, length, addr, port); } @@ -110,13 +110,13 @@ bool CG2ProtocolHandler::readPackets() m_length = length; // 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); - portmap[m_address.s_addr] = m_port; + m_portmap[m_address.s_addr] = m_port; } else { - if (portmap[m_address.s_addr] != m_port) { - CLog::logInfo("new port for %s is %u, was %u\n", inet_ntoa(m_address), m_port, portmap[m_address.s_addr]); - portmap[m_address.s_addr] = m_port; + if (m_portmap[m_address.s_addr] != m_port) { + CLog::logInfo("new port for %s is %u, was %u\n", inet_ntoa(m_address), m_port, m_portmap[m_address.s_addr]); + m_portmap[m_address.s_addr] = m_port; } } @@ -170,3 +170,15 @@ void CG2ProtocolHandler::close() { m_socket.close(); } + +void CG2ProtocolHandler::traverseNat(const std::string& address) +{ + unsigned char buffer[1]; + ::memset(buffer, 0, 1); + + in_addr addr = CUDPReaderWriter::lookup(address); + + //wxLogError(wxT("Punching hole to %s"), address.mb_str()); + + m_socket.write(buffer, 1, addr, G2_DV_PORT); +} \ No newline at end of file diff --git a/G2ProtocolHandler.h b/G2ProtocolHandler.h index b2c8502..14eb0b3 100644 --- a/G2ProtocolHandler.h +++ b/G2ProtocolHandler.h @@ -47,9 +47,10 @@ public: CAMBEData* readAMBE(); void close(); + void traverseNat(const std::string& address); private: - std::unordered_map portmap; + std::unordered_map m_portmap; CUDPReaderWriter m_socket; G2_TYPE m_type; diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index d03b786..bd4a51a 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -634,6 +634,8 @@ bool IRCDDBApp::findUser(const std::string& usrCall) return true; } + + void IRCDDBApp::msgChannel(IRCMessage *m) { if (0==m->getPrefixNick().compare(0, 2, "s-") && m->numParams>=2) // server msg diff --git a/IRCDDBApp.h b/IRCDDBApp.h index 2039a58..7c2575a 100644 --- a/IRCDDBApp.h +++ b/IRCDDBApp.h @@ -67,6 +67,8 @@ public: bool findRepeater(const std::string& s); bool findGateway(const std::string& s); + bool notifyRepeaterNatTraversal(const std::string& repeater); + 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); diff --git a/IRCDDBClient.cpp b/IRCDDBClient.cpp index d4becd1..433c0b4 100644 --- a/IRCDDBClient.cpp +++ b/IRCDDBClient.cpp @@ -400,7 +400,7 @@ bool CIRCDDBClient::receiveUser(std::string& userCallsign, std::string& repeater address = m->getParam(3); timeStamp = m->getParam(4); - CLog::logTrace("IRC Receive User %s %s %s %s %s", userCallsign.c_str(), repeaterCallsign.c_str(), gatewayCallsign.c_str(), address.c_str(), timeStamp.c_str()); + //CLog::logTrace("IRC Receive User %s %s %s %s %s", userCallsign.c_str(), repeaterCallsign.c_str(), gatewayCallsign.c_str(), address.c_str(), timeStamp.c_str()); delete m; return true; diff --git a/NatTraversalHandler.cpp b/NatTraversalHandler.cpp index 8ee9ac0..9357c1b 100644 --- a/NatTraversalHandler.cpp +++ b/NatTraversalHandler.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2010,2011,2012,2013,2014,2015,2016,2017,2018 by Jonathan Naylor G4KLX + * 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 @@ -16,8 +17,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(ENABLE_NAT_TRAVERSAL) - #include "NatTraversalHandler.h" const unsigned int CACHE_SIZE = 500U; @@ -31,8 +30,10 @@ m_g2Handler(NULL) CNatTraversalHandler::~CNatTraversalHandler() { - for (CNatTraversalCache_t::iterator it = m_g2cache.begin(); it != m_g2cache.end(); ++it) + for (auto it = m_g2cache.begin(); it != m_g2cache.end(); ++it) delete it->second; + + m_g2cache.clear(); } void CNatTraversalHandler::setG2Handler(CG2ProtocolHandler * handler) @@ -40,7 +41,7 @@ void CNatTraversalHandler::setG2Handler(CG2ProtocolHandler * handler) m_g2Handler = handler; } -void CNatTraversalHandler::traverseNatG2(const wxString& address) +void CNatTraversalHandler::traverseNatG2(const std::string& address) { if(m_g2Handler != NULL){ CNatTraversalRecord* record = m_g2cache[address]; @@ -57,5 +58,3 @@ void CNatTraversalHandler::traverseNatG2(const wxString& address) } } } - -#endif \ No newline at end of file diff --git a/NatTraversalHandler.h b/NatTraversalHandler.h index 0069fea..4d56851 100644 --- a/NatTraversalHandler.h +++ b/NatTraversalHandler.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2010,2011,2012,2013,2014,2015,2016,2017,2018 by Jonathan Naylor G4KLX + * 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 @@ -16,7 +17,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#if defined(ENABLE_NAT_TRAVERSAL) #ifndef NatTraversalHandler_H #define NatTraversalHandler_H @@ -24,7 +24,8 @@ #include "G2ProtocolHandler.h" -#include +#include +#include #include enum NAT_TRAVERSAL_TYPE { @@ -36,7 +37,7 @@ enum NAT_TRAVERSAL_TYPE { class CNatTraversalRecord { public: - CNatTraversalRecord(const wxString& address) : + CNatTraversalRecord(const std::string& address) : m_address(address), m_timestamp(0) { @@ -53,12 +54,10 @@ public: } private: - wxString m_address; + std::string m_address; std::time_t m_timestamp; }; -WX_DECLARE_STRING_HASH_MAP(CNatTraversalRecord*, CNatTraversalCache_t); - /* * This keeps track of when we UDP punched to one destination so to avoid unnecessary traffic on each ircddb reporting */ @@ -68,13 +67,11 @@ public: ~CNatTraversalHandler(); void setG2Handler(CG2ProtocolHandler* handler); - void traverseNatG2(const wxString& address); + void traverseNatG2(const std::string& address); private: - CNatTraversalCache_t m_g2cache; + std::unordered_map m_g2cache; CG2ProtocolHandler* m_g2Handler; }; #endif - -#endif \ No newline at end of file From 58e2e74c5b6587b20e66b851982ef4a8338acf0e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 15 Jan 2022 17:44:42 +0100 Subject: [PATCH 129/201] #9 fix unsupported frames trigerring tx --- .vscode/tasks.json | 10 +++++----- APRSUnit.cpp | 9 +++++++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index ac3f100..168ca95 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,7 +12,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] }, { @@ -25,10 +28,7 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] } ] diff --git a/APRSUnit.cpp b/APRSUnit.cpp index 3fe066b..ad8f9e1 100644 --- a/APRSUnit.cpp +++ b/APRSUnit.cpp @@ -51,13 +51,17 @@ void CAPRSUnit::clock(unsigned int ms) { m_timer.clock(ms); if(m_status == APS_IDLE && !m_frameBuffer.empty() && m_timer.hasExpired()) { - m_status = APS_TRANSMIT; + auto frame = m_frameBuffer.front(); m_frameBuffer.pop_front(); m_headerData = new CHeaderData(); std::string dprs, text; - CAPRSToDPRS::aprsToDPRS(dprs, text, *m_headerData, *frame); + if(!CAPRSToDPRS::aprsToDPRS(dprs, text, *m_headerData, *frame)) { + delete m_headerData; + m_headerData = nullptr; + return; + } m_slowData = new CSlowDataEncoder(); @@ -73,6 +77,7 @@ void CAPRSUnit::clock(unsigned int ms) m_seq = 0U; m_start = std::chrono::high_resolution_clock::now(); + m_status = APS_TRANSMIT; return; } From 47b7ec54ab60815db124b480d2d2d671b0c58eda Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 15 Jan 2022 21:02:49 +0100 Subject: [PATCH 130/201] #5 implement message for G2 NATT --- .vscode/settings.json | 3 +- DStarGatewayThread.cpp | 3 +- IRCDDB.h | 8 +- IRCDDBApp.cpp | 345 +++++++++++++++++++++++------------------ IRCDDBApp.h | 2 +- IRCDDBClient.cpp | 98 ++++++++---- IRCDDBClient.h | 9 +- IRCDDBMultiClient.cpp | 16 +- IRCDDBMultiClient.h | 2 +- RepeaterHandler.cpp | 3 +- 10 files changed, 287 insertions(+), 202 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 246b6b6..0597c44 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,7 +20,8 @@ "ostream": "cpp", "sstream": "cpp", "stop_token": "cpp", - "streambuf": "cpp" + "streambuf": "cpp", + "chrono": "cpp" }, "editor.tokenColorCustomizations": { "textMateRules": [ diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index 550e19f..442439d 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -795,7 +795,8 @@ void CDStarGatewayThread::processIrcDDB() } } break; - + case IDRT_NATTRAVERSAL_G2: + break; default: return; } diff --git a/IRCDDB.h b/IRCDDB.h index 72e8c9a..d55538d 100644 --- a/IRCDDB.h +++ b/IRCDDB.h @@ -31,7 +31,8 @@ enum IRCDDB_RESPONSE_TYPE { IDRT_NONE, IDRT_USER, IDRT_GATEWAY, - IDRT_REPEATER + IDRT_REPEATER, + IDRT_NATTRAVERSAL_G2 }; @@ -111,6 +112,9 @@ public: // Send query for a user, a false return implies a network error virtual bool findUser(const std::string& userCallsign) = 0; + + // notify another repeater for NAT Traversal, a false return implies a network error + virtual bool notifyRepeaterNatTraversal(const std::string& repeater) = 0; // Support for the Smart Group Server virtual void sendDStarGatewayInfo(const std::string subcommand, const std::vector parms) = 0; @@ -135,8 +139,6 @@ public: virtual bool receiveUser(std::string& userCallsign, std::string& repeaterCallsign, std::string& gatewayCallsign, std::string& address, std::string& timeStamp) = 0; virtual void close() = 0; // Implictely kills any threads in the IRC code - - virtual void queryUsers() = 0; }; typedef std::vector CIRCDDB_Array; diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index bd4a51a..cb9eacb 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -27,6 +27,7 @@ along with this program. If not, see . #include #include #include +#include #include "IRCDDBApp.h" #include "Utils.h" @@ -129,27 +130,27 @@ public: }; IRCDDBApp::IRCDDBApp(const std::string& u_chan) - : d(new IRCDDBAppPrivate) + : m_d(new IRCDDBAppPrivate) , m_maxTime((time_t)950000000) //februray 2000 { - d->m_sendQ = NULL; - d->m_initReady = false; + m_d->m_sendQ = NULL; + m_d->m_initReady = false; userListReset(); - d->m_state = 0; - d->m_timer = 0; - d->m_myNick = std::string("none"); + m_d->m_state = 0; + m_d->m_timer = 0; + m_d->m_myNick = std::string("none"); - d->m_updateChannel = u_chan; + m_d->m_updateChannel = u_chan; - d->m_terminateThread = false; + m_d->m_terminateThread = false; } IRCDDBApp::~IRCDDBApp() { - delete d->m_sendQ; - delete d; + delete m_d->m_sendQ; + delete m_d; } void IRCDDBApp::rptrQTH(const std::string& callsign, double latitude, double longitude, const std::string& desc1, const std::string& desc2, const std::string& infoURL) @@ -177,11 +178,11 @@ void IRCDDBApp::rptrQTH(const std::string& callsign, double latitude, double lon CUtils::ReplaceChar(d2, ' ', '_'); CUtils::ReplaceChar(cs, ' ', '_'); - std::lock_guard lochQTHURL(d->m_moduleQTHURLMutex); + std::lock_guard lochQTHURL(m_d->m_moduleQTHURLMutex); - d->m_moduleQTH[cs] = cs + std::string(" ") + pos + std::string(" ") + d1 + std::string(" ") + d2; + m_d->m_moduleQTH[cs] = cs + std::string(" ") + pos + std::string(" ") + d1 + std::string(" ") + d2; - CLog::logInfo("QTH: %s\n", d->m_moduleQTH[cs].c_str()); + CLog::logInfo("QTH: %s\n", m_d->m_moduleQTH[cs].c_str()); std::string url = infoURL; @@ -190,11 +191,11 @@ void IRCDDBApp::rptrQTH(const std::string& callsign, double latitude, double lon url.erase(sm.position(0), sm.length()); if (url.size()) { - d->m_moduleURL[cs] = cs + std::string(" ") + url; - CLog::logInfo("URL: %s\n", d->m_moduleURL[cs].c_str()); + m_d->m_moduleURL[cs] = cs + std::string(" ") + url; + CLog::logInfo("URL: %s\n", m_d->m_moduleURL[cs].c_str()); } - d->m_infoTimer = 5; // send info in 5 seconds + m_d->m_infoTimer = 5; // send info in 5 seconds } void IRCDDBApp::rptrQRG(const std::string& callsign, double txFrequency, double duplexShift, double range, double agl) @@ -207,11 +208,11 @@ void IRCDDBApp::rptrQRG(const std::string& callsign, double txFrequency, double std::string f(fstr); CUtils::ReplaceChar(f, ',', '.'); - std::lock_guard lockModuleQRG(d->m_moduleQRGMutex); - d->m_moduleQRG[cs] = cs + std::string(" ") + f; - CLog::logInfo("QRG: %s\n", d->m_moduleQRG[cs].c_str()); + std::lock_guard lockModuleQRG(m_d->m_moduleQRGMutex); + m_d->m_moduleQRG[cs] = cs + std::string(" ") + f; + CLog::logInfo("QRG: %s\n", m_d->m_moduleQRG[cs].c_str()); - d->m_infoTimer = 5; // send info in 5 seconds + m_d->m_infoTimer = 5; // send info in 5 seconds } void IRCDDBApp::kickWatchdog(const std::string& callsign, const std::string& s) @@ -227,20 +228,20 @@ void IRCDDBApp::kickWatchdog(const std::string& callsign, const std::string& s) std::string cs = callsign; CUtils::ReplaceChar(cs, ' ', '_'); - std::lock_guard lockModuleWD(d->m_moduleWDMutex); - d->m_moduleWD[cs] = cs + std::string(" ") + text; - d->m_wdTimer = 60; + std::lock_guard lockModuleWD(m_d->m_moduleWDMutex); + m_d->m_moduleWD[cs] = cs + std::string(" ") + text; + m_d->m_wdTimer = 60; } } int IRCDDBApp::getConnectionState() { - return d->m_state; + return m_d->m_state; } IRCDDB_RESPONSE_TYPE IRCDDBApp::getReplyMessageType() { - IRCMessage *m = d->m_replyQ.peekFirst(); + IRCMessage *m = m_d->m_replyQ.peekFirst(); if (m == NULL) return IDRT_NONE; @@ -255,6 +256,9 @@ IRCDDB_RESPONSE_TYPE IRCDDBApp::getReplyMessageType() if (0 == msgType.compare("IDRT_GATEWAY")) return IDRT_GATEWAY; + if(msgType.compare("NATTRAVERSAL_G2") == 0) + return IDRT_NATTRAVERSAL_G2; + CLog::logWarning("IRCDDBApp::getMessageType: unknown msg type: %s\n", msgType.c_str()); return IDRT_NONE; @@ -262,18 +266,18 @@ IRCDDB_RESPONSE_TYPE IRCDDBApp::getReplyMessageType() IRCMessage *IRCDDBApp::getReplyMessage() { - return d->m_replyQ.getMessage(); + return m_d->m_replyQ.getMessage(); } void IRCDDBApp::startWork() { - d->m_terminateThread = false; + m_d->m_terminateThread = false; m_future = std::async(std::launch::async, &IRCDDBApp::Entry, this); } void IRCDDBApp::stopWork() { - d->m_terminateThread = true; + m_d->m_terminateThread = true; m_future.get(); } @@ -286,8 +290,8 @@ unsigned int IRCDDBApp::calculateUsn(const std::string& nick) for (int i = 1; i <= 4; i++) { std::string ircUser = lnick + std::to_string(i); - if (d->m_userMap.count(ircUser) == 1) { - IRCDDBAppUserObject obj = d->m_userMap[ircUser]; + if (m_d->m_userMap.count(ircUser) == 1) { + IRCDDBAppUserObject obj = m_d->m_userMap[ircUser]; if (obj.m_usn > maxUsn) maxUsn = obj.m_usn; } @@ -297,7 +301,7 @@ unsigned int IRCDDBApp::calculateUsn(const std::string& nick) void IRCDDBApp::userJoin(const std::string& nick, const std::string& name, const std::string& host) { - std::lock_guard lockUserMap(d->m_userMapMutex); + std::lock_guard lockUserMap(m_d->m_userMapMutex); std::string lnick = nick; CUtils::ToLower(lnick); @@ -305,9 +309,9 @@ void IRCDDBApp::userJoin(const std::string& nick, const std::string& name, const IRCDDBAppUserObject u(lnick, name, host); u.m_usn = calculateUsn(lnick); - d->m_userMap[lnick] = u; + m_d->m_userMap[lnick] = u; - if (d->m_initReady) { + if (m_d->m_initReady) { std::string::size_type hyphenPos = nick.find('-'); if ((hyphenPos >= 4) && (hyphenPos <= 6)) { @@ -319,7 +323,7 @@ void IRCDDBApp::userJoin(const std::string& nick, const std::string& name, const IRCMessage *m2 = new IRCMessage("IDRT_GATEWAY"); m2->addParam(gatewayCallsign); m2->addParam(host); - d->m_replyQ.putMessage(m2); + m_d->m_replyQ.putMessage(m2); } } } @@ -329,25 +333,25 @@ void IRCDDBApp::userLeave(const std::string& nick) std::string lnick = nick; CUtils::ToLower(lnick); - std::lock_guard lockUserMap(d->m_userMapMutex); - d->m_userMap.erase(lnick); + std::lock_guard lockUserMap(m_d->m_userMapMutex); + m_d->m_userMap.erase(lnick); - if (d->m_currentServer.size()) { - if (d->m_userMap.count(d->m_myNick) != 1) { + if (m_d->m_currentServer.size()) { + if (m_d->m_userMap.count(m_d->m_myNick) != 1) { CLog::logInfo("IRCDDBApp::userLeave: could not find own nick\n"); return; } - IRCDDBAppUserObject me = d->m_userMap[d->m_myNick]; + IRCDDBAppUserObject me = m_d->m_userMap[m_d->m_myNick]; if (me.m_op == false) { // if I am not op, then look for new server - if (0 == d->m_currentServer.compare(lnick)) { + if (0 == m_d->m_currentServer.compare(lnick)) { // m_currentServer = null; - d->m_state = 2; // choose new server - d->m_timer = 200; - d->m_initReady = false; + m_d->m_state = 2; // choose new server + m_d->m_timer = 200; + m_d->m_initReady = false; } } } @@ -355,39 +359,39 @@ void IRCDDBApp::userLeave(const std::string& nick) void IRCDDBApp::userListReset() { - std::lock_guard lockUserMap(d->m_userMapMutex); - d->m_userMap.clear(); + std::lock_guard lockUserMap(m_d->m_userMapMutex); + m_d->m_userMap.clear(); } void IRCDDBApp::setCurrentNick(const std::string& nick) { - d->m_myNick = nick; + m_d->m_myNick = nick; CLog::logInfo("IRCDDBApp::setCurrentNick %s\n", nick.c_str()); } void IRCDDBApp::setBestServer(const std::string& ircUser) { - d->m_bestServer = ircUser; + m_d->m_bestServer = ircUser; CLog::logInfo("IRCDDBApp::setBestServer %s\n", ircUser.c_str()); } void IRCDDBApp::setTopic(const std::string& topic) { - d->m_channelTopic = topic; + m_d->m_channelTopic = topic; } bool IRCDDBApp::findServerUser() { bool found = false; - std::lock_guard lockUserMap(d->m_userMapMutex); + std::lock_guard lockUserMap(m_d->m_userMapMutex); std::map::iterator it; - for (it = d->m_userMap.begin(); it != d->m_userMap.end(); ++it) { + for (it = m_d->m_userMap.begin(); it != m_d->m_userMap.end(); ++it) { IRCDDBAppUserObject u = it->second; - if (0==u.m_nick.compare(0, 2, "s-") && u.m_op && d->m_myNick.compare(u.m_nick) && 0==u.m_nick.compare(d->m_bestServer)) { - d->m_currentServer = u.m_nick; + if (0==u.m_nick.compare(0, 2, "s-") && u.m_op && m_d->m_myNick.compare(u.m_nick) && 0==u.m_nick.compare(m_d->m_bestServer)) { + m_d->m_currentServer = u.m_nick; found = true; break; } @@ -397,12 +401,12 @@ bool IRCDDBApp::findServerUser() return true; } - if (8 == d->m_bestServer.size()) { - for (it = d->m_userMap.begin(); it != d->m_userMap.end(); ++it) { + if (8 == m_d->m_bestServer.size()) { + for (it = m_d->m_userMap.begin(); it != m_d->m_userMap.end(); ++it) { IRCDDBAppUserObject u = it->second; - if (0==u.m_nick.compare(d->m_bestServer.substr(0,7)) && u.m_op && d->m_myNick.compare(u.m_nick) ) { - d->m_currentServer = u.m_nick; + if (0==u.m_nick.compare(m_d->m_bestServer.substr(0,7)) && u.m_op && m_d->m_myNick.compare(u.m_nick) ) { + m_d->m_currentServer = u.m_nick; found = true; break; } @@ -413,10 +417,10 @@ bool IRCDDBApp::findServerUser() return true; } - for (it = d->m_userMap.begin(); it != d->m_userMap.end(); ++it) { + for (it = m_d->m_userMap.begin(); it != m_d->m_userMap.end(); ++it) { IRCDDBAppUserObject u = it->second; - if (0==u.m_nick.compare(0, 2, "s-") && u.m_op && d->m_myNick.compare(u.m_nick)) { - d->m_currentServer = u.m_nick; + if (0==u.m_nick.compare(0, 2, "s-") && u.m_op && m_d->m_myNick.compare(u.m_nick)) { + m_d->m_currentServer = u.m_nick; found = true; break; } @@ -426,13 +430,13 @@ bool IRCDDBApp::findServerUser() void IRCDDBApp::userChanOp(const std::string& nick, bool op) { - std::lock_guard lockUserMap(d->m_userMapMutex); + std::lock_guard lockUserMap(m_d->m_userMapMutex); std::string lnick = nick; CUtils::ToLower(lnick); - if (d->m_userMap.count(lnick) == 1) - d->m_userMap[lnick].m_op = op; + if (m_d->m_userMap.count(lnick) == 1) + m_d->m_userMap[lnick].m_op = op; } static const int numberOfTables = 2; @@ -446,12 +450,12 @@ std::string IRCDDBApp::getIPAddress(std::string& zonerp_cs) CUtils::ToLower(gw); CUtils::Trim(gw); - std::lock_guard lockUserMap(d->m_userMapMutex); + std::lock_guard lockUserMap(m_d->m_userMapMutex); for (int j=1; j <= 4; j++) { std::string ircUser = gw + std::string("-") + std::to_string(j); - if (d->m_userMap.count(ircUser) == 1) { - IRCDDBAppUserObject o = d->m_userMap[ircUser]; + if (m_d->m_userMap.count(ircUser) == 1) { + IRCDDBAppUserObject o = m_d->m_userMap[ircUser]; if (o.m_usn >= max_usn) { max_usn = o.m_usn; @@ -469,7 +473,7 @@ bool IRCDDBApp::findGateway(const std::string& gwCall) IRCMessage *m2 = new IRCMessage("IDRT_GATEWAY"); m2->addParam(gwCall); m2->addParam(getIPAddress(s)); - d->m_replyQ.putMessage(m2); + m_d->m_replyQ.putMessage(m2); return true; } @@ -510,7 +514,7 @@ static void findReflector(const std::string& rptrCall, IRCDDBAppPrivate *d) bool IRCDDBApp::findRepeater(const std::string& rptrCall) { if (0==rptrCall.compare(0, 3, "XRF") || 0==rptrCall.compare(0, 3, "REF") || 0==rptrCall.compare(0, 3, "DCS") || 0==rptrCall.compare(0, 3, "XLX") ) { - findReflector(rptrCall, d); + findReflector(rptrCall, m_d); return true; } @@ -519,10 +523,10 @@ bool IRCDDBApp::findRepeater(const std::string& rptrCall) std::string s("NONE"); std::string zonerp_cs; - std::lock_guard lockRptrMap(d->m_rptrMapMutex); + std::lock_guard lockRptrMap(m_d->m_rptrMapMutex); - if (1 == d->m_rptrMap.count(arearp_cs)) { - IRCDDBAppRptrObject o = d->m_rptrMap[arearp_cs]; + if (1 == m_d->m_rptrMap.count(arearp_cs)) { + IRCDDBAppRptrObject o = m_d->m_rptrMap[arearp_cs]; zonerp_cs = o.m_zonerp_cs; CUtils::ReplaceChar(zonerp_cs, '_', ' '); zonerp_cs.resize(7, ' '); @@ -534,7 +538,7 @@ bool IRCDDBApp::findRepeater(const std::string& rptrCall) m2->addParam(rptrCall); m2->addParam(zonerp_cs); m2->addParam(getIPAddress(s)); - d->m_replyQ.putMessage(m2); + m_d->m_replyQ.putMessage(m2); return true; } @@ -542,8 +546,8 @@ bool IRCDDBApp::findRepeater(const std::string& rptrCall) void IRCDDBApp::sendDStarGatewayInfo(const std::string &subcommand, const std::vector &pars) { IRCMessageQueue *q = getSendQ(); - std::string srv(d->m_currentServer); - if (srv.size() && d->m_state>=6 && q) { + std::string srv(m_d->m_currentServer); + if (srv.size() && m_d->m_state>=6 && q) { std::string command("DStarGateway "); command.append(subcommand); for (auto it=pars.begin(); it!=pars.end(); it++) { @@ -582,10 +586,10 @@ bool IRCDDBApp::sendHeard(const std::string& myCall, const std::string& myCallEx bool statsMsg = (tx_stats.size() > 0); - std::string srv(d->m_currentServer); + std::string srv(m_d->m_currentServer); IRCMessageQueue *q = getSendQ(); - if (srv.size() && d->m_state>=6 && q) { + if (srv.size() && m_d->m_state>=6 && q) { std::string cmd("UPDATE "); cmd += CUtils::getCurrentTime(); @@ -616,10 +620,10 @@ bool IRCDDBApp::sendHeard(const std::string& myCall, const std::string& myCallEx bool IRCDDBApp::findUser(const std::string& usrCall) { - std::string srv(d->m_currentServer); + std::string srv(m_d->m_currentServer); IRCMessageQueue *q = getSendQ(); - if (srv.size()>0 && d->m_state>=6 && q) { + if (srv.size()>0 && m_d->m_state>=6 && q) { std::string usr(usrCall); CUtils::ReplaceChar(usr, ' ', '_'); IRCMessage * m =new IRCMessage(srv, std::string("FIND ") + usr); @@ -629,12 +633,40 @@ bool IRCDDBApp::findUser(const std::string& usrCall) m2->addParam(usrCall); for (int i=0; i<4; i++) m2->addParam(std::string("")); - d->m_replyQ.putMessage(m2); + m_d->m_replyQ.putMessage(m2); } return true; } +bool IRCDDBApp::notifyRepeaterNatTraversal(const std::string& repeater) +{ + auto firstSpacePos = repeater.find_first_of(' '); + if(firstSpacePos == std::string::npos) + return true; + + auto lrepeater = repeater.substr(0, firstSpacePos); + CUtils::ToLower(lrepeater); + std::string nick; + + std::lock_guard loclUserMap(m_d->m_userMapMutex); + for(unsigned int i = 1; i <= 4U; i++) { + nick = lrepeater + "-" + std::to_string(i); + if(m_d->m_userMap.count(nick) == 1) { + break; + } + nick.clear(); + } + if(nick.empty()) { + CLog::logDebug("Unable to dind IRC nick for repeater %s", repeater.c_str()); + return true; + } + + IRCMessage * ircMessage = new IRCMessage(nick, "NATTRAVERSAL_G2"); + m_d->m_sendQ->putMessage(ircMessage); + + return true; +} void IRCDDBApp::msgChannel(IRCMessage *m) { @@ -653,7 +685,7 @@ void IRCDDBApp::doNotFound(std::string& msg, std::string& retval) std::string tk = tkz.front(); tkz.erase(tkz.begin()); - if (std::regex_match(tk, d->m_tablePattern)) { + if (std::regex_match(tk, m_d->m_tablePattern)) { tableID = std::stoi(tk); if (tableID<0 || tableID>=numberOfTables) { @@ -669,7 +701,7 @@ void IRCDDBApp::doNotFound(std::string& msg, std::string& retval) } if (0 == tableID) { - if (! std::regex_match(tk, d->m_dbPattern)) + if (! std::regex_match(tk, m_d->m_dbPattern)) return; // no valid key retval = tk; } @@ -685,7 +717,7 @@ void IRCDDBApp::doUpdate(std::string& msg) std::string tk = tkz.front(); tkz.erase(tkz.begin()); - if (std::regex_match(tk, d->m_tablePattern)) { + if (std::regex_match(tk, m_d->m_tablePattern)) { tableID = std::stoi(tk); if ((tableID < 0) || (tableID >= numberOfTables)) { CLog::logInfo("invalid table ID %d\n", tableID); @@ -699,13 +731,13 @@ void IRCDDBApp::doUpdate(std::string& msg) tkz.erase(tkz.begin()); } - if (std::regex_match(tk, d->m_datePattern)) { + if (std::regex_match(tk, m_d->m_datePattern)) { if (tkz.empty()) return; // nothing after date string std::string timeToken = tkz.front(); // time token tkz.erase(tkz.begin()); - if (! std::regex_match(timeToken, d->m_timePattern)) + if (! std::regex_match(timeToken, m_d->m_timePattern)) return; // no time string after date string time_t dt = CUtils::parseTime(tk + std::string(" ") + timeToken); @@ -717,7 +749,7 @@ void IRCDDBApp::doUpdate(std::string& msg) std::string key = tkz.front(); tkz.erase(tkz.begin()); - if (! std::regex_match(key, d->m_dbPattern)) + if (! std::regex_match(key, m_d->m_dbPattern)) return; // no valid key if (tkz.empty()) @@ -726,15 +758,15 @@ void IRCDDBApp::doUpdate(std::string& msg) std::string value = tkz.front(); tkz.erase(tkz.begin()); - if (! std::regex_match(value, d->m_dbPattern)) + if (! std::regex_match(value, m_d->m_dbPattern)) return; // no valid key if (tableID == 1) { - std::lock_guard lockRptrMap(d->m_rptrMapMutex); + std::lock_guard lockRptrMap(m_d->m_rptrMapMutex); IRCDDBAppRptrObject newRptr(dt, key, value, m_maxTime); - d->m_rptrMap[key] = newRptr; + m_d->m_rptrMap[key] = newRptr; - if (d->m_initReady) { + if (m_d->m_initReady) { std::string arearp_cs(key); std::string zonerp_cs(value); CUtils::ReplaceChar(arearp_cs, '_', ' '); @@ -746,10 +778,10 @@ void IRCDDBApp::doUpdate(std::string& msg) m2->addParam(arearp_cs); m2->addParam(zonerp_cs); m2->addParam(getIPAddress(value)); - d->m_replyQ.putMessage(m2); + m_d->m_replyQ.putMessage(m2); } - } else if (0==tableID && d->m_initReady) { - std::lock_guard lockRptrMap(d->m_rptrMapMutex); + } else if (0==tableID && m_d->m_initReady) { + std::lock_guard lockRptrMap(m_d->m_rptrMapMutex); std::string userCallsign(key); std::string arearp_cs(value); std::string zonerp_cs; @@ -757,8 +789,8 @@ void IRCDDBApp::doUpdate(std::string& msg) CUtils::ReplaceChar(userCallsign, '_', ' '); CUtils::ReplaceChar(arearp_cs, '_', ' '); - if (1 == d->m_rptrMap.count(value)) { - IRCDDBAppRptrObject o = d->m_rptrMap[value]; + if (1 == m_d->m_rptrMap.count(value)) { + IRCDDBAppRptrObject o = m_d->m_rptrMap[value]; zonerp_cs = o.m_zonerp_cs; CUtils::ReplaceChar(zonerp_cs, '_', ' '); zonerp_cs.resize(7, ' '); @@ -772,7 +804,7 @@ void IRCDDBApp::doUpdate(std::string& msg) m2->addParam(zonerp_cs); m2->addParam(ip_addr); m2->addParam(tk + std::string(" ") + timeToken); - d->m_replyQ.putMessage(m2); + m_d->m_replyQ.putMessage(m2); } } } @@ -794,7 +826,7 @@ static std::string getTableIDString(int tableID, bool spaceBeforeNumber) void IRCDDBApp::msgQuery(IRCMessage *m) { - if (0==m->getPrefixNick().compare(0, 2, "s-") && m->numParams>=2) { // server msg + if (0 == m->getPrefixNick().compare(0, 2, "s-") && m->numParams >=2 ) { // server msg std::string msg(m->m_params[1]); std::vector tkz = CUtils::stringTokenizer(msg); @@ -814,11 +846,11 @@ void IRCDDBApp::msgQuery(IRCMessage *m) } doUpdate(restOfLine); } else if (0 == cmd.compare("LIST_END")) { - if (5 == d->m_state) // if in sendlist processing state - d->m_state = 3; // get next table + if (5 == m_d->m_state) // if in sendlist processing state + m_d->m_state = 3; // get next table } else if (0 == cmd.compare("LIST_MORE")) { - if (5 == d->m_state) // if in sendlist processing state - d->m_state = 4; // send next SENDLIST + if (5 == m_d->m_state) // if in sendlist processing state + m_d->m_state = 4; // send next SENDLIST } else if (0 == cmd.compare("NOT_FOUND")) { std::string callsign; std::string restOfLine; @@ -836,20 +868,27 @@ void IRCDDBApp::msgQuery(IRCMessage *m) m2->addParam(callsign); for (int i=0; i<4; i++) m2->addParam(std::string("")); - d->m_replyQ.putMessage(m2); + m_d->m_replyQ.putMessage(m2); } } } + else if(m->m_params[0] == m_d->m_myNick) { + if(boost::starts_with(m->m_params[1], "NATTRAVERSAL_")) { + IRCMessage * m2 = new IRCMessage(m->m_params[1]); + m2->addParam(m->getPrefixHost()); + m_d->m_replyQ.putMessage(m2); + } + } } void IRCDDBApp::setSendQ(IRCMessageQueue *s) { - d->m_sendQ = s; + m_d->m_sendQ = s; } IRCMessageQueue *IRCDDBApp::getSendQ() { - return d->m_sendQ; + return m_d->m_sendQ; } std::string IRCDDBApp::getLastEntryTime(int tableID) @@ -872,30 +911,30 @@ static bool needsDatabaseUpdate(int tableID) void IRCDDBApp::Entry() { int sendlistTableID = 0; - while (!d->m_terminateThread) { - if (d->m_timer > 0) - d->m_timer--; - switch(d->m_state) { + while (!m_d->m_terminateThread) { + if (m_d->m_timer > 0) + m_d->m_timer--; + switch(m_d->m_state) { case 0: // wait for network to start if (getSendQ()) - d->m_state = 1; + m_d->m_state = 1; break; case 1: // connect to db - d->m_state = 2; - d->m_timer = 200; + m_d->m_state = 2; + m_d->m_timer = 200; break; case 2: // choose server CLog::logInfo("IRCDDBApp: state=2 choose new 's-'-user\n"); if (NULL == getSendQ()) - d->m_state = 10; + m_d->m_state = 10; else { if (findServerUser()) { sendlistTableID = numberOfTables; - d->m_state = 3; // next: send "SENDLIST" - } else if (0 == d->m_timer) { - d->m_state = 10; + m_d->m_state = 3; // next: send "SENDLIST" + } else if (0 == m_d->m_timer) { + m_d->m_state = 10; IRCMessage *m = new IRCMessage("QUIT"); m->addParam("no op user with 's-' found."); IRCMessageQueue *q = getSendQ(); @@ -907,39 +946,39 @@ void IRCDDBApp::Entry() case 3: if (NULL == getSendQ()) - d->m_state = 10; // disconnect DB + m_d->m_state = 10; // disconnect DB else { sendlistTableID--; if (sendlistTableID < 0) - d->m_state = 6; // end of sendlist + m_d->m_state = 6; // end of sendlist else { CLog::logInfo("IRCDDBApp: state=3 tableID=%d\n", sendlistTableID); - d->m_state = 4; // send "SENDLIST" - d->m_timer = 900; // 15 minutes max for update + m_d->m_state = 4; // send "SENDLIST" + m_d->m_timer = 900; // 15 minutes max for update } } break; case 4: if (NULL == getSendQ()) - d->m_state = 10; // disconnect DB + m_d->m_state = 10; // disconnect DB else { if (needsDatabaseUpdate(sendlistTableID)) { - IRCMessage *m = new IRCMessage(d->m_currentServer, std::string("SENDLIST") + getTableIDString(sendlistTableID, true) + std::string(" ") + getLastEntryTime(sendlistTableID)); + IRCMessage *m = new IRCMessage(m_d->m_currentServer, std::string("SENDLIST") + getTableIDString(sendlistTableID, true) + std::string(" ") + getLastEntryTime(sendlistTableID)); IRCMessageQueue *q = getSendQ(); if (q) q->putMessage(m); - d->m_state = 5; // wait for answers + m_d->m_state = 5; // wait for answers } else - d->m_state = 3; // don't send SENDLIST for this table, go to next table + m_d->m_state = 3; // don't send SENDLIST for this table, go to next table } break; case 5: // sendlist processing if (NULL == getSendQ()) - d->m_state = 10; // disconnect DB - else if (0 == d->m_timer) { - d->m_state = 10; // disconnect DB + m_d->m_state = 10; // disconnect DB + else if (0 == m_d->m_timer) { + m_d->m_state = 10; // disconnect DB IRCMessage *m = new IRCMessage("QUIT"); m->addParam("timeout SENDLIST"); IRCMessageQueue *q = getSendQ(); @@ -950,79 +989,79 @@ void IRCDDBApp::Entry() case 6: if (NULL == getSendQ()) - d->m_state = 10; // disconnect DB + m_d->m_state = 10; // disconnect DB else { CLog::logInfo( "IRCDDBApp: state=6 initialization completed\n"); - d->m_infoTimer = 2; - d->m_initReady = true; - d->m_state = 7; + m_d->m_infoTimer = 2; + m_d->m_initReady = true; + m_d->m_state = 7; } break; case 7: // standby state after initialization if (NULL == getSendQ()) - d->m_state = 10; // disconnect DB + m_d->m_state = 10; // disconnect DB - if (d->m_infoTimer > 0) { - d->m_infoTimer--; + if (m_d->m_infoTimer > 0) { + m_d->m_infoTimer--; - if (0 == d->m_infoTimer) { + if (0 == m_d->m_infoTimer) { { // Scope for mutext locking - std::lock_guard lochQTHURL(d->m_moduleQTHURLMutex); - for (auto it = d->m_moduleQTH.begin(); it != d->m_moduleQTH.end(); ++it) { + std::lock_guard lochQTHURL(m_d->m_moduleQTHURLMutex); + for (auto it = m_d->m_moduleQTH.begin(); it != m_d->m_moduleQTH.end(); ++it) { std::string value = it->second; - IRCMessage *m = new IRCMessage(d->m_currentServer, std::string("IRCDDB RPTRQTH: ") + value); + IRCMessage *m = new IRCMessage(m_d->m_currentServer, std::string("IRCDDB RPTRQTH: ") + value); IRCMessageQueue *q = getSendQ(); if (q != NULL) q->putMessage(m); } - d->m_moduleQTH.clear(); + m_d->m_moduleQTH.clear(); - for (auto it = d->m_moduleURL.begin(); it != d->m_moduleURL.end(); ++it) { + for (auto it = m_d->m_moduleURL.begin(); it != m_d->m_moduleURL.end(); ++it) { std::string value = it->second; - IRCMessage *m = new IRCMessage(d->m_currentServer, std::string("IRCDDB RPTRURL: ") + value); + IRCMessage *m = new IRCMessage(m_d->m_currentServer, std::string("IRCDDB RPTRURL: ") + value); IRCMessageQueue *q = getSendQ(); if (q != NULL) q->putMessage(m); } - d->m_moduleURL.clear(); + m_d->m_moduleURL.clear(); } - std::lock_guard lockModuleQRG(d->m_moduleQRGMutex); - for (auto it = d->m_moduleQRG.begin(); it != d->m_moduleQRG.end(); ++it) { + std::lock_guard lockModuleQRG(m_d->m_moduleQRGMutex); + for (auto it = m_d->m_moduleQRG.begin(); it != m_d->m_moduleQRG.end(); ++it) { std::string value = it->second; - IRCMessage* m = new IRCMessage(d->m_currentServer, std::string("IRCDDB RPTRQRG: ") + value); + IRCMessage* m = new IRCMessage(m_d->m_currentServer, std::string("IRCDDB RPTRQRG: ") + value); IRCMessageQueue* q = getSendQ(); if (q != NULL) q->putMessage(m); } - d->m_moduleQRG.clear(); + m_d->m_moduleQRG.clear(); } } - if (d->m_wdTimer > 0) { - d->m_wdTimer--; + if (m_d->m_wdTimer > 0) { + m_d->m_wdTimer--; - if (0 == d->m_wdTimer) { - std::lock_guard lockModuleWD(d->m_moduleWDMutex); + if (0 == m_d->m_wdTimer) { + std::lock_guard lockModuleWD(m_d->m_moduleWDMutex); - for (auto it = d->m_moduleWD.begin(); it != d->m_moduleWD.end(); ++it) { + for (auto it = m_d->m_moduleWD.begin(); it != m_d->m_moduleWD.end(); ++it) { std::string value = it->second; - IRCMessage *m = new IRCMessage(d->m_currentServer, std::string("IRCDDB RPTRSW: ") + value); + IRCMessage *m = new IRCMessage(m_d->m_currentServer, std::string("IRCDDB RPTRSW: ") + value); IRCMessageQueue *q = getSendQ(); if (q) q->putMessage(m); } - d->m_moduleWD.clear(); + m_d->m_moduleWD.clear(); } } break; case 10: // disconnect db - d->m_state = 0; - d->m_timer = 0; - d->m_initReady = false; + m_d->m_state = 0; + m_d->m_timer = 0; + m_d->m_initReady = false; break; } std::this_thread::sleep_for(std::chrono::seconds(1)); diff --git a/IRCDDBApp.h b/IRCDDBApp.h index 7c2575a..8a3066d 100644 --- a/IRCDDBApp.h +++ b/IRCDDBApp.h @@ -92,7 +92,7 @@ private: bool findServerUser(); unsigned int calculateUsn(const std::string& nick); std::string getLastEntryTime(int tableID); - IRCDDBAppPrivate *d; + IRCDDBAppPrivate *m_d; time_t m_maxTime; std::future m_future; }; diff --git a/IRCDDBClient.cpp b/IRCDDBClient.cpp index 433c0b4..e95f4b4 100644 --- a/IRCDDBClient.cpp +++ b/IRCDDBClient.cpp @@ -28,23 +28,23 @@ along with this program. If not, see . struct CIRCDDBClientPrivate { IRCClient *client; - IRCDDBApp *app; + IRCDDBApp *m_app; }; CIRCDDBClient::CIRCDDBClient(const std::string& hostName, unsigned int port, const std::string& callsign, const std::string& password, const std::string& versionInfo, const std::string& localAddr, bool isQuadNet ) : -d(new CIRCDDBClientPrivate), +m_d(new CIRCDDBClientPrivate), m_isQuadNet(isQuadNet) { std::string update_channel("#dstar"); - d->app = new IRCDDBApp(update_channel); - d->client = new IRCClient(d->app, update_channel, hostName, port, callsign, password, versionInfo, localAddr); + m_d->m_app = new IRCDDBApp(update_channel); + m_d->client = new IRCClient(m_d->m_app, update_channel, hostName, port, callsign, password, versionInfo, localAddr); } CIRCDDBClient::~CIRCDDBClient() { - delete d->client; - delete d->app; - delete d; + delete m_d->client; + delete m_d->m_app; + delete m_d; } @@ -52,33 +52,33 @@ CIRCDDBClient::~CIRCDDBClient() bool CIRCDDBClient::open() { CLog::logInfo("start client and app\n"); - d->client->startWork(); - d->app->startWork(); + m_d->client->startWork(); + m_d->m_app->startWork(); return true; } int CIRCDDBClient::getConnectionState() { - return d->app->getConnectionState(); + return m_d->m_app->getConnectionState(); } void CIRCDDBClient::rptrQTH(const std::string& callsign, double latitude, double longitude, const std::string& desc1, const std::string& desc2, const std::string& infoURL) { - d->app->rptrQTH(callsign, latitude, longitude, desc1, desc2, infoURL); + m_d->m_app->rptrQTH(callsign, latitude, longitude, desc1, desc2, infoURL); } void CIRCDDBClient::rptrQRG(const std::string& callsign, double txFrequency, double duplexShift, double range, double agl) { - d->app->rptrQRG(callsign, txFrequency, duplexShift, range, agl); + m_d->m_app->rptrQRG(callsign, txFrequency, duplexShift, range, agl); } void CIRCDDBClient::kickWatchdog(const std::string& callsign, const std::string& wdInfo) { - d->app->kickWatchdog(callsign, wdInfo); + m_d->m_app->kickWatchdog(callsign, wdInfo); } @@ -112,7 +112,7 @@ bool CIRCDDBClient::sendHeard( const std::string& myCall, const std::string& myC return false; } - return d->app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, std::string(" "), std::string(""), std::string("")); + return m_d->m_app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, std::string(" "), std::string(""), std::string("")); } void CIRCDDBClient::sendDStarGatewayInfo(const std::string subcommand, const std::vector parms) @@ -123,7 +123,7 @@ void CIRCDDBClient::sendDStarGatewayInfo(const std::string subcommand, const std CLog::logInfo("\n"); if(m_isQuadNet) { - d->app->sendDStarGatewayInfo(subcommand, parms); + m_d->m_app->sendDStarGatewayInfo(subcommand, parms); } } @@ -175,7 +175,7 @@ bool CIRCDDBClient::sendHeardWithTXMsg(const std::string& myCall, const std::str msg.push_back('_'); } } - return d->app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, dest, msg, std::string("")); + return m_d->m_app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, dest, msg, std::string("")); } @@ -238,7 +238,7 @@ bool CIRCDDBClient::sendHeardWithTXStats( const std::string& myCall, const std:: } stats.resize(20, '_'); - return d->app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, std::string(" "), std::string(""), stats); + return m_d->m_app->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, std::string(" "), std::string(""), stats); } // Send query for a gateway/reflector, a false return implies a network error @@ -250,7 +250,7 @@ bool CIRCDDBClient::findGateway(const std::string& gatewayCallsign) } std::string gw(gatewayCallsign); CUtils::ToUpper(gw); - return d->app->findGateway(gw); + return m_d->m_app->findGateway(gw); } @@ -262,7 +262,7 @@ bool CIRCDDBClient::findRepeater(const std::string& repeaterCallsign) } std::string rptr(repeaterCallsign); CUtils::ToUpper(rptr); - return d->app->findRepeater(rptr); + return m_d->m_app->findRepeater(rptr); } // Send query for a user, a false return implies a network error @@ -275,7 +275,12 @@ bool CIRCDDBClient::findUser(const std::string& userCallsign) CLog::logTrace("IRC Find user %s", userCallsign.c_str()); std::string usr(userCallsign); CUtils::ToUpper(usr); - return d->app->findUser(usr); + return m_d->m_app->findUser(usr); +} + +bool CIRCDDBClient::notifyRepeaterNatTraversal(const std::string& repeater) +{ + return m_d->m_app->notifyRepeaterNatTraversal(repeater); } // The following functions are for processing received messages @@ -283,21 +288,21 @@ bool CIRCDDBClient::findUser(const std::string& userCallsign) // Get the waiting message type IRCDDB_RESPONSE_TYPE CIRCDDBClient::getMessageType() { - return d->app->getReplyMessageType(); + return m_d->m_app->getReplyMessageType(); } // Get a gateway message, as a result of IDRT_REPEATER returned from getMessageType() // A false return implies a network error bool CIRCDDBClient::receiveRepeater(std::string& repeaterCallsign, std::string& gatewayCallsign, std::string& address) { - IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType(); + IRCDDB_RESPONSE_TYPE rt = m_d->m_app->getReplyMessageType(); if (rt != IDRT_REPEATER) { CLog::logDebug("CIRCDDBClient::receiveRepeater: unexpected response type=%d\n", rt); return false; } - IRCMessage *m = d->app->getReplyMessage(); + IRCMessage *m = m_d->m_app->getReplyMessage(); if (m == NULL) { CLog::logDebug("CIRCDDBClient::receiveRepeater: no message\n"); return false; @@ -326,14 +331,14 @@ bool CIRCDDBClient::receiveRepeater(std::string& repeaterCallsign, std::string& // A false return implies a network error bool CIRCDDBClient::receiveGateway(std::string& gatewayCallsign, std::string& address) { - IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType(); + IRCDDB_RESPONSE_TYPE rt = m_d->m_app->getReplyMessageType(); if (rt != IDRT_GATEWAY) { CLog::logDebug("CIRCDDBClient::receiveGateway: unexpected response type=%d\n", rt); return false; } - IRCMessage *m = d->app->getReplyMessage(); + IRCMessage *m = m_d->m_app->getReplyMessage(); if (m == NULL) { CLog::logDebug("CIRCDDBClient::receiveGateway: no message\n"); @@ -368,14 +373,14 @@ bool CIRCDDBClient::receiveUser(std::string& userCallsign, std::string& repeater bool CIRCDDBClient::receiveUser(std::string& userCallsign, std::string& repeaterCallsign, std::string& gatewayCallsign, std::string& address, std::string& timeStamp) { - IRCDDB_RESPONSE_TYPE rt = d->app->getReplyMessageType(); + IRCDDB_RESPONSE_TYPE rt = m_d->m_app->getReplyMessageType(); if (rt != IDRT_USER) { CLog::logDebug("CIRCDDBClient::receiveUser: unexpected response type=%d\n", rt); return false; } - IRCMessage * m = d->app->getReplyMessage(); + IRCMessage * m = m_d->m_app->getReplyMessage(); if (m == NULL) { CLog::logDebug("CIRCDDBClient::receiveUser: no message\n"); @@ -406,13 +411,42 @@ bool CIRCDDBClient::receiveUser(std::string& userCallsign, std::string& repeater return true; } -void CIRCDDBClient::close() // Implictely kills any threads in the IRC code +bool CIRCDDBClient::receiveNATTraversalG2(std::string& address) { - d->client -> stopWork(); - d->app -> stopWork(); -} + IRCDDB_RESPONSE_TYPE rt = m_d->m_app->getReplyMessageType(); + + if(rt != IDRT_NATTRAVERSAL_G2) { + CLog::logDebug("CIRCDDBClient::receiveNATTraversalG2: unexpected response type=%d\n", rt); + return false; + } + IRCMessage * m = m_d->m_app->getReplyMessage(); -void CIRCDDBClient::queryUsers() + if (m == NULL) { + CLog::logDebug("CIRCDDBClient::receiveUser: 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; +} + +void CIRCDDBClient::close() // Implictely kills any threads in the IRC code { + m_d->client -> stopWork(); + m_d->m_app -> stopWork(); } diff --git a/IRCDDBClient.h b/IRCDDBClient.h index e33a3f0..7160b66 100644 --- a/IRCDDBClient.h +++ b/IRCDDBClient.h @@ -106,6 +106,9 @@ public: // Send query for a user, a false return implies a network error bool findUser(const std::string& userCallsign); + // notify another repeater for NAT Traversal, a false return implies a network error + bool notifyRepeaterNatTraversal(const std::string& repeater); + // Support for the Smart Group Server void sendDStarGatewayInfo(const std::string subcommand, const std::vector parms); @@ -128,12 +131,12 @@ public: bool receiveUser(std::string& userCallsign, std::string& repeaterCallsign, std::string& gatewayCallsign, std::string& address, std::string& timeStamp); - void close(); // Implictely kills any threads in the IRC code + bool receiveNATTraversalG2(std::string& address); - void queryUsers(); + void close(); // Implictely kills any threads in the IRC code private: - struct CIRCDDBClientPrivate * const d; + struct CIRCDDBClientPrivate * const m_d; bool m_isQuadNet; }; diff --git a/IRCDDBMultiClient.cpp b/IRCDDBMultiClient.cpp index d4f2ead..5c13b77 100644 --- a/IRCDDBMultiClient.cpp +++ b/IRCDDBMultiClient.cpp @@ -181,6 +181,16 @@ bool CIRCDDBMultiClient::findUser(const std::string & userCallsign) return result; } +bool CIRCDDBMultiClient::notifyRepeaterNatTraversal(const std::string& repeater) +{ + bool result = true; + for (unsigned int i = 0; i < m_clients.size(); i++) { + result = m_clients[i]->notifyRepeaterNatTraversal(repeater) && result; + } + + return result; +} + IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType() { //procees the inner clients at each call @@ -370,9 +380,3 @@ CIRCDDBMultiClientQuery_HashMap * CIRCDDBMultiClient::getQueriesHashMap(IRCDDB_R return NULL; } } - - -void CIRCDDBMultiClient::queryUsers() -{ - -} \ No newline at end of file diff --git a/IRCDDBMultiClient.h b/IRCDDBMultiClient.h index 44a18cd..f9fcbb7 100644 --- a/IRCDDBMultiClient.h +++ b/IRCDDBMultiClient.h @@ -150,6 +150,7 @@ public: virtual bool findGateway(const std::string & gatewayCallsign); virtual bool findRepeater(const std::string & repeaterCallsign); virtual bool findUser(const std::string & userCallsign); + virtual bool notifyRepeaterNatTraversal(const std::string& repeater); virtual IRCDDB_RESPONSE_TYPE getMessageType(); virtual bool receiveRepeater(std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address); virtual bool receiveGateway(std::string & gatewayCallsign, std::string & address); @@ -157,7 +158,6 @@ public: virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address, std::string & timeStamp); virtual void sendDStarGatewayInfo(const std::string subcommand, const std::vector parms); virtual void close(); - virtual void queryUsers(); // diff --git a/RepeaterHandler.cpp b/RepeaterHandler.cpp index 13635b3..2529eaf 100644 --- a/RepeaterHandler.cpp +++ b/RepeaterHandler.cpp @@ -2022,7 +2022,7 @@ void CRepeaterHandler::g2CommandHandler(const std::string& callsign, const std:: if (m_linkStatus == LS_LINKING_CCS || m_linkStatus == LS_LINKED_CCS) return; - if (callsign.substr(0,1) == "/") { + if (!callsign.empty() && callsign[0] == '/') { if (m_irc == NULL) { CLog::logInfo("%s is trying to G2 route with ircDDB disabled", user.c_str()); m_g2Status = G2_LOCAL; @@ -2053,6 +2053,7 @@ void CRepeaterHandler::g2CommandHandler(const std::string& callsign, const std:: m_g2User = "CQCQCQ "; CRepeaterData* data = m_cache->findRepeater(m_g2Repeater); + m_irc->notifyRepeaterNatTraversal(m_g2Repeater); if (data == NULL) { m_g2Status = G2_REPEATER; From 7d50a078b1b535d0051d17c6e4d231749d009940 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 15 Jan 2022 22:09:07 +0100 Subject: [PATCH 131/201] #5 Handle G2 Nat traversal --- DStarGatewayThread.cpp | 25 +++++++++++-------------- DStarGatewayThread.h | 4 ---- G2ProtocolHandler.cpp | 4 ++-- IRCDDB.h | 2 ++ IRCDDBMultiClient.cpp | 17 +++++++++++++++++ IRCDDBMultiClient.h | 1 + 6 files changed, 33 insertions(+), 20 deletions(-) diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index 9cd87b6..9641d85 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -76,9 +76,7 @@ m_dextraPool(NULL), m_dplusPool(NULL), m_dcsPool(NULL), m_g2Handler(NULL), -#if defined(ENABLE_NAT_TRAVERSAL) m_natTraversal(NULL), -#endif m_aprsWriter(NULL), m_irc(NULL), m_cache(), @@ -209,12 +207,10 @@ void* CDStarGatewayThread::Entry() m_g2Handler = NULL; } -#if defined(ENABLE_NAT_TRAVERSAL) if(m_g2Handler != NULL) { m_natTraversal = new CNatTraversalHandler(); m_natTraversal->setG2Handler(m_g2Handler); } -#endif // Wait here until we have the essentials to run while (!m_killed && (m_dextraPool == NULL || m_dplusPool == NULL || m_dcsPool == NULL || m_g2Handler == NULL || (m_icomRepeaterHandler == NULL && m_hbRepeaterHandler == NULL && m_dummyRepeaterHandler == NULL) || m_gatewayCallsign.empty())) @@ -748,9 +744,6 @@ void CDStarGatewayThread::processIrcDDB() if (!address.empty()) { CLog::logDebug("USER: %s %s %s %s", user.c_str(), repeater.c_str(), gateway.c_str(), address.c_str()); m_cache.updateUser(user, repeater, gateway, address, timestamp, DP_DEXTRA, false, false); -#if defined(ENABLE_NAT_TRAVERSAL) - m_natTraversal->traverseNatG2(address); -#endif } else { CLog::logDebug("USER: %s NOT FOUND", user.c_str()); } @@ -767,9 +760,6 @@ void CDStarGatewayThread::processIrcDDB() if (!address.empty()) { CLog::logDebug("REPEATER: %s %s %s", repeater.c_str(), gateway.c_str(), address.c_str()); m_cache.updateRepeater(repeater, gateway, address, DP_DEXTRA, false, false); -#if defined(ENABLE_NAT_TRAVERSAL) - m_natTraversal->traverseNatG2(address); -#endif } else { CLog::logDebug("REPEATER: %s NOT FOUND", repeater.c_str()); } @@ -787,16 +777,23 @@ void CDStarGatewayThread::processIrcDDB() if (!address.empty()) { CLog::logDebug("GATEWAY: %s %s", gateway.c_str(), address.c_str()); m_cache.updateGateway(gateway, address, DP_DEXTRA, false, false); -#if defined(ENABLE_NAT_TRAVERSAL) - m_natTraversal->traverseNatG2(address); -#endif } else { CLog::logDebug("GATEWAY: %s NOT FOUND", gateway.c_str()); } } break; - case IDRT_NATTRAVERSAL_G2: + case IDRT_NATTRAVERSAL_G2: { + std::string address; + bool res = m_irc->receiveNATTraversalG2(address); + if(!res) + return; + + CLog::logInfo("%s wants to G2 route to us, punching UDP Holes through NAT", address.c_str()); + m_g2Handler->traverseNat(address); + } break; + case IDRT_NONE: + return; default: return; } diff --git a/DStarGatewayThread.h b/DStarGatewayThread.h index 5203a68..e6830c1 100644 --- a/DStarGatewayThread.h +++ b/DStarGatewayThread.h @@ -37,9 +37,7 @@ #include "Timer.h" #include "Defs.h" #include "Thread.h" -#if defined(ENABLE_NAT_TRAVERSAL) #include "NatTraversalHandler.h" -#endif class CDStarGatewayThread : public CThread{ public: @@ -106,9 +104,7 @@ private: CDPlusProtocolHandlerPool* m_dplusPool; CDCSProtocolHandlerPool* m_dcsPool; CG2ProtocolHandler* m_g2Handler; -#if defined(ENABLE_NAT_TRAVERSAL) CNatTraversalHandler* m_natTraversal; -#endif CAPRSHandler* m_aprsWriter; CIRCDDB* m_irc; CCacheManager m_cache; diff --git a/G2ProtocolHandler.cpp b/G2ProtocolHandler.cpp index df3fa0e..d6cfd86 100644 --- a/G2ProtocolHandler.cpp +++ b/G2ProtocolHandler.cpp @@ -178,7 +178,7 @@ void CG2ProtocolHandler::traverseNat(const std::string& address) in_addr addr = CUDPReaderWriter::lookup(address); - //wxLogError(wxT("Punching hole to %s"), address.mb_str()); + CLog::logInfo("Punching hole to %s", address.c_str()); m_socket.write(buffer, 1, addr, G2_DV_PORT); -} \ No newline at end of file +} diff --git a/IRCDDB.h b/IRCDDB.h index d55538d..e1f8186 100644 --- a/IRCDDB.h +++ b/IRCDDB.h @@ -138,6 +138,8 @@ public: virtual bool receiveUser(std::string& userCallsign, std::string& repeaterCallsign, std::string& gatewayCallsign, std::string& address, std::string& timeStamp) = 0; + virtual bool receiveNATTraversalG2(std::string& address) = 0; + virtual void close() = 0; // Implictely kills any threads in the IRC code }; diff --git a/IRCDDBMultiClient.cpp b/IRCDDBMultiClient.cpp index 5c13b77..49259de 100644 --- a/IRCDDBMultiClient.cpp +++ b/IRCDDBMultiClient.cpp @@ -183,6 +183,7 @@ bool CIRCDDBMultiClient::findUser(const std::string & userCallsign) bool CIRCDDBMultiClient::notifyRepeaterNatTraversal(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]->notifyRepeaterNatTraversal(repeater) && result; @@ -191,6 +192,17 @@ bool CIRCDDBMultiClient::notifyRepeaterNatTraversal(const std::string& repeater) 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; +} + IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType() { //procees the inner clients at each call @@ -218,6 +230,11 @@ IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType() key = repeater; break; } + case IDRT_NATTRAVERSAL_G2: { + if (!m_clients[i]->receiveNATTraversalG2(address)) + type = IDRT_NATTRAVERSAL_G2; + key = "NAT_TRAVERSAL_G2"; + } case IDRT_NONE: { default: break; diff --git a/IRCDDBMultiClient.h b/IRCDDBMultiClient.h index f9fcbb7..18c913f 100644 --- a/IRCDDBMultiClient.h +++ b/IRCDDBMultiClient.h @@ -156,6 +156,7 @@ public: virtual bool receiveGateway(std::string & gatewayCallsign, std::string & address); virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address); virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address, std::string & timeStamp); + virtual bool receiveNATTraversalG2(std::string& address); virtual void sendDStarGatewayInfo(const std::string subcommand, const std::vector parms); virtual void close(); From baf0642cccbb03fa33432bff593b3377bd0c70ed Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 15 Jan 2022 22:35:03 +0100 Subject: [PATCH 132/201] #5 remove portmap --- G2ProtocolHandler.cpp | 32 ++++++++++++++++---------------- G2ProtocolHandler.h | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/G2ProtocolHandler.cpp b/G2ProtocolHandler.cpp index d6cfd86..2e3aca2 100644 --- a/G2ProtocolHandler.cpp +++ b/G2ProtocolHandler.cpp @@ -41,7 +41,7 @@ m_port(0U) CG2ProtocolHandler::~CG2ProtocolHandler() { delete[] m_buffer; - m_portmap.clear(); + // m_portmap.clear(); } bool CG2ProtocolHandler::open() @@ -59,11 +59,11 @@ bool CG2ProtocolHandler::writeHeader(const CHeaderData& header) #endif in_addr addr = header.getYourAddress(); - auto found = m_portmap.find(addr.s_addr); - unsigned int port = (m_portmap.end()==found) ? header.getYourPort() : found->second; + // auto found = m_portmap.find(addr.s_addr); + // unsigned int port = (m_portmap.end()==found) ? header.getYourPort() : found->second; for (unsigned int i = 0U; i < 5U; i++) { - bool res = m_socket.write(buffer, length, addr, port); + bool res = m_socket.write(buffer, length, addr, m_port); if (!res) return false; } @@ -81,10 +81,10 @@ bool CG2ProtocolHandler::writeAMBE(const CAMBEData& data) #endif in_addr addr = data.getYourAddress(); - auto found = m_portmap.find(addr.s_addr); - unsigned int port = (m_portmap.end()==found) ? data.getYourPort() : found->second; + // auto found = m_portmap.find(addr.s_addr); + // unsigned int port = (m_portmap.end()==found) ? data.getYourPort() : found->second; - return m_socket.write(buffer, length, addr, port); + return m_socket.write(buffer, length, addr, m_port); } G2_TYPE CG2ProtocolHandler::read() @@ -110,15 +110,15 @@ bool CG2ProtocolHandler::readPackets() m_length = length; // save the incoming port (this is to enable mobile hotspots) - 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); - m_portmap[m_address.s_addr] = m_port; - } else { - 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, m_portmap[m_address.s_addr]); - m_portmap[m_address.s_addr] = m_port; - } - } + // 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); + // m_portmap[m_address.s_addr] = m_port; + // } else { + // 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, m_portmap[m_address.s_addr]); + // m_portmap[m_address.s_addr] = m_port; + // } + // } if (m_buffer[0] != 'D' || m_buffer[1] != 'S' || m_buffer[2] != 'V' || m_buffer[3] != 'T') { return true; diff --git a/G2ProtocolHandler.h b/G2ProtocolHandler.h index 14eb0b3..82c58f1 100644 --- a/G2ProtocolHandler.h +++ b/G2ProtocolHandler.h @@ -50,7 +50,7 @@ public: void traverseNat(const std::string& address); private: - std::unordered_map m_portmap; + // std::unordered_map m_portmap; CUDPReaderWriter m_socket; G2_TYPE m_type; From ab3b1aa55bd1bf69c55d45a8402912acf2e06952 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 15 Jan 2022 22:50:20 +0100 Subject: [PATCH 133/201] Revert "#5 remove portmap" This reverts commit baf0642cccbb03fa33432bff593b3377bd0c70ed. --- G2ProtocolHandler.cpp | 32 ++++++++++++++++---------------- G2ProtocolHandler.h | 2 +- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/G2ProtocolHandler.cpp b/G2ProtocolHandler.cpp index 2e3aca2..d6cfd86 100644 --- a/G2ProtocolHandler.cpp +++ b/G2ProtocolHandler.cpp @@ -41,7 +41,7 @@ m_port(0U) CG2ProtocolHandler::~CG2ProtocolHandler() { delete[] m_buffer; - // m_portmap.clear(); + m_portmap.clear(); } bool CG2ProtocolHandler::open() @@ -59,11 +59,11 @@ bool CG2ProtocolHandler::writeHeader(const CHeaderData& header) #endif in_addr addr = header.getYourAddress(); - // auto found = m_portmap.find(addr.s_addr); - // unsigned int port = (m_portmap.end()==found) ? header.getYourPort() : found->second; + auto found = m_portmap.find(addr.s_addr); + unsigned int port = (m_portmap.end()==found) ? header.getYourPort() : found->second; for (unsigned int i = 0U; i < 5U; i++) { - bool res = m_socket.write(buffer, length, addr, m_port); + bool res = m_socket.write(buffer, length, addr, port); if (!res) return false; } @@ -81,10 +81,10 @@ bool CG2ProtocolHandler::writeAMBE(const CAMBEData& data) #endif in_addr addr = data.getYourAddress(); - // auto found = m_portmap.find(addr.s_addr); - // unsigned int port = (m_portmap.end()==found) ? data.getYourPort() : found->second; + auto found = m_portmap.find(addr.s_addr); + unsigned int port = (m_portmap.end()==found) ? data.getYourPort() : found->second; - return m_socket.write(buffer, length, addr, m_port); + return m_socket.write(buffer, length, addr, port); } G2_TYPE CG2ProtocolHandler::read() @@ -110,15 +110,15 @@ bool CG2ProtocolHandler::readPackets() m_length = length; // save the incoming port (this is to enable mobile hotspots) - // 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); - // m_portmap[m_address.s_addr] = m_port; - // } else { - // 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, m_portmap[m_address.s_addr]); - // m_portmap[m_address.s_addr] = m_port; - // } - // } + 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); + m_portmap[m_address.s_addr] = m_port; + } else { + 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, m_portmap[m_address.s_addr]); + m_portmap[m_address.s_addr] = m_port; + } + } if (m_buffer[0] != 'D' || m_buffer[1] != 'S' || m_buffer[2] != 'V' || m_buffer[3] != 'T') { return true; diff --git a/G2ProtocolHandler.h b/G2ProtocolHandler.h index 82c58f1..14eb0b3 100644 --- a/G2ProtocolHandler.h +++ b/G2ProtocolHandler.h @@ -50,7 +50,7 @@ public: void traverseNat(const std::string& address); private: - // std::unordered_map m_portmap; + std::unordered_map m_portmap; CUDPReaderWriter m_socket; G2_TYPE m_type; From 605c0aaba81be9488d12007e118ca0f514fa382a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 15 Jan 2022 23:41:02 +0100 Subject: [PATCH 134/201] #5 rename member variable --- IRCDDBApp.cpp | 4 ++-- IRCMessage.cpp | 12 ++++++------ IRCMessage.h | 2 +- IRCProtocol.cpp | 36 ++++++++++++++++++------------------ IRCReceiver.cpp | 12 ++++++------ 5 files changed, 33 insertions(+), 33 deletions(-) diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index cb9eacb..c84f495 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -670,7 +670,7 @@ bool IRCDDBApp::notifyRepeaterNatTraversal(const std::string& repeater) void IRCDDBApp::msgChannel(IRCMessage *m) { - if (0==m->getPrefixNick().compare(0, 2, "s-") && m->numParams>=2) // server msg + if (0==m->getPrefixNick().compare(0, 2, "s-") && m->m_numParams>=2) // server msg doUpdate(m->m_params[1]); } @@ -826,7 +826,7 @@ static std::string getTableIDString(int tableID, bool spaceBeforeNumber) void IRCDDBApp::msgQuery(IRCMessage *m) { - if (0 == m->getPrefixNick().compare(0, 2, "s-") && m->numParams >=2 ) { // server msg + if (0 == m->getPrefixNick().compare(0, 2, "s-") && m->m_numParams >=2 ) { // server msg std::string msg(m->m_params[1]); std::vector tkz = CUtils::stringTokenizer(msg); diff --git a/IRCMessage.cpp b/IRCMessage.cpp index f8e407f..b881470 100644 --- a/IRCMessage.cpp +++ b/IRCMessage.cpp @@ -24,14 +24,14 @@ along with this program. If not, see . IRCMessage::IRCMessage() { - numParams = 0; + m_numParams = 0; m_prefixParsed = false; } IRCMessage::IRCMessage(const std::string& toNick, const std::string& msg) { m_command.assign("PRIVMSG"); - numParams = 2; + m_numParams = 2; m_params.push_back(toNick); m_params.push_back(msg); m_prefixParsed = false; @@ -40,7 +40,7 @@ IRCMessage::IRCMessage(const std::string& toNick, const std::string& msg) IRCMessage::IRCMessage(const std::string& cmd) { m_command = cmd; - numParams = 0; + m_numParams = 0; m_prefixParsed = false; } @@ -52,7 +52,7 @@ IRCMessage::~IRCMessage() void IRCMessage::addParam(const std::string& p) { m_params.push_back(p); - numParams = m_params.size(); + m_numParams = m_params.size(); } int IRCMessage::getParamCount() @@ -119,8 +119,8 @@ void IRCMessage::composeMessage(std::string& output) o.append(m_command); - for (int i=0; i < numParams; i++) { - if (i == (numParams - 1)) + for (int i=0; i < m_numParams; i++) { + if (i == (m_numParams - 1)) o.append(std::string(" :") + m_params[i]); else o.append(std::string(" ") + m_params[i]); diff --git a/IRCMessage.h b/IRCMessage.h index bb7df32..35c579e 100644 --- a/IRCMessage.h +++ b/IRCMessage.h @@ -36,7 +36,7 @@ public: std::string m_command; std::vector m_params; - int numParams; + int m_numParams; std::string& getPrefixNick(); std::string& getPrefixName(); std::string& getPrefixHost(); diff --git a/IRCProtocol.cpp b/IRCProtocol.cpp index dd74135..c23ced8 100644 --- a/IRCProtocol.cpp +++ b/IRCProtocol.cpp @@ -106,12 +106,12 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) IRCMessage *m2 = new IRCMessage(); m2->m_command = std::string("PONG"); if (m->m_params.size() > 0) { - m2->numParams = 1; + m2->m_numParams = 1; m2->m_params.push_back(m->m_params[0]); } sendQ -> putMessage(m2); } else if (0 == m->m_command.compare("JOIN")) { - if (m->numParams>=1 && 0==m->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 (m_debugChannel.size()) m_state = 7; // next: join debug_channel @@ -121,7 +121,7 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) m_app->userJoin(m->getPrefixNick(), m->getPrefixName(), m->getPrefixHost()); } - if (m->numParams>=1 && 0==m->m_params[0].compare(m_debugChannel)) { + if (m->m_numParams>=1 && 0==m->m_params[0].compare(m_debugChannel)) { if (0==m->getPrefixNick().compare(m_currentNick) && 8==m_state) m_state = 10; // next: WHO * } @@ -131,12 +131,12 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) m_state = 11; } } else if (0 == m->m_command.compare("PART")) { - if (m->numParams>=1 && 0==m->m_params[0].compare(m_channel)) { + if (m->m_numParams>=1 && 0==m->m_params[0].compare(m_channel)) { if (m_app != NULL) m_app->userLeave(m->getPrefixNick()); } } else if (0 == m->m_command.compare("KICK")) { - if (m->numParams>=2 && 0==m->m_params[0].compare(m_channel)) { + if (m->m_numParams>=2 && 0==m->m_params[0].compare(m_channel)) { if (0 == m->m_params[1].compare(m_currentNick)) { // i was kicked!! delete m; @@ -148,11 +148,11 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) if (m_app) m_app->userLeave(m->getPrefixNick()); } else if (0 == m->m_command.compare("MODE")) { - if (m->numParams>=3 && 0==m->m_params[0].compare(m_channel)) { + if (m->m_numParams>=3 && 0==m->m_params[0].compare(m_channel)) { if (m_app) { std::string mode = m->m_params[1]; - for (size_t i=1; inumParams>=i+2; i++) { + for (size_t i=1; im_numParams>=i+2; i++) { if ('o' == mode[i]) { if ('+' == mode[0]) m_app->userChanOp(m->m_params[i+1], true); @@ -163,14 +163,14 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) } } } else if (0 == m->m_command.compare("PRIVMSG")) { - if (m->numParams==2 && m_app) { + if (m->m_numParams==2 && m_app) { if (0 == m->m_params[0].compare(m_channel) && m_app) m_app->msgChannel(m); else if (0 == m->m_params[0].compare(m_currentNick) && m_app) m_app->msgQuery(m); } } else if (0 == m->m_command.compare("352")) { // WHO list - if (m->numParams>=7 && 0==m->m_params[0].compare(m_currentNick) && 0==m->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) { m_app->userJoin(m->m_params[5], m->m_params[2], m->m_params[3]); m_app->userChanOp(m->m_params[5], 0==m->m_params[6].compare("H@")); @@ -182,7 +182,7 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) m_timer = 10; // wait 5 seconds.. } } else if (0==m->m_command.compare("332") || 0==m->m_command.compare("TOPIC")) { // topic - if (2==m->numParams && m_app && 0==m->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->m_params[1]); } @@ -194,13 +194,13 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) case 1: m = new IRCMessage(); m->m_command = std::string("PASS"); - m->numParams = 1; + m->m_numParams = 1; m->m_params.push_back(m_password); sendQ->putMessage(m); m = new IRCMessage(); m->m_command = std::string("NICK"); - m->numParams = 1; + m->m_numParams = 1; m->m_params.push_back(m_currentNick); sendQ->putMessage(m); @@ -212,7 +212,7 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) if (0 == m_timer) { m = new IRCMessage(); m->m_command = std::string("USER"); - m->numParams = 4; + m->m_numParams = 4; m->m_params.push_back(m_name); m->m_params.push_back(std::string("0")); m->m_params.push_back(std::string("*")); @@ -229,7 +229,7 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) chooseNewNick(); m = new IRCMessage(); m->m_command = std::string("NICK"); - m->numParams = 1; + m->m_numParams = 1; m->m_params.push_back(m_currentNick); sendQ->putMessage(m); @@ -246,7 +246,7 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) case 5: m = new IRCMessage(); m->m_command = std::string("JOIN"); - m->numParams = 1; + m->m_numParams = 1; m->m_params.push_back(m_channel); sendQ->putMessage(m); @@ -265,7 +265,7 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) m = new IRCMessage(); m->m_command = std::string("JOIN"); - m->numParams = 1; + m->m_numParams = 1; m->m_params.push_back(m_debugChannel); sendQ->putMessage(m); @@ -281,7 +281,7 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) case 10: m = new IRCMessage(); m->m_command = std::string("WHO"); - m->numParams = 2; + m->m_numParams = 2; m->m_params.push_back(m_channel); m->m_params.push_back(std::string("*")); sendQ->putMessage(m); @@ -297,7 +297,7 @@ bool IRCProtocol::processQueues(IRCMessageQueue *recvQ, IRCMessageQueue *sendQ) if (0 == m_timer) { m = new IRCMessage(); m->m_command = std::string("PING"); - m->numParams = 1; + m->m_numParams = 1; m->m_params.push_back(m_currentNick); sendQ->putMessage(m); diff --git a/IRCReceiver.cpp b/IRCReceiver.cpp index 5e6bfed..24620a0 100644 --- a/IRCReceiver.cpp +++ b/IRCReceiver.cpp @@ -131,7 +131,7 @@ void IRCReceiver::Entry() case 2: if (b == ' ') { state = 3; // params are next - m->numParams = 1; + m->m_numParams = 1; m->m_params.push_back(std::string("")); } else m->m_command.push_back(b); @@ -139,18 +139,18 @@ void IRCReceiver::Entry() case 3: if (b == ' ') { - m->numParams++; - if (m->numParams >= 15) + m->m_numParams++; + if (m->m_numParams >= 15) state = 5; // ignore the rest m->m_params.push_back(std::string("")); - } else if (b==':' && m->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 else - m->m_params[m->numParams-1].push_back(b); + m->m_params[m->m_numParams-1].push_back(b); break; case 4: - m->m_params[m->numParams-1].push_back(b); + m->m_params[m->m_numParams-1].push_back(b); break; } // switch } From 5fb9b57626bd03cdd21b300686f5c3786c00eec6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 16 Jan 2022 07:53:13 +0100 Subject: [PATCH 135/201] #5 Also punch holes on callsign routing --- RepeaterHandler.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/RepeaterHandler.cpp b/RepeaterHandler.cpp index 9e1d71f..782a39b 100644 --- a/RepeaterHandler.cpp +++ b/RepeaterHandler.cpp @@ -2109,6 +2109,7 @@ void CRepeaterHandler::g2CommandHandler(const std::string& callsign, const std:: m_g2User = callsign; m_g2Address = data->getAddress(); m_g2Repeater = data->getRepeater(); + m_irc->notifyRepeaterNatTraversal(m_g2Repeater); m_g2Gateway = data->getGateway(); header.setDestination(m_g2Address, G2_DV_PORT); header.setRepeaters(m_g2Gateway, m_g2Repeater); From a150b9d35c2cf294b5d4fb1b590923b91a0b79d3 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 16 Jan 2022 13:28:21 +0100 Subject: [PATCH 136/201] #5 Remove nat traversal handler --- DStarGatewayThread.cpp | 6 ---- DStarGatewayThread.h | 2 -- NatTraversalHandler.cpp | 60 -------------------------------- NatTraversalHandler.h | 77 ----------------------------------------- 4 files changed, 145 deletions(-) delete mode 100644 NatTraversalHandler.cpp delete mode 100644 NatTraversalHandler.h diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index 9641d85..b2e9e7a 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -76,7 +76,6 @@ m_dextraPool(NULL), m_dplusPool(NULL), m_dcsPool(NULL), m_g2Handler(NULL), -m_natTraversal(NULL), m_aprsWriter(NULL), m_irc(NULL), m_cache(), @@ -207,11 +206,6 @@ void* CDStarGatewayThread::Entry() m_g2Handler = NULL; } - if(m_g2Handler != NULL) { - m_natTraversal = new CNatTraversalHandler(); - m_natTraversal->setG2Handler(m_g2Handler); - } - // Wait here until we have the essentials to run while (!m_killed && (m_dextraPool == NULL || m_dplusPool == NULL || m_dcsPool == NULL || m_g2Handler == NULL || (m_icomRepeaterHandler == NULL && m_hbRepeaterHandler == NULL && m_dummyRepeaterHandler == NULL) || m_gatewayCallsign.empty())) ::std::this_thread::sleep_for(std::chrono::milliseconds(500UL)); // 1/2 sec diff --git a/DStarGatewayThread.h b/DStarGatewayThread.h index e6830c1..e81aaf1 100644 --- a/DStarGatewayThread.h +++ b/DStarGatewayThread.h @@ -37,7 +37,6 @@ #include "Timer.h" #include "Defs.h" #include "Thread.h" -#include "NatTraversalHandler.h" class CDStarGatewayThread : public CThread{ public: @@ -104,7 +103,6 @@ private: CDPlusProtocolHandlerPool* m_dplusPool; CDCSProtocolHandlerPool* m_dcsPool; CG2ProtocolHandler* m_g2Handler; - CNatTraversalHandler* m_natTraversal; CAPRSHandler* m_aprsWriter; CIRCDDB* m_irc; CCacheManager m_cache; diff --git a/NatTraversalHandler.cpp b/NatTraversalHandler.cpp deleted file mode 100644 index 9357c1b..0000000 --- a/NatTraversalHandler.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2010,2011,2012,2013,2014,2015,2016,2017,2018 by Jonathan Naylor G4KLX - * 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 "NatTraversalHandler.h" - -const unsigned int CACHE_SIZE = 500U; - -CNatTraversalHandler::CNatTraversalHandler() : -m_g2cache(CACHE_SIZE), -m_g2Handler(NULL) -{ - -} - -CNatTraversalHandler::~CNatTraversalHandler() -{ - for (auto it = m_g2cache.begin(); it != m_g2cache.end(); ++it) - delete it->second; - - m_g2cache.clear(); -} - -void CNatTraversalHandler::setG2Handler(CG2ProtocolHandler * handler) -{ - m_g2Handler = handler; -} - -void CNatTraversalHandler::traverseNatG2(const std::string& address) -{ - if(m_g2Handler != NULL){ - CNatTraversalRecord* record = m_g2cache[address]; - - if(record == NULL) { - record = new CNatTraversalRecord(address); - m_g2cache[address] = record; - } - - std::time_t currentTime = std::time(NULL); - if(currentTime - record->getTimestamp() > G2_TRAVERSAL_TIMEOUT) { - record->setTimestamp(currentTime); - m_g2Handler->traverseNat(address); - } - } -} diff --git a/NatTraversalHandler.h b/NatTraversalHandler.h deleted file mode 100644 index 4d56851..0000000 --- a/NatTraversalHandler.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2010,2011,2012,2013,2014,2015,2016,2017,2018 by Jonathan Naylor G4KLX - * 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. - */ - -#ifndef NatTraversalHandler_H -#define NatTraversalHandler_H - -#define G2_TRAVERSAL_TIMEOUT 29 //seconds - -#include "G2ProtocolHandler.h" - -#include -#include -#include - -enum NAT_TRAVERSAL_TYPE { - NTT_G2, - //NTT_DEXTRA - //NTT_DCS - //NTT_DPLUS -}; - -class CNatTraversalRecord { -public: - CNatTraversalRecord(const std::string& address) : - m_address(address), - m_timestamp(0) - { - } - - std::time_t getTimestamp() const - { - return m_timestamp; - } - - void setTimestamp(std::time_t timestamp) - { - m_timestamp = timestamp; - } - -private: - std::string m_address; - std::time_t m_timestamp; -}; - -/* -* This keeps track of when we UDP punched to one destination so to avoid unnecessary traffic on each ircddb reporting -*/ -class CNatTraversalHandler { -public: - CNatTraversalHandler(); - ~CNatTraversalHandler(); - - void setG2Handler(CG2ProtocolHandler* handler); - void traverseNatG2(const std::string& address); - -private: - std::unordered_map m_g2cache; - CG2ProtocolHandler* m_g2Handler; -}; - -#endif From f0a4320928b80da83ec1f1aa7f86c2c6cffad720 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 16 Jan 2022 13:42:24 +0100 Subject: [PATCH 137/201] #5 install sig handler --- DStarGatewayApp.cpp | 29 +++++++++++++++++++++++++++-- DStarGatewayApp.h | 2 ++ Makefile | 2 +- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/DStarGatewayApp.cpp b/DStarGatewayApp.cpp index 3a8ae42..1b47533 100644 --- a/DStarGatewayApp.cpp +++ b/DStarGatewayApp.cpp @@ -23,6 +23,11 @@ #include #include #include +#include +#include +#include +#include +#include #include "DStarGatewayDefs.h" #include "DStarGatewayConfig.h" @@ -41,9 +46,15 @@ #include "APRSGPSDIdFrameProvider.h" #include "APRSFixedIdFrameProvider.h" -#ifndef UNIT_TESTS +#ifdef UNIT_TESTS +int fakemain(int argc, char *argv[]) +#else int main(int argc, char *argv[]) +#endif { + // install sigHandler + signal(SIGSEGV, __sigHandler); + setbuf(stdout, NULL); if (2 != argc) { printf("usage: %s path_to_config_file\n", argv[0]); @@ -70,7 +81,21 @@ int main(int argc, char *argv[]) return 0; } -#endif + +void __sigHandler(int sig) +{ + if(sig == SIGSEGV) { + void *array[100]; + size_t size; + // get void*'s for all entries on the stack + size = backtrace(array, 100); + + // print out all the frames to stderr + fprintf(stderr, "Error: signal %d:\n", sig); + backtrace_symbols_fd(array, size, STDERR_FILENO); + exit(1); + } +} CDStarGatewayApp::CDStarGatewayApp(const std::string &configFile) : m_configFile(configFile), m_thread(NULL) { diff --git a/DStarGatewayApp.h b/DStarGatewayApp.h index 2af3de9..3461e88 100644 --- a/DStarGatewayApp.h +++ b/DStarGatewayApp.h @@ -21,6 +21,8 @@ #include "DStarGatewayThread.h" +void __sigHandler(int sig); + class CDStarGatewayApp { private: diff --git a/Makefile b/Makefile index 973fbaa..b057963 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ export LOG_DIR=/var/log/dstargateway/ ifeq ($(ENABLE_DEBUG), 1) # choose this if you want debugging help -export CPPFLAGS=-g -ggdb -W -Wall -Werror -std=c++17 +export CPPFLAGS=-g -rdynamic -ggdb -W -Wall -Werror -std=c++17 else # or, you can choose this for a much smaller executable without debugging help CPPFLAGS=-W -O3 -Wall -Werror -std=c++17 From 3c991205beceeccd05a042387cd8c7c25217f05f Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Mon, 17 Jan 2022 20:49:38 +0100 Subject: [PATCH 138/201] #5 use terminate handler in debug mode --- APRSHandlerThread.cpp | 4 ++ DPlusAuthenticator.cpp | 4 ++ DStarGatewayApp.cpp | 65 ++++++++++++++++++++++----------- DStarGatewayApp.h | 3 ++ DStarGatewayThread.cpp | 4 ++ IcomRepeaterProtocolHandler.cpp | 4 ++ Makefile | 7 ++-- README.md | 6 +++ 8 files changed, 73 insertions(+), 24 deletions(-) diff --git a/APRSHandlerThread.cpp b/APRSHandlerThread.cpp index b13e99b..9745341 100644 --- a/APRSHandlerThread.cpp +++ b/APRSHandlerThread.cpp @@ -123,7 +123,9 @@ void* CAPRSHandlerThread::Entry() startReconnectionTimer(); } +#ifndef DEBUG_DSTARGW try { +#endif m_keepAliveTimer.start(); while (!m_exit) { if (!m_connected) { @@ -194,6 +196,7 @@ void* CAPRSHandlerThread::Entry() auto s = m_queue.getData(); s.clear(); } +#ifndef DEBUG_DSTARGW } catch (std::exception& e) { std::string message(e.what()); @@ -202,6 +205,7 @@ void* CAPRSHandlerThread::Entry() catch (...) { CLog::logInfo("Unknown exception raised in the APRS Writer thread"); } +#endif CLog::logInfo("Stopping the APRS Writer thread"); diff --git a/DPlusAuthenticator.cpp b/DPlusAuthenticator.cpp index 2921996..b9d1768 100644 --- a/DPlusAuthenticator.cpp +++ b/DPlusAuthenticator.cpp @@ -72,7 +72,9 @@ void* CDPlusAuthenticator::Entry() m_timer.start(); +#ifndef DEBUG_DSTARGW try { +#endif while (!m_killed) { if (m_timer.hasExpired()) { authenticate(m_loginCallsign, OPENDSTAR_HOSTNAME, OPENDSTAR_PORT, '2', true); @@ -83,6 +85,7 @@ void* CDPlusAuthenticator::Entry() m_timer.clock(); } +#ifndef DEBUG_DSTARGW } catch (std::exception& e) { std::string message(e.what()); @@ -91,6 +94,7 @@ void* CDPlusAuthenticator::Entry() catch (...) { CLog::logError("Unknown exception raised in the D-Plus Authenticator thread"); } +#endif CLog::logInfo("Stopping the D-Plus Authenticator thread"); diff --git a/DStarGatewayApp.cpp b/DStarGatewayApp.cpp index 1b47533..45f2c8a 100644 --- a/DStarGatewayApp.cpp +++ b/DStarGatewayApp.cpp @@ -23,11 +23,11 @@ #include #include #include -#include -#include #include -#include -#include +#include +#ifdef DEBUG_DSTARGW +#include +#endif #include "DStarGatewayDefs.h" #include "DStarGatewayConfig.h" @@ -52,8 +52,14 @@ int fakemain(int argc, char *argv[]) int main(int argc, char *argv[]) #endif { - // install sigHandler - signal(SIGSEGV, __sigHandler); + std::set_terminate(CDStarGatewayApp::terminateHandler); + + // TODO 2022-01-17 handle SIGTERM etc .... + // signal(SIGSEGV, CDStarGatewayApp::sigHandler); + // signal(SIGILL, CDStarGatewayApp::sigHandler); + // signal(SIGFPE, CDStarGatewayApp::sigHandler); + // signal(SIGABRT, CDStarGatewayApp::sigHandler); + // signal(SIGTERM, CDStarGatewayApp::sigHandler); setbuf(stdout, NULL); if (2 != argc) { @@ -82,21 +88,6 @@ int main(int argc, char *argv[]) return 0; } -void __sigHandler(int sig) -{ - if(sig == SIGSEGV) { - void *array[100]; - size_t size; - // get void*'s for all entries on the stack - size = backtrace(array, 100); - - // print out all the frames to stderr - fprintf(stderr, "Error: signal %d:\n", sig); - backtrace_symbols_fd(array, size, STDERR_FILENO); - exit(1); - } -} - CDStarGatewayApp::CDStarGatewayApp(const std::string &configFile) : m_configFile(configFile), m_thread(NULL) { } @@ -285,3 +276,35 @@ bool CDStarGatewayApp::createThread() return true; } +void CDStarGatewayApp::sigHandler(int /*sig*/) +{ + // TODO 2022-01-17 handle SIGTERM etc .... +} + +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 unkown exception occured"); + } + } catch(const std::exception& e) { + CLog::logFatal("Unhandled exception occured %s", e.what()); + } + +#ifdef DEBUG_DSTARGW + CLog::logFatal("%s", stackTrace.str().c_str()); +#endif + exit(1); +} \ No newline at end of file diff --git a/DStarGatewayApp.h b/DStarGatewayApp.h index 3461e88..4929018 100644 --- a/DStarGatewayApp.h +++ b/DStarGatewayApp.h @@ -36,4 +36,7 @@ public: bool init(); void run(); + + static void sigHandler(int sig); + static void terminateHandler(); }; diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index b2e9e7a..fce9403 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -335,7 +335,9 @@ void* CDStarGatewayThread::Entry() m_statusFileTimer.start(); m_statusTimer2.start(); +#ifndef DEBUG_DSTARGW try { +#endif while (!m_killed) { if (m_icomRepeaterHandler != NULL) processRepeater(m_icomRepeaterHandler); @@ -411,6 +413,7 @@ void* CDStarGatewayThread::Entry() ::std::this_thread::sleep_for(std::chrono::milliseconds(TIME_PER_TIC_MS)); } +#ifndef DEBUG_DSTARGW } catch (std::exception& e) { std::string message(e.what()); @@ -419,6 +422,7 @@ void* CDStarGatewayThread::Entry() catch (...) { CLog::logFatal("Unknown exception raised in the main thread"); } +#endif CLog::logInfo("Stopping the ircDDB Gateway thread"); diff --git a/IcomRepeaterProtocolHandler.cpp b/IcomRepeaterProtocolHandler.cpp index d220690..51f30cb 100644 --- a/IcomRepeaterProtocolHandler.cpp +++ b/IcomRepeaterProtocolHandler.cpp @@ -135,7 +135,9 @@ void* CIcomRepeaterProtocolHandler::Entry() { CLog::logInfo("Starting the Icom Controller thread"); +#ifndef DEBUG_DSTARGW try { +#endif while (!m_killed) { sendGwyPackets(); @@ -145,6 +147,7 @@ void* CIcomRepeaterProtocolHandler::Entry() m_retryTimer.clock(); } +#ifndef DEBUG_DSTARGW } catch (std::exception& e) { std::string message(e.what()); @@ -153,6 +156,7 @@ void* CIcomRepeaterProtocolHandler::Entry() catch (...) { CLog::logError("Unknown exception raised in the Icom Controller thread"); } +#endif CLog::logInfo("Stopping the Icom Controller thread"); diff --git a/Makefile b/Makefile index b057963..0174975 100644 --- a/Makefile +++ b/Makefile @@ -23,14 +23,15 @@ export LOG_DIR=/var/log/dstargateway/ ifeq ($(ENABLE_DEBUG), 1) # choose this if you want debugging help -export CPPFLAGS=-g -rdynamic -ggdb -W -Wall -Werror -std=c++17 +export CPPFLAGS=-g -rdynamic -DBOOST_STACKTRACE_USE_ADDR2LINE -DDEBUG_DSTARGW -no-pie -fno-pie -ggdb -W -Wall -Werror -std=c++17 +export LDFLAGS=-ldl -no-pie -fno-pie else # or, you can choose this for a much smaller executable without debugging help -CPPFLAGS=-W -O3 -Wall -Werror -std=c++17 +export CPPFLAGS=-W -O3 -Wall -Werror -std=c++17 endif export CC=g++ -export LDFLAGS:=-lcurl -pthread +export LDFLAGS+= -lcurl -pthread ifeq ($(USE_GPSD), 1) export CPPFLAGS+= -DUSE_GPSD diff --git a/README.md b/README.md index 9b75943..e89f7bd 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ - [3.4. Prerequisites and dependencies](#34-prerequisites-and-dependencies) - [3.5. Building](#35-building) - [3.5.0.1. Build With GPSD Support](#3501-build-with-gpsd-support) + - [3.5.0.2. Debug Build](#3502-debug-build) - [3.6. Installing](#36-installing) - [3.7. Configuring](#37-configuring) - [4. Contributing](#4-contributing) @@ -91,6 +92,11 @@ make ``` make USE_GPS=1 ``` +#### 3.5.0.2. Debug Build +``` +make ENABLE_DEBUG=1 +``` +Note that this will link with libl ## 3.6. Installing The program is meant to run as a systemd service. All bits an pieces are provided. ``` From 3ed0d18dc3e05dc65e426bf1f3b11d29ea7c6603 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 18 Jan 2022 07:02:15 +0100 Subject: [PATCH 139/201] #5 make log message more explicit --- G2ProtocolHandler.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/G2ProtocolHandler.cpp b/G2ProtocolHandler.cpp index d6cfd86..0106bb6 100644 --- a/G2ProtocolHandler.cpp +++ b/G2ProtocolHandler.cpp @@ -111,11 +111,11 @@ bool CG2ProtocolHandler::readPackets() // save the incoming port (this is to enable mobile hotspots) 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); m_portmap[m_address.s_addr] = m_port; } else { 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, m_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]); m_portmap[m_address.s_addr] = m_port; } } From eba23340502fda67ccc9a769a5f47d6668f53025 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 18 Jan 2022 17:20:51 +0100 Subject: [PATCH 140/201] #5 better error handling, do not leave the program in a dangling state --- APRSHandlerThread.cpp | 2 ++ DPlusAuthenticator.cpp | 2 ++ DStarGatewayApp.cpp | 23 ++++++++++++++--------- DStarGatewayApp.h | 2 +- DStarGatewayThread.cpp | 2 ++ IcomRepeaterProtocolHandler.cpp | 2 ++ 6 files changed, 23 insertions(+), 10 deletions(-) diff --git a/APRSHandlerThread.cpp b/APRSHandlerThread.cpp index 9745341..1d6b099 100644 --- a/APRSHandlerThread.cpp +++ b/APRSHandlerThread.cpp @@ -201,9 +201,11 @@ void* CAPRSHandlerThread::Entry() catch (std::exception& e) { std::string message(e.what()); CLog::logInfo("Exception raised in the APRS Writer thread - \"%s\"", message.c_str()); + throw; } catch (...) { CLog::logInfo("Unknown exception raised in the APRS Writer thread"); + throw; } #endif diff --git a/DPlusAuthenticator.cpp b/DPlusAuthenticator.cpp index b9d1768..e67ccf7 100644 --- a/DPlusAuthenticator.cpp +++ b/DPlusAuthenticator.cpp @@ -90,9 +90,11 @@ void* CDPlusAuthenticator::Entry() catch (std::exception& e) { std::string message(e.what()); CLog::logError("Exception raised in the D-Plus Authenticator thread - \"%s\"", message.c_str()); + throw; } catch (...) { CLog::logError("Unknown exception raised in the D-Plus Authenticator thread"); + throw; } #endif diff --git a/DStarGatewayApp.cpp b/DStarGatewayApp.cpp index 45f2c8a..7c498d3 100644 --- a/DStarGatewayApp.cpp +++ b/DStarGatewayApp.cpp @@ -54,11 +54,10 @@ int main(int argc, char *argv[]) { std::set_terminate(CDStarGatewayApp::terminateHandler); - // TODO 2022-01-17 handle SIGTERM etc .... - // signal(SIGSEGV, CDStarGatewayApp::sigHandler); - // signal(SIGILL, CDStarGatewayApp::sigHandler); - // signal(SIGFPE, CDStarGatewayApp::sigHandler); - // signal(SIGABRT, CDStarGatewayApp::sigHandler); + signal(SIGSEGV, CDStarGatewayApp::sigHandlerFatal); + signal(SIGILL, CDStarGatewayApp::sigHandlerFatal); + signal(SIGFPE, CDStarGatewayApp::sigHandlerFatal); + signal(SIGABRT, CDStarGatewayApp::sigHandlerFatal); // signal(SIGTERM, CDStarGatewayApp::sigHandler); setbuf(stdout, NULL); @@ -276,9 +275,15 @@ bool CDStarGatewayApp::createThread() return true; } -void CDStarGatewayApp::sigHandler(int /*sig*/) +void CDStarGatewayApp::sigHandlerFatal(int sig) { - // TODO 2022-01-17 handle SIGTERM etc .... + 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() @@ -297,14 +302,14 @@ void CDStarGatewayApp::terminateHandler() std::rethrow_exception(eptr); } else { - CLog::logFatal("Unhandled unkown exception occured"); + CLog::logFatal("Unhandled unknown exception occured"); } } catch(const std::exception& e) { CLog::logFatal("Unhandled exception occured %s", e.what()); } #ifdef DEBUG_DSTARGW - CLog::logFatal("%s", stackTrace.str().c_str()); + CLog::logFatal("Stack Trace : \n%s", stackTrace.str().c_str()); #endif exit(1); } \ No newline at end of file diff --git a/DStarGatewayApp.h b/DStarGatewayApp.h index 4929018..08c67cb 100644 --- a/DStarGatewayApp.h +++ b/DStarGatewayApp.h @@ -37,6 +37,6 @@ public: bool init(); void run(); - static void sigHandler(int sig); + static void sigHandlerFatal(int sig); static void terminateHandler(); }; diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index fce9403..1db50f4 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -418,9 +418,11 @@ void* CDStarGatewayThread::Entry() catch (std::exception& e) { std::string message(e.what()); CLog::logFatal("Exception raised in the main thread - \"%s\"", message.c_str()); + throw; } catch (...) { CLog::logFatal("Unknown exception raised in the main thread"); + throw; } #endif diff --git a/IcomRepeaterProtocolHandler.cpp b/IcomRepeaterProtocolHandler.cpp index 51f30cb..d6e20f8 100644 --- a/IcomRepeaterProtocolHandler.cpp +++ b/IcomRepeaterProtocolHandler.cpp @@ -152,9 +152,11 @@ void* CIcomRepeaterProtocolHandler::Entry() catch (std::exception& e) { std::string message(e.what()); CLog::logError("Exception raised in the Icom Controller thread - \"%s\"", message.c_str()); + throw; } catch (...) { CLog::logError("Unknown exception raised in the Icom Controller thread"); + throw; } #endif From a88bf0bb1777b30b7f288a1f2a6a772a9a33d19b Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 18 Jan 2022 23:13:57 +0100 Subject: [PATCH 141/201] #5 add some logging --- G2ProtocolHandler.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/G2ProtocolHandler.cpp b/G2ProtocolHandler.cpp index 0106bb6..f044240 100644 --- a/G2ProtocolHandler.cpp +++ b/G2ProtocolHandler.cpp @@ -107,6 +107,10 @@ bool CG2ProtocolHandler::readPackets() if (length <= 0) return false; + if(length == 1) { + CLog::logDebug("G2 Nat traversal packet received"); + } + m_length = length; // save the incoming port (this is to enable mobile hotspots) From 9bb9f0b3e48aa7a296e9a36ee62b2349cc0b7e5c Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 18 Jan 2022 23:14:43 +0100 Subject: [PATCH 142/201] #5 Test add results of WHO query to gateway list --- IRCDDBApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index c84f495..0b4a4f9 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -311,7 +311,7 @@ void IRCDDBApp::userJoin(const std::string& nick, const std::string& name, const m_d->m_userMap[lnick] = u; - if (m_d->m_initReady) { + /*if (m_d->m_initReady)*/ { std::string::size_type hyphenPos = nick.find('-'); if ((hyphenPos >= 4) && (hyphenPos <= 6)) { From 12b0d037651f75b35caa2284f7df1198c0a7089f Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 19 Jan 2022 08:33:26 +0100 Subject: [PATCH 143/201] #5 make ircddb version sam structure as ircddbgateway ircddb version --- DStarGatewayApp.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/DStarGatewayApp.cpp b/DStarGatewayApp.cpp index 7c498d3..16c3903 100644 --- a/DStarGatewayApp.cpp +++ b/DStarGatewayApp.cpp @@ -215,12 +215,13 @@ bool CDStarGatewayApp::createThread() CLog::logInfo("DD Mode enabled: %d", int(ddEnabled)); // Setup ircddb + auto ircddbVersionInfo = "linux_" + PRODUCT_NAME + "-" + VERSION; std::vector clients; for(unsigned int i=0; i < config.getIrcDDBCount(); i++) { TircDDB ircDDBConfig; config.getIrcDDB(i, ircDDBConfig); CLog::logInfo("ircDDB Network %d set to %s user: %s, Quadnet %d", i + 1,ircDDBConfig.hostname.c_str(), ircDDBConfig.username.c_str(), ircDDBConfig.isQuadNet); - CIRCDDB * ircDDB = new CIRCDDBClient(ircDDBConfig.hostname, 9007U, ircDDBConfig.username, ircDDBConfig.password, FULL_PRODUCT_NAME, gatewayConfig.address, ircDDBConfig.isQuadNet); + CIRCDDB * ircDDB = new CIRCDDBClient(ircDDBConfig.hostname, 9007U, ircDDBConfig.username, ircDDBConfig.password, ircddbVersionInfo, gatewayConfig.address, ircDDBConfig.isQuadNet); clients.push_back(ircDDB); } if(clients.size() > 0U) { @@ -312,4 +313,4 @@ void CDStarGatewayApp::terminateHandler() CLog::logFatal("Stack Trace : \n%s", stackTrace.str().c_str()); #endif exit(1); -} \ No newline at end of file +} From 2f7a5c196d0d06023f03a7ec51ead3a91e452a1a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 19 Jan 2022 11:43:26 +0100 Subject: [PATCH 144/201] #5 do not look like 22 years in the past ! --- IRCDDBApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index 0b4a4f9..ea942ed 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -131,7 +131,7 @@ public: IRCDDBApp::IRCDDBApp(const std::string& u_chan) : m_d(new IRCDDBAppPrivate) - , m_maxTime((time_t)950000000) //februray 2000 + , m_maxTime((time_t)time(0) - (time_t)(60 * 24 * 60 60)) // look 60 days in the past { m_d->m_sendQ = NULL; m_d->m_initReady = false; From d4d152b9c49ccc42a788bd1cf0b009db818e9ccb Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 19 Jan 2022 11:46:32 +0100 Subject: [PATCH 145/201] #5 fix typo, look only 60 days into the past, not 22 years ! --- IRCDDBApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index ea942ed..6f76565 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -131,7 +131,7 @@ public: IRCDDBApp::IRCDDBApp(const std::string& u_chan) : m_d(new IRCDDBAppPrivate) - , m_maxTime((time_t)time(0) - (time_t)(60 * 24 * 60 60)) // look 60 days in the past + , m_maxTime((time_t)time(0) - (time_t)(60 * 24 * 60 * 60)) // look 60 days in the past { m_d->m_sendQ = NULL; m_d->m_initReady = false; From bff32329113a7326f73453bb245b6471ed77413a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 19 Jan 2022 16:45:46 +0100 Subject: [PATCH 146/201] #5 traverseNat cleanup --- G2ProtocolHandler.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/G2ProtocolHandler.cpp b/G2ProtocolHandler.cpp index f044240..60e1b30 100644 --- a/G2ProtocolHandler.cpp +++ b/G2ProtocolHandler.cpp @@ -177,12 +177,11 @@ void CG2ProtocolHandler::close() void CG2ProtocolHandler::traverseNat(const std::string& address) { - unsigned char buffer[1]; - ::memset(buffer, 0, 1); + unsigned char buffer = 0x00U; in_addr addr = CUDPReaderWriter::lookup(address); - CLog::logInfo("Punching hole to %s", address.c_str()); + CLog::logInfo("G2 Punching hole to %s", address.c_str()); - m_socket.write(buffer, 1, addr, G2_DV_PORT); + m_socket.write(&buffer, 1U, addr, G2_DV_PORT); } From 13335e492458eaacc5b79006a45f6f2967188eb3 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 19 Jan 2022 19:06:33 +0100 Subject: [PATCH 147/201] #5 first implementaion of Dextra NatTraversal --- .vscode/settings.json | 3 ++- DExtraProtocolHandler.cpp | 13 +++++++++- DExtraProtocolHandler.h | 1 + DStarGatewayThread.cpp | 27 +++++++++++++++++++-- IRCDDB.h | 7 ++++-- IRCDDBApp.cpp | 45 +++++++++++++++++++++++++++++++++-- IRCDDBApp.h | 3 ++- IRCDDBClient.cpp | 46 ++++++++++++++++++++++++++++++++--- IRCDDBClient.h | 4 +++- IRCDDBMultiClient.cpp | 50 ++++++++++++++++++++++++++++++++------- IRCDDBMultiClient.h | 15 ++++++++++-- RepeaterHandler.cpp | 4 ++-- 12 files changed, 192 insertions(+), 26 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f39f63c..5c9c832 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -71,7 +71,8 @@ "system_error": "cpp", "thread": "cpp", "typeindex": "cpp", - "variant": "cpp" + "variant": "cpp", + "iostream": "cpp" }, "editor.tokenColorCustomizations": { "textMateRules": [ diff --git a/DExtraProtocolHandler.cpp b/DExtraProtocolHandler.cpp index 5ef827f..6963bd9 100644 --- a/DExtraProtocolHandler.cpp +++ b/DExtraProtocolHandler.cpp @@ -19,7 +19,7 @@ */ #include "DExtraProtocolHandler.h" - +#include "Log.h" #include "Utils.h" // #define DUMP_TX @@ -113,6 +113,17 @@ bool CDExtraProtocolHandler::writeConnect(const CConnectData& connect) return true; } +void CDExtraProtocolHandler::traverseNat(const std::string& address, unsigned int remotePort) +{ + unsigned char buffer = 0x00U; + + in_addr addr = CUDPReaderWriter::lookup(address); + + CLog::logInfo("DExtra Punching hole to %s:%u", address.c_str(), remotePort); + + m_socket.write(&buffer, 1U, addr, remotePort); +} + DEXTRA_TYPE CDExtraProtocolHandler::read() { bool res = true; diff --git a/DExtraProtocolHandler.h b/DExtraProtocolHandler.h index 7936bd1..24c2bef 100644 --- a/DExtraProtocolHandler.h +++ b/DExtraProtocolHandler.h @@ -51,6 +51,7 @@ public: bool writeAMBE(const CAMBEData& data); bool writeConnect(const CConnectData& connect); bool writePoll(const CPollData& poll); + void traverseNat(const std::string& address, unsigned int remotePort); DEXTRA_TYPE read(); CHeaderData* readHeader(); diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index 1db50f4..765179a 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "DStarGatewayThread.h" #include "DStarGatewayDefs.h" @@ -788,8 +789,30 @@ void CDStarGatewayThread::processIrcDDB() if(!res) return; - CLog::logInfo("%s wants to G2 route to us, punching UDP Holes through NAT", address.c_str()); - m_g2Handler->traverseNat(address); + 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; + + if(m_dextraEnabled && 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()); + auto remotePortInt = boost::lexical_cast(remotePort); + 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_NONE: diff --git a/IRCDDB.h b/IRCDDB.h index e1f8186..b285119 100644 --- a/IRCDDB.h +++ b/IRCDDB.h @@ -32,7 +32,8 @@ enum IRCDDB_RESPONSE_TYPE { IDRT_USER, IDRT_GATEWAY, IDRT_REPEATER, - IDRT_NATTRAVERSAL_G2 + IDRT_NATTRAVERSAL_G2, + IDRT_NATTRAVERSAL_DEXTRA, }; @@ -114,7 +115,8 @@ public: virtual bool findUser(const std::string& userCallsign) = 0; // notify another repeater for NAT Traversal, a false return implies a network error - virtual bool notifyRepeaterNatTraversal(const std::string& repeater) = 0; + virtual bool notifyRepeaterG2NatTraversal(const std::string& repeater) = 0; + virtual bool notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myport) = 0; // Support for the Smart Group Server virtual void sendDStarGatewayInfo(const std::string subcommand, const std::vector parms) = 0; @@ -139,6 +141,7 @@ public: virtual bool receiveUser(std::string& userCallsign, std::string& repeaterCallsign, std::string& gatewayCallsign, std::string& address, std::string& timeStamp) = 0; virtual bool receiveNATTraversalG2(std::string& address) = 0; + virtual bool receiveNATTraversalDextra(std::string& address, std::string& remotePort) = 0; virtual void close() = 0; // Implictely kills any threads in the IRC code }; diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index 6f76565..f89a84d 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -259,6 +259,9 @@ IRCDDB_RESPONSE_TYPE IRCDDBApp::getReplyMessageType() if(msgType.compare("NATTRAVERSAL_G2") == 0) return IDRT_NATTRAVERSAL_G2; + if(msgType.compare("NATTRAVERSAL_DEXTRA") == 0) + return IDRT_NATTRAVERSAL_DEXTRA; + CLog::logWarning("IRCDDBApp::getMessageType: unknown msg type: %s\n", msgType.c_str()); return IDRT_NONE; @@ -638,7 +641,7 @@ bool IRCDDBApp::findUser(const std::string& usrCall) return true; } -bool IRCDDBApp::notifyRepeaterNatTraversal(const std::string& repeater) +bool IRCDDBApp::notifyRepeaterG2NatTraversal(const std::string& repeater) { auto firstSpacePos = repeater.find_first_of(' '); if(firstSpacePos == std::string::npos) @@ -668,6 +671,37 @@ bool IRCDDBApp::notifyRepeaterNatTraversal(const std::string& repeater) return true; } +bool IRCDDBApp::notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myLocalPort) +{ + auto firstSpacePos = repeater.find_first_of(' '); + if(firstSpacePos == std::string::npos) + return true; + + auto lrepeater = repeater.substr(0, firstSpacePos); + CUtils::ToLower(lrepeater); + std::string nick; + + std::lock_guard loclUserMap(m_d->m_userMapMutex); + for(unsigned int i = 1; i <= 4U; i++) { + nick = lrepeater + "-" + std::to_string(i); + if(m_d->m_userMap.count(nick) == 1) { + break; + } + nick.clear(); + } + + if(nick.empty()) { + CLog::logDebug("Unable to dind IRC nick for repeater %s", repeater.c_str()); + return true; + } + + IRCMessage * ircMessage = new IRCMessage(nick, "NATTRAVERSAL_DEXTRA"); + ircMessage->addParam(std::to_string(myLocalPort)); + m_d->m_sendQ->putMessage(ircMessage); + + return true; +} + void IRCDDBApp::msgChannel(IRCMessage *m) { if (0==m->getPrefixNick().compare(0, 2, "s-") && m->m_numParams>=2) // server msg @@ -873,11 +907,18 @@ void IRCDDBApp::msgQuery(IRCMessage *m) } } else if(m->m_params[0] == m_d->m_myNick) { - if(boost::starts_with(m->m_params[1], "NATTRAVERSAL_")) { + if(m->m_params.size() >= 2U && m->m_params[1] == "NATTRAVERSAL_G2") { IRCMessage * m2 = new IRCMessage(m->m_params[1]); m2->addParam(m->getPrefixHost()); m_d->m_replyQ.putMessage(m2); } + else if(m->m_params.size() >= 2U && boost::starts_with(m->m_params[1], "NATTRAVERSAL_DEXTRA")) { + IRCMessage * m2 = new IRCMessage(m->m_params[1].substr(0, (std::string("NATTRAVERSAL_DEXTRA")).length())); + m2->addParam(m->getPrefixHost()); + std::string remotePort = boost::trim_copy(boost::replace_all_copy(m->m_params[1], "NATTRAVERSAL_DEXTRA", "")); + m2->addParam(remotePort); + m_d->m_replyQ.putMessage(m2); + } } } diff --git a/IRCDDBApp.h b/IRCDDBApp.h index 8a3066d..7677e98 100644 --- a/IRCDDBApp.h +++ b/IRCDDBApp.h @@ -67,7 +67,8 @@ public: bool findRepeater(const std::string& s); bool findGateway(const std::string& s); - bool notifyRepeaterNatTraversal(const std::string& repeater); + bool notifyRepeaterG2NatTraversal(const std::string& repeater); + bool notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myLocalPort); bool sendHeard(const std::string& myCall, const std::string& myCallExt, const std::string& yourCall, const std::string& rpt1, const std::string& rpt2, unsigned char flag1, unsigned char flag2, unsigned char flag3, const std::string& destination, const std::string& tx_msg, const std::string& tx_stats); diff --git a/IRCDDBClient.cpp b/IRCDDBClient.cpp index e95f4b4..60c51b0 100644 --- a/IRCDDBClient.cpp +++ b/IRCDDBClient.cpp @@ -278,9 +278,14 @@ bool CIRCDDBClient::findUser(const std::string& userCallsign) return m_d->m_app->findUser(usr); } -bool CIRCDDBClient::notifyRepeaterNatTraversal(const std::string& repeater) +bool CIRCDDBClient::notifyRepeaterG2NatTraversal(const std::string& repeater) { - return m_d->m_app->notifyRepeaterNatTraversal(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); } // The following functions are for processing received messages @@ -423,7 +428,7 @@ bool CIRCDDBClient::receiveNATTraversalG2(std::string& address) IRCMessage * m = m_d->m_app->getReplyMessage(); if (m == NULL) { - CLog::logDebug("CIRCDDBClient::receiveUser: no message\n"); + CLog::logDebug("CIRCDDBClient::receiveNATTraversalG2: no message\n"); return false; } @@ -445,6 +450,41 @@ bool CIRCDDBClient::receiveNATTraversalG2(std::string& address) 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_G2', 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; +} + void CIRCDDBClient::close() // Implictely kills any threads in the IRC code { m_d->client -> stopWork(); diff --git a/IRCDDBClient.h b/IRCDDBClient.h index 7160b66..a5c8981 100644 --- a/IRCDDBClient.h +++ b/IRCDDBClient.h @@ -107,7 +107,8 @@ public: bool findUser(const std::string& userCallsign); // notify another repeater for NAT Traversal, a false return implies a network error - bool notifyRepeaterNatTraversal(const std::string& repeater); + bool notifyRepeaterG2NatTraversal(const std::string& repeater); + bool notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myport); // Support for the Smart Group Server void sendDStarGatewayInfo(const std::string subcommand, const std::vector parms); @@ -132,6 +133,7 @@ public: bool receiveUser(std::string& userCallsign, std::string& repeaterCallsign, std::string& gatewayCallsign, std::string& address, std::string& timeStamp); bool receiveNATTraversalG2(std::string& address); + bool receiveNATTraversalDextra(std::string& address, std::string& remotePort); void close(); // Implictely kills any threads in the IRC code diff --git a/IRCDDBMultiClient.cpp b/IRCDDBMultiClient.cpp index 49259de..96cb913 100644 --- a/IRCDDBMultiClient.cpp +++ b/IRCDDBMultiClient.cpp @@ -150,7 +150,7 @@ void CIRCDDBMultiClient::sendDStarGatewayInfo(const std::string subcommand, cons bool CIRCDDBMultiClient::findGateway(const std::string & gatewayCallsign) { - pushQuery(IDRT_GATEWAY, gatewayCallsign, new CIRCDDBMultiClientQuery("", "", gatewayCallsign, "", "", IDRT_GATEWAY)); + pushQuery(IDRT_GATEWAY, gatewayCallsign, new CIRCDDBMultiClientQuery("", "", gatewayCallsign, "", "", "", IDRT_GATEWAY)); bool result = true; for (unsigned int i = 0; i < m_clients.size(); i++) { result = m_clients[i]->findGateway(gatewayCallsign) && result; @@ -161,7 +161,7 @@ bool CIRCDDBMultiClient::findGateway(const std::string & gatewayCallsign) bool CIRCDDBMultiClient::findRepeater(const std::string & repeaterCallsign) { - pushQuery(IDRT_REPEATER, repeaterCallsign, new CIRCDDBMultiClientQuery("", repeaterCallsign, "", "", "", IDRT_REPEATER)); + pushQuery(IDRT_REPEATER, repeaterCallsign, new CIRCDDBMultiClientQuery("", repeaterCallsign, "", "", "", "", IDRT_REPEATER)); bool result = true; for (unsigned int i = 0; i < m_clients.size(); i++) { result = m_clients[i]->findRepeater(repeaterCallsign) && result; @@ -172,7 +172,7 @@ bool CIRCDDBMultiClient::findRepeater(const std::string & repeaterCallsign) bool CIRCDDBMultiClient::findUser(const std::string & userCallsign) { - pushQuery(IDRT_USER, userCallsign, new CIRCDDBMultiClientQuery(userCallsign, "", "", "", "", IDRT_USER)); + pushQuery(IDRT_USER, userCallsign, new CIRCDDBMultiClientQuery(userCallsign, "", "", "", "", "", IDRT_USER)); bool result = true; for (unsigned int i = 0; i < m_clients.size(); i++) { result = m_clients[i]->findUser(userCallsign) && result; @@ -181,17 +181,30 @@ bool CIRCDDBMultiClient::findUser(const std::string & userCallsign) return result; } -bool CIRCDDBMultiClient::notifyRepeaterNatTraversal(const std::string& repeater) +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]->notifyRepeaterNatTraversal(repeater) && result; + 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::receiveNATTraversalG2(std::string& address) { CIRCDDBMultiClientQuery * item = checkAndGetNextResponse(IDRT_NATTRAVERSAL_G2, "CIRCDDBMultiClient::receiveNATTraversalG2: unexpected response type"); @@ -203,11 +216,23 @@ bool CIRCDDBMultiClient::receiveNATTraversalG2(std::string& address) 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; +} + IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType() { - //procees the inner clients at each call + //process the inner clients at each call for (unsigned int i = 0; i < m_clients.size(); i++) { - std::string user = "", repeater = "", gateway = "", address = "", timestamp = "", key = ""; + std::string user = "", repeater = "", gateway = "", address = "", timestamp = "", key = "", port =""; IRCDDB_RESPONSE_TYPE type = m_clients[i]->getMessageType(); @@ -234,6 +259,13 @@ IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType() 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_NONE: { default: @@ -250,12 +282,12 @@ IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType() CIRCDDBMultiClientQuery * item = popQuery(type, key); if (item != NULL) {//is this a response to a query we've sent ? - item->Update(user, repeater, gateway, address, timestamp);//update item (if needed) + item->Update(user, repeater, gateway, address, timestamp, port);//update item (if needed) canAddToQueue = (item->incrementResponseCount() >= m_clients.size()); //did all the clients respond or did we have an answer ? wasQuery = true; } else { - item = new CIRCDDBMultiClientQuery(user, repeater, gateway, address, timestamp, type); + item = new CIRCDDBMultiClientQuery(user, repeater, gateway, address, timestamp, port, type); canAddToQueue = true; } diff --git a/IRCDDBMultiClient.h b/IRCDDBMultiClient.h index 18c913f..eff829a 100644 --- a/IRCDDBMultiClient.h +++ b/IRCDDBMultiClient.h @@ -40,12 +40,14 @@ public: const std::string& gateway, const std::string& address, const std::string& timestamp, + const std::string& remotePort, IRCDDB_RESPONSE_TYPE type) : m_user(user), m_repeater(repeater), m_gateway(gateway), m_address(address), m_timestamp(timestamp), + m_remotePort(remotePort), m_type(type), m_responseCount(0) { @@ -77,6 +79,11 @@ public: return m_timestamp; } + std::string getRemotePort() const + { + return m_remotePort; + } + unsigned int getResponseCount() { return m_responseCount; @@ -92,7 +99,7 @@ public: /* Updates the entry, but only if the timestamp is newer. if an address was already specified it is kept. */ - void Update(const std::string& user, const std::string& repeater, const std::string& gateway, const std::string& address, const std::string& timestamp) + void Update(const std::string& user, const std::string& repeater, const std::string& gateway, const std::string& address, const std::string& timestamp, const std::string& remotePort) { //wxLogMessage("Before : %s"), toString()); if (timestamp.empty() || timestamp.compare(m_timestamp) >= 0) { @@ -100,6 +107,7 @@ public: m_repeater = repeater; m_gateway = gateway; m_timestamp = timestamp; + m_remotePort = remotePort; if(m_address.empty() && !address.empty()) m_address = address; @@ -125,6 +133,7 @@ private: std::string m_gateway; std::string m_address; std::string m_timestamp; + std::string m_remotePort; IRCDDB_RESPONSE_TYPE m_type; unsigned int m_responseCount; }; @@ -150,13 +159,15 @@ public: virtual bool findGateway(const std::string & gatewayCallsign); virtual bool findRepeater(const std::string & repeaterCallsign); virtual bool findUser(const std::string & userCallsign); - virtual bool notifyRepeaterNatTraversal(const std::string& repeater); + virtual bool notifyRepeaterG2NatTraversal(const std::string& repeater); + virtual bool notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myPort); virtual IRCDDB_RESPONSE_TYPE getMessageType(); virtual bool receiveRepeater(std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address); virtual bool receiveGateway(std::string & gatewayCallsign, std::string & address); virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address); virtual bool receiveUser(std::string & userCallsign, std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address, std::string & timeStamp); virtual bool receiveNATTraversalG2(std::string& address); + virtual bool receiveNATTraversalDextra(std::string& address, std::string& remotePort); virtual void sendDStarGatewayInfo(const std::string subcommand, const std::vector parms); virtual void close(); diff --git a/RepeaterHandler.cpp b/RepeaterHandler.cpp index 782a39b..01dd1ee 100644 --- a/RepeaterHandler.cpp +++ b/RepeaterHandler.cpp @@ -2057,7 +2057,7 @@ void CRepeaterHandler::g2CommandHandler(const std::string& callsign, const std:: m_g2User = "CQCQCQ "; CRepeaterData* data = m_cache->findRepeater(m_g2Repeater); - m_irc->notifyRepeaterNatTraversal(m_g2Repeater); + m_irc->notifyRepeaterG2NatTraversal(m_g2Repeater); if (data == NULL) { m_g2Status = G2_REPEATER; @@ -2109,7 +2109,7 @@ void CRepeaterHandler::g2CommandHandler(const std::string& callsign, const std:: m_g2User = callsign; m_g2Address = data->getAddress(); m_g2Repeater = data->getRepeater(); - m_irc->notifyRepeaterNatTraversal(m_g2Repeater); + m_irc->notifyRepeaterG2NatTraversal(m_g2Repeater); m_g2Gateway = data->getGateway(); header.setDestination(m_g2Address, G2_DV_PORT); header.setRepeaters(m_g2Gateway, m_g2Repeater); From 3d0b31682ea88f44215fed1b57aecb03ae231ec3 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 19 Jan 2022 19:24:56 +0100 Subject: [PATCH 148/201] #5 send notify messages --- DExtraHandler.cpp | 4 +++- DExtraHandler.h | 2 +- RepeaterHandler.cpp | 13 ++++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/DExtraHandler.cpp b/DExtraHandler.cpp index 68fbd1a..0268b19 100644 --- a/DExtraHandler.cpp +++ b/DExtraHandler.cpp @@ -403,8 +403,9 @@ void CDExtraHandler::process(CConnectData& connect) } } -void CDExtraHandler::link(IReflectorCallback* handler, const std::string& repeater, const std::string &gateway, const in_addr& address) +void CDExtraHandler::link(IReflectorCallback* handler, const std::string& repeater, const std::string &gateway, const in_addr& address, unsigned int& localPort) { + localPort = 0U; CDExtraProtocolHandler* protoHandler = m_pool->getHandler(); if (protoHandler == NULL) return; @@ -422,6 +423,7 @@ void CDExtraHandler::link(IReflectorCallback* handler, const std::string& repeat } if (found) { + localPort = protoHandler->getPort(); CConnectData reply(repeater, gateway, CT_LINK1, address, DEXTRA_PORT); protoHandler->writeConnect(reply); } else { diff --git a/DExtraHandler.h b/DExtraHandler.h index cd9ec0c..0ac616f 100644 --- a/DExtraHandler.h +++ b/DExtraHandler.h @@ -52,7 +52,7 @@ public: static void setHeaderLogger(CHeaderLogger* logger); static void setMaxDongles(unsigned int maxDongles); - static void link(IReflectorCallback* handler, const std::string& repeater, const std::string& reflector, const in_addr& address); + static void link(IReflectorCallback* handler, const std::string& repeater, const std::string& reflector, const in_addr& address, unsigned int& localPort); static void unlink(IReflectorCallback* handler, const std::string& reflector = "", bool exclude = true); static void unlink(); diff --git a/RepeaterHandler.cpp b/RepeaterHandler.cpp index 01dd1ee..cfad808 100644 --- a/RepeaterHandler.cpp +++ b/RepeaterHandler.cpp @@ -1381,8 +1381,9 @@ void CRepeaterHandler::resolveRepeaterInt(const std::string& repeater, const std default: if (m_dextraEnabled) { m_linkGateway = gateway; + unsigned int localPort = 0U; addr.s_addr = ::inet_addr(address.c_str()); - CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, addr); + CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, addr, localPort); m_linkStatus = LS_LINKING_DEXTRA; } else { CLog::logInfo("Require DExtra for linking to %s, but DExtra is disabled", repeater.c_str()); @@ -2321,8 +2322,11 @@ void CRepeaterHandler::linkInt(const std::string& callsign) default: if (m_dextraEnabled) { + unsigned int localPort = 0U; m_linkStatus = LS_LINKING_DEXTRA; - CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress()); + CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress(), localPort); + if(m_irc != nullptr && localPort > 0U) + m_irc->notifyRepeaterDextraNatTraversal(m_linkRepeater, localPort); writeLinkingTo(m_linkRepeater); triggerInfo(); } else { @@ -2493,8 +2497,11 @@ void CRepeaterHandler::startupInt() default: if (m_dextraEnabled) { + unsigned int localPort = 0U; m_linkStatus = LS_LINKING_DEXTRA; - CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress()); + CDExtraHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress(), localPort); + if(m_irc != nullptr && localPort > 0U) + m_irc->notifyRepeaterDextraNatTraversal(m_linkRepeater, localPort); writeLinkingTo(m_linkRepeater); triggerInfo(); } else { From f0dd08b2bc12a9b397e69316d130f64d51f0bfed Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 19 Jan 2022 20:04:40 +0100 Subject: [PATCH 149/201] #5 ensure we always return the incoming handler --- DExtraProtocolHandlerPool.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/DExtraProtocolHandlerPool.cpp b/DExtraProtocolHandlerPool.cpp index 0b77b56..c356858 100644 --- a/DExtraProtocolHandlerPool.cpp +++ b/DExtraProtocolHandlerPool.cpp @@ -43,6 +43,10 @@ CDExtraProtocolHandlerPool::~CDExtraProtocolHandlerPool() CDExtraProtocolHandler* CDExtraProtocolHandlerPool::getIncomingHandler() { + auto it = m_pool.find(m_basePort); + if(it != m_pool.end()) + return it->second; + return getHandler(m_basePort); } From 8a97101e08c334eaeae8aff852a1888fbefedb46 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 19 Jan 2022 20:14:12 +0100 Subject: [PATCH 150/201] #5 fix typo --- IRCDDBApp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index f89a84d..c9ca209 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -661,7 +661,7 @@ bool IRCDDBApp::notifyRepeaterG2NatTraversal(const std::string& repeater) } if(nick.empty()) { - CLog::logDebug("Unable to dind IRC nick for repeater %s", repeater.c_str()); + CLog::logDebug("Unable to find IRC nick for repeater %s", repeater.c_str()); return true; } @@ -691,7 +691,7 @@ bool IRCDDBApp::notifyRepeaterDextraNatTraversal(const std::string& repeater, un } if(nick.empty()) { - CLog::logDebug("Unable to dind IRC nick for repeater %s", repeater.c_str()); + CLog::logDebug("Unable to find IRC nick for repeater %s", repeater.c_str()); return true; } From 06fc2aefb9e1c5b71216e74ea04df9a5cd9cf4d9 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 19 Jan 2022 20:18:07 +0100 Subject: [PATCH 151/201] #5 make sure we always return incoming handler --- DCSProtocolHandlerPool.cpp | 4 ++++ DPlusProtocolHandlerPool.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/DCSProtocolHandlerPool.cpp b/DCSProtocolHandlerPool.cpp index c0c87f8..cc00e43 100644 --- a/DCSProtocolHandlerPool.cpp +++ b/DCSProtocolHandlerPool.cpp @@ -44,6 +44,10 @@ CDCSProtocolHandlerPool::~CDCSProtocolHandlerPool() CDCSProtocolHandler *CDCSProtocolHandlerPool::getIncomingHandler() { + auto it = m_pool.find(m_basePort); + if(it != m_pool.end()) + return it->second; + return getHandler(m_basePort); } diff --git a/DPlusProtocolHandlerPool.cpp b/DPlusProtocolHandlerPool.cpp index db464a8..b9ef667 100644 --- a/DPlusProtocolHandlerPool.cpp +++ b/DPlusProtocolHandlerPool.cpp @@ -44,6 +44,10 @@ CDPlusProtocolHandlerPool::~CDPlusProtocolHandlerPool() CDPlusProtocolHandler* CDPlusProtocolHandlerPool::getIncomingHandler() { + auto it = m_pool.find(m_basePort); + if(it != m_pool.end()) + return it->second; + return getHandler(m_basePort); } From 708bcc07ea375d20f165bf1387d7b751a692ff47 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 19 Jan 2022 20:50:08 +0100 Subject: [PATCH 152/201] #5 add tests for protocol handler pools --- .vscode/tasks.json | 10 ++-- Tests/DCSProtocolHandlerPool/getHandler.cpp | 55 +++++++++++++++++++ .../getIncomingHandler.cpp | 45 +++++++++++++++ Tests/DPlusProtocolHandlerPool/getHandler.cpp | 55 +++++++++++++++++++ .../getIncomingHandler.cpp | 45 +++++++++++++++ .../DextraProtocolHandlerPool/getHandler.cpp | 55 +++++++++++++++++++ .../getIncomingHandler.cpp | 45 +++++++++++++++ 7 files changed, 305 insertions(+), 5 deletions(-) create mode 100644 Tests/DCSProtocolHandlerPool/getHandler.cpp create mode 100644 Tests/DCSProtocolHandlerPool/getIncomingHandler.cpp create mode 100644 Tests/DPlusProtocolHandlerPool/getHandler.cpp create mode 100644 Tests/DPlusProtocolHandlerPool/getIncomingHandler.cpp create mode 100644 Tests/DextraProtocolHandlerPool/getHandler.cpp create mode 100644 Tests/DextraProtocolHandlerPool/getIncomingHandler.cpp diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 168ca95..ac3f100 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,10 +12,7 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] }, { @@ -28,7 +25,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] } ] diff --git a/Tests/DCSProtocolHandlerPool/getHandler.cpp b/Tests/DCSProtocolHandlerPool/getHandler.cpp new file mode 100644 index 0000000..3d31874 --- /dev/null +++ b/Tests/DCSProtocolHandlerPool/getHandler.cpp @@ -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 + +#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); + } +} \ No newline at end of file diff --git a/Tests/DCSProtocolHandlerPool/getIncomingHandler.cpp b/Tests/DCSProtocolHandlerPool/getIncomingHandler.cpp new file mode 100644 index 0000000..f4c3f34 --- /dev/null +++ b/Tests/DCSProtocolHandlerPool/getIncomingHandler.cpp @@ -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 + +#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); + } +} \ No newline at end of file diff --git a/Tests/DPlusProtocolHandlerPool/getHandler.cpp b/Tests/DPlusProtocolHandlerPool/getHandler.cpp new file mode 100644 index 0000000..2389298 --- /dev/null +++ b/Tests/DPlusProtocolHandlerPool/getHandler.cpp @@ -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 + +#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); + } +} \ No newline at end of file diff --git a/Tests/DPlusProtocolHandlerPool/getIncomingHandler.cpp b/Tests/DPlusProtocolHandlerPool/getIncomingHandler.cpp new file mode 100644 index 0000000..a27dbd9 --- /dev/null +++ b/Tests/DPlusProtocolHandlerPool/getIncomingHandler.cpp @@ -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 + +#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); + } +} \ No newline at end of file diff --git a/Tests/DextraProtocolHandlerPool/getHandler.cpp b/Tests/DextraProtocolHandlerPool/getHandler.cpp new file mode 100644 index 0000000..bc7c805 --- /dev/null +++ b/Tests/DextraProtocolHandlerPool/getHandler.cpp @@ -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 + +#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); + } +} \ No newline at end of file diff --git a/Tests/DextraProtocolHandlerPool/getIncomingHandler.cpp b/Tests/DextraProtocolHandlerPool/getIncomingHandler.cpp new file mode 100644 index 0000000..c6bfbc5 --- /dev/null +++ b/Tests/DextraProtocolHandlerPool/getIncomingHandler.cpp @@ -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 + +#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); + } +} \ No newline at end of file From 0050ac116c411054bd23663f12e6138462a482d6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 21 Jan 2022 17:12:06 +0100 Subject: [PATCH 153/201] #5 Update Readme --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e89f7bd..a2778e4 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ the testing framwework used is Google Test. # 5. Version History ## 5.1. Version 0.5 +- [Improvement] Add NAT Traversal for G2 and DExtra, using IRCDDB as a Rendez Vous server - [Improvement] Add forwarding of RS-MS1A messages to APRS-IS ([#9](https://github.com/F4FXL/DStarGateway/issues/9)) - [Bugfix] Failed to download XLX Hosts when URL contains a = sign ([#14](https://github.com/F4FXL/DStarGateway/issues/14)) - [Bugfix] Remote control connection failed ([#13](https://github.com/F4FXL/DStarGateway/issues/13)) @@ -145,9 +146,9 @@ the testing framwework used is Google Test. First working version # 6. Future I started this during my 2021 seasons holiday. It took me almost 8 days to get to a workable version. Here are a couple of stuff I'd like to do : -- ☒ Better NatTraversal +- ☑ Better NatTraversal - No banging on every gateway: use ircDDB (or something else) as mitigation server to notify peer - - Support for all protocols (G2, DExtra, DCS, REF) + - Support for all protocols (G2, DExtra, DCS (?), DPlus) - A [branch](https://github.com/F4FXL/DStarGateway/tree/feature/NatTraversal) already exists for this - ☑ Send the connection status to APRS-IS as a status frame - ☒ Reinstantiate DRATS From a1a783b64d215b3270e4db2d641e36454d12f35c Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 21 Jan 2022 18:20:55 +0100 Subject: [PATCH 154/201] #5 Add Dplus NAT Traversal --- .vscode/tasks.json | 10 ++--- DPlusHandler.cpp | 4 +- DPlusHandler.h | 2 +- DPlusProtocolHandler.cpp | 13 +++++- DPlusProtocolHandler.h | 2 + DStarGatewayThread.cpp | 17 +++++++- IRCDDB.h | 3 ++ IRCDDBApp.cpp | 85 +++++++++++++++++++++++----------------- IRCDDBApp.h | 3 ++ IRCDDBClient.cpp | 42 +++++++++++++++++++- IRCDDBClient.h | 2 + IRCDDBMultiClient.cpp | 21 ++++++++++ IRCDDBMultiClient.h | 2 + RepeaterHandler.cpp | 13 ++++-- 14 files changed, 170 insertions(+), 49 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index ac3f100..168ca95 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,7 +12,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] }, { @@ -25,10 +28,7 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] } ] diff --git a/DPlusHandler.cpp b/DPlusHandler.cpp index aa78395..178eefd 100644 --- a/DPlusHandler.cpp +++ b/DPlusHandler.cpp @@ -357,8 +357,9 @@ void CDPlusHandler::process(CConnectData& connect) } } -void CDPlusHandler::link(IReflectorCallback* handler, const std::string& repeater, const std::string &gateway, const in_addr& address) +void CDPlusHandler::link(IReflectorCallback* handler, const std::string& repeater, const std::string &gateway, const in_addr& address, unsigned int& localPort) { + localPort = 0U; CDPlusProtocolHandler* protoHandler = m_pool->getHandler(); if (protoHandler == NULL) return; @@ -377,6 +378,7 @@ void CDPlusHandler::link(IReflectorCallback* handler, const std::string& repeate if (found) { CConnectData connect(CT_LINK1, address, DPLUS_PORT); + localPort = protoHandler->getPort(); protoHandler->writeConnect(connect); m_stateChange = true; } else { diff --git a/DPlusHandler.h b/DPlusHandler.h index 2e6ea83..78b5b7a 100644 --- a/DPlusHandler.h +++ b/DPlusHandler.h @@ -58,7 +58,7 @@ public: static void startAuthenticator(const std::string& address, CCacheManager* cache); - static void link(IReflectorCallback* handler, const std::string& repeater, const std::string& reflector, const in_addr& address); + static void link(IReflectorCallback* handler, const std::string& repeater, const std::string& reflector, const in_addr& address, unsigned int& localPort); static void relink(IReflectorCallback* handler, const std::string& reflector); static void unlink(IReflectorCallback* handler, const std::string& reflector = "", bool exclude = true); static void unlink(); diff --git a/DPlusProtocolHandler.cpp b/DPlusProtocolHandler.cpp index 7414aa0..41e1e21 100644 --- a/DPlusProtocolHandler.cpp +++ b/DPlusProtocolHandler.cpp @@ -18,7 +18,7 @@ */ #include "DPlusProtocolHandler.h" - +#include "Log.h" #include "DStarDefines.h" #include "Utils.h" @@ -107,6 +107,17 @@ bool CDPlusProtocolHandler::writeConnect(const CConnectData& connect) return m_socket.write(buffer, length, connect.getYourAddress(), connect.getYourPort()); } +void CDPlusProtocolHandler::traverseNat(const std::string& address, unsigned int remotePort) +{ + unsigned char buffer = 0x00U; + + in_addr addr = CUDPReaderWriter::lookup(address); + + CLog::logInfo("DPlus Punching hole to %s:%u", address.c_str(), remotePort); + + m_socket.write(&buffer, 1U, addr, remotePort); +} + DPLUS_TYPE CDPlusProtocolHandler::read() { bool res = true; diff --git a/DPlusProtocolHandler.h b/DPlusProtocolHandler.h index 85b51f6..144dcf6 100644 --- a/DPlusProtocolHandler.h +++ b/DPlusProtocolHandler.h @@ -27,6 +27,7 @@ #include "PollData.h" #include +#include enum DPLUS_TYPE { DP_NONE, @@ -49,6 +50,7 @@ public: bool writeAMBE(const CAMBEData& data); bool writeConnect(const CConnectData& connect); bool writePoll(const CPollData& poll); + void traverseNat(const std::string& address, unsigned int remotePort); DPLUS_TYPE read(); CHeaderData* readHeader(); diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index 765179a..5229ceb 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -799,7 +799,6 @@ void CDStarGatewayThread::processIrcDDB() } break; case IDRT_NATTRAVERSAL_DEXTRA: { - std::string address, remotePort; bool res = m_irc->receiveNATTraversalDextra(address, remotePort); if(!res) @@ -814,6 +813,22 @@ void CDStarGatewayThread::processIrcDDB() 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; + + if(m_dextraEnabled && m_dextraPool != 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()); + auto remotePortInt = boost::lexical_cast(remotePort); + 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 DExtra is Disabled", address.c_str(), remotePort.c_str()); + } + } break; case IDRT_NONE: return; diff --git a/IRCDDB.h b/IRCDDB.h index b285119..6b5534a 100644 --- a/IRCDDB.h +++ b/IRCDDB.h @@ -34,6 +34,7 @@ enum IRCDDB_RESPONSE_TYPE { IDRT_REPEATER, IDRT_NATTRAVERSAL_G2, IDRT_NATTRAVERSAL_DEXTRA, + IDRT_NATTRAVERSAL_DPLUS, }; @@ -117,6 +118,7 @@ public: // notify another repeater for NAT Traversal, a false return implies a network error virtual bool notifyRepeaterG2NatTraversal(const std::string& repeater) = 0; virtual bool notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myport) = 0; + virtual bool notifyRepeaterDPlusNatTraversal(const std::string& repeater, unsigned int myport) = 0; // Support for the Smart Group Server virtual void sendDStarGatewayInfo(const std::string subcommand, const std::vector parms) = 0; @@ -142,6 +144,7 @@ public: 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 }; diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index c9ca209..7599bd8 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -262,6 +262,9 @@ IRCDDB_RESPONSE_TYPE IRCDDBApp::getReplyMessageType() if(msgType.compare("NATTRAVERSAL_DEXTRA") == 0) return IDRT_NATTRAVERSAL_DEXTRA; + if(msgType.compare("NATTRAVERSAL_DPLUS") == 0) + return IDRT_NATTRAVERSAL_DPLUS; + CLog::logWarning("IRCDDBApp::getMessageType: unknown msg type: %s\n", msgType.c_str()); return IDRT_NONE; @@ -643,27 +646,10 @@ bool IRCDDBApp::findUser(const std::string& usrCall) bool IRCDDBApp::notifyRepeaterG2NatTraversal(const std::string& repeater) { - auto firstSpacePos = repeater.find_first_of(' '); - if(firstSpacePos == std::string::npos) - return true; - - auto lrepeater = repeater.substr(0, firstSpacePos); - CUtils::ToLower(lrepeater); std::string nick; - std::lock_guard loclUserMap(m_d->m_userMapMutex); - for(unsigned int i = 1; i <= 4U; i++) { - nick = lrepeater + "-" + std::to_string(i); - if(m_d->m_userMap.count(nick) == 1) { - break; - } - nick.clear(); - } - - if(nick.empty()) { - CLog::logDebug("Unable to find IRC nick for repeater %s", repeater.c_str()); - return true; - } + if(!getNickForRepeater(repeater, nick)) + return true; //return true because this return value is handled as a network error, whoch is actually uncleve IRCMessage * ircMessage = new IRCMessage(nick, "NATTRAVERSAL_G2"); m_d->m_sendQ->putMessage(ircMessage); @@ -673,33 +659,53 @@ bool IRCDDBApp::notifyRepeaterG2NatTraversal(const std::string& repeater) bool IRCDDBApp::notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myLocalPort) { + std::string nick; + + if(!getNickForRepeater(repeater, nick)) + return true; //return true because this return value is handled as a network error, whoch is actually uncleve + + IRCMessage * ircMessage = new IRCMessage(nick, "NATTRAVERSAL_DEXTRA"); + ircMessage->addParam(std::to_string(myLocalPort)); + m_d->m_sendQ->putMessage(ircMessage); + + return true; +} + +bool IRCDDBApp::notifyRepeaterDPlusNatTraversal(const std::string& repeater, unsigned int myLocalPort) +{ + std::string nick; + + if(!getNickForRepeater(repeater, nick)) + return true; //return true because this return value is handled as a network error, whoch is actually unclever + + IRCMessage * ircMessage = new IRCMessage(nick, "NATTRAVERSAL_DPLUS"); + ircMessage->addParam(std::to_string(myLocalPort)); + m_d->m_sendQ->putMessage(ircMessage); + + return true; +} + +bool IRCDDBApp::getNickForRepeater(const std::string& repeater, std::string& nick) const +{ + std::lock_guard lockUserMap(m_d->m_userMapMutex); + auto firstSpacePos = repeater.find_first_of(' '); if(firstSpacePos == std::string::npos) - return true; - + return false; + auto lrepeater = repeater.substr(0, firstSpacePos); CUtils::ToLower(lrepeater); - std::string nick; - - std::lock_guard loclUserMap(m_d->m_userMapMutex); + for(unsigned int i = 1; i <= 4U; i++) { nick = lrepeater + "-" + std::to_string(i); if(m_d->m_userMap.count(nick) == 1) { - break; + return true; } - nick.clear(); - } - - if(nick.empty()) { - CLog::logDebug("Unable to find IRC nick for repeater %s", repeater.c_str()); - return true; } - IRCMessage * ircMessage = new IRCMessage(nick, "NATTRAVERSAL_DEXTRA"); - ircMessage->addParam(std::to_string(myLocalPort)); - m_d->m_sendQ->putMessage(ircMessage); - - return true; + nick.clear(); + CLog::logDebug("Unable to find IRC nick for repeater %s", repeater.c_str()); + return false; } void IRCDDBApp::msgChannel(IRCMessage *m) @@ -919,6 +925,13 @@ void IRCDDBApp::msgQuery(IRCMessage *m) m2->addParam(remotePort); m_d->m_replyQ.putMessage(m2); } + else if(m->m_params.size() >= 2U && boost::starts_with(m->m_params[1], "NATTRAVERSAL_DPLUS")) { + IRCMessage * m2 = new IRCMessage(m->m_params[1].substr(0, (std::string("NATTRAVERSAL_DPLUS")).length())); + m2->addParam(m->getPrefixHost()); + std::string remotePort = boost::trim_copy(boost::replace_all_copy(m->m_params[1], "NATTRAVERSAL_DPLUS", "")); + m2->addParam(remotePort); + m_d->m_replyQ.putMessage(m2); + } } } diff --git a/IRCDDBApp.h b/IRCDDBApp.h index 7677e98..c88935e 100644 --- a/IRCDDBApp.h +++ b/IRCDDBApp.h @@ -69,6 +69,7 @@ public: bool notifyRepeaterG2NatTraversal(const std::string& repeater); bool notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myLocalPort); + bool notifyRepeaterDPlusNatTraversal(const std::string& repeater, unsigned int myLocalPort); bool sendHeard(const std::string& myCall, const std::string& myCallExt, const std::string& yourCall, const std::string& rpt1, const std::string& rpt2, unsigned char flag1, unsigned char flag2, unsigned char flag3, const std::string& destination, const std::string& tx_msg, const std::string& tx_stats); @@ -93,6 +94,8 @@ private: bool findServerUser(); unsigned int calculateUsn(const std::string& nick); std::string getLastEntryTime(int tableID); + bool getNickForRepeater(const std::string& repeater, std::string& user) const; + IRCDDBAppPrivate *m_d; time_t m_maxTime; std::future m_future; diff --git a/IRCDDBClient.cpp b/IRCDDBClient.cpp index 60c51b0..644ef35 100644 --- a/IRCDDBClient.cpp +++ b/IRCDDBClient.cpp @@ -288,6 +288,11 @@ bool CIRCDDBClient::notifyRepeaterDextraNatTraversal(const std::string& repeater 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 // Get the waiting message type @@ -467,7 +472,7 @@ bool CIRCDDBClient::receiveNATTraversalDextra(std::string& address, std::string& } if (m->getCommand().compare("NATTRAVERSAL_DEXTRA")) { - CLog::logDebug("CIRCDDBClient::receiveNATTraversalDextra: wrong message type, expected 'NATTRAVERSAL_G2', got '%s'\n", m->getCommand().c_str()); + CLog::logDebug("CIRCDDBClient::receiveNATTraversalDextra: wrong message type, expected 'NATTRAVERSAL_DEXTRA', got '%s'\n", m->getCommand().c_str()); delete m; return false; } @@ -485,6 +490,41 @@ bool CIRCDDBClient::receiveNATTraversalDextra(std::string& address, std::string& 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(); diff --git a/IRCDDBClient.h b/IRCDDBClient.h index a5c8981..4a0f8d2 100644 --- a/IRCDDBClient.h +++ b/IRCDDBClient.h @@ -109,6 +109,7 @@ public: // notify another repeater for NAT Traversal, a false return implies a network error bool notifyRepeaterG2NatTraversal(const std::string& repeater); bool notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myport); + bool notifyRepeaterDPlusNatTraversal(const std::string& repeater, unsigned int myport); // Support for the Smart Group Server void sendDStarGatewayInfo(const std::string subcommand, const std::vector parms); @@ -134,6 +135,7 @@ public: 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 diff --git a/IRCDDBMultiClient.cpp b/IRCDDBMultiClient.cpp index 96cb913..a7fd1fd 100644 --- a/IRCDDBMultiClient.cpp +++ b/IRCDDBMultiClient.cpp @@ -203,7 +203,16 @@ bool CIRCDDBMultiClient::notifyRepeaterDextraNatTraversal(const std::string& rep 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) { @@ -228,6 +237,18 @@ bool CIRCDDBMultiClient::receiveNATTraversalDextra(std::string& address, std::st 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() { //process the inner clients at each call diff --git a/IRCDDBMultiClient.h b/IRCDDBMultiClient.h index eff829a..2b47a5f 100644 --- a/IRCDDBMultiClient.h +++ b/IRCDDBMultiClient.h @@ -161,6 +161,7 @@ public: virtual bool findUser(const std::string & userCallsign); virtual bool notifyRepeaterG2NatTraversal(const std::string& repeater); virtual bool notifyRepeaterDextraNatTraversal(const std::string& repeater, unsigned int myPort); + virtual bool notifyRepeaterDPlusNatTraversal(const std::string& repeater, unsigned int myPort); virtual IRCDDB_RESPONSE_TYPE getMessageType(); virtual bool receiveRepeater(std::string & repeaterCallsign, std::string & gatewayCallsign, std::string & address); virtual bool receiveGateway(std::string & gatewayCallsign, std::string & address); @@ -168,6 +169,7 @@ public: 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 parms); virtual void close(); diff --git a/RepeaterHandler.cpp b/RepeaterHandler.cpp index cfad808..b88bea2 100644 --- a/RepeaterHandler.cpp +++ b/RepeaterHandler.cpp @@ -1342,8 +1342,9 @@ void CRepeaterHandler::resolveRepeaterInt(const std::string& repeater, const std case DP_DPLUS: if (m_dplusEnabled) { m_linkGateway = gateway; + unsigned int localPort = 0U; addr.s_addr = ::inet_addr(address.c_str()); - CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, addr); + CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, addr, localPort); m_linkStatus = LS_LINKING_DPLUS; } else { CLog::logInfo("Require D-Plus for linking to %s, but D-Plus is disabled", repeater.c_str()); @@ -2287,8 +2288,11 @@ void CRepeaterHandler::linkInt(const std::string& callsign) switch (data->getProtocol()) { case DP_DPLUS: if (m_dplusEnabled) { + unsigned int localPort = 0U; m_linkStatus = LS_LINKING_DPLUS; - CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress()); + CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress(), localPort); + if(m_irc != nullptr && localPort > 0U) + m_irc->notifyRepeaterDPlusNatTraversal(m_linkRepeater, localPort); writeLinkingTo(m_linkRepeater); triggerInfo(); } else { @@ -2462,8 +2466,11 @@ void CRepeaterHandler::startupInt() switch (protocol) { case DP_DPLUS: if (m_dplusEnabled) { + unsigned int localPort = 0U; m_linkStatus = LS_LINKING_DPLUS; - CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress()); + CDPlusHandler::link(this, m_rptCallsign, m_linkRepeater, data->getAddress(), localPort); + if(m_irc != nullptr && localPort > 0U) + m_irc->notifyRepeaterDPlusNatTraversal(m_linkRepeater, localPort); writeLinkingTo(m_linkRepeater); triggerInfo(); } else { From b22affb68320b8d969cd21965ab09f71c2393572 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 21 Jan 2022 18:41:12 +0100 Subject: [PATCH 155/201] #5 fix copy paste error and add missing case --- DStarGatewayThread.cpp | 2 +- IRCDDBMultiClient.cpp | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index 5229ceb..afc6533 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -820,7 +820,7 @@ void CDStarGatewayThread::processIrcDDB() if(!res) return; - if(m_dextraEnabled && m_dextraPool != nullptr && m_dplusPool->getIncomingHandler() != nullptr) { + if(m_dplusEnabled && 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()); auto remotePortInt = boost::lexical_cast(remotePort); m_dplusPool->getIncomingHandler()->traverseNat(address, remotePortInt); diff --git a/IRCDDBMultiClient.cpp b/IRCDDBMultiClient.cpp index a7fd1fd..bd8378e 100644 --- a/IRCDDBMultiClient.cpp +++ b/IRCDDBMultiClient.cpp @@ -288,6 +288,12 @@ IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType() key = "NAT_TRAVERSAL_DEXTRA"; break; } + case IDRT_NATTRAVERSAL_DPLUS: { + if (!m_clients[i]->receiveNATTraversalDPlus(address, port)) + type = IDRT_NATTRAVERSAL_DEXTRA; + key = "NAT_TRAVERSAL_DPLUS"; + break; + } case IDRT_NONE: { default: break; From ca226e5d45523b01f047c43d978ed7015226f6c4 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 21 Jan 2022 20:08:06 +0100 Subject: [PATCH 156/201] #5 make sure we do not crash on illegal port --- .vscode/tasks.json | 10 +++--- DStarGatewayThread.cpp | 9 +++-- StringUtils.cpp | 17 +++++++++ StringUtils.h | 2 ++ Tests/StringUtils/stringToPort.cpp | 57 ++++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 Tests/StringUtils/stringToPort.cpp diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 168ca95..ac3f100 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,10 +12,7 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] }, { @@ -28,7 +25,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] } ] diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index afc6533..3c030e2 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include "DStarGatewayThread.h" #include "DStarGatewayDefs.h" @@ -804,9 +803,9 @@ void CDStarGatewayThread::processIrcDDB() if(!res) return; - if(m_dextraEnabled && m_dextraPool != nullptr && m_dextraPool->getIncomingHandler() != nullptr) { + 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()); - auto remotePortInt = boost::lexical_cast(remotePort); m_dextraPool->getIncomingHandler()->traverseNat(address, remotePortInt); } else { @@ -820,9 +819,9 @@ void CDStarGatewayThread::processIrcDDB() if(!res) return; - if(m_dplusEnabled && m_dplusPool != nullptr && m_dplusPool->getIncomingHandler() != nullptr) { + 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()); - auto remotePortInt = boost::lexical_cast(remotePort); m_dplusPool->getIncomingHandler()->traverseNat(address, remotePortInt); } else { diff --git a/StringUtils.cpp b/StringUtils.cpp index 63de202..9a98c88 100644 --- a/StringUtils.cpp +++ b/StringUtils.cpp @@ -16,6 +16,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include +#include + #include "StringUtils.h" size_t CStringUtils::find_nth(const std::string& haystack, char needle, size_t nth) @@ -32,4 +35,18 @@ size_t CStringUtils::find_nth(const std::string& haystack, char needle, size_t n } return std::string::npos; +} + +unsigned int CStringUtils::stringToPort(const std::string& s) +{ + unsigned int port = 0U; + std::string ls = boost::trim_copy(s); + + if(!ls.empty() && std::all_of(ls.begin(), ls.end(), [](char c){ return c > '0' && c < '9'; })) { + auto portTemp = boost::lexical_cast(ls); + if(portTemp > 0U && portTemp <= 65535U) + port = portTemp; + } + + return port; } \ No newline at end of file diff --git a/StringUtils.h b/StringUtils.h index ccb7294..5df05ab 100644 --- a/StringUtils.h +++ b/StringUtils.h @@ -52,4 +52,6 @@ public: } static size_t find_nth(const std::string& haystack, char needle, size_t nth); + + static unsigned int stringToPort(const std::string& s); }; diff --git a/Tests/StringUtils/stringToPort.cpp b/Tests/StringUtils/stringToPort.cpp new file mode 100644 index 0000000..b4923ea --- /dev/null +++ b/Tests/StringUtils/stringToPort.cpp @@ -0,0 +1,57 @@ +/* + * 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 + +#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); + } +} \ No newline at end of file From b103ae9e3a45ed43d96890bcc393dc752160d220 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 21 Jan 2022 20:56:55 +0100 Subject: [PATCH 157/201] #5 fix typo --- DStarGatewayThread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index 3c030e2..6b8d810 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -825,7 +825,7 @@ void CDStarGatewayThread::processIrcDDB() 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 DExtra is Disabled", address.c_str(), remotePort.c_str()); + 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; From b7ac29589d8d502e8a04521950c7191435b9851c Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 21 Jan 2022 20:58:43 +0100 Subject: [PATCH 158/201] #5 fix stupid port conversion bug --- StringUtils.cpp | 2 +- Tests/StringUtils/stringToPort.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/StringUtils.cpp b/StringUtils.cpp index 9a98c88..a20a6ec 100644 --- a/StringUtils.cpp +++ b/StringUtils.cpp @@ -42,7 +42,7 @@ 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'; })) { + if(!ls.empty() && std::all_of(ls.begin(), ls.end(), [](char c){ return c >= '0' && c <= '9'; })) { auto portTemp = boost::lexical_cast(ls); if(portTemp > 0U && portTemp <= 65535U) port = portTemp; diff --git a/Tests/StringUtils/stringToPort.cpp b/Tests/StringUtils/stringToPort.cpp index b4923ea..b3cc740 100644 --- a/Tests/StringUtils/stringToPort.cpp +++ b/Tests/StringUtils/stringToPort.cpp @@ -54,4 +54,33 @@ namespace StringUtilsTests 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); + } } \ No newline at end of file From 4db1455c682122944b86baa4b983ff633c6d7b57 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 21 Jan 2022 22:27:49 +0100 Subject: [PATCH 159/201] #5 fix "NOT FOUND bug on irc receive user" --- .vscode/tasks.json | 10 +++++----- IRCDDBApp.cpp | 17 ++++++++++++++++- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index ac3f100..168ca95 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,7 +12,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] }, { @@ -25,10 +28,7 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] } ] diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index 7599bd8..9615cb6 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -87,6 +87,7 @@ public: , m_datePattern("^20[0-9][0-9]-((1[0-2])|(0[1-9]))-((3[01])|([12][0-9])|(0[1-9]))$") , m_timePattern("^((2[0-3])|([01][0-9])):[0-5][0-9]:[0-5][0-9]$") , m_dbPattern("^[0-9A-Z_]{8}$") + , m_fromPattern("\\(from: (.*)\\)") { } @@ -108,6 +109,7 @@ public: std::regex m_datePattern; std::regex m_timePattern; std::regex m_dbPattern; + std::regex m_fromPattern; bool m_initReady; bool m_terminateThread; @@ -830,12 +832,25 @@ void IRCDDBApp::doUpdate(std::string& msg) CUtils::ReplaceChar(arearp_cs, '_', ' '); if (1 == m_d->m_rptrMap.count(value)) { + CLog::logTrace("doUptate RPTR already prsent"); IRCDDBAppRptrObject o = m_d->m_rptrMap[value]; zonerp_cs = o.m_zonerp_cs; CUtils::ReplaceChar(zonerp_cs, '_', ' '); zonerp_cs.resize(7, ' '); + ip_addr = getIPAddress(zonerp_cs); zonerp_cs.push_back('G'); - ip_addr = getIPAddress(o.m_zonerp_cs); + } + else { + CLog::logTrace("doUptate RPTR not present"); + zonerp_cs = arearp_cs.substr(0, arearp_cs.length() - 1U); + ip_addr = getIPAddress(zonerp_cs); + zonerp_cs.push_back('G'); + + if(!ip_addr.empty()) { + auto tmp = boost::replace_all_copy(zonerp_cs, " ", "_"); + IRCDDBAppRptrObject newRptr(dt, value, tmp, m_maxTime); + m_d->m_rptrMap[value] = newRptr; + } } IRCMessage *m2 = new IRCMessage("IDRT_USER"); From 88cdfd4a15a4547b8a9d22a1f41fbdf18d7c2fe6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 21 Jan 2022 22:35:34 +0100 Subject: [PATCH 160/201] fix typo --- IRCDDBApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index 9615cb6..5db2926 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -832,7 +832,7 @@ void IRCDDBApp::doUpdate(std::string& msg) CUtils::ReplaceChar(arearp_cs, '_', ' '); if (1 == m_d->m_rptrMap.count(value)) { - CLog::logTrace("doUptate RPTR already prsent"); + CLog::logTrace("doUptate RPTR already present"); IRCDDBAppRptrObject o = m_d->m_rptrMap[value]; zonerp_cs = o.m_zonerp_cs; CUtils::ReplaceChar(zonerp_cs, '_', ' '); From 0afad78fbcb8bd52381900359d263141b02e1fad Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 21 Jan 2022 22:56:26 +0100 Subject: [PATCH 161/201] #5 always get ip from nick --- IRCDDBApp.cpp | 28 ++++++++++++++++++++++------ IRCDDBApp.h | 3 ++- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index 5db2926..5416d31 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -449,7 +449,7 @@ void IRCDDBApp::userChanOp(const std::string& nick, bool op) static const int numberOfTables = 2; -std::string IRCDDBApp::getIPAddress(std::string& zonerp_cs) +std::string IRCDDBApp::getIPAddressFromCall(std::string& zonerp_cs) { unsigned int max_usn = 0; std::string ipAddr; @@ -474,13 +474,24 @@ std::string IRCDDBApp::getIPAddress(std::string& zonerp_cs) return ipAddr; } +std::string IRCDDBApp::getIPAddressFromNick(std::string& ircUser) +{ + std::string ipAddress; + + if (m_d->m_userMap.count(ircUser) == 1) { + ipAddress.assign(m_d->m_userMap[ircUser].m_host); + } + + return ipAddress; +} + bool IRCDDBApp::findGateway(const std::string& gwCall) { std::string s = gwCall.substr(0,6); IRCMessage *m2 = new IRCMessage("IDRT_GATEWAY"); m2->addParam(gwCall); - m2->addParam(getIPAddress(s)); + m2->addParam(getIPAddressFromCall(s)); m_d->m_replyQ.putMessage(m2); return true; @@ -545,7 +556,7 @@ bool IRCDDBApp::findRepeater(const std::string& rptrCall) IRCMessage * m2 = new IRCMessage("IDRT_REPEATER"); m2->addParam(rptrCall); m2->addParam(zonerp_cs); - m2->addParam(getIPAddress(s)); + m2->addParam(getIPAddressFromCall(s)); m_d->m_replyQ.putMessage(m2); return true; @@ -819,7 +830,7 @@ void IRCDDBApp::doUpdate(std::string& msg) IRCMessage *m2 = new IRCMessage("IDRT_REPEATER"); m2->addParam(arearp_cs); m2->addParam(zonerp_cs); - m2->addParam(getIPAddress(value)); + m2->addParam(getIPAddressFromCall(value)); m_d->m_replyQ.putMessage(m2); } } else if (0==tableID && m_d->m_initReady) { @@ -831,19 +842,24 @@ void IRCDDBApp::doUpdate(std::string& msg) CUtils::ReplaceChar(userCallsign, '_', ' '); CUtils::ReplaceChar(arearp_cs, '_', ' '); + std::smatch sm1; + std::string nick; + if(std::regex_search(msg, sm1, m_d->m_fromPattern)) + nick = sm1[1]; + if (1 == m_d->m_rptrMap.count(value)) { CLog::logTrace("doUptate RPTR already present"); IRCDDBAppRptrObject o = m_d->m_rptrMap[value]; zonerp_cs = o.m_zonerp_cs; CUtils::ReplaceChar(zonerp_cs, '_', ' '); zonerp_cs.resize(7, ' '); - ip_addr = getIPAddress(zonerp_cs); + ip_addr = nick.empty() ? getIPAddressFromCall(zonerp_cs) : getIPAddressFromNick(nick); zonerp_cs.push_back('G'); } else { CLog::logTrace("doUptate RPTR not present"); zonerp_cs = arearp_cs.substr(0, arearp_cs.length() - 1U); - ip_addr = getIPAddress(zonerp_cs); + ip_addr = nick.empty() ? getIPAddressFromCall(zonerp_cs) : getIPAddressFromNick(nick); zonerp_cs.push_back('G'); if(!ip_addr.empty()) { diff --git a/IRCDDBApp.h b/IRCDDBApp.h index c88935e..a53ed34 100644 --- a/IRCDDBApp.h +++ b/IRCDDBApp.h @@ -90,7 +90,8 @@ protected: private: void doUpdate(std::string& msg); void doNotFound(std::string& msg, std::string& retval); - std::string getIPAddress(std::string& zonerp_cs); + std::string getIPAddressFromCall(std::string& zonerp_cs); + std::string getIPAddressFromNick(std::string& ircUser); bool findServerUser(); unsigned int calculateUsn(const std::string& nick); std::string getLastEntryTime(int tableID); From eab9bf81255267e57f4e040cc29555b88ba3df53 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 22 Jan 2022 07:08:47 +0100 Subject: [PATCH 162/201] Fix no longr able to write to log after log has been trucnated --- LogFileTarget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/LogFileTarget.cpp b/LogFileTarget.cpp index f40dc3c..d99d09e 100644 --- a/LogFileTarget.cpp +++ b/LogFileTarget.cpp @@ -95,6 +95,7 @@ void CLogFileTarget::printLogIntRotate(const std::string& msg) } void CLogFileTarget::printLogInt(const std::string& msg) { + m_file.seekp(0, std::ios::end); if(m_rotate) printLogIntRotate(msg); else From 5798afda18ae77e3a991bdd5148b4a385ce526b9 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 22 Jan 2022 07:17:10 +0100 Subject: [PATCH 163/201] #5 update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a2778e4..cb7ce3c 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,7 @@ First working version 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 : - ☑ Better NatTraversal - No banging on every gateway: use ircDDB (or something else) as mitigation server to notify peer - - Support for all protocols (G2, DExtra, DCS (?), DPlus) + - 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 - ☑ Send the connection status to APRS-IS as a status frame - ☒ Reinstantiate DRATS From 2e5927a644ff5dcd828b35dffade3df2be6a0fe3 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 22 Jan 2022 07:21:21 +0100 Subject: [PATCH 164/201] Udpate readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cb7ce3c..e938cb4 100644 --- a/README.md +++ b/README.md @@ -127,7 +127,7 @@ the testing framwework used is Google Test. # 5. Version History ## 5.1. Version 0.5 -- [Improvement] Add NAT Traversal for G2 and DExtra, using IRCDDB as a Rendez Vous server +- [Improvement] Add NAT Traversal for G2 and DExtra, using IRCDDB as a Rendez Vous server ([#5](https://github.com/F4FXL/DStarGateway/issues/5)) - [Improvement] Add forwarding of RS-MS1A messages to APRS-IS ([#9](https://github.com/F4FXL/DStarGateway/issues/9)) - [Bugfix] Failed to download XLX Hosts when URL contains a = sign ([#14](https://github.com/F4FXL/DStarGateway/issues/14)) - [Bugfix] Remote control connection failed ([#13](https://github.com/F4FXL/DStarGateway/issues/13)) From 41e89227728b1670a3a415080d9a33c76edb027a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 22 Jan 2022 16:00:20 +0100 Subject: [PATCH 165/201] #5 Add netutils --- .vscode/tasks.json | 10 +++--- NetUtils.cpp | 49 +++++++++++++++++++++++++ NetUtils.h | 30 ++++++++++++++++ Tests/NetUtils/lookup.cpp | 59 +++++++++++++++++++++++++++++++ Tests/NetUtils/lookupPreferV6.cpp | 58 ++++++++++++++++++++++++++++++ 5 files changed, 201 insertions(+), 5 deletions(-) create mode 100644 NetUtils.cpp create mode 100644 NetUtils.h create mode 100644 Tests/NetUtils/lookup.cpp create mode 100644 Tests/NetUtils/lookupPreferV6.cpp diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 168ca95..ac3f100 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,10 +12,7 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] }, { @@ -28,7 +25,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] } ] diff --git a/NetUtils.cpp b/NetUtils.cpp new file mode 100644 index 0000000..b3b283d --- /dev/null +++ b/NetUtils.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 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 +#include + + +#include "NetUtils.h" + +bool CNetUtils::lookupPreferV6(const std::string& hostname, sockaddr_storage& addr) +{ + struct addrinfo hints; + ::memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + + return lookup(hostname, addr, hints); +} + +bool CNetUtils::lookup(const std::string& hostname, sockaddr_storage& addr, struct addrinfo& hints) +{ + struct addrinfo *res; + + int err = getaddrinfo(hostname.c_str(), nullptr, &hints, &res); + if(err != 0) { + lookup("255.255.255.255", addr, hints); + return false; + } + + ::memcpy(&addr, res->ai_addr, res->ai_addrlen); + + ::freeaddrinfo(res); + + return true; +} \ No newline at end of file diff --git a/NetUtils.h b/NetUtils.h new file mode 100644 index 0000000..31b4678 --- /dev/null +++ b/NetUtils.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 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. + */ + +#pragma once + +#include +#include +#include + +class CNetUtils +{ +public: + static bool lookupPreferV6(const std::string& hostname, sockaddr_storage& addr); + static bool lookup(const std::string& hostname, sockaddr_storage& addr, struct addrinfo& hints); +}; \ No newline at end of file diff --git a/Tests/NetUtils/lookup.cpp b/Tests/NetUtils/lookup.cpp new file mode 100644 index 0000000..f55f23c --- /dev/null +++ b/Tests/NetUtils/lookup.cpp @@ -0,0 +1,59 @@ +/* + * 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 + +#include + +#include "../../NetUtils.h" + +namespace NetUtilsTests +{ + class NetUtils_lookup: public ::testing::Test { + + }; + + TEST_F(NetUtils_lookup, googleShallAlwaysSucceed) + { + sockaddr_storage addr; + struct addrinfo hints; + ::memset(&hints, 0, sizeof(hints)); + + bool res = CNetUtils::lookup("google.fr", addr, hints); + + bool familyOk = addr.ss_family == AF_INET6 || addr.ss_family == AF_INET; + EXPECT_TRUE(familyOk); + EXPECT_TRUE(res); + } + + TEST_F(NetUtils_lookup, erroneousAddress) + { + sockaddr_storage addr; + struct addrinfo hints; + ::memset(&hints, 0, sizeof(hints)); + + bool res = CNetUtils::lookup("gfilufgclqsegfuligyhfcguyhfguilfguils4df64sdw46fcq6sfgvd6f6d7f67d6f7c6sd7f6s7gfv6fc7d6f76tf.fr", addr, hints); + + EXPECT_EQ(addr.ss_family, AF_INET); + + auto ptr = (sockaddr_in*)(&addr); + + EXPECT_EQ((uint32_t)(ptr->sin_addr.s_addr), (uint32_t)INADDR_NONE); + EXPECT_FALSE(res); + } +} \ No newline at end of file diff --git a/Tests/NetUtils/lookupPreferV6.cpp b/Tests/NetUtils/lookupPreferV6.cpp new file mode 100644 index 0000000..27d874a --- /dev/null +++ b/Tests/NetUtils/lookupPreferV6.cpp @@ -0,0 +1,58 @@ +/* + * 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 + +#include + +#include "../../NetUtils.h" + +namespace NetUtilsTests +{ + class NetUtils_lookupPreferV6 : public ::testing::Test { + + }; + + TEST_F(NetUtils_lookupPreferV6, googleShallAlwaysSucceed) + { + sockaddr_storage addr; + struct addrinfo hints; + ::memset(&hints, 0, sizeof(hints)); + + bool res = CNetUtils::lookup("google.fr", addr, hints); + + EXPECT_EQ(addr.ss_family, AF_INET6); + EXPECT_TRUE(res); + } + + TEST_F(NetUtils_lookupPreferV6, erroneousAddress) + { + sockaddr_storage addr; + struct addrinfo hints; + ::memset(&hints, 0, sizeof(hints)); + + bool res = CNetUtils::lookup("gfilufgclqsegfuligyhfcguyhfguilfguils4df64sdw46fcq6sfgvd6f6d7f67d6f7c6sd7f6s7gfv6fc7d6f76tf.fr", addr, hints); + + EXPECT_EQ(addr.ss_family, AF_INET); + + auto ptr = (sockaddr_in*)(&addr); + + EXPECT_EQ((uint32_t)(ptr->sin_addr.s_addr), (uint32_t)INADDR_NONE); + EXPECT_FALSE(res); + } +} \ No newline at end of file From 708341e9171578f5020d0724e1c98b47d1ac3800 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 22 Jan 2022 17:08:45 +0100 Subject: [PATCH 166/201] #16 Add lookup V4 --- NetUtils.cpp | 13 +++- NetUtils.h | 3 +- Tests/NetUtils/lookupV4.cpp | 68 +++++++++++++++++++ .../{lookupPreferV6.cpp => lookupV6.cpp} | 28 +++++--- 4 files changed, 101 insertions(+), 11 deletions(-) create mode 100644 Tests/NetUtils/lookupV4.cpp rename Tests/NetUtils/{lookupPreferV6.cpp => lookupV6.cpp} (63%) diff --git a/NetUtils.cpp b/NetUtils.cpp index b3b283d..f4046d8 100644 --- a/NetUtils.cpp +++ b/NetUtils.cpp @@ -22,7 +22,16 @@ #include "NetUtils.h" -bool CNetUtils::lookupPreferV6(const std::string& hostname, sockaddr_storage& addr) +bool CNetUtils::lookupV4(const std::string& hostname, sockaddr_storage& addr) +{ + struct addrinfo hints; + ::memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + + return lookup(hostname, addr, hints); +} + +bool CNetUtils::lookupV6(const std::string& hostname, sockaddr_storage& addr) { struct addrinfo hints; ::memset(&hints, 0, sizeof(hints)); @@ -37,6 +46,8 @@ bool CNetUtils::lookup(const std::string& hostname, sockaddr_storage& addr, stru int err = getaddrinfo(hostname.c_str(), nullptr, &hints, &res); if(err != 0) { + ::memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; lookup("255.255.255.255", addr, hints); return false; } diff --git a/NetUtils.h b/NetUtils.h index 31b4678..b3dd779 100644 --- a/NetUtils.h +++ b/NetUtils.h @@ -25,6 +25,7 @@ class CNetUtils { public: - static bool lookupPreferV6(const std::string& hostname, sockaddr_storage& addr); + static bool lookupV6(const std::string& hostname, sockaddr_storage& addr); + static bool lookupV4(const std::string& hostname, sockaddr_storage& addr); static bool lookup(const std::string& hostname, sockaddr_storage& addr, struct addrinfo& hints); }; \ No newline at end of file diff --git a/Tests/NetUtils/lookupV4.cpp b/Tests/NetUtils/lookupV4.cpp new file mode 100644 index 0000000..5f554fb --- /dev/null +++ b/Tests/NetUtils/lookupV4.cpp @@ -0,0 +1,68 @@ +/* + * 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 + +#include + +#include "../../NetUtils.h" + +namespace NetUtilsTests +{ + class NetUtils_lookupV4 : public ::testing::Test { + + }; + + TEST_F(NetUtils_lookupV4, googleShallAlwaysSucceed) + { + sockaddr_storage addr; + + bool res = CNetUtils::lookupV4("google.fr", addr); + + EXPECT_EQ(addr.ss_family, AF_INET); + EXPECT_TRUE(res); + } + + TEST_F(NetUtils_lookupV4, erroneousAddress) + { + sockaddr_storage addr; + + bool res = CNetUtils::lookupV4("gfilufgclqsegfuligyhfcguyhfguilfguils4df64sdw46fcq6sfgvd6f6d7f67d6f7c6sd7f6s7gfv6fc7d6f76tf.fr", addr); + + EXPECT_EQ(addr.ss_family, AF_INET); + + auto ptr = (sockaddr_in*)(&addr); + + EXPECT_EQ((uint32_t)(ptr->sin_addr.s_addr), (uint32_t)INADDR_NONE); + EXPECT_FALSE(res); + } + + TEST_F(NetUtils_lookupV4, addressWithNoIPV4) + { + sockaddr_storage addr; + + bool res = CNetUtils::lookupV4("ircv6.openquad.net", addr); + + EXPECT_EQ(addr.ss_family, AF_INET); + + auto ptr = (sockaddr_in*)(&addr); + + EXPECT_EQ((uint32_t)(ptr->sin_addr.s_addr), (uint32_t)INADDR_NONE); + EXPECT_FALSE(res); + } +} \ No newline at end of file diff --git a/Tests/NetUtils/lookupPreferV6.cpp b/Tests/NetUtils/lookupV6.cpp similarity index 63% rename from Tests/NetUtils/lookupPreferV6.cpp rename to Tests/NetUtils/lookupV6.cpp index 27d874a..1a6c9bf 100644 --- a/Tests/NetUtils/lookupPreferV6.cpp +++ b/Tests/NetUtils/lookupV6.cpp @@ -24,29 +24,39 @@ namespace NetUtilsTests { - class NetUtils_lookupPreferV6 : public ::testing::Test { + class NetUtils_lookupV6 : public ::testing::Test { }; - TEST_F(NetUtils_lookupPreferV6, googleShallAlwaysSucceed) + TEST_F(NetUtils_lookupV6, googleShallAlwaysSucceed) { sockaddr_storage addr; - struct addrinfo hints; - ::memset(&hints, 0, sizeof(hints)); - bool res = CNetUtils::lookup("google.fr", addr, hints); + bool res = CNetUtils::lookupV6("google.fr", addr); EXPECT_EQ(addr.ss_family, AF_INET6); EXPECT_TRUE(res); } - TEST_F(NetUtils_lookupPreferV6, erroneousAddress) + TEST_F(NetUtils_lookupV6, erroneousAddress) { sockaddr_storage addr; - struct addrinfo hints; - ::memset(&hints, 0, sizeof(hints)); - bool res = CNetUtils::lookup("gfilufgclqsegfuligyhfcguyhfguilfguils4df64sdw46fcq6sfgvd6f6d7f67d6f7c6sd7f6s7gfv6fc7d6f76tf.fr", addr, hints); + bool res = CNetUtils::lookupV6("gfilufgclqsegfuligyhfcguyhfguilfguils4df64sdw46fcq6sfgvd6f6d7f67d6f7c6sd7f6s7gfv6fc7d6f76tf.fr", addr); + + EXPECT_EQ(addr.ss_family, AF_INET); + + auto ptr = (sockaddr_in*)(&addr); + + EXPECT_EQ((uint32_t)(ptr->sin_addr.s_addr), (uint32_t)INADDR_NONE); + EXPECT_FALSE(res); + } + + TEST_F(NetUtils_lookupV6, addressWithNoIPV6) + { + sockaddr_storage addr; + + bool res = CNetUtils::lookupV6("ircv4.openquad.net", addr); EXPECT_EQ(addr.ss_family, AF_INET); From 3d4eda60ace81c028ec673246384e280c6736106 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 22 Jan 2022 18:11:39 +0100 Subject: [PATCH 167/201] #16 add read with sockaddr_storage --- .vscode/tasks.json | 10 +++++----- UDPReaderWriter.cpp | 21 +++++++++++++++------ UDPReaderWriter.h | 3 ++- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index ac3f100..168ca95 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,7 +12,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] }, { @@ -25,10 +28,7 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] } ] diff --git a/UDPReaderWriter.cpp b/UDPReaderWriter.cpp index d89beea..f28f564 100644 --- a/UDPReaderWriter.cpp +++ b/UDPReaderWriter.cpp @@ -101,7 +101,7 @@ bool CUDPReaderWriter::open() return true; } -int CUDPReaderWriter::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port) +int CUDPReaderWriter::read(unsigned char* buffer, unsigned int length, struct sockaddr_storage& addr) { // Check that the readfrom() won't block fd_set readFds; @@ -122,8 +122,7 @@ int CUDPReaderWriter::read(unsigned char* buffer, unsigned int length, in_addr& if (ret == 0) return 0; - sockaddr_in addr; - socklen_t size = sizeof(sockaddr_in); + socklen_t size = sizeof(addr); ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size); if (len <= 0) { @@ -131,12 +130,22 @@ int CUDPReaderWriter::read(unsigned char* buffer, unsigned int length, in_addr& return -1; } - address = addr.sin_addr; - port = ntohs(addr.sin_port); - return len; } +int CUDPReaderWriter::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port) +{ + struct sockaddr_storage addr; + auto res = read(buffer, length, addr); + + if(res >= 0 && addr.ss_family == AF_INET) { + address = ((struct sockaddr_in*)&addr)->sin_addr; + port = ntohs(((struct sockaddr_in*)&addr)->sin_port); + } + + return res; +} + bool CUDPReaderWriter::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port) { sockaddr_in addr; diff --git a/UDPReaderWriter.h b/UDPReaderWriter.h index 25cfb08..0ccfaa4 100644 --- a/UDPReaderWriter.h +++ b/UDPReaderWriter.h @@ -41,7 +41,8 @@ public: bool open(); - int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port); + int read(unsigned char* buffer, unsigned int length, struct sockaddr_storage& addr); + int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port); bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port); void close(); From 04beb314ac8a149624f51383b82c3e3f2edbdea6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 22 Jan 2022 18:21:42 +0100 Subject: [PATCH 168/201] touch instead of RM --- Makefile | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 0174975..86bc984 100644 --- a/Makefile +++ b/Makefile @@ -137,9 +137,8 @@ removehostfiles : .PHONY tests: tests : GitVersion.h -# remove these to force tests makefile to rebuild them with -DUNIT_TESTS, otherwise we end up with 2 mains - @$(RM) -f DStarGatewayApp.o - @$(RM) -f DStarGatewayApp.d +# force tests makefile to rebuild them with -DUNIT_TESTS, otherwise we end up with 2 mains + @touch DStarGatewayApp.cpp @$(MAKE) -C Tests dstargateway_tests .PHONY run-tests: From ebdf6bb3a22ce133e7e6c5bdca1db830eabc04b2 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 23 Jan 2022 17:17:45 +0100 Subject: [PATCH 169/201] Add match --- NetUtils.cpp | 68 +++++++++++++++++++++++++++++- NetUtils.h | 12 ++++++ Tests/NetUtils/match.cpp | 90 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 Tests/NetUtils/match.cpp diff --git a/NetUtils.cpp b/NetUtils.cpp index f4046d8..ad45f29 100644 --- a/NetUtils.cpp +++ b/NetUtils.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2022 by Geoffrey Merck F4FXL / KC3FRA + * Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,9 +20,11 @@ #include #include - #include "NetUtils.h" +#define TOIPV6(s) ((struct sockaddr_in6*)&s) +#define TOIPV4(s) (((struct sockaddr_in*)&s)) + bool CNetUtils::lookupV4(const std::string& hostname, sockaddr_storage& addr) { struct addrinfo hints; @@ -40,6 +43,13 @@ bool CNetUtils::lookupV6(const std::string& hostname, sockaddr_storage& addr) return lookup(hostname, addr, hints); } +bool CNetUtils::lookup(const std::string& hostname, sockaddr_storage& addr) +{ + struct addrinfo hints; + ::memset(&hints, 0, sizeof(hints)); + return lookup(hostname, addr, hints); +} + bool CNetUtils::lookup(const std::string& hostname, sockaddr_storage& addr, struct addrinfo& hints) { struct addrinfo *res; @@ -57,4 +67,58 @@ bool CNetUtils::lookup(const std::string& hostname, sockaddr_storage& addr, stru ::freeaddrinfo(res); return true; -} \ No newline at end of file +} + +bool CNetUtils::match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type) +{ + if (addr1.ss_family != addr2.ss_family) + return false; + + if (type == IMT_ADDRESS_AND_PORT) { + switch (addr1.ss_family) { + case AF_INET: + struct sockaddr_in *in_1, *in_2; + in_1 = (struct sockaddr_in*)&addr1; + in_2 = (struct sockaddr_in*)&addr2; + return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port); + case AF_INET6: + struct sockaddr_in6 *in6_1, *in6_2; + in6_1 = (struct sockaddr_in6*)&addr1; + in6_2 = (struct sockaddr_in6*)&addr2; + return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port); + default: + return false; + } + } else if (type == IMT_ADDRESS_ONLY) { + switch (addr1.ss_family) { + case AF_INET: + struct sockaddr_in *in_1, *in_2; + in_1 = (struct sockaddr_in*)&addr1; + in_2 = (struct sockaddr_in*)&addr2; + return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr; + case AF_INET6: + struct sockaddr_in6 *in6_1, *in6_2; + in6_1 = (struct sockaddr_in6*)&addr1; + in6_2 = (struct sockaddr_in6*)&addr2; + return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr); + default: + return false; + } + } else { + return false; + } +} + +void CNetUtils::setPort(struct sockaddr_storage& addr, in_port_t port) +{ + switch (addr.ss_family) + { + case AF_INET: + TOIPV4(addr)->sin_port = port; + break; + case AF_INET6: + TOIPV6(addr)->sin6_port = port; + default: + break; + } +} diff --git a/NetUtils.h b/NetUtils.h index b3dd779..1578c97 100644 --- a/NetUtils.h +++ b/NetUtils.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2022 by Geoffrey Merck F4FXL / KC3FRA + * Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX * * 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 @@ -22,10 +23,21 @@ #include #include + +#define GETPORT(s) (s.ss_family == AF_INET6 ? TOIPV6(s)->sin6_port : TOIPV4(s)->sin_port) + +enum IPMATCHTYPE { + IMT_ADDRESS_AND_PORT, + IMT_ADDRESS_ONLY +}; + class CNetUtils { public: static bool lookupV6(const std::string& hostname, sockaddr_storage& addr); static bool lookupV4(const std::string& hostname, sockaddr_storage& addr); + static bool lookup(const std::string& hostname, sockaddr_storage& addr); static bool lookup(const std::string& hostname, sockaddr_storage& addr, struct addrinfo& hints); + static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type); + static void setPort(struct sockaddr_storage& addr, in_port_t port); }; \ No newline at end of file diff --git a/Tests/NetUtils/match.cpp b/Tests/NetUtils/match.cpp new file mode 100644 index 0000000..0f58d12 --- /dev/null +++ b/Tests/NetUtils/match.cpp @@ -0,0 +1,90 @@ +/* + * 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 + +#include + +#include "../../NetUtils.h" + +namespace NetUtilsTests +{ + class NetUtils_match: public ::testing::Test { + + }; + + TEST_F(NetUtils_match, MatchIPAndPort_differentFamilySamePort) + { + struct sockaddr_storage addr1, addr2; + addr1.ss_family = AF_INET6; + addr2.ss_family = AF_INET; + + ((struct sockaddr_in6 *)&addr1)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr1)->sin6_port = 123; + + ((struct sockaddr_in *)&addr2)->sin_addr.s_addr = INADDR_LOOPBACK; + ((struct sockaddr_in *)&addr2)->sin_port = 123; + + EXPECT_FALSE(CNetUtils::match(addr1, addr2, IMT_ADDRESS_AND_PORT)); + } + + TEST_F(NetUtils_match, MatchIPAndPort_SameFamilySamePort) + { + struct sockaddr_storage addr1, addr2; + addr1.ss_family = AF_INET6; + addr2.ss_family = AF_INET6; + + ((struct sockaddr_in6 *)&addr1)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr1)->sin6_port = 123; + + ((struct sockaddr_in6 *)&addr2)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr2)->sin6_port = 123; + + EXPECT_TRUE(CNetUtils::match(addr1, addr2, IMT_ADDRESS_AND_PORT)); + } + + TEST_F(NetUtils_match, MatchIPAndPort_SameFamilyDifferentPort) + { + struct sockaddr_storage addr1, addr2; + addr1.ss_family = AF_INET6; + addr2.ss_family = AF_INET6; + + ((struct sockaddr_in6 *)&addr1)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr1)->sin6_port = 123; + + ((struct sockaddr_in6 *)&addr2)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr2)->sin6_port = 456; + + EXPECT_FALSE(CNetUtils::match(addr1, addr2, IMT_ADDRESS_AND_PORT)); + } + + TEST_F(NetUtils_match, MatchIP_SameFamilyDifferentPort) + { + struct sockaddr_storage addr1, addr2; + addr1.ss_family = AF_INET6; + addr2.ss_family = AF_INET6; + + ((struct sockaddr_in6 *)&addr1)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr1)->sin6_port = 123; + + ((struct sockaddr_in6 *)&addr2)->sin6_addr = IN6ADDR_LOOPBACK_INIT; + ((struct sockaddr_in6 *)&addr2)->sin6_port = 456; + + EXPECT_TRUE(CNetUtils::match(addr1, addr2, IMT_ADDRESS_ONLY)); + } +} \ No newline at end of file From 53b5d469a8e52cd7da50e414881b88a19525b4c6 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 23 Jan 2022 17:21:33 +0100 Subject: [PATCH 170/201] add hash --- G2ProtocolHandler.h | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/G2ProtocolHandler.h b/G2ProtocolHandler.h index 14eb0b3..b949886 100644 --- a/G2ProtocolHandler.h +++ b/G2ProtocolHandler.h @@ -20,11 +20,14 @@ #pragma once #include +#include +#include #include "UDPReaderWriter.h" #include "DStarDefines.h" #include "HeaderData.h" #include "AMBEData.h" +#include "NetUtils.h" enum G2_TYPE { GT_NONE, @@ -32,6 +35,37 @@ enum G2_TYPE { GT_AMBE }; +// struct sockaddr_storage_map { +// struct comp { +// bool operator() (const struct sockaddr_storage& a, const struct sockaddr_storage& b) const { +// return CNetUtils::match(a, b, IMT_ADDRESS_AND_PORT); +// } +// }; +// struct hash { +// std::size_t operator() (const sockaddr_storage& a) const { +// switch(a.ss_family) +// { +// case AF_INET: { +// auto ptr4 = ((struct sockaddr_in *)&a); +// size_t res = AF_INET; +// boost::hash_combine(res, ptr4->sin_addr.s_addr); +// boost::hash_combine(res, ptr4->sin_port); +// return res; +// } +// case AF_INET6: { +// auto ptr6 = ((struct sockaddr_in6 *)&a); +// size_t res = AF_INET6; +// boost::hash_combine(res, ptr6->sin6_port); +// boost::hash_combine(res, ptr6->sin6_addr); +// return res; +// } +// default: +// return 0U; +// } +// } +// }; +// }; + class CG2ProtocolHandler { public: CG2ProtocolHandler(unsigned int port, const std::string& addr = std::string("")); From 4d4f9f3a527381b942ff37aa0c341c258a34f3bc Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Tue, 25 Jan 2022 20:44:50 +0100 Subject: [PATCH 171/201] #16 Add G2 Pool, start some IPV6 changes --- AMBEData.cpp | 12 +++ AMBEData.h | 1 + DStarGatewayThread.cpp | 8 +- DStarGatewayThread.h | 4 +- G2Handler.cpp | 4 +- G2Handler.h | 6 +- G2ProtocolHandler.cpp | 101 +++++++---------------- G2ProtocolHandler.h | 48 ++--------- G2ProtocolHandlerPool.cpp | 169 ++++++++++++++++++++++++++++++++++++++ G2ProtocolHandlerPool.h | 91 ++++++++++++++++++++ HeaderData.cpp | 13 ++- HeaderData.h | 1 + NetUtils.cpp | 3 - NetUtils.h | 4 +- RepeaterHandler.cpp | 4 +- RepeaterHandler.h | 6 +- UDPReaderWriter.cpp | 41 +++++++-- UDPReaderWriter.h | 1 + 18 files changed, 377 insertions(+), 140 deletions(-) create mode 100644 G2ProtocolHandlerPool.cpp create mode 100644 G2ProtocolHandlerPool.h diff --git a/AMBEData.cpp b/AMBEData.cpp index 1c2bf87..2cef8c0 100644 --- a/AMBEData.cpp +++ b/AMBEData.cpp @@ -24,6 +24,7 @@ #include "AMBEData.h" #include "DStarDefines.h" #include "Utils.h" +#include "NetUtils.h" CAMBEData::CAMBEData() : m_rptSeq(0U), @@ -582,6 +583,17 @@ unsigned int CAMBEData::getMyPort() const return m_myPort; } +struct sockaddr_storage CAMBEData::getDestination() const +{ + struct sockaddr_storage dest; + ::memset(&dest, 0, sizeof(sockaddr_storage)); + dest.ss_family = AF_INET; + TOIPV4(dest)->sin_addr = m_yourAddress; + TOIPV4(dest)->sin_port = htons(m_yourPort); + + return dest; +} + CHeaderData& CAMBEData::getHeader() { return m_header; diff --git a/AMBEData.h b/AMBEData.h index 8282852..695a5c2 100644 --- a/AMBEData.h +++ b/AMBEData.h @@ -77,6 +77,7 @@ public: in_addr getYourAddress() const; unsigned int getYourPort() const; + struct sockaddr_storage getDestination() const; unsigned int getMyPort() const; unsigned int getErrors() const; diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index 6b8d810..d69d7fb 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -198,7 +198,7 @@ void* CDStarGatewayThread::Entry() CLog::logError("Failed to allocate incoming DCS handler\n"); } - m_g2Handler = new CG2ProtocolHandler(G2_DV_PORT, m_gatewayAddress); + m_g2Handler = new CG2ProtocolHandlerPool(G2_DV_PORT, m_gatewayAddress); bool ret = m_g2Handler->open(); if (!ret) { CLog::logError("Could not open the G2 protocol handler"); @@ -232,7 +232,7 @@ void* CDStarGatewayThread::Entry() loadGateways(); loadAllReflectors(); - CG2Handler::setG2ProtocolHandler(m_g2Handler); + CG2Handler::setG2ProtocolHandlerPool(m_g2Handler); CG2Handler::setHeaderLogger(headerLogger); CDExtraHandler::setCallsign(m_gatewayCallsign); @@ -250,7 +250,7 @@ void* CDStarGatewayThread::Entry() CDCSHandler::setHeaderLogger(headerLogger); CRepeaterHandler::setLocalAddress(m_gatewayAddress); - CRepeaterHandler::setG2Handler(m_g2Handler); + CRepeaterHandler::setG2HandlerPool(m_g2Handler); if (m_irc != NULL) CRepeaterHandler::setIRC(m_irc); @@ -284,7 +284,7 @@ void* CDStarGatewayThread::Entry() #ifdef USE_STARNET CStarNetHandler::setCache(&m_cache); CStarNetHandler::setGateway(m_gatewayCallsign); - CStarNetHandler::setG2Handler(m_g2Handler); + CStarNetHandler::setG2HandlerPool(m_g2Handler); if (m_irc != NULL) CStarNetHandler::setIRC(m_irc); diff --git a/DStarGatewayThread.h b/DStarGatewayThread.h index e81aaf1..413cf9d 100644 --- a/DStarGatewayThread.h +++ b/DStarGatewayThread.h @@ -28,7 +28,7 @@ #include "RepeaterProtocolHandler.h" #include "DStarGatewayStatusData.h" #include "DCSProtocolHandlerPool.h" -#include "G2ProtocolHandler.h" +#include "G2ProtocolHandlerPool.h" #include "RemoteHandler.h" #include "CacheManager.h" #include "CallsignList.h" @@ -102,7 +102,7 @@ private: CDExtraProtocolHandlerPool* m_dextraPool; CDPlusProtocolHandlerPool* m_dplusPool; CDCSProtocolHandlerPool* m_dcsPool; - CG2ProtocolHandler* m_g2Handler; + CG2ProtocolHandlerPool* m_g2Handler; CAPRSHandler* m_aprsWriter; CIRCDDB* m_irc; CCacheManager m_cache; diff --git a/G2Handler.cpp b/G2Handler.cpp index 8cbede5..8670b32 100644 --- a/G2Handler.cpp +++ b/G2Handler.cpp @@ -31,7 +31,7 @@ unsigned int CG2Handler::m_maxRoutes = 0U; CG2Handler** CG2Handler::m_routes = NULL; -CG2ProtocolHandler* CG2Handler::m_handler = NULL; +CG2ProtocolHandlerPool* CG2Handler::m_handler = NULL; CHeaderLogger* CG2Handler::m_headerLogger = NULL; @@ -60,7 +60,7 @@ void CG2Handler::initialise(unsigned int maxRoutes) m_routes[i] = NULL; } -void CG2Handler::setG2ProtocolHandler(CG2ProtocolHandler* handler) +void CG2Handler::setG2ProtocolHandlerPool(CG2ProtocolHandlerPool* handler) { assert(handler != NULL); diff --git a/G2Handler.h b/G2Handler.h index d2b14cd..89f3291 100644 --- a/G2Handler.h +++ b/G2Handler.h @@ -22,7 +22,7 @@ #include -#include "G2ProtocolHandler.h" +#include "G2ProtocolHandlerPool.h" #include "RepeaterHandler.h" #include "DStarDefines.h" #include "HeaderLogger.h" @@ -34,7 +34,7 @@ class CG2Handler { public: static void initialise(unsigned int maxRoutes); - static void setG2ProtocolHandler(CG2ProtocolHandler* handler); + static void setG2ProtocolHandlerPool(CG2ProtocolHandlerPool* handler); static void setHeaderLogger(CHeaderLogger* logger); static void process(CHeaderData& header); @@ -54,7 +54,7 @@ private: static unsigned int m_maxRoutes; static CG2Handler** m_routes; - static CG2ProtocolHandler* m_handler; + static CG2ProtocolHandlerPool* m_handler; static CHeaderLogger* m_headerLogger; diff --git a/G2ProtocolHandler.cpp b/G2ProtocolHandler.cpp index 60e1b30..ae3ac4e 100644 --- a/G2ProtocolHandler.cpp +++ b/G2ProtocolHandler.cpp @@ -18,6 +18,7 @@ */ #include +#include #include "G2ProtocolHandler.h" #include "Utils.h" @@ -27,26 +28,20 @@ const unsigned int BUFFER_LENGTH = 255U; -CG2ProtocolHandler::CG2ProtocolHandler(unsigned int port, const std::string& addr) : -m_socket(addr, port), +CG2ProtocolHandler::CG2ProtocolHandler(CUDPReaderWriter* socket, const struct sockaddr_storage& destination, unsigned int bufferSize) : +m_socket(socket), m_type(GT_NONE), -m_buffer(NULL), +m_buffer(nullptr), m_length(0U), -m_address(), -m_port(0U) +m_address(destination) { - m_buffer = new unsigned char[BUFFER_LENGTH]; + m_buffer = new unsigned char[bufferSize]; + ::memset(m_buffer, 0, bufferSize); } CG2ProtocolHandler::~CG2ProtocolHandler() { delete[] m_buffer; - m_portmap.clear(); -} - -bool CG2ProtocolHandler::open() -{ - return m_socket.open(); } bool CG2ProtocolHandler::writeHeader(const CHeaderData& header) @@ -58,12 +53,12 @@ bool CG2ProtocolHandler::writeHeader(const CHeaderData& header) CUtils::dump("Sending Header", buffer, length); #endif - in_addr addr = header.getYourAddress(); - auto found = m_portmap.find(addr.s_addr); - unsigned int port = (m_portmap.end()==found) ? header.getYourPort() : found->second; + assert(CNetUtils::match(header.getDestination(), m_address, IMT_ADDRESS_ONLY)); + + //CLog::logTrace("Write header to %s:%u", inet_ntoa(addr), ntohs(TOIPV4(m_address)->sin_port)); for (unsigned int i = 0U; i < 5U; i++) { - bool res = m_socket.write(buffer, length, addr, port); + bool res = m_socket->write(buffer, length, m_address); if (!res) return false; } @@ -80,58 +75,34 @@ bool CG2ProtocolHandler::writeAMBE(const CAMBEData& data) CUtils::dump("Sending Data", buffer, length); #endif - in_addr addr = data.getYourAddress(); - auto found = m_portmap.find(addr.s_addr); - unsigned int port = (m_portmap.end()==found) ? data.getYourPort() : found->second; - - return m_socket.write(buffer, length, addr, port); + assert(CNetUtils::match(data.getDestination(), m_address, IMT_ADDRESS_ONLY)); + //CLog::logTrace("Write ambe to %s:%u", inet_ntoa(addr), ntohs(TOIPV4(m_address)->sin_port)); + return m_socket->write(buffer, length, m_address); } -G2_TYPE CG2ProtocolHandler::read() +bool CG2ProtocolHandler::setBuffer(unsigned char * buffer, int length) { - bool res = true; - - // Loop until we have no more data from the socket or we have data for the higher layers - while (res) - res = readPackets(); - - return m_type; -} + assert(buffer != nullptr); -bool CG2ProtocolHandler::readPackets() -{ m_type = GT_NONE; + ::memcpy(m_buffer, buffer, length); - // No more data? - int length = m_socket.read(m_buffer, BUFFER_LENGTH, m_address, m_port); - if (length <= 0) + if(length <= 0) return false; - if(length == 1) { - CLog::logDebug("G2 Nat traversal packet received"); - } - m_length = length; - // save the incoming port (this is to enable mobile hotspots) - if (m_portmap.end() == m_portmap.find(m_address.s_addr)) { - CLog::logInfo("G2 new address %s on port %u\n", inet_ntoa(m_address), m_port); - m_portmap[m_address.s_addr] = m_port; - } else { - if (m_portmap[m_address.s_addr] != m_port) { - CLog::logInfo("G2 new port for %s is %u, was %u\n", inet_ntoa(m_address), m_port, m_portmap[m_address.s_addr]); - m_portmap[m_address.s_addr] = m_port; - } - } - if (m_buffer[0] != 'D' || m_buffer[1] != 'S' || m_buffer[2] != 'V' || m_buffer[3] != 'T') { + CLog::logTrace("DSVT"); return true; } else { // Header or data packet type? - if ((m_buffer[14] & 0x80) == 0x80) + if ((m_buffer[14] & 0x80) == 0x80) { m_type = GT_HEADER; - else + } + else { m_type = GT_AMBE; + } return false; } @@ -140,15 +111,16 @@ bool CG2ProtocolHandler::readPackets() CHeaderData* CG2ProtocolHandler::readHeader() { if (m_type != GT_HEADER) - return NULL; + return nullptr; + m_type = GT_NONE; // Header data has been consumed, reset our status CHeaderData* header = new CHeaderData; // G2 checksums are unreliable - bool res = header->setG2Data(m_buffer, m_length, false, m_address, m_port); + bool res = header->setG2Data(m_buffer, m_length, false, TOIPV4(m_address)->sin_addr, ntohs(GETPORT(m_address))); if (!res) { delete header; - return NULL; + return nullptr; } return header; @@ -159,9 +131,10 @@ CAMBEData* CG2ProtocolHandler::readAMBE() if (m_type != GT_AMBE) return NULL; + m_type = GT_NONE; // Ambe data has been consumed, reset our status CAMBEData* data = new CAMBEData; - bool res = data->setG2Data(m_buffer, m_length, m_address, m_port); + bool res = data->setG2Data(m_buffer, m_length, TOIPV4(m_address)->sin_addr, ntohs(GETPORT(m_address))); if (!res) { delete data; return NULL; @@ -169,19 +142,3 @@ CAMBEData* CG2ProtocolHandler::readAMBE() return data; } - -void CG2ProtocolHandler::close() -{ - m_socket.close(); -} - -void CG2ProtocolHandler::traverseNat(const std::string& address) -{ - unsigned char buffer = 0x00U; - - in_addr addr = CUDPReaderWriter::lookup(address); - - CLog::logInfo("G2 Punching hole to %s", address.c_str()); - - m_socket.write(&buffer, 1U, addr, G2_DV_PORT); -} diff --git a/G2ProtocolHandler.h b/G2ProtocolHandler.h index b949886..df50724 100644 --- a/G2ProtocolHandler.h +++ b/G2ProtocolHandler.h @@ -21,7 +21,6 @@ #include #include -#include #include "UDPReaderWriter.h" #include "DStarDefines.h" @@ -35,40 +34,9 @@ enum G2_TYPE { GT_AMBE }; -// struct sockaddr_storage_map { -// struct comp { -// bool operator() (const struct sockaddr_storage& a, const struct sockaddr_storage& b) const { -// return CNetUtils::match(a, b, IMT_ADDRESS_AND_PORT); -// } -// }; -// struct hash { -// std::size_t operator() (const sockaddr_storage& a) const { -// switch(a.ss_family) -// { -// case AF_INET: { -// auto ptr4 = ((struct sockaddr_in *)&a); -// size_t res = AF_INET; -// boost::hash_combine(res, ptr4->sin_addr.s_addr); -// boost::hash_combine(res, ptr4->sin_port); -// return res; -// } -// case AF_INET6: { -// auto ptr6 = ((struct sockaddr_in6 *)&a); -// size_t res = AF_INET6; -// boost::hash_combine(res, ptr6->sin6_port); -// boost::hash_combine(res, ptr6->sin6_addr); -// return res; -// } -// default: -// return 0U; -// } -// } -// }; -// }; - class CG2ProtocolHandler { public: - CG2ProtocolHandler(unsigned int port, const std::string& addr = std::string("")); + CG2ProtocolHandler(CUDPReaderWriter* socket, const struct sockaddr_storage& destination, unsigned int bufferSize); ~CG2ProtocolHandler(); bool open(); @@ -76,22 +44,24 @@ public: bool writeHeader(const CHeaderData& header); bool writeAMBE(const CAMBEData& data); - G2_TYPE read(); CHeaderData* readHeader(); CAMBEData* readAMBE(); + struct sockaddr_storage getDestination() { return m_address; } + G2_TYPE getType() { return m_type; } + + bool setBuffer(unsigned char * buffer, int length); + void close(); - void traverseNat(const std::string& address); + private: - std::unordered_map m_portmap; - CUDPReaderWriter m_socket; + CUDPReaderWriter * m_socket; G2_TYPE m_type; unsigned char* m_buffer; unsigned int m_length; - in_addr m_address; - unsigned int m_port; + struct sockaddr_storage m_address; bool readPackets(); }; diff --git a/G2ProtocolHandlerPool.cpp b/G2ProtocolHandlerPool.cpp new file mode 100644 index 0000000..92467fd --- /dev/null +++ b/G2ProtocolHandlerPool.cpp @@ -0,0 +1,169 @@ +/* + * 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 + +#include "Log.h" +#include "G2ProtocolHandlerPool.h" + +const unsigned int G2_BUFFER_LENGTH = 255U; + +CG2ProtocolHandlerPool::CG2ProtocolHandlerPool(unsigned short port, const std::string& address) : +m_address(address), +m_basePort(port), +m_socket(address, port) +{ + assert(port > 0U); + m_index = m_pool.end(); +} + +CG2ProtocolHandlerPool::~CG2ProtocolHandlerPool() +{ + +} + +bool CG2ProtocolHandlerPool::open() +{ + bool res = m_socket.open(); + return res; +} + +void CG2ProtocolHandlerPool::close() +{ + for(auto handler : m_pool) { + delete handler; + } + m_pool.clear(); + m_index = m_pool.end(); + m_socket.close(); +} + +G2_TYPE CG2ProtocolHandlerPool::read() +{ + bool res = true; + while(res) + res = readPackets(); + + if(m_index == m_pool.end()) + m_index = m_pool.begin(); + + while(m_index != m_pool.end()) { + if((*m_index)->getType() != GT_NONE) { + return (*m_index)->getType(); + } + m_index++; + } + + return GT_NONE; +} + +CAMBEData * CG2ProtocolHandlerPool::readAMBE() +{ + if(m_index == m_pool.end() || (*m_index)->getType() != GT_AMBE) + return nullptr; + + return (*m_index)->readAMBE(); +} + +CHeaderData * CG2ProtocolHandlerPool::readHeader() +{ + if(m_index == m_pool.end() || (*m_index)->getType() != GT_HEADER) + return nullptr; + + return (*m_index)->readHeader(); +} + +bool CG2ProtocolHandlerPool::readPackets() +{ + unsigned char buffer[G2_BUFFER_LENGTH]; + struct sockaddr_storage addr; + ::memset(&addr, 0, sizeof(sockaddr_storage)); + + // No more data? + int length = m_socket.read(buffer, G2_BUFFER_LENGTH, addr); + if(length <= 0) return false; + + if(length == 1 && buffer[0] == 0U) { + CLog::logDebug("G2 Nat traversal packet received"); + } + + CG2ProtocolHandler * handler = findHandler(addr, IMT_ADDRESS_AND_PORT); + if(handler == nullptr) { + CLog::logTrace("new incoming G2 %s:%u", inet_ntoa(TOIPV4(addr)->sin_addr), ntohs(TOIPV4(addr)->sin_port)); + handler = new CG2ProtocolHandler(&m_socket, addr, G2_BUFFER_LENGTH); + m_pool.push_back(handler); + m_index = m_pool.end(); + } + + bool res = handler->setBuffer(buffer, length); + return res; +} + +void CG2ProtocolHandlerPool::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); +} + +bool CG2ProtocolHandlerPool::writeHeader(const CHeaderData& header) +{ + auto handler = findHandler(header.getDestination(), IMT_ADDRESS_ONLY); + if(handler == nullptr) { + handler = new CG2ProtocolHandler(&m_socket, header.getDestination(), G2_BUFFER_LENGTH); + m_pool.push_back(handler); + m_index = m_pool.end(); + } + return handler->writeHeader(header); +} + +bool CG2ProtocolHandlerPool::writeAMBE(const CAMBEData& data) +{ + auto handler = findHandler(data.getDestination(), IMT_ADDRESS_ONLY); + if(handler == nullptr) { + handler = new CG2ProtocolHandler(&m_socket, data.getDestination(), G2_BUFFER_LENGTH); + m_pool.push_back(handler); + m_index = m_pool.end(); + } + + return handler->writeAMBE(data); +} + +CG2ProtocolHandler * CG2ProtocolHandlerPool::findHandler(const struct sockaddr_storage& addr, IPMATCHTYPE matchType) const +{ + for(auto handler : m_pool) { + if(handler != nullptr && CNetUtils::match(addr, handler->getDestination(), matchType)) + return handler; + } + + return nullptr; +} + +CG2ProtocolHandler * CG2ProtocolHandlerPool::findHandler(in_addr addr, unsigned int port, IPMATCHTYPE matchType) const +{ + struct sockaddr_storage addrStorage; + addrStorage.ss_family = AF_INET; + TOIPV4(addrStorage)->sin_addr = addr; + TOIPV4(addrStorage)->sin_port = port; + + return findHandler(addrStorage, matchType); +} \ No newline at end of file diff --git a/G2ProtocolHandlerPool.h b/G2ProtocolHandlerPool.h new file mode 100644 index 0000000..afdc339 --- /dev/null +++ b/G2ProtocolHandlerPool.h @@ -0,0 +1,91 @@ +/* + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +#include "G2ProtocolHandler.h" +#include "NetUtils.h" + +struct sockaddr_storage_map { + struct compAddrAndPort { + bool operator() (const struct sockaddr_storage& a, const struct sockaddr_storage& b) const { + return CNetUtils::match(a, b, IMT_ADDRESS_AND_PORT); + } + }; + struct hash { + std::size_t operator() (const sockaddr_storage& a) const { + switch(a.ss_family) + { + case AF_INET: { + auto ptr4 = ((struct sockaddr_in *)&a); + size_t res = AF_INET; + boost::hash_combine(res, ptr4->sin_port); + boost::hash_combine(res, ptr4->sin_addr.s_addr); + return res; + } + case AF_INET6: { + auto ptr6 = ((struct sockaddr_in6 *)&a); + size_t res = AF_INET6; + boost::hash_combine(res, ptr6->sin6_port); + auto in6Ptr = (unsigned int *)&(ptr6->sin6_addr); + boost::hash_combine(res, in6Ptr[0]); + boost::hash_combine(res, in6Ptr[1]); + boost::hash_combine(res, in6Ptr[2]); + boost::hash_combine(res, in6Ptr[3]); + return res; + } + default: + return 0U; + } + } + }; +}; + +class CG2ProtocolHandlerPool +{ +public: + CG2ProtocolHandlerPool(unsigned short g2Port, const std::string& address = ""); + ~CG2ProtocolHandlerPool(); + + bool open(); + void close(); + G2_TYPE read(); + CAMBEData * readAMBE(); + CHeaderData * readHeader(); + + bool writeAMBE(const CAMBEData& data); + bool writeHeader(const CHeaderData& header); + + void traverseNat(const std::string& address); + +private: + bool readPackets(); + CG2ProtocolHandler * findHandler(const struct sockaddr_storage& addr, IPMATCHTYPE matchType) const; + CG2ProtocolHandler * findHandler(in_addr addr, unsigned int port, IPMATCHTYPE matchType) const; + + std::string m_address; + unsigned int m_basePort; + CUDPReaderWriter m_socket; + std::vector m_pool; + std::vector::iterator m_index; +}; \ No newline at end of file diff --git a/HeaderData.cpp b/HeaderData.cpp index b29ac0a..6747571 100644 --- a/HeaderData.cpp +++ b/HeaderData.cpp @@ -23,7 +23,7 @@ #include #include #include "HeaderData.h" - +#include "NetUtils.h" #include "CCITTChecksum.h" #include "DStarDefines.h" #include "Utils.h" @@ -922,6 +922,17 @@ unsigned int CHeaderData::getYourPort() const return m_yourPort; } +struct sockaddr_storage CHeaderData::getDestination() const +{ + struct sockaddr_storage dest; + ::memset(&dest, 0, sizeof(sockaddr_storage)); + dest.ss_family = AF_INET; + TOIPV4(dest)->sin_addr = m_yourAddress; + TOIPV4(dest)->sin_port = htons(m_yourPort); + + return dest; +} + unsigned int CHeaderData::getMyPort() const { return m_myPort; diff --git a/HeaderData.h b/HeaderData.h index c4ced7c..d004503 100644 --- a/HeaderData.h +++ b/HeaderData.h @@ -94,6 +94,7 @@ public: in_addr getYourAddress() const; unsigned int getYourPort() const; + struct sockaddr_storage getDestination() const; unsigned int getMyPort() const; unsigned int getErrors() const; diff --git a/NetUtils.cpp b/NetUtils.cpp index ad45f29..e0d3ac9 100644 --- a/NetUtils.cpp +++ b/NetUtils.cpp @@ -22,9 +22,6 @@ #include "NetUtils.h" -#define TOIPV6(s) ((struct sockaddr_in6*)&s) -#define TOIPV4(s) (((struct sockaddr_in*)&s)) - bool CNetUtils::lookupV4(const std::string& hostname, sockaddr_storage& addr) { struct addrinfo hints; diff --git a/NetUtils.h b/NetUtils.h index 1578c97..b5c795b 100644 --- a/NetUtils.h +++ b/NetUtils.h @@ -23,8 +23,10 @@ #include #include - +#define TOIPV6(s) ((struct sockaddr_in6*)&s) +#define TOIPV4(s) (((struct sockaddr_in*)&s)) #define GETPORT(s) (s.ss_family == AF_INET6 ? TOIPV6(s)->sin6_port : TOIPV4(s)->sin_port) +#define SETPORT(s, p) (if(s.ss_family == AF_INET6)TOIPV6(s)->sin6_port = p;else TOIPV4(s)->sin_port = p;) enum IPMATCHTYPE { IMT_ADDRESS_AND_PORT, diff --git a/RepeaterHandler.cpp b/RepeaterHandler.cpp index b88bea2..de58ca5 100644 --- a/RepeaterHandler.cpp +++ b/RepeaterHandler.cpp @@ -45,7 +45,7 @@ unsigned int CRepeaterHandler::m_maxRepeaters = 0U; CRepeaterHandler** CRepeaterHandler::m_repeaters = NULL; std::string CRepeaterHandler::m_localAddress; -CG2ProtocolHandler* CRepeaterHandler::m_g2Handler = NULL; +CG2ProtocolHandlerPool* CRepeaterHandler::m_g2Handler = NULL; CIRCDDB* CRepeaterHandler::m_irc = NULL; CCacheManager* CRepeaterHandler::m_cache = NULL; std::string CRepeaterHandler::m_gateway; @@ -301,7 +301,7 @@ void CRepeaterHandler::add(const std::string& callsign, const std::string& band, delete repeater; } -void CRepeaterHandler::setG2Handler(CG2ProtocolHandler* handler) +void CRepeaterHandler::setG2HandlerPool(CG2ProtocolHandlerPool* handler) { assert(handler != NULL); diff --git a/RepeaterHandler.h b/RepeaterHandler.h index 678e383..0d7922a 100644 --- a/RepeaterHandler.h +++ b/RepeaterHandler.h @@ -28,7 +28,7 @@ #include "DExtraProtocolHandler.h" #include "DPlusProtocolHandler.h" #include "RemoteRepeaterData.h" -#include "G2ProtocolHandler.h" +#include "G2ProtocolHandlerPool.h" #include "ReflectorCallback.h" #include "RepeaterCallback.h" #include "AnnouncementUnit.h" @@ -75,7 +75,7 @@ public: #endif static void setLocalAddress(const std::string& address); - static void setG2Handler(CG2ProtocolHandler* handler); + static void setG2HandlerPool(CG2ProtocolHandlerPool* handler); static void setIRC(CIRCDDB* irc); static void setCache(CCacheManager* cache); static void setGateway(const std::string& gateway); @@ -168,7 +168,7 @@ private: static CRepeaterHandler** m_repeaters; static std::string m_localAddress; - static CG2ProtocolHandler* m_g2Handler; + static CG2ProtocolHandlerPool* m_g2Handler; static CCacheManager* m_cache; static std::string m_gateway; static CIRCDDB* m_irc; diff --git a/UDPReaderWriter.cpp b/UDPReaderWriter.cpp index f28f564..d0b826f 100644 --- a/UDPReaderWriter.cpp +++ b/UDPReaderWriter.cpp @@ -21,6 +21,7 @@ #include #include "UDPReaderWriter.h" #include "Log.h" +#include "NetUtils.h" CUDPReaderWriter::CUDPReaderWriter(const std::string& address, unsigned int port) : m_address(address), @@ -139,8 +140,8 @@ int CUDPReaderWriter::read(unsigned char* buffer, unsigned int length, in_addr& auto res = read(buffer, length, addr); if(res >= 0 && addr.ss_family == AF_INET) { - address = ((struct sockaddr_in*)&addr)->sin_addr; - port = ntohs(((struct sockaddr_in*)&addr)->sin_port); + address = TOIPV4(addr)->sin_addr; + port = ntohs(TOIPV4(addr)->sin_port); } return res; @@ -148,14 +149,36 @@ int CUDPReaderWriter::read(unsigned char* buffer, unsigned int length, in_addr& bool CUDPReaderWriter::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port) { - sockaddr_in addr; - ::memset(&addr, 0x00, sizeof(sockaddr_in)); + struct sockaddr_storage addr; + ::memset(&addr, 0, sizeof(sockaddr_storage)); + + addr.ss_family = AF_INET; + TOIPV4(addr)->sin_addr = address; + TOIPV4(addr)->sin_port = htons(port); + + return write(buffer, length, addr); + // sockaddr_in addr; + // ::memset(&addr, 0x00, sizeof(sockaddr_in)); + + // addr.sin_family = AF_INET; + // addr.sin_addr = address; + // addr.sin_port = htons(port); + + // ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in)); + // if (ret < 0) { + // CLog::logError("Error returned from sendto (port: %u), err: %s\n", m_port, strerror(errno)); + // return false; + // } - addr.sin_family = AF_INET; - addr.sin_addr = address; - addr.sin_port = htons(port); + // if (ret != ssize_t(length)) + // return false; - ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in)); + // return true; +} + +bool CUDPReaderWriter::write(const unsigned char* buffer, unsigned int length, const struct sockaddr_storage& addr) +{ + ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(addr)); if (ret < 0) { CLog::logError("Error returned from sendto (port: %u), err: %s\n", m_port, strerror(errno)); return false; @@ -167,6 +190,8 @@ bool CUDPReaderWriter::write(const unsigned char* buffer, unsigned int length, c return true; } + + void CUDPReaderWriter::close() { ::close(m_fd); diff --git a/UDPReaderWriter.h b/UDPReaderWriter.h index 0ccfaa4..0cddfac 100644 --- a/UDPReaderWriter.h +++ b/UDPReaderWriter.h @@ -44,6 +44,7 @@ public: int read(unsigned char* buffer, unsigned int length, struct sockaddr_storage& addr); int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port); bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port); + bool write(const unsigned char* buffer, unsigned int length, const struct sockaddr_storage& addr); void close(); From 5713e166cd14cd0a426867e7eada2d5353101c19 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 26 Jan 2022 19:20:52 +0100 Subject: [PATCH 172/201] #16 variable renaming --- DStarGatewayThread.cpp | 32 ++++++++++++++++---------------- DStarGatewayThread.h | 2 +- RepeaterHandler.cpp | 14 +++++++------- RepeaterHandler.h | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index d69d7fb..4f2873d 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -75,7 +75,7 @@ m_dummyRepeaterHandler(NULL), m_dextraPool(NULL), m_dplusPool(NULL), m_dcsPool(NULL), -m_g2Handler(NULL), +m_g2HandlerPool(NULL), m_aprsWriter(NULL), m_irc(NULL), m_cache(), @@ -198,16 +198,16 @@ void* CDStarGatewayThread::Entry() CLog::logError("Failed to allocate incoming DCS handler\n"); } - m_g2Handler = new CG2ProtocolHandlerPool(G2_DV_PORT, m_gatewayAddress); - bool ret = m_g2Handler->open(); + m_g2HandlerPool = new CG2ProtocolHandlerPool(G2_DV_PORT, m_gatewayAddress); + bool ret = m_g2HandlerPool->open(); if (!ret) { CLog::logError("Could not open the G2 protocol handler"); - delete m_g2Handler; - m_g2Handler = NULL; + delete m_g2HandlerPool; + m_g2HandlerPool = NULL; } // 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_g2HandlerPool == 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 if (m_killed) @@ -232,7 +232,7 @@ void* CDStarGatewayThread::Entry() loadGateways(); loadAllReflectors(); - CG2Handler::setG2ProtocolHandlerPool(m_g2Handler); + CG2Handler::setG2ProtocolHandlerPool(m_g2HandlerPool); CG2Handler::setHeaderLogger(headerLogger); CDExtraHandler::setCallsign(m_gatewayCallsign); @@ -250,7 +250,7 @@ void* CDStarGatewayThread::Entry() CDCSHandler::setHeaderLogger(headerLogger); CRepeaterHandler::setLocalAddress(m_gatewayAddress); - CRepeaterHandler::setG2HandlerPool(m_g2Handler); + CRepeaterHandler::setG2HandlerPool(m_g2HandlerPool); if (m_irc != NULL) CRepeaterHandler::setIRC(m_irc); @@ -284,7 +284,7 @@ void* CDStarGatewayThread::Entry() #ifdef USE_STARNET CStarNetHandler::setCache(&m_cache); CStarNetHandler::setGateway(m_gatewayCallsign); - CStarNetHandler::setG2HandlerPool(m_g2Handler); + CStarNetHandler::setG2HandlerPool(m_g2HandlerPool); if (m_irc != NULL) CStarNetHandler::setIRC(m_irc); @@ -453,8 +453,8 @@ void* CDStarGatewayThread::Entry() m_dcsPool->close(); delete m_dcsPool; - m_g2Handler->close(); - delete m_g2Handler; + m_g2HandlerPool->close(); + delete m_g2HandlerPool; if (m_irc != NULL) { m_irc->close(); @@ -788,9 +788,9 @@ void CDStarGatewayThread::processIrcDDB() if(!res) return; - if(m_g2Handler != nullptr) { + if(m_g2HandlerPool != nullptr) { CLog::logInfo("%s wants to G2 route to us, punching UDP Holes through NAT", address.c_str()); - m_g2Handler->traverseNat(address); + m_g2HandlerPool->traverseNat(address); } else { CLog::logInfo("%s wants to G2 route to us, but G2 is disabled", address.c_str()); @@ -1096,11 +1096,11 @@ void CDStarGatewayThread::processDCS() void CDStarGatewayThread::processG2() { for (;;) { - G2_TYPE type = m_g2Handler->read(); + G2_TYPE type = m_g2HandlerPool->read(); switch (type) { case GT_HEADER: { - CHeaderData* header = m_g2Handler->readHeader(); + CHeaderData* header = m_g2HandlerPool->readHeader(); if (header != NULL) { // CLog::logInfo("G2 header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s Flags: %02X %02X %02X", header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str(), header->getFlag1(), header->getFlag2(), header->getFlag3()); CG2Handler::process(*header); @@ -1110,7 +1110,7 @@ void CDStarGatewayThread::processG2() break; case GT_AMBE: { - CAMBEData* data = m_g2Handler->readAMBE(); + CAMBEData* data = m_g2HandlerPool->readAMBE(); if (data != NULL) { CG2Handler::process(*data); delete data; diff --git a/DStarGatewayThread.h b/DStarGatewayThread.h index 413cf9d..5b4fe3c 100644 --- a/DStarGatewayThread.h +++ b/DStarGatewayThread.h @@ -102,7 +102,7 @@ private: CDExtraProtocolHandlerPool* m_dextraPool; CDPlusProtocolHandlerPool* m_dplusPool; CDCSProtocolHandlerPool* m_dcsPool; - CG2ProtocolHandlerPool* m_g2Handler; + CG2ProtocolHandlerPool* m_g2HandlerPool; CAPRSHandler* m_aprsWriter; CIRCDDB* m_irc; CCacheManager m_cache; diff --git a/RepeaterHandler.cpp b/RepeaterHandler.cpp index de58ca5..c55ca20 100644 --- a/RepeaterHandler.cpp +++ b/RepeaterHandler.cpp @@ -45,7 +45,7 @@ unsigned int CRepeaterHandler::m_maxRepeaters = 0U; CRepeaterHandler** CRepeaterHandler::m_repeaters = NULL; std::string CRepeaterHandler::m_localAddress; -CG2ProtocolHandlerPool* CRepeaterHandler::m_g2Handler = NULL; +CG2ProtocolHandlerPool* CRepeaterHandler::m_g2HandlerPool = NULL; CIRCDDB* CRepeaterHandler::m_irc = NULL; CCacheManager* CRepeaterHandler::m_cache = NULL; std::string CRepeaterHandler::m_gateway; @@ -305,7 +305,7 @@ void CRepeaterHandler::setG2HandlerPool(CG2ProtocolHandlerPool* handler) { assert(handler != NULL); - m_g2Handler = handler; + m_g2HandlerPool = handler; } void CRepeaterHandler::setCache(CCacheManager* cache) @@ -883,7 +883,7 @@ void CRepeaterHandler::processRepeater(CAMBEData& data) case G2_OK: data.setDestination(m_g2Address, G2_DV_PORT); - m_g2Handler->writeAMBE(data); + m_g2HandlerPool->writeAMBE(data); if (data.isEnd()) { m_repeaterId = 0x00U; @@ -1283,7 +1283,7 @@ void CRepeaterHandler::resolveUserInt(const std::string& user, const std::string m_g2Header->setDestination(m_g2Address, G2_DV_PORT); m_g2Header->setRepeaters(m_g2Gateway, m_g2Repeater); - m_g2Handler->writeHeader(*m_g2Header); + m_g2HandlerPool->writeHeader(*m_g2Header); delete m_g2Header; m_g2Status = G2_OK; @@ -1315,7 +1315,7 @@ void CRepeaterHandler::resolveRepeaterInt(const std::string& repeater, const std m_g2Header->setDestination(m_g2Address, G2_DV_PORT); m_g2Header->setRepeaters(m_g2Gateway, m_g2Repeater); - m_g2Handler->writeHeader(*m_g2Header); + m_g2HandlerPool->writeHeader(*m_g2Header); delete m_g2Header; m_g2Status = G2_OK; @@ -2072,7 +2072,7 @@ void CRepeaterHandler::g2CommandHandler(const std::string& callsign, const std:: m_g2Gateway = data->getGateway(); header.setDestination(m_g2Address, G2_DV_PORT); header.setRepeaters(m_g2Gateway, m_g2Repeater); - m_g2Handler->writeHeader(header); + m_g2HandlerPool->writeHeader(header); delete data; } } else if (string_right(callsign, 1) != "L" && string_right(callsign, 1) != "U") { @@ -2115,7 +2115,7 @@ void CRepeaterHandler::g2CommandHandler(const std::string& callsign, const std:: m_g2Gateway = data->getGateway(); header.setDestination(m_g2Address, G2_DV_PORT); header.setRepeaters(m_g2Gateway, m_g2Repeater); - m_g2Handler->writeHeader(header); + m_g2HandlerPool->writeHeader(header); delete data; } diff --git a/RepeaterHandler.h b/RepeaterHandler.h index 0d7922a..0b29b85 100644 --- a/RepeaterHandler.h +++ b/RepeaterHandler.h @@ -168,7 +168,7 @@ private: static CRepeaterHandler** m_repeaters; static std::string m_localAddress; - static CG2ProtocolHandlerPool* m_g2Handler; + static CG2ProtocolHandlerPool* m_g2HandlerPool; static CCacheManager* m_cache; static std::string m_gateway; static CIRCDDB* m_irc; From 9a2b8e67c2d9bda15f2ac384ce76e4b5650a3d1e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 26 Jan 2022 20:17:42 +0100 Subject: [PATCH 173/201] #16 disable log message --- IRCDDBApp.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/IRCDDBApp.cpp b/IRCDDBApp.cpp index 5416d31..58909de 100644 --- a/IRCDDBApp.cpp +++ b/IRCDDBApp.cpp @@ -848,7 +848,7 @@ void IRCDDBApp::doUpdate(std::string& msg) nick = sm1[1]; if (1 == m_d->m_rptrMap.count(value)) { - CLog::logTrace("doUptate RPTR already present"); + // CLog::logTrace("doUptate RPTR already present"); IRCDDBAppRptrObject o = m_d->m_rptrMap[value]; zonerp_cs = o.m_zonerp_cs; CUtils::ReplaceChar(zonerp_cs, '_', ' '); @@ -857,7 +857,7 @@ void IRCDDBApp::doUpdate(std::string& msg) zonerp_cs.push_back('G'); } else { - CLog::logTrace("doUptate RPTR not present"); + // CLog::logTrace("doUptate RPTR not present"); zonerp_cs = arearp_cs.substr(0, arearp_cs.length() - 1U); ip_addr = nick.empty() ? getIPAddressFromCall(zonerp_cs) : getIPAddressFromNick(nick); zonerp_cs.push_back('G'); From 41a891d9e32fee017969d53064668f713ded92de Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 26 Jan 2022 20:18:06 +0100 Subject: [PATCH 174/201] #16 add some logging for incoming G2 headers --- DStarGatewayThread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DStarGatewayThread.cpp b/DStarGatewayThread.cpp index 4f2873d..693075d 100644 --- a/DStarGatewayThread.cpp +++ b/DStarGatewayThread.cpp @@ -1102,7 +1102,7 @@ void CDStarGatewayThread::processG2() case GT_HEADER: { CHeaderData* header = m_g2HandlerPool->readHeader(); if (header != NULL) { - // CLog::logInfo("G2 header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s Flags: %02X %02X %02X", header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str(), header->getFlag1(), header->getFlag2(), header->getFlag3()); + CLog::logDebug("G2 header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s Flags: %02X %02X %02X", header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str(), header->getFlag1(), header->getFlag2(), header->getFlag3()); CG2Handler::process(*header); delete header; } From 8fea9370624415ac4106b3063db1b9cd6ab37b41 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 26 Jan 2022 20:20:15 +0100 Subject: [PATCH 175/201] #16 clean up routes after inactivity --- .vscode/settings.json | 3 ++- G2Handler.cpp | 2 ++ G2ProtocolHandler.cpp | 11 ++++++++++- G2ProtocolHandler.h | 7 ++++--- G2ProtocolHandlerPool.cpp | 25 +++++++++++++++++++++++-- G2ProtocolHandlerPool.h | 2 ++ 6 files changed, 43 insertions(+), 7 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 5c9c832..42e5956 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -72,7 +72,8 @@ "thread": "cpp", "typeindex": "cpp", "variant": "cpp", - "iostream": "cpp" + "iostream": "cpp", + "fstream": "cpp" }, "editor.tokenColorCustomizations": { "textMateRules": [ diff --git a/G2Handler.cpp b/G2Handler.cpp index 8670b32..12db48d 100644 --- a/G2Handler.cpp +++ b/G2Handler.cpp @@ -175,6 +175,8 @@ void CG2Handler::process(CAMBEData& data) void CG2Handler::clock(unsigned int ms) { + m_handler->clock(ms); + for (unsigned int i = 0U; i < m_maxRoutes; i++) { CG2Handler* route = m_routes[i]; if (route != NULL) { diff --git a/G2ProtocolHandler.cpp b/G2ProtocolHandler.cpp index ae3ac4e..cbaf541 100644 --- a/G2ProtocolHandler.cpp +++ b/G2ProtocolHandler.cpp @@ -33,8 +33,10 @@ m_socket(socket), m_type(GT_NONE), m_buffer(nullptr), m_length(0U), -m_address(destination) +m_address(destination), +m_inactivityTimer(1000U, 29U) { + m_inactivityTimer.start(); m_buffer = new unsigned char[bufferSize]; ::memset(m_buffer, 0, bufferSize); } @@ -46,6 +48,7 @@ CG2ProtocolHandler::~CG2ProtocolHandler() bool CG2ProtocolHandler::writeHeader(const CHeaderData& header) { + m_inactivityTimer.start(); unsigned char buffer[60U]; unsigned int length = header.getG2Data(buffer, 60U, true); @@ -68,6 +71,7 @@ bool CG2ProtocolHandler::writeHeader(const CHeaderData& header) bool CG2ProtocolHandler::writeAMBE(const CAMBEData& data) { + m_inactivityTimer.start(); unsigned char buffer[40U]; unsigned int length = data.getG2Data(buffer, 40U); @@ -90,6 +94,8 @@ bool CG2ProtocolHandler::setBuffer(unsigned char * buffer, int length) if(length <= 0) return false; + m_inactivityTimer.start(); + m_length = length; if (m_buffer[0] != 'D' || m_buffer[1] != 'S' || m_buffer[2] != 'V' || m_buffer[3] != 'T') { @@ -110,6 +116,7 @@ bool CG2ProtocolHandler::setBuffer(unsigned char * buffer, int length) CHeaderData* CG2ProtocolHandler::readHeader() { + m_inactivityTimer.start(); if (m_type != GT_HEADER) return nullptr; @@ -128,6 +135,7 @@ CHeaderData* CG2ProtocolHandler::readHeader() CAMBEData* CG2ProtocolHandler::readAMBE() { + m_inactivityTimer.start(); if (m_type != GT_AMBE) return NULL; @@ -142,3 +150,4 @@ CAMBEData* CG2ProtocolHandler::readAMBE() return data; } + diff --git a/G2ProtocolHandler.h b/G2ProtocolHandler.h index df50724..edcf2b3 100644 --- a/G2ProtocolHandler.h +++ b/G2ProtocolHandler.h @@ -27,6 +27,7 @@ #include "HeaderData.h" #include "AMBEData.h" #include "NetUtils.h" +#include "Timer.h" enum G2_TYPE { GT_NONE, @@ -52,16 +53,16 @@ public: bool setBuffer(unsigned char * buffer, int length); - void close(); - + void clock(unsigned int ms) { m_inactivityTimer.clock(ms); } + bool isInactive() { return m_inactivityTimer.hasExpired(); } private: - CUDPReaderWriter * m_socket; G2_TYPE m_type; unsigned char* m_buffer; unsigned int m_length; struct sockaddr_storage m_address; + CTimer m_inactivityTimer; bool readPackets(); }; diff --git a/G2ProtocolHandlerPool.cpp b/G2ProtocolHandlerPool.cpp index 92467fd..7db90d8 100644 --- a/G2ProtocolHandlerPool.cpp +++ b/G2ProtocolHandlerPool.cpp @@ -127,7 +127,10 @@ void CG2ProtocolHandlerPool::traverseNat(const std::string& address) bool CG2ProtocolHandlerPool::writeHeader(const CHeaderData& header) { - auto handler = findHandler(header.getDestination(), IMT_ADDRESS_ONLY); + auto handler = findHandler(header.getDestination(), IMT_ADDRESS_AND_PORT); + if(handler == nullptr) + handler = findHandler(header.getDestination(), IMT_ADDRESS_ONLY); + if(handler == nullptr) { handler = new CG2ProtocolHandler(&m_socket, header.getDestination(), G2_BUFFER_LENGTH); m_pool.push_back(handler); @@ -138,7 +141,10 @@ bool CG2ProtocolHandlerPool::writeHeader(const CHeaderData& header) bool CG2ProtocolHandlerPool::writeAMBE(const CAMBEData& data) { - auto handler = findHandler(data.getDestination(), IMT_ADDRESS_ONLY); + auto handler = findHandler(data.getDestination(), IMT_ADDRESS_AND_PORT); + if(handler == nullptr) + handler = findHandler(data.getDestination(), IMT_ADDRESS_ONLY); + if(handler == nullptr) { handler = new CG2ProtocolHandler(&m_socket, data.getDestination(), G2_BUFFER_LENGTH); m_pool.push_back(handler); @@ -166,4 +172,19 @@ CG2ProtocolHandler * CG2ProtocolHandlerPool::findHandler(in_addr addr, unsigned TOIPV4(addrStorage)->sin_port = port; return findHandler(addrStorage, matchType); +} + +void CG2ProtocolHandlerPool::clock(unsigned int ms) +{ + for(auto it = m_pool.begin(); it != m_pool.end();) { + (*it)->clock(ms); + if((*it)->isInactive()) { + delete (*it); + it = m_pool.erase(it); + m_index = m_pool.end(); + } + else { + it++; + } + } } \ No newline at end of file diff --git a/G2ProtocolHandlerPool.h b/G2ProtocolHandlerPool.h index afdc339..9926fc3 100644 --- a/G2ProtocolHandlerPool.h +++ b/G2ProtocolHandlerPool.h @@ -78,6 +78,8 @@ public: void traverseNat(const std::string& address); + void clock(unsigned int ms); + private: bool readPackets(); CG2ProtocolHandler * findHandler(const struct sockaddr_storage& addr, IPMATCHTYPE matchType) const; From c7734af8afc60d42a2320d58014b3f63f1726cbe Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 26 Jan 2022 20:37:31 +0100 Subject: [PATCH 176/201] #16 only read header once --- G2ProtocolHandler.cpp | 10 ++++++++-- G2ProtocolHandler.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/G2ProtocolHandler.cpp b/G2ProtocolHandler.cpp index cbaf541..e73d918 100644 --- a/G2ProtocolHandler.cpp +++ b/G2ProtocolHandler.cpp @@ -34,7 +34,8 @@ m_type(GT_NONE), m_buffer(nullptr), m_length(0U), m_address(destination), -m_inactivityTimer(1000U, 29U) +m_inactivityTimer(1000U, 29U), +m_id(0U) { m_inactivityTimer.start(); m_buffer = new unsigned char[bufferSize]; @@ -117,7 +118,7 @@ bool CG2ProtocolHandler::setBuffer(unsigned char * buffer, int length) CHeaderData* CG2ProtocolHandler::readHeader() { m_inactivityTimer.start(); - if (m_type != GT_HEADER) + if (m_type != GT_HEADER || m_id != 0U) return nullptr; m_type = GT_NONE; // Header data has been consumed, reset our status @@ -130,6 +131,8 @@ CHeaderData* CG2ProtocolHandler::readHeader() return nullptr; } + m_id = header->getId();// remember the id so we do not read it duplicate + return header; } @@ -148,6 +151,9 @@ CAMBEData* CG2ProtocolHandler::readAMBE() return NULL; } + if(data->isEnd()) + m_id = 0U; + return data; } diff --git a/G2ProtocolHandler.h b/G2ProtocolHandler.h index edcf2b3..92b42a0 100644 --- a/G2ProtocolHandler.h +++ b/G2ProtocolHandler.h @@ -63,6 +63,7 @@ private: unsigned int m_length; struct sockaddr_storage m_address; CTimer m_inactivityTimer; + unsigned int m_id; bool readPackets(); }; From a39e5f656cb5e373675a8ffd3da1d7fb03853552 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Wed, 26 Jan 2022 20:42:36 +0100 Subject: [PATCH 177/201] #16 remove duplicate header check (done below) --- G2Handler.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/G2Handler.cpp b/G2Handler.cpp index 12db48d..1aaf362 100644 --- a/G2Handler.cpp +++ b/G2Handler.cpp @@ -101,16 +101,7 @@ void CG2Handler::process(CHeaderData& header) in_addr address = header.getYourAddress(); unsigned int id = header.getId(); - - for (unsigned int i = 0U; i < m_maxRoutes; i++) { - CG2Handler* route = m_routes[i]; - if (route != NULL) { - // Is this a duplicate header, ignore it - if (route->m_id == id) - return; - } - } - + // Find the destination repeater CRepeaterHandler* repeater = CRepeaterHandler::findDVRepeater(header.getRptCall2()); if (repeater == NULL) { @@ -176,7 +167,7 @@ void CG2Handler::process(CAMBEData& data) void CG2Handler::clock(unsigned int ms) { m_handler->clock(ms); - + for (unsigned int i = 0U; i < m_maxRoutes; i++) { CG2Handler* route = m_routes[i]; if (route != NULL) { From 06f7c9d262af7907689c4e536a57346d12f31c66 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 28 Jan 2022 17:08:05 +0100 Subject: [PATCH 178/201] #16 only restart time on read header or ambe --- G2ProtocolHandler.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/G2ProtocolHandler.cpp b/G2ProtocolHandler.cpp index e73d918..5592acd 100644 --- a/G2ProtocolHandler.cpp +++ b/G2ProtocolHandler.cpp @@ -95,8 +95,6 @@ bool CG2ProtocolHandler::setBuffer(unsigned char * buffer, int length) if(length <= 0) return false; - m_inactivityTimer.start(); - m_length = length; if (m_buffer[0] != 'D' || m_buffer[1] != 'S' || m_buffer[2] != 'V' || m_buffer[3] != 'T') { From dafd00c245081413f3da7c9b2bb1a96ab4a98aca Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Fri, 28 Jan 2022 17:11:35 +0100 Subject: [PATCH 179/201] #16 update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e938cb4..755b04f 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,7 @@ the testing framwework used is Google Test. # 5. Version History ## 5.1. Version 0.5 +- [Bugfix] Two simultaneous incoming G2 streams would fail to be transmitted on dual band repeaters ([#16](https://github.com/F4FXL/DStarGateway/issues/16)) - [Improvement] Add NAT Traversal for G2 and DExtra, using IRCDDB as a Rendez Vous server ([#5](https://github.com/F4FXL/DStarGateway/issues/5)) - [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)) From afe99951417a6dfd42b933be6d66a09da2321281 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 29 Jan 2022 15:38:06 +0100 Subject: [PATCH 180/201] #17 clean up includes in tests --- .vscode/tasks.json | 10 +++++----- Tests/APRSFormater/frameToString.cpp | 2 +- Tests/APRSParser/parseAPRSFrame.cpp | 2 +- Tests/APRStoDPRS/aprsToDPRS.cpp | 2 +- Tests/Config/getValue.cpp | 2 +- Tests/Config/load.cpp | 2 +- Tests/DCSProtocolHandlerPool/getHandler.cpp | 2 +- Tests/DCSProtocolHandlerPool/getIncomingHandler.cpp | 2 +- Tests/DPlusProtocolHandlerPool/getHandler.cpp | 2 +- Tests/DPlusProtocolHandlerPool/getIncomingHandler.cpp | 2 +- Tests/DextraProtocolHandlerPool/getHandler.cpp | 2 +- Tests/DextraProtocolHandlerPool/getIncomingHandler.cpp | 2 +- Tests/NetUtils/lookup.cpp | 2 +- Tests/NetUtils/lookupV4.cpp | 2 +- Tests/NetUtils/lookupV6.cpp | 2 +- Tests/NetUtils/match.cpp | 2 +- Tests/RSMS1AMessageBuilder/buildMessage.cpp | 2 +- Tests/RSMS1AMessageBuilder/parseMessage.cpp | 2 +- Tests/SlowDataEncoder/GPSData.cpp | 4 ++-- Tests/SlowDataEncoder/HeaderData.cpp | 4 ++-- Tests/SlowDataEncoder/InterleavedData.cpp | 4 ++-- Tests/SlowDataEncoder/TextData.cpp | 4 ++-- Tests/StringUtils/stringToPort.cpp | 2 +- Tests/Utils/swap_endian.cpp | 2 +- Tests/Utils/swap_endian_be.cpp | 6 +++--- 25 files changed, 35 insertions(+), 35 deletions(-) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 168ca95..ac3f100 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,10 +12,7 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] }, { @@ -28,7 +25,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] } ] diff --git a/Tests/APRSFormater/frameToString.cpp b/Tests/APRSFormater/frameToString.cpp index 7b457e4..da17cbe 100644 --- a/Tests/APRSFormater/frameToString.cpp +++ b/Tests/APRSFormater/frameToString.cpp @@ -18,7 +18,7 @@ #include -#include "../../APRSFormater.h" +#include "APRSFormater.h" class APRSFormater_frameToString : public ::testing::Test { diff --git a/Tests/APRSParser/parseAPRSFrame.cpp b/Tests/APRSParser/parseAPRSFrame.cpp index fdead96..a2d1ae1 100644 --- a/Tests/APRSParser/parseAPRSFrame.cpp +++ b/Tests/APRSParser/parseAPRSFrame.cpp @@ -18,7 +18,7 @@ #include -#include "../../APRSParser.h" +#include "APRSParser.h" namespace APRSParserTests { diff --git a/Tests/APRStoDPRS/aprsToDPRS.cpp b/Tests/APRStoDPRS/aprsToDPRS.cpp index 872d3a0..1334e8f 100644 --- a/Tests/APRStoDPRS/aprsToDPRS.cpp +++ b/Tests/APRStoDPRS/aprsToDPRS.cpp @@ -18,7 +18,7 @@ #include -#include "../../APRStoDPRS.h" +#include "APRStoDPRS.h" namespace APRStoDPRSTests { diff --git a/Tests/Config/getValue.cpp b/Tests/Config/getValue.cpp index 5df3883..c7c0d15 100644 --- a/Tests/Config/getValue.cpp +++ b/Tests/Config/getValue.cpp @@ -20,7 +20,7 @@ #include #include -#include "../../Config.h" +#include "Config.h" namespace ConfigTests { diff --git a/Tests/Config/load.cpp b/Tests/Config/load.cpp index e03cea6..3d600e8 100644 --- a/Tests/Config/load.cpp +++ b/Tests/Config/load.cpp @@ -20,7 +20,7 @@ #include #include -#include "../../Config.h" +#include "Config.h" namespace ConfigTests { diff --git a/Tests/DCSProtocolHandlerPool/getHandler.cpp b/Tests/DCSProtocolHandlerPool/getHandler.cpp index 3d31874..9721803 100644 --- a/Tests/DCSProtocolHandlerPool/getHandler.cpp +++ b/Tests/DCSProtocolHandlerPool/getHandler.cpp @@ -18,7 +18,7 @@ #include -#include "../../DCSProtocolHandlerPool.h" +#include "DCSProtocolHandlerPool.h" namespace DCSProtocolHandlerPoolTests { diff --git a/Tests/DCSProtocolHandlerPool/getIncomingHandler.cpp b/Tests/DCSProtocolHandlerPool/getIncomingHandler.cpp index f4c3f34..b675b05 100644 --- a/Tests/DCSProtocolHandlerPool/getIncomingHandler.cpp +++ b/Tests/DCSProtocolHandlerPool/getIncomingHandler.cpp @@ -18,7 +18,7 @@ #include -#include "../../DCSProtocolHandlerPool.h" +#include "DCSProtocolHandlerPool.h" namespace DCSProtocolHandlerPoolTests { diff --git a/Tests/DPlusProtocolHandlerPool/getHandler.cpp b/Tests/DPlusProtocolHandlerPool/getHandler.cpp index 2389298..dbb6948 100644 --- a/Tests/DPlusProtocolHandlerPool/getHandler.cpp +++ b/Tests/DPlusProtocolHandlerPool/getHandler.cpp @@ -18,7 +18,7 @@ #include -#include "../../DPlusProtocolHandlerPool.h" +#include "DPlusProtocolHandlerPool.h" namespace DPlusProtocolHandlerPoolTests { diff --git a/Tests/DPlusProtocolHandlerPool/getIncomingHandler.cpp b/Tests/DPlusProtocolHandlerPool/getIncomingHandler.cpp index a27dbd9..14ddf6e 100644 --- a/Tests/DPlusProtocolHandlerPool/getIncomingHandler.cpp +++ b/Tests/DPlusProtocolHandlerPool/getIncomingHandler.cpp @@ -18,7 +18,7 @@ #include -#include "../../DPlusProtocolHandlerPool.h" +#include "DPlusProtocolHandlerPool.h" namespace DPlusProtocolHandlerPoolTests { diff --git a/Tests/DextraProtocolHandlerPool/getHandler.cpp b/Tests/DextraProtocolHandlerPool/getHandler.cpp index bc7c805..0f0f6dc 100644 --- a/Tests/DextraProtocolHandlerPool/getHandler.cpp +++ b/Tests/DextraProtocolHandlerPool/getHandler.cpp @@ -18,7 +18,7 @@ #include -#include "../../DExtraProtocolHandlerPool.h" +#include "DExtraProtocolHandlerPool.h" namespace DextraProtocolHandlerPoolTests { diff --git a/Tests/DextraProtocolHandlerPool/getIncomingHandler.cpp b/Tests/DextraProtocolHandlerPool/getIncomingHandler.cpp index c6bfbc5..ae90c3d 100644 --- a/Tests/DextraProtocolHandlerPool/getIncomingHandler.cpp +++ b/Tests/DextraProtocolHandlerPool/getIncomingHandler.cpp @@ -18,7 +18,7 @@ #include -#include "../../DExtraProtocolHandlerPool.h" +#include "DExtraProtocolHandlerPool.h" namespace DextraProtocolHandlerPoolTests { diff --git a/Tests/NetUtils/lookup.cpp b/Tests/NetUtils/lookup.cpp index f55f23c..e499f59 100644 --- a/Tests/NetUtils/lookup.cpp +++ b/Tests/NetUtils/lookup.cpp @@ -20,7 +20,7 @@ #include -#include "../../NetUtils.h" +#include "NetUtils.h" namespace NetUtilsTests { diff --git a/Tests/NetUtils/lookupV4.cpp b/Tests/NetUtils/lookupV4.cpp index 5f554fb..da5b88e 100644 --- a/Tests/NetUtils/lookupV4.cpp +++ b/Tests/NetUtils/lookupV4.cpp @@ -20,7 +20,7 @@ #include -#include "../../NetUtils.h" +#include "NetUtils.h" namespace NetUtilsTests { diff --git a/Tests/NetUtils/lookupV6.cpp b/Tests/NetUtils/lookupV6.cpp index 1a6c9bf..99b95af 100644 --- a/Tests/NetUtils/lookupV6.cpp +++ b/Tests/NetUtils/lookupV6.cpp @@ -20,7 +20,7 @@ #include -#include "../../NetUtils.h" +#include "NetUtils.h" namespace NetUtilsTests { diff --git a/Tests/NetUtils/match.cpp b/Tests/NetUtils/match.cpp index 0f58d12..bade2b5 100644 --- a/Tests/NetUtils/match.cpp +++ b/Tests/NetUtils/match.cpp @@ -20,7 +20,7 @@ #include -#include "../../NetUtils.h" +#include "NetUtils.h" namespace NetUtilsTests { diff --git a/Tests/RSMS1AMessageBuilder/buildMessage.cpp b/Tests/RSMS1AMessageBuilder/buildMessage.cpp index aefcb68..42ef3d0 100644 --- a/Tests/RSMS1AMessageBuilder/buildMessage.cpp +++ b/Tests/RSMS1AMessageBuilder/buildMessage.cpp @@ -18,7 +18,7 @@ #include -#include "../../RSMS1AMessageBuilder.h" +#include "RSMS1AMessageBuilder.h" namespace RSMS1AMessageBuilderTests { diff --git a/Tests/RSMS1AMessageBuilder/parseMessage.cpp b/Tests/RSMS1AMessageBuilder/parseMessage.cpp index 5e1c82d..c614c13 100644 --- a/Tests/RSMS1AMessageBuilder/parseMessage.cpp +++ b/Tests/RSMS1AMessageBuilder/parseMessage.cpp @@ -18,7 +18,7 @@ #include -#include "../../RSMS1AMessageBuilder.h" +#include "RSMS1AMessageBuilder.h" namespace RSMS1AMessageBuilderTests { diff --git a/Tests/SlowDataEncoder/GPSData.cpp b/Tests/SlowDataEncoder/GPSData.cpp index 21bc48f..85fe6c6 100644 --- a/Tests/SlowDataEncoder/GPSData.cpp +++ b/Tests/SlowDataEncoder/GPSData.cpp @@ -18,8 +18,8 @@ #include -#include "../../SlowDataEncoder.h" -#include "../../DStarDefines.h" +#include "SlowDataEncoder.h" +#include "DStarDefines.h" namespace SlowDataEncoderTests { diff --git a/Tests/SlowDataEncoder/HeaderData.cpp b/Tests/SlowDataEncoder/HeaderData.cpp index a3d253c..9948e78 100644 --- a/Tests/SlowDataEncoder/HeaderData.cpp +++ b/Tests/SlowDataEncoder/HeaderData.cpp @@ -18,8 +18,8 @@ #include -#include "../../SlowDataEncoder.h" -#include "../../DStarDefines.h" +#include "SlowDataEncoder.h" +#include "DStarDefines.h" namespace SlowDataEncoderTests { diff --git a/Tests/SlowDataEncoder/InterleavedData.cpp b/Tests/SlowDataEncoder/InterleavedData.cpp index 0651b15..7d225e1 100644 --- a/Tests/SlowDataEncoder/InterleavedData.cpp +++ b/Tests/SlowDataEncoder/InterleavedData.cpp @@ -19,8 +19,8 @@ #include #include -#include "../../SlowDataEncoder.h" -#include "../../DStarDefines.h" +#include "SlowDataEncoder.h" +#include "DStarDefines.h" namespace SlowDataEncoderTests { diff --git a/Tests/SlowDataEncoder/TextData.cpp b/Tests/SlowDataEncoder/TextData.cpp index b2ba775..22c4c7d 100644 --- a/Tests/SlowDataEncoder/TextData.cpp +++ b/Tests/SlowDataEncoder/TextData.cpp @@ -18,8 +18,8 @@ #include -#include "../../SlowDataEncoder.h" -#include "../../DStarDefines.h" +#include "SlowDataEncoder.h" +#include "DStarDefines.h" namespace SlowDataEncoderTests { diff --git a/Tests/StringUtils/stringToPort.cpp b/Tests/StringUtils/stringToPort.cpp index b3cc740..6770a89 100644 --- a/Tests/StringUtils/stringToPort.cpp +++ b/Tests/StringUtils/stringToPort.cpp @@ -18,7 +18,7 @@ #include -#include "../../StringUtils.h" +#include "StringUtils.h" namespace StringUtilsTests { diff --git a/Tests/Utils/swap_endian.cpp b/Tests/Utils/swap_endian.cpp index 767d10e..af94adc 100644 --- a/Tests/Utils/swap_endian.cpp +++ b/Tests/Utils/swap_endian.cpp @@ -18,7 +18,7 @@ #include -#include "../../Utils.h" +#include "Utils.h" class Utils_swap_endian : public ::testing::Test { diff --git a/Tests/Utils/swap_endian_be.cpp b/Tests/Utils/swap_endian_be.cpp index 8e3a817..50f7cb2 100644 --- a/Tests/Utils/swap_endian_be.cpp +++ b/Tests/Utils/swap_endian_be.cpp @@ -18,9 +18,9 @@ #include -#include "../../Utils.h" -#include "../../StringUtils.h" -#include "../../Log.h" +#include "Utils.h" +#include "StringUtils.h" +#include "Log.h" class Utils_swap_endian_be : public ::testing::Test { From 1a20ce54434f09a6602b8b1da7d489e2e790bfd1 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 29 Jan 2022 17:29:27 +0100 Subject: [PATCH 181/201] #17 Add BaseCommon --- .vscode/tasks.json | 10 +++++----- CCITTChecksum.cpp => BaseCommon/CCITTChecksum.cpp | 0 CCITTChecksum.h => BaseCommon/CCITTChecksum.h | 0 Config.cpp => BaseCommon/Config.cpp | 0 Config.h => BaseCommon/Config.h | 0 Log.cpp => BaseCommon/Log.cpp | 0 Log.h => BaseCommon/Log.h | 0 .../LogConsoleTarget.cpp | 0 .../LogConsoleTarget.h | 0 LogFileTarget.cpp => BaseCommon/LogFileTarget.cpp | 0 LogFileTarget.h => BaseCommon/LogFileTarget.h | 0 LogSeverity.h => BaseCommon/LogSeverity.h | 0 LogTarget.cpp => BaseCommon/LogTarget.cpp | 0 LogTarget.h => BaseCommon/LogTarget.h | 0 BaseCommon/Makefile | 12 ++++++++++++ NetUtils.cpp => BaseCommon/NetUtils.cpp | 0 NetUtils.h => BaseCommon/NetUtils.h | 0 RingBuffer.h => BaseCommon/RingBuffer.h | 0 SHA256.cpp => BaseCommon/SHA256.cpp | 0 SHA256.h => BaseCommon/SHA256.h | 0 StringUtils.cpp => BaseCommon/StringUtils.cpp | 0 StringUtils.h => BaseCommon/StringUtils.h | 0 Thread.cpp => BaseCommon/Thread.cpp | 0 Thread.h => BaseCommon/Thread.h | 0 Timer.cpp => BaseCommon/Timer.cpp | 0 Timer.h => BaseCommon/Timer.h | 0 Utils.cpp => BaseCommon/Utils.cpp | 0 Utils.h => BaseCommon/Utils.h | 0 Makefile | 14 +++++++++----- 29 files changed, 26 insertions(+), 10 deletions(-) rename CCITTChecksum.cpp => BaseCommon/CCITTChecksum.cpp (100%) rename CCITTChecksum.h => BaseCommon/CCITTChecksum.h (100%) rename Config.cpp => BaseCommon/Config.cpp (100%) rename Config.h => BaseCommon/Config.h (100%) rename Log.cpp => BaseCommon/Log.cpp (100%) rename Log.h => BaseCommon/Log.h (100%) rename LogConsoleTarget.cpp => BaseCommon/LogConsoleTarget.cpp (100%) rename LogConsoleTarget.h => BaseCommon/LogConsoleTarget.h (100%) rename LogFileTarget.cpp => BaseCommon/LogFileTarget.cpp (100%) rename LogFileTarget.h => BaseCommon/LogFileTarget.h (100%) rename LogSeverity.h => BaseCommon/LogSeverity.h (100%) rename LogTarget.cpp => BaseCommon/LogTarget.cpp (100%) rename LogTarget.h => BaseCommon/LogTarget.h (100%) create mode 100644 BaseCommon/Makefile rename NetUtils.cpp => BaseCommon/NetUtils.cpp (100%) rename NetUtils.h => BaseCommon/NetUtils.h (100%) rename RingBuffer.h => BaseCommon/RingBuffer.h (100%) rename SHA256.cpp => BaseCommon/SHA256.cpp (100%) rename SHA256.h => BaseCommon/SHA256.h (100%) rename StringUtils.cpp => BaseCommon/StringUtils.cpp (100%) rename StringUtils.h => BaseCommon/StringUtils.h (100%) rename Thread.cpp => BaseCommon/Thread.cpp (100%) rename Thread.h => BaseCommon/Thread.h (100%) rename Timer.cpp => BaseCommon/Timer.cpp (100%) rename Timer.h => BaseCommon/Timer.h (100%) rename Utils.cpp => BaseCommon/Utils.cpp (100%) rename Utils.h => BaseCommon/Utils.h (100%) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index ac3f100..168ca95 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -12,7 +12,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] }, { @@ -25,10 +28,7 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] } ] diff --git a/CCITTChecksum.cpp b/BaseCommon/CCITTChecksum.cpp similarity index 100% rename from CCITTChecksum.cpp rename to BaseCommon/CCITTChecksum.cpp diff --git a/CCITTChecksum.h b/BaseCommon/CCITTChecksum.h similarity index 100% rename from CCITTChecksum.h rename to BaseCommon/CCITTChecksum.h diff --git a/Config.cpp b/BaseCommon/Config.cpp similarity index 100% rename from Config.cpp rename to BaseCommon/Config.cpp diff --git a/Config.h b/BaseCommon/Config.h similarity index 100% rename from Config.h rename to BaseCommon/Config.h diff --git a/Log.cpp b/BaseCommon/Log.cpp similarity index 100% rename from Log.cpp rename to BaseCommon/Log.cpp diff --git a/Log.h b/BaseCommon/Log.h similarity index 100% rename from Log.h rename to BaseCommon/Log.h diff --git a/LogConsoleTarget.cpp b/BaseCommon/LogConsoleTarget.cpp similarity index 100% rename from LogConsoleTarget.cpp rename to BaseCommon/LogConsoleTarget.cpp diff --git a/LogConsoleTarget.h b/BaseCommon/LogConsoleTarget.h similarity index 100% rename from LogConsoleTarget.h rename to BaseCommon/LogConsoleTarget.h diff --git a/LogFileTarget.cpp b/BaseCommon/LogFileTarget.cpp similarity index 100% rename from LogFileTarget.cpp rename to BaseCommon/LogFileTarget.cpp diff --git a/LogFileTarget.h b/BaseCommon/LogFileTarget.h similarity index 100% rename from LogFileTarget.h rename to BaseCommon/LogFileTarget.h diff --git a/LogSeverity.h b/BaseCommon/LogSeverity.h similarity index 100% rename from LogSeverity.h rename to BaseCommon/LogSeverity.h diff --git a/LogTarget.cpp b/BaseCommon/LogTarget.cpp similarity index 100% rename from LogTarget.cpp rename to BaseCommon/LogTarget.cpp diff --git a/LogTarget.h b/BaseCommon/LogTarget.h similarity index 100% rename from LogTarget.h rename to BaseCommon/LogTarget.h diff --git a/BaseCommon/Makefile b/BaseCommon/Makefile new file mode 100644 index 0000000..dc769f0 --- /dev/null +++ b/BaseCommon/Makefile @@ -0,0 +1,12 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:.cpp=.o) +DEPS = $(SRCS:.cpp=.d) + +BaseCommon.a: $(OBJS) + $(AR) rcs BaseCommon.a $(OBJS) + +%.o : %.cpp + $(CC) $(CPPFLAGS) -MMD -MD -c $< -o $@ + +clean: + $(RM) *.o *.d BaseCommon.a \ No newline at end of file diff --git a/NetUtils.cpp b/BaseCommon/NetUtils.cpp similarity index 100% rename from NetUtils.cpp rename to BaseCommon/NetUtils.cpp diff --git a/NetUtils.h b/BaseCommon/NetUtils.h similarity index 100% rename from NetUtils.h rename to BaseCommon/NetUtils.h diff --git a/RingBuffer.h b/BaseCommon/RingBuffer.h similarity index 100% rename from RingBuffer.h rename to BaseCommon/RingBuffer.h diff --git a/SHA256.cpp b/BaseCommon/SHA256.cpp similarity index 100% rename from SHA256.cpp rename to BaseCommon/SHA256.cpp diff --git a/SHA256.h b/BaseCommon/SHA256.h similarity index 100% rename from SHA256.h rename to BaseCommon/SHA256.h diff --git a/StringUtils.cpp b/BaseCommon/StringUtils.cpp similarity index 100% rename from StringUtils.cpp rename to BaseCommon/StringUtils.cpp diff --git a/StringUtils.h b/BaseCommon/StringUtils.h similarity index 100% rename from StringUtils.h rename to BaseCommon/StringUtils.h diff --git a/Thread.cpp b/BaseCommon/Thread.cpp similarity index 100% rename from Thread.cpp rename to BaseCommon/Thread.cpp diff --git a/Thread.h b/BaseCommon/Thread.h similarity index 100% rename from Thread.h rename to BaseCommon/Thread.h diff --git a/Timer.cpp b/BaseCommon/Timer.cpp similarity index 100% rename from Timer.cpp rename to BaseCommon/Timer.cpp diff --git a/Timer.h b/BaseCommon/Timer.h similarity index 100% rename from Timer.h rename to BaseCommon/Timer.h diff --git a/Utils.cpp b/BaseCommon/Utils.cpp similarity index 100% rename from Utils.cpp rename to BaseCommon/Utils.cpp diff --git a/Utils.h b/BaseCommon/Utils.h similarity index 100% rename from Utils.h rename to BaseCommon/Utils.h diff --git a/Makefile b/Makefile index 86bc984..97b259f 100644 --- a/Makefile +++ b/Makefile @@ -45,11 +45,14 @@ DEPS = $(SRCS:.cpp=.d) .PHONY: all all: dstargateway -dstargateway : GitVersion.h $(OBJS) - $(CC) $(CPPFLAGS) -o dstargateway $(OBJS) $(LDFLAGS) +dstargateway : GitVersion.h $(OBJS) BaseCommon/BaseCommon.a + $(CC) $(CPPFLAGS) -o dstargateway $(OBJS) BaseCommon/BaseCommon.a $(LDFLAGS) %.o : %.cpp - $(CC) $(CPPFLAGS) -MMD -MD -c $< -o $@ + $(CC) -IBaseCommon/ $(CPPFLAGS) -MMD -MD -c $< -o $@ + +BaseCommon/BaseCommon.a: FORCE + $(MAKE) -C BaseCommon GitVersion.h : FORCE ifneq ("$(wildcard .git/index)","") @@ -71,8 +74,9 @@ endif .PHONY: clean clean: - @$(RM) GitVersion.h $(OBJS) $(DEPS) dstargateway - @$(MAKE) -C Tests clean + $(RM) GitVersion.h *.o *.d dstargateway + $(MAKE) -C Tests clean + $(MAKE) -C BaseCommon clean -include $(DEPS) From af4cd2819f6391ce9dbd18514386b35a28c35fad Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 29 Jan 2022 18:17:06 +0100 Subject: [PATCH 182/201] #17 add APRS lib, move scokets to base common --- APRSFormater.cpp => APRS/APRSFormater.cpp | 0 APRSFormater.h => APRS/APRSFormater.h | 0 APRSFrame.cpp => APRS/APRSFrame.cpp | 0 APRSFrame.h => APRS/APRSFrame.h | 0 APRSParser.cpp => APRS/APRSParser.cpp | 0 APRSParser.h => APRS/APRSParser.h | 0 APRSUtils.cpp => APRS/APRSUtils.cpp | 0 APRSUtils.h => APRS/APRSUtils.h | 0 APRS/Makefile | 12 ++++++++++++ .../TCPReaderWriterClient.cpp | 0 .../TCPReaderWriterClient.h | 0 .../UDPReaderWriter.cpp | 0 UDPReaderWriter.h => BaseCommon/UDPReaderWriter.h | 0 Makefile | 10 +++++++--- 14 files changed, 19 insertions(+), 3 deletions(-) rename APRSFormater.cpp => APRS/APRSFormater.cpp (100%) rename APRSFormater.h => APRS/APRSFormater.h (100%) rename APRSFrame.cpp => APRS/APRSFrame.cpp (100%) rename APRSFrame.h => APRS/APRSFrame.h (100%) rename APRSParser.cpp => APRS/APRSParser.cpp (100%) rename APRSParser.h => APRS/APRSParser.h (100%) rename APRSUtils.cpp => APRS/APRSUtils.cpp (100%) rename APRSUtils.h => APRS/APRSUtils.h (100%) create mode 100644 APRS/Makefile rename TCPReaderWriterClient.cpp => BaseCommon/TCPReaderWriterClient.cpp (100%) rename TCPReaderWriterClient.h => BaseCommon/TCPReaderWriterClient.h (100%) rename UDPReaderWriter.cpp => BaseCommon/UDPReaderWriter.cpp (100%) rename UDPReaderWriter.h => BaseCommon/UDPReaderWriter.h (100%) diff --git a/APRSFormater.cpp b/APRS/APRSFormater.cpp similarity index 100% rename from APRSFormater.cpp rename to APRS/APRSFormater.cpp diff --git a/APRSFormater.h b/APRS/APRSFormater.h similarity index 100% rename from APRSFormater.h rename to APRS/APRSFormater.h diff --git a/APRSFrame.cpp b/APRS/APRSFrame.cpp similarity index 100% rename from APRSFrame.cpp rename to APRS/APRSFrame.cpp diff --git a/APRSFrame.h b/APRS/APRSFrame.h similarity index 100% rename from APRSFrame.h rename to APRS/APRSFrame.h diff --git a/APRSParser.cpp b/APRS/APRSParser.cpp similarity index 100% rename from APRSParser.cpp rename to APRS/APRSParser.cpp diff --git a/APRSParser.h b/APRS/APRSParser.h similarity index 100% rename from APRSParser.h rename to APRS/APRSParser.h diff --git a/APRSUtils.cpp b/APRS/APRSUtils.cpp similarity index 100% rename from APRSUtils.cpp rename to APRS/APRSUtils.cpp diff --git a/APRSUtils.h b/APRS/APRSUtils.h similarity index 100% rename from APRSUtils.h rename to APRS/APRSUtils.h diff --git a/APRS/Makefile b/APRS/Makefile new file mode 100644 index 0000000..d72b824 --- /dev/null +++ b/APRS/Makefile @@ -0,0 +1,12 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:.cpp=.o) +DEPS = $(SRCS:.cpp=.d) + +APRS.a: $(OBJS) + $(AR) rcs APRS.a $(OBJS) + +%.o : %.cpp + $(CC) -I../BaseCommon $(CPPFLAGS) -MMD -MD -c $< -o $@ + +clean: + $(RM) *.o *.d APRS.a \ No newline at end of file diff --git a/TCPReaderWriterClient.cpp b/BaseCommon/TCPReaderWriterClient.cpp similarity index 100% rename from TCPReaderWriterClient.cpp rename to BaseCommon/TCPReaderWriterClient.cpp diff --git a/TCPReaderWriterClient.h b/BaseCommon/TCPReaderWriterClient.h similarity index 100% rename from TCPReaderWriterClient.h rename to BaseCommon/TCPReaderWriterClient.h diff --git a/UDPReaderWriter.cpp b/BaseCommon/UDPReaderWriter.cpp similarity index 100% rename from UDPReaderWriter.cpp rename to BaseCommon/UDPReaderWriter.cpp diff --git a/UDPReaderWriter.h b/BaseCommon/UDPReaderWriter.h similarity index 100% rename from UDPReaderWriter.h rename to BaseCommon/UDPReaderWriter.h diff --git a/Makefile b/Makefile index 97b259f..45eb55d 100644 --- a/Makefile +++ b/Makefile @@ -45,15 +45,18 @@ DEPS = $(SRCS:.cpp=.d) .PHONY: all all: dstargateway -dstargateway : GitVersion.h $(OBJS) BaseCommon/BaseCommon.a - $(CC) $(CPPFLAGS) -o dstargateway $(OBJS) BaseCommon/BaseCommon.a $(LDFLAGS) +dstargateway : GitVersion.h $(OBJS) APRS/APRS.a BaseCommon/BaseCommon.a + $(CC) $(CPPFLAGS) -o dstargateway $(OBJS) APRS/APRS.a BaseCommon/BaseCommon.a $(LDFLAGS) %.o : %.cpp - $(CC) -IBaseCommon/ $(CPPFLAGS) -MMD -MD -c $< -o $@ + $(CC) -IAPRS/ -IBaseCommon/ $(CPPFLAGS) -MMD -MD -c $< -o $@ BaseCommon/BaseCommon.a: FORCE $(MAKE) -C BaseCommon +APRS/APRS.a: BaseCommon/BaseCommon.a FORCE + $(MAKE) -C APRS + GitVersion.h : FORCE ifneq ("$(wildcard .git/index)","") @echo "#pragma once" > /tmp/$@ @@ -76,6 +79,7 @@ endif clean: $(RM) GitVersion.h *.o *.d dstargateway $(MAKE) -C Tests clean + $(MAKE) -C APRS clean $(MAKE) -C BaseCommon clean -include $(DEPS) From 6a6ad5a70f42d3977e1620ce4d311efa778766ce Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 30 Jan 2022 06:37:01 +0100 Subject: [PATCH 183/201] #17 fnished prepratin for aditional tools --- .circleci/config.yml | 9 +-- APRSCollector.cpp => Common/APRSCollector.cpp | 0 APRSCollector.h => Common/APRSCollector.h | 0 APRSEntry.cpp => Common/APRSEntry.cpp | 0 APRSEntry.h => Common/APRSEntry.h | 0 .../APRSEntryStatus.cpp | 0 APRSEntryStatus.h => Common/APRSEntryStatus.h | 0 .../APRSFixedIdFrameProvider.cpp | 0 .../APRSFixedIdFrameProvider.h | 0 .../APRSGPSDIdFrameProvider.cpp | 0 .../APRSGPSDIdFrameProvider.h | 0 APRSHandler.cpp => Common/APRSHandler.cpp | 0 APRSHandler.h => Common/APRSHandler.h | 0 .../APRSHandlerThread.cpp | 0 .../APRSHandlerThread.h | 0 .../APRSIdFrameProvider.cpp | 0 .../APRSIdFrameProvider.h | 0 APRSUnit.cpp => Common/APRSUnit.cpp | 0 APRSUnit.h => Common/APRSUnit.h | 0 APRStoDPRS.cpp => Common/APRStoDPRS.cpp | 0 APRStoDPRS.h => Common/APRStoDPRS.h | 0 .../AnnouncementUnit.cpp | 0 .../AnnouncementUnit.h | 0 AudioUnit.cpp => Common/AudioUnit.cpp | 0 AudioUnit.h => Common/AudioUnit.h | 0 CCSCallback.h => Common/CCSCallback.h | 0 CCSData.cpp => Common/CCSData.cpp | 0 CCSData.h => Common/CCSData.h | 0 .../CCSProtocolHandler.cpp | 0 .../CCSProtocolHandler.h | 0 CacheManager.cpp => Common/CacheManager.cpp | 0 CacheManager.h => Common/CacheManager.h | 0 ConnectData.cpp => Common/ConnectData.cpp | 0 ConnectData.h => Common/ConnectData.h | 0 DCSHandler.cpp => Common/DCSHandler.cpp | 0 DCSHandler.h => Common/DCSHandler.h | 0 .../DCSProtocolHandler.cpp | 0 .../DCSProtocolHandler.h | 0 .../DCSProtocolHandlerPool.cpp | 0 .../DCSProtocolHandlerPool.h | 0 DDHandler.cpp => Common/DDHandler.cpp | 0 DDHandler.h => Common/DDHandler.h | 0 DExtraHandler.cpp => Common/DExtraHandler.cpp | 0 DExtraHandler.h => Common/DExtraHandler.h | 0 .../DExtraProtocolHandler.cpp | 0 .../DExtraProtocolHandler.h | 0 .../DExtraProtocolHandlerPool.cpp | 0 .../DExtraProtocolHandlerPool.h | 0 .../DPlusAuthenticator.cpp | 0 .../DPlusAuthenticator.h | 0 DPlusHandler.cpp => Common/DPlusHandler.cpp | 0 DPlusHandler.h => Common/DPlusHandler.h | 0 .../DPlusProtocolHandler.cpp | 0 .../DPlusProtocolHandler.h | 0 .../DPlusProtocolHandlerPool.cpp | 0 .../DPlusProtocolHandlerPool.h | 0 Defs.h => Common/Defs.h | 0 .../DummyRepeaterProtocolHandler.cpp | 0 .../DummyRepeaterProtocolHandler.h | 0 EchoUnit.cpp => Common/EchoUnit.cpp | 0 EchoUnit.h => Common/EchoUnit.h | 0 G2Handler.cpp => Common/G2Handler.cpp | 0 G2Handler.h => Common/G2Handler.h | 0 .../G2ProtocolHandler.cpp | 0 .../G2ProtocolHandler.h | 0 .../G2ProtocolHandlerPool.cpp | 0 .../G2ProtocolHandlerPool.h | 0 GPSACollector.cpp => Common/GPSACollector.cpp | 0 GPSACollector.h => Common/GPSACollector.h | 0 GatewayCache.cpp => Common/GatewayCache.cpp | 0 GatewayCache.h => Common/GatewayCache.h | 0 .../HBRepeaterProtocolHandler.cpp | 0 .../HBRepeaterProtocolHandler.h | 0 HeaderLogger.cpp => Common/HeaderLogger.cpp | 0 HeaderLogger.h => Common/HeaderLogger.h | 0 HeardData.cpp => Common/HeardData.cpp | 0 HeardData.h => Common/HeardData.h | 0 .../IcomRepeaterProtocolHandler.cpp | 0 .../IcomRepeaterProtocolHandler.h | 0 Common/Makefile | 19 ++++++ .../NMEASentenceCollector.cpp | 0 .../NMEASentenceCollector.h | 0 PollData.cpp => Common/PollData.cpp | 0 PollData.h => Common/PollData.h | 0 .../RSMS1AMessageBuilder.cpp | 0 .../RSMS1AMessageBuilder.h | 0 .../RSMS1AMessageCollector.cpp | 0 .../RSMS1AMessageCollector.h | 0 .../ReadAPRSFrameCallback.h | 0 .../ReflectorCallback.h | 0 RemoteHandler.cpp => Common/RemoteHandler.cpp | 0 RemoteHandler.h => Common/RemoteHandler.h | 0 .../RemoteLinkData.cpp | 0 RemoteLinkData.h => Common/RemoteLinkData.h | 0 .../RemoteProtocolHandler.cpp | 0 .../RemoteProtocolHandler.h | 0 .../RemoteRepeaterData.cpp | 0 .../RemoteRepeaterData.h | 0 RemoteUser.cpp => Common/RemoteUser.cpp | 0 RemoteUser.h => Common/RemoteUser.h | 0 RepeaterCache.cpp => Common/RepeaterCache.cpp | 0 RepeaterCache.h => Common/RepeaterCache.h | 0 .../RepeaterCallback.h | 0 .../RepeaterHandler.cpp | 0 RepeaterHandler.h => Common/RepeaterHandler.h | 0 .../RepeaterProtocolHandler.h | 0 .../SentenceCollector.cpp | 0 .../SentenceCollector.h | 0 .../SlowDataCollector.cpp | 0 .../SlowDataCollector.h | 0 .../SlowDataCollectorThrottle.cpp | 0 .../SlowDataCollectorThrottle.h | 0 .../SlowDataEncoder.cpp | 0 SlowDataEncoder.h => Common/SlowDataEncoder.h | 0 StatusData.cpp => Common/StatusData.cpp | 0 StatusData.h => Common/StatusData.h | 0 TextCollector.cpp => Common/TextCollector.cpp | 0 TextCollector.h => Common/TextCollector.h | 0 TextData.cpp => Common/TextData.cpp | 0 TextData.h => Common/TextData.h | 0 UserCache.cpp => Common/UserCache.cpp | 0 UserCache.h => Common/UserCache.h | 0 VersionUnit.cpp => Common/VersionUnit.cpp | 0 VersionUnit.h => Common/VersionUnit.h | 0 .../XLXHostsFileDownloader.cpp | 0 .../XLXHostsFileDownloader.h | 0 example.cfg => Common/example.cfg | 0 AMBEData.cpp => DStarBase/AMBEData.cpp | 0 AMBEData.h => DStarBase/AMBEData.h | 0 .../CallsignList.cpp | 0 CallsignList.h => DStarBase/CallsignList.h | 0 DDData.cpp => DStarBase/DDData.cpp | 0 DDData.h => DStarBase/DDData.h | 0 DStarDefines.h => DStarBase/DStarDefines.h | 0 DTMF.cpp => DStarBase/DTMF.cpp | 0 DTMF.h => DStarBase/DTMF.h | 0 .../DVTOOLFileReader.cpp | 0 .../DVTOOLFileReader.h | 0 HeaderData.cpp => DStarBase/HeaderData.cpp | 0 HeaderData.h => DStarBase/HeaderData.h | 0 HostFile.cpp => DStarBase/HostFile.cpp | 0 HostFile.h => DStarBase/HostFile.h | 0 DStarBase/Makefile | 14 ++++ .../DStarGatewayApp.cpp | 0 .../DStarGatewayApp.h | 0 .../DStarGatewayConfig.cpp | 0 .../DStarGatewayConfig.h | 0 .../DStarGatewayDefs.h | 0 .../DStarGatewayStatusData.cpp | 0 .../DStarGatewayStatusData.h | 0 .../DStarGatewayThread.cpp | 0 .../DStarGatewayThread.h | 0 DStarGateway/Makefile | 30 +++++++++ .../RepeaterProtocolHandlerFactory.cpp | 0 .../RepeaterProtocolHandlerFactory.h | 0 IRCApplication.h => IRCDDB/IRCApplication.h | 0 IRCClient.cpp => IRCDDB/IRCClient.cpp | 0 IRCClient.h => IRCDDB/IRCClient.h | 0 IRCDDB.cpp => IRCDDB/IRCDDB.cpp | 0 IRCDDB.h => IRCDDB/IRCDDB.h | 0 IRCDDBApp.cpp => IRCDDB/IRCDDBApp.cpp | 0 IRCDDBApp.h => IRCDDB/IRCDDBApp.h | 0 IRCDDBClient.cpp => IRCDDB/IRCDDBClient.cpp | 0 IRCDDBClient.h => IRCDDB/IRCDDBClient.h | 0 .../IRCDDBMultiClient.cpp | 0 .../IRCDDBMultiClient.h | 0 IRCMessage.cpp => IRCDDB/IRCMessage.cpp | 0 IRCMessage.h => IRCDDB/IRCMessage.h | 0 .../IRCMessageQueue.cpp | 0 IRCMessageQueue.h => IRCDDB/IRCMessageQueue.h | 0 IRCProtocol.cpp => IRCDDB/IRCProtocol.cpp | 0 IRCProtocol.h => IRCDDB/IRCProtocol.h | 0 IRCReceiver.cpp => IRCDDB/IRCReceiver.cpp | 0 IRCReceiver.h => IRCDDB/IRCReceiver.h | 0 IRCDDB/Makefile | 16 +++++ Makefile | 64 ++++++++----------- Tests/Makefile | 15 +++-- VersionInfo/Makefile | 23 +++++++ Version.h => VersionInfo/Version.h | 0 179 files changed, 144 insertions(+), 46 deletions(-) rename APRSCollector.cpp => Common/APRSCollector.cpp (100%) rename APRSCollector.h => Common/APRSCollector.h (100%) rename APRSEntry.cpp => Common/APRSEntry.cpp (100%) rename APRSEntry.h => Common/APRSEntry.h (100%) rename APRSEntryStatus.cpp => Common/APRSEntryStatus.cpp (100%) rename APRSEntryStatus.h => Common/APRSEntryStatus.h (100%) rename APRSFixedIdFrameProvider.cpp => Common/APRSFixedIdFrameProvider.cpp (100%) rename APRSFixedIdFrameProvider.h => Common/APRSFixedIdFrameProvider.h (100%) rename APRSGPSDIdFrameProvider.cpp => Common/APRSGPSDIdFrameProvider.cpp (100%) rename APRSGPSDIdFrameProvider.h => Common/APRSGPSDIdFrameProvider.h (100%) rename APRSHandler.cpp => Common/APRSHandler.cpp (100%) rename APRSHandler.h => Common/APRSHandler.h (100%) rename APRSHandlerThread.cpp => Common/APRSHandlerThread.cpp (100%) rename APRSHandlerThread.h => Common/APRSHandlerThread.h (100%) rename APRSIdFrameProvider.cpp => Common/APRSIdFrameProvider.cpp (100%) rename APRSIdFrameProvider.h => Common/APRSIdFrameProvider.h (100%) rename APRSUnit.cpp => Common/APRSUnit.cpp (100%) rename APRSUnit.h => Common/APRSUnit.h (100%) rename APRStoDPRS.cpp => Common/APRStoDPRS.cpp (100%) rename APRStoDPRS.h => Common/APRStoDPRS.h (100%) rename AnnouncementUnit.cpp => Common/AnnouncementUnit.cpp (100%) rename AnnouncementUnit.h => Common/AnnouncementUnit.h (100%) rename AudioUnit.cpp => Common/AudioUnit.cpp (100%) rename AudioUnit.h => Common/AudioUnit.h (100%) rename CCSCallback.h => Common/CCSCallback.h (100%) rename CCSData.cpp => Common/CCSData.cpp (100%) rename CCSData.h => Common/CCSData.h (100%) rename CCSProtocolHandler.cpp => Common/CCSProtocolHandler.cpp (100%) rename CCSProtocolHandler.h => Common/CCSProtocolHandler.h (100%) rename CacheManager.cpp => Common/CacheManager.cpp (100%) rename CacheManager.h => Common/CacheManager.h (100%) rename ConnectData.cpp => Common/ConnectData.cpp (100%) rename ConnectData.h => Common/ConnectData.h (100%) rename DCSHandler.cpp => Common/DCSHandler.cpp (100%) rename DCSHandler.h => Common/DCSHandler.h (100%) rename DCSProtocolHandler.cpp => Common/DCSProtocolHandler.cpp (100%) rename DCSProtocolHandler.h => Common/DCSProtocolHandler.h (100%) rename DCSProtocolHandlerPool.cpp => Common/DCSProtocolHandlerPool.cpp (100%) rename DCSProtocolHandlerPool.h => Common/DCSProtocolHandlerPool.h (100%) rename DDHandler.cpp => Common/DDHandler.cpp (100%) rename DDHandler.h => Common/DDHandler.h (100%) rename DExtraHandler.cpp => Common/DExtraHandler.cpp (100%) rename DExtraHandler.h => Common/DExtraHandler.h (100%) rename DExtraProtocolHandler.cpp => Common/DExtraProtocolHandler.cpp (100%) rename DExtraProtocolHandler.h => Common/DExtraProtocolHandler.h (100%) rename DExtraProtocolHandlerPool.cpp => Common/DExtraProtocolHandlerPool.cpp (100%) rename DExtraProtocolHandlerPool.h => Common/DExtraProtocolHandlerPool.h (100%) rename DPlusAuthenticator.cpp => Common/DPlusAuthenticator.cpp (100%) rename DPlusAuthenticator.h => Common/DPlusAuthenticator.h (100%) rename DPlusHandler.cpp => Common/DPlusHandler.cpp (100%) rename DPlusHandler.h => Common/DPlusHandler.h (100%) rename DPlusProtocolHandler.cpp => Common/DPlusProtocolHandler.cpp (100%) rename DPlusProtocolHandler.h => Common/DPlusProtocolHandler.h (100%) rename DPlusProtocolHandlerPool.cpp => Common/DPlusProtocolHandlerPool.cpp (100%) rename DPlusProtocolHandlerPool.h => Common/DPlusProtocolHandlerPool.h (100%) rename Defs.h => Common/Defs.h (100%) rename DummyRepeaterProtocolHandler.cpp => Common/DummyRepeaterProtocolHandler.cpp (100%) rename DummyRepeaterProtocolHandler.h => Common/DummyRepeaterProtocolHandler.h (100%) rename EchoUnit.cpp => Common/EchoUnit.cpp (100%) rename EchoUnit.h => Common/EchoUnit.h (100%) rename G2Handler.cpp => Common/G2Handler.cpp (100%) rename G2Handler.h => Common/G2Handler.h (100%) rename G2ProtocolHandler.cpp => Common/G2ProtocolHandler.cpp (100%) rename G2ProtocolHandler.h => Common/G2ProtocolHandler.h (100%) rename G2ProtocolHandlerPool.cpp => Common/G2ProtocolHandlerPool.cpp (100%) rename G2ProtocolHandlerPool.h => Common/G2ProtocolHandlerPool.h (100%) rename GPSACollector.cpp => Common/GPSACollector.cpp (100%) rename GPSACollector.h => Common/GPSACollector.h (100%) rename GatewayCache.cpp => Common/GatewayCache.cpp (100%) rename GatewayCache.h => Common/GatewayCache.h (100%) rename HBRepeaterProtocolHandler.cpp => Common/HBRepeaterProtocolHandler.cpp (100%) rename HBRepeaterProtocolHandler.h => Common/HBRepeaterProtocolHandler.h (100%) rename HeaderLogger.cpp => Common/HeaderLogger.cpp (100%) rename HeaderLogger.h => Common/HeaderLogger.h (100%) rename HeardData.cpp => Common/HeardData.cpp (100%) rename HeardData.h => Common/HeardData.h (100%) rename IcomRepeaterProtocolHandler.cpp => Common/IcomRepeaterProtocolHandler.cpp (100%) rename IcomRepeaterProtocolHandler.h => Common/IcomRepeaterProtocolHandler.h (100%) create mode 100644 Common/Makefile rename NMEASentenceCollector.cpp => Common/NMEASentenceCollector.cpp (100%) rename NMEASentenceCollector.h => Common/NMEASentenceCollector.h (100%) rename PollData.cpp => Common/PollData.cpp (100%) rename PollData.h => Common/PollData.h (100%) rename RSMS1AMessageBuilder.cpp => Common/RSMS1AMessageBuilder.cpp (100%) rename RSMS1AMessageBuilder.h => Common/RSMS1AMessageBuilder.h (100%) rename RSMS1AMessageCollector.cpp => Common/RSMS1AMessageCollector.cpp (100%) rename RSMS1AMessageCollector.h => Common/RSMS1AMessageCollector.h (100%) rename ReadAPRSFrameCallback.h => Common/ReadAPRSFrameCallback.h (100%) rename ReflectorCallback.h => Common/ReflectorCallback.h (100%) rename RemoteHandler.cpp => Common/RemoteHandler.cpp (100%) rename RemoteHandler.h => Common/RemoteHandler.h (100%) rename RemoteLinkData.cpp => Common/RemoteLinkData.cpp (100%) rename RemoteLinkData.h => Common/RemoteLinkData.h (100%) rename RemoteProtocolHandler.cpp => Common/RemoteProtocolHandler.cpp (100%) rename RemoteProtocolHandler.h => Common/RemoteProtocolHandler.h (100%) rename RemoteRepeaterData.cpp => Common/RemoteRepeaterData.cpp (100%) rename RemoteRepeaterData.h => Common/RemoteRepeaterData.h (100%) rename RemoteUser.cpp => Common/RemoteUser.cpp (100%) rename RemoteUser.h => Common/RemoteUser.h (100%) rename RepeaterCache.cpp => Common/RepeaterCache.cpp (100%) rename RepeaterCache.h => Common/RepeaterCache.h (100%) rename RepeaterCallback.h => Common/RepeaterCallback.h (100%) rename RepeaterHandler.cpp => Common/RepeaterHandler.cpp (100%) rename RepeaterHandler.h => Common/RepeaterHandler.h (100%) rename RepeaterProtocolHandler.h => Common/RepeaterProtocolHandler.h (100%) rename SentenceCollector.cpp => Common/SentenceCollector.cpp (100%) rename SentenceCollector.h => Common/SentenceCollector.h (100%) rename SlowDataCollector.cpp => Common/SlowDataCollector.cpp (100%) rename SlowDataCollector.h => Common/SlowDataCollector.h (100%) rename SlowDataCollectorThrottle.cpp => Common/SlowDataCollectorThrottle.cpp (100%) rename SlowDataCollectorThrottle.h => Common/SlowDataCollectorThrottle.h (100%) rename SlowDataEncoder.cpp => Common/SlowDataEncoder.cpp (100%) rename SlowDataEncoder.h => Common/SlowDataEncoder.h (100%) rename StatusData.cpp => Common/StatusData.cpp (100%) rename StatusData.h => Common/StatusData.h (100%) rename TextCollector.cpp => Common/TextCollector.cpp (100%) rename TextCollector.h => Common/TextCollector.h (100%) rename TextData.cpp => Common/TextData.cpp (100%) rename TextData.h => Common/TextData.h (100%) rename UserCache.cpp => Common/UserCache.cpp (100%) rename UserCache.h => Common/UserCache.h (100%) rename VersionUnit.cpp => Common/VersionUnit.cpp (100%) rename VersionUnit.h => Common/VersionUnit.h (100%) rename XLXHostsFileDownloader.cpp => Common/XLXHostsFileDownloader.cpp (100%) rename XLXHostsFileDownloader.h => Common/XLXHostsFileDownloader.h (100%) rename example.cfg => Common/example.cfg (100%) rename AMBEData.cpp => DStarBase/AMBEData.cpp (100%) rename AMBEData.h => DStarBase/AMBEData.h (100%) rename CallsignList.cpp => DStarBase/CallsignList.cpp (100%) rename CallsignList.h => DStarBase/CallsignList.h (100%) rename DDData.cpp => DStarBase/DDData.cpp (100%) rename DDData.h => DStarBase/DDData.h (100%) rename DStarDefines.h => DStarBase/DStarDefines.h (100%) rename DTMF.cpp => DStarBase/DTMF.cpp (100%) rename DTMF.h => DStarBase/DTMF.h (100%) rename DVTOOLFileReader.cpp => DStarBase/DVTOOLFileReader.cpp (100%) rename DVTOOLFileReader.h => DStarBase/DVTOOLFileReader.h (100%) rename HeaderData.cpp => DStarBase/HeaderData.cpp (100%) rename HeaderData.h => DStarBase/HeaderData.h (100%) rename HostFile.cpp => DStarBase/HostFile.cpp (100%) rename HostFile.h => DStarBase/HostFile.h (100%) create mode 100644 DStarBase/Makefile rename DStarGatewayApp.cpp => DStarGateway/DStarGatewayApp.cpp (100%) rename DStarGatewayApp.h => DStarGateway/DStarGatewayApp.h (100%) rename DStarGatewayConfig.cpp => DStarGateway/DStarGatewayConfig.cpp (100%) rename DStarGatewayConfig.h => DStarGateway/DStarGatewayConfig.h (100%) rename DStarGatewayDefs.h => DStarGateway/DStarGatewayDefs.h (100%) rename DStarGatewayStatusData.cpp => DStarGateway/DStarGatewayStatusData.cpp (100%) rename DStarGatewayStatusData.h => DStarGateway/DStarGatewayStatusData.h (100%) rename DStarGatewayThread.cpp => DStarGateway/DStarGatewayThread.cpp (100%) rename DStarGatewayThread.h => DStarGateway/DStarGatewayThread.h (100%) create mode 100644 DStarGateway/Makefile rename RepeaterProtocolHandlerFactory.cpp => DStarGateway/RepeaterProtocolHandlerFactory.cpp (100%) rename RepeaterProtocolHandlerFactory.h => DStarGateway/RepeaterProtocolHandlerFactory.h (100%) rename IRCApplication.h => IRCDDB/IRCApplication.h (100%) rename IRCClient.cpp => IRCDDB/IRCClient.cpp (100%) rename IRCClient.h => IRCDDB/IRCClient.h (100%) rename IRCDDB.cpp => IRCDDB/IRCDDB.cpp (100%) rename IRCDDB.h => IRCDDB/IRCDDB.h (100%) rename IRCDDBApp.cpp => IRCDDB/IRCDDBApp.cpp (100%) rename IRCDDBApp.h => IRCDDB/IRCDDBApp.h (100%) rename IRCDDBClient.cpp => IRCDDB/IRCDDBClient.cpp (100%) rename IRCDDBClient.h => IRCDDB/IRCDDBClient.h (100%) rename IRCDDBMultiClient.cpp => IRCDDB/IRCDDBMultiClient.cpp (100%) rename IRCDDBMultiClient.h => IRCDDB/IRCDDBMultiClient.h (100%) rename IRCMessage.cpp => IRCDDB/IRCMessage.cpp (100%) rename IRCMessage.h => IRCDDB/IRCMessage.h (100%) rename IRCMessageQueue.cpp => IRCDDB/IRCMessageQueue.cpp (100%) rename IRCMessageQueue.h => IRCDDB/IRCMessageQueue.h (100%) rename IRCProtocol.cpp => IRCDDB/IRCProtocol.cpp (100%) rename IRCProtocol.h => IRCDDB/IRCProtocol.h (100%) rename IRCReceiver.cpp => IRCDDB/IRCReceiver.cpp (100%) rename IRCReceiver.h => IRCDDB/IRCReceiver.h (100%) create mode 100644 IRCDDB/Makefile create mode 100644 VersionInfo/Makefile rename Version.h => VersionInfo/Version.h (100%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0502fb1..4e8c1d4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,14 +20,11 @@ jobs: sudo apt-get update sudo apt-get -y install libgtest-dev libcurl4-openssl-dev libboost-dev libgps-dev - run: - name: "Build App" - command: "make -j 3 dstargateway USE_GPSD=1" - - run: - name: "Build Tests" - command: "make -j 3 tests USE_GPSD=1" + name: "Build" + command: "make -j 3 ENABLE_DEBUG=1 USE_GPSD=1" - run: name: "Run Tests" - command: "make run-tests USE_GPSD=1" + command: "make run-tests" # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows workflows: diff --git a/APRSCollector.cpp b/Common/APRSCollector.cpp similarity index 100% rename from APRSCollector.cpp rename to Common/APRSCollector.cpp diff --git a/APRSCollector.h b/Common/APRSCollector.h similarity index 100% rename from APRSCollector.h rename to Common/APRSCollector.h diff --git a/APRSEntry.cpp b/Common/APRSEntry.cpp similarity index 100% rename from APRSEntry.cpp rename to Common/APRSEntry.cpp diff --git a/APRSEntry.h b/Common/APRSEntry.h similarity index 100% rename from APRSEntry.h rename to Common/APRSEntry.h diff --git a/APRSEntryStatus.cpp b/Common/APRSEntryStatus.cpp similarity index 100% rename from APRSEntryStatus.cpp rename to Common/APRSEntryStatus.cpp diff --git a/APRSEntryStatus.h b/Common/APRSEntryStatus.h similarity index 100% rename from APRSEntryStatus.h rename to Common/APRSEntryStatus.h diff --git a/APRSFixedIdFrameProvider.cpp b/Common/APRSFixedIdFrameProvider.cpp similarity index 100% rename from APRSFixedIdFrameProvider.cpp rename to Common/APRSFixedIdFrameProvider.cpp diff --git a/APRSFixedIdFrameProvider.h b/Common/APRSFixedIdFrameProvider.h similarity index 100% rename from APRSFixedIdFrameProvider.h rename to Common/APRSFixedIdFrameProvider.h diff --git a/APRSGPSDIdFrameProvider.cpp b/Common/APRSGPSDIdFrameProvider.cpp similarity index 100% rename from APRSGPSDIdFrameProvider.cpp rename to Common/APRSGPSDIdFrameProvider.cpp diff --git a/APRSGPSDIdFrameProvider.h b/Common/APRSGPSDIdFrameProvider.h similarity index 100% rename from APRSGPSDIdFrameProvider.h rename to Common/APRSGPSDIdFrameProvider.h diff --git a/APRSHandler.cpp b/Common/APRSHandler.cpp similarity index 100% rename from APRSHandler.cpp rename to Common/APRSHandler.cpp diff --git a/APRSHandler.h b/Common/APRSHandler.h similarity index 100% rename from APRSHandler.h rename to Common/APRSHandler.h diff --git a/APRSHandlerThread.cpp b/Common/APRSHandlerThread.cpp similarity index 100% rename from APRSHandlerThread.cpp rename to Common/APRSHandlerThread.cpp diff --git a/APRSHandlerThread.h b/Common/APRSHandlerThread.h similarity index 100% rename from APRSHandlerThread.h rename to Common/APRSHandlerThread.h diff --git a/APRSIdFrameProvider.cpp b/Common/APRSIdFrameProvider.cpp similarity index 100% rename from APRSIdFrameProvider.cpp rename to Common/APRSIdFrameProvider.cpp diff --git a/APRSIdFrameProvider.h b/Common/APRSIdFrameProvider.h similarity index 100% rename from APRSIdFrameProvider.h rename to Common/APRSIdFrameProvider.h diff --git a/APRSUnit.cpp b/Common/APRSUnit.cpp similarity index 100% rename from APRSUnit.cpp rename to Common/APRSUnit.cpp diff --git a/APRSUnit.h b/Common/APRSUnit.h similarity index 100% rename from APRSUnit.h rename to Common/APRSUnit.h diff --git a/APRStoDPRS.cpp b/Common/APRStoDPRS.cpp similarity index 100% rename from APRStoDPRS.cpp rename to Common/APRStoDPRS.cpp diff --git a/APRStoDPRS.h b/Common/APRStoDPRS.h similarity index 100% rename from APRStoDPRS.h rename to Common/APRStoDPRS.h diff --git a/AnnouncementUnit.cpp b/Common/AnnouncementUnit.cpp similarity index 100% rename from AnnouncementUnit.cpp rename to Common/AnnouncementUnit.cpp diff --git a/AnnouncementUnit.h b/Common/AnnouncementUnit.h similarity index 100% rename from AnnouncementUnit.h rename to Common/AnnouncementUnit.h diff --git a/AudioUnit.cpp b/Common/AudioUnit.cpp similarity index 100% rename from AudioUnit.cpp rename to Common/AudioUnit.cpp diff --git a/AudioUnit.h b/Common/AudioUnit.h similarity index 100% rename from AudioUnit.h rename to Common/AudioUnit.h diff --git a/CCSCallback.h b/Common/CCSCallback.h similarity index 100% rename from CCSCallback.h rename to Common/CCSCallback.h diff --git a/CCSData.cpp b/Common/CCSData.cpp similarity index 100% rename from CCSData.cpp rename to Common/CCSData.cpp diff --git a/CCSData.h b/Common/CCSData.h similarity index 100% rename from CCSData.h rename to Common/CCSData.h diff --git a/CCSProtocolHandler.cpp b/Common/CCSProtocolHandler.cpp similarity index 100% rename from CCSProtocolHandler.cpp rename to Common/CCSProtocolHandler.cpp diff --git a/CCSProtocolHandler.h b/Common/CCSProtocolHandler.h similarity index 100% rename from CCSProtocolHandler.h rename to Common/CCSProtocolHandler.h diff --git a/CacheManager.cpp b/Common/CacheManager.cpp similarity index 100% rename from CacheManager.cpp rename to Common/CacheManager.cpp diff --git a/CacheManager.h b/Common/CacheManager.h similarity index 100% rename from CacheManager.h rename to Common/CacheManager.h diff --git a/ConnectData.cpp b/Common/ConnectData.cpp similarity index 100% rename from ConnectData.cpp rename to Common/ConnectData.cpp diff --git a/ConnectData.h b/Common/ConnectData.h similarity index 100% rename from ConnectData.h rename to Common/ConnectData.h diff --git a/DCSHandler.cpp b/Common/DCSHandler.cpp similarity index 100% rename from DCSHandler.cpp rename to Common/DCSHandler.cpp diff --git a/DCSHandler.h b/Common/DCSHandler.h similarity index 100% rename from DCSHandler.h rename to Common/DCSHandler.h diff --git a/DCSProtocolHandler.cpp b/Common/DCSProtocolHandler.cpp similarity index 100% rename from DCSProtocolHandler.cpp rename to Common/DCSProtocolHandler.cpp diff --git a/DCSProtocolHandler.h b/Common/DCSProtocolHandler.h similarity index 100% rename from DCSProtocolHandler.h rename to Common/DCSProtocolHandler.h diff --git a/DCSProtocolHandlerPool.cpp b/Common/DCSProtocolHandlerPool.cpp similarity index 100% rename from DCSProtocolHandlerPool.cpp rename to Common/DCSProtocolHandlerPool.cpp diff --git a/DCSProtocolHandlerPool.h b/Common/DCSProtocolHandlerPool.h similarity index 100% rename from DCSProtocolHandlerPool.h rename to Common/DCSProtocolHandlerPool.h diff --git a/DDHandler.cpp b/Common/DDHandler.cpp similarity index 100% rename from DDHandler.cpp rename to Common/DDHandler.cpp diff --git a/DDHandler.h b/Common/DDHandler.h similarity index 100% rename from DDHandler.h rename to Common/DDHandler.h diff --git a/DExtraHandler.cpp b/Common/DExtraHandler.cpp similarity index 100% rename from DExtraHandler.cpp rename to Common/DExtraHandler.cpp diff --git a/DExtraHandler.h b/Common/DExtraHandler.h similarity index 100% rename from DExtraHandler.h rename to Common/DExtraHandler.h diff --git a/DExtraProtocolHandler.cpp b/Common/DExtraProtocolHandler.cpp similarity index 100% rename from DExtraProtocolHandler.cpp rename to Common/DExtraProtocolHandler.cpp diff --git a/DExtraProtocolHandler.h b/Common/DExtraProtocolHandler.h similarity index 100% rename from DExtraProtocolHandler.h rename to Common/DExtraProtocolHandler.h diff --git a/DExtraProtocolHandlerPool.cpp b/Common/DExtraProtocolHandlerPool.cpp similarity index 100% rename from DExtraProtocolHandlerPool.cpp rename to Common/DExtraProtocolHandlerPool.cpp diff --git a/DExtraProtocolHandlerPool.h b/Common/DExtraProtocolHandlerPool.h similarity index 100% rename from DExtraProtocolHandlerPool.h rename to Common/DExtraProtocolHandlerPool.h diff --git a/DPlusAuthenticator.cpp b/Common/DPlusAuthenticator.cpp similarity index 100% rename from DPlusAuthenticator.cpp rename to Common/DPlusAuthenticator.cpp diff --git a/DPlusAuthenticator.h b/Common/DPlusAuthenticator.h similarity index 100% rename from DPlusAuthenticator.h rename to Common/DPlusAuthenticator.h diff --git a/DPlusHandler.cpp b/Common/DPlusHandler.cpp similarity index 100% rename from DPlusHandler.cpp rename to Common/DPlusHandler.cpp diff --git a/DPlusHandler.h b/Common/DPlusHandler.h similarity index 100% rename from DPlusHandler.h rename to Common/DPlusHandler.h diff --git a/DPlusProtocolHandler.cpp b/Common/DPlusProtocolHandler.cpp similarity index 100% rename from DPlusProtocolHandler.cpp rename to Common/DPlusProtocolHandler.cpp diff --git a/DPlusProtocolHandler.h b/Common/DPlusProtocolHandler.h similarity index 100% rename from DPlusProtocolHandler.h rename to Common/DPlusProtocolHandler.h diff --git a/DPlusProtocolHandlerPool.cpp b/Common/DPlusProtocolHandlerPool.cpp similarity index 100% rename from DPlusProtocolHandlerPool.cpp rename to Common/DPlusProtocolHandlerPool.cpp diff --git a/DPlusProtocolHandlerPool.h b/Common/DPlusProtocolHandlerPool.h similarity index 100% rename from DPlusProtocolHandlerPool.h rename to Common/DPlusProtocolHandlerPool.h diff --git a/Defs.h b/Common/Defs.h similarity index 100% rename from Defs.h rename to Common/Defs.h diff --git a/DummyRepeaterProtocolHandler.cpp b/Common/DummyRepeaterProtocolHandler.cpp similarity index 100% rename from DummyRepeaterProtocolHandler.cpp rename to Common/DummyRepeaterProtocolHandler.cpp diff --git a/DummyRepeaterProtocolHandler.h b/Common/DummyRepeaterProtocolHandler.h similarity index 100% rename from DummyRepeaterProtocolHandler.h rename to Common/DummyRepeaterProtocolHandler.h diff --git a/EchoUnit.cpp b/Common/EchoUnit.cpp similarity index 100% rename from EchoUnit.cpp rename to Common/EchoUnit.cpp diff --git a/EchoUnit.h b/Common/EchoUnit.h similarity index 100% rename from EchoUnit.h rename to Common/EchoUnit.h diff --git a/G2Handler.cpp b/Common/G2Handler.cpp similarity index 100% rename from G2Handler.cpp rename to Common/G2Handler.cpp diff --git a/G2Handler.h b/Common/G2Handler.h similarity index 100% rename from G2Handler.h rename to Common/G2Handler.h diff --git a/G2ProtocolHandler.cpp b/Common/G2ProtocolHandler.cpp similarity index 100% rename from G2ProtocolHandler.cpp rename to Common/G2ProtocolHandler.cpp diff --git a/G2ProtocolHandler.h b/Common/G2ProtocolHandler.h similarity index 100% rename from G2ProtocolHandler.h rename to Common/G2ProtocolHandler.h diff --git a/G2ProtocolHandlerPool.cpp b/Common/G2ProtocolHandlerPool.cpp similarity index 100% rename from G2ProtocolHandlerPool.cpp rename to Common/G2ProtocolHandlerPool.cpp diff --git a/G2ProtocolHandlerPool.h b/Common/G2ProtocolHandlerPool.h similarity index 100% rename from G2ProtocolHandlerPool.h rename to Common/G2ProtocolHandlerPool.h diff --git a/GPSACollector.cpp b/Common/GPSACollector.cpp similarity index 100% rename from GPSACollector.cpp rename to Common/GPSACollector.cpp diff --git a/GPSACollector.h b/Common/GPSACollector.h similarity index 100% rename from GPSACollector.h rename to Common/GPSACollector.h diff --git a/GatewayCache.cpp b/Common/GatewayCache.cpp similarity index 100% rename from GatewayCache.cpp rename to Common/GatewayCache.cpp diff --git a/GatewayCache.h b/Common/GatewayCache.h similarity index 100% rename from GatewayCache.h rename to Common/GatewayCache.h diff --git a/HBRepeaterProtocolHandler.cpp b/Common/HBRepeaterProtocolHandler.cpp similarity index 100% rename from HBRepeaterProtocolHandler.cpp rename to Common/HBRepeaterProtocolHandler.cpp diff --git a/HBRepeaterProtocolHandler.h b/Common/HBRepeaterProtocolHandler.h similarity index 100% rename from HBRepeaterProtocolHandler.h rename to Common/HBRepeaterProtocolHandler.h diff --git a/HeaderLogger.cpp b/Common/HeaderLogger.cpp similarity index 100% rename from HeaderLogger.cpp rename to Common/HeaderLogger.cpp diff --git a/HeaderLogger.h b/Common/HeaderLogger.h similarity index 100% rename from HeaderLogger.h rename to Common/HeaderLogger.h diff --git a/HeardData.cpp b/Common/HeardData.cpp similarity index 100% rename from HeardData.cpp rename to Common/HeardData.cpp diff --git a/HeardData.h b/Common/HeardData.h similarity index 100% rename from HeardData.h rename to Common/HeardData.h diff --git a/IcomRepeaterProtocolHandler.cpp b/Common/IcomRepeaterProtocolHandler.cpp similarity index 100% rename from IcomRepeaterProtocolHandler.cpp rename to Common/IcomRepeaterProtocolHandler.cpp diff --git a/IcomRepeaterProtocolHandler.h b/Common/IcomRepeaterProtocolHandler.h similarity index 100% rename from IcomRepeaterProtocolHandler.h rename to Common/IcomRepeaterProtocolHandler.h diff --git a/Common/Makefile b/Common/Makefile new file mode 100644 index 0000000..f04541f --- /dev/null +++ b/Common/Makefile @@ -0,0 +1,19 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:.cpp=.o) +DEPS = $(SRCS:.cpp=.d) + +Common.a: $(OBJS) ../APRS/APRS.a ../BaseCommon/BaseCommon.a ../DStarBase/DStarBase.a ../IRCDDB/IRCDDB.a ../VersionInfo/GitVersion.h + $(AR) rcs Common.a $(OBJS) + +%.o : %.cpp + $(CC) -I../APRS -I../BaseCommon -I../DStarBase -I../IRCDDB -I../VersionInfo $(CPPFLAGS) -MMD -MD -c $< -o $@ + +.PHONY clean: +clean: + $(RM) *.o *.d Common.a + +../APRS/APRS.a: +../BaseCommon/BaseCommon.a: +../DStarBase/DStarBase.a: +../IRCDDB/IRCDDB.a: +../VersionInfo/GitVersion.h: diff --git a/NMEASentenceCollector.cpp b/Common/NMEASentenceCollector.cpp similarity index 100% rename from NMEASentenceCollector.cpp rename to Common/NMEASentenceCollector.cpp diff --git a/NMEASentenceCollector.h b/Common/NMEASentenceCollector.h similarity index 100% rename from NMEASentenceCollector.h rename to Common/NMEASentenceCollector.h diff --git a/PollData.cpp b/Common/PollData.cpp similarity index 100% rename from PollData.cpp rename to Common/PollData.cpp diff --git a/PollData.h b/Common/PollData.h similarity index 100% rename from PollData.h rename to Common/PollData.h diff --git a/RSMS1AMessageBuilder.cpp b/Common/RSMS1AMessageBuilder.cpp similarity index 100% rename from RSMS1AMessageBuilder.cpp rename to Common/RSMS1AMessageBuilder.cpp diff --git a/RSMS1AMessageBuilder.h b/Common/RSMS1AMessageBuilder.h similarity index 100% rename from RSMS1AMessageBuilder.h rename to Common/RSMS1AMessageBuilder.h diff --git a/RSMS1AMessageCollector.cpp b/Common/RSMS1AMessageCollector.cpp similarity index 100% rename from RSMS1AMessageCollector.cpp rename to Common/RSMS1AMessageCollector.cpp diff --git a/RSMS1AMessageCollector.h b/Common/RSMS1AMessageCollector.h similarity index 100% rename from RSMS1AMessageCollector.h rename to Common/RSMS1AMessageCollector.h diff --git a/ReadAPRSFrameCallback.h b/Common/ReadAPRSFrameCallback.h similarity index 100% rename from ReadAPRSFrameCallback.h rename to Common/ReadAPRSFrameCallback.h diff --git a/ReflectorCallback.h b/Common/ReflectorCallback.h similarity index 100% rename from ReflectorCallback.h rename to Common/ReflectorCallback.h diff --git a/RemoteHandler.cpp b/Common/RemoteHandler.cpp similarity index 100% rename from RemoteHandler.cpp rename to Common/RemoteHandler.cpp diff --git a/RemoteHandler.h b/Common/RemoteHandler.h similarity index 100% rename from RemoteHandler.h rename to Common/RemoteHandler.h diff --git a/RemoteLinkData.cpp b/Common/RemoteLinkData.cpp similarity index 100% rename from RemoteLinkData.cpp rename to Common/RemoteLinkData.cpp diff --git a/RemoteLinkData.h b/Common/RemoteLinkData.h similarity index 100% rename from RemoteLinkData.h rename to Common/RemoteLinkData.h diff --git a/RemoteProtocolHandler.cpp b/Common/RemoteProtocolHandler.cpp similarity index 100% rename from RemoteProtocolHandler.cpp rename to Common/RemoteProtocolHandler.cpp diff --git a/RemoteProtocolHandler.h b/Common/RemoteProtocolHandler.h similarity index 100% rename from RemoteProtocolHandler.h rename to Common/RemoteProtocolHandler.h diff --git a/RemoteRepeaterData.cpp b/Common/RemoteRepeaterData.cpp similarity index 100% rename from RemoteRepeaterData.cpp rename to Common/RemoteRepeaterData.cpp diff --git a/RemoteRepeaterData.h b/Common/RemoteRepeaterData.h similarity index 100% rename from RemoteRepeaterData.h rename to Common/RemoteRepeaterData.h diff --git a/RemoteUser.cpp b/Common/RemoteUser.cpp similarity index 100% rename from RemoteUser.cpp rename to Common/RemoteUser.cpp diff --git a/RemoteUser.h b/Common/RemoteUser.h similarity index 100% rename from RemoteUser.h rename to Common/RemoteUser.h diff --git a/RepeaterCache.cpp b/Common/RepeaterCache.cpp similarity index 100% rename from RepeaterCache.cpp rename to Common/RepeaterCache.cpp diff --git a/RepeaterCache.h b/Common/RepeaterCache.h similarity index 100% rename from RepeaterCache.h rename to Common/RepeaterCache.h diff --git a/RepeaterCallback.h b/Common/RepeaterCallback.h similarity index 100% rename from RepeaterCallback.h rename to Common/RepeaterCallback.h diff --git a/RepeaterHandler.cpp b/Common/RepeaterHandler.cpp similarity index 100% rename from RepeaterHandler.cpp rename to Common/RepeaterHandler.cpp diff --git a/RepeaterHandler.h b/Common/RepeaterHandler.h similarity index 100% rename from RepeaterHandler.h rename to Common/RepeaterHandler.h diff --git a/RepeaterProtocolHandler.h b/Common/RepeaterProtocolHandler.h similarity index 100% rename from RepeaterProtocolHandler.h rename to Common/RepeaterProtocolHandler.h diff --git a/SentenceCollector.cpp b/Common/SentenceCollector.cpp similarity index 100% rename from SentenceCollector.cpp rename to Common/SentenceCollector.cpp diff --git a/SentenceCollector.h b/Common/SentenceCollector.h similarity index 100% rename from SentenceCollector.h rename to Common/SentenceCollector.h diff --git a/SlowDataCollector.cpp b/Common/SlowDataCollector.cpp similarity index 100% rename from SlowDataCollector.cpp rename to Common/SlowDataCollector.cpp diff --git a/SlowDataCollector.h b/Common/SlowDataCollector.h similarity index 100% rename from SlowDataCollector.h rename to Common/SlowDataCollector.h diff --git a/SlowDataCollectorThrottle.cpp b/Common/SlowDataCollectorThrottle.cpp similarity index 100% rename from SlowDataCollectorThrottle.cpp rename to Common/SlowDataCollectorThrottle.cpp diff --git a/SlowDataCollectorThrottle.h b/Common/SlowDataCollectorThrottle.h similarity index 100% rename from SlowDataCollectorThrottle.h rename to Common/SlowDataCollectorThrottle.h diff --git a/SlowDataEncoder.cpp b/Common/SlowDataEncoder.cpp similarity index 100% rename from SlowDataEncoder.cpp rename to Common/SlowDataEncoder.cpp diff --git a/SlowDataEncoder.h b/Common/SlowDataEncoder.h similarity index 100% rename from SlowDataEncoder.h rename to Common/SlowDataEncoder.h diff --git a/StatusData.cpp b/Common/StatusData.cpp similarity index 100% rename from StatusData.cpp rename to Common/StatusData.cpp diff --git a/StatusData.h b/Common/StatusData.h similarity index 100% rename from StatusData.h rename to Common/StatusData.h diff --git a/TextCollector.cpp b/Common/TextCollector.cpp similarity index 100% rename from TextCollector.cpp rename to Common/TextCollector.cpp diff --git a/TextCollector.h b/Common/TextCollector.h similarity index 100% rename from TextCollector.h rename to Common/TextCollector.h diff --git a/TextData.cpp b/Common/TextData.cpp similarity index 100% rename from TextData.cpp rename to Common/TextData.cpp diff --git a/TextData.h b/Common/TextData.h similarity index 100% rename from TextData.h rename to Common/TextData.h diff --git a/UserCache.cpp b/Common/UserCache.cpp similarity index 100% rename from UserCache.cpp rename to Common/UserCache.cpp diff --git a/UserCache.h b/Common/UserCache.h similarity index 100% rename from UserCache.h rename to Common/UserCache.h diff --git a/VersionUnit.cpp b/Common/VersionUnit.cpp similarity index 100% rename from VersionUnit.cpp rename to Common/VersionUnit.cpp diff --git a/VersionUnit.h b/Common/VersionUnit.h similarity index 100% rename from VersionUnit.h rename to Common/VersionUnit.h diff --git a/XLXHostsFileDownloader.cpp b/Common/XLXHostsFileDownloader.cpp similarity index 100% rename from XLXHostsFileDownloader.cpp rename to Common/XLXHostsFileDownloader.cpp diff --git a/XLXHostsFileDownloader.h b/Common/XLXHostsFileDownloader.h similarity index 100% rename from XLXHostsFileDownloader.h rename to Common/XLXHostsFileDownloader.h diff --git a/example.cfg b/Common/example.cfg similarity index 100% rename from example.cfg rename to Common/example.cfg diff --git a/AMBEData.cpp b/DStarBase/AMBEData.cpp similarity index 100% rename from AMBEData.cpp rename to DStarBase/AMBEData.cpp diff --git a/AMBEData.h b/DStarBase/AMBEData.h similarity index 100% rename from AMBEData.h rename to DStarBase/AMBEData.h diff --git a/CallsignList.cpp b/DStarBase/CallsignList.cpp similarity index 100% rename from CallsignList.cpp rename to DStarBase/CallsignList.cpp diff --git a/CallsignList.h b/DStarBase/CallsignList.h similarity index 100% rename from CallsignList.h rename to DStarBase/CallsignList.h diff --git a/DDData.cpp b/DStarBase/DDData.cpp similarity index 100% rename from DDData.cpp rename to DStarBase/DDData.cpp diff --git a/DDData.h b/DStarBase/DDData.h similarity index 100% rename from DDData.h rename to DStarBase/DDData.h diff --git a/DStarDefines.h b/DStarBase/DStarDefines.h similarity index 100% rename from DStarDefines.h rename to DStarBase/DStarDefines.h diff --git a/DTMF.cpp b/DStarBase/DTMF.cpp similarity index 100% rename from DTMF.cpp rename to DStarBase/DTMF.cpp diff --git a/DTMF.h b/DStarBase/DTMF.h similarity index 100% rename from DTMF.h rename to DStarBase/DTMF.h diff --git a/DVTOOLFileReader.cpp b/DStarBase/DVTOOLFileReader.cpp similarity index 100% rename from DVTOOLFileReader.cpp rename to DStarBase/DVTOOLFileReader.cpp diff --git a/DVTOOLFileReader.h b/DStarBase/DVTOOLFileReader.h similarity index 100% rename from DVTOOLFileReader.h rename to DStarBase/DVTOOLFileReader.h diff --git a/HeaderData.cpp b/DStarBase/HeaderData.cpp similarity index 100% rename from HeaderData.cpp rename to DStarBase/HeaderData.cpp diff --git a/HeaderData.h b/DStarBase/HeaderData.h similarity index 100% rename from HeaderData.h rename to DStarBase/HeaderData.h diff --git a/HostFile.cpp b/DStarBase/HostFile.cpp similarity index 100% rename from HostFile.cpp rename to DStarBase/HostFile.cpp diff --git a/HostFile.h b/DStarBase/HostFile.h similarity index 100% rename from HostFile.h rename to DStarBase/HostFile.h diff --git a/DStarBase/Makefile b/DStarBase/Makefile new file mode 100644 index 0000000..c6e019d --- /dev/null +++ b/DStarBase/Makefile @@ -0,0 +1,14 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:.cpp=.o) +DEPS = $(SRCS:.cpp=.d) + +DStarBase.a: $(OBJS) + $(AR) rcs DStarBase.a $(OBJS) + +%.o : %.cpp + $(CC) -I../BaseCommon $(CPPFLAGS) -MMD -MD -c $< -o $@ + +clean: + $(RM) *.o *.d DStarBase.a + +../BaseCommon/BaseCommon.a: diff --git a/DStarGatewayApp.cpp b/DStarGateway/DStarGatewayApp.cpp similarity index 100% rename from DStarGatewayApp.cpp rename to DStarGateway/DStarGatewayApp.cpp diff --git a/DStarGatewayApp.h b/DStarGateway/DStarGatewayApp.h similarity index 100% rename from DStarGatewayApp.h rename to DStarGateway/DStarGatewayApp.h diff --git a/DStarGatewayConfig.cpp b/DStarGateway/DStarGatewayConfig.cpp similarity index 100% rename from DStarGatewayConfig.cpp rename to DStarGateway/DStarGatewayConfig.cpp diff --git a/DStarGatewayConfig.h b/DStarGateway/DStarGatewayConfig.h similarity index 100% rename from DStarGatewayConfig.h rename to DStarGateway/DStarGatewayConfig.h diff --git a/DStarGatewayDefs.h b/DStarGateway/DStarGatewayDefs.h similarity index 100% rename from DStarGatewayDefs.h rename to DStarGateway/DStarGatewayDefs.h diff --git a/DStarGatewayStatusData.cpp b/DStarGateway/DStarGatewayStatusData.cpp similarity index 100% rename from DStarGatewayStatusData.cpp rename to DStarGateway/DStarGatewayStatusData.cpp diff --git a/DStarGatewayStatusData.h b/DStarGateway/DStarGatewayStatusData.h similarity index 100% rename from DStarGatewayStatusData.h rename to DStarGateway/DStarGatewayStatusData.h diff --git a/DStarGatewayThread.cpp b/DStarGateway/DStarGatewayThread.cpp similarity index 100% rename from DStarGatewayThread.cpp rename to DStarGateway/DStarGatewayThread.cpp diff --git a/DStarGatewayThread.h b/DStarGateway/DStarGatewayThread.h similarity index 100% rename from DStarGatewayThread.h rename to DStarGateway/DStarGatewayThread.h diff --git a/DStarGateway/Makefile b/DStarGateway/Makefile new file mode 100644 index 0000000..e7afbaf --- /dev/null +++ b/DStarGateway/Makefile @@ -0,0 +1,30 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:.cpp=.o) +DEPS = $(SRCS:.cpp=.d) + +dstargateway: ../VersionInfo/GitVersion.h $(OBJS) ../APRS/APRS.a ../IRCDDB/IRCDDB.a ../DStarBase/DStarBase.a ../BaseCommon/BaseCommon.a ../Common/Common.a + $(CC) $(CPPFLAGS) -o dstargateway $(OBJS) ../Common/Common.a ../APRS/APRS.a ../DStarBase/DStarBase.a ../IRCDDB/IRCDDB.a ../BaseCommon/BaseCommon.a $(LDFLAGS) + +%.o : %.cpp + $(CC) -I../APRS -I../Common -I../BaseCommon -I../DStarBase -I../IRCDDB -I../VersionInfo $(CPPFLAGS) -MMD -MD -c $< -o $@ + +.PHONY clean: +clean: + $(RM) *.o *.d Common.a + +.PHONY install: +install: dstargateway +# copy executable + @cp -f dstargateway $(BIN_DIR + +# copy and adjust config + @cp -fn example.cfg $(CFG_DIR)/dstargateway.cfg + @sed -i "s|path=/var/log/dstargateway/|path=$(LOG_DIR)|g" $(CFG_DIR)/dstargateway.cfg + @sed -i "s|data=/usr/local/share/dstargateway.d/|data=$(DATA_DIR)|g" $(CFG_DIR)/dstargateway.cfg + +../APRS/APRS.a: +../Common/Common.a: +../DStarBase/DStarBase.a: +../BaseCommon/BaseCommon.a: +../IRCDDB/IRCDDB.a: +../VersionInfo/GitVersion.h: diff --git a/RepeaterProtocolHandlerFactory.cpp b/DStarGateway/RepeaterProtocolHandlerFactory.cpp similarity index 100% rename from RepeaterProtocolHandlerFactory.cpp rename to DStarGateway/RepeaterProtocolHandlerFactory.cpp diff --git a/RepeaterProtocolHandlerFactory.h b/DStarGateway/RepeaterProtocolHandlerFactory.h similarity index 100% rename from RepeaterProtocolHandlerFactory.h rename to DStarGateway/RepeaterProtocolHandlerFactory.h diff --git a/IRCApplication.h b/IRCDDB/IRCApplication.h similarity index 100% rename from IRCApplication.h rename to IRCDDB/IRCApplication.h diff --git a/IRCClient.cpp b/IRCDDB/IRCClient.cpp similarity index 100% rename from IRCClient.cpp rename to IRCDDB/IRCClient.cpp diff --git a/IRCClient.h b/IRCDDB/IRCClient.h similarity index 100% rename from IRCClient.h rename to IRCDDB/IRCClient.h diff --git a/IRCDDB.cpp b/IRCDDB/IRCDDB.cpp similarity index 100% rename from IRCDDB.cpp rename to IRCDDB/IRCDDB.cpp diff --git a/IRCDDB.h b/IRCDDB/IRCDDB.h similarity index 100% rename from IRCDDB.h rename to IRCDDB/IRCDDB.h diff --git a/IRCDDBApp.cpp b/IRCDDB/IRCDDBApp.cpp similarity index 100% rename from IRCDDBApp.cpp rename to IRCDDB/IRCDDBApp.cpp diff --git a/IRCDDBApp.h b/IRCDDB/IRCDDBApp.h similarity index 100% rename from IRCDDBApp.h rename to IRCDDB/IRCDDBApp.h diff --git a/IRCDDBClient.cpp b/IRCDDB/IRCDDBClient.cpp similarity index 100% rename from IRCDDBClient.cpp rename to IRCDDB/IRCDDBClient.cpp diff --git a/IRCDDBClient.h b/IRCDDB/IRCDDBClient.h similarity index 100% rename from IRCDDBClient.h rename to IRCDDB/IRCDDBClient.h diff --git a/IRCDDBMultiClient.cpp b/IRCDDB/IRCDDBMultiClient.cpp similarity index 100% rename from IRCDDBMultiClient.cpp rename to IRCDDB/IRCDDBMultiClient.cpp diff --git a/IRCDDBMultiClient.h b/IRCDDB/IRCDDBMultiClient.h similarity index 100% rename from IRCDDBMultiClient.h rename to IRCDDB/IRCDDBMultiClient.h diff --git a/IRCMessage.cpp b/IRCDDB/IRCMessage.cpp similarity index 100% rename from IRCMessage.cpp rename to IRCDDB/IRCMessage.cpp diff --git a/IRCMessage.h b/IRCDDB/IRCMessage.h similarity index 100% rename from IRCMessage.h rename to IRCDDB/IRCMessage.h diff --git a/IRCMessageQueue.cpp b/IRCDDB/IRCMessageQueue.cpp similarity index 100% rename from IRCMessageQueue.cpp rename to IRCDDB/IRCMessageQueue.cpp diff --git a/IRCMessageQueue.h b/IRCDDB/IRCMessageQueue.h similarity index 100% rename from IRCMessageQueue.h rename to IRCDDB/IRCMessageQueue.h diff --git a/IRCProtocol.cpp b/IRCDDB/IRCProtocol.cpp similarity index 100% rename from IRCProtocol.cpp rename to IRCDDB/IRCProtocol.cpp diff --git a/IRCProtocol.h b/IRCDDB/IRCProtocol.h similarity index 100% rename from IRCProtocol.h rename to IRCDDB/IRCProtocol.h diff --git a/IRCReceiver.cpp b/IRCDDB/IRCReceiver.cpp similarity index 100% rename from IRCReceiver.cpp rename to IRCDDB/IRCReceiver.cpp diff --git a/IRCReceiver.h b/IRCDDB/IRCReceiver.h similarity index 100% rename from IRCReceiver.h rename to IRCDDB/IRCReceiver.h diff --git a/IRCDDB/Makefile b/IRCDDB/Makefile new file mode 100644 index 0000000..d84f384 --- /dev/null +++ b/IRCDDB/Makefile @@ -0,0 +1,16 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:.cpp=.o) +DEPS = $(SRCS:.cpp=.d) + +IRCDDB.a: $(OBJS) ../VersionInfo/GitVersion.h ../BaseCommon/BaseCommon.a + $(AR) rcs IRCDDB.a $(OBJS) + +%.o : %.cpp + $(CC) -I../BaseCommon -I../VersionInfo $(CPPFLAGS) -MMD -MD -c $< -o $@ + +.PHONY clean: +clean: + $(RM) *.o *.d IRCDDB.a + +../BaseCommon/BaseCommon.a: +../VersionInfo/GitVersion.h: diff --git a/Makefile b/Makefile index 45eb55d..9835c1f 100644 --- a/Makefile +++ b/Makefile @@ -43,44 +43,42 @@ OBJS = $(SRCS:.cpp=.o) DEPS = $(SRCS:.cpp=.d) .PHONY: all -all: dstargateway +all: DStarGateway/dstargateway tests -dstargateway : GitVersion.h $(OBJS) APRS/APRS.a BaseCommon/BaseCommon.a - $(CC) $(CPPFLAGS) -o dstargateway $(OBJS) APRS/APRS.a BaseCommon/BaseCommon.a $(LDFLAGS) +DStarGateway/dstargateway : VersionInfo/GitVersion.h $(OBJS) APRS/APRS.a Common/Common.a DStarBase/DStarBase.a IRCDDB/IRCDDB.a BaseCommon/BaseCommon.a + $(MAKE) -C DStarGateway %.o : %.cpp - $(CC) -IAPRS/ -IBaseCommon/ $(CPPFLAGS) -MMD -MD -c $< -o $@ + $(CC) -IAPRS/ -IBaseCommon/ -IDStarBase/ -IIRCDDB/ -IVersionInfo/ $(CPPFLAGS) -MMD -MD -c $< -o $@ + +APRS/APRS.a: BaseCommon/BaseCommon.a FORCE + $(MAKE) -C APRS + +Common/Common.a: VersionInfo/GitVersion.h APRS/APRS.a BaseCommon/BaseCommon.a FORCE + $(MAKE) -C Common BaseCommon/BaseCommon.a: FORCE $(MAKE) -C BaseCommon -APRS/APRS.a: BaseCommon/BaseCommon.a FORCE - $(MAKE) -C APRS +DStarBase/DStarBase.a: BaseCommon/BaseCommon.a FORCE + $(MAKE) -C DStarBase -GitVersion.h : FORCE -ifneq ("$(wildcard .git/index)","") - @echo "#pragma once" > /tmp/$@ - @echo "#include " >> /tmp/$@ - @echo "const std::string gitversion(\"$(shell git rev-parse --short HEAD)\");" >> /tmp/$@ -else - @echo "#pragma once" > /tmp/$@ - @echo "#include " >> /tmp/$@ - @echo "const std::string gitversion(\"0000000\");" >> /tmp/$@ -endif - @cmp -s /tmp/$@ $@; \ - RETVAL=$$?; \ - if [ $$RETVAL -ne 0 ]; then \ - echo "Git version has changed"; \ - cp -f /tmp/$@ $@; \ - fi; \ - rm /tmp/$@; +IRCDDB/IRCDDB.a: VersionInfo/GitVersion.h BaseCommon/BaseCommon.a FORCE + $(MAKE) -C IRCDDB + +VersionInfo/GitVersion.h: + $(MAKE) -C VersionInfo .PHONY: clean clean: - $(RM) GitVersion.h *.o *.d dstargateway $(MAKE) -C Tests clean $(MAKE) -C APRS clean + $(MAKE) -C Common clean $(MAKE) -C BaseCommon clean + $(MAKE) -C DStarBase clean + $(MAKE) -C DStarGateway clean + $(MAKE) -C IRCDDB clean + $(MAKE) -C VersionInfo -include $(DEPS) @@ -94,7 +92,7 @@ newhostfiles : @wget http://www.pistar.uk/downloads/DPlus_Hosts.txt -nv -O $(DATA_DIR)/DPlus_Hosts.txt .PHONY: install -install : dstargateway +install : DStarGateway/dstargateway # create user for daemon @useradd --user-group -M --system dstar --shell /bin/false || true @@ -109,13 +107,8 @@ install : dstargateway $(MAKE) -C Data install @chown -R dstar:dstar $(DATA_DIR) -# copy and adjust config - @cp -fn example.cfg $(CFG_DIR)/dstargateway.cfg - @sed -i "s|path=/var/log/dstargateway/|path=$(LOG_DIR)|g" $(CFG_DIR)/dstargateway.cfg - @sed -i "s|data=/usr/local/share/dstargateway.d/|data=$(DATA_DIR)|g" $(CFG_DIR)/dstargateway.cfg - -# copy binary - @cp -f dstargateway $(BIN_DIR) +#install executables + $(MAKE) -C DStarGateway install # SystemD service install @cp -f debian/dstargateway.service /lib/systemd/system/ @@ -144,12 +137,11 @@ removehostfiles : @rm -f $(DATA_DIR)/DPlus_Hosts.txt .PHONY tests: -tests : GitVersion.h -# force tests makefile to rebuild them with -DUNIT_TESTS, otherwise we end up with 2 mains - @touch DStarGatewayApp.cpp +tests : VersionInfo/GitVersion.h $(OBJS) APRS/APRS.a Common/Common.a DStarBase/DStarBase.a IRCDDB/IRCDDB.a BaseCommon/BaseCommon.a FORCE @$(MAKE) -C Tests dstargateway_tests .PHONY run-tests: +run-tests: tests @$(MAKE) -C Tests run-tests -FORCE: \ No newline at end of file +FORCE: diff --git a/Tests/Makefile b/Tests/Makefile index 39c4504..2aafd55 100644 --- a/Tests/Makefile +++ b/Tests/Makefile @@ -3,11 +3,11 @@ SRCS = $(wildcard *.cpp) $(wildcard ../*.cpp) $(wildcard */*.cpp) OBJS = $(SRCS:.cpp=.o) DEPS = $(SRCS:.cpp=.d) -dstargateway_tests: $(OBJS) - $(CC) $(CPPFLAGS) -o dstargateway_tests $(OBJS) $(LDFLAGS) -lgtest -lgtest_main +dstargateway_tests: ../VersionInfo/GitVersion.h $(OBJS) ../APRS/APRS.a ../IRCDDB/IRCDDB.a ../DStarBase/DStarBase.a ../BaseCommon/BaseCommon.a ../Common/Common.a + $(CC) $(CPPFLAGS) -o dstargateway_tests $(OBJS) ../Common/Common.a ../APRS/APRS.a ../DStarBase/DStarBase.a ../IRCDDB/IRCDDB.a ../BaseCommon/BaseCommon.a $(LDFLAGS) -lgtest -lgtest_main %.o : %.cpp - $(CC) $(CPPFLAGS) -DUNIT_TESTS -I../ -MMD -MD -c $< -o $@ + $(CC) $(CPPFLAGS) -DUNIT_TESTS -I../APRS -I../Common -I../BaseCommon -I../DStarBase -I../IRCDDB -I../VersionInfo -MMD -MD -c $< -o $@ -include $(DEPS) @@ -16,4 +16,11 @@ dstargateway_tests: $(OBJS) .PHONY clean : clean : - @$(RM) $(OBJS) $(DEPS) dstargateway_tests + @$(RM) *.o *.d dstargateway_tests + +../APRS/APRS.a: +../Common/Common.a: +../DStarBase/DStarBase.a: +../BaseCommon/BaseCommon.a: +../IRCDDB/IRCDDB.a: +../VersionInfo/GitVersion.h: diff --git a/VersionInfo/Makefile b/VersionInfo/Makefile new file mode 100644 index 0000000..0c6223e --- /dev/null +++ b/VersionInfo/Makefile @@ -0,0 +1,23 @@ +GitVersion.h : FORCE +ifneq ("$(wildcard .git/index)","") + @echo "#pragma once" > /tmp/$@ + @echo "#include " >> /tmp/$@ + @echo "const std::string gitversion(\"$(shell git rev-parse --short HEAD)\");" >> /tmp/$@ +else + @echo "#pragma once" > /tmp/$@ + @echo "#include " >> /tmp/$@ + @echo "const std::string gitversion(\"0000000\");" >> /tmp/$@ +endif + @cmp -s /tmp/$@ $@; \ + RETVAL=$$?; \ + if [ $$RETVAL -ne 0 ]; then \ + echo "Git version has changed"; \ + cp -f /tmp/$@ $@; \ + fi; \ + rm /tmp/$@; + +.PHONY: clean +clean: + $(RM) *.o *.d GitVersion.h + +FORCE: diff --git a/Version.h b/VersionInfo/Version.h similarity index 100% rename from Version.h rename to VersionInfo/Version.h From 17d0dc0d5a11ac740c42c008253287bdb07f57f1 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 30 Jan 2022 06:55:51 +0100 Subject: [PATCH 184/201] #17 fix git version not being generated --- Makefile | 2 +- VersionInfo/Makefile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9835c1f..9f295b6 100644 --- a/Makefile +++ b/Makefile @@ -66,7 +66,7 @@ DStarBase/DStarBase.a: BaseCommon/BaseCommon.a FORCE IRCDDB/IRCDDB.a: VersionInfo/GitVersion.h BaseCommon/BaseCommon.a FORCE $(MAKE) -C IRCDDB -VersionInfo/GitVersion.h: +VersionInfo/GitVersion.h: FORCE $(MAKE) -C VersionInfo .PHONY: clean diff --git a/VersionInfo/Makefile b/VersionInfo/Makefile index 0c6223e..0753691 100644 --- a/VersionInfo/Makefile +++ b/VersionInfo/Makefile @@ -1,5 +1,5 @@ GitVersion.h : FORCE -ifneq ("$(wildcard .git/index)","") +ifneq ("$(wildcard ../.git/index)","") @echo "#pragma once" > /tmp/$@ @echo "#include " >> /tmp/$@ @echo "const std::string gitversion(\"$(shell git rev-parse --short HEAD)\");" >> /tmp/$@ From c23134009e46973305e2422de43ddef83410f9ec Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 30 Jan 2022 07:38:11 +0100 Subject: [PATCH 185/201] #17 fix tests not running --- .circleci/config.yml | 2 +- .vscode/tasks.json | 25 +++++++++++++++++++------ Makefile | 1 + Tests/Makefile | 5 ++--- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4e8c1d4..f858990 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,7 +24,7 @@ jobs: command: "make -j 3 ENABLE_DEBUG=1 USE_GPSD=1" - run: name: "Run Tests" - command: "make run-tests" + command: "make run-tests ENABLE_DEBUG=1 USE_GPSD=1" # Invoke jobs via workflows # See: https://circleci.com/docs/2.0/configuration-reference/#workflows workflows: diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 168ca95..68a8d9e 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,7 +4,7 @@ "version": "2.0.0", "tasks": [ { - "label": "Build", + "label": "Build All", "type": "shell", "command": "make", "args": [ @@ -12,10 +12,20 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", + "problemMatcher": [] + }, + { + "label": "Build DStarGateway", + "type": "shell", + "command": "make", + "args": [ + "-j3", + "ENABLE_DEBUG=1", + "USE_GPSD=1", + "DStarGateway/dstargateway" + ], + "group": "build", "problemMatcher": [] }, { @@ -28,7 +38,10 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] } ] diff --git a/Makefile b/Makefile index 9f295b6..fc595b6 100644 --- a/Makefile +++ b/Makefile @@ -145,3 +145,4 @@ run-tests: tests @$(MAKE) -C Tests run-tests FORCE: + @true diff --git a/Tests/Makefile b/Tests/Makefile index 2aafd55..2e29d24 100644 --- a/Tests/Makefile +++ b/Tests/Makefile @@ -1,10 +1,9 @@ - -SRCS = $(wildcard *.cpp) $(wildcard ../*.cpp) $(wildcard */*.cpp) +SRCS = $(wildcard *.cpp) $(wildcard */*.cpp) OBJS = $(SRCS:.cpp=.o) DEPS = $(SRCS:.cpp=.d) dstargateway_tests: ../VersionInfo/GitVersion.h $(OBJS) ../APRS/APRS.a ../IRCDDB/IRCDDB.a ../DStarBase/DStarBase.a ../BaseCommon/BaseCommon.a ../Common/Common.a - $(CC) $(CPPFLAGS) -o dstargateway_tests $(OBJS) ../Common/Common.a ../APRS/APRS.a ../DStarBase/DStarBase.a ../IRCDDB/IRCDDB.a ../BaseCommon/BaseCommon.a $(LDFLAGS) -lgtest -lgtest_main + $(CC) $(CPPFLAGS) -o dstargateway_tests $(OBJS) ../Common/Common.a ../APRS/APRS.a ../DStarBase/DStarBase.a ../IRCDDB/IRCDDB.a ../BaseCommon/BaseCommon.a $(LDFLAGS) -lgtest -lgtest_main %.o : %.cpp $(CC) $(CPPFLAGS) -DUNIT_TESTS -I../APRS -I../Common -I../BaseCommon -I../DStarBase -I../IRCDDB -I../VersionInfo -MMD -MD -c $< -o $@ From f1b3a2b0e3990be63a1da4ea370bbc7c8a5e8328 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 30 Jan 2022 07:44:55 +0100 Subject: [PATCH 186/201] #17 move example.cfg to correct folder --- {Common => DStarGateway}/example.cfg | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {Common => DStarGateway}/example.cfg (100%) diff --git a/Common/example.cfg b/DStarGateway/example.cfg similarity index 100% rename from Common/example.cfg rename to DStarGateway/example.cfg From dde6bda1cfe22cb7068246737650fadcd27e0eeb Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 30 Jan 2022 07:49:10 +0100 Subject: [PATCH 187/201] #17 fix broken install --- DStarGateway/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DStarGateway/Makefile b/DStarGateway/Makefile index e7afbaf..81a7298 100644 --- a/DStarGateway/Makefile +++ b/DStarGateway/Makefile @@ -15,7 +15,7 @@ clean: .PHONY install: install: dstargateway # copy executable - @cp -f dstargateway $(BIN_DIR + @cp -f dstargateway $(BIN_DIR) # copy and adjust config @cp -fn example.cfg $(CFG_DIR)/dstargateway.cfg From f835d5a8fe1fd5619c727bf5e769051ff2ce65a0 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 30 Jan 2022 07:52:53 +0100 Subject: [PATCH 188/201] vs code stuff --- .vscode/launch.json | 4 ++-- .vscode/tasks.json | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index ef85a5f..1bba5af 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,8 +8,8 @@ "name": "(gdb) Lancer", "type": "cppdbg", "request": "launch", - "program": "${workspaceFolder}/dstargateway", - "args": ["${workspaceFolder}/___test.cfg"], + "program": "${workspaceFolder}/DStarGateway/dstargateway", + "args": ["${workspaceFolder}/Sandbox/___test.cfg"], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 68a8d9e..f14f4ca 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -25,7 +25,10 @@ "USE_GPSD=1", "DStarGateway/dstargateway" ], - "group": "build", + "group": { + "kind": "build", + "isDefault": true + }, "problemMatcher": [] }, { @@ -38,10 +41,7 @@ "ENABLE_DEBUG=1", "USE_GPSD=1" ], - "group": { - "kind": "build", - "isDefault": true - }, + "group": "build", "problemMatcher": [] } ] From accb66a52121150084f7b99c0e99ff555b0e4d45 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 30 Jan 2022 15:30:36 +0100 Subject: [PATCH 189/201] #17 fix copy paste error --- DStarGateway/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DStarGateway/Makefile b/DStarGateway/Makefile index 81a7298..73318d1 100644 --- a/DStarGateway/Makefile +++ b/DStarGateway/Makefile @@ -10,7 +10,7 @@ dstargateway: ../VersionInfo/GitVersion.h $(OBJS) ../APRS/APRS.a ../IRCDDB/IRCDD .PHONY clean: clean: - $(RM) *.o *.d Common.a + $(RM) *.o *.d dstargateway .PHONY install: install: dstargateway From 46d00ede092dcf9bf1b5139ccf01f3fa50f06c74 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 30 Jan 2022 15:35:40 +0100 Subject: [PATCH 190/201] Bump copypright --- DStarGateway/DStarGatewayApp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DStarGateway/DStarGatewayApp.cpp b/DStarGateway/DStarGatewayApp.cpp index 16c3903..15de622 100644 --- a/DStarGateway/DStarGatewayApp.cpp +++ b/DStarGateway/DStarGatewayApp.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2010,2011 by Jonathan Naylor G4KLX - * Copyright (c) 2021 by Geoffrey Merck F4FXL / KC3FRA + * 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 From fbe9fdaa9b853fc6cf5e9fe7eda39654584e7fd5 Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 30 Jan 2022 20:26:28 +0100 Subject: [PATCH 191/201] #17 Add DGWRemoteControl --- DGWRemoteControl/Makefile | 27 +++++++++++++++++++++++++++ Makefile | 17 +++++++---------- 2 files changed, 34 insertions(+), 10 deletions(-) create mode 100644 DGWRemoteControl/Makefile diff --git a/DGWRemoteControl/Makefile b/DGWRemoteControl/Makefile new file mode 100644 index 0000000..ca08e63 --- /dev/null +++ b/DGWRemoteControl/Makefile @@ -0,0 +1,27 @@ +SRCS = $(wildcard *.cpp) +OBJS = $(SRCS:.cpp=.o) +DEPS = $(SRCS:.cpp=.d) + +dgwremotecontrol: ../VersionInfo/GitVersion.h $(OBJS) ../DStarBase/DStarBase.a ../BaseCommon/BaseCommon.a + $(CC) $(CPPFLAGS) -o dgwremotecontrol $(OBJS) ../DStarBase/DStarBase.a ../BaseCommon/BaseCommon.a $(LDFLAGS) + +%.o : %.cpp + $(CC) -I../APRS -I../Common -I../BaseCommon -I../DStarBase -I../IRCDDB -I../VersionInfo $(CPPFLAGS) -MMD -MD -c $< -o $@ + +.PHONY clean: +clean: + $(RM) *.o *.d dgwremotecontrol.a + +.PHONY install: +install: dgwremotecontrol +# copy executable + @cp -f dgwremotecontrol $(BIN_DIR) + +# copy and adjust config + @cp -fn example.cfg $(CFG_DIR)/dgwremotecontrol.cfg + @sed -i "s|path=/var/log/dgwremotecontrol/|path=$(LOG_DIR)|g" $(CFG_DIR)/dgwremotecontrol.cfg + @sed -i "s|data=/usr/local/share/dgwremotecontrol.d/|data=$(DATA_DIR)|g" $(CFG_DIR)/dgwremotecontrol.cfg + +../BaseCommon/BaseCommon.a: +../DStarBase/DStarBase.a: +../VersionInfo/GitVersion.h: diff --git a/Makefile b/Makefile index fc595b6..1b56e12 100644 --- a/Makefile +++ b/Makefile @@ -38,18 +38,9 @@ export CPPFLAGS+= -DUSE_GPSD export LDFLAGS+= -lgps endif -SRCS = $(wildcard *.cpp) -OBJS = $(SRCS:.cpp=.o) -DEPS = $(SRCS:.cpp=.d) .PHONY: all -all: DStarGateway/dstargateway tests - -DStarGateway/dstargateway : VersionInfo/GitVersion.h $(OBJS) APRS/APRS.a Common/Common.a DStarBase/DStarBase.a IRCDDB/IRCDDB.a BaseCommon/BaseCommon.a - $(MAKE) -C DStarGateway - -%.o : %.cpp - $(CC) -IAPRS/ -IBaseCommon/ -IDStarBase/ -IIRCDDB/ -IVersionInfo/ $(CPPFLAGS) -MMD -MD -c $< -o $@ +all: DStarGateway/dstargateway DGWRemoteControl/dgwremotecontrol tests APRS/APRS.a: BaseCommon/BaseCommon.a FORCE $(MAKE) -C APRS @@ -63,6 +54,12 @@ BaseCommon/BaseCommon.a: FORCE DStarBase/DStarBase.a: BaseCommon/BaseCommon.a FORCE $(MAKE) -C DStarBase +DStarGateway/dstargateway : VersionInfo/GitVersion.h $(OBJS) APRS/APRS.a Common/Common.a DStarBase/DStarBase.a IRCDDB/IRCDDB.a BaseCommon/BaseCommon.a FORCE + $(MAKE) -C DStarGateway + +DGWRemoteControl/dgwremotecontrol: VersionInfo/GitVersion.h $(OBJS) DStarBase/DStarBase.a BaseCommon/BaseCommon.a FORCE + $(MAKE) -C DGWRemoteControl + IRCDDB/IRCDDB.a: VersionInfo/GitVersion.h BaseCommon/BaseCommon.a FORCE $(MAKE) -C IRCDDB From 5c76994689b3cb8c58ce032f82e5adbc1e37539e Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sun, 30 Jan 2022 20:53:04 +0100 Subject: [PATCH 192/201] #17 start DGWRemoteControl --- .gitignore | 1 + .vscode/launch.json | 26 +- .vscode/tasks.json | 13 + BaseCommon/optionparser.h | 699 +++++++++++++++++++++++ BaseCommon/optionparser.h.LICENSE | 21 + DGWRemoteControl/DGWRemoteControlApp.cpp | 82 +++ VersionInfo/Version.h | 1 + 7 files changed, 842 insertions(+), 1 deletion(-) create mode 100644 BaseCommon/optionparser.h create mode 100644 BaseCommon/optionparser.h.LICENSE create mode 100644 DGWRemoteControl/DGWRemoteControlApp.cpp diff --git a/.gitignore b/.gitignore index 32c2539..08410df 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ Sandbox/* *.app dstargateway Tests/dstargateway_tests +DGWRemoteControl/dgwremotecontrol diff --git a/.vscode/launch.json b/.vscode/launch.json index 1bba5af..264e6c4 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "(gdb) Lancer", + "name": "(gdb) dstargateway", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/DStarGateway/dstargateway", @@ -28,6 +28,30 @@ } ] }, + { + "name": "(gdb) dgwremotecontrol", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/DGWRemoteControl/dgwremotecontrol", + "args": ["--name", "blabla", "F4FXL__B", "link", "never", "DCS208_C"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Activer l'impression en mode Pretty pour gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Définir la version désassemblage sur Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + ] + }, { "name": "Tests", "type": "cppdbg", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index f14f4ca..7b2b113 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -25,6 +25,19 @@ "USE_GPSD=1", "DStarGateway/dstargateway" ], + "group": "build", + "problemMatcher": [] + }, + { + "label": "Build DGWRemoteControl", + "type": "shell", + "command": "make", + "args": [ + "-j3", + "ENABLE_DEBUG=1", + "USE_GPSD=1", + "DGWRemoteControl/dgwremotecontrol" + ], "group": { "kind": "build", "isDefault": true diff --git a/BaseCommon/optionparser.h b/BaseCommon/optionparser.h new file mode 100644 index 0000000..d5f90d2 --- /dev/null +++ b/BaseCommon/optionparser.h @@ -0,0 +1,699 @@ +//----------------------------------------------------------------------------- +// optionparser.h -- A Header-Only commandline argument parser +// Author: Luke de Oliveira +// License: MIT +//----------------------------------------------------------------------------- + +#ifndef OPTIONPARSER_H_ +#define OPTIONPARSER_H_ + +#include +#include +#include +#include +#include +#include +#include + +namespace optionparser { + +// The utils::* namespace contains general utilities not necessarily useful +// outside the main scope of the library +namespace utils { + +std::vector split_str(std::string s, + const std::string &delimiter = " ") { + size_t pos = 0; + size_t delimiter_length = delimiter.length(); + std::vector vals; + while ((pos = s.find(delimiter)) != std::string::npos) { + vals.push_back(s.substr(0, pos)); + s.erase(0, pos + delimiter_length); + } + vals.push_back(s); + return vals; +} + +std::string stitch_str(const std::vector &text, + unsigned max_per_line = 80, + const std::string &leading_str = "") { + std::vector result; + + std::string line_value; + for (const auto &token : text) { + if (line_value.empty()) { + line_value = (leading_str + token); + continue; + } + + auto hypothetical_line = line_value; + hypothetical_line.append(" " + token); + + if (hypothetical_line.size() > max_per_line) { + // In this case, we were better off before + result.emplace_back(line_value); + line_value = (leading_str + token); + } else { + line_value = hypothetical_line; + } + } + // Collect the last line since we don't track indices in the loop proper. + result.emplace_back(line_value); + return std::accumulate( + result.begin() + 1, result.end(), result.at(0), + [](std::string &s, const std::string &piece) -> std::string { + return s + "\n" + piece; + }); +} + +} // end namespace utils + +// Define a thin error for any sort of parser error that arises +class ParserError : public std::runtime_error { + using std::runtime_error::runtime_error; +}; + +// Enums for Option config +enum StorageMode { STORE_TRUE = 0, STORE_VALUE, STORE_MULT_VALUES }; +enum OptionType { LONG_OPT = 0, SHORT_OPT, POSITIONAL_OPT, EMPTY_OPT }; + +// Option class definition +class Option { +public: + Option() = default; + + std::string help_doc(); + + std::string &short_flag() { return m_short_flag; } + std::string &long_flag() { return m_long_flag; } + std::string &pos_flag() { return m_pos_flag; } + + bool found() { return m_found; } + Option &found(bool found) { + m_found = found; + return *this; + } + + StorageMode mode() { return m_mode; } + Option &mode(const StorageMode &mode) { + m_mode = mode; + return *this; + } + + bool required() { return m_required; } + Option &required(bool req) { + m_required = req; + return *this; + } + + std::string metavar() { + std::string formatted_metavar; + if (!m_metavar.empty()) { + if (m_mode == STORE_TRUE) { + return ""; + } + formatted_metavar = m_metavar; + } else { + for (const auto &cand : + {m_dest, m_pos_flag, m_long_flag, std::string("ARG")}) { + if (!cand.empty()) { + formatted_metavar = cand.substr(cand.find_first_not_of('-')); + std::transform(formatted_metavar.begin(), formatted_metavar.end(), + formatted_metavar.begin(), ::toupper); + break; + } + } + } + if (m_mode == STORE_MULT_VALUES) { + formatted_metavar = (formatted_metavar + "1 [" + formatted_metavar + + "2, " + formatted_metavar + "3, ...]"); + } + return formatted_metavar; + } + + Option &metavar(const std::string &mvar) { + m_metavar = mvar; + return *this; + } + + std::string help() { return m_help; } + Option &help(const std::string &help) { + m_help = help; + return *this; + } + + std::string dest() { return m_dest; } + Option &dest(const std::string &dest) { + m_dest = dest; + return *this; + } + + std::string default_value() { return m_default_value; } + + Option &default_value(const std::string &default_value) { + m_default_value = default_value; + return *this; + } + + Option &default_value(const char *default_value) { + m_default_value = std::string(default_value); + return *this; + } + + template Option &default_value(const T &default_value) { + m_default_value = std::to_string(default_value); + return *this; + } + + static OptionType get_type(std::string opt); + static std::string get_destination(const std::string &first_option, + const std::string &second_option); + static void validate_option_types(const OptionType &first_option_type, + const OptionType &second_option_type); + +private: + bool m_found = false; + bool m_required = false; + StorageMode m_mode = STORE_TRUE; + std::string m_help = ""; + std::string m_dest = ""; + std::string m_default_value = ""; + std::string m_metavar = ""; + + std::string m_short_flag = ""; + std::string m_long_flag = ""; + std::string m_pos_flag = ""; +}; + +// Non-inline definitions for Option methods +std::string Option::help_doc() { + std::string h = " "; + if (!m_long_flag.empty()) { + h += m_long_flag; + if (!m_short_flag.empty()) { + h += ", "; + } + } + if (!m_short_flag.empty()) { + h += m_short_flag; + } + if (!m_pos_flag.empty()) { + h += m_pos_flag; + } + + auto arg_buf = std::max(h.length() + 1, static_cast(25)); + auto help_str = utils::stitch_str(utils::split_str(m_help), arg_buf + 50, + std::string(arg_buf, ' ')); + char char_buf[h.length() + help_str.length() + 100]; + sprintf(char_buf, ("%-" + std::to_string(arg_buf) + "s%s\n").c_str(), + h.c_str(), help_str.substr(arg_buf).c_str()); + return std::string(char_buf); +} + +OptionType Option::get_type(std::string opt) { + if (opt.empty()) { + return OptionType::EMPTY_OPT; + } + if (opt.size() == 2) { + if (opt[0] == '-') { + return OptionType::SHORT_OPT; + } + } + + if (opt.size() > 2) { + if (opt[0] == '-' && opt[1] == '-') { + return OptionType::LONG_OPT; + } + } + + return OptionType::POSITIONAL_OPT; +} + +void Option::validate_option_types(const OptionType &first_option_type, + const OptionType &second_option_type) { + + auto err = [](const std::string &msg) { + throw std::runtime_error("Parser inconsistency: " + msg); + }; + if (first_option_type == OptionType::EMPTY_OPT) { + err("Cannot have first option be empty."); + } + if (first_option_type == OptionType::POSITIONAL_OPT && + second_option_type != OptionType::EMPTY_OPT) { + err("Positional arguments can only have one option, found non-empty second " + "option."); + } + if (second_option_type == OptionType::POSITIONAL_OPT) { + err("Cannot have second option be a positional option."); + } +} + +std::string Option::get_destination(const std::string &first_option, + const std::string &second_option) { + std::string dest; + + auto first_opt_type = Option::get_type(first_option); + auto second_opt_type = Option::get_type(second_option); + + validate_option_types(first_opt_type, second_opt_type); + + if (first_opt_type == OptionType::LONG_OPT) { + dest = first_option.substr(2); + } else if (second_opt_type == OptionType::LONG_OPT) { + dest = second_option.substr(2); + } else { + if (first_opt_type == OptionType::SHORT_OPT) { + dest = first_option.substr(1) + "_option"; + } else if (second_opt_type == OptionType::SHORT_OPT) { + dest = second_option.substr(1) + "_option"; + } else { + if (first_opt_type == OptionType::POSITIONAL_OPT && + second_opt_type == OptionType::EMPTY_OPT) { + dest = first_option; + } else { + std::string msg = "Parser inconsistency error."; + throw std::runtime_error(msg); + } + } + } + + return dest; +} + +// OptionParser class definition +class OptionParser { +public: + explicit OptionParser(std::string description = "", bool create_help = true) + : m_options(0), m_description(std::move(description)), + m_pos_args_count(1), m_exit_on_failure(true) { + if (create_help) { + add_option("--help", "-h").help("Display this help message and exit."); + } + } + + ~OptionParser() = default; + + void eat_arguments(unsigned int argc, char const *argv[]); + + Option &add_option(const std::string &first_option, + const std::string &second_option = ""); + + // We template-specialize these later + template T get_value(const std::string &key); + + void help(); + + OptionParser &exit_on_failure(bool exit = true); + + OptionParser &throw_on_failure(bool throw_ = true); + +private: + Option &add_option_internal(const std::string &first_option, + const std::string &second_option); + + void try_to_exit_with_message(const std::string &e); + + ParserError fail_for_missing_key(const std::string &key); + + ParserError fail_unrecognized_argument(const std::string &arg); + + ParserError + fail_for_missing_arguments(const std::vector &missing_flags); + + bool get_value_arg(std::vector &arguments, unsigned int &arg, + Option &opt, std::string &flag); + + bool try_to_get_opt(std::vector &arguments, unsigned int &arg, + Option &option, std::string &flag); + + void check_for_missing_args(); + + + std::vector