Rewrite the networking for dual IPv4 and IPv6.

This commit is contained in:
Jonathan Naylor 2020-11-04 11:50:57 +00:00
parent ef58905da9
commit bfbdfea30b
12 changed files with 283 additions and 67 deletions

View File

@ -41,6 +41,7 @@ m_file(file),
m_callsign(),
m_rptAddress(),
m_rptPort(0U),
m_myAddress(),
m_myPort(0U),
m_debug(false),
m_daemon(false),
@ -142,6 +143,8 @@ bool CConf::read()
m_rptAddress = value;
else if (::strcmp(key, "RptPort") == 0)
m_rptPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "LocalAddress") == 0)
m_myAddress = value;
else if (::strcmp(key, "LocalPort") == 0)
m_myPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
@ -229,6 +232,11 @@ unsigned int CConf::getRptPort() const
return m_rptPort;
}
std::string CConf::getMyAddress() const
{
return m_myAddress;
}
unsigned int CConf::getMyPort() const
{
return m_myPort;

View File

@ -34,6 +34,7 @@ public:
std::string getCallsign() const;
std::string getRptAddress() const;
unsigned int getRptPort() const;
std::string getMyAddress() const;
unsigned int getMyPort() const;
bool getDebug() const;
bool getDaemon() const;
@ -77,6 +78,7 @@ private:
std::string m_callsign;
std::string m_rptAddress;
unsigned int m_rptPort;
std::string m_myAddress;
unsigned int m_myPort;
bool m_debug;
bool m_daemon;

View File

@ -1,10 +1,10 @@
CC = cc
CXX = c++
CFLAGS = -g -O3 -Wall -DHAVE_LOG_H -std=c++0x -pthread
CFLAGS = -g -O3 -Wall -DHAVE_LOG_H -DUDP_SOCKET_MAX=2 -std=c++0x -pthread
LIBS = -lpthread
LDFLAGS = -g
OBJECTS = Conf.o DMRLookup.o Log.o Mutex.o Network.o P25Gateway.o Reflectors.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o Voice.o
OBJECTS = Conf.o DMRLookup.o Log.o Mutex.o P25Gateway.o P25Network.o Reflectors.o RptNetwork.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o Voice.o
all: P25Gateway

View File

@ -17,10 +17,11 @@
*/
#include "P25Gateway.h"
#include "RptNetwork.h"
#include "P25Network.h"
#include "Reflectors.h"
#include "StopWatch.h"
#include "DMRLookup.h"
#include "Network.h"
#include "Version.h"
#include "Thread.h"
#include "Voice.h"
@ -188,14 +189,14 @@ void CP25Gateway::run()
return;
}
CNetwork localNetwork(m_conf.getMyPort(), m_conf.getCallsign(), m_conf.getDebug());
CRptNetwork localNetwork(m_conf.getMyAddress(), m_conf.getMyPort(), rptAddr, rptAddrLen, m_conf.getCallsign(), m_conf.getDebug());
ret = localNetwork.open();
if (!ret) {
::LogFinalise();
return;
}
CNetwork remoteNetwork(m_conf.getNetworkPort(), m_conf.getCallsign(), m_conf.getNetworkDebug());
CP25Network remoteNetwork(m_conf.getNetworkPort(), m_conf.getCallsign(), m_conf.getNetworkDebug());
ret = remoteNetwork.open();
if (!ret) {
localNetwork.close();
@ -266,9 +267,9 @@ void CP25Gateway::run()
staticTG.m_addrLen = reflector->m_addrLen;
staticTGs.push_back(staticTG);
remoteNetwork.writePoll(staticTG.m_addr, staticTG.m_addrLen);
remoteNetwork.writePoll(staticTG.m_addr, staticTG.m_addrLen);
remoteNetwork.writePoll(staticTG.m_addr, staticTG.m_addrLen);
remoteNetwork.poll(staticTG.m_addr, staticTG.m_addrLen);
remoteNetwork.poll(staticTG.m_addr, staticTG.m_addrLen);
remoteNetwork.poll(staticTG.m_addr, staticTG.m_addrLen);
LogMessage("Statically linked to reflector %u", *it);
}
@ -280,7 +281,7 @@ void CP25Gateway::run()
unsigned int addrLen;
// From the reflector to the MMDVM
unsigned int len = remoteNetwork.readData(buffer, 200U, addr, addrLen);
unsigned int len = remoteNetwork.read(buffer, 200U, addr, addrLen);
if (len > 0U) {
// If we're linked and it's from the right place, send it on
if (currentAddrLen > 0U && CUDPSocket::match(currentAddr, addr)) {
@ -295,7 +296,7 @@ void CP25Gateway::run()
buffer[3U] = (currentTG >> 0) & 0xFFU;
}
localNetwork.writeData(buffer, len, rptAddr, rptAddrLen);
localNetwork.write(buffer, len);
hangTimer.start();
}
@ -324,7 +325,7 @@ void CP25Gateway::run()
buffer[3U] = (currentTG >> 0) & 0xFFU;
}
localNetwork.writeData(buffer, len, rptAddr, rptAddrLen);
localNetwork.write(buffer, len);
LogMessage("Switched to reflector %u due to network activity", currentTG);
@ -336,7 +337,7 @@ void CP25Gateway::run()
}
// From the MMDVM to the reflector or control data
len = localNetwork.readData(buffer, 200U, addr, addrLen);
len = localNetwork.read(buffer, 200U);
if (len > 0U) {
if (buffer[0U] == 0x65U) {
dstTG = (buffer[1U] << 16) & 0xFF0000U;
@ -353,9 +354,9 @@ void CP25Gateway::run()
LogMessage("Unlinking from reflector %u by %s", currentTG, callsign.c_str());
if (!currentIsStatic) {
remoteNetwork.writeUnlink(currentAddr, currentAddrLen);
remoteNetwork.writeUnlink(currentAddr, currentAddrLen);
remoteNetwork.writeUnlink(currentAddr, currentAddrLen);
remoteNetwork.unlink(currentAddr, currentAddrLen);
remoteNetwork.unlink(currentAddr, currentAddrLen);
remoteNetwork.unlink(currentAddr, currentAddrLen);
}
hangTimer.stop();
@ -394,9 +395,9 @@ void CP25Gateway::run()
LogMessage("Switched to reflector %u due to RF activity from %s", currentTG, callsign.c_str());
if (!currentIsStatic) {
remoteNetwork.writePoll(currentAddr, currentAddrLen);
remoteNetwork.writePoll(currentAddr, currentAddrLen);
remoteNetwork.writePoll(currentAddr, currentAddrLen);
remoteNetwork.poll(currentAddr, currentAddrLen);
remoteNetwork.poll(currentAddr, currentAddrLen);
remoteNetwork.poll(currentAddr, currentAddrLen);
}
hangTimer.setTimeout(rfHangTime);
@ -430,7 +431,7 @@ void CP25Gateway::run()
buffer[3U] = (currentTG >> 0) & 0xFFU;
}
remoteNetwork.writeData(buffer, len, currentAddr, currentAddrLen);
remoteNetwork.write(buffer, len, currentAddr, currentAddrLen);
hangTimer.start();
}
}
@ -438,7 +439,7 @@ void CP25Gateway::run()
if (voice != NULL) {
unsigned int length = voice->read(buffer);
if (length > 0U)
localNetwork.writeData(buffer, length, rptAddr, rptAddrLen);
localNetwork.write(buffer, length);
}
if (remoteSocket != NULL) {
@ -455,9 +456,9 @@ void CP25Gateway::run()
LogMessage("Unlinked from reflector %u by remote command", currentTG);
if (!currentIsStatic) {
remoteNetwork.writeUnlink(currentAddr, currentAddrLen);
remoteNetwork.writeUnlink(currentAddr, currentAddrLen);
remoteNetwork.writeUnlink(currentAddr, currentAddrLen);
remoteNetwork.unlink(currentAddr, currentAddrLen);
remoteNetwork.unlink(currentAddr, currentAddrLen);
remoteNetwork.unlink(currentAddr, currentAddrLen);
}
hangTimer.stop();
@ -495,9 +496,9 @@ void CP25Gateway::run()
LogMessage("Switched to reflector %u by remote command", currentTG);
if (!currentIsStatic) {
remoteNetwork.writePoll(currentAddr, currentAddrLen);
remoteNetwork.writePoll(currentAddr, currentAddrLen);
remoteNetwork.writePoll(currentAddr, currentAddrLen);
remoteNetwork.poll(currentAddr, currentAddrLen);
remoteNetwork.poll(currentAddr, currentAddrLen);
remoteNetwork.poll(currentAddr, currentAddrLen);
}
hangTimer.setTimeout(rfHangTime);
@ -533,9 +534,9 @@ void CP25Gateway::run()
LogMessage("Unlinking from %u due to inactivity", currentTG);
if (!currentIsStatic) {
remoteNetwork.writeUnlink(currentAddr, currentAddrLen);
remoteNetwork.writeUnlink(currentAddr, currentAddrLen);
remoteNetwork.writeUnlink(currentAddr, currentAddrLen);
remoteNetwork.unlink(currentAddr, currentAddrLen);
remoteNetwork.unlink(currentAddr, currentAddrLen);
remoteNetwork.unlink(currentAddr, currentAddrLen);
}
if (voice != NULL)
@ -549,15 +550,17 @@ void CP25Gateway::run()
currentTG = 0U;
}
localNetwork.clock(ms);
pollTimer.clock(ms);
if (pollTimer.isRunning() && pollTimer.hasExpired()) {
// Poll the static TGs
for (std::vector<CStaticTG>::const_iterator it = staticTGs.cbegin(); it != staticTGs.cend(); ++it)
remoteNetwork.writePoll((*it).m_addr, (*it).m_addrLen);
remoteNetwork.poll((*it).m_addr, (*it).m_addrLen);
// Poll the dynamic TG
if (!currentIsStatic && currentAddrLen > 0U)
remoteNetwork.writePoll(currentAddr, currentAddrLen);
remoteNetwork.poll(currentAddr, currentAddrLen);
pollTimer.start();
}

View File

@ -2,6 +2,7 @@
Callsign=G4KLX
RptAddress=127.0.0.1
RptPort=32010
LocalAddress=127.0.0.1
LocalPort=42020
Debug=0
Daemon=1

View File

@ -87,7 +87,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>HAVE_LOG_H;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>HAVE_LOG_H;UDP_SOCKET_MAX=2;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -101,7 +101,7 @@
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>HAVE_LOG_H;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>HAVE_LOG_H;UDP_SOCKET_MAX=2;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -117,7 +117,7 @@
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>HAVE_LOG_H;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>HAVE_LOG_H;UDP_SOCKET_MAX=2;WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -135,7 +135,7 @@
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>HAVE_LOG_H;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>HAVE_LOG_H;UDP_SOCKET_MAX=2;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@ -150,9 +150,10 @@
<ClInclude Include="DMRLookup.h" />
<ClInclude Include="Log.h" />
<ClInclude Include="Mutex.h" />
<ClInclude Include="Network.h" />
<ClInclude Include="P25Gateway.h" />
<ClInclude Include="P25Network.h" />
<ClInclude Include="Reflectors.h" />
<ClInclude Include="RptNetwork.h" />
<ClInclude Include="StopWatch.h" />
<ClInclude Include="Thread.h" />
<ClInclude Include="Timer.h" />
@ -166,9 +167,10 @@
<ClCompile Include="DMRLookup.cpp" />
<ClCompile Include="Log.cpp" />
<ClCompile Include="Mutex.cpp" />
<ClCompile Include="Network.cpp" />
<ClCompile Include="P25Gateway.cpp" />
<ClCompile Include="P25Network.cpp" />
<ClCompile Include="Reflectors.cpp" />
<ClCompile Include="RptNetwork.cpp" />
<ClCompile Include="StopWatch.cpp" />
<ClCompile Include="Thread.cpp" />
<ClCompile Include="Timer.cpp" />

View File

@ -23,9 +23,6 @@
<ClInclude Include="Mutex.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Network.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25Gateway.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -53,6 +50,12 @@
<ClInclude Include="Voice.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="P25Network.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RptNetwork.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Conf.cpp">
@ -67,9 +70,6 @@
<ClCompile Include="Mutex.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Network.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="P25Gateway.cpp">
<Filter>Source Files</Filter>
</ClCompile>
@ -94,5 +94,11 @@
<ClCompile Include="Voice.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="P25Network.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="RptNetwork.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -16,7 +16,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "Network.h"
#include "P25Network.h"
#include "Utils.h"
#include "Log.h"
@ -24,26 +24,33 @@
#include <cassert>
#include <cstring>
CNetwork::CNetwork(unsigned int port, const std::string& callsign, bool debug) :
CP25Network::CP25Network(unsigned int port, const std::string& callsign, bool debug) :
m_callsign(callsign),
m_socket(port),
m_socket(),
m_port(port),
m_debug(debug)
{
assert(port > 0U);
m_callsign.resize(10U, ' ');
}
CNetwork::~CNetwork()
CP25Network::~CP25Network()
{
}
bool CNetwork::open()
bool CP25Network::open()
{
LogInfo("Opening P25 network connection");
return m_socket.open();
bool ret = m_socket.open(0, PF_INET, "", m_port);
if (!ret)
return false;
return m_socket.open(1, PF_INET6, "", m_port);
}
bool CNetwork::writeData(const unsigned char* data, unsigned int length, const sockaddr_storage& addr, unsigned int addrLen)
bool CP25Network::write(const unsigned char* data, unsigned int length, const sockaddr_storage& addr, unsigned int addrLen)
{
assert(data != NULL);
assert(length > 0U);
@ -54,7 +61,7 @@ bool CNetwork::writeData(const unsigned char* data, unsigned int length, const s
return m_socket.write(data, length, addr, addrLen);
}
bool CNetwork::writePoll(const sockaddr_storage& addr, unsigned int addrLen)
bool CP25Network::poll(const sockaddr_storage& addr, unsigned int addrLen)
{
unsigned char data[15U];
@ -69,7 +76,7 @@ bool CNetwork::writePoll(const sockaddr_storage& addr, unsigned int addrLen)
return m_socket.write(data, 11U, addr, addrLen);
}
bool CNetwork::writeUnlink(const sockaddr_storage& addr, unsigned int addrLen)
bool CP25Network::unlink(const sockaddr_storage& addr, unsigned int addrLen)
{
unsigned char data[15U];
@ -84,7 +91,7 @@ bool CNetwork::writeUnlink(const sockaddr_storage& addr, unsigned int addrLen)
return m_socket.write(data, 11U, addr, addrLen);
}
unsigned int CNetwork::readData(unsigned char* data, unsigned int length, sockaddr_storage& addr, unsigned int& addrLen)
unsigned int CP25Network::read(unsigned char* data, unsigned int length, sockaddr_storage& addr, unsigned int& addrLen)
{
assert(data != NULL);
assert(length > 0U);
@ -99,7 +106,7 @@ unsigned int CNetwork::readData(unsigned char* data, unsigned int length, sockad
return len;
}
void CNetwork::close()
void CP25Network::close()
{
m_socket.close();

View File

@ -16,35 +16,36 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef Network_H
#define Network_H
#ifndef P25Network_H
#define P25Network_H
#include "UDPSocket.h"
#include <cstdint>
#include <string>
class CNetwork {
class CP25Network {
public:
CNetwork(unsigned int port, const std::string& callsign, bool debug);
~CNetwork();
CP25Network(unsigned int port, const std::string& callsign, bool debug);
~CP25Network();
bool open();
bool writeData(const unsigned char* data, unsigned int length, const sockaddr_storage& addr, unsigned int addrLen);
bool write(const unsigned char* data, unsigned int length, const sockaddr_storage& addr, unsigned int addrLen);
unsigned int readData(unsigned char* data, unsigned int length, sockaddr_storage& addr, unsigned int& addrLen);
unsigned int read(unsigned char* data, unsigned int length, sockaddr_storage& addr, unsigned int& addrLen);
bool writePoll(const sockaddr_storage& addr, unsigned int addrLen);
bool poll(const sockaddr_storage& addr, unsigned int addrLen);
bool writeUnlink(const sockaddr_storage& addr, unsigned int addrLen);
bool unlink(const sockaddr_storage& addr, unsigned int addrLen);
void close();
private:
std::string m_callsign;
CUDPSocket m_socket;
bool m_debug;
std::string m_callsign;
CUDPSocket m_socket;
unsigned int m_port;
bool m_debug;
};
#endif

130
P25Gateway/RptNetwork.cpp Normal file
View File

@ -0,0 +1,130 @@
/*
* Copyright (C) 2009-2014,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 "RptNetwork.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
CRptNetwork::CRptNetwork(const std::string& myAddr, unsigned int myPort, const sockaddr_storage& rptAddr, unsigned int rptAddrLen, const std::string& callsign, bool debug) :
m_myAddr(),
m_myAddrLen(0U),
m_rptAddr(rptAddr),
m_rptAddrLen(rptAddrLen),
m_callsign(callsign),
m_socket(myAddr, myPort),
m_debug(debug),
m_timer(1000U, 5U)
{
assert(myPort > 0U);
assert(rptAddrLen > 0U);
CUDPSocket::lookup(myAddr, myPort, m_myAddr, m_myAddrLen);
m_callsign.resize(10U, ' ');
}
CRptNetwork::~CRptNetwork()
{
}
bool CRptNetwork::open()
{
if (m_myAddrLen == 0U) {
LogError("Unable to resolve the local address and port");
return false;
}
LogInfo("Opening Rpt network connection");
bool ret = m_socket.open(m_myAddr);
if (ret) {
m_timer.start();
return true;
} else {
return false;
}
}
bool CRptNetwork::write(const unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
if (m_debug)
CUtils::dump(1U, "Rpt Network Data Sent", data, length);
return m_socket.write(data, length, m_rptAddr, m_rptAddrLen);
}
bool CRptNetwork::writePoll()
{
unsigned char data[15U];
data[0U] = 0xF0U;
for (unsigned int i = 0U; i < 10U; i++)
data[i + 1U] = m_callsign.at(i);
if (m_debug)
CUtils::dump(1U, "Rpt Network Poll Sent", data, 11U);
return m_socket.write(data, 11U, m_rptAddr, m_rptAddrLen);
}
unsigned int CRptNetwork::read(unsigned char* data, unsigned int length)
{
assert(data != NULL);
assert(length > 0U);
sockaddr_storage addr;
unsigned int addrLen = 0U;
int len = m_socket.read(data, length, addr, addrLen);
if (len <= 0)
return 0U;
if (!CUDPSocket::match(addr, m_rptAddr))
return 0U;
if (m_debug)
CUtils::dump(1U, "Rpt Network Data Received", data, len);
return len;
}
void CRptNetwork::clock(unsigned int ms)
{
m_timer.clock(ms);
if (m_timer.isRunning() && m_timer.hasExpired()) {
writePoll();
m_timer.start();
}
}
void CRptNetwork::close()
{
m_timer.stop();
m_socket.close();
LogInfo("Closing Rpt network connection");
}

56
P25Gateway/RptNetwork.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2009-2014,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.
*/
#ifndef RptNetwork_H
#define RptNetwork_H
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
class CRptNetwork {
public:
CRptNetwork(const std::string& myAddr, unsigned int myPort, const sockaddr_storage& rptAddr, unsigned int rptAddrLen, const std::string& callsign, bool debug);
~CRptNetwork();
bool open();
bool write(const unsigned char* data, unsigned int length);
unsigned int read(unsigned char* data, unsigned int length);
void clock(unsigned int ms);
void close();
private:
sockaddr_storage m_myAddr;
unsigned int m_myAddrLen;
sockaddr_storage m_rptAddr;
unsigned int m_rptAddrLen;
std::string m_callsign;
CUDPSocket m_socket;
bool m_debug;
CTimer m_timer;
bool writePoll();
};
#endif

View File

@ -19,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20201102";
const char* VERSION = "20201104";
#endif