diff --git a/Log.cpp b/Log.cpp index c0ce9177..4f816c4e 100644 --- a/Log.cpp +++ b/Log.cpp @@ -32,7 +32,8 @@ #include "network/Network.h" #if defined(_WIN32) || defined(_WIN64) -#include +#define WIN32_LEAN_AND_MEAN +#include #else #include #endif diff --git a/Mutex.h b/Mutex.h index 28cc71b1..b57d33c4 100644 --- a/Mutex.h +++ b/Mutex.h @@ -33,6 +33,7 @@ #include "Defines.h" #if defined(_WIN32) || defined(_WIN64) +#define WIN32_LEAN_AND_MEAN #include #else #include diff --git a/StopWatch.h b/StopWatch.h index 44d7d83a..3e2262c0 100644 --- a/StopWatch.h +++ b/StopWatch.h @@ -33,6 +33,7 @@ #include "Defines.h" #if defined(_WIN32) || defined(_WIN64) +#define WIN32_LEAN_AND_MEAN #include #else #include diff --git a/Thread.h b/Thread.h index 09e6848e..a9f20b8a 100644 --- a/Thread.h +++ b/Thread.h @@ -33,6 +33,7 @@ #include "Defines.h" #if defined(_WIN32) || defined(_WIN64) +#define WIN32_LEAN_AND_MEAN #include #else #include diff --git a/host/Host.cpp b/host/Host.cpp index 119cbeaa..f086e118 100644 --- a/host/Host.cpp +++ b/host/Host.cpp @@ -32,6 +32,7 @@ #include "dmr/Control.h" #include "p25/Control.h" #include "modem/SerialController.h" +#include "network/UDPSocket.h" #include "lookups/RSSIInterpolator.h" #include "host/Host.h" #include "HostMain.h" @@ -97,7 +98,7 @@ Host::Host(const std::string& confFile) : m_tidLookup(NULL), m_remoteControl(NULL) { - /* stub */ + UDPSocket::startup(); } /// @@ -105,7 +106,7 @@ Host::Host(const std::string& confFile) : /// Host::~Host() { - /* stub */ + UDPSocket::shutdown(); } /// diff --git a/modem/Modem.cpp b/modem/Modem.cpp index 9e153686..370cd343 100644 --- a/modem/Modem.cpp +++ b/modem/Modem.cpp @@ -46,7 +46,8 @@ using namespace modem; #include #if defined(_WIN32) || defined(_WIN64) -#include +#define WIN32_LEAN_AND_MEAN +#include #else #include #endif diff --git a/modem/SerialController.h b/modem/SerialController.h index d1981aea..e6802fb8 100644 --- a/modem/SerialController.h +++ b/modem/SerialController.h @@ -37,6 +37,7 @@ #include #if defined(_WIN32) || defined(_WIN64) +#define WIN32_LEAN_AND_MEAN #include #endif diff --git a/network/BaseNetwork.cpp b/network/BaseNetwork.cpp index 0b6f8649..8576a723 100644 --- a/network/BaseNetwork.cpp +++ b/network/BaseNetwork.cpp @@ -62,6 +62,8 @@ BaseNetwork::BaseNetwork(uint32_t localPort, uint32_t id, bool duplex, bool debu m_allowDiagnosticTransfer(allowDiagnosticTransfer), m_duplex(duplex), m_debug(debug), + m_addr(), + m_addrLen(0U), m_socket(localPort), m_status(NET_STAT_INVALID), m_retryTimer(1000U, 10U), @@ -948,19 +950,16 @@ bool BaseNetwork::writeP25PDU(const uint32_t id, const uint32_t streamId, const /// /// Buffer to write to the network. /// Length of buffer to write. -/// IP address to write data to. -/// Port number for remote UDP socket. /// True, if buffer is written to the network, otherwise false. -bool BaseNetwork::write(const uint8_t* data, uint32_t length, const in_addr& address, uint32_t port) +bool BaseNetwork::write(const uint8_t* data, uint32_t length) { assert(data != NULL); assert(length > 0U); - assert(port > 0U); // if (m_debug) // Utils::dump(1U, "Network Transmitted", data, length); - bool ret = m_socket.write(data, length, address, port); + bool ret = m_socket.write(data, length, m_addr, m_addrLen); if (!ret) { LogError(LOG_NET, "Socket has failed when writing data to the peer, retrying connection"); return false; diff --git a/network/BaseNetwork.h b/network/BaseNetwork.h index ba5dd776..cb4bc028 100644 --- a/network/BaseNetwork.h +++ b/network/BaseNetwork.h @@ -247,6 +247,8 @@ namespace network bool m_duplex; bool m_debug; + sockaddr_storage m_addr; + unsigned int m_addrLen; UDPSocket m_socket; NET_CONN_STATUS m_status; @@ -280,9 +282,7 @@ namespace network bool writeP25PDU(const uint32_t id, const uint32_t streamId, const uint32_t llId, const uint8_t dataType, const uint8_t* data, const uint32_t len); /// Writes data to the network. - virtual bool write(const uint8_t* data, uint32_t length) = 0; - /// Writes data to the network. - virtual bool write(const uint8_t* data, uint32_t length, const in_addr& address, uint32_t port); + virtual bool write(const uint8_t* data, uint32_t length); }; } // namespace network diff --git a/network/Network.cpp b/network/Network.cpp index 0ebee0e6..34e20331 100644 --- a/network/Network.cpp +++ b/network/Network.cpp @@ -61,8 +61,7 @@ using namespace network; Network::Network(const std::string& address, uint32_t port, uint32_t local, uint32_t id, const std::string& password, bool duplex, bool debug, bool slot1, bool slot2, bool allowActivityTransfer, bool allowDiagnosticTransfer, bool updateLookup) : BaseNetwork(local, id, duplex, debug, slot1, slot2, allowActivityTransfer, allowDiagnosticTransfer), - m_addressStr(address), - m_address(), + m_address(address), m_port(port), m_password(password), m_enabled(false), @@ -85,8 +84,6 @@ Network::Network(const std::string& address, uint32_t port, uint32_t local, uint assert(!address.empty()); assert(port > 0U); assert(!password.empty()); - - m_address = UDPSocket::lookup(address); } /// @@ -171,7 +168,7 @@ void Network::clock(uint32_t ms) if (m_status == NET_STAT_WAITING_CONNECT) { m_retryTimer.clock(ms); if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) { - bool ret = m_socket.open(); + bool ret = m_socket.open(m_addr.ss_family); if (ret) { ret = writeLogin(); if (!ret) @@ -187,9 +184,9 @@ void Network::clock(uint32_t ms) return; } - in_addr address; - uint32_t port; - int length = m_socket.read(m_buffer, DATA_PACKET_LENGTH, address, port); + sockaddr_storage address; + unsigned int addrLen; + int length = m_socket.read(m_buffer, DATA_PACKET_LENGTH, address, addrLen); if (length < 0) { LogError(LOG_NET, "Socket has failed, retrying connection to the master"); close(); @@ -200,7 +197,12 @@ void Network::clock(uint32_t ms) if (m_debug && length > 0) Utils::dump(1U, "Network Received", m_buffer, length); - if (length > 0 && m_address.s_addr == address.s_addr && m_port == port) { + if (length > 0) { + if (!UDPSocket::match(m_addr, address)) { + LogError(LOG_NET, "Packet received from an invalid source"); + return; + } + if (::memcmp(m_buffer, TAG_DMR_DATA, 4U) == 0) { if (m_enabled) { if (m_debug) @@ -388,8 +390,9 @@ bool Network::open() if (m_debug) LogMessage(LOG_NET, "Opening Network"); - if (m_address.s_addr == INADDR_NONE) { - m_address = UDPSocket::lookup(m_addressStr); + if (UDPSocket::lookup(m_address, m_port, m_addr, m_addrLen) != 0) { + LogMessage(LOG_NET, "Could not lookup the address of the master"); + return false; } m_status = NET_STAT_WAITING_CONNECT; @@ -545,17 +548,3 @@ bool Network::writePing() return write(buffer, 11U); } - -/// -/// Writes data to the network. -/// -/// Buffer to write to the network. -/// Length of buffer to write. -/// True, if buffer is written to the network, otherwise false. -bool Network::write(const uint8_t* data, uint32_t length) -{ - assert(data != NULL); - assert(length > 0U); - - return BaseNetwork::write(data, length, m_address, m_port); -} diff --git a/network/Network.h b/network/Network.h index ae243e76..b737d14e 100644 --- a/network/Network.h +++ b/network/Network.h @@ -77,9 +77,8 @@ namespace network void close(); private: - std::string m_addressStr; - in_addr m_address; - uint32_t m_port; + std::string m_address; + unsigned int m_port; std::string m_password; @@ -117,9 +116,6 @@ namespace network bool writeConfig(); /// Writes a network stay-alive ping. bool writePing(); - - /// Writes data to the network. - bool write(const uint8_t* data, uint32_t length); }; } // namespace network diff --git a/network/RemoteControl.cpp b/network/RemoteControl.cpp index 085a969f..d5326fd6 100644 --- a/network/RemoteControl.cpp +++ b/network/RemoteControl.cpp @@ -164,10 +164,10 @@ void RemoteControl::process(Host* host, dmr::Control* dmr, p25::Control* p25) args.clear(); uint8_t buffer[RC_BUFFER_LENGTH]; - in_addr address; - uint32_t port; - uint32_t ret = m_socket.read((uint8_t*)buffer, RC_BUFFER_LENGTH, address, port); + sockaddr_storage address; + unsigned int addrLen; + uint32_t ret = m_socket.read((uint8_t*)buffer, RC_BUFFER_LENGTH, address, addrLen); if (ret > 0U) { buffer[ret] = '\0'; diff --git a/network/UDPSocket.cpp b/network/UDPSocket.cpp index 96d830cd..dcaa501a 100644 --- a/network/UDPSocket.cpp +++ b/network/UDPSocket.cpp @@ -11,7 +11,7 @@ // Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) // /* -* Copyright (C) 2006-2016 by Jonathan Naylor G4KLX +* Copyright (C) 2006-2016,2020 by Jonathan Naylor G4KLX * Copyright (C) 2017-2020 by Bryan Biedenkapp N2PLL * * This program is free software; you can redistribute it and/or modify @@ -32,8 +32,6 @@ #include "network/UDPSocket.h" #include "Log.h" -using namespace network; - #include #if !defined(_WIN32) && !defined(_WIN64) @@ -41,6 +39,8 @@ using namespace network; #include #endif +using namespace network; + // --------------------------------------------------------------------------- // Public Class Members // --------------------------------------------------------------------------- @@ -49,35 +49,34 @@ using namespace network; /// /// Hostname/IP address to connect to. /// Port number. -UDPSocket::UDPSocket(const std::string& address, uint32_t port) : - m_address(address), - m_port(port), - m_fd(-1) +UDPSocket::UDPSocket(const std::string& address, unsigned int port) : + 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(LOG_NET, "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; + } } /// /// Initializes a new instance of the UDPSocket class. /// /// Port number. -UDPSocket::UDPSocket(uint32_t port) : - m_address(), - m_port(port), - m_fd(-1) +UDPSocket::UDPSocket(unsigned int port) : + 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) - LogError(LOG_NET, "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; + } } /// @@ -85,19 +84,58 @@ UDPSocket::UDPSocket(uint32_t port) : /// UDPSocket::~UDPSocket() { -#if defined(_WIN32) || defined(_WIN64) - ::WSACleanup(); -#endif + /* stub */ +} + +/// +/// Opens UDP socket connection. +/// +/// +/// True, if UDP socket is opened, otherwise false. +bool UDPSocket::open(const sockaddr_storage& address) +{ + return open(address.ss_family); +} + +/// +/// Opens UDP socket connection. +/// +/// +/// True, if UDP socket is opened, otherwise false. +bool UDPSocket::open(unsigned int af) +{ + return open(0, af, m_address_save, m_port_save); } /// /// Opens UDP socket connection. /// +/// +/// +/// +/// /// True, if UDP socket is opened, otherwise false. -bool UDPSocket::open() +bool UDPSocket::open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port) { - m_fd = ::socket(PF_INET, SOCK_DGRAM, 0); - if (m_fd < 0) { + sockaddr_storage addr; + unsigned int addrlen; + struct addrinfo hints; + + ::memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_PASSIVE; + hints.ai_family = af; + + /* to determine protocol family, call lookup() first. */ + int err = lookup(address, port, addr, addrlen, hints); + if (err != 0) { + LogError(LOG_NET, "The local address is invalid - %s", address.c_str()); + return false; + } + + close(index); + + int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0); + if (fd < 0) { #if defined(_WIN32) || defined(_WIN64) LogError(LOG_NET, "Cannot create the UDP socket, err: %lu", ::GetLastError()); #else @@ -106,27 +144,14 @@ bool UDPSocket::open() return false; } - if (m_port > 0U) { - sockaddr_in addr; - ::memset(&addr, 0x00, sizeof(sockaddr_in)); - addr.sin_family = AF_INET; - addr.sin_port = htons(m_port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - if (!m_address.empty()) { -#if defined(_WIN32) || defined(_WIN64) - addr.sin_addr.s_addr = ::inet_addr(m_address.c_str()); -#else - addr.sin_addr.s_addr = ::inet_addr(m_address.c_str()); -#endif - if (addr.sin_addr.s_addr == INADDR_NONE) { - LogError(LOG_NET, "The local address is invalid - %s", m_address.c_str()); - return false; - } - } + 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(LOG_NET, "Cannot set the UDP socket option, err: %lu", ::GetLastError()); #else @@ -135,7 +160,7 @@ bool UDPSocket::open() return false; } - if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { + if (::bind(fd, (sockaddr*)& addr, addrlen) == -1) { #if defined(_WIN32) || defined(_WIN64) LogError(LOG_NET, "Cannot bind the UDP address, err: %lu", ::GetLastError()); #else @@ -143,6 +168,8 @@ bool UDPSocket::open() #endif return false; } + + LogInfo("Opening UDP port on %u", port); } return true; @@ -154,64 +181,81 @@ bool UDPSocket::open() /// Buffer to read data into. /// Length of data to read. /// IP address to read data from. -/// Port number for remote UDP socket. +/// /// Actual length of data read from remote UDP socket. -int UDPSocket::read(uint8_t* buffer, uint32_t length, in_addr& address, uint32_t& port) +int UDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int& addrLen) { assert(buffer != NULL); assert(length > 0U); // Check that the readfrom() won't block - fd_set readFds; - FD_ZERO(&readFds); + 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 #if defined(_WIN32) || defined(_WIN64) - FD_SET((uint32_t)m_fd, &readFds); + int ret = WSAPoll(pfd, n, 0); #else - FD_SET(m_fd, &readFds); + int ret = ::poll(pfd, n, 0); #endif - - // Return immediately - timeval tv; - tv.tv_sec = 0L; - tv.tv_usec = 0L; - - int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv); if (ret < 0) { #if defined(_WIN32) || defined(_WIN64) - LogError(LOG_NET, "Error returned from UDP select, err: %lu", ::GetLastError()); + LogError(LOG_NET, "Error returned from UDP poll, err: %lu", ::GetLastError()); #else - LogError(LOG_NET, "Error returned from UDP select, err: %d", errno); + LogError(LOG_NET, "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; - sockaddr_in addr; #if defined(_WIN32) || defined(_WIN64) - int size = sizeof(sockaddr_in); + int size = sizeof(sockaddr_storage); #else - socklen_t size = sizeof(sockaddr_in); + socklen_t size = sizeof(sockaddr_storage); #endif #if defined(_WIN32) || defined(_WIN64) - int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &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 *)&addr, &size); + ssize_t len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr*)& address, &size); #endif if (len <= 0) { #if defined(_WIN32) || defined(_WIN64) LogError(LOG_NET, "Error returned from recvfrom, err: %lu", ::GetLastError()); #else LogError(LOG_NET, "Error returned from recvfrom, err: %d", errno); + + if (len == -1 && errno == ENOTSOCK) { + LogMessage(LOG_NET, "Re-opening UDP port on %u", m_port); + close(); + open(); + } #endif return -1; } - address = addr.sin_addr; - port = ntohs(addr.sin_port); - + m_counter++; + addrLen = size; return len; } @@ -221,43 +265,44 @@ int UDPSocket::read(uint8_t* buffer, uint32_t length, in_addr& address, uint32_t /// Buffer containing data to write to socket. /// Length of data to write. /// IP address to write data to. -/// Port number for remote UDP socket. +/// /// Actual length of data written to remote UDP socket. -bool UDPSocket::write(const uint8_t* buffer, uint32_t length, const in_addr& address, uint32_t port) +bool UDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addrLen) { assert(buffer != NULL); assert(length > 0U); - sockaddr_in addr; - ::memset(&addr, 0x00, sizeof(sockaddr_in)); + bool result = false; - addr.sin_family = AF_INET; - addr.sin_addr = address; - addr.sin_port = htons(port); + 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 *)&addr, sizeof(sockaddr_in)); + int ret = ::sendto(m_fd[i], (char*)buffer, length, 0, (sockaddr*)& address, addrLen); #else - ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in)); + ssize_t ret = ::sendto(m_fd[i], (char*)buffer, length, 0, (sockaddr*)& address, addrLen); #endif - if (ret < 0) { + + if (ret < 0) { #if defined(_WIN32) || defined(_WIN64) - LogError(LOG_NET, "Error returned from sendto, err: %lu", ::GetLastError()); + LogError(LOG_NET, "Error returned from sendto, err: %lu", ::GetLastError()); #else - LogError(LOG_NET, "Error returned from sendto, err: %d", errno); + LogError(LOG_NET, "Error returned from sendto, err: %d", errno); #endif - return false; - } - + } + else { #if defined(_WIN32) || defined(_WIN64) - if (ret != int(length)) - return false; + if (ret == int(length)) + result = true; #else - if (ret != ssize_t(length)) - return false; + if (ret == ssize_t(length)) + result = true; #endif + } + } - return true; + return result; } /// @@ -265,54 +310,158 @@ bool UDPSocket::write(const uint8_t* buffer, uint32_t length, const in_addr& add /// void UDPSocket::close() { + for (int i = 0; i < UDP_SOCKET_MAX; i++) + close(i); +} + +/// +/// Closes the UDP socket connection. +/// +/// +void UDPSocket::close(const unsigned int index) +{ + if ((index < UDP_SOCKET_MAX) && (m_fd[index] >= 0)) { #if defined(_WIN32) || defined(_WIN64) - ::closesocket(m_fd); + ::closesocket(m_fd[index]); #else - ::close(m_fd); + ::close(m_fd[index]); #endif + m_fd[index] = -1; + } } /// -/// Helper to lookup a hostname and resolve it to an IP address. +/// /// -/// String containing hostname to resolve. -/// IP address structure for containing resolved hostname. -in_addr UDPSocket::lookup(const std::string& hostname) +void UDPSocket::startup() { - in_addr addr; #if defined(_WIN32) || defined(_WIN64) - unsigned long address = ::inet_addr(hostname.c_str()); - if (address != INADDR_NONE && address != INADDR_ANY) { - addr.s_addr = address; - return addr; + WSAData data; + int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); + if (wsaRet != 0) { + LogError(LOG_NET, "Error from WSAStartup"); } +#endif +} - struct hostent* hp = ::gethostbyname(hostname.c_str()); - if (hp != NULL) { - ::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr)); - return addr; - } +/// +/// +/// +void UDPSocket::shutdown() +{ +#if defined(_WIN32) || defined(_WIN64) + ::WSACleanup(); +#endif +} - LogError(LOG_NET, "Cannot find address for host %s", hostname.c_str()); +/// +/// Helper to lookup a hostname and resolve it to an IP address. +/// +/// String containing hostname to resolve. +/// Numeric port number of service to resolve. +/// Socket address structure. +/// +/// Zero if no error during lookup, otherwise error. +int UDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& addrLen) +{ + struct addrinfo hints; + ::memset(&hints, 0, sizeof(hints)); - addr.s_addr = INADDR_NONE; - return addr; -#else - in_addr_t address = ::inet_addr(hostname.c_str()); - if (address != in_addr_t(-1)) { - addr.s_addr = address; - return addr; + return lookup(hostname, port, addr, addrLen, hints); +} + +/// +/// Helper to lookup a hostname and resolve it to an IP address. +/// +/// String containing hostname to resolve. +/// Numeric port number of service to resolve. +/// Socket address structure. +/// +/// +/// Zero if no error during lookup, otherwise error. +int UDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& addrLen, struct addrinfo& hints) +{ + std::string portstr = std::to_string(port); + struct addrinfo* res; + + /* port is always digits, no needs to lookup service */ + hints.ai_flags |= AI_NUMERICSERV; + + 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, addrLen = sizeof(sockaddr_in)); + paddr->sin_family = AF_INET; + paddr->sin_port = htons(port); + paddr->sin_addr.s_addr = htonl(INADDR_NONE); + LogError("Cannot find address for host %s", hostname.c_str()); + return err; } - struct hostent* hp = ::gethostbyname(hostname.c_str()); - if (hp != NULL) { - ::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr)); - return addr; + ::memcpy(&addr, res->ai_addr, addrLen = res->ai_addrlen); + + freeaddrinfo(res); + + return 0; +} + +/// +/// +/// +/// +/// +/// +/// +bool UDPSocket::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; + } +} - LogError(LOG_NET, "Cannot find address for host %s", hostname.c_str()); +/// +/// +/// +/// +/// +bool UDPSocket::isNone(const sockaddr_storage& addr) +{ + struct sockaddr_in* in = (struct sockaddr_in*) & addr; - addr.s_addr = INADDR_NONE; - return addr; -#endif + return ((addr.ss_family == AF_INET) && (in->sin_addr.s_addr == htonl(INADDR_NONE))); } diff --git a/network/UDPSocket.h b/network/UDPSocket.h index 6aa9a2f7..980a7f64 100644 --- a/network/UDPSocket.h +++ b/network/UDPSocket.h @@ -11,7 +11,7 @@ // Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) // /* -* Copyright (C) 2009-2011,2013,2015,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 @@ -39,14 +39,25 @@ #include #include #include +#include #include #include #include #include #else -#include +#include +#include #endif +#if !defined(UDP_SOCKET_MAX) +#define UDP_SOCKET_MAX 1 +#endif + +enum IPMATCHTYPE { + IMT_ADDRESS_AND_PORT, + IMT_ADDRESS_ONLY +}; + namespace network { // --------------------------------------------------------------------------- @@ -58,31 +69,54 @@ namespace network class HOST_SW_API UDPSocket { public: /// Initializes a new instance of the UDPSocket class. - UDPSocket(const std::string& address, uint32_t port = 0U); + UDPSocket(const std::string& address, unsigned int port = 0U); + /// Initializes a new instance of the UDPSocket class. + UDPSocket(unsigned int port = 0U); /// Initializes a new instance of the UDPSocket class. - UDPSocket(uint32_t port = 0U); - /// Finalizes a instance of the UDPSocket class. ~UDPSocket(); /// Opens UDP socket connection. - bool open(); + bool open(unsigned int af = AF_UNSPEC); + /// Opens UDP socket connection. + bool open(const sockaddr_storage& address); + /// Opens UDP socket connection. + bool open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port); /// Read data from the UDP socket. - int read(uint8_t* buffer, uint32_t length, in_addr& address, uint32_t& port); + int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int& addrLen); /// Write data to the UDP socket. - bool write(const uint8_t* buffer, uint32_t length, const in_addr& address, uint32_t port); + bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addrLen); /// Closes the UDP socket connection. void close(); + /// Closes the UDP socket connection. + void close(const unsigned int index); + + /// + static void startup(); + /// + static void shutdown(); /// Helper to lookup a hostname and resolve it to an IP address. - static in_addr lookup(const std::string& hostName); + static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& addrLen); + /// Helper to lookup a hostname and resolve it to an IP address. + static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& addrLen, 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; - uint16_t 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; }; -} // namespace Net +} // namespace network #endif // __UDP_SOCKET_H__ diff --git a/p25/DataPacket.cpp b/p25/DataPacket.cpp index 07f68e36..715f778e 100644 --- a/p25/DataPacket.cpp +++ b/p25/DataPacket.cpp @@ -47,19 +47,6 @@ using namespace p25::data; #include #include -#if !defined(_WIN32) && !defined(_WIN64) -#include -#include -#include -#include -#include -#include -#include -#include -#else -#include -#endif - // --------------------------------------------------------------------------- // Public Class Members // ---------------------------------------------------------------------------