From 41e89227728b1670a3a415080d9a33c76edb027a Mon Sep 17 00:00:00 2001 From: Geoffrey Merck Date: Sat, 22 Jan 2022 16:00:20 +0100 Subject: [PATCH 01/15] #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 02/15] #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 03/15] #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 04/15] 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 05/15] 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 06/15] 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 07/15] #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 08/15] #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 09/15] #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 10/15] #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 11/15] #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 12/15] #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 13/15] #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 14/15] #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 15/15] #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))