From c6deee572f1af7e091609abe9300eb1b496c966c Mon Sep 17 00:00:00 2001 From: Jonathan Naylor Date: Sun, 6 Sep 2020 13:45:06 +0100 Subject: [PATCH] IPv6 cleanups. --- NXDNGateway/APRSWriter.cpp | 12 +- NXDNGateway/IcomNetwork.cpp | 10 +- NXDNGateway/KenwoodNetwork.cpp | 24 ++- NXDNGateway/Makefile | 8 +- NXDNGateway/NXDNNetwork.h | 6 +- NXDNGateway/Reflectors.cpp | 64 +++++--- NXDNGateway/Reflectors.h | 14 +- NXDNGateway/RptNetwork.h | 2 +- NXDNGateway/UDPSocket.cpp | 218 ++++++++++++++++--------- NXDNGateway/UDPSocket.h | 31 +++- NXDNGateway/Version.h | 2 +- NXDNParrot/Makefile | 4 +- NXDNParrot/UDPSocket.cpp | 263 ++++++++++++++++++++----------- NXDNParrot/UDPSocket.h | 37 +++-- NXDNParrot/Version.h | 2 +- NXDNReflector/IcomNetwork.cpp | 12 +- NXDNReflector/IcomNetwork.h | 2 +- NXDNReflector/KenwoodNetwork.cpp | 24 ++- NXDNReflector/KenwoodNetwork.h | 2 +- NXDNReflector/Makefile | 8 +- NXDNReflector/UDPSocket.cpp | 218 ++++++++++++++++--------- NXDNReflector/UDPSocket.h | 31 +++- NXDNReflector/Version.h | 2 +- 23 files changed, 664 insertions(+), 332 deletions(-) diff --git a/NXDNGateway/APRSWriter.cpp b/NXDNGateway/APRSWriter.cpp index 0191dc1..bc58ea9 100644 --- a/NXDNGateway/APRSWriter.cpp +++ b/NXDNGateway/APRSWriter.cpp @@ -35,7 +35,7 @@ m_longitude(0.0F), m_height(0), m_desc(), m_aprsAddr(), -m_aprsAddrLen(), +m_aprsAddrLen(0U), m_aprsSocket() #if defined(USE_GPSD) ,m_gpsdEnabled(false), @@ -53,7 +53,8 @@ m_gpsdData() m_callsign.append(suffix.substr(0U, 1U)); } - CUDPSocket::lookup(address, port, m_aprsAddr, m_aprsAddrLen); + if (CUDPSocket::lookup(address, port, m_aprsAddr, m_aprsAddrLen) != 0) + m_aprsAddrLen = 0U; } CAPRSWriter::~CAPRSWriter() @@ -88,6 +89,11 @@ void CAPRSWriter::setGPSDLocation(const std::string& address, const std::string& bool CAPRSWriter::open() { + if (m_aprsAddrLen == 0U) { + LogError("Unable to resolve the address of the APRS Gateway"); + return false; + } + #if defined(USE_GPSD) if (m_gpsdEnabled) { int ret = ::gps_open(m_gpsdAddress.c_str(), m_gpsdPort.c_str(), &m_gpsdData); @@ -101,7 +107,7 @@ bool CAPRSWriter::open() LogMessage("Connected to GPSD"); } #endif - bool ret = m_aprsSocket.open(); + bool ret = m_aprsSocket.open(m_aprsAddr); if (!ret) return false; diff --git a/NXDNGateway/IcomNetwork.cpp b/NXDNGateway/IcomNetwork.cpp index 0925009..a42a627 100644 --- a/NXDNGateway/IcomNetwork.cpp +++ b/NXDNGateway/IcomNetwork.cpp @@ -29,14 +29,15 @@ const unsigned int BUFFER_LENGTH = 200U; CIcomNetwork::CIcomNetwork(unsigned int localPort, const std::string& rptAddress, unsigned int rptPort, bool debug) : m_socket(localPort), m_addr(), -m_addrLen(), +m_addrLen(0U), m_debug(debug) { assert(localPort > 0U); assert(!rptAddress.empty()); assert(rptPort > 0U); - CUDPSocket::lookup(rptAddress, rptPort, m_addr, m_addrLen); + if (CUDPSocket::lookup(rptAddress, rptPort, m_addr, m_addrLen) != 0) + m_addrLen = 0U; } CIcomNetwork::~CIcomNetwork() @@ -45,6 +46,11 @@ CIcomNetwork::~CIcomNetwork() bool CIcomNetwork::open() { + if (m_addrLen == 0U) { + LogError("Unable to resolve the address of the Icom network"); + return false; + } + LogMessage("Opening Icom connection"); return m_socket.open(); diff --git a/NXDNGateway/KenwoodNetwork.cpp b/NXDNGateway/KenwoodNetwork.cpp index f406abd..a5f1abe 100644 --- a/NXDNGateway/KenwoodNetwork.cpp +++ b/NXDNGateway/KenwoodNetwork.cpp @@ -37,9 +37,9 @@ CKenwoodNetwork::CKenwoodNetwork(unsigned int localPort, const std::string& rptA m_rtpSocket(localPort + 0U), m_rtcpSocket(localPort + 1U), m_rtcpAddr(), -m_rtcpAddrLen(), +m_rtcpAddrLen(0U), m_rtpAddr(), -m_rtpAddrLen(), +m_rtpAddrLen(0U), m_headerSeen(false), m_seen1(false), m_seen2(false), @@ -65,8 +65,11 @@ m_random() m_sacch = new unsigned char[10U]; - CUDPSocket::lookup(rptAddress, rptPort + 0U, m_rtpAddr, m_rtpAddrLen); - CUDPSocket::lookup(rptAddress, rptPort + 1U, m_rtcpAddr, m_rtcpAddrLen); + if (CUDPSocket::lookup(rptAddress, rptPort + 0U, m_rtpAddr, m_rtpAddrLen) != 0) + m_rtpAddrLen = 0U; + + if (CUDPSocket::lookup(rptAddress, rptPort + 1U, m_rtcpAddr, m_rtcpAddrLen) != 0) + m_rtcpAddrLen = 0U; std::random_device rd; std::mt19937 mt(rd()); @@ -80,12 +83,17 @@ CKenwoodNetwork::~CKenwoodNetwork() bool CKenwoodNetwork::open() { + if (m_rtpAddrLen == 0U || m_rtcpAddrLen == 0U) { + LogError("Unable to resolve the address of the Kenwood network"); + return false; + } + LogMessage("Opening Kenwood connection"); - if (!m_rtcpSocket.open()) + if (!m_rtcpSocket.open(m_rtcpAddr)) return false; - if (!m_rtpSocket.open()) { + if (!m_rtpSocket.open(m_rtpAddr)) { m_rtcpSocket.close(); return false; } @@ -559,7 +567,7 @@ unsigned int CKenwoodNetwork::readRTP(unsigned char* data) return 0U; // Check if the data is for us - if (!CUDPSocket::match(m_rtpAddr, addr)) { + if (!CUDPSocket::match(m_rtpAddr, addr, IMT_ADDRESS_ONLY)) { LogMessage("Kenwood RTP packet received from an invalid source"); return 0U; } @@ -585,7 +593,7 @@ unsigned int CKenwoodNetwork::readRTCP(unsigned char* data) return 0U; // Check if the data is for us - if (!CUDPSocket::match(m_rtcpAddr, addr)) { + if (!CUDPSocket::match(m_rtcpAddr, addr, IMT_ADDRESS_ONLY)) { LogMessage("Kenwood RTCP packet received from an invalid source"); return 0U; } diff --git a/NXDNGateway/Makefile b/NXDNGateway/Makefile index df938eb..c989240 100644 --- a/NXDNGateway/Makefile +++ b/NXDNGateway/Makefile @@ -1,12 +1,12 @@ -CC = gcc -CXX = g++ +CC = cc +CXX = c++ # Use the following CFLAGS and LIBS if you don't want to use gpsd. -CFLAGS = -g -O3 -Wall -std=c++0x -pthread +CFLAGS = -g -O3 -Wall -DHAVE_LOG_H -std=c++0x -pthread LIBS = -lpthread # Use the following CFLAGS and LIBS if you do want to use gpsd. -#CFLAGS = -g -O3 -Wall -DUSE_GPSD -std=c++0x -pthread +#CFLAGS = -g -O3 -Wall -DHAVE_LOG_H -DUSE_GPSD -std=c++0x -pthread #LIBS = -lpthread -lgps LDFLAGS = -g diff --git a/NXDNGateway/NXDNNetwork.h b/NXDNGateway/NXDNNetwork.h index 33a0c65..1ce4cde 100644 --- a/NXDNGateway/NXDNNetwork.h +++ b/NXDNGateway/NXDNNetwork.h @@ -42,9 +42,9 @@ public: void close(); private: - std::string m_callsign; - CUDPSocket m_socket; - bool m_debug; + std::string m_callsign; + CUDPSocket m_socket; + bool m_debug; }; #endif diff --git a/NXDNGateway/Reflectors.cpp b/NXDNGateway/Reflectors.cpp index 41d1f59..9b509eb 100644 --- a/NXDNGateway/Reflectors.cpp +++ b/NXDNGateway/Reflectors.cpp @@ -81,10 +81,17 @@ bool CReflectors::load() std::string host = std::string(p2); unsigned int port = (unsigned int)::atoi(p3); - CNXDNReflector* refl = new CNXDNReflector; - refl->m_id = (unsigned short)::atoi(p1); - CUDPSocket::lookup(host, port, refl->m_addr, refl->m_addrLen); - m_reflectors.push_back(refl); + sockaddr_storage addr; + unsigned int addrLen; + if (CUDPSocket::lookup(host, port, addr, addrLen) == 0) { + CNXDNReflector* refl = new CNXDNReflector; + refl->m_id = (unsigned short)::atoi(p1); + refl->m_addr = addr; + refl->m_addrLen = addrLen; + m_reflectors.push_back(refl); + } else { + LogWarning("Unable to resolve the address of %s", host.c_str()); + } } } @@ -109,10 +116,17 @@ bool CReflectors::load() std::string host = std::string(p2); unsigned int port = (unsigned int)::atoi(p3); - CNXDNReflector* refl = new CNXDNReflector; - refl->m_id = id; - CUDPSocket::lookup(host, port, refl->m_addr, refl->m_addrLen); - m_reflectors.push_back(refl); + sockaddr_storage addr; + unsigned int addrLen; + if (CUDPSocket::lookup(host, port, addr, addrLen) == 0) { + CNXDNReflector* refl = new CNXDNReflector; + refl->m_id = id; + refl->m_addr = addr; + refl->m_addrLen = addrLen; + m_reflectors.push_back(refl); + } else { + LogWarning("Unable to resolve the address of %s", host.c_str()); + } } } } @@ -125,20 +139,34 @@ bool CReflectors::load() // Add the Parrot entry if (m_parrotPort > 0U) { - CNXDNReflector* refl = new CNXDNReflector; - refl->m_id = 10U; - CUDPSocket::lookup(m_parrotAddress, m_parrotPort, refl->m_addr, refl->m_addrLen); - m_reflectors.push_back(refl); - LogInfo("Loaded NXDN parrot (TG%u)", refl->m_id); + sockaddr_storage addr; + unsigned int addrLen; + if (CUDPSocket::lookup(m_parrotAddress, m_parrotPort, addr, addrLen) == 0) { + CNXDNReflector* refl = new CNXDNReflector; + refl->m_id = 10U; + refl->m_addr = addr; + refl->m_addrLen = addrLen; + m_reflectors.push_back(refl); + LogInfo("Loaded NXDN parrot (TG%u)", refl->m_id); + } else { + LogWarning("Unable to resolve the address of the NXDN Parrot"); + } } // Add the NXDN2DMR entry if (m_nxdn2dmrPort > 0U) { - CNXDNReflector* refl = new CNXDNReflector; - refl->m_id = 20U; - CUDPSocket::lookup(m_nxdn2dmrAddress, m_nxdn2dmrPort, refl->m_addr, refl->m_addrLen); - m_reflectors.push_back(refl); - LogInfo("Loaded NXDN2DMR reflector (TG%u)", refl->m_id); + sockaddr_storage addr; + unsigned int addrLen; + if (CUDPSocket::lookup(m_nxdn2dmrAddress, m_nxdn2dmrPort, addr, addrLen) == 0) { + CNXDNReflector* refl = new CNXDNReflector; + refl->m_id = 20U; + refl->m_addr = addr; + refl->m_addrLen = addrLen; + m_reflectors.push_back(refl); + LogInfo("Loaded NXDN2DMR (TG%u)", refl->m_id); + } else { + LogWarning("Unable to resolve the address of NXDN2DMR"); + } } size = m_reflectors.size(); diff --git a/NXDNGateway/Reflectors.h b/NXDNGateway/Reflectors.h index e10b774..9e0358a 100644 --- a/NXDNGateway/Reflectors.h +++ b/NXDNGateway/Reflectors.h @@ -54,14 +54,14 @@ public: void clock(unsigned int ms); private: - std::string m_hostsFile1; - std::string m_hostsFile2; - std::string m_parrotAddress; - unsigned int m_parrotPort; - std::string m_nxdn2dmrAddress; - unsigned int m_nxdn2dmrPort; + std::string m_hostsFile1; + std::string m_hostsFile2; + std::string m_parrotAddress; + unsigned int m_parrotPort; + std::string m_nxdn2dmrAddress; + unsigned int m_nxdn2dmrPort; std::vector m_reflectors; - CTimer m_timer; + CTimer m_timer; }; #endif diff --git a/NXDNGateway/RptNetwork.h b/NXDNGateway/RptNetwork.h index 44f86d8..8cdedac 100644 --- a/NXDNGateway/RptNetwork.h +++ b/NXDNGateway/RptNetwork.h @@ -47,7 +47,7 @@ public: virtual void close() = 0; - virtual void clock(unsigned int ms) = 0; + virtual void clock(unsigned int ms) = 0; private: }; diff --git a/NXDNGateway/UDPSocket.cpp b/NXDNGateway/UDPSocket.cpp index 659d816..382925f 100644 --- a/NXDNGateway/UDPSocket.cpp +++ b/NXDNGateway/UDPSocket.cpp @@ -17,7 +17,6 @@ */ #include "UDPSocket.h" -#include "Log.h" #include @@ -26,26 +25,36 @@ #include #endif +#if defined(HAVE_LOG_H) +#include "Log.h" +#else +#define LogError(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__) +#define LogInfo(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__) +#endif CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) : -m_address(address), -m_port(port), -m_fd(-1) +m_address_save(address), +m_port_save(port), +m_counter(0U) { - assert(!address.empty()); - #if defined(_WIN32) || defined(_WIN64) WSAData data; int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); if (wsaRet != 0) LogError("Error from WSAStartup"); #endif + for (int i = 0; i < UDP_SOCKET_MAX; i++) { + m_address[i] = ""; + m_port[i] = 0U; + m_af[i] = 0U; + m_fd[i] = -1; + } } CUDPSocket::CUDPSocket(unsigned int port) : -m_address(), -m_port(port), -m_fd(-1) +m_address_save(), +m_port_save(port), +m_counter(0U) { #if defined(_WIN32) || defined(_WIN64) WSAData data; @@ -53,6 +62,12 @@ m_fd(-1) if (wsaRet != 0) LogError("Error from WSAStartup"); #endif + for (int i = 0; i < UDP_SOCKET_MAX; i++) { + m_address[i] = ""; + m_port[i] = 0U; + m_af[i] = 0U; + m_fd[i] = -1; + } } CUDPSocket::~CUDPSocket() @@ -96,58 +111,82 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_ return 0; } -bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& addr2) +bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type) { if (addr1.ss_family != addr2.ss_family) return false; - 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: + 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; } } -bool CUDPSocket::isnone(const sockaddr_storage& addr) +bool CUDPSocket::isNone(const sockaddr_storage& addr) { struct sockaddr_in *in = (struct sockaddr_in *)&addr; return ((addr.ss_family == AF_INET) && (in->sin_addr.s_addr == htonl(INADDR_NONE))); } -bool CUDPSocket::open() +bool CUDPSocket::open(const sockaddr_storage& address) { - return open(AF_UNSPEC); + return open(address.ss_family); } -bool CUDPSocket::open(const unsigned int af) +bool CUDPSocket::open(unsigned int af) +{ + return open(0, af, m_address_save, m_port_save); +} + +bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port) { sockaddr_storage addr; unsigned int addrlen; struct addrinfo hints; ::memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_PASSIVE; + hints.ai_flags = AI_PASSIVE; hints.ai_family = af; /* to determine protocol family, call lookup() first. */ - int err = lookup(m_address, m_port, addr, addrlen, hints); + int err = lookup(address, port, addr, addrlen, hints); if (err != 0) { - LogError("The local address is invalid - %s", m_address.c_str()); + LogError("The local address is invalid - %s", address.c_str()); return false; } - m_fd = ::socket(addr.ss_family, SOCK_DGRAM, 0); - if (m_fd < 0) { + int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0); + if (fd < 0) { #if defined(_WIN32) || defined(_WIN64) LogError("Cannot create the UDP socket, err: %lu", ::GetLastError()); #else @@ -156,9 +195,14 @@ bool CUDPSocket::open(const unsigned int af) return false; } - if (m_port > 0U) { + m_address[index] = address; + m_port[index] = port; + m_af[index] = addr.ss_family; + m_fd[index] = fd; + + if (port > 0U) { int reuse = 1; - if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { + if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { #if defined(_WIN32) || defined(_WIN64) LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError()); #else @@ -167,7 +211,7 @@ bool CUDPSocket::open(const unsigned int af) return false; } - if (::bind(m_fd, (sockaddr*)&addr, addrlen) == -1) { + if (::bind(fd, (sockaddr*)&addr, addrlen) == -1) { #if defined(_WIN32) || defined(_WIN64) LogError("Cannot bind the UDP address, err: %lu", ::GetLastError()); #else @@ -176,7 +220,7 @@ bool CUDPSocket::open(const unsigned int af) return false; } - LogInfo("Opening UDP port on %u", m_port); + LogInfo("Opening UDP port on %u", port); } return true; @@ -188,30 +232,43 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag assert(length > 0U); // Check that the readfrom() won't block - fd_set readFds; - FD_ZERO(&readFds); -#if defined(_WIN32) || defined(_WIN64) - FD_SET((unsigned int)m_fd, &readFds); -#else - FD_SET(m_fd, &readFds); -#endif + int i, n; + struct pollfd pfd[UDP_SOCKET_MAX]; + for (i = n = 0; i < UDP_SOCKET_MAX; i++) { + if (m_fd[i] >= 0) { + pfd[n].fd = m_fd[i]; + pfd[n].events = POLLIN; + n++; + } + } + + // no socket descriptor to receive + if (n == 0) + return 0; // Return immediately - timeval tv; - tv.tv_sec = 0L; - tv.tv_usec = 0L; - - int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv); +#if defined(_WIN32) || defined(_WIN64) + int ret = WSAPoll(pfd, n, 0); +#else + int ret = ::poll(pfd, n, 0); +#endif if (ret < 0) { #if defined(_WIN32) || defined(_WIN64) - LogError("Error returned from UDP select, err: %lu", ::GetLastError()); + LogError("Error returned from UDP poll, err: %lu", ::GetLastError()); #else - LogError("Error returned from UDP select, err: %d", errno); + LogError("Error returned from UDP poll, err: %d", errno); #endif return -1; } - if (ret == 0) + int index; + for (i = 0; i < n; i++) { + // round robin + index = (i + m_counter) % n; + if (pfd[index].revents & POLLIN) + break; + } + if (i == n) return 0; #if defined(_WIN32) || defined(_WIN64) @@ -221,9 +278,9 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag #endif #if defined(_WIN32) || defined(_WIN64) - int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); + int len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); #else - ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); + ssize_t len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); #endif if (len <= 0) { #if defined(_WIN32) || defined(_WIN64) @@ -234,6 +291,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag return -1; } + m_counter++; address_length = size; return len; } @@ -243,36 +301,52 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const s assert(buffer != NULL); assert(length > 0U); + bool result = false; + + for (int i = 0; i < UDP_SOCKET_MAX; i++) { + if (m_fd[i] < 0 || m_af[i] != address.ss_family) + continue; + #if defined(_WIN32) || defined(_WIN64) - int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, address_length); + int ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length); #else - ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, address_length); + ssize_t ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length); #endif - if (ret < 0) { + + if (ret < 0) { #if defined(_WIN32) || defined(_WIN64) - LogError("Error returned from sendto, err: %lu", ::GetLastError()); + LogError("Error returned from sendto, err: %lu", ::GetLastError()); #else - LogError("Error returned from sendto, err: %d", errno); + LogError("Error returned from sendto, err: %d", errno); #endif - return false; + } else { +#if defined(_WIN32) || defined(_WIN64) + if (ret == int(length)) + result = true; +#else + if (ret == ssize_t(length)) + result = true; +#endif + } } -#if defined(_WIN32) || defined(_WIN64) - if (ret != int(length)) - return false; -#else - if (ret != ssize_t(length)) - return false; -#endif - - return true; + return result; } void CUDPSocket::close() { -#if defined(_WIN32) || defined(_WIN64) - ::closesocket(m_fd); -#else - ::close(m_fd); -#endif + for (int i = 0; i < UDP_SOCKET_MAX; i++) + close(m_fd[i]); +} + +void CUDPSocket::close(const unsigned int index) +{ + if (m_fd[index] >= 0) { +#if defined(_WIN32) || defined(_WIN64) + ::closesocket(m_fd[index]); +#else + ::close(m_fd[index]); +#endif + m_fd[index] = -1; + } } diff --git a/NXDNGateway/UDPSocket.h b/NXDNGateway/UDPSocket.h index 386f059..b22eefc 100644 --- a/NXDNGateway/UDPSocket.h +++ b/NXDNGateway/UDPSocket.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -35,29 +36,45 @@ #include #endif +#if !defined(UDP_SOCKET_MAX) +#define UDP_SOCKET_MAX 1 +#endif + +enum IPMATCHTYPE { + IMT_ADDRESS_AND_PORT, + IMT_ADDRESS_ONLY +}; + class CUDPSocket { public: CUDPSocket(const std::string& address, unsigned int port = 0U); CUDPSocket(unsigned int port = 0U); ~CUDPSocket(); - bool open(); - bool open(const unsigned int af); + bool open(unsigned int af = AF_UNSPEC); + bool open(const sockaddr_storage& address); + bool open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port); int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length); bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length); void close(); + void close(const unsigned int index); static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length); static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length, struct addrinfo& hints); - static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2); - static bool isnone(const sockaddr_storage& addr); + static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IMT_ADDRESS_AND_PORT); + + static bool isNone(const sockaddr_storage& addr); private: - std::string m_address; - unsigned short m_port; - int m_fd; + std::string m_address_save; + unsigned short m_port_save; + std::string m_address[UDP_SOCKET_MAX]; + unsigned short m_port[UDP_SOCKET_MAX]; + unsigned int m_af[UDP_SOCKET_MAX]; + int m_fd[UDP_SOCKET_MAX]; + unsigned int m_counter; }; #endif diff --git a/NXDNGateway/Version.h b/NXDNGateway/Version.h index 55fea3c..b3a94e5 100644 --- a/NXDNGateway/Version.h +++ b/NXDNGateway/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200903"; +const char* VERSION = "20200906"; #endif diff --git a/NXDNParrot/Makefile b/NXDNParrot/Makefile index 4a03a5f..e82bca0 100644 --- a/NXDNParrot/Makefile +++ b/NXDNParrot/Makefile @@ -1,5 +1,5 @@ -CC = gcc -CXX = g++ +CC = cc +CXX = c++ CFLAGS = -g -O3 -Wall -std=c++0x -pthread LIBS = -lpthread LDFLAGS = -g diff --git a/NXDNParrot/UDPSocket.cpp b/NXDNParrot/UDPSocket.cpp index aa1770c..382925f 100644 --- a/NXDNParrot/UDPSocket.cpp +++ b/NXDNParrot/UDPSocket.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2016 by Jonathan Naylor G4KLX + * Copyright (C) 2006-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 @@ -25,33 +25,49 @@ #include #endif +#if defined(HAVE_LOG_H) +#include "Log.h" +#else +#define LogError(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__) +#define LogInfo(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__) +#endif CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) : -m_address(address), -m_port(port), -m_fd(-1) +m_address_save(address), +m_port_save(port), +m_counter(0U) { - assert(!address.empty()); - #if defined(_WIN32) || defined(_WIN64) WSAData data; int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); if (wsaRet != 0) - ::fprintf(stderr, "Error from WSAStartup\n"); + LogError("Error from WSAStartup"); #endif + for (int i = 0; i < UDP_SOCKET_MAX; i++) { + m_address[i] = ""; + m_port[i] = 0U; + m_af[i] = 0U; + m_fd[i] = -1; + } } CUDPSocket::CUDPSocket(unsigned int port) : -m_address(), -m_port(port), -m_fd(-1) +m_address_save(), +m_port_save(port), +m_counter(0U) { #if defined(_WIN32) || defined(_WIN64) WSAData data; int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); if (wsaRet != 0) - ::fprintf(stderr, "Error from WSAStartup\n"); + LogError("Error from WSAStartup"); #endif + for (int i = 0; i < UDP_SOCKET_MAX; i++) { + m_address[i] = ""; + m_port[i] = 0U; + m_af[i] = 0U; + m_fd[i] = -1; + } } CUDPSocket::~CUDPSocket() @@ -61,7 +77,7 @@ CUDPSocket::~CUDPSocket() #endif } -int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage &addr, unsigned int &address_length) +int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& address_length) { struct addrinfo hints; ::memset(&hints, 0, sizeof(hints)); @@ -69,117 +85,142 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_ return lookup(hostname, port, addr, address_length, hints); } -int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage &addr, unsigned int &address_length, struct addrinfo &hints) +int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& address_length, struct addrinfo& hints) { - int err; std::string portstr = std::to_string(port); struct addrinfo *res; /* port is always digits, no needs to lookup service */ hints.ai_flags |= AI_NUMERICSERV; - err = getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res); - if (err) { - sockaddr_in *paddr = (sockaddr_in *)&addr; - ::memset(paddr, 0, address_length = sizeof(sockaddr_in)); + int err = getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res); + if (err != 0) { + sockaddr_in* paddr = (sockaddr_in*)&addr; + ::memset(paddr, 0x00U, address_length = sizeof(sockaddr_in)); paddr->sin_family = AF_INET; paddr->sin_port = htons(port); paddr->sin_addr.s_addr = htonl(INADDR_NONE); - ::fprintf(stderr, "Cannot find address for host %s\n", hostname.c_str()); + LogError("Cannot find address for host %s", hostname.c_str()); return err; } ::memcpy(&addr, res->ai_addr, address_length = res->ai_addrlen); freeaddrinfo(res); + return 0; } -bool CUDPSocket::match(const sockaddr_storage &addr1, const sockaddr_storage &addr2) +bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type) { if (addr1.ss_family != addr2.ss_family) return false; - 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: + 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; } } -bool CUDPSocket::isnone(const sockaddr_storage &addr) +bool CUDPSocket::isNone(const sockaddr_storage& addr) { struct sockaddr_in *in = (struct sockaddr_in *)&addr; - return ( (addr.ss_family == AF_INET) && - (in->sin_addr.s_addr == htonl(INADDR_NONE)) ); + return ((addr.ss_family == AF_INET) && (in->sin_addr.s_addr == htonl(INADDR_NONE))); } -bool CUDPSocket::open() +bool CUDPSocket::open(const sockaddr_storage& address) { - return open(AF_UNSPEC); + return open(address.ss_family); } -bool CUDPSocket::open(const unsigned int af) +bool CUDPSocket::open(unsigned int af) +{ + return open(0, af, m_address_save, m_port_save); +} + +bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port) { - int err; sockaddr_storage addr; unsigned int addrlen; struct addrinfo hints; ::memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_PASSIVE; + hints.ai_flags = AI_PASSIVE; hints.ai_family = af; /* to determine protocol family, call lookup() first. */ - err = lookup(m_address, m_port, addr, addrlen, hints); - if (err) { - ::fprintf(stderr, "The local address is invalid - %s\n", m_address.c_str()); + int err = lookup(address, port, addr, addrlen, hints); + if (err != 0) { + LogError("The local address is invalid - %s", address.c_str()); return false; } - m_fd = ::socket(addr.ss_family, SOCK_DGRAM, 0); - if (m_fd < 0) { + int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0); + if (fd < 0) { #if defined(_WIN32) || defined(_WIN64) - ::fprintf(stderr, "Cannot create the UDP socket, err: %lu\n", ::GetLastError()); + LogError("Cannot create the UDP socket, err: %lu", ::GetLastError()); #else - ::fprintf(stderr, "Cannot create the UDP socket, err: %d\n", errno); + LogError("Cannot create the UDP socket, err: %d", errno); #endif return false; } - if (m_port > 0U) { + m_address[index] = address; + m_port[index] = port; + m_af[index] = addr.ss_family; + m_fd[index] = fd; + + if (port > 0U) { int reuse = 1; - if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { + if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { #if defined(_WIN32) || defined(_WIN64) - ::fprintf(stderr, "Cannot set the UDP socket option, err: %lu\n", ::GetLastError()); + LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError()); #else - ::fprintf(stderr, "Cannot set the UDP socket option, err: %d\n", errno); + LogError("Cannot set the UDP socket option, err: %d", errno); #endif return false; } - if (::bind(m_fd, (sockaddr*)&addr, addrlen) == -1) { + if (::bind(fd, (sockaddr*)&addr, addrlen) == -1) { #if defined(_WIN32) || defined(_WIN64) - ::fprintf(stderr, "Cannot bind the UDP address, err: %lu\n", ::GetLastError()); + LogError("Cannot bind the UDP address, err: %lu", ::GetLastError()); #else - ::fprintf(stderr, "Cannot bind the UDP address, err: %d\n", errno); + LogError("Cannot bind the UDP address, err: %d", errno); #endif return false; } - ::fprintf(stdout, "Opening UDP port on %u\n", m_port); + LogInfo("Opening UDP port on %u", port); } return true; @@ -191,30 +232,43 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag assert(length > 0U); // Check that the readfrom() won't block - fd_set readFds; - FD_ZERO(&readFds); -#if defined(_WIN32) || defined(_WIN64) - FD_SET((unsigned int)m_fd, &readFds); -#else - FD_SET(m_fd, &readFds); -#endif + int i, n; + struct pollfd pfd[UDP_SOCKET_MAX]; + for (i = n = 0; i < UDP_SOCKET_MAX; i++) { + if (m_fd[i] >= 0) { + pfd[n].fd = m_fd[i]; + pfd[n].events = POLLIN; + n++; + } + } + + // no socket descriptor to receive + if (n == 0) + return 0; // Return immediately - timeval tv; - tv.tv_sec = 0L; - tv.tv_usec = 0L; - - int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv); +#if defined(_WIN32) || defined(_WIN64) + int ret = WSAPoll(pfd, n, 0); +#else + int ret = ::poll(pfd, n, 0); +#endif if (ret < 0) { #if defined(_WIN32) || defined(_WIN64) - ::fprintf(stderr, "Error returned from UDP select, err: %lu\n", ::GetLastError()); + LogError("Error returned from UDP poll, err: %lu", ::GetLastError()); #else - ::fprintf(stderr, "Error returned from UDP select, err: %d\n", errno); + LogError("Error returned from UDP poll, err: %d", errno); #endif return -1; } - if (ret == 0) + int index; + for (i = 0; i < n; i++) { + // round robin + index = (i + m_counter) % n; + if (pfd[index].revents & POLLIN) + break; + } + if (i == n) return 0; #if defined(_WIN32) || defined(_WIN64) @@ -224,19 +278,20 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag #endif #if defined(_WIN32) || defined(_WIN64) - int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); + int len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); #else - ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); + ssize_t len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); #endif if (len <= 0) { #if defined(_WIN32) || defined(_WIN64) - ::fprintf(stderr, "Error returned from recvfrom, err: %lu\n", ::GetLastError()); + LogError("Error returned from recvfrom, err: %lu", ::GetLastError()); #else - ::fprintf(stderr, "Error returned from recvfrom, err: %d\n", errno); + LogError("Error returned from recvfrom, err: %d", errno); #endif return -1; } + m_counter++; address_length = size; return len; } @@ -246,36 +301,52 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const s assert(buffer != NULL); assert(length > 0U); + bool result = false; + + for (int i = 0; i < UDP_SOCKET_MAX; i++) { + if (m_fd[i] < 0 || m_af[i] != address.ss_family) + continue; + #if defined(_WIN32) || defined(_WIN64) - int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, address_length); + int ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length); #else - ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, address_length); + ssize_t ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length); #endif - if (ret < 0) { + + if (ret < 0) { #if defined(_WIN32) || defined(_WIN64) - ::fprintf(stderr, "Error returned from sendto, err: %lu\n", ::GetLastError()); + LogError("Error returned from sendto, err: %lu", ::GetLastError()); #else - ::fprintf(stderr, "Error returned from sendto, err: %d\n", errno); + LogError("Error returned from sendto, err: %d", errno); #endif - return false; + } else { +#if defined(_WIN32) || defined(_WIN64) + if (ret == int(length)) + result = true; +#else + if (ret == ssize_t(length)) + result = true; +#endif + } } -#if defined(_WIN32) || defined(_WIN64) - if (ret != int(length)) - return false; -#else - if (ret != ssize_t(length)) - return false; -#endif - - return true; + return result; } void CUDPSocket::close() { -#if defined(_WIN32) || defined(_WIN64) - ::closesocket(m_fd); -#else - ::close(m_fd); -#endif + for (int i = 0; i < UDP_SOCKET_MAX; i++) + close(m_fd[i]); +} + +void CUDPSocket::close(const unsigned int index) +{ + if (m_fd[index] >= 0) { +#if defined(_WIN32) || defined(_WIN64) + ::closesocket(m_fd[index]); +#else + ::close(m_fd[index]); +#endif + m_fd[index] = -1; + } } diff --git a/NXDNParrot/UDPSocket.h b/NXDNParrot/UDPSocket.h index 46b2370..b22eefc 100644 --- a/NXDNParrot/UDPSocket.h +++ b/NXDNParrot/UDPSocket.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009-2011,2013,2015,2016 by Jonathan Naylor G4KLX + * 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 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -35,29 +36,45 @@ #include #endif +#if !defined(UDP_SOCKET_MAX) +#define UDP_SOCKET_MAX 1 +#endif + +enum IPMATCHTYPE { + IMT_ADDRESS_AND_PORT, + IMT_ADDRESS_ONLY +}; + class CUDPSocket { public: CUDPSocket(const std::string& address, unsigned int port = 0U); CUDPSocket(unsigned int port = 0U); ~CUDPSocket(); - bool open(); - bool open(const unsigned int af); + bool open(unsigned int af = AF_UNSPEC); + bool open(const sockaddr_storage& address); + bool open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port); int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length); bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length); void close(); + void close(const unsigned int index); - static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage &address, unsigned int &address_length); - static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage &address, unsigned int &address_length, struct addrinfo &hints); - static bool match(const sockaddr_storage &addr1, const sockaddr_storage &addr2); - static bool isnone(const sockaddr_storage &addr); + static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length); + static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length, struct addrinfo& hints); + static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IMT_ADDRESS_AND_PORT); + + static bool isNone(const sockaddr_storage& addr); private: - std::string m_address; - unsigned short m_port; - int m_fd; + std::string m_address_save; + unsigned short m_port_save; + std::string m_address[UDP_SOCKET_MAX]; + unsigned short m_port[UDP_SOCKET_MAX]; + unsigned int m_af[UDP_SOCKET_MAX]; + int m_fd[UDP_SOCKET_MAX]; + unsigned int m_counter; }; #endif diff --git a/NXDNParrot/Version.h b/NXDNParrot/Version.h index dbd230c..8d2d1c1 100644 --- a/NXDNParrot/Version.h +++ b/NXDNParrot/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200903"; +const char* VERSION = "20200906"; #endif diff --git a/NXDNReflector/IcomNetwork.cpp b/NXDNReflector/IcomNetwork.cpp index 609e4f8..93a1ceb 100644 --- a/NXDNReflector/IcomNetwork.cpp +++ b/NXDNReflector/IcomNetwork.cpp @@ -31,12 +31,13 @@ const unsigned int ICOM_PORT = 41300U; CIcomNetwork::CIcomNetwork(const std::string& address, bool debug) : m_socket(ICOM_PORT), m_addr(), -m_addrLen(), +m_addrLen(0U), m_debug(debug) { assert(!address.empty()); - CUDPSocket::lookup(address, ICOM_PORT, m_addr, m_addrLen); + if (CUDPSocket::lookup(address, ICOM_PORT, m_addr, m_addrLen) != 0) + m_addrLen = 0U; } CIcomNetwork::~CIcomNetwork() @@ -45,9 +46,14 @@ CIcomNetwork::~CIcomNetwork() bool CIcomNetwork::open() { + if (m_addrLen == 0U) { + LogError("Unable to resolve the address of the Icom network"); + return false; + } + LogMessage("Opening Icom network connection"); - return m_socket.open(); + return m_socket.open(m_addr); } bool CIcomNetwork::write(const unsigned char* data, unsigned int len) diff --git a/NXDNReflector/IcomNetwork.h b/NXDNReflector/IcomNetwork.h index fccc06c..60d2f4d 100644 --- a/NXDNReflector/IcomNetwork.h +++ b/NXDNReflector/IcomNetwork.h @@ -38,7 +38,7 @@ public: void close(); - void clock(unsigned int ms); + void clock(unsigned int ms); private: CUDPSocket m_socket; diff --git a/NXDNReflector/KenwoodNetwork.cpp b/NXDNReflector/KenwoodNetwork.cpp index e634014..2ae3cf9 100644 --- a/NXDNReflector/KenwoodNetwork.cpp +++ b/NXDNReflector/KenwoodNetwork.cpp @@ -40,9 +40,9 @@ CKenwoodNetwork::CKenwoodNetwork(const std::string& address, bool debug) : m_rtpSocket(RTP_PORT), m_rtcpSocket(RTCP_PORT), m_rtpAddr(), -m_rtpAddrLen(), +m_rtpAddrLen(0U), m_rtcpAddr(), -m_rtcpAddrLen(), +m_rtcpAddrLen(0U), m_headerSeen(false), m_seen1(false), m_seen2(false), @@ -66,8 +66,11 @@ m_random() m_sacch = new unsigned char[10U]; - CUDPSocket::lookup(address, RTP_PORT, m_rtpAddr, m_rtpAddrLen); - CUDPSocket::lookup(address, RTCP_PORT, m_rtcpAddr, m_rtcpAddrLen); + if (CUDPSocket::lookup(address, RTP_PORT, m_rtpAddr, m_rtpAddrLen) != 0) + m_rtpAddrLen = 0U; + + if (CUDPSocket::lookup(address, RTCP_PORT, m_rtcpAddr, m_rtcpAddrLen) != 0) + m_rtcpAddrLen = 0U; std::random_device rd; std::mt19937 mt(rd()); @@ -81,12 +84,17 @@ CKenwoodNetwork::~CKenwoodNetwork() bool CKenwoodNetwork::open() { + if (m_rtpAddrLen == 0U || m_rtcpAddrLen == 0U) { + LogError("Unable to resolve the address of the Kenwood network"); + return false; + } + LogMessage("Opening Kenwood connection"); - if (!m_rtcpSocket.open()) + if (!m_rtcpSocket.open(m_rtcpAddr)) return false; - if (!m_rtpSocket.open()) { + if (!m_rtpSocket.open(m_rtpAddr)) { m_rtcpSocket.close(); return false; } @@ -560,7 +568,7 @@ unsigned int CKenwoodNetwork::readRTP(unsigned char* data) return 0U; // Check if the data is for us - if (!CUDPSocket::match(m_rtpAddr, addr)) { + if (!CUDPSocket::match(m_rtpAddr, addr, IMT_ADDRESS_ONLY)) { LogMessage("Kenwood RTP packet received from an invalid source"); return 0U; } @@ -586,7 +594,7 @@ unsigned int CKenwoodNetwork::readRTCP(unsigned char* data) return 0U; // Check if the data is for us - if (!CUDPSocket::match(m_rtcpAddr, addr)) { + if (!CUDPSocket::match(m_rtcpAddr, addr, IMT_ADDRESS_ONLY)) { LogMessage("Kenwood RTCP packet received from an invalid source"); return 0U; } diff --git a/NXDNReflector/KenwoodNetwork.h b/NXDNReflector/KenwoodNetwork.h index 54cf2c1..a981fea 100644 --- a/NXDNReflector/KenwoodNetwork.h +++ b/NXDNReflector/KenwoodNetwork.h @@ -39,7 +39,7 @@ public: void close(); - void clock(unsigned int ms); + void clock(unsigned int ms); private: CUDPSocket m_rtpSocket; diff --git a/NXDNReflector/Makefile b/NXDNReflector/Makefile index c1145eb..33ed070 100644 --- a/NXDNReflector/Makefile +++ b/NXDNReflector/Makefile @@ -1,6 +1,6 @@ -CC = gcc -CXX = g++ -CFLAGS = -g -O3 -Wall -std=c++0x -pthread +CC = cc +CXX = c++ +CFLAGS = -g -O3 -Wall -DHAVE_LOG_H -std=c++0x -pthread LIBS = -lpthread LDFLAGS = -g @@ -19,4 +19,4 @@ install: clean: $(RM) NXDNReflector *.o *.d *.bak *~ - \ No newline at end of file + diff --git a/NXDNReflector/UDPSocket.cpp b/NXDNReflector/UDPSocket.cpp index 659d816..382925f 100644 --- a/NXDNReflector/UDPSocket.cpp +++ b/NXDNReflector/UDPSocket.cpp @@ -17,7 +17,6 @@ */ #include "UDPSocket.h" -#include "Log.h" #include @@ -26,26 +25,36 @@ #include #endif +#if defined(HAVE_LOG_H) +#include "Log.h" +#else +#define LogError(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__) +#define LogInfo(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__) +#endif CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) : -m_address(address), -m_port(port), -m_fd(-1) +m_address_save(address), +m_port_save(port), +m_counter(0U) { - assert(!address.empty()); - #if defined(_WIN32) || defined(_WIN64) WSAData data; int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); if (wsaRet != 0) LogError("Error from WSAStartup"); #endif + for (int i = 0; i < UDP_SOCKET_MAX; i++) { + m_address[i] = ""; + m_port[i] = 0U; + m_af[i] = 0U; + m_fd[i] = -1; + } } CUDPSocket::CUDPSocket(unsigned int port) : -m_address(), -m_port(port), -m_fd(-1) +m_address_save(), +m_port_save(port), +m_counter(0U) { #if defined(_WIN32) || defined(_WIN64) WSAData data; @@ -53,6 +62,12 @@ m_fd(-1) if (wsaRet != 0) LogError("Error from WSAStartup"); #endif + for (int i = 0; i < UDP_SOCKET_MAX; i++) { + m_address[i] = ""; + m_port[i] = 0U; + m_af[i] = 0U; + m_fd[i] = -1; + } } CUDPSocket::~CUDPSocket() @@ -96,58 +111,82 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_ return 0; } -bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& addr2) +bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type) { if (addr1.ss_family != addr2.ss_family) return false; - 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: + 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; } } -bool CUDPSocket::isnone(const sockaddr_storage& addr) +bool CUDPSocket::isNone(const sockaddr_storage& addr) { struct sockaddr_in *in = (struct sockaddr_in *)&addr; return ((addr.ss_family == AF_INET) && (in->sin_addr.s_addr == htonl(INADDR_NONE))); } -bool CUDPSocket::open() +bool CUDPSocket::open(const sockaddr_storage& address) { - return open(AF_UNSPEC); + return open(address.ss_family); } -bool CUDPSocket::open(const unsigned int af) +bool CUDPSocket::open(unsigned int af) +{ + return open(0, af, m_address_save, m_port_save); +} + +bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port) { sockaddr_storage addr; unsigned int addrlen; struct addrinfo hints; ::memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_PASSIVE; + hints.ai_flags = AI_PASSIVE; hints.ai_family = af; /* to determine protocol family, call lookup() first. */ - int err = lookup(m_address, m_port, addr, addrlen, hints); + int err = lookup(address, port, addr, addrlen, hints); if (err != 0) { - LogError("The local address is invalid - %s", m_address.c_str()); + LogError("The local address is invalid - %s", address.c_str()); return false; } - m_fd = ::socket(addr.ss_family, SOCK_DGRAM, 0); - if (m_fd < 0) { + int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0); + if (fd < 0) { #if defined(_WIN32) || defined(_WIN64) LogError("Cannot create the UDP socket, err: %lu", ::GetLastError()); #else @@ -156,9 +195,14 @@ bool CUDPSocket::open(const unsigned int af) return false; } - if (m_port > 0U) { + m_address[index] = address; + m_port[index] = port; + m_af[index] = addr.ss_family; + m_fd[index] = fd; + + if (port > 0U) { int reuse = 1; - if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { + if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) { #if defined(_WIN32) || defined(_WIN64) LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError()); #else @@ -167,7 +211,7 @@ bool CUDPSocket::open(const unsigned int af) return false; } - if (::bind(m_fd, (sockaddr*)&addr, addrlen) == -1) { + if (::bind(fd, (sockaddr*)&addr, addrlen) == -1) { #if defined(_WIN32) || defined(_WIN64) LogError("Cannot bind the UDP address, err: %lu", ::GetLastError()); #else @@ -176,7 +220,7 @@ bool CUDPSocket::open(const unsigned int af) return false; } - LogInfo("Opening UDP port on %u", m_port); + LogInfo("Opening UDP port on %u", port); } return true; @@ -188,30 +232,43 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag assert(length > 0U); // Check that the readfrom() won't block - fd_set readFds; - FD_ZERO(&readFds); -#if defined(_WIN32) || defined(_WIN64) - FD_SET((unsigned int)m_fd, &readFds); -#else - FD_SET(m_fd, &readFds); -#endif + int i, n; + struct pollfd pfd[UDP_SOCKET_MAX]; + for (i = n = 0; i < UDP_SOCKET_MAX; i++) { + if (m_fd[i] >= 0) { + pfd[n].fd = m_fd[i]; + pfd[n].events = POLLIN; + n++; + } + } + + // no socket descriptor to receive + if (n == 0) + return 0; // Return immediately - timeval tv; - tv.tv_sec = 0L; - tv.tv_usec = 0L; - - int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv); +#if defined(_WIN32) || defined(_WIN64) + int ret = WSAPoll(pfd, n, 0); +#else + int ret = ::poll(pfd, n, 0); +#endif if (ret < 0) { #if defined(_WIN32) || defined(_WIN64) - LogError("Error returned from UDP select, err: %lu", ::GetLastError()); + LogError("Error returned from UDP poll, err: %lu", ::GetLastError()); #else - LogError("Error returned from UDP select, err: %d", errno); + LogError("Error returned from UDP poll, err: %d", errno); #endif return -1; } - if (ret == 0) + int index; + for (i = 0; i < n; i++) { + // round robin + index = (i + m_counter) % n; + if (pfd[index].revents & POLLIN) + break; + } + if (i == n) return 0; #if defined(_WIN32) || defined(_WIN64) @@ -221,9 +278,9 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag #endif #if defined(_WIN32) || defined(_WIN64) - int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); + int len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); #else - ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); + ssize_t len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size); #endif if (len <= 0) { #if defined(_WIN32) || defined(_WIN64) @@ -234,6 +291,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag return -1; } + m_counter++; address_length = size; return len; } @@ -243,36 +301,52 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const s assert(buffer != NULL); assert(length > 0U); + bool result = false; + + for (int i = 0; i < UDP_SOCKET_MAX; i++) { + if (m_fd[i] < 0 || m_af[i] != address.ss_family) + continue; + #if defined(_WIN32) || defined(_WIN64) - int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, address_length); + int ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length); #else - ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, address_length); + ssize_t ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length); #endif - if (ret < 0) { + + if (ret < 0) { #if defined(_WIN32) || defined(_WIN64) - LogError("Error returned from sendto, err: %lu", ::GetLastError()); + LogError("Error returned from sendto, err: %lu", ::GetLastError()); #else - LogError("Error returned from sendto, err: %d", errno); + LogError("Error returned from sendto, err: %d", errno); #endif - return false; + } else { +#if defined(_WIN32) || defined(_WIN64) + if (ret == int(length)) + result = true; +#else + if (ret == ssize_t(length)) + result = true; +#endif + } } -#if defined(_WIN32) || defined(_WIN64) - if (ret != int(length)) - return false; -#else - if (ret != ssize_t(length)) - return false; -#endif - - return true; + return result; } void CUDPSocket::close() { -#if defined(_WIN32) || defined(_WIN64) - ::closesocket(m_fd); -#else - ::close(m_fd); -#endif + for (int i = 0; i < UDP_SOCKET_MAX; i++) + close(m_fd[i]); +} + +void CUDPSocket::close(const unsigned int index) +{ + if (m_fd[index] >= 0) { +#if defined(_WIN32) || defined(_WIN64) + ::closesocket(m_fd[index]); +#else + ::close(m_fd[index]); +#endif + m_fd[index] = -1; + } } diff --git a/NXDNReflector/UDPSocket.h b/NXDNReflector/UDPSocket.h index 386f059..b22eefc 100644 --- a/NXDNReflector/UDPSocket.h +++ b/NXDNReflector/UDPSocket.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -35,29 +36,45 @@ #include #endif +#if !defined(UDP_SOCKET_MAX) +#define UDP_SOCKET_MAX 1 +#endif + +enum IPMATCHTYPE { + IMT_ADDRESS_AND_PORT, + IMT_ADDRESS_ONLY +}; + class CUDPSocket { public: CUDPSocket(const std::string& address, unsigned int port = 0U); CUDPSocket(unsigned int port = 0U); ~CUDPSocket(); - bool open(); - bool open(const unsigned int af); + bool open(unsigned int af = AF_UNSPEC); + bool open(const sockaddr_storage& address); + bool open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port); int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length); bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length); void close(); + void close(const unsigned int index); static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length); static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length, struct addrinfo& hints); - static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2); - static bool isnone(const sockaddr_storage& addr); + static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IMT_ADDRESS_AND_PORT); + + static bool isNone(const sockaddr_storage& addr); private: - std::string m_address; - unsigned short m_port; - int m_fd; + std::string m_address_save; + unsigned short m_port_save; + std::string m_address[UDP_SOCKET_MAX]; + unsigned short m_port[UDP_SOCKET_MAX]; + unsigned int m_af[UDP_SOCKET_MAX]; + int m_fd[UDP_SOCKET_MAX]; + unsigned int m_counter; }; #endif diff --git a/NXDNReflector/Version.h b/NXDNReflector/Version.h index 2649064..9ce9715 100644 --- a/NXDNReflector/Version.h +++ b/NXDNReflector/Version.h @@ -19,6 +19,6 @@ #if !defined(VERSION_H) #define VERSION_H -const char* VERSION = "20200903"; +const char* VERSION = "20200906"; #endif