Merge branch 'bugfix/SimultaneousG2_#16' into develop closes #16

pull/32/head
Geoffrey Merck 4 years ago
commit 1e6fee9d4d

@ -72,7 +72,8 @@
"thread": "cpp",
"typeindex": "cpp",
"variant": "cpp",
"iostream": "cpp"
"iostream": "cpp",
"fstream": "cpp"
},
"editor.tokenColorCustomizations": {
"textMateRules": [

@ -24,6 +24,7 @@
#include "AMBEData.h"
#include "DStarDefines.h"
#include "Utils.h"
#include "NetUtils.h"
CAMBEData::CAMBEData() :
m_rptSeq(0U),
@ -582,6 +583,17 @@ unsigned int CAMBEData::getMyPort() const
return m_myPort;
}
struct sockaddr_storage CAMBEData::getDestination() const
{
struct sockaddr_storage dest;
::memset(&dest, 0, sizeof(sockaddr_storage));
dest.ss_family = AF_INET;
TOIPV4(dest)->sin_addr = m_yourAddress;
TOIPV4(dest)->sin_port = htons(m_yourPort);
return dest;
}
CHeaderData& CAMBEData::getHeader()
{
return m_header;

@ -77,6 +77,7 @@ public:
in_addr getYourAddress() const;
unsigned int getYourPort() const;
struct sockaddr_storage getDestination() const;
unsigned int getMyPort() const;
unsigned int getErrors() const;

@ -75,7 +75,7 @@ m_dummyRepeaterHandler(NULL),
m_dextraPool(NULL),
m_dplusPool(NULL),
m_dcsPool(NULL),
m_g2Handler(NULL),
m_g2HandlerPool(NULL),
m_aprsWriter(NULL),
m_irc(NULL),
m_cache(),
@ -198,16 +198,16 @@ void* CDStarGatewayThread::Entry()
CLog::logError("Failed to allocate incoming DCS handler\n");
}
m_g2Handler = new CG2ProtocolHandler(G2_DV_PORT, m_gatewayAddress);
bool ret = m_g2Handler->open();
m_g2HandlerPool = new CG2ProtocolHandlerPool(G2_DV_PORT, m_gatewayAddress);
bool ret = m_g2HandlerPool->open();
if (!ret) {
CLog::logError("Could not open the G2 protocol handler");
delete m_g2Handler;
m_g2Handler = NULL;
delete m_g2HandlerPool;
m_g2HandlerPool = NULL;
}
// Wait here until we have the essentials to run
while (!m_killed && (m_dextraPool == NULL || m_dplusPool == NULL || m_dcsPool == NULL || m_g2Handler == NULL || (m_icomRepeaterHandler == NULL && m_hbRepeaterHandler == NULL && m_dummyRepeaterHandler == NULL) || m_gatewayCallsign.empty()))
while (!m_killed && (m_dextraPool == NULL || m_dplusPool == NULL || m_dcsPool == NULL || m_g2HandlerPool == NULL || (m_icomRepeaterHandler == NULL && m_hbRepeaterHandler == NULL && m_dummyRepeaterHandler == NULL) || m_gatewayCallsign.empty()))
::std::this_thread::sleep_for(std::chrono::milliseconds(500UL)); // 1/2 sec
if (m_killed)
@ -232,7 +232,7 @@ void* CDStarGatewayThread::Entry()
loadGateways();
loadAllReflectors();
CG2Handler::setG2ProtocolHandler(m_g2Handler);
CG2Handler::setG2ProtocolHandlerPool(m_g2HandlerPool);
CG2Handler::setHeaderLogger(headerLogger);
CDExtraHandler::setCallsign(m_gatewayCallsign);
@ -250,7 +250,7 @@ void* CDStarGatewayThread::Entry()
CDCSHandler::setHeaderLogger(headerLogger);
CRepeaterHandler::setLocalAddress(m_gatewayAddress);
CRepeaterHandler::setG2Handler(m_g2Handler);
CRepeaterHandler::setG2HandlerPool(m_g2HandlerPool);
if (m_irc != NULL)
CRepeaterHandler::setIRC(m_irc);
@ -284,7 +284,7 @@ void* CDStarGatewayThread::Entry()
#ifdef USE_STARNET
CStarNetHandler::setCache(&m_cache);
CStarNetHandler::setGateway(m_gatewayCallsign);
CStarNetHandler::setG2Handler(m_g2Handler);
CStarNetHandler::setG2HandlerPool(m_g2HandlerPool);
if (m_irc != NULL)
CStarNetHandler::setIRC(m_irc);
@ -453,8 +453,8 @@ void* CDStarGatewayThread::Entry()
m_dcsPool->close();
delete m_dcsPool;
m_g2Handler->close();
delete m_g2Handler;
m_g2HandlerPool->close();
delete m_g2HandlerPool;
if (m_irc != NULL) {
m_irc->close();
@ -788,9 +788,9 @@ void CDStarGatewayThread::processIrcDDB()
if(!res)
return;
if(m_g2Handler != nullptr) {
if(m_g2HandlerPool != nullptr) {
CLog::logInfo("%s wants to G2 route to us, punching UDP Holes through NAT", address.c_str());
m_g2Handler->traverseNat(address);
m_g2HandlerPool->traverseNat(address);
}
else {
CLog::logInfo("%s wants to G2 route to us, but G2 is disabled", address.c_str());
@ -1096,13 +1096,13 @@ void CDStarGatewayThread::processDCS()
void CDStarGatewayThread::processG2()
{
for (;;) {
G2_TYPE type = m_g2Handler->read();
G2_TYPE type = m_g2HandlerPool->read();
switch (type) {
case GT_HEADER: {
CHeaderData* header = m_g2Handler->readHeader();
CHeaderData* header = m_g2HandlerPool->readHeader();
if (header != NULL) {
// CLog::logInfo("G2 header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s Flags: %02X %02X %02X", header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str(), header->getFlag1(), header->getFlag2(), header->getFlag3());
CLog::logDebug("G2 header - My: %s/%s Your: %s Rpt1: %s Rpt2: %s Flags: %02X %02X %02X", header->getMyCall1().c_str(), header->getMyCall2().c_str(), header->getYourCall().c_str(), header->getRptCall1().c_str(), header->getRptCall2().c_str(), header->getFlag1(), header->getFlag2(), header->getFlag3());
CG2Handler::process(*header);
delete header;
}
@ -1110,7 +1110,7 @@ void CDStarGatewayThread::processG2()
break;
case GT_AMBE: {
CAMBEData* data = m_g2Handler->readAMBE();
CAMBEData* data = m_g2HandlerPool->readAMBE();
if (data != NULL) {
CG2Handler::process(*data);
delete data;

@ -28,7 +28,7 @@
#include "RepeaterProtocolHandler.h"
#include "DStarGatewayStatusData.h"
#include "DCSProtocolHandlerPool.h"
#include "G2ProtocolHandler.h"
#include "G2ProtocolHandlerPool.h"
#include "RemoteHandler.h"
#include "CacheManager.h"
#include "CallsignList.h"
@ -102,7 +102,7 @@ private:
CDExtraProtocolHandlerPool* m_dextraPool;
CDPlusProtocolHandlerPool* m_dplusPool;
CDCSProtocolHandlerPool* m_dcsPool;
CG2ProtocolHandler* m_g2Handler;
CG2ProtocolHandlerPool* m_g2HandlerPool;
CAPRSHandler* m_aprsWriter;
CIRCDDB* m_irc;
CCacheManager m_cache;

@ -31,7 +31,7 @@
unsigned int CG2Handler::m_maxRoutes = 0U;
CG2Handler** CG2Handler::m_routes = NULL;
CG2ProtocolHandler* CG2Handler::m_handler = NULL;
CG2ProtocolHandlerPool* CG2Handler::m_handler = NULL;
CHeaderLogger* CG2Handler::m_headerLogger = NULL;
@ -60,7 +60,7 @@ void CG2Handler::initialise(unsigned int maxRoutes)
m_routes[i] = NULL;
}
void CG2Handler::setG2ProtocolHandler(CG2ProtocolHandler* handler)
void CG2Handler::setG2ProtocolHandlerPool(CG2ProtocolHandlerPool* handler)
{
assert(handler != NULL);
@ -102,15 +102,6 @@ void CG2Handler::process(CHeaderData& header)
in_addr address = header.getYourAddress();
unsigned int id = header.getId();
for (unsigned int i = 0U; i < m_maxRoutes; i++) {
CG2Handler* route = m_routes[i];
if (route != NULL) {
// Is this a duplicate header, ignore it
if (route->m_id == id)
return;
}
}
// Find the destination repeater
CRepeaterHandler* repeater = CRepeaterHandler::findDVRepeater(header.getRptCall2());
if (repeater == NULL) {
@ -175,6 +166,8 @@ void CG2Handler::process(CAMBEData& data)
void CG2Handler::clock(unsigned int ms)
{
m_handler->clock(ms);
for (unsigned int i = 0U; i < m_maxRoutes; i++) {
CG2Handler* route = m_routes[i];
if (route != NULL) {

@ -22,7 +22,7 @@
#include <netinet/in.h>
#include "G2ProtocolHandler.h"
#include "G2ProtocolHandlerPool.h"
#include "RepeaterHandler.h"
#include "DStarDefines.h"
#include "HeaderLogger.h"
@ -34,7 +34,7 @@ class CG2Handler {
public:
static void initialise(unsigned int maxRoutes);
static void setG2ProtocolHandler(CG2ProtocolHandler* handler);
static void setG2ProtocolHandlerPool(CG2ProtocolHandlerPool* handler);
static void setHeaderLogger(CHeaderLogger* logger);
static void process(CHeaderData& header);
@ -54,7 +54,7 @@ private:
static unsigned int m_maxRoutes;
static CG2Handler** m_routes;
static CG2ProtocolHandler* m_handler;
static CG2ProtocolHandlerPool* m_handler;
static CHeaderLogger* m_headerLogger;

@ -18,6 +18,7 @@
*/
#include <string>
#include <cstring>
#include "G2ProtocolHandler.h"
#include "Utils.h"
@ -27,30 +28,28 @@
const unsigned int BUFFER_LENGTH = 255U;
CG2ProtocolHandler::CG2ProtocolHandler(unsigned int port, const std::string& addr) :
m_socket(addr, port),
CG2ProtocolHandler::CG2ProtocolHandler(CUDPReaderWriter* socket, const struct sockaddr_storage& destination, unsigned int bufferSize) :
m_socket(socket),
m_type(GT_NONE),
m_buffer(NULL),
m_buffer(nullptr),
m_length(0U),
m_address(),
m_port(0U)
m_address(destination),
m_inactivityTimer(1000U, 29U),
m_id(0U)
{
m_buffer = new unsigned char[BUFFER_LENGTH];
m_inactivityTimer.start();
m_buffer = new unsigned char[bufferSize];
::memset(m_buffer, 0, bufferSize);
}
CG2ProtocolHandler::~CG2ProtocolHandler()
{
delete[] m_buffer;
m_portmap.clear();
}
bool CG2ProtocolHandler::open()
{
return m_socket.open();
}
bool CG2ProtocolHandler::writeHeader(const CHeaderData& header)
{
m_inactivityTimer.start();
unsigned char buffer[60U];
unsigned int length = header.getG2Data(buffer, 60U, true);
@ -58,12 +57,12 @@ bool CG2ProtocolHandler::writeHeader(const CHeaderData& header)
CUtils::dump("Sending Header", buffer, length);
#endif
in_addr addr = header.getYourAddress();
auto found = m_portmap.find(addr.s_addr);
unsigned int port = (m_portmap.end()==found) ? header.getYourPort() : found->second;
assert(CNetUtils::match(header.getDestination(), m_address, IMT_ADDRESS_ONLY));
//CLog::logTrace("Write header to %s:%u", inet_ntoa(addr), ntohs(TOIPV4(m_address)->sin_port));
for (unsigned int i = 0U; i < 5U; i++) {
bool res = m_socket.write(buffer, length, addr, port);
bool res = m_socket->write(buffer, length, m_address);
if (!res)
return false;
}
@ -73,6 +72,7 @@ bool CG2ProtocolHandler::writeHeader(const CHeaderData& header)
bool CG2ProtocolHandler::writeAMBE(const CAMBEData& data)
{
m_inactivityTimer.start();
unsigned char buffer[40U];
unsigned int length = data.getG2Data(buffer, 40U);
@ -80,58 +80,34 @@ bool CG2ProtocolHandler::writeAMBE(const CAMBEData& data)
CUtils::dump("Sending Data", buffer, length);
#endif
in_addr addr = data.getYourAddress();
auto found = m_portmap.find(addr.s_addr);
unsigned int port = (m_portmap.end()==found) ? data.getYourPort() : found->second;
return m_socket.write(buffer, length, addr, port);
assert(CNetUtils::match(data.getDestination(), m_address, IMT_ADDRESS_ONLY));
//CLog::logTrace("Write ambe to %s:%u", inet_ntoa(addr), ntohs(TOIPV4(m_address)->sin_port));
return m_socket->write(buffer, length, m_address);
}
G2_TYPE CG2ProtocolHandler::read()
bool CG2ProtocolHandler::setBuffer(unsigned char * buffer, int length)
{
bool res = true;
// Loop until we have no more data from the socket or we have data for the higher layers
while (res)
res = readPackets();
return m_type;
}
assert(buffer != nullptr);
bool CG2ProtocolHandler::readPackets()
{
m_type = GT_NONE;
::memcpy(m_buffer, buffer, length);
// No more data?
int length = m_socket.read(m_buffer, BUFFER_LENGTH, m_address, m_port);
if(length <= 0)
return false;
if(length == 1) {
CLog::logDebug("G2 Nat traversal packet received");
}
m_length = length;
// save the incoming port (this is to enable mobile hotspots)
if (m_portmap.end() == m_portmap.find(m_address.s_addr)) {
CLog::logInfo("G2 new address %s on port %u\n", inet_ntoa(m_address), m_port);
m_portmap[m_address.s_addr] = m_port;
} else {
if (m_portmap[m_address.s_addr] != m_port) {
CLog::logInfo("G2 new port for %s is %u, was %u\n", inet_ntoa(m_address), m_port, m_portmap[m_address.s_addr]);
m_portmap[m_address.s_addr] = m_port;
}
}
if (m_buffer[0] != 'D' || m_buffer[1] != 'S' || m_buffer[2] != 'V' || m_buffer[3] != 'T') {
CLog::logTrace("DSVT");
return true;
} else {
// Header or data packet type?
if ((m_buffer[14] & 0x80) == 0x80)
if ((m_buffer[14] & 0x80) == 0x80) {
m_type = GT_HEADER;
else
}
else {
m_type = GT_AMBE;
}
return false;
}
@ -139,49 +115,43 @@ bool CG2ProtocolHandler::readPackets()
CHeaderData* CG2ProtocolHandler::readHeader()
{
if (m_type != GT_HEADER)
return NULL;
m_inactivityTimer.start();
if (m_type != GT_HEADER || m_id != 0U)
return nullptr;
m_type = GT_NONE; // Header data has been consumed, reset our status
CHeaderData* header = new CHeaderData;
// G2 checksums are unreliable
bool res = header->setG2Data(m_buffer, m_length, false, m_address, m_port);
bool res = header->setG2Data(m_buffer, m_length, false, TOIPV4(m_address)->sin_addr, ntohs(GETPORT(m_address)));
if (!res) {
delete header;
return NULL;
return nullptr;
}
m_id = header->getId();// remember the id so we do not read it duplicate
return header;
}
CAMBEData* CG2ProtocolHandler::readAMBE()
{
m_inactivityTimer.start();
if (m_type != GT_AMBE)
return NULL;
m_type = GT_NONE; // Ambe data has been consumed, reset our status
CAMBEData* data = new CAMBEData;
bool res = data->setG2Data(m_buffer, m_length, m_address, m_port);
bool res = data->setG2Data(m_buffer, m_length, TOIPV4(m_address)->sin_addr, ntohs(GETPORT(m_address)));
if (!res) {
delete data;
return NULL;
}
return data;
}
if(data->isEnd())
m_id = 0U;
void CG2ProtocolHandler::close()
{
m_socket.close();
return data;
}
void CG2ProtocolHandler::traverseNat(const std::string& address)
{
unsigned char buffer = 0x00U;
in_addr addr = CUDPReaderWriter::lookup(address);
CLog::logInfo("G2 Punching hole to %s", address.c_str());
m_socket.write(&buffer, 1U, addr, G2_DV_PORT);
}

@ -20,11 +20,14 @@
#pragma once
#include <unordered_map>
#include <sys/socket.h>
#include "UDPReaderWriter.h"
#include "DStarDefines.h"
#include "HeaderData.h"
#include "AMBEData.h"
#include "NetUtils.h"
#include "Timer.h"
enum G2_TYPE {
GT_NONE,
@ -34,7 +37,7 @@ enum G2_TYPE {
class CG2ProtocolHandler {
public:
CG2ProtocolHandler(unsigned int port, const std::string& addr = std::string(""));
CG2ProtocolHandler(CUDPReaderWriter* socket, const struct sockaddr_storage& destination, unsigned int bufferSize);
~CG2ProtocolHandler();
bool open();
@ -42,22 +45,25 @@ public:
bool writeHeader(const CHeaderData& header);
bool writeAMBE(const CAMBEData& data);
G2_TYPE read();
CHeaderData* readHeader();
CAMBEData* readAMBE();
void close();
void traverseNat(const std::string& address);
struct sockaddr_storage getDestination() { return m_address; }
G2_TYPE getType() { return m_type; }
private:
std::unordered_map<uint32_t, unsigned int> m_portmap;
bool setBuffer(unsigned char * buffer, int length);
void clock(unsigned int ms) { m_inactivityTimer.clock(ms); }
bool isInactive() { return m_inactivityTimer.hasExpired(); }
CUDPReaderWriter m_socket;
private:
CUDPReaderWriter * m_socket;
G2_TYPE m_type;
unsigned char* m_buffer;
unsigned int m_length;
in_addr m_address;
unsigned int m_port;
struct sockaddr_storage m_address;
CTimer m_inactivityTimer;
unsigned int m_id;
bool readPackets();
};

@ -0,0 +1,190 @@
/*
* Copyright (c) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <cassert>
#include "Log.h"
#include "G2ProtocolHandlerPool.h"
const unsigned int G2_BUFFER_LENGTH = 255U;
CG2ProtocolHandlerPool::CG2ProtocolHandlerPool(unsigned short port, const std::string& address) :
m_address(address),
m_basePort(port),
m_socket(address, port)
{
assert(port > 0U);
m_index = m_pool.end();
}
CG2ProtocolHandlerPool::~CG2ProtocolHandlerPool()
{
}
bool CG2ProtocolHandlerPool::open()
{
bool res = m_socket.open();
return res;
}
void CG2ProtocolHandlerPool::close()
{
for(auto handler : m_pool) {
delete handler;
}
m_pool.clear();
m_index = m_pool.end();
m_socket.close();
}
G2_TYPE CG2ProtocolHandlerPool::read()
{
bool res = true;
while(res)
res = readPackets();
if(m_index == m_pool.end())
m_index = m_pool.begin();
while(m_index != m_pool.end()) {
if((*m_index)->getType() != GT_NONE) {
return (*m_index)->getType();
}
m_index++;
}
return GT_NONE;
}
CAMBEData * CG2ProtocolHandlerPool::readAMBE()
{
if(m_index == m_pool.end() || (*m_index)->getType() != GT_AMBE)
return nullptr;
return (*m_index)->readAMBE();
}
CHeaderData * CG2ProtocolHandlerPool::readHeader()
{
if(m_index == m_pool.end() || (*m_index)->getType() != GT_HEADER)
return nullptr;
return (*m_index)->readHeader();
}
bool CG2ProtocolHandlerPool::readPackets()
{
unsigned char buffer[G2_BUFFER_LENGTH];
struct sockaddr_storage addr;
::memset(&addr, 0, sizeof(sockaddr_storage));
// No more data?
int length = m_socket.read(buffer, G2_BUFFER_LENGTH, addr);
if(length <= 0) return false;
if(length == 1 && buffer[0] == 0U) {
CLog::logDebug("G2 Nat traversal packet received");
}
CG2ProtocolHandler * handler = findHandler(addr, IMT_ADDRESS_AND_PORT);
if(handler == nullptr) {
CLog::logTrace("new incoming G2 %s:%u", inet_ntoa(TOIPV4(addr)->sin_addr), ntohs(TOIPV4(addr)->sin_port));
handler = new CG2ProtocolHandler(&m_socket, addr, G2_BUFFER_LENGTH);
m_pool.push_back(handler);
m_index = m_pool.end();
}
bool res = handler->setBuffer(buffer, length);
return res;
}
void CG2ProtocolHandlerPool::traverseNat(const std::string& address)
{
unsigned char buffer = 0x00U;
in_addr addr = CUDPReaderWriter::lookup(address);
CLog::logInfo("G2 Punching hole to %s", address.c_str());
m_socket.write(&buffer, 1U, addr, G2_DV_PORT);
}
bool CG2ProtocolHandlerPool::writeHeader(const CHeaderData& header)
{
auto handler = findHandler(header.getDestination(), IMT_ADDRESS_AND_PORT);
if(handler == nullptr)
handler = findHandler(header.getDestination(), IMT_ADDRESS_ONLY);
if(handler == nullptr) {
handler = new CG2ProtocolHandler(&m_socket, header.getDestination(), G2_BUFFER_LENGTH);
m_pool.push_back(handler);
m_index = m_pool.end();
}
return handler->writeHeader(header);
}
bool CG2ProtocolHandlerPool::writeAMBE(const CAMBEData& data)
{
auto handler = findHandler(data.getDestination(), IMT_ADDRESS_AND_PORT);
if(handler == nullptr)
handler = findHandler(data.getDestination(), IMT_ADDRESS_ONLY);
if(handler == nullptr) {
handler = new CG2ProtocolHandler(&m_socket, data.getDestination(), G2_BUFFER_LENGTH);
m_pool.push_back(handler);
m_index = m_pool.end();
}
return handler->writeAMBE(data);
}
CG2ProtocolHandler * CG2ProtocolHandlerPool::findHandler(const struct sockaddr_storage& addr, IPMATCHTYPE matchType) const
{
for(auto handler : m_pool) {
if(handler != nullptr && CNetUtils::match(addr, handler->getDestination(), matchType))
return handler;
}
return nullptr;
}
CG2ProtocolHandler * CG2ProtocolHandlerPool::findHandler(in_addr addr, unsigned int port, IPMATCHTYPE matchType) const
{
struct sockaddr_storage addrStorage;
addrStorage.ss_family = AF_INET;
TOIPV4(addrStorage)->sin_addr = addr;
TOIPV4(addrStorage)->sin_port = port;
return findHandler(addrStorage, matchType);
}
void CG2ProtocolHandlerPool::clock(unsigned int ms)
{
for(auto it = m_pool.begin(); it != m_pool.end();) {
(*it)->clock(ms);
if((*it)->isInactive()) {
delete (*it);
it = m_pool.erase(it);
m_index = m_pool.end();
}
else {
it++;
}
}
}

@ -0,0 +1,93 @@
/*
* Copyright (c) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#pragma once
#include <string>
#include <vector>
#include <sys/socket.h>
#include <boost/container_hash/hash.hpp>
#include "G2ProtocolHandler.h"
#include "NetUtils.h"
struct sockaddr_storage_map {
struct compAddrAndPort {
bool operator() (const struct sockaddr_storage& a, const struct sockaddr_storage& b) const {
return CNetUtils::match(a, b, IMT_ADDRESS_AND_PORT);
}
};
struct hash {
std::size_t operator() (const sockaddr_storage& a) const {
switch(a.ss_family)
{
case AF_INET: {
auto ptr4 = ((struct sockaddr_in *)&a);
size_t res = AF_INET;
boost::hash_combine(res, ptr4->sin_port);
boost::hash_combine(res, ptr4->sin_addr.s_addr);
return res;
}
case AF_INET6: {
auto ptr6 = ((struct sockaddr_in6 *)&a);
size_t res = AF_INET6;
boost::hash_combine(res, ptr6->sin6_port);
auto in6Ptr = (unsigned int *)&(ptr6->sin6_addr);
boost::hash_combine(res, in6Ptr[0]);
boost::hash_combine(res, in6Ptr[1]);
boost::hash_combine(res, in6Ptr[2]);
boost::hash_combine(res, in6Ptr[3]);
return res;
}
default:
return 0U;
}
}
};
};
class CG2ProtocolHandlerPool
{
public:
CG2ProtocolHandlerPool(unsigned short g2Port, const std::string& address = "");
~CG2ProtocolHandlerPool();
bool open();
void close();
G2_TYPE read();
CAMBEData * readAMBE();
CHeaderData * readHeader();
bool writeAMBE(const CAMBEData& data);
bool writeHeader(const CHeaderData& header);
void traverseNat(const std::string& address);
void clock(unsigned int ms);
private:
bool readPackets();
CG2ProtocolHandler * findHandler(const struct sockaddr_storage& addr, IPMATCHTYPE matchType) const;
CG2ProtocolHandler * findHandler(in_addr addr, unsigned int port, IPMATCHTYPE matchType) const;
std::string m_address;
unsigned int m_basePort;
CUDPReaderWriter m_socket;
std::vector<CG2ProtocolHandler *> m_pool;
std::vector<CG2ProtocolHandler *>::iterator m_index;
};

@ -23,7 +23,7 @@
#include <cassert>
#include <cstring>
#include "HeaderData.h"
#include "NetUtils.h"
#include "CCITTChecksum.h"
#include "DStarDefines.h"
#include "Utils.h"
@ -922,6 +922,17 @@ unsigned int CHeaderData::getYourPort() const
return m_yourPort;
}
struct sockaddr_storage CHeaderData::getDestination() const
{
struct sockaddr_storage dest;
::memset(&dest, 0, sizeof(sockaddr_storage));
dest.ss_family = AF_INET;
TOIPV4(dest)->sin_addr = m_yourAddress;
TOIPV4(dest)->sin_port = htons(m_yourPort);
return dest;
}
unsigned int CHeaderData::getMyPort() const
{
return m_myPort;

@ -94,6 +94,7 @@ public:
in_addr getYourAddress() const;
unsigned int getYourPort() const;
struct sockaddr_storage getDestination() const;
unsigned int getMyPort() const;
unsigned int getErrors() const;

@ -848,7 +848,7 @@ void IRCDDBApp::doUpdate(std::string& msg)
nick = sm1[1];
if (1 == m_d->m_rptrMap.count(value)) {
CLog::logTrace("doUptate RPTR already present");
// CLog::logTrace("doUptate RPTR already present");
IRCDDBAppRptrObject o = m_d->m_rptrMap[value];
zonerp_cs = o.m_zonerp_cs;
CUtils::ReplaceChar(zonerp_cs, '_', ' ');
@ -857,7 +857,7 @@ void IRCDDBApp::doUpdate(std::string& msg)
zonerp_cs.push_back('G');
}
else {
CLog::logTrace("doUptate RPTR not present");
// CLog::logTrace("doUptate RPTR not present");
zonerp_cs = arearp_cs.substr(0, arearp_cs.length() - 1U);
ip_addr = nick.empty() ? getIPAddressFromCall(zonerp_cs) : getIPAddressFromNick(nick);
zonerp_cs.push_back('G');

@ -137,9 +137,8 @@ removehostfiles :
.PHONY tests:
tests : GitVersion.h
# remove these to force tests makefile to rebuild them with -DUNIT_TESTS, otherwise we end up with 2 mains
@$(RM) -f DStarGatewayApp.o
@$(RM) -f DStarGatewayApp.d
# force tests makefile to rebuild them with -DUNIT_TESTS, otherwise we end up with 2 mains
@touch DStarGatewayApp.cpp
@$(MAKE) -C Tests dstargateway_tests
.PHONY run-tests:

@ -0,0 +1,121 @@
/*
* Copyright (c) 2022 by Geoffrey Merck F4FXL / KC3FRA
* Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <sys/types.h>
#include <cstring>
#include "NetUtils.h"
bool CNetUtils::lookupV4(const std::string& hostname, sockaddr_storage& addr)
{
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
return lookup(hostname, addr, hints);
}
bool CNetUtils::lookupV6(const std::string& hostname, sockaddr_storage& addr)
{
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
return lookup(hostname, addr, hints);
}
bool CNetUtils::lookup(const std::string& hostname, sockaddr_storage& addr)
{
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
return lookup(hostname, addr, hints);
}
bool CNetUtils::lookup(const std::string& hostname, sockaddr_storage& addr, struct addrinfo& hints)
{
struct addrinfo *res;
int err = getaddrinfo(hostname.c_str(), nullptr, &hints, &res);
if(err != 0) {
::memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
lookup("255.255.255.255", addr, hints);
return false;
}
::memcpy(&addr, res->ai_addr, res->ai_addrlen);
::freeaddrinfo(res);
return true;
}
bool CNetUtils::match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type)
{
if (addr1.ss_family != addr2.ss_family)
return false;
if (type == IMT_ADDRESS_AND_PORT) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
}
} else if (type == IMT_ADDRESS_ONLY) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
}
} else {
return false;
}
}
void CNetUtils::setPort(struct sockaddr_storage& addr, in_port_t port)
{
switch (addr.ss_family)
{
case AF_INET:
TOIPV4(addr)->sin_port = port;
break;
case AF_INET6:
TOIPV6(addr)->sin6_port = port;
default:
break;
}
}

@ -0,0 +1,45 @@
/*
* Copyright (c) 2022 by Geoffrey Merck F4FXL / KC3FRA
* Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#pragma once
#include <string>
#include <netdb.h>
#include <sys/socket.h>
#define TOIPV6(s) ((struct sockaddr_in6*)&s)
#define TOIPV4(s) (((struct sockaddr_in*)&s))
#define GETPORT(s) (s.ss_family == AF_INET6 ? TOIPV6(s)->sin6_port : TOIPV4(s)->sin_port)
#define SETPORT(s, p) (if(s.ss_family == AF_INET6)TOIPV6(s)->sin6_port = p;else TOIPV4(s)->sin_port = p;)
enum IPMATCHTYPE {
IMT_ADDRESS_AND_PORT,
IMT_ADDRESS_ONLY
};
class CNetUtils
{
public:
static bool lookupV6(const std::string& hostname, sockaddr_storage& addr);
static bool lookupV4(const std::string& hostname, sockaddr_storage& addr);
static bool lookup(const std::string& hostname, sockaddr_storage& addr);
static bool lookup(const std::string& hostname, sockaddr_storage& addr, struct addrinfo& hints);
static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type);
static void setPort(struct sockaddr_storage& addr, in_port_t port);
};

@ -127,6 +127,7 @@ the testing framwework used is Google Test.
# 5. Version History
## 5.1. Version 0.5
- [Bugfix] Two simultaneous incoming G2 streams would fail to be transmitted on dual band repeaters ([#16](https://github.com/F4FXL/DStarGateway/issues/16))
- [Improvement] Add NAT Traversal for G2 and DExtra, using IRCDDB as a Rendez Vous server ([#5](https://github.com/F4FXL/DStarGateway/issues/5))
- [Improvement] Add forwarding of RS-MS1A messages to APRS-IS ([#9](https://github.com/F4FXL/DStarGateway/issues/9))
- [Bugfix] Failed to download XLX Hosts when URL contains a = sign ([#14](https://github.com/F4FXL/DStarGateway/issues/14))

@ -45,7 +45,7 @@ unsigned int CRepeaterHandler::m_maxRepeaters = 0U;
CRepeaterHandler** CRepeaterHandler::m_repeaters = NULL;
std::string CRepeaterHandler::m_localAddress;
CG2ProtocolHandler* CRepeaterHandler::m_g2Handler = NULL;
CG2ProtocolHandlerPool* CRepeaterHandler::m_g2HandlerPool = NULL;
CIRCDDB* CRepeaterHandler::m_irc = NULL;
CCacheManager* CRepeaterHandler::m_cache = NULL;
std::string CRepeaterHandler::m_gateway;
@ -301,11 +301,11 @@ void CRepeaterHandler::add(const std::string& callsign, const std::string& band,
delete repeater;
}
void CRepeaterHandler::setG2Handler(CG2ProtocolHandler* handler)
void CRepeaterHandler::setG2HandlerPool(CG2ProtocolHandlerPool* handler)
{
assert(handler != NULL);
m_g2Handler = handler;
m_g2HandlerPool = handler;
}
void CRepeaterHandler::setCache(CCacheManager* cache)
@ -883,7 +883,7 @@ void CRepeaterHandler::processRepeater(CAMBEData& data)
case G2_OK:
data.setDestination(m_g2Address, G2_DV_PORT);
m_g2Handler->writeAMBE(data);
m_g2HandlerPool->writeAMBE(data);
if (data.isEnd()) {
m_repeaterId = 0x00U;
@ -1283,7 +1283,7 @@ void CRepeaterHandler::resolveUserInt(const std::string& user, const std::string
m_g2Header->setDestination(m_g2Address, G2_DV_PORT);
m_g2Header->setRepeaters(m_g2Gateway, m_g2Repeater);
m_g2Handler->writeHeader(*m_g2Header);
m_g2HandlerPool->writeHeader(*m_g2Header);
delete m_g2Header;
m_g2Status = G2_OK;
@ -1315,7 +1315,7 @@ void CRepeaterHandler::resolveRepeaterInt(const std::string& repeater, const std
m_g2Header->setDestination(m_g2Address, G2_DV_PORT);
m_g2Header->setRepeaters(m_g2Gateway, m_g2Repeater);
m_g2Handler->writeHeader(*m_g2Header);
m_g2HandlerPool->writeHeader(*m_g2Header);
delete m_g2Header;
m_g2Status = G2_OK;
@ -2072,7 +2072,7 @@ void CRepeaterHandler::g2CommandHandler(const std::string& callsign, const std::
m_g2Gateway = data->getGateway();
header.setDestination(m_g2Address, G2_DV_PORT);
header.setRepeaters(m_g2Gateway, m_g2Repeater);
m_g2Handler->writeHeader(header);
m_g2HandlerPool->writeHeader(header);
delete data;
}
} else if (string_right(callsign, 1) != "L" && string_right(callsign, 1) != "U") {
@ -2115,7 +2115,7 @@ void CRepeaterHandler::g2CommandHandler(const std::string& callsign, const std::
m_g2Gateway = data->getGateway();
header.setDestination(m_g2Address, G2_DV_PORT);
header.setRepeaters(m_g2Gateway, m_g2Repeater);
m_g2Handler->writeHeader(header);
m_g2HandlerPool->writeHeader(header);
delete data;
}

@ -28,7 +28,7 @@
#include "DExtraProtocolHandler.h"
#include "DPlusProtocolHandler.h"
#include "RemoteRepeaterData.h"
#include "G2ProtocolHandler.h"
#include "G2ProtocolHandlerPool.h"
#include "ReflectorCallback.h"
#include "RepeaterCallback.h"
#include "AnnouncementUnit.h"
@ -75,7 +75,7 @@ public:
#endif
static void setLocalAddress(const std::string& address);
static void setG2Handler(CG2ProtocolHandler* handler);
static void setG2HandlerPool(CG2ProtocolHandlerPool* handler);
static void setIRC(CIRCDDB* irc);
static void setCache(CCacheManager* cache);
static void setGateway(const std::string& gateway);
@ -168,7 +168,7 @@ private:
static CRepeaterHandler** m_repeaters;
static std::string m_localAddress;
static CG2ProtocolHandler* m_g2Handler;
static CG2ProtocolHandlerPool* m_g2HandlerPool;
static CCacheManager* m_cache;
static std::string m_gateway;
static CIRCDDB* m_irc;

@ -0,0 +1,59 @@
/*
* Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <gtest/gtest.h>
#include <netdb.h>
#include "../../NetUtils.h"
namespace NetUtilsTests
{
class NetUtils_lookup: public ::testing::Test {
};
TEST_F(NetUtils_lookup, googleShallAlwaysSucceed)
{
sockaddr_storage addr;
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
bool res = CNetUtils::lookup("google.fr", addr, hints);
bool familyOk = addr.ss_family == AF_INET6 || addr.ss_family == AF_INET;
EXPECT_TRUE(familyOk);
EXPECT_TRUE(res);
}
TEST_F(NetUtils_lookup, erroneousAddress)
{
sockaddr_storage addr;
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
bool res = CNetUtils::lookup("gfilufgclqsegfuligyhfcguyhfguilfguils4df64sdw46fcq6sfgvd6f6d7f67d6f7c6sd7f6s7gfv6fc7d6f76tf.fr", addr, hints);
EXPECT_EQ(addr.ss_family, AF_INET);
auto ptr = (sockaddr_in*)(&addr);
EXPECT_EQ((uint32_t)(ptr->sin_addr.s_addr), (uint32_t)INADDR_NONE);
EXPECT_FALSE(res);
}
}

@ -0,0 +1,68 @@
/*
* Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <gtest/gtest.h>
#include <netdb.h>
#include "../../NetUtils.h"
namespace NetUtilsTests
{
class NetUtils_lookupV4 : public ::testing::Test {
};
TEST_F(NetUtils_lookupV4, googleShallAlwaysSucceed)
{
sockaddr_storage addr;
bool res = CNetUtils::lookupV4("google.fr", addr);
EXPECT_EQ(addr.ss_family, AF_INET);
EXPECT_TRUE(res);
}
TEST_F(NetUtils_lookupV4, erroneousAddress)
{
sockaddr_storage addr;
bool res = CNetUtils::lookupV4("gfilufgclqsegfuligyhfcguyhfguilfguils4df64sdw46fcq6sfgvd6f6d7f67d6f7c6sd7f6s7gfv6fc7d6f76tf.fr", addr);
EXPECT_EQ(addr.ss_family, AF_INET);
auto ptr = (sockaddr_in*)(&addr);
EXPECT_EQ((uint32_t)(ptr->sin_addr.s_addr), (uint32_t)INADDR_NONE);
EXPECT_FALSE(res);
}
TEST_F(NetUtils_lookupV4, addressWithNoIPV4)
{
sockaddr_storage addr;
bool res = CNetUtils::lookupV4("ircv6.openquad.net", addr);
EXPECT_EQ(addr.ss_family, AF_INET);
auto ptr = (sockaddr_in*)(&addr);
EXPECT_EQ((uint32_t)(ptr->sin_addr.s_addr), (uint32_t)INADDR_NONE);
EXPECT_FALSE(res);
}
}

@ -0,0 +1,68 @@
/*
* Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <gtest/gtest.h>
#include <netdb.h>
#include "../../NetUtils.h"
namespace NetUtilsTests
{
class NetUtils_lookupV6 : public ::testing::Test {
};
TEST_F(NetUtils_lookupV6, googleShallAlwaysSucceed)
{
sockaddr_storage addr;
bool res = CNetUtils::lookupV6("google.fr", addr);
EXPECT_EQ(addr.ss_family, AF_INET6);
EXPECT_TRUE(res);
}
TEST_F(NetUtils_lookupV6, erroneousAddress)
{
sockaddr_storage addr;
bool res = CNetUtils::lookupV6("gfilufgclqsegfuligyhfcguyhfguilfguils4df64sdw46fcq6sfgvd6f6d7f67d6f7c6sd7f6s7gfv6fc7d6f76tf.fr", addr);
EXPECT_EQ(addr.ss_family, AF_INET);
auto ptr = (sockaddr_in*)(&addr);
EXPECT_EQ((uint32_t)(ptr->sin_addr.s_addr), (uint32_t)INADDR_NONE);
EXPECT_FALSE(res);
}
TEST_F(NetUtils_lookupV6, addressWithNoIPV6)
{
sockaddr_storage addr;
bool res = CNetUtils::lookupV6("ircv4.openquad.net", addr);
EXPECT_EQ(addr.ss_family, AF_INET);
auto ptr = (sockaddr_in*)(&addr);
EXPECT_EQ((uint32_t)(ptr->sin_addr.s_addr), (uint32_t)INADDR_NONE);
EXPECT_FALSE(res);
}
}

@ -0,0 +1,90 @@
/*
* Copyright (C) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <gtest/gtest.h>
#include <netdb.h>
#include "../../NetUtils.h"
namespace NetUtilsTests
{
class NetUtils_match: public ::testing::Test {
};
TEST_F(NetUtils_match, MatchIPAndPort_differentFamilySamePort)
{
struct sockaddr_storage addr1, addr2;
addr1.ss_family = AF_INET6;
addr2.ss_family = AF_INET;
((struct sockaddr_in6 *)&addr1)->sin6_addr = IN6ADDR_LOOPBACK_INIT;
((struct sockaddr_in6 *)&addr1)->sin6_port = 123;
((struct sockaddr_in *)&addr2)->sin_addr.s_addr = INADDR_LOOPBACK;
((struct sockaddr_in *)&addr2)->sin_port = 123;
EXPECT_FALSE(CNetUtils::match(addr1, addr2, IMT_ADDRESS_AND_PORT));
}
TEST_F(NetUtils_match, MatchIPAndPort_SameFamilySamePort)
{
struct sockaddr_storage addr1, addr2;
addr1.ss_family = AF_INET6;
addr2.ss_family = AF_INET6;
((struct sockaddr_in6 *)&addr1)->sin6_addr = IN6ADDR_LOOPBACK_INIT;
((struct sockaddr_in6 *)&addr1)->sin6_port = 123;
((struct sockaddr_in6 *)&addr2)->sin6_addr = IN6ADDR_LOOPBACK_INIT;
((struct sockaddr_in6 *)&addr2)->sin6_port = 123;
EXPECT_TRUE(CNetUtils::match(addr1, addr2, IMT_ADDRESS_AND_PORT));
}
TEST_F(NetUtils_match, MatchIPAndPort_SameFamilyDifferentPort)
{
struct sockaddr_storage addr1, addr2;
addr1.ss_family = AF_INET6;
addr2.ss_family = AF_INET6;
((struct sockaddr_in6 *)&addr1)->sin6_addr = IN6ADDR_LOOPBACK_INIT;
((struct sockaddr_in6 *)&addr1)->sin6_port = 123;
((struct sockaddr_in6 *)&addr2)->sin6_addr = IN6ADDR_LOOPBACK_INIT;
((struct sockaddr_in6 *)&addr2)->sin6_port = 456;
EXPECT_FALSE(CNetUtils::match(addr1, addr2, IMT_ADDRESS_AND_PORT));
}
TEST_F(NetUtils_match, MatchIP_SameFamilyDifferentPort)
{
struct sockaddr_storage addr1, addr2;
addr1.ss_family = AF_INET6;
addr2.ss_family = AF_INET6;
((struct sockaddr_in6 *)&addr1)->sin6_addr = IN6ADDR_LOOPBACK_INIT;
((struct sockaddr_in6 *)&addr1)->sin6_port = 123;
((struct sockaddr_in6 *)&addr2)->sin6_addr = IN6ADDR_LOOPBACK_INIT;
((struct sockaddr_in6 *)&addr2)->sin6_port = 456;
EXPECT_TRUE(CNetUtils::match(addr1, addr2, IMT_ADDRESS_ONLY));
}
}

@ -21,6 +21,7 @@
#include <string.h>
#include "UDPReaderWriter.h"
#include "Log.h"
#include "NetUtils.h"
CUDPReaderWriter::CUDPReaderWriter(const std::string& address, unsigned int port) :
m_address(address),
@ -101,7 +102,7 @@ bool CUDPReaderWriter::open()
return true;
}
int CUDPReaderWriter::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port)
int CUDPReaderWriter::read(unsigned char* buffer, unsigned int length, struct sockaddr_storage& addr)
{
// Check that the readfrom() won't block
fd_set readFds;
@ -122,8 +123,7 @@ int CUDPReaderWriter::read(unsigned char* buffer, unsigned int length, in_addr&
if (ret == 0)
return 0;
sockaddr_in addr;
socklen_t size = sizeof(sockaddr_in);
socklen_t size = sizeof(addr);
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
if (len <= 0) {
@ -131,22 +131,54 @@ int CUDPReaderWriter::read(unsigned char* buffer, unsigned int length, in_addr&
return -1;
}
address = addr.sin_addr;
port = ntohs(addr.sin_port);
return len;
}
int CUDPReaderWriter::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port)
{
struct sockaddr_storage addr;
auto res = read(buffer, length, addr);
if(res >= 0 && addr.ss_family == AF_INET) {
address = TOIPV4(addr)->sin_addr;
port = ntohs(TOIPV4(addr)->sin_port);
}
return res;
}
bool CUDPReaderWriter::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port)
{
sockaddr_in addr;
::memset(&addr, 0x00, sizeof(sockaddr_in));
struct sockaddr_storage addr;
::memset(&addr, 0, sizeof(sockaddr_storage));
addr.sin_family = AF_INET;
addr.sin_addr = address;
addr.sin_port = htons(port);
addr.ss_family = AF_INET;
TOIPV4(addr)->sin_addr = address;
TOIPV4(addr)->sin_port = htons(port);
return write(buffer, length, addr);
// sockaddr_in addr;
// ::memset(&addr, 0x00, sizeof(sockaddr_in));
// addr.sin_family = AF_INET;
// addr.sin_addr = address;
// addr.sin_port = htons(port);
// ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
// if (ret < 0) {
// CLog::logError("Error returned from sendto (port: %u), err: %s\n", m_port, strerror(errno));
// return false;
// }
// if (ret != ssize_t(length))
// return false;
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
// return true;
}
bool CUDPReaderWriter::write(const unsigned char* buffer, unsigned int length, const struct sockaddr_storage& addr)
{
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
CLog::logError("Error returned from sendto (port: %u), err: %s\n", m_port, strerror(errno));
return false;
@ -158,6 +190,8 @@ bool CUDPReaderWriter::write(const unsigned char* buffer, unsigned int length, c
return true;
}
void CUDPReaderWriter::close()
{
::close(m_fd);

@ -41,8 +41,10 @@ public:
bool open();
int read(unsigned char* buffer, unsigned int length, struct sockaddr_storage& addr);
int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port);
bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port);
bool write(const unsigned char* buffer, unsigned int length, const struct sockaddr_storage& addr);
void close();

Loading…
Cancel
Save

Powered by TurnKey Linux.