Allow IAX to lookup hosts from a master hosts file and reduce the

polling frequency for NEW commands.
This commit is contained in:
Jonathan Naylor
2024-11-01 16:36:53 +00:00
parent 724a44e0c4
commit a2f0d1c81c
12 changed files with 432 additions and 307 deletions

236
Conf.cpp
View File

@@ -54,6 +54,9 @@ enum SECTION {
SECTION_M17_NETWORK,
SECTION_POCSAG_NETWORK,
SECTION_FM_NETWORK,
SECTION_USRP_NETWORK,
SECTION_RAW_NETWORK,
SECTION_IAX_NETWORK,
SECTION_AX25_NETWORK,
SECTION_TFTSERIAL,
SECTION_HD44780,
@@ -290,22 +293,30 @@ m_pocsagNetworkModeHang(3U),
m_pocsagNetworkDebug(false),
m_fmNetworkEnabled(false),
m_fmNetworkProtocol("USRP"),
m_fmNetworkDomain("register.allstarlink.org"),
m_fmNetworkPassword(),
m_fmNetworkSource(),
m_fmNetworkDestination(),
m_fmNetworkSampleRate(48000U),
m_fmNetworkSquelchFile(),
m_fmGatewayAddress(),
m_fmGatewayPort(0U),
m_fmLocalAddress(),
m_fmLocalPort(0U),
m_fmPreEmphasis(true),
m_fmDeEmphasis(true),
m_fmTXAudioGain(1.0F),
m_fmRXAudioGain(1.0F),
m_fmNetworkModeHang(3U),
m_fmNetworkDebug(false),
m_usrpGatewayAddress(),
m_usrpGatewayPort(0U),
m_usrpLocalAddress("127.0.0.1"),
m_usrpLocalPort(0U),
m_rawGatewayAddress(),
m_rawGatewayPort(0U),
m_rawLocalAddress("127.0.0.1"),
m_rawLocalPort(0U),
m_rawSampleRate(48000U),
m_rawSquelchFile(),
m_iaxHostsFile1("IAXHosts.txt"),
m_iaxHostsFile2(),
m_iaxAuthAddress("register.allstarlink.org"),
m_iaxAuthPort(4569U),
m_iaxLocalPort(4569U),
m_iaxPassword(),
m_iaxSourceId(),
m_iaxDestinationId(),
m_ax25NetworkEnabled(false),
m_ax25NetworkPort(),
m_ax25NetworkSpeed(9600U),
@@ -422,6 +433,12 @@ bool CConf::read()
section = SECTION_POCSAG_NETWORK;
else if (::strncmp(buffer, "[FM Network]", 12U) == 0)
section = SECTION_FM_NETWORK;
else if (::strncmp(buffer, "[USRP Network]", 14U) == 0)
section = SECTION_USRP_NETWORK;
else if (::strncmp(buffer, "[RAW Network]", 13U) == 0)
section = SECTION_RAW_NETWORK;
else if (::strncmp(buffer, "[IAX Network]", 13U) == 0)
section = SECTION_IAX_NETWORK;
else if (::strncmp(buffer, "[AX.25 Network]", 15U) == 0)
section = SECTION_AX25_NETWORK;
else if (::strncmp(buffer, "[TFT Serial]", 12U) == 0)
@@ -1042,26 +1059,6 @@ bool CConf::read()
m_fmNetworkEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Protocol") == 0)
m_fmNetworkProtocol = value;
else if (::strcmp(key, "Domain") == 0)
m_fmNetworkDomain = value;
else if (::strcmp(key, "Password") == 0)
m_fmNetworkPassword = value;
else if (::strcmp(key, "Source") == 0)
m_fmNetworkSource = value;
else if (::strcmp(key, "Destination") == 0)
m_fmNetworkDestination = value;
else if (::strcmp(key, "SampleRate") == 0)
m_fmNetworkSampleRate = (unsigned int)::atoi(value);
else if (::strcmp(key, "SquelchFile") == 0)
m_fmNetworkSquelchFile = value;
else if (::strcmp(key, "LocalAddress") == 0)
m_fmLocalAddress = value;
else if (::strcmp(key, "LocalPort") == 0)
m_fmLocalPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "GatewayAddress") == 0)
m_fmGatewayAddress = value;
else if (::strcmp(key, "GatewayPort") == 0)
m_fmGatewayPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "PreEmphasis") == 0)
m_fmPreEmphasis = ::atoi(value) == 1;
else if (::strcmp(key, "DeEmphasis") == 0)
@@ -1074,6 +1071,45 @@ bool CConf::read()
m_fmNetworkModeHang = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_fmNetworkDebug = ::atoi(value) == 1;
} else if (section == SECTION_USRP_NETWORK) {
if (::strcmp(key, "GatewayAddress") == 0)
m_usrpGatewayAddress = value;
else if (::strcmp(key, "GatewayPort") == 0)
m_usrpGatewayPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "LocalAddress") == 0)
m_usrpLocalAddress = value;
else if (::strcmp(key, "LocalPort") == 0)
m_usrpLocalPort = (unsigned short)::atoi(value);
} else if (section == SECTION_RAW_NETWORK) {
if (::strcmp(key, "GatewayAddress") == 0)
m_rawGatewayAddress = value;
else if (::strcmp(key, "GatewayPort") == 0)
m_rawGatewayPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "LocalAddress") == 0)
m_rawLocalAddress = value;
else if (::strcmp(key, "LocalPort") == 0)
m_rawLocalPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "SampleRate") == 0)
m_rawSampleRate = (unsigned int)::atoi(value);
else if (::strcmp(key, "SquelchFile") == 0)
m_rawSquelchFile = value;
} else if (section == SECTION_IAX_NETWORK) {
if (::strcmp(key, "HostsFile1") == 0)
m_iaxHostsFile1 = value;
else if (::strcmp(key, "HostsFile2") == 0)
m_iaxHostsFile2 = value;
else if (::strcmp(key, "AuthAddress") == 0)
m_iaxAuthAddress = value;
else if (::strcmp(key, "AuthPort") == 0)
m_iaxAuthPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "LocalPort") == 0)
m_iaxLocalPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "Password") == 0)
m_iaxPassword = value;
else if (::strcmp(key, "SourceId") == 0)
m_iaxSourceId = value;
else if (::strcmp(key, "DestinationId") == 0)
m_iaxDestinationId = value;
} else if (section == SECTION_AX25_NETWORK) {
if (::strcmp(key, "Enable") == 0)
m_ax25NetworkEnabled = ::atoi(value) == 1;
@@ -2300,56 +2336,6 @@ std::string CConf::getFMNetworkProtocol() const
return m_fmNetworkProtocol;
}
std::string CConf::getFMNetworkDomain() const
{
return m_fmNetworkDomain;
}
std::string CConf::getFMNetworkPassword() const
{
return m_fmNetworkPassword;
}
std::string CConf::getFMNetworkSource() const
{
return m_fmNetworkSource;
}
std::string CConf::getFMNetworkDestination() const
{
return m_fmNetworkDestination;
}
unsigned int CConf::getFMNetworkSampleRate() const
{
return m_fmNetworkSampleRate;
}
std::string CConf::getFMNetworkSquelchFile() const
{
return m_fmNetworkSquelchFile;
}
std::string CConf::getFMGatewayAddress() const
{
return m_fmGatewayAddress;
}
unsigned short CConf::getFMGatewayPort() const
{
return m_fmGatewayPort;
}
std::string CConf::getFMLocalAddress() const
{
return m_fmLocalAddress;
}
unsigned short CConf::getFMLocalPort() const
{
return m_fmLocalPort;
}
bool CConf::getFMPreEmphasis() const
{
return m_fmPreEmphasis;
@@ -2380,6 +2366,96 @@ bool CConf::getFMNetworkDebug() const
return m_fmNetworkDebug;
}
std::string CConf::getUSRPGatewayAddress() const
{
return m_usrpGatewayAddress;
}
unsigned short CConf::getUSRPGatewayPort() const
{
return m_usrpGatewayPort;
}
std::string CConf::getUSRPLocalAddress() const
{
return m_usrpLocalAddress;
}
unsigned short CConf::getUSRPLocalPort() const
{
return m_usrpLocalPort;
}
std::string CConf::getRAWGatewayAddress() const
{
return m_rawGatewayAddress;
}
unsigned short CConf::getRAWGatewayPort() const
{
return m_rawGatewayPort;
}
std::string CConf::getRAWLocalAddress() const
{
return m_rawLocalAddress;
}
unsigned short CConf::getRAWLocalPort() const
{
return m_rawLocalPort;
}
unsigned int CConf::getRAWSampleRate() const
{
return m_rawSampleRate;
}
std::string CConf::getRAWSquelchFile() const
{
return m_rawSquelchFile;
}
std::string CConf::getIAXHostsFile1() const
{
return m_iaxHostsFile1;
}
std::string CConf::getIAXHostsFile2() const
{
return m_iaxHostsFile2;
}
std::string CConf::getIAXAuthAddress() const
{
return m_iaxAuthAddress;
}
unsigned short CConf::getIAXAuthPort() const
{
return m_iaxAuthPort;
}
unsigned short CConf::getIAXLocalPort() const
{
return m_iaxLocalPort;
}
std::string CConf::getIAXPassword() const
{
return m_iaxPassword;
}
std::string CConf::getIAXSourceId() const
{
return m_iaxSourceId;
}
std::string CConf::getIAXDestinationId() const
{
return m_iaxDestinationId;
}
bool CConf::getAX25NetworkEnabled() const
{
return m_ax25NetworkEnabled;

65
Conf.h
View File

@@ -303,16 +303,6 @@ public:
// The FM Network section
bool getFMNetworkEnabled() const;
std::string getFMNetworkProtocol() const;
std::string getFMNetworkDomain() const;
std::string getFMNetworkPassword() const;
std::string getFMNetworkSource() const;
std::string getFMNetworkDestination() const;
unsigned int getFMNetworkSampleRate() const;
std::string getFMNetworkSquelchFile() const;
std::string getFMGatewayAddress() const;
unsigned short getFMGatewayPort() const;
std::string getFMLocalAddress() const;
unsigned short getFMLocalPort() const;
bool getFMPreEmphasis() const;
bool getFMDeEmphasis() const;
float getFMTXAudioGain() const;
@@ -320,6 +310,30 @@ public:
unsigned int getFMNetworkModeHang() const;
bool getFMNetworkDebug() const;
// The USRP Network section
std::string getUSRPGatewayAddress() const;
unsigned short getUSRPGatewayPort() const;
std::string getUSRPLocalAddress() const;
unsigned short getUSRPLocalPort() const;
// The RAW Network section
std::string getRAWGatewayAddress() const;
unsigned short getRAWGatewayPort() const;
std::string getRAWLocalAddress() const;
unsigned short getRAWLocalPort() const;
unsigned int getRAWSampleRate() const;
std::string getRAWSquelchFile() const;
// The IAX Network section
std::string getIAXHostsFile1() const;
std::string getIAXHostsFile2() const;
std::string getIAXAuthAddress() const;
unsigned short getIAXAuthPort() const;
unsigned short getIAXLocalPort() const;
std::string getIAXPassword() const;
std::string getIAXSourceId() const;
std::string getIAXDestinationId() const;
// The AX.25 Network section
bool getAX25NetworkEnabled() const;
std::string getAX25NetworkPort() const;
@@ -629,16 +643,6 @@ private:
bool m_fmNetworkEnabled;
std::string m_fmNetworkProtocol;
std::string m_fmNetworkDomain;
std::string m_fmNetworkPassword;
std::string m_fmNetworkSource;
std::string m_fmNetworkDestination;
unsigned int m_fmNetworkSampleRate;
std::string m_fmNetworkSquelchFile;
std::string m_fmGatewayAddress;
unsigned short m_fmGatewayPort;
std::string m_fmLocalAddress;
unsigned short m_fmLocalPort;
bool m_fmPreEmphasis;
bool m_fmDeEmphasis;
float m_fmTXAudioGain;
@@ -646,6 +650,27 @@ private:
unsigned int m_fmNetworkModeHang;
bool m_fmNetworkDebug;
std::string m_usrpGatewayAddress;
unsigned short m_usrpGatewayPort;
std::string m_usrpLocalAddress;
unsigned short m_usrpLocalPort;
std::string m_rawGatewayAddress;
unsigned short m_rawGatewayPort;
std::string m_rawLocalAddress;
unsigned short m_rawLocalPort;
unsigned int m_rawSampleRate;
std::string m_rawSquelchFile;
std::string m_iaxHostsFile1;
std::string m_iaxHostsFile2;
std::string m_iaxAuthAddress;
unsigned short m_iaxAuthPort;
unsigned short m_iaxLocalPort;
std::string m_iaxPassword;
std::string m_iaxSourceId;
std::string m_iaxDestinationId;
bool m_ax25NetworkEnabled;
std::string m_ax25NetworkPort;
unsigned int m_ax25NetworkSpeed;

View File

@@ -33,8 +33,6 @@
#include <unistd.h>
#endif
#define DEBUG_IAX
const unsigned char IAX_PROTO_VERSION = 2U;
const unsigned char AST_FRAME_DTMF = 1U;
@@ -123,20 +121,22 @@ const unsigned char IAX_IE_CALLTOKEN = 54U;
const unsigned int BUFFER_LENGTH = 1500U;
CFMIAXNetwork::CFMIAXNetwork(const std::string& domain, const std::string& password, const std::string& source, const std::string& destination, const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, bool debug) :
CFMIAXNetwork::CFMIAXNetwork(const std::string& hostFile1, const std::string& hostFile2, const std::string& authAddress, unsigned short authPort, unsigned short localPort, const std::string& password, const std::string& sourceId, const std::string& destinationId, bool debug) :
m_hostFile1(hostFile1),
m_hostFile2(hostFile2),
m_password(password),
m_source(source),
m_destination(destination),
m_socket(localAddress, localPort),
m_domainAddr(),
m_domainAddrLen(0U),
m_authAddr(),
m_authAddrLen(0U),
m_sourceId(sourceId),
m_destinationId(destinationId),
m_socket(localPort),
m_serverAddr(),
m_serverAddrLen(0U),
m_debug(debug),
m_enabled(false),
m_buffer(2000U, "FM Network"),
m_status(IAXS_DISCONNECTED),
m_retryTimer(1000U, 0U, 500U),
m_retryTimer(1000U, 5U),
m_pingTimer(1000U, 2U),
m_seed(),
m_timestamp(),
@@ -154,23 +154,20 @@ m_rxDelay(0U),
m_rxDropped(0U),
m_rxOOO(0U),
m_keyed(false),
m_random()
m_random(),
m_hosts()
#if defined(_WIN32) || defined(_WIN64)
, m_provider(0UL)
#endif
{
assert(!domain.empty());
assert(!hostFile1.empty());
assert(!authAddress.empty());
assert(!password.empty());
assert(!source.empty());
assert(!destination.empty());
assert(gatewayPort > 0U);
assert(!gatewayAddress.empty());
assert(!sourceId.empty());
assert(!destinationId.empty());
if (CUDPSocket::lookup(domain, gatewayPort, m_domainAddr, m_domainAddrLen) != 0)
m_domainAddrLen = 0U;
if (CUDPSocket::lookup(gatewayAddress, gatewayPort, m_serverAddr, m_serverAddrLen) != 0)
m_serverAddrLen = 0U;
if (CUDPSocket::lookup(authAddress, authPort, m_authAddr, m_authAddrLen) != 0)
m_authAddrLen = 0U;
std::random_device rd;
std::mt19937 mt(rd());
@@ -183,14 +180,19 @@ CFMIAXNetwork::~CFMIAXNetwork()
bool CFMIAXNetwork::open()
{
if (m_domainAddrLen == 0U) {
LogError("Unable to resolve the address of the ASL Registration Server");
if (m_authAddrLen == 0U) {
LogError("Unable to resolve the address of the Authorisation Server");
return false;
}
if (m_serverAddrLen == 0U) {
LogError("Unable to resolve the address of the IAX Gateway");
bool ret = loadHostsFile(m_hostFile1);
if (!ret)
return false;
if (!m_hostFile2.empty()) {
ret = loadHostsFile(m_hostFile2);
if (!ret)
return false;
}
LogMessage("Opening FM IAX network connection");
@@ -202,7 +204,13 @@ bool CFMIAXNetwork::open()
}
#endif
bool ret = m_socket.open(m_domainAddr);
ret = lookupHost();
if (!ret) {
LogError("Cannot find the destination id of %s in the IAX hosts file", m_destinationId.c_str());
return false;
}
ret = m_socket.open(m_authAddr);
if (!ret)
return false;
@@ -307,7 +315,7 @@ void CFMIAXNetwork::clock(unsigned int ms)
return;
// Check if the data is for us
if (!CUDPSocket::match(addr, m_domainAddr, IMT_ADDRESS_AND_PORT) &&
if (!CUDPSocket::match(addr, m_authAddr, IMT_ADDRESS_AND_PORT) &&
!CUDPSocket::match(addr, m_serverAddr, IMT_ADDRESS_AND_PORT)) {
LogMessage("FM IAX packet received from an invalid source");
return;
@@ -320,33 +328,18 @@ void CFMIAXNetwork::clock(unsigned int ms)
unsigned char iSeqNo = buffer[8U];
if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_ACK)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
LogDebug("IAX ACK received");
#endif
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_PING)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
LogDebug("IAX PING received");
#endif
m_rxFrames++;
m_iSeqNo = iSeqNo + 1U;
writeAck(addr, addrLen, ts);
writePong(addr, addrLen, ts);
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_PONG)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
LogDebug("IAX PONG received");
#endif
m_rxFrames++;
m_iSeqNo = iSeqNo + 1U;
writeAck(addr, addrLen, ts);
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_CALLTOKEN)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
#endif
m_dLinkCallNo = ((buffer[0U] << 8) | (buffer[1U] << 0)) & 0x7FFFU;
m_callToken = getIEString(buffer, length, IAX_IE_CALLTOKEN);
@@ -355,9 +348,6 @@ void CFMIAXNetwork::clock(unsigned int ms)
writeNew();
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_ACCEPT)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
#endif
m_rxFrames++;
m_iSeqNo = iSeqNo + 1U;
@@ -369,10 +359,6 @@ void CFMIAXNetwork::clock(unsigned int ms)
m_retryTimer.stop();
m_pingTimer.start();
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_REGREJ)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
LogDebug("IAX REGREJ received");
#endif
LogError("Registraton rejected by the IAX gateway");
m_iSeqNo = iSeqNo + 1U;
@@ -385,9 +371,6 @@ void CFMIAXNetwork::clock(unsigned int ms)
m_retryTimer.stop();
m_pingTimer.stop();
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_REJECT)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
#endif
LogError("Command rejected by the IAX gateway");
m_iSeqNo = iSeqNo + 1U;
@@ -400,10 +383,6 @@ void CFMIAXNetwork::clock(unsigned int ms)
m_retryTimer.stop();
m_pingTimer.stop();
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_REGAUTH)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
LogDebug("IAX REGAUTH received");
#endif
m_dAuthCallNo = ((buffer[0U] << 8) | (buffer[1U] << 0)) & 0x7FFFU;
m_rxFrames++;
@@ -426,10 +405,6 @@ void CFMIAXNetwork::clock(unsigned int ms)
writeRegReq();
}
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_REGACK)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
LogDebug("IAX REGACK received");
#endif
LogError("Registraton accepted by the IAX gateway");
m_rxFrames++;
@@ -445,9 +420,6 @@ void CFMIAXNetwork::clock(unsigned int ms)
m_retryTimer.start();
m_pingTimer.stop();
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_HANGUP)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
#endif
LogError("Hangup from the IAX gateway");
m_iSeqNo = iSeqNo + 1U;
@@ -459,9 +431,6 @@ void CFMIAXNetwork::clock(unsigned int ms)
m_retryTimer.stop();
m_pingTimer.stop();
} else if (compareFrame(buffer, AST_FRAME_CONTROL, AST_CONTROL_ANSWER)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
#endif
m_rxFrames++;
m_iSeqNo = iSeqNo + 1U;
@@ -469,9 +438,6 @@ void CFMIAXNetwork::clock(unsigned int ms)
writeAck(addr, addrLen, ts);
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_VNAK)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
#endif
LogError("Messages rejected by the IAX gateway");
m_rxFrames++;
@@ -479,38 +445,23 @@ void CFMIAXNetwork::clock(unsigned int ms)
writeAck(addr, addrLen, ts);
} else if (compareFrame(buffer, AST_FRAME_TEXT, 0U)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
#endif
m_iSeqNo = iSeqNo + 1U;
LogMessage("IAX TEXT received - %.*s", length - 12U, buffer + 12U);
writeAck(addr, addrLen, ts);
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_LAGRQ)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
LogDebug("IAX LAGRQ received");
#endif
m_rxFrames++;
m_iSeqNo = iSeqNo + 1U;
writeLagRq(addr, addrLen);
writeLagRp(addr, addrLen, ts);
} else if (compareFrame(buffer, AST_FRAME_IAX, IAX_COMMAND_LAGRP)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
LogDebug("IAX LAGRP received");
#endif
m_rxFrames++;
m_iSeqNo = iSeqNo + 1U;
writeAck(addr, addrLen, ts);
} else if (compareFrame(buffer, AST_FRAME_CONTROL, AST_CONTROL_KEY)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
LogDebug("IAX KEY received");
#endif
m_rxFrames++;
m_iSeqNo = iSeqNo + 1U;
@@ -518,10 +469,6 @@ void CFMIAXNetwork::clock(unsigned int ms)
m_keyed = true;
} else if (compareFrame(buffer, AST_FRAME_CONTROL, AST_CONTROL_UNKEY)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
LogDebug("IAX UNKEY received");
#endif
m_rxFrames++;
m_iSeqNo = iSeqNo + 1U;
@@ -529,10 +476,6 @@ void CFMIAXNetwork::clock(unsigned int ms)
m_keyed = false;
} else if (compareFrame(buffer, AST_FRAME_VOICE, AST_FORMAT_ULAW)) {
#if defined(DEBUG_IAX)
CUtils::dump(1U, "FM IAX Network Data Received", buffer, length);
LogDebug("IAX ULAW received");
#endif
m_rxFrames++;
m_iSeqNo = iSeqNo + 1U;
@@ -546,9 +489,6 @@ void CFMIAXNetwork::clock(unsigned int ms)
m_buffer.addData(buffer + 12U, length - 12U);
} else if ((buffer[0U] & 0x80U) == 0x00U) {
#if defined(DEBUG_IAX)
LogDebug("IAX audio received");
#endif
if (!m_enabled)
return;
@@ -628,10 +568,6 @@ void CFMIAXNetwork::enable(bool enabled)
bool CFMIAXNetwork::writeNew()
{
#if defined(DEBUG_IAX)
LogDebug("IAX NEW sent");
#endif
unsigned short sCall = m_sLinkCallNo | 0x8000U;
m_timestamp.start();
@@ -663,9 +599,9 @@ bool CFMIAXNetwork::writeNew()
unsigned int pos = 0U;
setIEUInt16(buffer, pos, IAX_IE_VERSION, IAX_PROTO_VERSION);
setIEString(buffer, pos, IAX_IE_CALLED_NUMBER, m_destination);
setIEString(buffer, pos, IAX_IE_CALLED_NUMBER, m_destinationId);
setIEString(buffer, pos, IAX_IE_CODEC_PREFS, "DMLC");
setIEString(buffer, pos, IAX_IE_CALLING_NUMBER, m_source);
setIEString(buffer, pos, IAX_IE_CALLING_NUMBER, m_sourceId);
setIEUInt8(buffer, pos, IAX_IE_CALLINGPRES, 0U);
setIEUInt8(buffer, pos, IAX_IE_CALLINGTON, 0U);
setIEUInt16(buffer, pos, IAX_IE_CALLINGTNS, 0U);
@@ -681,9 +617,7 @@ bool CFMIAXNetwork::writeNew()
length = setIEString(buffer, pos, IAX_IE_CALLTOKEN, m_callToken);
#if !defined(DEBUG_IAX)
if (m_debug)
#endif
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, length);
m_oSeqNo++;
@@ -693,10 +627,6 @@ bool CFMIAXNetwork::writeNew()
bool CFMIAXNetwork::writeKey(bool key)
{
#if defined(DEBUG_IAX)
LogDebug("IAX KEY/UNKEY sent");
#endif
unsigned short sCall = m_sLinkCallNo | 0x8000U;
unsigned int ts = m_timestamp.elapsed();
@@ -721,9 +651,7 @@ bool CFMIAXNetwork::writeKey(bool key)
buffer[11U] = key ? AST_CONTROL_KEY : AST_CONTROL_UNKEY;
#if !defined(DEBUG_IAX)
if (m_debug)
#endif
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, 12U);
m_oSeqNo++;
@@ -735,10 +663,6 @@ bool CFMIAXNetwork::writePing(const sockaddr_storage& addr, unsigned int addrLen
{
assert(addrLen > 0U);
#if defined(DEBUG_IAX)
LogDebug("IAX PING sent");
#endif
unsigned short sCall = m_sLinkCallNo | 0x8000U;
unsigned int ts = m_timestamp.elapsed();
@@ -763,9 +687,7 @@ bool CFMIAXNetwork::writePing(const sockaddr_storage& addr, unsigned int addrLen
buffer[11U] = IAX_COMMAND_PING;
#if !defined(DEBUG_IAX)
if (m_debug)
#endif
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, 12U);
m_oSeqNo++;
@@ -777,10 +699,6 @@ bool CFMIAXNetwork::writePong(const sockaddr_storage& addr, unsigned int addrLen
{
assert(addrLen > 0U);
#if defined(DEBUG_IAX)
LogDebug("IAX PONG sent");
#endif
unsigned short sCall = m_sLinkCallNo | 0x8000U;
unsigned char buffer[50U];
@@ -817,9 +735,7 @@ bool CFMIAXNetwork::writePong(const sockaddr_storage& addr, unsigned int addrLen
setIEUInt32(buffer, pos, IAX_IE_RR_DROPPED, m_rxDropped);
setIEUInt32(buffer, pos, IAX_IE_RR_OOO, m_rxOOO);
#if !defined(DEBUG_IAX)
if (m_debug)
#endif
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, 46U);
m_oSeqNo++;
@@ -831,10 +747,6 @@ bool CFMIAXNetwork::writeAck(const sockaddr_storage& addr, unsigned int addrLen,
{
assert(addrLen > 0U);
#if defined(DEBUG_IAX)
LogDebug("IAX ACK sent");
#endif
unsigned short sCallNo = 0U;
unsigned short dCallNo = 0U;
@@ -867,9 +779,7 @@ bool CFMIAXNetwork::writeAck(const sockaddr_storage& addr, unsigned int addrLen,
buffer[11U] = IAX_COMMAND_ACK;
#if !defined(DEBUG_IAX)
if (m_debug)
#endif
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, 12U);
return m_socket.write(buffer, 12U, addr, addrLen);
@@ -879,10 +789,6 @@ bool CFMIAXNetwork::writeLagRp(const sockaddr_storage& addr, unsigned int addrLe
{
assert(addrLen > 0U);
#if defined(DEBUG_IAX)
LogDebug("IAX LAGRP sent");
#endif
unsigned short sCall = m_sLinkCallNo | 0x8000U;
unsigned char buffer[15U];
@@ -906,9 +812,7 @@ bool CFMIAXNetwork::writeLagRp(const sockaddr_storage& addr, unsigned int addrLe
buffer[11U] = IAX_COMMAND_LAGRP;
#if !defined(DEBUG_IAX)
if (m_debug)
#endif
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, 12U);
m_oSeqNo++;
@@ -920,10 +824,6 @@ bool CFMIAXNetwork::writeLagRq(const sockaddr_storage& addr, unsigned int addrLe
{
assert(addrLen > 0U);
#if defined(DEBUG_IAX)
LogDebug("IAX LAGRQ sent");
#endif
unsigned short sCall = m_sLinkCallNo | 0x8000U;
unsigned int ts = m_timestamp.elapsed();
@@ -948,9 +848,7 @@ bool CFMIAXNetwork::writeLagRq(const sockaddr_storage& addr, unsigned int addrLe
buffer[11U] = IAX_COMMAND_LAGRQ;
#if !defined(DEBUG_IAX)
if (m_debug)
#endif
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, 12U);
m_oSeqNo++;
@@ -960,10 +858,6 @@ bool CFMIAXNetwork::writeLagRq(const sockaddr_storage& addr, unsigned int addrLe
bool CFMIAXNetwork::writeHangup()
{
#if defined(DEBUG_IAX)
LogDebug("IAX HANGUP sent");
#endif
unsigned short sCall = m_sLinkCallNo | 0x8000U;
unsigned int ts = m_timestamp.elapsed();
@@ -991,11 +885,8 @@ bool CFMIAXNetwork::writeHangup()
unsigned int pos = 0U;
unsigned int length = setIEUInt8(buffer, pos, IAX_IE_CAUSE, 0x00U);
#if !defined(DEBUG_IAX)
if (m_debug)
#endif
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, length);
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, length);
m_oSeqNo++;
@@ -1064,10 +955,6 @@ bool CFMIAXNetwork::writeRegReq()
{
const unsigned short REFRESH_TIME = 60U;
#if defined(DEBUG_IAX)
LogDebug("IAX REGREQ sent");
#endif
unsigned short sCall = m_sAuthCallNo | 0x8000U;
unsigned short dCall = m_dAuthCallNo;
@@ -1095,7 +982,7 @@ bool CFMIAXNetwork::writeRegReq()
buffer[11U] = IAX_COMMAND_REGREQ;
unsigned int pos = 0U;
setIEString(buffer, pos, IAX_IE_USERNAME, m_source);
setIEString(buffer, pos, IAX_IE_USERNAME, m_sourceId);
setIEUInt16(buffer, pos, IAX_IE_REFRESH, REFRESH_TIME);
@@ -1145,12 +1032,10 @@ bool CFMIAXNetwork::writeRegReq()
unsigned int length = setIEString(buffer, pos, IAX_IE_CALLTOKEN, m_callToken);
#if !defined(DEBUG_IAX)
if (m_debug)
#endif
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, length);
return m_socket.write(buffer, length, m_domainAddr, m_domainAddrLen);
return m_socket.write(buffer, length, m_authAddr, m_authAddrLen);
}
bool CFMIAXNetwork::writeAudio(const short* audio, unsigned int length)
@@ -1158,10 +1043,6 @@ bool CFMIAXNetwork::writeAudio(const short* audio, unsigned int length)
assert(audio != NULL);
assert(length > 0U);
#if defined(DEBUG_IAX)
LogDebug("IAX ULAW sent");
#endif
unsigned short sCall = m_sLinkCallNo | 0x8000U;
unsigned int ts = m_timestamp.elapsed();
@@ -1188,9 +1069,7 @@ bool CFMIAXNetwork::writeAudio(const short* audio, unsigned int length)
uLawEncode(audio, buffer + 12U, length);
#if !defined(DEBUG_IAX)
if (m_debug)
#endif
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, 12U + length);
m_oSeqNo++;
@@ -1203,9 +1082,6 @@ bool CFMIAXNetwork::writeMiniFrame(const short* audio, unsigned int length)
assert(audio != NULL);
assert(length > 0U);
#if defined(DEBUG_IAX)
LogDebug("IAX audio sent");
#endif
unsigned short ts = m_timestamp.elapsed();
unsigned char buffer[300U];
@@ -1218,9 +1094,7 @@ bool CFMIAXNetwork::writeMiniFrame(const short* audio, unsigned int length)
uLawEncode(audio, buffer + 4U, length);
#if !defined(DEBUG_IAX)
if (m_debug)
#endif
CUtils::dump(1U, "FM IAX Network Data Sent", buffer, 4U + length);
return m_socket.write(buffer, 4U + length, m_serverAddr, m_serverAddrLen);
@@ -1459,3 +1333,78 @@ uint8_t CFMIAXNetwork::getIEUInt8(const unsigned char* buffer, unsigned int leng
return 0U;
}
std::string CFMIAXNetwork::getAddress()
{
if (m_serverAddrLen == 0U)
return "NONE";
char buffer1[250U];
char buffer2[250U];
int ret = ::getnameinfo((sockaddr*)&m_serverAddr, m_serverAddrLen, buffer1, 250, buffer2, 250, NI_NUMERICHOST | NI_NUMERICSERV);
if (ret != 0)
return "NONE";
return std::string(buffer1);
}
bool CFMIAXNetwork::loadHostsFile(const std::string& fileName)
{
assert(!fileName.empty());
FILE* fp = ::fopen(fileName.c_str(), "rt");
if (fp == NULL) {
LogError("Cannot open the IAX hosts file - %s", fileName.c_str());
return false;
}
char buffer[BUFFER_LENGTH];
unsigned int n = 0U;
while (::fgets(buffer, BUFFER_LENGTH, fp) != NULL) {
if ((buffer[0U] < '0') || (buffer[0U] > '9'))
continue;
char* p1 = ::strtok(buffer, "=");
char* p2 = ::strtok(NULL, "@");
char* p3 = ::strtok(NULL, ":");
char* p4 = ::strtok(NULL, "/");
char* p5 = ::strtok(NULL, ",");
char* p6 = ::strtok(NULL, "\r\n");
if ((p1 == NULL) || (p2 == NULL) || (p3 == NULL) || (p4 == NULL) || (p5 == NULL) || (p6 == NULL))
continue;
m_hosts[p1] = std::pair<std::string, unsigned short>(std::string(p3), (unsigned short)::atoi(p4));
n++;
}
::fclose(fp);
LogInfo("Loaded %u IAX hosts from %s, hosts list is %d entries long", n, fileName.c_str(), m_hosts.size());
return true;
}
bool CFMIAXNetwork::lookupHost()
{
assert(!m_destinationId.empty());
const auto& lookup = m_hosts.find(m_destinationId);
if (lookup == m_hosts.cend()) {
LogError("Cannot find %s in the host list", m_destinationId.c_str());
return false;
}
std::pair<std::string, unsigned short> entry = lookup->second;
if (CUDPSocket::lookup(entry.first, entry.second, m_serverAddr, m_serverAddrLen) != 0) {
LogError("Cannot resolve the hostname/address of %s:%u", entry.first.c_str(), entry.second);
return false;
}
LogMessage("Mapped IAX node id of %s to %s:%u", m_destinationId.c_str(), entry.first.c_str(), entry.second);
return true;
}

View File

@@ -28,6 +28,7 @@
#include <cstdint>
#include <string>
#include <random>
#include <map>
#if defined(_WIN32) || defined(_WIN64)
#include <wincrypt.h>
@@ -45,7 +46,7 @@ enum IAX_STATUS {
class CFMIAXNetwork : public IFMNetwork {
public:
CFMIAXNetwork(const std::string& domain, const std::string& password, const std::string& source, const std::string& destination, const std::string& localAddress, unsigned short localPort, const std::string& gatewayAddress, unsigned short gatewayPort, bool debug);
CFMIAXNetwork(const std::string& hostFile1, const std::string& hostFile2, const std::string& authAddress, unsigned short authPort, unsigned short localPort, const std::string& password, const std::string& sourceId, const std::string& destinationId, bool debug);
virtual ~CFMIAXNetwork();
virtual bool open();
@@ -66,13 +67,17 @@ public:
virtual void clock(unsigned int ms);
virtual std::string getAddress();
private:
std::string m_hostFile1;
std::string m_hostFile2;
sockaddr_storage m_authAddr;
unsigned int m_authAddrLen;
std::string m_password;
std::string m_source;
std::string m_destination;
std::string m_sourceId;
std::string m_destinationId;
CUDPSocket m_socket;
sockaddr_storage m_domainAddr;
unsigned int m_domainAddrLen;
sockaddr_storage m_serverAddr;
unsigned int m_serverAddrLen;
bool m_debug;
@@ -98,10 +103,14 @@ private:
unsigned int m_rxOOO;
bool m_keyed;
std::mt19937 m_random;
std::map<std::string, std::pair<std::string, unsigned short>> m_hosts;
#if defined(_WIN32) || defined(_WIN64)
HCRYPTPROV m_provider;
#endif
bool loadHostsFile(const std::string& fileName);
bool lookupHost();
bool writeNew();
bool writeKey(bool key);
bool writePing(const sockaddr_storage& addr, unsigned int addrLen);

View File

@@ -44,6 +44,8 @@ public:
virtual void clock(unsigned int ms) = 0;
virtual std::string getAddress() = 0;
private:
};

View File

@@ -303,3 +303,17 @@ void CFMRAWNetwork::enable(bool enabled)
m_enabled = enabled;
}
std::string CFMRAWNetwork::getAddress()
{
if (m_addrLen == 0U)
return "NONE";
char buffer1[250U];
char buffer2[250U];
int ret = ::getnameinfo((sockaddr*)&m_addr, m_addrLen, buffer1, 250, buffer2, 250, NI_NUMERICHOST | NI_NUMERICSERV);
if (ret != 0)
return "NONE";
return std::string(buffer1);
}

View File

@@ -53,6 +53,8 @@ public:
virtual void clock(unsigned int ms);
virtual std::string getAddress();
private:
CUDPSocket m_socket;
sockaddr_storage m_addr;

View File

@@ -386,3 +386,17 @@ void CFMUSRPNetwork::enable(bool enabled)
m_enabled = enabled;
}
std::string CFMUSRPNetwork::getAddress()
{
if (m_addrLen == 0U)
return "NONE";
char buffer1[250U];
char buffer2[250U];
int ret = ::getnameinfo((sockaddr*)&m_addr, m_addrLen, buffer1, 250, buffer2, 250, NI_NUMERICHOST | NI_NUMERICSERV);
if (ret != 0)
return "NONE";
return std::string(buffer1);
}

View File

@@ -49,6 +49,8 @@ public:
virtual void clock(unsigned int ms);
virtual std::string getAddress();
private:
std::string m_callsign;
CUDPSocket m_socket;

View File

@@ -289,25 +289,37 @@ Debug=0
Enable=1
# Protocol may be USRP, RAW, or IAX
Protocol=IAX
# LocalAddress=127.0.0.1
LocalPort=4569
GatewayAddress=209.112.244.27
GatewayPort=4569
PreEmphasis=1
DeEmphasis=1
TXAudioGain=1.0
RXAudioGain=1.0
# ModeHang=3
Debug=0
# SampleRate and SquelchFile are RAW mode only options
[USRP Network]
# LocalAddress=127.0.0.1
LocalPort=4569
GatewayAddress=209.112.244.27
GatewayPort=4569
[RAW Network]
# LocalAddress=127.0.0.1
LocalPort=4569
GatewayAddress=209.112.244.27
GatewayPort=4569
SampleRate=48000
# The squelch file is optional
SquelchFile=/tmp/sql
# Domain, Password, Source, and Destination are IAX only options
Domain=register.allstarlink.org
[IAX Network]
HostsFile1=ASLHosts.txt
# HostsFile2=./private/ASLHosts.txt
AuthAddress=register.allstarlink.org
AuthPort=4569
# LocalPort=4569
Password=PASSWORD
Source=12345
Destination=54321
SourceId=12345
DestinationId=54321
[AX.25 Network]
Enable=1

View File

@@ -1883,17 +1883,7 @@ bool CMMDVMHost::createPOCSAGNetwork()
bool CMMDVMHost::createFMNetwork()
{
std::string callsign = m_conf.getFMCallsign();
std::string domain = m_conf.getFMNetworkDomain();
std::string password = m_conf.getFMNetworkPassword();
std::string source = m_conf.getFMNetworkSource();
std::string destination = m_conf.getFMNetworkDestination();
std::string protocol = m_conf.getFMNetworkProtocol();
unsigned int sampleRate = m_conf.getFMNetworkSampleRate();
std::string squelchFile = m_conf.getFMNetworkSquelchFile();
std::string gatewayAddress = m_conf.getFMGatewayAddress();
unsigned short gatewayPort = m_conf.getFMGatewayPort();
std::string localAddress = m_conf.getFMLocalAddress();
unsigned short localPort = m_conf.getFMLocalPort();
bool preEmphasis = m_conf.getFMPreEmphasis();
bool deEmphasis = m_conf.getFMDeEmphasis();
float txAudioGain = m_conf.getFMTXAudioGain();
@@ -1903,33 +1893,63 @@ bool CMMDVMHost::createFMNetwork()
LogInfo("FM Network Parameters");
LogInfo(" Protocol: %s", protocol.c_str());
LogInfo(" Gateway Address: %s", gatewayAddress.c_str());
LogInfo(" Gateway Port: %hu", gatewayPort);
LogInfo(" Local Address: %s", localAddress.c_str());
LogInfo(" Local Port: %hu", localPort);
LogInfo(" Pre-Emphasis: %s", preEmphasis ? "yes" : "no");
LogInfo(" De-Emphasis: %s", deEmphasis ? "yes" : "no");
LogInfo(" TX Audio Gain: %.2f", txAudioGain);
LogInfo(" RX Audio Gain: %.2f", rxAudioGain);
LogInfo(" Mode Hang: %us", m_fmNetModeHang);
if (protocol == "RAW") {
LogInfo(" Sample Rate: %u", sampleRate);
LogInfo(" Squelch File: %s", squelchFile.empty() ? "(none)" : squelchFile.c_str());
}
if (protocol == "IAX") {
LogInfo(" Domain: %s", domain.c_str());
LogInfo(" Source: %s", source.c_str());
LogInfo(" Destiation: %s", destination.c_str());
}
if (protocol == "USRP") {
std::string gatewayAddress = m_conf.getUSRPGatewayAddress();
unsigned short gatewayPort = m_conf.getUSRPGatewayPort();
std::string localAddress = m_conf.getUSRPLocalAddress();
unsigned short localPort = m_conf.getUSRPLocalPort();
LogInfo("USRP Network Parameters");
LogInfo(" Gateway Address: %s", gatewayAddress.c_str());
LogInfo(" Gateway Port: %hu", gatewayPort);
LogInfo(" Local Address: %s", localAddress.c_str());
LogInfo(" Local Port: %hu", localPort);
m_fmNetwork = new CFMUSRPNetwork(callsign, localAddress, localPort, gatewayAddress, gatewayPort, debug);
} else if (protocol == "RAW") {
std::string gatewayAddress = m_conf.getRAWGatewayAddress();
unsigned short gatewayPort = m_conf.getRAWGatewayPort();
std::string localAddress = m_conf.getRAWLocalAddress();
unsigned short localPort = m_conf.getRAWLocalPort();
unsigned int sampleRate = m_conf.getRAWSampleRate();
std::string squelchFile = m_conf.getRAWSquelchFile();
LogInfo("RAW Network Parameters");
LogInfo(" Gateway Address: %s", gatewayAddress.c_str());
LogInfo(" Gateway Port: %hu", gatewayPort);
LogInfo(" Local Address: %s", localAddress.c_str());
LogInfo(" Local Port: %hu", localPort);
LogInfo(" Sample Rate: %u", sampleRate);
LogInfo(" Squelch File: %s", squelchFile.empty() ? "(none)" : squelchFile.c_str());
m_fmNetwork = new CFMRAWNetwork(localAddress, localPort, gatewayAddress, gatewayPort, sampleRate, squelchFile, debug);
} else if (protocol == "IAX") {
m_fmNetwork = new CFMIAXNetwork(domain, password, source, destination, localAddress, localPort, gatewayAddress, gatewayPort, debug);
std::string hostsFile1 = m_conf.getIAXHostsFile1();
std::string hostsFile2 = m_conf.getIAXHostsFile2();
std::string authAddress = m_conf.getIAXAuthAddress();
unsigned short authPort = m_conf.getIAXAuthPort();
unsigned short localPort = m_conf.getIAXLocalPort();
std::string password = m_conf.getIAXPassword();
std::string sourceId = m_conf.getIAXSourceId();
std::string destinationId = m_conf.getIAXDestinationId();
LogInfo("IAX Network Parameters");
LogInfo(" Hosts File 1: %s", hostsFile1.c_str());
if (!hostsFile2.empty())
LogInfo(" Hosts File 2: %s", hostsFile2.c_str());
LogInfo(" Auth Address: %s", authAddress.c_str());
LogInfo(" Auth Port: %u", authPort);
LogInfo(" Local Port: %u", localPort);
LogInfo(" Source Id: %s", sourceId.c_str());
LogInfo(" Destination Id: %s", destinationId.c_str());
m_fmNetwork = new CFMIAXNetwork(hostsFile1, hostsFile2, authAddress, authPort, localPort, password, sourceId, destinationId, debug);
} else {
LogError("Invalid FM network protocol specified - %s", protocol.c_str());
return false;
@@ -2822,5 +2842,5 @@ void CMMDVMHost::buildNetworkHostsString(std::string &str)
str += std::string(" p25:\"") + ((m_p25Enabled && (m_p25Network != NULL)) ? m_conf.getP25GatewayAddress() : "NONE") + "\"";
str += std::string(" nxdn:\"") + ((m_nxdnEnabled && (m_nxdnNetwork != NULL)) ? m_conf.getNXDNGatewayAddress() : "NONE") + "\"";
str += std::string(" m17:\"") + ((m_m17Enabled && (m_m17Network != NULL)) ? m_conf.getM17GatewayAddress() : "NONE") + "\"";
str += std::string(" fm:\"") + ((m_fmEnabled && (m_fmNetwork != NULL)) ? m_conf.getFMGatewayAddress() : "NONE") + "\"";
str += std::string(" fm:\"") + ((m_fmEnabled && (m_fmNetwork != NULL)) ? m_fmNetwork->getAddress() : "NONE") + "\"";
}

View File

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