apply upstream updates to UDPSocket;

pull/1/head
Bryan Biedenkapp 5 years ago
parent 646217ac8d
commit 6640485dad

@ -32,7 +32,8 @@
#include "network/Network.h" #include "network/Network.h"
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#include <Windows.h> #define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else #else
#include <sys/time.h> #include <sys/time.h>
#endif #endif

@ -33,6 +33,7 @@
#include "Defines.h" #include "Defines.h"
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#else #else
#include <pthread.h> #include <pthread.h>

@ -33,6 +33,7 @@
#include "Defines.h" #include "Defines.h"
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#else #else
#include <sys/time.h> #include <sys/time.h>

@ -33,6 +33,7 @@
#include "Defines.h" #include "Defines.h"
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#else #else
#include <pthread.h> #include <pthread.h>

@ -32,6 +32,7 @@
#include "dmr/Control.h" #include "dmr/Control.h"
#include "p25/Control.h" #include "p25/Control.h"
#include "modem/SerialController.h" #include "modem/SerialController.h"
#include "network/UDPSocket.h"
#include "lookups/RSSIInterpolator.h" #include "lookups/RSSIInterpolator.h"
#include "host/Host.h" #include "host/Host.h"
#include "HostMain.h" #include "HostMain.h"
@ -97,7 +98,7 @@ Host::Host(const std::string& confFile) :
m_tidLookup(NULL), m_tidLookup(NULL),
m_remoteControl(NULL) m_remoteControl(NULL)
{ {
/* stub */ UDPSocket::startup();
} }
/// <summary> /// <summary>
@ -105,7 +106,7 @@ Host::Host(const std::string& confFile) :
/// </summary> /// </summary>
Host::~Host() Host::~Host()
{ {
/* stub */ UDPSocket::shutdown();
} }
/// <summary> /// <summary>

@ -46,7 +46,8 @@ using namespace modem;
#include <ctime> #include <ctime>
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#include <Windows.h> #define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else #else
#include <unistd.h> #include <unistd.h>
#endif #endif

@ -37,6 +37,7 @@
#include <string> #include <string>
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#endif #endif

@ -62,6 +62,8 @@ BaseNetwork::BaseNetwork(uint32_t localPort, uint32_t id, bool duplex, bool debu
m_allowDiagnosticTransfer(allowDiagnosticTransfer), m_allowDiagnosticTransfer(allowDiagnosticTransfer),
m_duplex(duplex), m_duplex(duplex),
m_debug(debug), m_debug(debug),
m_addr(),
m_addrLen(0U),
m_socket(localPort), m_socket(localPort),
m_status(NET_STAT_INVALID), m_status(NET_STAT_INVALID),
m_retryTimer(1000U, 10U), m_retryTimer(1000U, 10U),
@ -948,19 +950,16 @@ bool BaseNetwork::writeP25PDU(const uint32_t id, const uint32_t streamId, const
/// </summary> /// </summary>
/// <param name="buffer">Buffer to write to the network.</param> /// <param name="buffer">Buffer to write to the network.</param>
/// <param name="length">Length of buffer to write.</param> /// <param name="length">Length of buffer to write.</param>
/// <param name="address">IP address to write data to.</param>
/// <param name="port">Port number for remote UDP socket.</param>
/// <returns>True, if buffer is written to the network, otherwise false.</returns> /// <returns>True, if buffer is written to the network, otherwise false.</returns>
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(data != NULL);
assert(length > 0U); assert(length > 0U);
assert(port > 0U);
// if (m_debug) // if (m_debug)
// Utils::dump(1U, "Network Transmitted", data, length); // 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) { if (!ret) {
LogError(LOG_NET, "Socket has failed when writing data to the peer, retrying connection"); LogError(LOG_NET, "Socket has failed when writing data to the peer, retrying connection");
return false; return false;

@ -247,6 +247,8 @@ namespace network
bool m_duplex; bool m_duplex;
bool m_debug; bool m_debug;
sockaddr_storage m_addr;
unsigned int m_addrLen;
UDPSocket m_socket; UDPSocket m_socket;
NET_CONN_STATUS m_status; 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); 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);
/// <summary>Writes data to the network.</summary> /// <summary>Writes data to the network.</summary>
virtual bool write(const uint8_t* data, uint32_t length) = 0; virtual bool write(const uint8_t* data, uint32_t length);
/// <summary>Writes data to the network.</summary>
virtual bool write(const uint8_t* data, uint32_t length, const in_addr& address, uint32_t port);
}; };
} // namespace network } // namespace network

@ -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, 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) : bool duplex, bool debug, bool slot1, bool slot2, bool allowActivityTransfer, bool allowDiagnosticTransfer, bool updateLookup) :
BaseNetwork(local, id, duplex, debug, slot1, slot2, allowActivityTransfer, allowDiagnosticTransfer), BaseNetwork(local, id, duplex, debug, slot1, slot2, allowActivityTransfer, allowDiagnosticTransfer),
m_addressStr(address), m_address(address),
m_address(),
m_port(port), m_port(port),
m_password(password), m_password(password),
m_enabled(false), m_enabled(false),
@ -85,8 +84,6 @@ Network::Network(const std::string& address, uint32_t port, uint32_t local, uint
assert(!address.empty()); assert(!address.empty());
assert(port > 0U); assert(port > 0U);
assert(!password.empty()); assert(!password.empty());
m_address = UDPSocket::lookup(address);
} }
/// <summary> /// <summary>
@ -171,7 +168,7 @@ void Network::clock(uint32_t ms)
if (m_status == NET_STAT_WAITING_CONNECT) { if (m_status == NET_STAT_WAITING_CONNECT) {
m_retryTimer.clock(ms); m_retryTimer.clock(ms);
if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) { if (m_retryTimer.isRunning() && m_retryTimer.hasExpired()) {
bool ret = m_socket.open(); bool ret = m_socket.open(m_addr.ss_family);
if (ret) { if (ret) {
ret = writeLogin(); ret = writeLogin();
if (!ret) if (!ret)
@ -187,9 +184,9 @@ void Network::clock(uint32_t ms)
return; return;
} }
in_addr address; sockaddr_storage address;
uint32_t port; unsigned int addrLen;
int length = m_socket.read(m_buffer, DATA_PACKET_LENGTH, address, port); int length = m_socket.read(m_buffer, DATA_PACKET_LENGTH, address, addrLen);
if (length < 0) { if (length < 0) {
LogError(LOG_NET, "Socket has failed, retrying connection to the master"); LogError(LOG_NET, "Socket has failed, retrying connection to the master");
close(); close();
@ -200,7 +197,12 @@ void Network::clock(uint32_t ms)
if (m_debug && length > 0) if (m_debug && length > 0)
Utils::dump(1U, "Network Received", m_buffer, length); 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 (::memcmp(m_buffer, TAG_DMR_DATA, 4U) == 0) {
if (m_enabled) { if (m_enabled) {
if (m_debug) if (m_debug)
@ -388,8 +390,9 @@ bool Network::open()
if (m_debug) if (m_debug)
LogMessage(LOG_NET, "Opening Network"); LogMessage(LOG_NET, "Opening Network");
if (m_address.s_addr == INADDR_NONE) { if (UDPSocket::lookup(m_address, m_port, m_addr, m_addrLen) != 0) {
m_address = UDPSocket::lookup(m_addressStr); LogMessage(LOG_NET, "Could not lookup the address of the master");
return false;
} }
m_status = NET_STAT_WAITING_CONNECT; m_status = NET_STAT_WAITING_CONNECT;
@ -545,17 +548,3 @@ bool Network::writePing()
return write(buffer, 11U); return write(buffer, 11U);
} }
/// <summary>
/// Writes data to the network.
/// </summary>
/// <param name="data">Buffer to write to the network.</param>
/// <param name="length">Length of buffer to write.</param>
/// <returns>True, if buffer is written to the network, otherwise false.</returns>
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);
}

@ -77,9 +77,8 @@ namespace network
void close(); void close();
private: private:
std::string m_addressStr; std::string m_address;
in_addr m_address; unsigned int m_port;
uint32_t m_port;
std::string m_password; std::string m_password;
@ -117,9 +116,6 @@ namespace network
bool writeConfig(); bool writeConfig();
/// <summary>Writes a network stay-alive ping.</summary> /// <summary>Writes a network stay-alive ping.</summary>
bool writePing(); bool writePing();
/// <summary>Writes data to the network.</summary>
bool write(const uint8_t* data, uint32_t length);
}; };
} // namespace network } // namespace network

@ -164,10 +164,10 @@ void RemoteControl::process(Host* host, dmr::Control* dmr, p25::Control* p25)
args.clear(); args.clear();
uint8_t buffer[RC_BUFFER_LENGTH]; 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) { if (ret > 0U) {
buffer[ret] = '\0'; buffer[ret] = '\0';

@ -11,7 +11,7 @@
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) // 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 * Copyright (C) 2017-2020 by Bryan Biedenkapp N2PLL
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -32,8 +32,6 @@
#include "network/UDPSocket.h" #include "network/UDPSocket.h"
#include "Log.h" #include "Log.h"
using namespace network;
#include <cassert> #include <cassert>
#if !defined(_WIN32) && !defined(_WIN64) #if !defined(_WIN32) && !defined(_WIN64)
@ -41,6 +39,8 @@ using namespace network;
#include <cstring> #include <cstring>
#endif #endif
using namespace network;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public Class Members // Public Class Members
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -49,35 +49,34 @@ using namespace network;
/// </summary> /// </summary>
/// <param name="address">Hostname/IP address to connect to.</param> /// <param name="address">Hostname/IP address to connect to.</param>
/// <param name="port">Port number.</param> /// <param name="port">Port number.</param>
UDPSocket::UDPSocket(const std::string& address, uint32_t port) : UDPSocket::UDPSocket(const std::string& address, unsigned int port) :
m_address(address), m_address_save(address),
m_port(port), m_port_save(port),
m_fd(-1) m_counter(0U)
{ {
assert(!address.empty()); for (int i = 0; i < UDP_SOCKET_MAX; i++) {
#if defined(_WIN32) || defined(_WIN64) m_address[i] = "";
WSAData data; m_port[i] = 0U;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); m_af[i] = 0U;
if (wsaRet != 0) m_fd[i] = -1;
LogError(LOG_NET, "Error from WSAStartup"); }
#endif
} }
/// <summary> /// <summary>
/// Initializes a new instance of the UDPSocket class. /// Initializes a new instance of the UDPSocket class.
/// </summary> /// </summary>
/// <param name="port">Port number.</param> /// <param name="port">Port number.</param>
UDPSocket::UDPSocket(uint32_t port) : UDPSocket::UDPSocket(unsigned int port) :
m_address(), m_address_save(),
m_port(port), m_port_save(port),
m_fd(-1) m_counter(0U)
{ {
#if defined(_WIN32) || defined(_WIN64) for (int i = 0; i < UDP_SOCKET_MAX; i++) {
WSAData data; m_address[i] = "";
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data); m_port[i] = 0U;
if (wsaRet != 0) m_af[i] = 0U;
LogError(LOG_NET, "Error from WSAStartup"); m_fd[i] = -1;
#endif }
} }
/// <summary> /// <summary>
@ -85,48 +84,74 @@ UDPSocket::UDPSocket(uint32_t port) :
/// </summary> /// </summary>
UDPSocket::~UDPSocket() UDPSocket::~UDPSocket()
{ {
#if defined(_WIN32) || defined(_WIN64) /* stub */
::WSACleanup();
#endif
} }
/// <summary> /// <summary>
/// Opens UDP socket connection. /// Opens UDP socket connection.
/// </summary> /// </summary>
/// <param name="address"></param>
/// <returns>True, if UDP socket is opened, otherwise false.</returns> /// <returns>True, if UDP socket is opened, otherwise false.</returns>
bool UDPSocket::open() bool UDPSocket::open(const sockaddr_storage& address)
{ {
m_fd = ::socket(PF_INET, SOCK_DGRAM, 0); return open(address.ss_family);
if (m_fd < 0) { }
#if defined(_WIN32) || defined(_WIN64)
LogError(LOG_NET, "Cannot create the UDP socket, err: %lu", ::GetLastError()); /// <summary>
#else /// Opens UDP socket connection.
LogError(LOG_NET, "Cannot create the UDP socket, err: %d", errno); /// </summary>
#endif /// <param name="af"></param>
/// <returns>True, if UDP socket is opened, otherwise false.</returns>
bool UDPSocket::open(unsigned int af)
{
return open(0, af, m_address_save, m_port_save);
}
/// <summary>
/// Opens UDP socket connection.
/// </summary>
/// <param name="index"></param>
/// <param name="af"></param>
/// <param name="address"></param>
/// <param name="port"></param>
/// <returns>True, if UDP socket is opened, otherwise false.</returns>
bool UDPSocket::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_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; return false;
} }
if (m_port > 0U) { close(index);
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()) { int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0);
if (fd < 0) {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str()); LogError(LOG_NET, "Cannot create the UDP socket, err: %lu", ::GetLastError());
#else #else
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str()); LogError(LOG_NET, "Cannot create the UDP socket, err: %d", errno);
#endif #endif
if (addr.sin_addr.s_addr == INADDR_NONE) {
LogError(LOG_NET, "The local address is invalid - %s", m_address.c_str());
return false; 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; 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) #if defined(_WIN32) || defined(_WIN64)
LogError(LOG_NET, "Cannot set the UDP socket option, err: %lu", ::GetLastError()); LogError(LOG_NET, "Cannot set the UDP socket option, err: %lu", ::GetLastError());
#else #else
@ -135,7 +160,7 @@ bool UDPSocket::open()
return false; return false;
} }
if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) { if (::bind(fd, (sockaddr*)& addr, addrlen) == -1) {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
LogError(LOG_NET, "Cannot bind the UDP address, err: %lu", ::GetLastError()); LogError(LOG_NET, "Cannot bind the UDP address, err: %lu", ::GetLastError());
#else #else
@ -143,6 +168,8 @@ bool UDPSocket::open()
#endif #endif
return false; return false;
} }
LogInfo("Opening UDP port on %u", port);
} }
return true; return true;
@ -154,64 +181,81 @@ bool UDPSocket::open()
/// <param name="buffer">Buffer to read data into.</param> /// <param name="buffer">Buffer to read data into.</param>
/// <param name="length">Length of data to read.</param> /// <param name="length">Length of data to read.</param>
/// <param name="address">IP address to read data from.</param> /// <param name="address">IP address to read data from.</param>
/// <param name="port">Port number for remote UDP socket.</param> /// <param name="addrLen"></param>
/// <returns>Actual length of data read from remote UDP socket.</returns> /// <returns>Actual length of data read from remote UDP socket.</returns>
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(buffer != NULL);
assert(length > 0U); assert(length > 0U);
// Check that the readfrom() won't block // Check that the readfrom() won't block
fd_set readFds; int i, n;
FD_ZERO(&readFds); 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) #if defined(_WIN32) || defined(_WIN64)
FD_SET((uint32_t)m_fd, &readFds); int ret = WSAPoll(pfd, n, 0);
#else #else
FD_SET(m_fd, &readFds); int ret = ::poll(pfd, n, 0);
#endif #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 (ret < 0) {
#if defined(_WIN32) || defined(_WIN64) #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 #else
LogError(LOG_NET, "Error returned from UDP select, err: %d", errno); LogError(LOG_NET, "Error returned from UDP poll, err: %d", errno);
#endif #endif
return -1; 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; return 0;
sockaddr_in addr;
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
int size = sizeof(sockaddr_in); int size = sizeof(sockaddr_storage);
#else #else
socklen_t size = sizeof(sockaddr_in); socklen_t size = sizeof(sockaddr_storage);
#endif #endif
#if defined(_WIN32) || defined(_WIN64) #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 #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 #endif
if (len <= 0) { if (len <= 0) {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
LogError(LOG_NET, "Error returned from recvfrom, err: %lu", ::GetLastError()); LogError(LOG_NET, "Error returned from recvfrom, err: %lu", ::GetLastError());
#else #else
LogError(LOG_NET, "Error returned from recvfrom, err: %d", errno); 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 #endif
return -1; return -1;
} }
address = addr.sin_addr; m_counter++;
port = ntohs(addr.sin_port); addrLen = size;
return len; return len;
} }
@ -221,43 +265,44 @@ int UDPSocket::read(uint8_t* buffer, uint32_t length, in_addr& address, uint32_t
/// <param name="buffer">Buffer containing data to write to socket.</param> /// <param name="buffer">Buffer containing data to write to socket.</param>
/// <param name="length">Length of data to write.</param> /// <param name="length">Length of data to write.</param>
/// <param name="address">IP address to write data to.</param> /// <param name="address">IP address to write data to.</param>
/// <param name="port">Port number for remote UDP socket.</param> /// <param name="addrLen"></param>
/// <returns>Actual length of data written to remote UDP socket.</returns> /// <returns>Actual length of data written to remote UDP socket.</returns>
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(buffer != NULL);
assert(length > 0U); assert(length > 0U);
sockaddr_in addr; bool result = false;
::memset(&addr, 0x00, sizeof(sockaddr_in));
addr.sin_family = AF_INET; for (int i = 0; i < UDP_SOCKET_MAX; i++) {
addr.sin_addr = address; if (m_fd[i] < 0 || m_af[i] != address.ss_family)
addr.sin_port = htons(port); continue;
#if defined(_WIN32) || defined(_WIN64) #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 #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 #endif
if (ret < 0) { if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64) #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 #else
LogError(LOG_NET, "Error returned from sendto, err: %d", errno); LogError(LOG_NET, "Error returned from sendto, err: %d", errno);
#endif #endif
return false;
} }
else {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
if (ret != int(length)) if (ret == int(length))
return false; result = true;
#else #else
if (ret != ssize_t(length)) if (ret == ssize_t(length))
return false; result = true;
#endif #endif
}
}
return true; return result;
} }
/// <summary> /// <summary>
@ -265,10 +310,47 @@ bool UDPSocket::write(const uint8_t* buffer, uint32_t length, const in_addr& add
/// </summary> /// </summary>
void UDPSocket::close() void UDPSocket::close()
{ {
for (int i = 0; i < UDP_SOCKET_MAX; i++)
close(i);
}
/// <summary>
/// Closes the UDP socket connection.
/// </summary>
/// <param name="index"></param>
void UDPSocket::close(const unsigned int index)
{
if ((index < UDP_SOCKET_MAX) && (m_fd[index] >= 0)) {
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
::closesocket(m_fd); ::closesocket(m_fd[index]);
#else #else
::close(m_fd); ::close(m_fd[index]);
#endif
m_fd[index] = -1;
}
}
/// <summary>
///
/// </summary>
void UDPSocket::startup()
{
#if defined(_WIN32) || defined(_WIN64)
WSAData data;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
if (wsaRet != 0) {
LogError(LOG_NET, "Error from WSAStartup");
}
#endif
}
/// <summary>
///
/// </summary>
void UDPSocket::shutdown()
{
#if defined(_WIN32) || defined(_WIN64)
::WSACleanup();
#endif #endif
} }
@ -276,43 +358,110 @@ void UDPSocket::close()
/// Helper to lookup a hostname and resolve it to an IP address. /// Helper to lookup a hostname and resolve it to an IP address.
/// </summary> /// </summary>
/// <param name="hostname">String containing hostname to resolve.</param> /// <param name="hostname">String containing hostname to resolve.</param>
/// <returns>IP address structure for containing resolved hostname.</returns> /// <param name="port">Numeric port number of service to resolve.</param>
in_addr UDPSocket::lookup(const std::string& hostname) /// <param name="addr">Socket address structure.</param>
/// <param name="addrLen"></param>
/// <returns>Zero if no error during lookup, otherwise error.</returns>
int UDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& addrLen)
{ {
in_addr addr; struct addrinfo hints;
#if defined(_WIN32) || defined(_WIN64) ::memset(&hints, 0, sizeof(hints));
unsigned long address = ::inet_addr(hostname.c_str());
if (address != INADDR_NONE && address != INADDR_ANY) { return lookup(hostname, port, addr, addrLen, hints);
addr.s_addr = address;
return addr;
} }
struct hostent* hp = ::gethostbyname(hostname.c_str()); /// <summary>
if (hp != NULL) { /// Helper to lookup a hostname and resolve it to an IP address.
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr)); /// </summary>
return addr; /// <param name="hostname">String containing hostname to resolve.</param>
/// <param name="port">Numeric port number of service to resolve.</param>
/// <param name="addr">Socket address structure.</param>
/// <param name="addrLen"></param>
/// <param name="hints"></param>
/// <returns>Zero if no error during lookup, otherwise error.</returns>
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;
} }
LogError(LOG_NET, "Cannot find address for host %s", hostname.c_str()); ::memcpy(&addr, res->ai_addr, addrLen = res->ai_addrlen);
addr.s_addr = INADDR_NONE; freeaddrinfo(res);
return addr;
#else return 0;
in_addr_t address = ::inet_addr(hostname.c_str());
if (address != in_addr_t(-1)) {
addr.s_addr = address;
return addr;
} }
struct hostent* hp = ::gethostbyname(hostname.c_str()); /// <summary>
if (hp != NULL) { ///
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr)); /// </summary>
return addr; /// <param name="addr1"></param>
/// <param name="addr2"></param>
/// <param name="type"></param>
/// <returns></returns>
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()); /// <summary>
///
/// </summary>
/// <param name="addr"></param>
/// <returns></returns>
bool UDPSocket::isNone(const sockaddr_storage& addr)
{
struct sockaddr_in* in = (struct sockaddr_in*) & addr;
addr.s_addr = INADDR_NONE; return ((addr.ss_family == AF_INET) && (in->sin_addr.s_addr == htonl(INADDR_NONE)));
return addr;
#endif
} }

@ -11,7 +11,7 @@
// Licensed under the GPLv2 License (https://opensource.org/licenses/GPL-2.0) // 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 * 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 * it under the terms of the GNU General Public License as published by
@ -39,14 +39,25 @@
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <poll.h>
#include <unistd.h> #include <unistd.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <errno.h> #include <errno.h>
#else #else
#include <winsock.h> #include <winsock2.h>
#include <ws2tcpip.h>
#endif #endif
#if !defined(UDP_SOCKET_MAX)
#define UDP_SOCKET_MAX 1
#endif
enum IPMATCHTYPE {
IMT_ADDRESS_AND_PORT,
IMT_ADDRESS_ONLY
};
namespace network namespace network
{ {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -58,31 +69,54 @@ namespace network
class HOST_SW_API UDPSocket { class HOST_SW_API UDPSocket {
public: public:
/// <summary>Initializes a new instance of the UDPSocket class.</summary> /// <summary>Initializes a new instance of the UDPSocket class.</summary>
UDPSocket(const std::string& address, uint32_t port = 0U); UDPSocket(const std::string& address, unsigned int port = 0U);
/// <summary>Initializes a new instance of the UDPSocket class.</summary>
UDPSocket(unsigned int port = 0U);
/// <summary>Initializes a new instance of the UDPSocket class.</summary> /// <summary>Initializes a new instance of the UDPSocket class.</summary>
UDPSocket(uint32_t port = 0U);
/// <summary>Finalizes a instance of the UDPSocket class.</summary>
~UDPSocket(); ~UDPSocket();
/// <summary>Opens UDP socket connection.</summary> /// <summary>Opens UDP socket connection.</summary>
bool open(); bool open(unsigned int af = AF_UNSPEC);
/// <summary>Opens UDP socket connection.</summary>
bool open(const sockaddr_storage& address);
/// <summary>Opens UDP socket connection.</summary>
bool open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port);
/// <summary>Read data from the UDP socket.</summary> /// <summary>Read data from the UDP socket.</summary>
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);
/// <summary>Write data to the UDP socket.</summary> /// <summary>Write data to the UDP socket.</summary>
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);
/// <summary>Closes the UDP socket connection.</summary> /// <summary>Closes the UDP socket connection.</summary>
void close(); void close();
/// <summary>Closes the UDP socket connection.</summary>
void close(const unsigned int index);
/// <summary></summary>
static void startup();
/// <summary></summary>
static void shutdown();
/// <summary>Helper to lookup a hostname and resolve it to an IP address.</summary> /// <summary>Helper to lookup a hostname and resolve it to an IP address.</summary>
static in_addr lookup(const std::string& hostName); static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& addrLen);
/// <summary>Helper to lookup a hostname and resolve it to an IP address.</summary>
static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& addrLen, struct addrinfo& hints);
/// <summary></summary>
static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IMT_ADDRESS_AND_PORT);
/// <summary></summary>
static bool isNone(const sockaddr_storage& addr);
private: private:
std::string m_address; std::string m_address_save;
uint16_t m_port; unsigned short m_port_save;
int m_fd; 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__ #endif // __UDP_SOCKET_H__

@ -47,19 +47,6 @@ using namespace p25::data;
#include <cstring> #include <cstring>
#include <ctime> #include <ctime>
#if !defined(_WIN32) && !defined(_WIN64)
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#else
#include <winsock.h>
#endif
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Public Class Members // Public Class Members
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------

Loading…
Cancel
Save

Powered by TurnKey Linux.