starting to use json

pull/1/head
Tom Early 3 years ago
parent f001a2fbbd
commit 6e7ba8c5a0

3
.gitignore vendored

@ -10,4 +10,5 @@ configure.h
configure.sql
reflector.cfg
wiresx/configure.php
urfd
urfd*
inicheck

@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h"
#include "BMClient.h"

@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "Reflector.h"
#include "BMPeer.h"

@ -18,7 +18,7 @@
#include <string.h>
#include "Main.h"
#include "BMPeer.h"
#include "BMProtocol.h"
#include "Reflector.h"
@ -73,7 +73,7 @@ void CBMProtocol::Task(void)
else if ( IsValidDvHeaderPacket(Buffer, Header) )
{
// callsign allowed?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip) )
if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip) )
{
OnDvHeaderPacketIn(Header, Ip);
}
@ -83,7 +83,7 @@ void CBMProtocol::Task(void)
std::cout << "XLX (" << Version.GetMajor() << "." << Version.GetMinor() << "." << Version.GetRevision() << ") connect packet for modules " << Modules << " from " << Callsign << " at " << Ip << std::endl;
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::bm, Modules) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::bm, Modules) )
{
// acknowledge the request
EncodeConnectAckPacket(&Buffer, Modules);
@ -101,10 +101,10 @@ void CBMProtocol::Task(void)
std::cout << "XLX ack packet for modules " << Modules << " from " << Callsign << " at " << Ip << std::endl;
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::bm, Modules) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::bm, Modules) )
{
// already connected ?
CPeers *peers = g_Reflector.GetPeers();
CPeers *peers = g_Refl..GetPeers();
if ( peers->FindPeer(Callsign, Ip, EProtocol::bm) == nullptr )
{
// create the new peer
@ -115,7 +115,7 @@ void CBMProtocol::Task(void)
// this also add all new clients to reflector client list
peers->AddPeer(peer);
}
g_Reflector.ReleasePeers();
g_Refl..ReleasePeers();
}
}
else if ( IsValidDisconnectPacket(Buffer, &Callsign) )
@ -123,7 +123,7 @@ void CBMProtocol::Task(void)
std::cout << "XLX disconnect packet from " << Callsign << " at " << Ip << std::endl;
// find peer
CPeers *peers = g_Reflector.GetPeers();
CPeers *peers = g_Refl..GetPeers();
std::shared_ptr<CPeer>peer = peers->FindPeer(Ip, EProtocol::bm);
if ( peer != nullptr )
{
@ -132,7 +132,7 @@ void CBMProtocol::Task(void)
// and delete them
peers->RemovePeer(peer);
}
g_Reflector.ReleasePeers();
g_Refl..ReleasePeers();
}
else if ( IsValidNackPacket(Buffer, &Callsign) )
{
@ -143,14 +143,14 @@ void CBMProtocol::Task(void)
//std::cout << "XLX keepalive packet from " << Callsign << " at " << Ip << std::endl;
// find peer
CPeers *peers = g_Reflector.GetPeers();
CPeers *peers = g_Refl..GetPeers();
std::shared_ptr<CPeer>peer = peers->FindPeer(Ip, EProtocol::bm);
if ( peer != nullptr )
{
// keep it alive
peer->Alive();
}
g_Reflector.ReleasePeers();
g_Refl..ReleasePeers();
}
else
{
@ -210,7 +210,7 @@ void CBMProtocol::HandleQueue(void)
}
// and push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::bm, it)) != nullptr )
@ -237,7 +237,7 @@ void CBMProtocol::HandleQueue(void)
}
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
m_Queue.Unlock();
@ -255,7 +255,7 @@ void CBMProtocol::HandleKeepalives(void)
EncodeKeepAlivePacket(&keepalive);
// iterate on peers
CPeers *peers = g_Reflector.GetPeers();
CPeers *peers = g_Refl..GetPeers();
auto pit = peers->begin();
std::shared_ptr<CPeer>peer = nullptr;
while ( (peer = peers->FindNextPeer(EProtocol::bm, pit)) != nullptr )
@ -282,7 +282,7 @@ void CBMProtocol::HandleKeepalives(void)
peers->RemovePeer(peer);
}
}
g_Reflector.ReleasePeers();
g_Refl..ReleasePeers();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -293,8 +293,8 @@ void CBMProtocol::HandlePeerLinks(void)
CBuffer buffer;
// get the list of peers
CPeerCallsignList *list = g_GateKeeper.GetPeerList();
CPeers *peers = g_Reflector.GetPeers();
CPeerCallsignList *list = g_Gate.GetPeerList();
CPeers *peers = g_Refl..GetPeers();
// check if all our connected peers are still listed by gatekeeper
// if not, disconnect
@ -330,8 +330,8 @@ void CBMProtocol::HandlePeerLinks(void)
}
// done
g_Reflector.ReleasePeers();
g_GateKeeper.ReleasePeerList();
g_Refl..ReleasePeers();
g_Gate.ReleasePeerList();
}
@ -360,11 +360,11 @@ void CBMProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, c
CCallsign rpt2(Header->GetRpt2Callsign());
// no stream open yet, open a new one
// find this client
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, EProtocol::bm, Header->GetRpt2Module());
std::shared_ptr<CClient>client = g_Refl..GetClients()->FindClient(Ip, EProtocol::bm, Header->GetRpt2Module());
if ( client )
{
// and try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams[stream->GetStreamId()] = stream;
@ -373,10 +373,10 @@ void CBMProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, c
peer = client->GetCallsign();
}
// release
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2, peer);
g_Reflector.ReleaseUsers();
g_Refl..GetUsers()->Hearing(my, rpt1, rpt2, peer);
g_Refl..ReleaseUsers();
}
}

@ -20,7 +20,6 @@
#include <vector>
#include <fstream>
#include "Main.h"
////////////////////////////////////////////////////////////////////////////////////////

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include <cctype>
#include "DMRIdDirFile.h"
@ -67,62 +67,62 @@ CCallsign::CCallsign(const char *sz, uint32_t dmrid, uint16_t nxdnid)
// dmrid ok ?
if ( m_uiDmrid == 0 )
{
g_DmridDir.Lock();
g_LDid.Lock();
{
m_uiDmrid = g_DmridDir.FindDmrid(*this);
m_uiDmrid = g_LDid.FindDmrid(*this);
}
g_DmridDir.Unlock();
g_LDid.Unlock();
}
if ( m_uiNXDNid == 0 )
{
g_NXDNidDir.Lock();
g_LNid.Lock();
{
m_uiNXDNid = g_NXDNidDir.FindNXDNid(*this);
m_uiNXDNid = g_LNid.FindNXDNid(*this);
}
g_NXDNidDir.Unlock();
g_LNid.Unlock();
}
}
else if ( m_uiDmrid != 0 )
{
g_DmridDir.Lock();
g_LDid.Lock();
{
const CCallsign *callsign = g_DmridDir.FindCallsign(m_uiDmrid);
const CCallsign *callsign = g_LDid.FindCallsign(m_uiDmrid);
if ( callsign != nullptr )
{
memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN);
}
}
g_DmridDir.Unlock();
g_LDid.Unlock();
if ( m_uiNXDNid == 0 )
{
g_NXDNidDir.Lock();
g_LNid.Lock();
{
m_uiNXDNid = g_NXDNidDir.FindNXDNid(*this);
m_uiNXDNid = g_LNid.FindNXDNid(*this);
}
g_NXDNidDir.Unlock();
g_LNid.Unlock();
}
CSIn();
}
else if ( m_uiNXDNid != 0 )
{
g_NXDNidDir.Lock();
g_LNid.Lock();
{
const CCallsign *callsign = g_NXDNidDir.FindCallsign(m_uiNXDNid);
const CCallsign *callsign = g_LNid.FindCallsign(m_uiNXDNid);
if ( callsign != nullptr )
{
memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN);
}
}
g_NXDNidDir.Unlock();
g_LNid.Unlock();
if ( m_uiDmrid == 0 )
{
g_DmridDir.Lock();
g_LDid.Lock();
{
m_uiDmrid = g_DmridDir.FindDmrid(*this);
m_uiDmrid = g_LDid.FindDmrid(*this);
}
g_DmridDir.Unlock();
g_LDid.Unlock();
}
CSIn();
}
@ -201,16 +201,16 @@ void CCallsign::SetCallsign(const char *sz, bool UpdateDmrid)
// and update dmrid
if ( UpdateDmrid )
{
g_DmridDir.Lock();
g_LDid.Lock();
{
m_uiDmrid = g_DmridDir.FindDmrid(*this);
m_uiDmrid = g_LDid.FindDmrid(*this);
}
g_DmridDir.Unlock();
g_NXDNidDir.Lock();
g_LDid.Unlock();
g_LNid.Lock();
{
m_uiNXDNid = g_NXDNidDir.FindNXDNid(*this);
m_uiNXDNid = g_LNid.FindNXDNid(*this);
}
g_NXDNidDir.Unlock();
g_LNid.Unlock();
}
}
@ -234,16 +234,16 @@ void CCallsign::SetCallsign(const uint8_t *buffer, int len, bool UpdateDmrid)
CSIn();
if ( UpdateDmrid )
{
g_DmridDir.Lock();
g_LDid.Lock();
{
m_uiDmrid = g_DmridDir.FindDmrid(*this);
m_uiDmrid = g_LDid.FindDmrid(*this);
}
g_DmridDir.Unlock();
g_NXDNidDir.Lock();
g_LDid.Unlock();
g_LNid.Lock();
{
m_uiNXDNid = g_NXDNidDir.FindNXDNid(*this);
m_uiNXDNid = g_LNid.FindNXDNid(*this);
}
g_NXDNidDir.Unlock();
g_LNid.Unlock();
}
}
@ -252,15 +252,15 @@ void CCallsign::SetDmrid(uint32_t dmrid, bool UpdateCallsign)
m_uiDmrid = dmrid;
if ( UpdateCallsign )
{
g_DmridDir.Lock();
g_LDid.Lock();
{
const CCallsign *callsign = g_DmridDir.FindCallsign(dmrid);
const CCallsign *callsign = g_LDid.FindCallsign(dmrid);
if ( callsign != nullptr )
{
memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN);
}
}
g_DmridDir.Unlock();
g_LDid.Unlock();
}
}
@ -277,15 +277,15 @@ void CCallsign::SetNXDNid(uint16_t nxdnid, bool UpdateCallsign)
m_uiNXDNid = nxdnid;
if ( UpdateCallsign )
{
g_DmridDir.Lock();
g_LDid.Lock();
{
const CCallsign *callsign = g_NXDNidDir.FindCallsign(nxdnid);
const CCallsign *callsign = g_LNid.FindCallsign(nxdnid);
if ( callsign != nullptr )
{
memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN);
}
}
g_NXDNidDir.Unlock();
g_LNid.Unlock();
}
}

@ -19,7 +19,7 @@
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "Main.h"
#include "CallsignList.h"
////////////////////////////////////////////////////////////////////////////////////////

@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "Main.h"
#include "CallsignListItem.h"
////////////////////////////////////////////////////////////////////////////////////////

@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h"
#include "CallsignListItem.h"
////////////////////////////////////////////////////////////////////////////////////////

@ -18,7 +18,7 @@
#pragma once
#include "Main.h"
#include "Callsign.h"
#include "IP.h"

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "Client.h"

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "Reflector.h"
#include "Clients.h"
@ -66,7 +66,7 @@ void CClients::AddClient(std::shared_ptr<CClient> client)
}
std::cout << std::endl;
// notify
g_Reflector.OnClientsChanged();
g_Refl..OnClientsChanged();
}
void CClients::RemoveClient(std::shared_ptr<CClient> client)
@ -90,7 +90,7 @@ void CClients::RemoveClient(std::shared_ptr<CClient> client)
std::cout << std::endl;
m_Clients.erase(it);
// notify
g_Reflector.OnClientsChanged();
g_Refl..OnClientsChanged();
break;
}
}

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "CodecStream.h"
#include "DVFramePacket.h"
@ -25,7 +25,12 @@
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CCodecStream::CCodecStream(CPacketStream *PacketStream, uint16_t streamid, ECodecType type, std::shared_ptr<CUnixDgramReader> reader)
CCodecStream::CCodecStream(CPacketStream *PacketStream)
{
m_PacketStream = PacketStream;
}
void CCodecStream::ResetStats(uint16_t streamid, ECodecType type)
{
keep_running = true;
m_uiStreamId = streamid;
@ -36,9 +41,6 @@ CCodecStream::CCodecStream(CPacketStream *PacketStream, uint16_t streamid, ECode
m_RTSum = 0;
m_RTCount = 0;
m_uiTotalPackets = 0;
m_PacketStream = PacketStream;
m_TCReader = reader;
InitCodecStream();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -52,7 +54,12 @@ CCodecStream::~CCodecStream()
{
m_Future.get();
}
// and close the socket
m_TCReader.Close();
}
void CCodecStream::ReportStats()
{
// display stats
if (m_RTCount > 0)
{
@ -69,11 +76,24 @@ CCodecStream::~CCodecStream()
////////////////////////////////////////////////////////////////////////////////////////
// initialization
void CCodecStream::InitCodecStream(void)
bool CCodecStream::InitCodecStream(char module)
{
m_TCWriter.SetUp(REF2TC);
std::string name(TC2REF);
name.append(1, module);
if (m_TCReader.Open(name.c_str()))
return true;
keep_running = true;
m_Future = std::async(std::launch::async, &CCodecStream::Thread, this);
try
{
m_Future = std::async(std::launch::async, &CCodecStream::Thread, this);
}
catch(const std::exception& e)
{
std::cerr << "Could not start Codec processing on module '" << module << "': " << e.what() << std::endl;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////
@ -92,21 +112,21 @@ void CCodecStream::Task(void)
STCPacket pack;
// any packet from transcoder
if (m_TCReader->Receive(&pack, 5))
if (m_TCReader.Receive(&pack, 5))
{
// update statistics
double rt = pack.rt_timer.time(); // the round-trip time
if ( m_RTMin == -1 )
if (0 == m_RTCount)
{
m_RTMin = rt;
m_RTMax = rt;
}
else
{
m_RTMin = MIN(m_RTMin, rt);
m_RTMax = MAX(m_RTMax, rt);
if (rt < m_RTMin)
m_RTMin = rt;
else if (rt > m_RTMax)
m_RTMax = rt;
}
m_RTSum += rt;
m_RTCount++;

@ -18,6 +18,9 @@
#pragma once
#include <atomic>
#include <future>
#include "UnixDgramSocket.h"
#include "PacketQueue.h"
@ -30,7 +33,11 @@ class CCodecStream : public CPacketQueue
{
public:
// constructor
CCodecStream(CPacketStream *packetstream, uint16_t streamid, ECodecType codectype, std::shared_ptr<CUnixDgramReader> reader);
CCodecStream(CPacketStream *packetstream);
bool InitCodecStream(char module);
void ResetStats(uint16_t streamid, ECodecType codectype);
void ReportStats();
// destructor
virtual ~CCodecStream();
@ -44,7 +51,6 @@ public:
protected:
// initialization
void InitCodecStream(void);
// data
uint16_t m_uiStreamId;
uint16_t m_uiPort;
@ -52,7 +58,7 @@ protected:
ECodecType m_eCodecIn;
// sockets
std::shared_ptr<CUnixDgramReader> m_TCReader;
CUnixDgramReader m_TCReader;
CUnixDgramWriter m_TCWriter;
// associated packet stream

@ -0,0 +1,928 @@
/*
* Copyright (c) 2023 by Thomas A. Early N7TAE
*
* 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 <curl/curl.h>
#include <stdlib.h>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <cstring>
#include <vector>
#include <list>
#include <algorithm>
#include <regex>
#include "Configure.h"
// ini file keywords
#define JAUTOLINKMODULE "AutoLinkModule"
#define JBLACKLISTPATH "BlacklistPath"
#define JBRANDMEISTER "Brandmeister"
#define JCALLSIGN "Callsign"
#define JCLIENTSPATH "ClientFilePath"
#define JCOUNTRY "Country"
#define JDCS "DCS"
#define JDEFAULTCALLSIGN "DefaultCallsign"
#define JDEFAULTID "DefaultId"
#define JDEFAULTRXFREQ "DefaultRxFreq"
#define JDEFAULTTXFREQ "DefaultTxFreq"
#define JDESCRIPTION "Description"
#define JDEXTRA "DExtra"
#define JDMRIDDB "DMR ID DB"
#define JDMRPLUS "DMRPlus"
#define JDPLUS "DPlus"
#define JFILES "Files"
#define JFILEPATH "FilePath"
#define JG3TERMINALPATH "G3TerminalPath"
#define JHOSTNAME "Hostname"
#define JINTERLINKPATH "InterlinkPath"
#define JIPADDRESSES "IpAddresses"
#define JIPV4BINDING "IPv4Binding"
#define JIPV4EXTERNAL "IPv4External"
#define JIPV6BINDING "IPv6Binding"
#define JIPV6EXTERNAL "IPv6External"
#define JJSONPATH "JsonPath"
#define JM17 "M17"
#define JMMDVM "MMDVM"
#define JMODE "Mode"
#define JMODULES "Modules"
#define JNAMES "Names"
#define JNXDNIDDB "NXDN ID DB"
#define JNXDN "NXDN"
#define JP25 "P25"
#define JPIDPATH "PidPath"
#define JPORT "Port"
#define JREFLECTORID "ReflectorID"
#define JREFRESHMIN "RefreshMin"
#define JREGISTRATIONDESCRIPTION "RegistrationDescription"
#define JREGISTRATIONID "RegistrationID"
#define JREGISTRATIONNAME "RegistrationName"
#define JSPONSOR "Sponsor"
#define JSUFFIX "Suffix"
#define JSYSOPEMAIL "SysopEmail"
#define JTRANSCODED "Transcoded"
#define JTRANSCODER "Transcoder"
#define JURF "URF"
#define JUSRP "USRP"
#define JWHITELISTPATH "WhitelistPath"
#define JYSF "YSF"
#define JYSFTXRXDB "YSF TX/RX DB"
static inline void split(const std::string &s, char delim, std::vector<std::string> &v)
{
std::istringstream iss(s);
std::string item;
while (std::getline(iss, item, delim))
v.push_back(item);
}
// trim from start (in place)
static inline void ltrim(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {
return !std::isspace(ch);
}));
}
// trim from end (in place)
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {
return !std::isspace(ch);
}).base(), s.end());
}
// trim from both ends (in place)
static inline void trim(std::string &s) {
ltrim(s);
rtrim(s);
}
// callback function writes data to a std::ostream
static size_t data_write(void* buf, size_t size, size_t nmemb, void* userp)
{
if(userp)
{
std::ostream& os = *static_cast<std::ostream*>(userp);
std::streamsize len = size * nmemb;
if(os.write(static_cast<char*>(buf), len))
return len;
}
return 0;
}
static CURLcode curl_read(const std::string& url, std::ostream& os, long timeout = 30)
{
CURLcode code(CURLE_FAILED_INIT);
CURL* curl = curl_easy_init();
if(curl)
{
if(CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &data_write))
&& CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L))
&& CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L))
&& CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_FILE, &os))
&& CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout))
&& CURLE_OK == (code = curl_easy_setopt(curl, CURLOPT_URL, url.c_str())))
{
code = curl_easy_perform(curl);
}
curl_easy_cleanup(curl);
}
return code;
}
void CConfigure::CurlAddresses(std::string &ipv4, std::string &ipv6) const
{
std::ostringstream oss;
curl_global_init(CURL_GLOBAL_ALL);
if(CURLE_OK == curl_read("https://ipv4.icanhazip.com", oss))
{
// Web page successfully written to string
ipv4.assign(oss.str());
trim(ipv4);
oss.str(std::string());
}
if(CURLE_OK == curl_read("https://ipv6.icanhazip.com", oss))
{
ipv6.assign(oss.str());
trim(ipv6);
}
curl_global_cleanup();
// std::cout << "IPv4=" << ipv4 << " IPv6=" << ipv6 << std::endl;
}
CConfigure::CConfigure()
{
IPv4RegEx = std::regex("^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3,3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]){1,1}$", std::regex::extended);
IPv6RegEx = std::regex("^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}){1,1}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|([0-9a-fA-F]{1,4}:){1,1}(:[0-9a-fA-F]{1,4}){1,6}|:((:[0-9a-fA-F]{1,4}){1,7}|:))$", std::regex::extended);
}
bool CConfigure::ReadData(const std::string &path)
// returns true on failure
{
bool rval = false;
ESection section = ESection::none;
counter = 0;
REFLECTOR::DB *pdb;
//data.ysfalmodule = 0;
//data.DPlusPort = data.DCSPort = data.DExtraPort = data.BMPort = data.DMRPlusPort = 0;
std::ifstream cfgfile(path.c_str(), std::ifstream::in);
if (! cfgfile.is_open()) {
std::cerr << "ERROR: '" << path << "' was not found!" << std::endl;
return true;
}
std::string ipv4, ipv6;
CurlAddresses(ipv4, ipv6);
std::string line;
while (std::getline(cfgfile, line))
{
counter++;
trim(line);
if (3 > line.size())
continue; // can't be anything
if ('#' == line.at(0))
continue; // skip comments
// check for next section
if ('[' == line.at(0))
{
std::string hname(line.substr(1));
auto pos = hname.find(']');
if (std::string::npos != pos)
hname.resize(pos);
section = ESection::none;
if (0 == hname.compare(JNAMES))
section = ESection::names;
else if (0 == hname.compare(JIPADDRESSES))
section = ESection::ip;
else if (0 == hname.compare(JMODULES))
section = ESection::modules;
else if (0 == hname.compare(JDPLUS))
section = ESection::dplus;
else if (0 == hname.compare(JDEXTRA))
section = ESection::dextra;
else if (0 == hname.compare(JDMRPLUS))
section = ESection::dmrplus;
else if (0 == hname.compare(JMMDVM))
section = ESection::mmdvm;
else if (0 == hname.compare(JNXDN))
section = ESection::nxdn;
else if (0 == hname.compare(JBRANDMEISTER))
section = ESection::bm;
else if (0 == hname.compare(JYSF))
section = ESection::ysf;
else if (0 == hname.compare(JDCS))
section = ESection::dcs;
else if (0 == hname.compare(JP25))
section = ESection::p25;
else if (0 == hname.compare(JM17))
section = ESection::m17;
else if (0 == hname.compare(JUSRP))
section = ESection::usrp;
else if (0 == hname.compare(JURF))
section = ESection::urf;
else if (0 == hname.compare(JDMRIDDB))
section = ESection::dmrid;
else if (0 == hname.compare(JNXDNIDDB))
section = ESection::nxdnid;
else if (0 == hname.compare(JYSFTXRXDB))
section = ESection::ysffreq;
else if (0 == hname.compare(JFILES))
section = ESection::files;
else
{
std::cerr << "WARNING: unknown ini file section: " << line << std::endl;
}
continue;
}
std::vector<std::string> tokens;
split(line, '=', tokens);
// check value for end-of-line comment
if (2 > tokens.size())
{
std::cout << "WARNING: line #" << counter << ": '" << line << "' does not contain an equal sign, skipping" << std::endl;
continue;
}
auto pos = tokens[1].find('#');
if (std::string::npos != pos)
{
tokens[1].assign(tokens[1].substr(0, pos));
rtrim(tokens[1]); // whitespace between the value and the end-of-line comment
}
// trim whitespace from around the '='
rtrim(tokens[0]);
ltrim(tokens[1]);
const std::string key(tokens[0]);
const std::string value(tokens[1]);
if (key.empty() || value.empty())
{
std::cout << "WARNING: line #" << counter << ": missing key or value: '" << line << "'" << std::endl;
continue;
}
switch (section)
{
case ESection::names:
if (0 == key.compare(JCALLSIGN))
data[j.names.cs] = value;
else if (0 == key.compare(JSYSOPEMAIL))
data[j.names.email] = value;
else if (0 == key.compare(JCOUNTRY))
data[j.names.country] = value.substr(0,2);
else if (0 == key.compare(JSPONSOR))
data[j.names.sponsor] = value;
else
badParam(key);
break;
case ESection::ip:
if (0 == key.compare(JIPV4BINDING))
{
data[j.ip.ipv4bind] = value;
}
else if (0 == key.compare(JIPV6BINDING))
{
data[j.ip.ipv6bind] = value;
}
else if (0 == key.compare(JIPV4EXTERNAL))
{
data[j.ip.ipv4address] = value;
}
else if (0 == key.compare(JIPV6EXTERNAL))
{
data[j.ip.ipv6address] = value;
}
else if (0 == key.compare(JTRANSCODER))
{
if (value.compare("local"))
{
std::cout << "WARNING: Line #" << counter << ": malformed transcoder address, '" << value << "', resetting..." << std::endl;
}
data[j.ip.transcoder] = "local";
}
else
badParam(key);
break;
case ESection::modules:
if (0 == key.compare(JMODULES))
{
std::string m(value);
if (checkModules(m))
{
std::cerr << "ERROR: line #" << counter << ": no letters found in Modules: '" << m << "'" << std::endl;
rval = true;
} else
data[j.modules.modules] = m;
}
else if (0 == key.compare(JTRANSCODED))
{
std::string m(value);
if (checkModules(m))
{
std::cerr << "ERROR: line #" << counter << ": no letters found in Transcoded: '" << m << "'" << std::endl;
rval = true;
} else
data[j.modules.tcmodules] = m;
}
else if (0 == key.compare(0, 11, "Description"))
{
if (12 == key.size() && isupper(key[11]))
data[key] = value;
else
badParam(key);
}
else
badParam(key);
break;
case ESection::bm:
if (0 == key.compare(JPORT))
data[j.bm.port] = getUnsigned(value, "Brandmeister Port", 1024, 65535, 10002);
else
badParam(key);
break;
case ESection::dcs:
if (0 == key.compare(JPORT))
data[j.dcs.port] = getUnsigned(value, "DCS Port", 1024, 65535, 30051);
else
badParam(key);
break;
case ESection::dextra:
if (0 == key.compare(JPORT))
data[j.dextra.port] = getUnsigned(value, "DExtra Port", 1024, 65535, 30001);
else
badParam(key);
break;
case ESection::dmrplus:
if (0 == key.compare(JPORT))
data[j.dmrplus.port] = getUnsigned(value, "DMRPlus Port", 1024, 65535, 8880);
else
badParam(key);
break;
case ESection::dplus:
if (0 == key.compare(JPORT))
data[j.dplus.port] = getUnsigned(value, "DPlus Port", 1024, 65535, 20001);
else
badParam(key);
break;
case ESection::m17:
if (0 == key.compare(JPORT))
data[j.m17.port] = getUnsigned(value, "M17 Port", 1024, 65535, 17000);
else
badParam(key);
break;
case ESection::mmdvm:
if (0 == key.compare(JPORT))
data[j.mmdvm.port] = getUnsigned(value, "MMDVM Port", 1024, 65535, 62030);
else if (0 == key.compare(JDEFAULTID))
data[j.mmdvm.defaultid] = getUnsigned(value, "MMDVM DefaultID", 0, 9999999, 0);
else
badParam(key);
break;
case ESection::nxdn:
if (0 == key.compare(JPORT))
data[j.nxdn.port] = getUnsigned(value, "NDXN Port", 1024, 65535, 41400);
else if (0 == key.compare(JAUTOLINKMODULE))
setAutolink(JNXDN, j.nxdn.autolinkmod, value);
else if (0 == key.compare(JREFLECTORID))
data[j.nxdn.reflectorid] = getUnsigned(value, "NXDN ReflectorID", 0, 65535, 0);
else
badParam(key);
break;
case ESection::p25:
if (0 == key.compare(JPORT))
data[j.p25.port] = getUnsigned(value, "P25 Port", 1024, 65535, 41000);
else if (0 == key.compare(JAUTOLINKMODULE))
setAutolink(JP25, j.p25.autolinkmod, value);
else if (0 == key.compare(JREFLECTORID))
data[j.p25.reflectorid] = getUnsigned(value, "P25 ReflectorID", 0, 16777215, 0);
else
badParam(key);
break;
case ESection::urf:
if (0 == key.compare(JPORT))
data[j.urf.port] = getUnsigned(value, "URF Port", 1024, 65535, 10017);
else
badParam(key);
break;
case ESection::usrp:
if (0 == key.compare(JPORT))
data[j.usrp.port] = getUnsigned(value, "USRP Port", 1024, 65535, 34001);
else if (0 == key.compare(JAUTOLINKMODULE))
setAutolink(JUSRP, j.usrp.autolinkmod, value);
else if (0 == key.compare(JDEFAULTCALLSIGN))
{
std::string cs;
for (auto &c : value)
if (isalnum(c))
cs.append(1, toupper(c));
if (cs.size() > 7) cs.resize(7);
data[j.usrp.defaultcallsign] = cs;
}
else if (0 == key.compare(JCLIENTSPATH))
data[j.usrp.clientfilepath] == value;
else
badParam(key);
break;
case ESection::ysf:
if (0 == key.compare(JPORT))
data[j.ysf.port] = getUnsigned(value, "YSF Port", 1024, 65535, 42000);
else if (0 == key.compare(JAUTOLINKMODULE))
setAutolink(JYSF, j.ysf.autolinkmod, value);
else if (0 == key.compare(JDEFAULTTXFREQ))
data[j.ysf.defaulttxfreq] = getUnsigned(value, "YSF DefaultTxFreq", 40000000, 2600000000, 439000000);
else if (0 == key.compare(JDEFAULTRXFREQ))
data[j.ysf.defaultrxfreq] = getUnsigned(value, "YSF DefaultRxFreq", 40000000, 2600000000, 439000000);
else if (0 == key.compare(JREGISTRATIONID))
data[j.ysf.ysfreflectordb.id] = getUnsigned(value, "YSF RegistrationID", 0, 9999999, 0);
else if (0 == key.compare(JREGISTRATIONNAME))
{
std::string name(value);
if (name.size() > 13) name.resize(13);
data[j.ysf.ysfreflectordb.name] = name;
}
else if (0 == key.compare(JREGISTRATIONDESCRIPTION))
{
std::string desc(value);
if (desc.size() > 16) desc.resize(16);
data[j.ysf.ysfreflectordb.description] = desc;
}
else
badParam(key);
break;
case ESection::dmrid:
case ESection::nxdnid:
case ESection::ysffreq:
switch (section)
{
case ESection::dmrid: pdb = &j.dmriddb; break;
case ESection::nxdnid: pdb = &j.nxdniddb; break;
case ESection::ysffreq: pdb = &j.ysftxrxdb; break;
}
if (0 == key.compare(JHOSTNAME))
data[pdb->hostname] = value;
else if (0 == key.compare(JSUFFIX))
data[pdb->suffix] = value;
else if (0 == key.compare(JMODE))
{
if ((0==value.compare("file")) || (0==value.compare("http")) || (0==value.compare("both")))
data[pdb->mode] = value;
else
{
std::cout << "WARNING: line #" << counter << ": Mode, '" << value << "' not recognized. Setting to 'http'" << std::endl;
data[pdb->mode] = "http";
}
}
else if (0 == key.compare(JREFRESHMIN))
data[pdb->refreshmin] = getUnsigned(value, JREFRESHMIN, 15, 14400, 180);
else if (0 == key.compare(JFILEPATH))
data[pdb->filepath] = value;
else
badParam(key);
break;
case ESection::files:
if (0 == key.compare(JPIDPATH))
data[j.files.pid] = value;
else if (0 == key.compare(JJSONPATH))
data[j.files.json] = value;
else if (0 == key.compare(JWHITELISTPATH))
data[j.files.white] = value;
else if (0 == key.compare(JBLACKLISTPATH))
data[j.files.black] = value;
else if (0 == key.compare(JINTERLINKPATH))
data[j.files.interlink] = value;
else if (0 == key.compare(JG3TERMINALPATH))
data[j.files.terminal] = value;
else
badParam(key);
break;
default:
std::cout << "WARNING: parameter '" << line << "' defined befor any [section]" << std::endl;
}
}
cfgfile.close();
////////////////////////////// check the input
// Names section
if (isDefined(ErrorLevel::fatal, JNAMES, JCALLSIGN, j.names.cs, rval))
{
const auto cs = data[j.names.cs].get<std::string>();
auto RefRegEx = std::regex("^URF([A-Z0-9]){3,3}$", std::regex::extended);
if (! std::regex_match(cs, RefRegEx))
{
std::cerr << "ERROR: [" << JNAMES << "] " << JCALLSIGN << " '" << cs << "' is malformed" << std::endl;
rval = true;
}
}
isDefined(ErrorLevel::mild, JNAMES, JSYSOPEMAIL, j.names.email, rval);
isDefined(ErrorLevel::mild, JNAMES, JCOUNTRY, j.names.country, rval);
isDefined(ErrorLevel::mild, JNAMES, JSPONSOR, j.names.sponsor, rval);
// IP Address section
// ipv4 bind and external
if (isDefined(ErrorLevel::fatal, JIPADDRESSES, JIPV4BINDING, j.ip.ipv4bind, rval))
{
if (std::regex_match(data[j.ip.ipv4bind].get<std::string>(), IPv4RegEx))
{
if (data.contains(j.ip.ipv4address))
{
auto v4 = data[j.ip.ipv4address].get<std::string>();
if (std::regex_match(v4, IPv4RegEx))
{
if (ipv4.compare(v4))
std::cout << "WARNING: specified IPv4 external address, " << v4 << ", is different than detected address, " << ipv4 << std::endl;
}
else
{
std::cerr << "ERROR: specifed IPv4 external address, " << v4 << ", is malformed" << std::endl;
rval = true;
}
}
else
{
// make sure curl worked!
if (std::regex_match(ipv4, IPv4RegEx))
data[j.ip.ipv4address] = ipv4;
else
{
std::cerr << "ERROR: could not detect IPv4 address at this time" << std::endl;
rval = true;
}
}
}
else
{
std::cerr << "ERROR: IPv4 binding address, " << data[j.ip.ipv4address].get<std::string>() << ", is malformed" << std::endl;
rval = true;
}
}
// ipv6 bind and external
if (data.contains(j.ip.ipv6bind))
{
if (std::regex_match(data[j.ip.ipv6bind].get<std::string>(), IPv6RegEx))
{
if (data.contains(j.ip.ipv6address))
{
auto v6 = data[j.ip.ipv6address].get<std::string>();
if (std::regex_match(v6, IPv6RegEx))
{
if (ipv6.compare(v6))
std::cout << "WARNING: specified IPv6 external address [" << v6 << "], is different than detected address [" << ipv6 << ']' << std::endl;
}
else
{
std::cerr << "ERROR: the specifed IPv6 address [" << v6 << "] is malformed" << std::endl;
rval = true;
}
}
else
{
// make sure curl worked!
if (std::regex_match(ipv6, IPv6RegEx))
data[j.ip.ipv6address] = ipv6;
else
{
std::cerr << "ERROR: could not detect IPv6 address at this time" << std::endl;
rval = true;
}
}
}
else
{
std::cerr << "ERROR: IPv6 binding address, " << data[j.ip.ipv6address].get<std::string>() << ", is malformed" << std::endl;
rval = true;
}
}
else
{
data[j.ip.ipv4bind] = nullptr;
data[j.ip.ipv6address] = nullptr;
}
// Modules section
if (isDefined(ErrorLevel::fatal, JMODULES, JMODULES, j.modules.modules, rval))
{
const auto mods(data[j.modules.modules].get<std::string>());
if (data.contains(j.modules.tcmodules))
{
const auto tcmods(data[j.modules.tcmodules].get<std::string>());
// how many transcoded modules
auto size = tcmods.size();
if (3 != size && 1 != size)
std::cout << "WARNING: [" << JMODULES << "] " << JTRANSCODED << " doesn't define three (or one) modules" << std::endl;
// make sure each transcoded module is configured
for (auto c : data[j.modules.tcmodules])
{
if (std::string::npos == mods.find(c))
{
std::cerr << "ERROR: transcoded module '" << c << "' not found in defined modules" << std::endl;
rval = true;
}
}
}
else
data[j.modules.tcmodules] = nullptr;
// finally, check the module descriptions
for (unsigned i=0; i<26; i++)
{
if (std::string::npos == mods.find('A'+i))
{
if (data.contains(j.modules.descriptor[i]))
{
std::cout << "WARNING: " << j.modules.descriptor[i] << " defined for an unconfigured module. Deleting..." << std::endl;
data.erase(j.modules.descriptor[i]);
}
}
else
{
if (! data.contains(j.modules.descriptor[i]))
{
std::string value("Module ");
value.append(1, 'A'+i);
std::cout << "WARNING: " << j.modules.descriptor[i] << " not found. Setting to " << value << std::endl;
data[j.modules.descriptor[i]] = value;
}
}
}
}
// "simple" protocols with only a Port
isDefined(ErrorLevel::fatal, JBRANDMEISTER, JPORT, j.bm.port, rval);
isDefined(ErrorLevel::fatal, JDCS, JPORT, j.dcs.port, rval);
isDefined(ErrorLevel::fatal, JDEXTRA, JPORT, j.dextra.port, rval);
isDefined(ErrorLevel::fatal, JDMRPLUS, JPORT, j.dmrplus.port, rval);
isDefined(ErrorLevel::fatal, JDPLUS, JPORT, j.dplus.port, rval);
isDefined(ErrorLevel::fatal, JM17, JPORT, j.m17.port, rval);
isDefined(ErrorLevel::fatal, JURF, JPORT, j.urf.port, rval);
// MMDVM
isDefined(ErrorLevel::fatal, JMMDVM, JPORT, j.mmdvm.port, rval);
isDefined(ErrorLevel::fatal, JMMDVM, JDEFAULTID, j.mmdvm.defaultid, rval);
// NXDN
isDefined(ErrorLevel::fatal, JNXDN, JPORT, j.nxdn.port, rval);
checkAutoLink(JNXDN, JAUTOLINKMODULE, j.nxdn.autolinkmod, rval);
isDefined(ErrorLevel::fatal, JNXDN, JREFLECTORID, j.nxdn.reflectorid, rval);
// P25
isDefined(ErrorLevel::fatal, JP25, JPORT, j.p25.port, rval);
checkAutoLink(JP25, JAUTOLINKMODULE, j.p25.autolinkmod, rval);
isDefined(ErrorLevel::fatal, JP25, JREFLECTORID, j.p25.reflectorid, rval);
// USRP
isDefined(ErrorLevel::fatal, JUSRP, JPORT, j.usrp.port, rval);
checkAutoLink(JUSRP, JAUTOLINKMODULE, j.usrp.autolinkmod, rval);
isDefined(ErrorLevel::fatal, JUSRP, JDEFAULTCALLSIGN, j.usrp.defaultcallsign, rval);
isDefined(ErrorLevel::fatal, JUSRP, JCLIENTSPATH, j.usrp.clientfilepath, rval);
// YSF
isDefined(ErrorLevel::fatal, JYSF, JPORT, j.ysf.port, rval);
checkAutoLink(JYSF, JAUTOLINKMODULE, j.ysf.autolinkmod, rval);
isDefined(ErrorLevel::fatal, JYSF, JDEFAULTRXFREQ, j.ysf.defaultrxfreq, rval);
isDefined(ErrorLevel::fatal, JYSF, JDEFAULTTXFREQ, j.ysf.defaulttxfreq, rval);
isDefined(ErrorLevel::mild, JYSF, JREGISTRATIONID, j.ysf.ysfreflectordb.id, rval);
isDefined(ErrorLevel::mild, JYSF, JREGISTRATIONNAME, j.ysf.ysfreflectordb.name, rval);
isDefined(ErrorLevel::mild, JYSF, JREGISTRATIONDESCRIPTION, j.ysf.ysfreflectordb.description, rval);
// Databases
std::list<std::pair<const std::string, const struct REFLECTOR::DB *>> dbs = {
{ JDMRIDDB, &j.dmriddb },
{ JNXDNIDDB, &j.nxdniddb },
{ JYSFTXRXDB, &j.ysftxrxdb }
};
for ( auto &item : dbs )
{
isDefined(ErrorLevel::fatal, item.first, JHOSTNAME, item.second->hostname, rval);
isDefined(ErrorLevel::fatal, item.first, JSUFFIX, item.second->suffix, rval);
isDefined(ErrorLevel::fatal, item.first, JMODE, item.second->mode, rval);
isDefined(ErrorLevel::fatal, item.first, JREFRESHMIN, item.second->refreshmin, rval);
isDefined(ErrorLevel::fatal, item.first, JFILEPATH, item.second->filepath, rval);
}
// Other files
isDefined(ErrorLevel::fatal, JFILES, JPIDPATH, j.files.pid, rval);
isDefined(ErrorLevel::fatal, JFILES, JJSONPATH, j.files.json, rval);
isDefined(ErrorLevel::fatal, JFILES, JWHITELISTPATH, j.files.white, rval);
isDefined(ErrorLevel::fatal, JFILES, JBLACKLISTPATH, j.files.black, rval);
isDefined(ErrorLevel::fatal, JFILES, JINTERLINKPATH, j.files.interlink, rval);
isDefined(ErrorLevel::fatal, JFILES, JG3TERMINALPATH, j.files.terminal, rval);
return rval;
}
bool CConfigure::isDefined(ErrorLevel level, const std::string &section, const std::string &pname, const std::string &key, bool &rval)
{
if (data.contains(key))
return true;
if (ErrorLevel::mild == level)
{
std::cout << "WARNING: [" << section << "] " << pname << " is not defined" << std::endl;
data[key] = nullptr;
}
else
{
std::cerr << "ERROR: [" << section << "] " << pname << " is not defined" << std::endl;
rval = true;
}
return false;
}
void CConfigure::checkAutoLink(const std::string &section, const std::string &pname, const std::string &key, bool &rval)
{
if (data.contains(key))
{
auto ismods = data.contains(j.modules.modules);
const auto mods(ismods ? data[j.modules.modules].get<std::string>() : "");
const auto c = data[key].get<std::string>().at(0);
if (std::string::npos == mods.find(c))
{
std::cerr << "ERROR: [" << section << "] " << pname << " module '" << c << "' not a configured module" << std::endl;
rval = true;
}
}
else
data[key] = nullptr;
}
std::string CConfigure::getDataRefreshType(ERefreshType type) const
{
if (ERefreshType::both == type)
return std::string("both");
else if (ERefreshType::file == type)
return std::string("file");
else
return std::string("http");
}
unsigned CConfigure::getUnsigned(const std::string &valuestr, const std::string &label, unsigned min, unsigned max, unsigned def) const
{
auto i = unsigned(std::stoul(valuestr.c_str()));
if ( i < min || i > max )
{
std::cout << "WARNING: line #" << counter << ": " << label << " is out of range. Reset to " << def << std::endl;
i = def;
}
return (unsigned)i;
}
void CConfigure::badParam(const std::string &key) const
{
std::cout << "WARNING: line #" << counter << ": Unexpected parameter: '" << key << "'" << std::endl;
}
bool CConfigure::checkModules(std::string &m) const
{
bool rval = false; // return true on error
for(unsigned i=0; i<m.size(); i++)
if (islower(m[i]))
m[i] = toupper(m[i]);
const std::string all("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
std::string found;
for (auto c : all)
if (std::string::npos != m.find(c) && std::string::npos == found.find(c))
found.append(1, c);
m.assign(found);
return m.empty();
}
void CConfigure::setAutolink(const std::string &section, const std::string &key, const std::string &value)
{
auto c = toupper(value.at(0));
if (isupper(c))
data[key] = std::string(1, c);
else
std::cout << "WARNING: line #" << counter << ": " << section << " AutoLinkModule is invalid: '" << value.substr(0, 1) << "'" << std::endl;
}
void CConfigure::Dump(bool justpublic) const
{
nlohmann::json tmpjson = data;
if (justpublic)
{
for (auto &it : data.items())
{
if (islower(it.key().at(0)))
tmpjson.erase(it.key());
}
}
std::cout << tmpjson.dump(4) << std::endl;
}
ERefreshType CConfigure::GetRefreshType(const std::string &key) const
{
ERefreshType type = ERefreshType::http;
if (data.contains(key))
{
if (data[key].is_string())
{
auto s = data[key].get<std::string>();
if (0 == s.compare("both"))
type = ERefreshType::both;
else if (0 == s.compare("file"))
type = ERefreshType::file;
else
type = ERefreshType::http;
}
}
return type;
}
std::string CConfigure::GetString(const std::string &key) const
{
std::string str;
if (data.contains(key))
{
if (data[key].is_null())
{
// null is the same thing as an empty string
return str;
}
else if (data[key].is_string())
{
str.assign(data[key].get<std::string>());
}
else
std::cerr << "ERROR: GetString(): '" << key << "' is not a string" << std::endl;
}
else
{
std::cerr << "ERROR: GetString(): item at '" << key << "' is not defined" << std::endl;
}
return str;
}
unsigned CConfigure::GetUnsigned(const std::string &key) const
{
unsigned u = 0;
if (data.contains(key))
{
if (data[key].is_number_unsigned())
{
u = data[key].get<unsigned>();
}
else
std::cerr << "ERROR: GetString(): '" << key << "' is not an unsigned value" << std::endl;
}
else
{
std::cerr << "ERROR: GetString(): item at '" << key << "' is not defined" << std::endl;
}
return u;
}
char CConfigure::GetAutolinkModule(const std::string &key) const
{
char c = 0;
if (data.contains(key))
{
if (data[key].is_string())
{
c = data[key].get<std::string>().at(0);
}
}
return c;
}
bool CConfigure::IsString(const std::string &key) const
{
if (data.contains(key))
return data[key].is_string();
return false;
}
#ifdef INICHECK
int main(int argc, char *argv[])
{
if (argc == 2)
{
CConfigure d;
auto rval = d.ReadData(argv[1]);
d.Dump(true);
return rval ? EXIT_FAILURE : EXIT_SUCCESS;
}
std::cerr << "Usage: " << argv[0] << " FILENAME" << std::endl;
return EXIT_SUCCESS;
}
#endif

@ -0,0 +1,106 @@
/*
* Copyright (c) 2023 by Thomas A. Early N7TAE
*
* 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 <cstdint>
#include <string>
#include <regex>
#include <nlohmann/json.hpp>
enum class ErrorLevel { fatal, mild };
enum class ERefreshType { file, http, both };
enum class ESection { none, names, ip, modules, urf, dplus, dextra, dcs, dmrplus, mmdvm, nxdn, bm, ysf, p25, m17, usrp, dmrid, nxdnid, ysffreq, files };
#define IS_TRUE(a) ((a)=='t' || (a)=='T' || (a)=='1')
class CConfigure
{
public:
// json names
struct REFLECTOR {
struct BM { const std::string port; } bm;
struct DCS { const std::string port; } dcs;
struct DEXTRA { const std::string port; } dextra;
struct DMRPLUS { const std::string port; } dmrplus;
struct DPLUS { const std::string port; } dplus;
struct M17 { const std::string port; } m17;
struct URF { const std::string port; } urf;
struct NAMES { const std::string cs, email, country, sponsor; } names;
struct IP { const std::string ipv4bind, ipv4address, ipv6bind, ipv6address, transcoder; } ip;
struct MODULES { const std::string modules, tcmodules, descriptor[26]; } modules;
struct USRP { const std::string port, autolinkmod, defaultcallsign, clientfilepath; } usrp;
struct P25NXDN { const std::string port, autolinkmod, reflectorid; } p25, nxdn;
struct YSF {
const std::string port, autolinkmod, defaulttxfreq, defaultrxfreq;
struct YSLREG { const std::string id, name, description; } ysfreflectordb;
} ysf;
struct MMDVM { const std::string port, defaultid; } mmdvm;
struct DB { const std::string hostname, suffix, mode, refreshmin, filepath; } dmriddb, nxdniddb, ysftxrxdb;
struct FILES { const std::string pid, json, white, black, interlink, terminal; } files;
} j = {
{ "BrandMeisterPort" },
{ "DCSPort" },
{ "DExtraPort" },
{ "DMRPlusPort" },
{ "DPlusPort" },
{ "M17Port" },
{ "URFPort" },
{ "Callsign", "SysopEmail", "Country", "Sponsor" },
{ "ipv4bind", "IPv4Address", "ipv6bind", "IPv6Address", "tcaddress" },
{ "Modules", "TranscodedModules", "DescriptionA", "DescriptionB", "DescriptionC",
"DescriptionD", "DescriptionE", "DescriptionF", "DescriptionG", "DescriptionH",
"DescriptionI", "DescriptionJ", "DescriptionK", "DescriptionL", "DescriptionM",
"DescriptionN", "DescriptionO", "DescriptionP", "DescriptionQ", "DescriptionR",
"DescriptionS", "DescriptionT", "DescriptionU", "DescriptionV", "DescriptionW",
"DescriptionX", "DescriptionY", "DescriptionZ" },
{ "USRPPort", "USRPAutolinkMod", "usrpDefaultCallsign", "usrpClientfilePath" },
{ "P25Port", "P25AutolinkMod", "P25ReflectorID" },
{ "NXDNPort", "NXDNAutolinkMod", "NXDNReflectorID" },
{ "YSFPort", "YSFAutoLinkMod", "YSFDefaultTxFreq", "YSFDefaultRxFreq", { "ysfrefdbid", "ysfrefdbname", "ysfrefdbdesc" } },
{ "MMDVMPort", "mmdvmdefaultid" },
{ "dmrIdDbHost", "dmrIdDbSuffix", "dmrIdDbMode", "dmrIdDbRefresh", "dmrIdDbFilePath" },
{ "nxdnIdDbHost", "nxdnIdDbSuffix", "nxdnIdDbMode", "nxdnIdDbRefresh", "nxdnIdDbFilePath" },
{ "ysfIdDbHost", "ysfIdDbSuffix", "ysfIdDbMode", "ysfIdDbRefresh", "ysfIdDbFilePath" },
{ "pidFilePath", "jsonFilePath", "whitelistFilePath", "blacklistFilePath", "interlinkFilePath", "g3TerminalFilePath" }
};
CConfigure();
bool ReadData(const std::string &path);
void Dump(bool justpublic) const;
std::string GetString(const std::string &key) const;
unsigned GetUnsigned(const std::string &key) const;
ERefreshType GetRefreshType(const std::string &key) const;
bool IsString(const std::string &key) const;
char GetAutolinkModule(const std::string &key) const;
private:
// CFGDATA data;
unsigned counter;
nlohmann::json data;
std::regex IPv4RegEx, IPv6RegEx;
void CurlAddresses(std::string &v4, std::string &v6) const;
std::string getDataRefreshType(ERefreshType t) const;
unsigned getUnsigned(const std::string &value, const std::string &label, unsigned min, unsigned max, unsigned defaultvalue) const;
void badParam(const std::string &param) const;
bool checkModules(std::string &m) const;
void setAutolink(const std::string &section, const std::string &key, const std::string &value);
bool isDefined(ErrorLevel level, const std::string &section, const std::string &pname, const std::string &key, bool &rval);
void checkAutoLink(const std::string &section, const std::string &pname, const std::string &key, bool &rval);
};

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "DCSClient.h"

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "DCSClient.h"
#include "DCSProtocol.h"
@ -68,7 +68,7 @@ void CDcsProtocol::Task(void)
if ( IsValidDvPacket(Buffer, Header, Frame) )
{
// callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dcs, Header->GetRpt2Module()) )
if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dcs, Header->GetRpt2Module()) )
{
OnDvHeaderPacketIn(Header, Ip);
@ -80,18 +80,18 @@ void CDcsProtocol::Task(void)
std::cout << "DCS connect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::dcs) && g_Reflector.IsValidModule(ToLinkModule) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::dcs) && g_Refl..IsValidModule(ToLinkModule) )
{
// valid module ?
if ( g_Reflector.IsValidModule(ToLinkModule) )
if ( g_Refl..IsValidModule(ToLinkModule) )
{
// acknowledge the request
EncodeConnectAckPacket(Callsign, ToLinkModule, &Buffer);
Send(Buffer, Ip);
// create the client and append
g_Reflector.GetClients()->AddClient(std::make_shared<CDcsClient>(Callsign, Ip, ToLinkModule));
g_Reflector.ReleaseClients();
g_Refl..GetClients()->AddClient(std::make_shared<CDcsClient>(Callsign, Ip, ToLinkModule));
g_Refl..ReleaseClients();
}
else
{
@ -115,7 +115,7 @@ void CDcsProtocol::Task(void)
std::cout << "DCS disconnect packet from " << Callsign << " at " << Ip << std::endl;
// find client
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::dcs);
if ( client != nullptr )
{
@ -125,21 +125,21 @@ void CDcsProtocol::Task(void)
EncodeConnectNackPacket(Callsign, ' ', &Buffer);
Send(Buffer, Ip);
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else if ( IsValidKeepAlivePacket(Buffer, &Callsign) )
{
//std::cout << "DCS keepalive packet from " << Callsign << " at " << Ip << std::endl;
// find all clients with that callsign & ip and keep them alive
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(Callsign, Ip, EProtocol::dcs, it)) != nullptr )
{
client->Alive();
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else if ( IsIgnorePacket(Buffer) )
{
@ -193,24 +193,24 @@ void CDcsProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
CCallsign rpt2(Header->GetRpt2Callsign());
// find this client
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, EProtocol::dcs);
std::shared_ptr<CClient>client = g_Refl..GetClients()->FindClient(Ip, EProtocol::dcs);
if ( client )
{
// get client callsign
rpt1 = client->GetCallsign();
// and try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams[stream->GetStreamId()] = stream;
}
}
// release
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers();
g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Refl..ReleaseUsers();
}
}
@ -253,7 +253,7 @@ void CDcsProtocol::HandleQueue(void)
if ( buffer.size() > 0 )
{
// and push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::dcs, it)) != nullptr )
@ -266,7 +266,7 @@ void CDcsProtocol::HandleQueue(void)
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
}
@ -285,7 +285,7 @@ void CDcsProtocol::HandleKeepalives(void)
EncodeKeepAlivePacket(&keepalive1);
// iterate on clients
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::dcs, it)) != nullptr )
@ -318,7 +318,7 @@ void CDcsProtocol::HandleKeepalives(void)
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
////////////////////////////////////////////////////////////////////////////////////////

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "DExtraClient.h"

@ -17,7 +17,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "Reflector.h"
#include "DExtraPeer.h"

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "DExtraPeer.h"
#include "DExtraClient.h"
@ -74,7 +74,7 @@ void CDextraProtocol::Task(void)
else if ( IsValidDvHeaderPacket(Buffer, Header) )
{
// callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dextra, Header->GetRpt2Module()) )
if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dextra, Header->GetRpt2Module()) )
{
OnDvHeaderPacketIn(Header, Ip);
}
@ -98,20 +98,20 @@ void CDextraProtocol::Task(void)
}
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::dextra) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::dextra) )
{
// valid module ?
if ( g_Reflector.IsValidModule(ToLinkModule) )
if ( g_Refl..IsValidModule(ToLinkModule) )
{
// is this an ack for a link request?
CPeerCallsignList *list = g_GateKeeper.GetPeerList();
CPeerCallsignList *list = g_Gate.GetPeerList();
CCallsignListItem *item = list->FindListItem(Callsign);
if ( item != nullptr && Callsign.GetCSModule() == item->GetModules()[1] && ToLinkModule == item->GetModules()[0] )
{
std::cout << "DExtra ack packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
// already connected ?
CPeers *peers = g_Reflector.GetPeers();
CPeers *peers = g_Refl..GetPeers();
if ( peers->FindPeer(Callsign, Ip, EProtocol::dextra) == nullptr )
{
// create the new peer
@ -120,7 +120,7 @@ void CDextraProtocol::Task(void)
// this also add all new clients to reflector client list
peers->AddPeer(std::make_shared<CDextraPeer>(Callsign, Ip, std::string(1, ToLinkModule).c_str(), CVersion(2, 0, 0)));
}
g_Reflector.ReleasePeers();
g_Refl..ReleasePeers();
}
else
{
@ -129,10 +129,10 @@ void CDextraProtocol::Task(void)
Send(Buffer, Ip);
// create the client and append
g_Reflector.GetClients()->AddClient(std::make_shared<CDextraClient>(Callsign, Ip, ToLinkModule, ProtRev));
g_Reflector.ReleaseClients();
g_Refl..GetClients()->AddClient(std::make_shared<CDextraClient>(Callsign, Ip, ToLinkModule, ProtRev));
g_Refl..ReleaseClients();
}
g_GateKeeper.ReleasePeerList();
g_Gate.ReleasePeerList();
}
else
{
@ -155,7 +155,7 @@ void CDextraProtocol::Task(void)
std::cout << "DExtra disconnect packet from " << Callsign << " at " << Ip << std::endl;
// find client & remove it
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::dextra);
if ( client != nullptr )
{
@ -172,21 +172,21 @@ void CDextraProtocol::Task(void)
// and remove it
clients->RemoveClient(client);
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else if ( IsValidKeepAlivePacket(Buffer, &Callsign) )
{
//std::cout << "DExtra keepalive packet from " << Callsign << " at " << Ip << std::endl;
// find all clients with that callsign & ip and keep them alive
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(Callsign, Ip, EProtocol::dextra, it)) != nullptr )
{
client->Alive();
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else
{
@ -239,7 +239,7 @@ void CDextraProtocol::HandleQueue(void)
if ( EncodeDvPacket(*packet, buffer) )
{
// and push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::dextra, it)) != nullptr )
@ -255,7 +255,7 @@ void CDextraProtocol::HandleQueue(void)
}
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
m_Queue.Unlock();
@ -273,7 +273,7 @@ void CDextraProtocol::HandleKeepalives(void)
EncodeKeepAlivePacket(&keepalive);
// iterate on clients
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::dextra, it)) != nullptr )
@ -290,7 +290,7 @@ void CDextraProtocol::HandleKeepalives(void)
// otherwise check if still with us
else if ( !client->IsAlive() )
{
CPeers *peers = g_Reflector.GetPeers();
CPeers *peers = g_Refl..GetPeers();
std::shared_ptr<CPeer>peer = peers->FindPeer(client->GetCallsign(), client->GetIp(), EProtocol::dextra);
if ( peer != nullptr && peer->GetReflectorModules()[0] == client->GetReflectorModule() )
{
@ -307,14 +307,14 @@ void CDextraProtocol::HandleKeepalives(void)
std::cout << "DExtra client " << client->GetCallsign() << " keepalive timeout" << std::endl;
clients->RemoveClient(client);
}
g_Reflector.ReleasePeers();
g_Refl..ReleasePeers();
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// iterate on peers
CPeers *peers = g_Reflector.GetPeers();
CPeers *peers = g_Refl..GetPeers();
auto pit = peers->begin();
std::shared_ptr<CPeer>peer = nullptr;
while ( (peer = peers->FindNextPeer(EProtocol::dextra, pit)) != nullptr )
@ -327,19 +327,19 @@ void CDextraProtocol::HandleKeepalives(void)
// no, disconnect all clients
CBuffer disconnect;
EncodeDisconnectPacket(&disconnect, peer->GetReflectorModules()[0]);
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
for ( auto cit=peer->cbegin(); cit!=peer->cend(); cit++ )
{
Send(disconnect, (*cit)->GetIp());
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// remove it
std::cout << "DExtra peer " << peer->GetCallsign() << " keepalive timeout" << std::endl;
peers->RemovePeer(peer);
}
}
g_Reflector.ReleasePeers();
g_Refl..ReleasePeers();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -350,8 +350,8 @@ void CDextraProtocol::HandlePeerLinks(void)
CBuffer buffer;
// get the list of peers
CPeerCallsignList *list = g_GateKeeper.GetPeerList();
CPeers *peers = g_Reflector.GetPeers();
CPeerCallsignList *list = g_Gate.GetPeerList();
CPeers *peers = g_Refl..GetPeers();
// check if all our connected peers are still listed by gatekeeper
// if not, disconnect
@ -390,8 +390,8 @@ void CDextraProtocol::HandlePeerLinks(void)
}
// done
g_Reflector.ReleasePeers();
g_GateKeeper.ReleasePeerList();
g_Refl..ReleasePeers();
g_Gate.ReleasePeerList();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -415,7 +415,7 @@ void CDextraProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Heade
CCallsign rpt2(Header->GetRpt2Callsign());
// find this client
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, EProtocol::dextra);
std::shared_ptr<CClient>client = g_Refl..GetClients()->FindClient(Ip, EProtocol::dextra);
if ( client )
{
// get client callsign
@ -430,18 +430,18 @@ void CDextraProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Heade
rpt2.SetCSModule(m);
}
// and try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams[stream->GetStreamId()] = stream;
}
}
// release
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers();
g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Refl..ReleaseUsers();
}
}

@ -1,145 +0,0 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h"
#include "Reflector.h"
#include "DMRIdDir.h"
#include "DMRIdDirFile.h"
#include "DMRIdDirHttp.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor & destructor
CDmridDir::CDmridDir()
{
keep_running = true;
}
CDmridDir::~CDmridDir()
{
Close();
}
////////////////////////////////////////////////////////////////////////////////////////
// init & close
bool CDmridDir::Init(void)
{
// load content
Reload();
// reset run flag
keep_running = true;
// start thread;
m_Future = std::async(std::launch::async, &CDmridDir::Thread, this);
return true;
}
void CDmridDir::Close(void)
{
keep_running = false;
if ( m_Future.valid() )
{
m_Future.get();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// thread
void CDmridDir::Thread()
{
while (keep_running)
{
// Wait DMRIDDB_REFRESH_RATE minutes
for (int i=0; i<30*DMRIDDB_REFRESH_RATE && keep_running; i++)
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
// have lists files changed ?
if ( NeedReload() )
{
Reload();
}
}
}
////////////////////////////////////////////////////////////////////////////////////////
// Reload
bool CDmridDir::Reload(void)
{
CBuffer buffer;
bool ok = false;
if ( LoadContent(&buffer) )
{
Lock();
{
ok = RefreshContent(buffer);
}
Unlock();
}
return ok;
}
////////////////////////////////////////////////////////////////////////////////////////
// find
const CCallsign *CDmridDir::FindCallsign(uint32_t dmrid)
{
auto found = m_CallsignMap.find(dmrid);
if ( found != m_CallsignMap.end() )
{
return &(found->second);
}
return nullptr;
}
uint32_t CDmridDir::FindDmrid(const CCallsign &callsign)
{
auto found = m_DmridMap.find(callsign);
if ( found != m_DmridMap.end() )
{
return (found->second);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////
// syntax helpers
bool CDmridDir::IsValidDmrid(const char *sz)
{
bool ok = false;
size_t n = ::strlen(sz);
if ( (n > 0) && (n <= 8) )
{
ok = true;
for ( size_t i = 0; (i < n) && ok; i++ )
{
ok &= ::isdigit(sz[i]);
}
}
return ok;
}

@ -1,159 +0,0 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "Main.h"
#include "DMRIdDirFile.h"
#if (DMRIDDB_USE_RLX_SERVER == 0)
CDmridDirFile g_DmridDir;
#endif
////////////////////////////////////////////////////////////////////////////////////////
// constructor & destructor
CDmridDirFile::CDmridDirFile()
{
memset(&m_LastModTime, 0, sizeof(time_t));
}
////////////////////////////////////////////////////////////////////////////////////////
// init & close
bool CDmridDirFile::Init(void)
{
return CDmridDir::Init();
}
////////////////////////////////////////////////////////////////////////////////////////
// refresh
bool CDmridDirFile::NeedReload(void)
{
bool needReload = false;
time_t time;
if ( GetLastModTime(&time) )
{
needReload = time != m_LastModTime;
}
return needReload;
}
bool CDmridDirFile::LoadContent(CBuffer *buffer)
{
bool ok = false;
std::ifstream file;
std::streampos size;
// open file
file.open(DMRIDDB_PATH, std::ios::in | std::ios::binary | std::ios::ate);
if ( file.is_open() )
{
// read file
size = file.tellg();
if ( size > 0 )
{
// read file into buffer
buffer->resize((int)size+1);
file.seekg (0, std::ios::beg);
file.read((char *)buffer->data(), (int)size);
// close file
file.close();
// update time
GetLastModTime(&m_LastModTime);
// done
ok = true;
}
}
// done
return ok;
}
bool CDmridDirFile::RefreshContent(const CBuffer &buffer)
{
bool ok = false;
// clear directory
m_CallsignMap.clear();
m_DmridMap.clear();
// scan buffer
if ( buffer.size() > 0 )
{
// crack it
char *ptr1 = (char *)buffer.data();
char *ptr2;
// get next line
while ( (ptr2 = ::strchr(ptr1, '\n')) != nullptr )
{
*ptr2 = 0;
// get items
char *dmrid;
char *callsign;
if ( ((dmrid = ::strtok(ptr1, ";")) != nullptr) && IsValidDmrid(dmrid) )
{
if ( ((callsign = ::strtok(nullptr, ";")) != nullptr) )
{
// new entry
uint32_t ui = atoi(dmrid);
CCallsign cs(callsign, ui);
if ( cs.IsValid() )
{
m_CallsignMap.insert(std::pair<uint32_t,CCallsign>(ui, cs));
m_DmridMap.insert(std::pair<CCallsign,uint32_t>(cs,ui));
}
}
}
// next line
ptr1 = ptr2+1;
}
// done
ok = true;
}
// report
std::cout << "Read " << m_DmridMap.size() << " DMR ids from file " << DMRIDDB_PATH << std::endl;
// done
return ok;
}
bool CDmridDirFile::GetLastModTime(time_t *time)
{
bool ok = false;
struct stat fileStat;
if( ::stat(DMRIDDB_PATH, &fileStat) != -1 )
{
*time = fileStat.st_mtime;
ok = true;
}
return ok;
}

@ -1,177 +0,0 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
// Copyright © 2021 Doug McLain AD8DP
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h"
#include "Reflector.h"
#include "DMRIdDirHttp.h"
#if (DMRIDDB_USE_RLX_SERVER == 1)
CDmridDirHttp g_DmridDir;
#endif
////////////////////////////////////////////////////////////////////////////////////////
// refresh
bool CDmridDirHttp::LoadContent(CBuffer *buffer)
{
// get file from xlxapi server
return HttpGet("xlxapi.rlx.lu", "api/exportdmr.php", 80, buffer);
}
bool CDmridDirHttp::RefreshContent(const CBuffer &buffer)
{
bool ok = false;
// clear directory
m_CallsignMap.clear();
m_DmridMap.clear();
// scan file
if ( buffer.size() > 0 )
{
char *ptr1 = (char *)buffer.data();
char *ptr2;
// get next line
while ( (ptr2 = ::strchr(ptr1, '\n')) != nullptr )
{
*ptr2 = 0;
// get items
char *dmrid;
char *callsign;
if ( ((dmrid = ::strtok(ptr1, ";")) != nullptr) && IsValidDmrid(dmrid) )
{
if ( ((callsign = ::strtok(nullptr, ";")) != nullptr) )
{
// new entry
uint32_t ui = atoi(dmrid);
CCallsign cs(callsign, ui);
if ( cs.IsValid() )
{
m_CallsignMap.insert(std::pair<uint32_t,CCallsign>(ui, cs));
m_DmridMap.insert(std::pair<CCallsign,uint32_t>(cs,ui));
}
}
}
// next line
ptr1 = ptr2+1;
}
// done
ok = true;
}
// report
std::cout << "Read " << m_DmridMap.size() << " DMR ids from xlxapi.rlx.lu database " << std::endl;
// done
return ok;
}
////////////////////////////////////////////////////////////////////////////////////////
// httpd helpers
#define DMRID_HTTPGET_SIZEMAX (256)
bool CDmridDirHttp::HttpGet(const char *hostname, const char *filename, int port, CBuffer *buffer)
{
bool ok = false;
int sock_id;
// open socket
if ( (sock_id = ::socket(AF_INET, SOCK_STREAM, 0)) >= 0 )
{
// get hostname address
struct sockaddr_in servaddr;
struct hostent *hp;
memset(&servaddr,0,sizeof(servaddr));
if( (hp = gethostbyname(hostname)) != nullptr )
{
// dns resolved
memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
servaddr.sin_port = htons(port);
servaddr.sin_family = AF_INET;
// connect
if ( ::connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0)
{
// send the GET request
char request[DMRID_HTTPGET_SIZEMAX];
::sprintf(request, "GET /%s HTTP/1.0\r\nFrom: %s\r\nUser-Agent: urfd\r\n\r\n",
filename, (const char *)g_Reflector.GetCallsign());
::write(sock_id, request, strlen(request));
// config receive timeouts
fd_set read_set;
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
FD_ZERO(&read_set);
FD_SET(sock_id, &read_set);
// get the reply back
buffer->clear();
bool done = false;
do
{
char buf[1440];
ssize_t len = 0;
select(sock_id+1, &read_set, nullptr, nullptr, &timeout);
//if ( (ret > 0) || ((ret < 0) && (errno == EINPROGRESS)) )
//if ( ret >= 0 )
//{
usleep(5000);
len = read(sock_id, buf, 1440);
if ( len > 0 )
{
buffer->Append((uint8_t *)buf, (int)len);
ok = true;
}
//}
done = (len <= 0);
}
while (!done);
buffer->Append((uint8_t)0);
// and disconnect
close(sock_id);
}
else
{
std::cout << "Cannot establish connection with host " << hostname << std::endl;
}
}
else
{
std::cout << "Host " << hostname << " not found" << std::endl;
}
}
else
{
std::cout << "Failed to open wget socket" << std::endl;
}
// done
return ok;
}

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "DMRMMDVMClient.h"

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "DMRMMDVMClient.h"
#include "DMRMMDVMProtocol.h"
@ -93,7 +93,7 @@ void CDmrmmdvmProtocol::Task(void)
if ( Receive4(Buffer, Ip, 20) )
#endif
{
//Buffer.DebugDump(g_Reflector.m_DebugFile);
//Buffer.DebugDump(g_Refl..m_DebugFile);
// crack the packet
if ( IsValidDvFramePacket(Buffer, Frames) )
{
@ -105,7 +105,7 @@ void CDmrmmdvmProtocol::Task(void)
else if ( IsValidDvHeaderPacket(Buffer, Header, &Cmd, &CallType) )
{
// callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dmrmmdvm) )
if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dmrmmdvm) )
{
// handle it
OnDvHeaderPacketIn(Header, Ip, Cmd, CallType);
@ -120,7 +120,7 @@ void CDmrmmdvmProtocol::Task(void)
std::cout << "DMRmmdvm connect packet from " << Callsign << " at " << Ip << std::endl;
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::dmrmmdvm) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::dmrmmdvm) )
{
// acknowledge the request
EncodeConnectAckPacket(&Buffer, Callsign, m_uiAuthSeed);
@ -139,14 +139,14 @@ void CDmrmmdvmProtocol::Task(void)
std::cout << "DMRmmdvm authentication packet from " << Callsign << " at " << Ip << std::endl;
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::dmrmmdvm) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::dmrmmdvm) )
{
// acknowledge the request
EncodeAckPacket(&Buffer, Callsign);
Send(Buffer, Ip);
// add client if needed
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Callsign, Ip, EProtocol::dmrmmdvm);
// client already connected ?
if ( client == nullptr )
@ -161,7 +161,7 @@ void CDmrmmdvmProtocol::Task(void)
client->Alive();
}
// and done
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else
{
@ -176,13 +176,13 @@ void CDmrmmdvmProtocol::Task(void)
std::cout << "DMRmmdvm disconnect packet from " << Callsign << " at " << Ip << std::endl;
// find client & remove it
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::dmrmmdvm);
if ( client != nullptr )
{
clients->RemoveClient(client);
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else if ( IsValidConfigPacket(Buffer, &Callsign, Ip) )
{
@ -197,7 +197,7 @@ void CDmrmmdvmProtocol::Task(void)
//std::cout << "DMRmmdvm keepalive packet from " << Callsign << " at " << Ip << std::endl;
// find all clients with that callsign & ip and keep them alive
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(Callsign, Ip, EProtocol::dmrmmdvm, it)) != nullptr )
@ -209,7 +209,7 @@ void CDmrmmdvmProtocol::Task(void)
// and mark as alive
client->Alive();
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else if ( IsValidRssiPacket(Buffer, &Callsign, &iRssi) )
{
@ -273,7 +273,7 @@ void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Hea
CCallsign rpt2(Header->GetRpt2Callsign());
// no stream open yet, open a new one
// firstfind this client
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, EProtocol::dmrmmdvm);
std::shared_ptr<CClient>client = g_Refl..GetClients()->FindClient(Ip, EProtocol::dmrmmdvm);
if ( client )
{
// process cmd if any
@ -282,7 +282,7 @@ void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Hea
// not linked yet
if ( cmd == CMD_LINK )
{
if ( g_Reflector.IsValidModule(rpt2.GetCSModule()) )
if ( g_Refl..IsValidModule(rpt2.GetCSModule()) )
{
std::cout << "DMRmmdvm client " << client->GetCallsign() << " linking on module " << rpt2.GetCSModule() << std::endl;
// link
@ -313,10 +313,10 @@ void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Hea
}
// and now, re-check module is valid && that it's not a private call
if ( g_Reflector.IsValidModule(rpt2.GetCSModule()) && (CallType == DMR_GROUP_CALL) )
if ( g_Refl..IsValidModule(rpt2.GetCSModule()) && (CallType == DMR_GROUP_CALL) )
{
// yes, try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams[stream->GetStreamId()] = stream;
@ -330,13 +330,13 @@ void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Hea
}
// release
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// update last heard
if ( lastheard )
{
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers();
g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Refl..ReleaseUsers();
}
}
}
@ -403,7 +403,7 @@ void CDmrmmdvmProtocol::HandleQueue(void)
if ( buffer.size() > 0 )
{
// and push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::dmrmmdvm, it)) != nullptr )
@ -416,7 +416,7 @@ void CDmrmmdvmProtocol::HandleQueue(void)
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
m_Queue.Unlock();
@ -432,7 +432,7 @@ void CDmrmmdvmProtocol::HandleKeepalives(void)
// and disconnect them if not
// iterate on clients
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::dmrmmdvm, it)) != nullptr )
@ -456,7 +456,7 @@ void CDmrmmdvmProtocol::HandleKeepalives(void)
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -696,7 +696,7 @@ bool CDmrmmdvmProtocol::IsValidDvFramePacket(const CBuffer &Buffer, std::array<s
// debug
//CBuffer dump;
//dump.Set(dmrsync, 6);
//dump.DebugDump(g_Reflector.m_DebugFile);
//dump.DebugDump(g_Refl..m_DebugFile);
// and create 3 dv frames
// frame1
@ -860,14 +860,14 @@ void CDmrmmdvmProtocol::EncodeMMDVMPacket(const CDvHeaderPacket &Header, const C
uint8_t tag[] = { 'D','M','R','D' };
Buffer->Set(tag, sizeof(tag));
uint8_t cs[12];
// DMR header
// uiSeqId
Buffer->Append((uint8_t)seqid);
// uiSrcId
uint32_t uiSrcId = Header.GetMyCallsign().GetDmrid();
DvFrame0.GetMyCallsign().GetCallsign(cs);
if(uiSrcId == 0){
uiSrcId = DvFrame0.GetMyCallsign().GetDmrid();
}
@ -880,7 +880,7 @@ void CDmrmmdvmProtocol::EncodeMMDVMPacket(const CDvHeaderPacket &Header, const C
if(uiSrcId == 0){
uiSrcId = DMRMMDVM_DEFAULTID;
}
AppendDmrIdToBuffer(Buffer, uiSrcId);
// uiDstId = TG9
uint32_t uiDstId = 9; // ModuleToDmrDestId(Header.GetRpt2Module());
@ -924,7 +924,7 @@ void CDmrmmdvmProtocol::EncodeMMDVMPacket(const CDvHeaderPacket &Header, const C
// debug
//CBuffer dump;
//dump.Set(&(Buffer->data()[33]), 7);
//dump.DebugDump(g_Reflector.m_DebugFile);
//dump.DebugDump(g_Refl..m_DebugFile);
// BER
Buffer->Append((uint8_t)0);

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "DMRPlusClient.h"

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "DMRPlusClient.h"
#include "DMRPlusProtocol.h"
@ -93,7 +93,7 @@ void CDmrplusProtocol::Task(void)
else if ( IsValidDvHeaderPacket(Ip, Buffer, Header) )
{
// callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dmrplus) )
if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dmrplus) )
{
// handle it
OnDvHeaderPacketIn(Header, Ip);
@ -104,14 +104,14 @@ void CDmrplusProtocol::Task(void)
//std::cout << "DMRplus keepalive/connect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::dmrplus) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::dmrplus) )
{
// acknowledge the request
EncodeConnectAckPacket(&Buffer);
Send(Buffer, Ip);
// add client if needed
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Callsign, Ip, EProtocol::dmrplus);
// client already connected ?
if ( client == nullptr )
@ -126,7 +126,7 @@ void CDmrplusProtocol::Task(void)
client->Alive();
}
// and done
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else
{
@ -141,13 +141,13 @@ void CDmrplusProtocol::Task(void)
std::cout << "DMRplus disconnect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
// find client & remove it
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::dmrplus);
if ( client != nullptr )
{
clients->RemoveClient(client);
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else
{
@ -196,21 +196,21 @@ void CDmrplusProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Head
// no stream open yet, open a new one
// find this client
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, EProtocol::dmrplus);
std::shared_ptr<CClient>client = g_Refl..GetClients()->FindClient(Ip, EProtocol::dmrplus);
if ( client )
{
// and try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams[stream->GetStreamId()] = stream;
}
}
// release
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers();
g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Refl..ReleaseUsers();
}
}
@ -268,7 +268,7 @@ void CDmrplusProtocol::HandleQueue(void)
if ( buffer.size() > 0 )
{
// and push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::dmrplus, it)) != nullptr )
@ -280,10 +280,10 @@ void CDmrplusProtocol::HandleQueue(void)
Send(buffer, client->GetIp());
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// debug
//buffer.DebugDump(g_Reflector.m_DebugFile);
//buffer.DebugDump(g_Refl..m_DebugFile);
}
}
m_Queue.Unlock();
@ -294,7 +294,7 @@ void CDmrplusProtocol::SendBufferToClients(const CBuffer &buffer, uint8_t module
if ( buffer.size() > 0 )
{
// and push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::dmrplus, it)) != nullptr )
@ -306,10 +306,10 @@ void CDmrplusProtocol::SendBufferToClients(const CBuffer &buffer, uint8_t module
Send(buffer, client->GetIp());
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// debug
//buffer.DebugDump(g_Reflector.m_DebugFile);
//buffer.DebugDump(g_Refl..m_DebugFile);
}
}
@ -324,7 +324,7 @@ void CDmrplusProtocol::HandleKeepalives(void)
// and disconnect them if not
// iterate on clients
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::dmrplus, it)) != nullptr )
@ -349,7 +349,7 @@ void CDmrplusProtocol::HandleKeepalives(void)
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
////////////////////////////////////////////////////////////////////////////////////////

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "DPlusClient.h"

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "DPlusClient.h"
#include "DPlusProtocol.h"
@ -72,7 +72,7 @@ void CDplusProtocol::Task(void)
else if ( IsValidDvHeaderPacket(Buffer, Header) )
{
// is muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dplus, Header->GetRpt2Module()) )
if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dplus, Header->GetRpt2Module()) )
{
// handle it
OnDvHeaderPacketIn(Header, Ip);
@ -90,15 +90,15 @@ void CDplusProtocol::Task(void)
std::cout << "DPlus login packet from " << Callsign << " at " << Ip << std::endl;
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::dplus) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::dplus) )
{
// acknowledge the request
EncodeLoginAckPacket(&Buffer);
Send(Buffer, Ip);
// create the client and append
g_Reflector.GetClients()->AddClient(std::make_shared<CDplusClient>(Callsign, Ip));
g_Reflector.ReleaseClients();
g_Refl..GetClients()->AddClient(std::make_shared<CDplusClient>(Callsign, Ip));
g_Refl..ReleaseClients();
}
else
{
@ -113,7 +113,7 @@ void CDplusProtocol::Task(void)
std::cout << "DPlus disconnect packet from " << Ip << std::endl;
// find client
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::dplus);
if ( client != nullptr )
{
@ -123,21 +123,21 @@ void CDplusProtocol::Task(void)
EncodeDisconnectPacket(&Buffer);
Send(Buffer, Ip);
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else if ( IsValidKeepAlivePacket(Buffer) )
{
//std::cout << "DPlus keepalive packet from " << Ip << std::endl;
// find all clients with that callsign & ip and keep them alive
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(Ip, EProtocol::dplus, it)) != nullptr )
{
client->Alive();
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else
{
@ -185,10 +185,10 @@ void CDplusProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header
CCallsign rpt2(Header->GetRpt2Callsign());
// first, check module is valid
if ( g_Reflector.IsValidModule(rpt2.GetCSModule()) )
if ( g_Refl..IsValidModule(rpt2.GetCSModule()) )
{
// find this client
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, EProtocol::dplus);
std::shared_ptr<CClient>client = g_Refl..GetClients()->FindClient(Ip, EProtocol::dplus);
if ( client )
{
// now we know if it's a dextra dongle or a genuine dplus node
@ -204,18 +204,18 @@ void CDplusProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header
// get client callsign
rpt1 = client->GetCallsign();
// and try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams[stream->GetStreamId()] = stream;
}
}
// release
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers();
g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Refl..ReleaseUsers();
}
else
{
@ -253,7 +253,7 @@ void CDplusProtocol::HandleQueue(void)
// and push it to all our clients who are not streaming in
// note that for dplus protocol, all stream of all modules are push to all clients
// it's client who decide which stream he's interrrested in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::dplus, it)) != nullptr )
@ -290,7 +290,7 @@ void CDplusProtocol::HandleQueue(void)
}
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
m_Queue.Unlock();
@ -343,7 +343,7 @@ void CDplusProtocol::HandleKeepalives(void)
EncodeKeepAlivePacket(&keepalive);
// iterate on clients
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::dplus, it)) != nullptr )
@ -371,7 +371,7 @@ void CDplusProtocol::HandleKeepalives(void)
clients->RemoveClient(client);
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
////////////////////////////////////////////////////////////////////////////////////////

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "DVFramePacket.h"

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include <cstdio>
#include "DMRIdDir.h"
@ -90,7 +90,7 @@ CDvHeaderPacket::CDvHeaderPacket(const struct dstar_header *buffer, uint16_t sid
m_uiFlag2 = buffer->Flag2;
m_uiFlag3 = buffer->Flag3;
m_csUR.SetCallsign(buffer->UR, CALLSIGN_LEN);
if((buffer->RPT1)[7] == 0x20){
char rptr1[8];
memcpy(rptr1, buffer->RPT1, 8);
@ -100,7 +100,7 @@ CDvHeaderPacket::CDvHeaderPacket(const struct dstar_header *buffer, uint16_t sid
else{
m_csRPT1.SetCallsign(buffer->RPT1, CALLSIGN_LEN);
}
m_csRPT1.SetCallsign(buffer->RPT1, CALLSIGN_LEN);
m_csRPT2.SetCallsign(buffer->RPT2, CALLSIGN_LEN);
m_csMY.SetCallsign(buffer->MY, CALLSIGN_LEN);

@ -0,0 +1,125 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#pragma once
#include <atomic>
#include <vector>
#include <array>
#include <list>
#include <map>
#include <unordered_map>
#include <queue>
#include <chrono>
#include <future>
#include <mutex>
#include <memory>
#include <atomic>
#include <condition_variable>
#include <ctime>
#include <cctype>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <arpa/inet.h>
////////////////////////////////////////////////////////////////////////////////////////
// defines
//// Module configuration
#define DSTAR_IPV4 true
#define DMR_IPV4 true
#define YSF_IPV4 true
#define BM_IPV4 true
#define M17_IPV4 true
#define URF_IPV4 true
#define DSTAR_IPV6 true
#define DMR_IPV6 false
#define YSF_IPV6 false
#define BM_IPV6 false
#define M17_IPV6 true
#define URF_IPV6 true
// protocols ---------------------------------------------------
enum class EProtocol { any, none, dextra, dplus, dcs, bm, urf, dmrplus, dmrmmdvm, ysf, m17 };
// DExtra
#define DEXTRA_KEEPALIVE_PERIOD 3 // in seconds
#define DEXTRA_KEEPALIVE_TIMEOUT (DEXTRA_KEEPALIVE_PERIOD*10) // in seconds
#define DEXTRA_RECONNECT_PERIOD 5 // in seconds
// DPlus
#define DPLUS_KEEPALIVE_PERIOD 1 // in seconds
#define DPLUS_KEEPALIVE_TIMEOUT (DPLUS_KEEPALIVE_PERIOD*10) // in seconds
#define DPLUS_DEFAULT_RPTR1_SUFFIX 'Y'
// DCS
#define DCS_KEEPALIVE_PERIOD 1 // in seconds
#define DCS_KEEPALIVE_TIMEOUT (DCS_KEEPALIVE_PERIOD*30) // in seconds
// XLX, used for BM
#define BM_KEEPALIVE_PERIOD 1 // in seconds
#define BM_KEEPALIVE_TIMEOUT (XLX_KEEPALIVE_PERIOD*30) // in seconds
#define BM_RECONNECT_PERIOD 5 // in seconds
// URF
#define URF_KEEPALIVE_PERIOD 1 // in seconds
#define URF_KEEPALIVE_TIMEOUT (URF_KEEPALIVE_PERIOD*30) // in seconds
#define URF_RECONNECT_PERIOD 5 // in seconds
// DMRPlus (dongle)
#define DMRPLUS_KEEPALIVE_PERIOD 1 // in seconds
#define DMRPLUS_KEEPALIVE_TIMEOUT (DMRPLUS_KEEPALIVE_PERIOD*10) // in seconds
#define DMRPLUS_REFLECTOR_SLOT DMR_SLOT2
// DMRMmdvm
#define DMRMMDVM_KEEPALIVE_PERIOD 10 // in seconds
#define DMRMMDVM_KEEPALIVE_TIMEOUT (DMRMMDVM_KEEPALIVE_PERIOD*10) // in seconds
#define DMRMMDVM_REFLECTOR_SLOT DMR_SLOT2
#define DMRMMDVM_REFLECTOR_COLOUR 1
// YSF
#define YSF_KEEPALIVE_PERIOD 3 // in seconds
#define YSF_KEEPALIVE_TIMEOUT (YSF_KEEPALIVE_PERIOD*10) // in seconds
// M17
#define M17_KEEPALIVE_PERIOD 3
#define M17_KEEPALIVE_TIMEOUT (M17_KEEPALIVE_PERIOD*10)
// G3 Terminal
#define G3_PRESENCE_PORT 12346 // UDP port
#define G3_CONFIG_PORT 12345 // UDP port
#define G3_DV_PORT 40000 // UDP port
#define G3_KEEPALIVE_PERIOD 10 // in seconds
#define G3_KEEPALIVE_TIMEOUT 3600 // in seconds, 1 hour
////////////////////////////////////////////////////////////////////////////////////////
// macros
#define MIN(a,b) ((a)<(b))?(a):(b)
#define MAX(a,b) ((a)>(b))?(a):(b)
#define MAKEWORD(low, high) ((uint16_t)(((uint8_t)(low)) | (((uint16_t)((uint8_t)(high))) << 8)))
#define MAKEDWORD(low, high) ((uint32_t)(((uint16_t)(low)) | (((uint32_t)((uint16_t)(high))) << 16)))
#define LOBYTE(w) ((uint8_t)(uint16_t)(w & 0x00FF))
#define HIBYTE(w) ((uint8_t)((((uint16_t)(w)) >> 8) & 0xFF))
#define LOWORD(dw) ((uint16_t)(uint32_t)(dw & 0x0000FFFF))
#define HIWORD(dw) ((uint16_t)((((uint32_t)(dw)) >> 16) & 0xFFFF))

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "G3Client.h"

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include <sys/stat.h>
#include "G3Client.h"
@ -37,7 +37,7 @@ bool CG3Protocol::Initialize(const char */*type*/, const EProtocol /*type*/, con
ReadOptions();
// init reflector apparent callsign
m_ReflectorCallsign = g_Reflector.GetCallsign();
m_ReflectorCallsign = g_Refl..GetCallsign();
// reset stop flag
keep_running = true;
@ -177,7 +177,7 @@ void CG3Protocol::PresenceTask(void)
Buffer.Append(m_GwAddress);
}
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>extant = nullptr;
while ( (extant = clients->FindNextClient(EProtocol::g3, it)) != nullptr )
@ -219,7 +219,7 @@ void CG3Protocol::PresenceTask(void)
clients->AddClient(std::make_shared<CG3Client>(Terminal, Ip));
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
m_PresenceSocket.Send(Buffer, ReqIp);
}
@ -260,7 +260,7 @@ void CG3Protocol::ConfigTask(void)
if (isRepeaterCall)
{
if ((Call.HasSameCallsign(GetReflectorCallsign())) && (g_Reflector.IsValidModule(Call.GetCSModule())))
if ((Call.HasSameCallsign(GetReflectorCallsign())) && (g_Refl..IsValidModule(Call.GetCSModule())))
{
Buffer.data()[3] = 0x00; // ok
}
@ -343,7 +343,7 @@ void CG3Protocol::IcmpTask(void)
{
if (iIcmpType == ICMP_DEST_UNREACH)
{
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::g3, it)) != nullptr )
@ -354,7 +354,7 @@ void CG3Protocol::IcmpTask(void)
clients->RemoveClient(client);
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
}
@ -378,7 +378,7 @@ void CG3Protocol::Task(void)
{
CIp ClIp;
CIp *BaseIp = nullptr;
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::g3, it)) != nullptr )
@ -394,7 +394,7 @@ void CG3Protocol::Task(void)
break;
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
if (BaseIp != nullptr)
{
@ -406,7 +406,7 @@ void CG3Protocol::Task(void)
else if ( IsValidDvHeaderPacket(Buffer, Header) )
{
// callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::g3, Header->GetRpt2Module()) )
if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::g3, Header->GetRpt2Module()) )
{
// handle it
OnDvHeaderPacketIn(Header, *BaseIp);
@ -454,7 +454,7 @@ void CG3Protocol::HandleQueue(void)
if ( EncodeDvPacket(*packet, buffer) )
{
// and push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::g3, it)) != nullptr )
@ -470,7 +470,7 @@ void CG3Protocol::HandleQueue(void)
}
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
m_Queue.Unlock();
@ -487,7 +487,7 @@ void CG3Protocol::HandleKeepalives(void)
CBuffer keepalive((uint8_t *)"PING", 4);
// iterate on clients
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::g3, it)) != nullptr )
@ -502,7 +502,7 @@ void CG3Protocol::HandleKeepalives(void)
Send(keepalive, client->GetIp());
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -527,7 +527,7 @@ void CG3Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, c
CCallsign rpt2(Header->GetRpt2Callsign());
// find this client
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::g3, it)) != nullptr )
@ -554,7 +554,7 @@ void CG3Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, c
}
else
{
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
return;
}
}
@ -563,19 +563,19 @@ void CG3Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, c
rpt1 = client->GetCallsign();
// and try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams[stream->GetStreamId()] = stream;
}
// update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers();
g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Refl..ReleaseUsers();
}
}
// release
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
@ -679,7 +679,7 @@ void CG3Protocol::NeedReload(void)
ReadOptions();
// we have new options - iterate on clients for potential removal
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::g3, it)) != nullptr )
@ -690,7 +690,7 @@ void CG3Protocol::NeedReload(void)
clients->RemoveClient(client);
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
}

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "Timer.h"
#include "GateKeeper.h"

@ -19,7 +19,7 @@
#pragma once
#include "Main.h"
#include "Defines.h"
#include "Callsign.h"
#include "IP.h"
#include "CallsignList.h"

@ -1,7 +1,5 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
// Copyright © 2023 Thomas A. Early N7TAE
//
// 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
@ -16,25 +14,18 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once
#include "DMRIdDir.h"
class CDmridDirHttp : public CDmridDir
{
public:
// constructor
CDmridDirHttp() {}
// destructor
~CDmridDirHttp() {}
// refresh
bool LoadContent(CBuffer *);
bool RefreshContent(const CBuffer &);
#include "Reflector.h"
#include "GateKeeper.h"
#include "Configure.h"
#include "Version.h"
#include "LookupDmr.h"
#include "LookupNxdn.h"
#include "LookupYsf.h"
protected:
// reload helpers
bool NeedReload(void) { return true; }
bool HttpGet(const char *, const char *, int, CBuffer *);
};
extern CReflector g_Refl;
extern CGateKeeper g_Gate;
extern CConfigure g_Conf;
extern CVersion g_Vers;
extern CLookupDmr g_LDid;
extern CLookupNxdn g_LNid;
extern CLookupYsf g_LYtr;

@ -0,0 +1,95 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2023 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#include <iostream>
#include <thread>
#include <sys/stat.h>
#include "Lookup.h"
CLookup::~CLookup()
{
LookupClose();
}
void CLookup::LookupClose()
{
keep_running = false;
if (m_Future.valid())
m_Future.get();
}
std::time_t CLookup::GetLastModTime()
{
struct stat fileStat;
if(0 == stat(m_Path.c_str(), &fileStat))
{
return fileStat.st_mtime;
}
return 0;
}
void CLookup::LookupInit()
{
LoadParameters();
m_Future = std::async(std::launch::async, &CLookup::Thread, this);
}
void CLookup::Thread()
{
while (keep_running)
{
bool loaded = false;
if (m_Type != ERefreshType::file) // get the HTTP contents
{
CBuffer buf;
loaded = LoadContentHttp(buf);
if (loaded)
{
Lock();
ClearContents();
RefreshContentHttp(buf);
Unlock();
}
}
if (m_Type != ERefreshType::http) // get the file contents
{
auto lastTime = GetLastModTime();
if (lastTime > m_LastModTime)
{
CBuffer buf;
if (LoadContentFile(buf))
{
Lock();
if (! loaded)
ClearContents();
RefreshContentFile(buf);
Unlock();
m_LastModTime = lastTime;
}
}
}
// now wait for a while...
for (unsigned i=0; i<20u*m_Refresh && keep_running; i++)
std::this_thread::sleep_for(std::chrono::seconds(3));
}
}

@ -1,7 +1,7 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
// Copyright © 2023 Thomas A. Early N7TAE
//
// 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
@ -18,68 +18,60 @@
#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <map>
#include <atomic>
#include <future>
#include "Buffer.h"
#include "Callsign.h"
#include "Configure.h"
// compare function for std::map::find
struct CDmridDirCallsignCompare
struct CCallsignCompare
{
bool operator() (const CCallsign &cs1, const CCallsign &cs2) const
{ return cs1.HasLowerCallsign(cs2);}
{
return cs1.HasLowerCallsign(cs2);
}
};
////////////////////////////////////////////////////////////////////////////////////////
class CDmridDir
class CLookup
{
public:
// constructor
CDmridDir();
CLookup() : keep_running(true), m_LastModTime(0) {}
// destructor
~CDmridDir();
virtual ~CLookup();
// init & close
virtual bool Init(void);
virtual void Close(void);
void LookupInit();
void LookupClose();
// locks
void Lock(void) { m_Mutex.lock(); }
void Unlock(void) { m_Mutex.unlock(); }
// refresh
virtual bool LoadContent(CBuffer *) { return false; }
virtual bool RefreshContent(const CBuffer &) { return false; }
// find
const CCallsign *FindCallsign(uint32_t);
uint32_t FindDmrid(const CCallsign &);
void Lock(void) { m_Mutex.lock(); }
void Unlock(void) { m_Mutex.unlock(); }
protected:
// thread
std::time_t GetLastModTime();
virtual void LoadParameters() = 0;
virtual void ClearContents() = 0;
void Thread();
// reload helpers
bool Reload(void);
virtual bool NeedReload(void) { return false; }
bool IsValidDmrid(const char *);
protected:
// data
std::map <uint32_t, CCallsign> m_CallsignMap;
std::map <CCallsign, uint32_t, CDmridDirCallsignCompare> m_DmridMap;
// refresh
virtual bool LoadContentFile(CBuffer &buf) = 0;
virtual bool LoadContentHttp(CBuffer &buf) = 0;
virtual void RefreshContentFile(const CBuffer &) = 0;
virtual void RefreshContentHttp(const CBuffer &) = 0;
// Lock()
std::mutex m_Mutex;
ERefreshType m_Type;
unsigned m_Refresh;
std::string m_Path, m_Host, m_Suffix;
std::time_t m_LastModTime;
// thread
std::atomic<bool> keep_running;
std::future<void> m_Future;
};

@ -0,0 +1,262 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2023 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#include <iostream>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include "Reflector.h"
#include "LookupDmr.h"
extern CReflector g_ref;
extern CConfigure g_cfg;
void CLookupDmr::ClearContents()
{
m_CallsignMap.clear();
m_DmridMap.clear();
}
void CLookupDmr::LoadParameters()
{
g_cfg.GetRefreshType(g_cfg.j.dmriddb.mode, m_Type);
g_cfg.GetUnsigned(g_cfg.j.dmriddb.refreshmin, m_Refresh);
g_cfg.GetString(g_cfg.j.dmriddb.filepath, m_Path);
g_cfg.GetString(g_cfg.j.dmriddb.hostname, m_Host);
g_cfg.GetString(g_cfg.j.dmriddb.suffix, m_Suffix);
}
uint32_t CLookupDmr::FindDmrid(const CCallsign &callsign)
{
auto found = m_DmridMap.find(callsign);
if ( found != m_DmridMap.end() )
{
return (found->second);
}
return 0;
}
const CCallsign *CLookupDmr::FindCallsign(uint32_t dmrid)
{
auto found = m_CallsignMap.find(dmrid);
if ( found != m_CallsignMap.end() )
{
return &(found->second);
}
return nullptr;
}
bool CLookupDmr::LoadContentFile(CBuffer &buffer)
{
buffer.clear();
std::ifstream file;
std::streampos size;
// open file
file.open(m_Path, std::ios::in | std::ios::binary | std::ios::ate);
if ( file.is_open() )
{
// read file
size = file.tellg();
if ( size > 0 )
{
// read file into buffer
buffer.resize((int)size+1);
file.seekg(0, std::ios::beg);
file.read((char *)buffer.data(), (int)size);
// close file
file.close();
}
}
// done
return buffer.size() > 0;
}
bool CLookupDmr::LoadContentHttp(CBuffer &buf)
{
// get file from xlxapi server
return HttpGet(m_Host.c_str(), m_Suffix.c_str(), 80, buf);
}
void CLookupDmr::RefreshContentFile(const CBuffer &buffer)
{
// crack it
char *ptr1 = (char *)buffer.data();
char *ptr2;
// get next line
while ( (ptr2 = strchr(ptr1, '\n')) != nullptr )
{
*ptr2 = 0;
// get items
char *dmrid;
char *callsign;
if ( ((dmrid = strtok(ptr1, ";")) != nullptr) && IsValidDmrId(dmrid) )
{
if ( ((callsign = ::strtok(nullptr, ";")) != nullptr) )
{
// new entry
uint32_t ui = atoi(dmrid);
CCallsign cs(callsign, ui);
if ( cs.IsValid() )
{
m_CallsignMap.insert(std::pair<uint32_t,CCallsign>(ui, cs));
m_DmridMap.insert(std::pair<CCallsign,uint32_t>(cs,ui));
}
}
}
// next line
ptr1 = ptr2+1;
}
std::cout << "Read " << m_DmridMap.size() << " DMR ids from file " << m_Refresh << std::endl;
}
void CLookupDmr::RefreshContentHttp(const CBuffer &buffer)
{
char *ptr1 = (char *)buffer.data();
char *ptr2;
// get next line
while ( (ptr2 = strchr(ptr1, '\n')) != nullptr )
{
*ptr2 = 0;
// get items
char *dmrid;
char *callsign;
if ( ((dmrid = strtok(ptr1, ";")) != nullptr) && IsValidDmrId(dmrid) )
{
if ( ((callsign = strtok(nullptr, ";")) != nullptr) )
{
// new entry
uint32_t ui = atoi(dmrid);
CCallsign cs(callsign, ui);
if ( cs.IsValid() )
{
m_CallsignMap.insert(std::pair<uint32_t, CCallsign>(ui, cs));
m_DmridMap.insert(std::pair<CCallsign, uint32_t>(cs,ui));
}
}
}
// next line
ptr1 = ptr2+1;
}
std::cout << "Read " << m_DmridMap.size() << " DMR ids from " << m_Host << " database " << std::endl;
}
bool CLookupDmr::IsValidDmrId(const char *sz)
{
bool ok = false;
size_t n = strlen(sz);
if ( (n > 0) && (n <= 8) )
{
ok = true;
for ( size_t i = 0; (i < n) && ok; i++ )
{
ok = ok && isdigit(sz[i]);
}
}
return ok;
}
#define DMRID_HTTPGET_SIZEMAX (256)
bool CLookupDmr::HttpGet(const char *hostname, const char *filename, int port, CBuffer &buffer)
{
buffer.clear();
int sock_id;
// open socket
if ( (sock_id = socket(AF_INET, SOCK_STREAM, 0)) >= 0 )
{
// get hostname address
struct sockaddr_in servaddr;
struct hostent *hp;
memset(&servaddr, 0, sizeof(servaddr));
if( (hp = gethostbyname(hostname)) != nullptr)
{
// dns resolved
memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
servaddr.sin_port = htons(port);
servaddr.sin_family = AF_INET;
// connect
if (connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0)
{
// send the GET request
char request[DMRID_HTTPGET_SIZEMAX];
::sprintf(request, "GET /%s HTTP/1.0\r\nFrom: %s\r\nUser-Agent: urfd\r\n\r\n", filename, g_ref.GetCallsign().GetCS().c_str());
::write(sock_id, request, strlen(request));
// config receive timeouts
fd_set read_set;
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
FD_ZERO(&read_set);
FD_SET(sock_id, &read_set);
// get the reply back
bool done = false;
do
{
char buf[1440];
ssize_t len = 0;
select(sock_id+1, &read_set, nullptr, nullptr, &timeout);
//if ( (ret > 0) || ((ret < 0) && (errno == EINPROGRESS)) )
//if ( ret >= 0 )
//{
usleep(5000);
len = read(sock_id, buf, 1440);
if ( len > 0 )
{
buffer.Append((uint8_t *)buf, (int)len);
}
//}
done = (len <= 0);
}
while (!done);
buffer.Append((uint8_t)0);
// and disconnect
close(sock_id);
}
else
{
std::cout << "Cannot establish connection with host " << hostname << std::endl;
}
}
else
{
std::cout << "Host " << hostname << " not found" << std::endl;
}
}
else
{
std::cout << "Failed to open wget socket" << std::endl;
}
// done
return buffer.size() > 1;
}

@ -1,7 +1,7 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
// Copyright © 2023 Thomas A. Early N7TAE
//
// 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
@ -18,23 +18,26 @@
#pragma once
#include "NXDNIdDir.h"
#include "Lookup.h"
class CNXDNidDirHttp : public CNXDNidDir
class CLookupDmr : public CLookup
{
public:
// constructor
CNXDNidDirHttp() {}
uint32_t FindDmrid(const CCallsign &cs);
const CCallsign *FindCallsign(uint32_t dmrid);
// destructor
~CNXDNidDirHttp() {}
protected:
void ClearContents();
void LoadParameters();
bool LoadContentFile(CBuffer &buf);
bool LoadContentHttp(CBuffer &buf);
void RefreshContentFile(const CBuffer &);
void RefreshContentHttp(const CBuffer &);
// refresh
bool LoadContent(CBuffer *);
bool RefreshContent(const CBuffer &);
private:
std::map <uint32_t, CCallsign> m_CallsignMap;
std::map <CCallsign, uint32_t, CCallsignCompare> m_DmridMap;
protected:
// reload helpers
bool NeedReload(void) { return true; }
bool HttpGet(const char *, const char *, int, CBuffer *);
bool IsValidDmrId(const char *);
bool HttpGet(const char *, const char *, int, CBuffer &);
};

@ -0,0 +1,264 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2023 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#include <iostream>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include "Reflector.h"
#include "LookupNxdn.h"
extern CReflector g_ref;
extern CConfigure g_cfg;
void CLookupNxdn::ClearContents()
{
m_CallsignMap.clear();
m_NxdnidMap.clear();
}
void CLookupNxdn::LoadParameters()
{
g_cfg.GetRefreshType(g_cfg.j.nxdniddb.mode, m_Type);
g_cfg.GetUnsigned(g_cfg.j.nxdniddb.refreshmin, m_Refresh);
g_cfg.GetString(g_cfg.j.nxdniddb.filepath, m_Path);
g_cfg.GetString(g_cfg.j.dmriddb.hostname, m_Host);
g_cfg.GetString(g_cfg.j.nxdniddb.suffix, m_Suffix);
}
const CCallsign *CLookupNxdn::FindCallsign(uint16_t nxdnid)
{
auto found = m_CallsignMap.find(nxdnid);
if ( found != m_CallsignMap.end() )
{
return &(found->second);
}
return nullptr;
}
uint16_t CLookupNxdn::FindNXDNid(const CCallsign &callsign)
{
auto found = m_NxdnidMap.find(callsign);
if ( found != m_NxdnidMap.end() )
{
return (found->second);
}
return 0;
}
bool CLookupNxdn::LoadContentFile(CBuffer &buffer)
{
buffer.clear();
std::ifstream file;
std::streampos size;
// open file
file.open(m_Path, std::ios::in | std::ios::binary | std::ios::ate);
if ( file.is_open() )
{
// read file
size = file.tellg();
if ( size > 0 )
{
// read file into buffer
buffer.resize((int)size+1);
file.seekg (0, std::ios::beg);
file.read((char *)buffer.data(), (int)size);
// close file
file.close();
// done
}
}
// done
return buffer.size() > 0;
}
bool CLookupNxdn::LoadContentHttp(CBuffer &buffer)
{
// get file from xlxapi server
return HttpGet(m_Host.c_str(), m_Suffix.c_str(), 80, buffer);
}
void CLookupNxdn::RefreshContentFile(const CBuffer &buffer)
{
// crack it
char *ptr1 = (char *)buffer.data();
char *ptr2;
// get next line
while ( (ptr2 = ::strchr(ptr1, '\n')) != nullptr )
{
*ptr2 = 0;
// get items
char *nxdnid;
char *callsign;
if ( ((nxdnid = ::strtok(ptr1, ",")) != nullptr) && IsValidNxdnId(nxdnid) )
{
if ( ((callsign = ::strtok(nullptr, ",")) != nullptr) )
{
// new entry
uint16_t us = atoi(nxdnid);
CCallsign cs(callsign, 0, us);
if ( cs.IsValid() )
{
m_CallsignMap.insert(std::pair<uint32_t,CCallsign>(us, cs));
m_NxdnidMap.insert(std::pair<CCallsign,uint32_t>(cs,us));
}
}
}
// next line
ptr1 = ptr2+1;
}
std::cout << "Read " << m_NxdnidMap.size() << " NXDN ids from file " << m_Path << std::endl;
}
void CLookupNxdn::RefreshContentHttp(const CBuffer &buffer)
{
char *ptr1 = (char *)buffer.data();
char *ptr2;
// get next line
while ( (ptr2 = strchr(ptr1, '\n')) != nullptr )
{
std::cout << "newline: " << std::string(ptr2) << std::endl;
*ptr2 = 0;
// get items
char *nxdnid;
char *callsign;
if ( ((nxdnid = ::strtok(ptr1, ",")) != nullptr) && IsValidNxdnId(nxdnid) )
{
if ( ((callsign = ::strtok(nullptr, ",")) != nullptr) )
{
// new entry
uint16_t us = atoi(nxdnid);
CCallsign cs(callsign, 0, us);
if ( cs.IsValid() )
{
m_CallsignMap.insert(std::pair<uint16_t,CCallsign>(us, cs));
m_NxdnidMap.insert(std::pair<CCallsign,uint16_t>(cs,us));
}
}
}
// next line
ptr1 = ptr2+1;
}
std::cout << "Read " << m_NxdnidMap.size() << " NXDN ids from " << m_Host << std::endl;
}
bool CLookupNxdn::IsValidNxdnId(const char *sz)
{
bool ok = false;
size_t n = ::strlen(sz);
if ( (n > 0) && (n <= 5) )
{
ok = true;
for ( size_t i = 0; (i < n) && ok; i++ )
{
ok = ok && isdigit(sz[i]);
}
}
return ok;
}
#define NXDNID_HTTPGET_SIZEMAX (256)
bool CLookupNxdn::HttpGet(const char *hostname, const char *filename, int port, CBuffer &buffer)
{
int sock_id;
buffer.clear();
// open socket
if ( (sock_id = socket(AF_INET, SOCK_STREAM, 0)) >= 0 )
{
// get hostname address
struct sockaddr_in servaddr;
struct hostent *hp;
memset(&servaddr,0,sizeof(servaddr));
if( (hp = gethostbyname(hostname)) != nullptr )
{
// dns resolved
memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
servaddr.sin_port = htons(port);
servaddr.sin_family = AF_INET;
// connect
if ( ::connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0)
{
// send the GET request
char request[NXDNID_HTTPGET_SIZEMAX];
::sprintf(request, "GET /%s HTTP/1.0\r\nFrom: %s\r\nUser-Agent: urfd\r\n\r\n", filename, (const char *)g_ref.GetCallsign());
::write(sock_id, request, strlen(request));
// config receive timeouts
fd_set read_set;
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
FD_ZERO(&read_set);
FD_SET(sock_id, &read_set);
// get the reply back
bool done = false;
do
{
char buf[1440];
ssize_t len = 0;
select(sock_id+1, &read_set, nullptr, nullptr, &timeout);
//if ( (ret > 0) || ((ret < 0) && (errno == EINPROGRESS)) )
//if ( ret >= 0 )
//{
usleep(5000);
len = read(sock_id, buf, 1440);
if ( len > 0 )
{
buffer.Append((uint8_t *)buf, (int)len);
}
//}
done = (len <= 0);
}
while (!done);
buffer.Append((uint8_t)0);
// and disconnect
close(sock_id);
}
else
{
std::cout << "Cannot establish connection with host " << hostname << std::endl;
}
}
else
{
std::cout << "Host " << hostname << " not found" << std::endl;
}
}
else
{
std::cout << "Failed to open wget socket" << std::endl;
}
// done
return buffer.size() > 1;
}

@ -1,7 +1,7 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
// Copyright © 2023 Thomas A. Early N7TAE
//
// 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
@ -18,30 +18,25 @@
#pragma once
#include "DMRIdDir.h"
#include "Lookup.h"
class CDmridDirFile : public CDmridDir
class CLookupNxdn : public CLookup
{
public:
// constructor
CDmridDirFile();
// destructor
~CDmridDirFile() {}
// init & close
bool Init(void);
// refresh
bool LoadContent(CBuffer *);
bool RefreshContent(const CBuffer &);
protected:
// reload helpers
bool NeedReload(void);
bool GetLastModTime(time_t *);
uint16_t FindNXDNid(const CCallsign &callsign);
const CCallsign *FindCallsign(uint16_t id);
protected:
// data
time_t m_LastModTime;
void ClearContents();
void LoadParameters();
bool LoadContentFile(CBuffer &buf);
bool LoadContentHttp(CBuffer &buf);
void RefreshContentFile(const CBuffer &);
void RefreshContentHttp(const CBuffer &);
private:
std::map <uint32_t, CCallsign> m_CallsignMap;
std::map <CCallsign, uint32_t, CCallsignCompare> m_NxdnidMap;
bool IsValidNxdnId(const char *);
bool HttpGet(const char *, const char *, int, CBuffer &);
};

@ -0,0 +1,256 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2023 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#include <iostream>
#include <string.h>
#include <sys/socket.h>
#include <mysql/mysql.h>
#include <netdb.h>
#include "Reflector.h"
#include "LookupYsf.h"
extern CReflector g_ref;
extern CConfigure g_cfg;
void CLookupYsf::ClearContents()
{
m_map.clear();
}
void CLookupYsf::LoadParameters()
{
g_cfg.GetRefreshType(g_cfg.j.ysftxrxdb.mode, m_Type);
g_cfg.GetUnsigned(g_cfg.j.ysftxrxdb.refreshmin, m_Refresh);
g_cfg.GetString(g_cfg.j.ysftxrxdb.filepath, m_Path);
g_cfg.GetString(g_cfg.j.ysftxrxdb.hostname, m_Host);
g_cfg.GetString(g_cfg.j.ysftxrxdb.suffix, m_Suffix);
g_cfg.GetUnsigned(g_cfg.j.ysf.defaulttxfreq, m_DefaultTx);
g_cfg.GetUnsigned(g_cfg.j.ysf.defaultrxfreq, m_DefaultRx);
}
bool CLookupYsf::LoadContentFile(CBuffer &buffer)
{
buffer.clear();
std::ifstream file;
std::streampos size;
// open file
file.open(m_Path, std::ios::in | std::ios::binary | std::ios::ate);
if (file.is_open())
{
// read file
size = file.tellg();
if (size > 0)
{
// read file into buffer
buffer.resize((int)size + 1);
file.seekg(0, std::ios::beg);
file.read((char *)buffer.data(), (int)size);
// close file
file.close();
}
}
return buffer.size() > 0;
}
bool CLookupYsf::LoadContentHttp(CBuffer &buffer)
{
// get file from http://xlxapi.rlx.lu/api/exportysfrepeaters.php
return HttpGet(m_Host.c_str(), m_Suffix.c_str(), 80, buffer);
}
void CLookupYsf::RefreshContentFile(const CBuffer &buffer)
{
// scan buffer
if (buffer.size() > 0)
{
// crack it
char *ptr1 = (char *)buffer.data();
char *ptr2;
// get next line
while ((ptr2 = ::strchr(ptr1, '\n')) != nullptr)
{
*ptr2 = 0;
// get items
char *callsign;
char *txfreq;
char *rxfreq;
if (((callsign = ::strtok(ptr1, ";")) != nullptr))
{
if (((txfreq = ::strtok(nullptr, ";")) != nullptr))
{
if (((rxfreq = ::strtok(nullptr, ";")) != nullptr))
{
// new entry
CCallsign cs(callsign);
CYsfNode node(atoi(txfreq), atoi(rxfreq));
if (cs.IsValid() && node.IsValid())
{
m_map.insert(std::pair<CCallsign, CYsfNode>(cs, node));
}
}
}
}
// next line
ptr1 = ptr2 + 1;
}
}
// report
std::cout << "Read " << m_map.size() << " YSF nodes from file " << m_Path << std::endl;
}
void CLookupYsf::RefreshContentHttp(const CBuffer &buffer)
{
// crack it
char *ptr1 = (char *)buffer.data();
char *ptr2;
// get next line
while ((ptr2 = ::strchr(ptr1, '\n')) != nullptr)
{
*ptr2 = 0;
// get items
char *callsign;
char *txfreq;
char *rxfreq;
if (((callsign = ::strtok(ptr1, ";")) != nullptr))
{
if (((txfreq = ::strtok(nullptr, ";")) != nullptr))
{
if (((rxfreq = ::strtok(nullptr, ";")) != nullptr))
{
// new entry
CCallsign cs(callsign);
CYsfNode node(atoi(txfreq), atoi(rxfreq));
if (cs.IsValid() && node.IsValid())
{
m_map.insert(std::pair<CCallsign, CYsfNode>(cs, node));
}
}
}
}
// next line
ptr1 = ptr2 + 1;
}
// report
std::cout << "Read " << m_map.size() << " YSF nodes from " << m_Host << " database " << std::endl;
}
#define YSFNODE_HTTPGET_SIZEMAX (256)
bool CLookupYsf::HttpGet(const char *hostname, const char *filename, int port, CBuffer &buffer)
{
buffer.clear();
int sock_id;
// open socket
if ((sock_id = socket(AF_INET, SOCK_STREAM, 0)) >= 0)
{
// get hostname address
struct sockaddr_in servaddr;
struct hostent *hp;
memset(&servaddr, 0, sizeof(servaddr));
if ((hp = gethostbyname(hostname)) != nullptr)
{
// dns resolved
memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
servaddr.sin_port = htons(port);
servaddr.sin_family = AF_INET;
// connect
if (connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0)
{
// send the GET request
char request[YSFNODE_HTTPGET_SIZEMAX];
sprintf(request, "GET /%s HTTP/1.0\r\nFrom: %s\r\nUser-Agent: urfd\r\n\r\n", filename, g_ref.GetCallsign().GetCS().c_str());
write(sock_id, request, strlen(request));
// config receive timeouts
fd_set read_set;
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
FD_ZERO(&read_set);
FD_SET(sock_id, &read_set);
// get the reply back
bool done = false;
do
{
char buf[1440];
ssize_t len = 0;
select(sock_id + 1, &read_set, nullptr, nullptr, &timeout);
// if ( (ret > 0) || ((ret < 0) && (errno == EINPROGRESS)) )
// if ( ret >= 0 )
//{
usleep(5000);
len = read(sock_id, buf, 1440);
if (len > 0)
{
buffer.Append((uint8_t *)buf, (int)len);
}
//}
done = (len <= 0);
} while (!done);
buffer.Append((uint8_t)0);
// and disconnect
close(sock_id);
}
else
{
std::cout << "Cannot establish connection with host " << hostname << std::endl;
}
}
else
{
std::cout << "Host " << hostname << " not found" << std::endl;
}
}
else
{
std::cout << "Failed to open wget socket" << std::endl;
}
// done
return buffer.size() > 1;
}
bool CLookupYsf::FindFrequencies(const CCallsign &callsign, uint32_t *txfreq, uint32_t *rxfreq)
{
auto found = m_map.find(callsign);
if (found != m_map.end())
{
*txfreq = found->second.GetTxFrequency();
*rxfreq = found->second.GetRxFrequency();
return true;
}
else
{
*txfreq = m_DefaultTx;
*rxfreq = m_DefaultRx;
return false;
}
}

@ -1,7 +1,7 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
// Copyright © 2023 Thomas A. Early N7TAE
//
// 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
@ -18,30 +18,26 @@
#pragma once
#include "NXDNIdDir.h"
#include "YSFNode.h"
#include "Lookup.h"
class CNXDNidDirFile : public CNXDNidDir
using CsNodeMap = std::map<CCallsign, CYsfNode, CCallsignCompare>;
class CLookupYsf : public CLookup
{
public:
// constructor
CNXDNidDirFile();
// destructor
~CNXDNidDirFile() {}
// init & close
bool Init(void);
// refresh
bool LoadContent(CBuffer *);
bool RefreshContent(const CBuffer &);
bool FindFrequencies(const CCallsign &, uint32_t *, uint32_t *);
protected:
// reload helpers
bool NeedReload(void);
bool GetLastModTime(time_t *);
void ClearContents();
void LoadParameters();
bool LoadContentFile(CBuffer &buf);
bool LoadContentHttp(CBuffer &buf);
void RefreshContentFile(const CBuffer &);
void RefreshContentHttp(const CBuffer &);
protected:
// data
time_t m_LastModTime;
private:
CsNodeMap m_map;
bool HttpGet(const char *, const char *, int, CBuffer &);
};

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "M17Client.h"

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "M17Client.h"
#include "M17Protocol.h"
@ -69,7 +69,7 @@ void CM17Protocol::Task(void)
if ( IsValidDvPacket(Buffer, Header, Frame) )
{
// callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::m17, Header->GetRpt2Module()) )
if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::m17, Header->GetRpt2Module()) )
{
OnDvHeaderPacketIn(Header, Ip);
@ -93,17 +93,17 @@ void CM17Protocol::Task(void)
std::cout << "M17 connect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::m17) && g_Reflector.IsValidModule(ToLinkModule) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::m17) && g_Refl..IsValidModule(ToLinkModule) )
{
// valid module ?
if ( g_Reflector.IsValidModule(ToLinkModule) )
if ( g_Refl..IsValidModule(ToLinkModule) )
{
// acknowledge the request
Send("ACKN", Ip);
// create the client and append
g_Reflector.GetClients()->AddClient(std::make_shared<CM17Client>(Callsign, Ip, ToLinkModule));
g_Reflector.ReleaseClients();
g_Refl..GetClients()->AddClient(std::make_shared<CM17Client>(Callsign, Ip, ToLinkModule));
g_Refl..ReleaseClients();
}
else
{
@ -125,7 +125,7 @@ void CM17Protocol::Task(void)
std::cout << "M17 disconnect packet from " << Callsign << " at " << Ip << std::endl;
// find client
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::m17);
if ( client != nullptr )
{
@ -134,19 +134,19 @@ void CM17Protocol::Task(void)
// and acknowledge the disconnect
Send("DISC", Ip);
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else if ( IsValidKeepAlivePacket(Buffer, Callsign) )
{
// find all clients with that callsign & ip and keep them alive
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(Callsign, Ip, EProtocol::m17, it)) != nullptr )
{
client->Alive();
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else
{
@ -196,24 +196,24 @@ void CM17Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
CCallsign rpt2(Header->GetRpt2Callsign());
// find this client
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, EProtocol::m17);
std::shared_ptr<CClient>client = g_Refl..GetClients()->FindClient(Ip, EProtocol::m17);
if ( client )
{
// get client callsign
rpt1 = client->GetCallsign();
// and try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams[stream->GetStreamId()] = stream;
}
}
// release
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers();
g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Refl..ReleaseUsers();
}
}
@ -249,7 +249,7 @@ void CM17Protocol::HandleQueue(void)
EncodeM17Packet(frame, m_StreamsCache[module].m_dvHeader, (CDvFramePacket *)packet.get(), m_StreamsCache[module].m_iSeqCounter);
// push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::m17, it)) != nullptr )
@ -266,7 +266,7 @@ void CM17Protocol::HandleQueue(void)
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
m_StreamsCache[module].m_iSeqCounter++;
}
@ -286,7 +286,7 @@ void CM17Protocol::HandleKeepalives(void)
EncodeKeepAlivePacket(keepalive);
// iterate on clients
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::m17, it)) != nullptr )
@ -312,7 +312,7 @@ void CM17Protocol::HandleKeepalives(void)
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -389,7 +389,7 @@ void CM17Protocol::EncodeKeepAlivePacket(CBuffer &Buffer)
{
Buffer.resize(10);
memcpy(Buffer.data(), "PING", 4);
g_Reflector.GetCallsign().CodeOut(Buffer.data() + 4);
g_Refl..GetCallsign().CodeOut(Buffer.data() + 4);
}
void CM17Protocol::EncodeM17Packet(SM17Frame &frame, const CDvHeaderPacket &Header, const CDvFramePacket *DvFrame, uint32_t iSeq) const

@ -16,59 +16,59 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "Reflector.h"
#include <sys/stat.h>
#include "Global.h"
////////////////////////////////////////////////////////////////////////////////////////
// global objects
CReflector g_Reflector;
CReflector g_Refl;
CGateKeeper g_Gate;
CConfigure g_Conf;
CVersion g_Vers(3,0,0); // The major byte should only change if the interlink packet changes!
CLookupDmr g_LDid;
CLookupNxdn g_LNid;
CLookupYsf g_LYtr;
////////////////////////////////////////////////////////////////////////////////////////
// function declaration
#include "Users.h"
int main()
int main(int argc, char *argv[])
{
const std::string cs(CALLSIGN);
if ((cs.size() != 6) || cs.compare(0, 3, "URF"))
if (argc != 2)
{
std::cerr << "Malformed reflector callsign: '" << cs << "', aborting!" << std::endl;
std::cerr << "No configuration file specifed! Usage: " << argv[0] << " /pathname/to/configuration/file" << std::endl;
return EXIT_FAILURE;
}
if (g_Conf.ReadData(argv[1]))
return EXIT_FAILURE;
// remove pidfile
remove(PIDFILE_PATH);
const std::string pidpath(g_Conf.GetString(g_Conf.j.files.pid));
const std::string callsign(g_Conf.GetString(g_Conf.j.names.cs));
remove(pidpath.c_str());
// splash
std::cout << "Starting " << cs << " " << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_REVISION << std::endl << std::endl;
#ifdef TRANSCODER_IS_REMOTE
g_Reflector.SetTranscoderIp(TRANSCODER_IP, INET6_ADDRSTRLEN);
#endif
std::cout << "Starting " << callsign << " " << g_Vers << std::endl;
// and let it run
if ( !g_Reflector.Start() )
if (g_Refl.Start())
{
std::cout << "Error starting reflector" << std::endl;
return EXIT_FAILURE;
}
std::cout << "Reflector " << g_Reflector.GetCallsign() << "started and listening" << std::endl;
std::cout << "Reflector " << callsign << "started and listening" << std::endl;
// write new pid file
std::ofstream ofs(PIDFILE_PATH, std::ofstream::out);
std::ofstream ofs(pidpath, std::ofstream::out);
ofs << getpid() << std::endl;
ofs.close();
pause(); // wait for any signal
g_Reflector.Stop();
g_Refl.Stop();
std::cout << "Reflector stopped" << std::endl;
// done

@ -1,276 +0,0 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#pragma once
#include <atomic>
#include <vector>
#include <array>
#include <list>
#include <map>
#include <unordered_map>
#include <queue>
#include <chrono>
#include <future>
#include <mutex>
#include <memory>
#include <atomic>
#include <condition_variable>
#include <ctime>
#include <cctype>
#include <iostream>
#include <iomanip>
#include <fstream>
#include <algorithm>
#include <arpa/inet.h>
#include "configure.h"
////////////////////////////////////////////////////////////////////////////////////////
// defines
//// Module configuration
#define DSTAR_IPV4 true
#define DMR_IPV4 true
#define YSF_IPV4 true
#define XLX_IPV4 true
#define M17_IPV4 true
#define P25_IPV4 true
#define NXDN_IPV4 true
#define USRP_IPV4 true
#define URF_IPV4 true
#define DSTAR_IPV6 false
#define DMR_IPV6 false
#define YSF_IPV6 false
#define XLX_IPV6 false
#define M17_IPV6 true
#define P25_IPV6 false
#define NXDN_IPV6 false
#define USRP_IPV6 false
#define URF_IPV6 true
// version -----------------------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 0
#define VERSION_REVISION 7
// global ------------------------------------------------------
//#define JSON_MONITOR
// debug -------------------------------------------------------
//#define DEBUG_NO_ERROR_ON_XML_OPEN_FAIL
//#define DEBUG_DUMPFILE
// protocols ---------------------------------------------------
#ifndef NO_G3
enum class EProtocol { any, none, dextra, dplus, dcs, bm, urf, dmrplus, dmrmmdvm, ysf, m17, g3, p25, nxdn, usrp };
#else
enum class EProtocol { any, none, dextra, dplus, dcs, bm, urf, dmrplus, dmrmmdvm, ysf, m17, p25, nxdn, usrp };
#endif
// DExtra
#define DEXTRA_PORT 30001 // UDP port
#define DEXTRA_KEEPALIVE_PERIOD 3 // in seconds
#define DEXTRA_KEEPALIVE_TIMEOUT (DEXTRA_KEEPALIVE_PERIOD*10) // in seconds
#define DEXTRA_RECONNECT_PERIOD 5 // in seconds
// DPlus
#define DPLUS_PORT 20001 // UDP port
#define DPLUS_KEEPALIVE_PERIOD 1 // in seconds
#define DPLUS_KEEPALIVE_TIMEOUT (DPLUS_KEEPALIVE_PERIOD*10) // in seconds
#define DPLUS_DEFAULT_RPTR1_SUFFIX 'Y'
// DCS
#define DCS_PORT 30051 // UDP port
#define DCS_KEEPALIVE_PERIOD 1 // in seconds
#define DCS_KEEPALIVE_TIMEOUT (DCS_KEEPALIVE_PERIOD*30) // in seconds
// XLX, used for BM
#define XLX_PORT 10002 // UDP port
#define XLX_KEEPALIVE_PERIOD 1 // in seconds
#define XLX_KEEPALIVE_TIMEOUT (XLX_KEEPALIVE_PERIOD*30) // in seconds
#define XLX_RECONNECT_PERIOD 5 // in seconds
// URF
#define URF_PORT 10017 // UDP port
#define URF_KEEPALIVE_PERIOD 1 // in seconds
#define URF_KEEPALIVE_TIMEOUT (URF_KEEPALIVE_PERIOD*30) // in seconds
#define URF_RECONNECT_PERIOD 5 // in seconds
// DMRPlus (dongle)
#define DMRPLUS_PORT 8880 // UDP port
#define DMRPLUS_KEEPALIVE_PERIOD 1 // in seconds
#define DMRPLUS_KEEPALIVE_TIMEOUT (DMRPLUS_KEEPALIVE_PERIOD*10) // in seconds
#define DMRPLUS_REFLECTOR_SLOT DMR_SLOT2
#define DMRPLUS_REFLECTOR_COLOUR 1
// DMRMmdvm
#define DMRMMDVM_PORT 62030 // UDP port
#define DMRMMDVM_KEEPALIVE_PERIOD 10 // in seconds
#define DMRMMDVM_KEEPALIVE_TIMEOUT (DMRMMDVM_KEEPALIVE_PERIOD*10) // in seconds
#define DMRMMDVM_REFLECTOR_SLOT DMR_SLOT2
#define DMRMMDVM_REFLECTOR_COLOUR 1
#define DMRMMDVM_DEFAULTID 0
// YSF
#define YSF_PORT 42000 // UDP port
#define YSF_KEEPALIVE_PERIOD 3 // in seconds
#define YSF_KEEPALIVE_TIMEOUT (YSF_KEEPALIVE_PERIOD*10) // in seconds
#define YSF_DEFAULT_NODE_TX_FREQ 445500000 // in Hz
#define YSF_DEFAULT_NODE_RX_FREQ 445500000 // in Hz
//#define YSF_REFLECTOR_ID 12345 // 5 digit YSF ID, assigned by registry when not defined
// the following 4 defines are now in configure.h
//#define YSF_REFLECTOR_NAME "URF000" // Max 16 characters, use reflector callsign when not defined
//#define YSF_REFLECTOR_DESCRIPTION "XLX reflector" // Max 14 characters
// #define YSF_AUTOLINK_ENABLE 0 // 1 = enable, 0 = disable auto-link
// #define YSF_AUTOLINK_MODULE 'B' // module for client to auto-link to
// M17
#define M17_PORT 17000
#define M17_KEEPALIVE_PERIOD 3
#define M17_KEEPALIVE_TIMEOUT (M17_KEEPALIVE_PERIOD*10)
#define M17_RECONNECT_PERIOD 5
// P25
#define P25_REFID 12345 // Reflector ID
#define P25_PORT 41000 // UDP port
#define P25_KEEPALIVE_PERIOD 3 // in seconds
#define P25_KEEPALIVE_TIMEOUT (P25_KEEPALIVE_PERIOD*10) // in seconds
#define P25_AUTOLINK_ENABLE 1 // 1 = enable, 0 = disable auto-link
#define P25_AUTOLINK_MODULE 'A' // module for client to auto-link to
// NXDN
#define NXDN_REFID 12345 // Reflector ID
#define NXDN_PORT 41400 // UDP port
#define NXDN_KEEPALIVE_PERIOD 3 // in seconds
#define NXDN_KEEPALIVE_TIMEOUT (NXDN_KEEPALIVE_PERIOD*10) // in seconds
#define NXDN_AUTOLINK_ENABLE 1 // 1 = enable, 0 = disable auto-link
#define NXDN_AUTOLINK_MODULE 'A' // module for client to auto-link to
// USRP
#define USRP_PORT 34001 // UDP port
#define USRP_KEEPALIVE_PERIOD 1 // in seconds
#define USRP_KEEPALIVE_TIMEOUT (USRP_KEEPALIVE_PERIOD*10) // in seconds
#define USRP_AUTOLINK_ENABLE 1 // 1 = enable, 0 = disable auto-link
#define USRP_AUTOLINK_MODULE 'A' // module for client to auto-link to
#define USRP_DEFAULT_CALLSIGN "ALLSTAR"
#define USRPCLIENTS_PATH "/home/pi/USRPClients.txt" // format ip;port; per line for each ALLSTAR/USRP node
#ifndef NO_G3
// G3 Terminal
#define G3_PRESENCE_PORT 12346 // UDP port
#define G3_CONFIG_PORT 12345 // UDP port
#define G3_DV_PORT 40000 // UDP port
#define G3_KEEPALIVE_PERIOD 10 // in seconds
#define G3_KEEPALIVE_TIMEOUT 3600 // in seconds, 1 hour
#endif
// Transcoder server --------------------------------------------
#ifdef TRANSCODER_IP
#define TRANSCODER_PORT 10100 // UDP port
#endif
#define TRANSCODER_KEEPALIVE_PERIOD 5 // in seconds
#define TRANSCODER_KEEPALIVE_TIMEOUT 30 // in seconds
#define TRANSCODER_AMBEPACKET_TIMEOUT 400 // in ms
// DMRid database -----------------------------------------------
// these values are now set in configure.h by ./rconfig
//#define DMRIDDB_USE_RLX_SERVER 1 // 1 = use http, 0 = use local file
//#define DMRIDDB_PATH "/usr/local/etc/dmrid.dat" // local file path
//#define DMRIDDB_REFRESH_RATE 180 // in minutes
//NXDNid database
#define NXDNIDDB_USE_RLX_SERVER 0 // 1 = use http, 0 = use local file
#define NXDNIDDB_PATH "/home/pi/NXDN.csv" // local file path
#define NXDNIDDB_REFRESH_RATE 180 // in minutes
// Wires-X node database ----------------------------------------
#define YSFNODEDB_USE_RLX_SERVER 1 // 1 = use http, 0 = use local file
#define YSFNODEDB_PATH "/usr/local/etc/ysfnode.dat" // local file path
#define YSFNODEDB_REFRESH_RATE 180 // in minutes
// xml & json reporting -----------------------------------------
#define LASTHEARD_USERS_MAX_SIZE 100
#define XML_UPDATE_PERIOD 10 // in seconds
#ifdef JSON_MONITOR
#define JSON_UPDATE_PERIOD 10 // in seconds
#define JSON_PORT 10001
#endif
// system paths -------------------------------------------------
#define XML_PATH "/var/log/xlxd.xml"
#define WHITELIST_PATH "/usr/local/etc/urfd.whitelist"
#define BLACKLIST_PATH "/usr/local/etc/urfd.blacklist"
#define INTERLINKLIST_PATH "/usr/local/etc/urfd.interlink"
#define TERMINALOPTIONS_PATH "/usr/local/etc/urfd.terminal"
#define PIDFILE_PATH "/var/run/xlxd.pid"
////////////////////////////////////////////////////////////////////////////////////////
// macros
#define MIN(a,b) ((a)<(b))?(a):(b)
#define MAX(a,b) ((a)>(b))?(a):(b)
#define MAKEWORD(low, high) ((uint16_t)(((uint8_t)(low)) | (((uint16_t)((uint8_t)(high))) << 8)))
#define MAKEDWORD(low, high) ((uint32_t)(((uint16_t)(low)) | (((uint32_t)((uint16_t)(high))) << 16)))
#define LOBYTE(w) ((uint8_t)(uint16_t)(w & 0x00FF))
#define HIBYTE(w) ((uint8_t)((((uint16_t)(w)) >> 8) & 0xFF))
#define LOWORD(dw) ((uint16_t)(uint32_t)(dw & 0x0000FFFF))
#define HIWORD(dw) ((uint16_t)((((uint32_t)(dw)) >> 16) & 0xFFFF))
////////////////////////////////////////////////////////////////////////////////////////
// global objects
class CReflector;
extern CReflector g_Reflector;
class CGateKeeper;
extern CGateKeeper g_GateKeeper;
#if (DMRIDDB_USE_RLX_SERVER == 1)
class CDmridDirHttp;
extern CDmridDirHttp g_DmridDir;
#else
class CDmridDirFile;
extern CDmridDirFile g_DmridDir;
#endif
#if (NXDNIDDB_USE_RLX_SERVER == 1)
class CNXDNidDirHttp;
extern CNXDNidDirHttp g_NXDNidDir;
#else
class CNXDNidDirFile;
extern CNXDNidDirFile g_NXDNidDir;
#endif
#if (YSFNODEDB_USE_RLX_SERVER == 1)
class CYsfNodeDirHttp;
extern CYsfNodeDirHttp g_YsfNodeDir;
#else
class CYsfNodeDirFile;
extern CYsfNodeDirFile g_YsfNodeDir;
#endif

@ -17,7 +17,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "NXDNClient.h"

@ -1,145 +0,0 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h"
#include "Reflector.h"
#include "NXDNIdDir.h"
#include "NXDNIdDirFile.h"
#include "NXDNIdDirHttp.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor & destructor
CNXDNidDir::CNXDNidDir()
{
keep_running = true;
}
CNXDNidDir::~CNXDNidDir()
{
Close();
}
////////////////////////////////////////////////////////////////////////////////////////
// init & close
bool CNXDNidDir::Init(void)
{
// load content
Reload();
// reset run flag
keep_running = true;
// start thread;
m_Future = std::async(std::launch::async, &CNXDNidDir::Thread, this);
return true;
}
void CNXDNidDir::Close(void)
{
keep_running = false;
if ( m_Future.valid() )
{
m_Future.get();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// thread
void CNXDNidDir::Thread()
{
while (keep_running)
{
// Wait DMRIDDB_REFRESH_RATE minutes
for (int i=0; i<30*NXDNIDDB_REFRESH_RATE && keep_running; i++)
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
// have lists files changed ?
if ( NeedReload() )
{
Reload();
}
}
}
////////////////////////////////////////////////////////////////////////////////////////
// Reload
bool CNXDNidDir::Reload(void)
{
CBuffer buffer;
bool ok = false;
if ( LoadContent(&buffer) )
{
Lock();
{
ok = RefreshContent(buffer);
}
Unlock();
}
return ok;
}
////////////////////////////////////////////////////////////////////////////////////////
// find
const CCallsign *CNXDNidDir::FindCallsign(uint16_t nxdnid)
{
auto found = m_CallsignMap.find(nxdnid);
if ( found != m_CallsignMap.end() )
{
return &(found->second);
}
return nullptr;
}
uint16_t CNXDNidDir::FindNXDNid(const CCallsign &callsign)
{
auto found = m_NXDNidMap.find(callsign);
if ( found != m_NXDNidMap.end() )
{
return (found->second);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////////////
// syntax helpers
bool CNXDNidDir::IsValidNXDNid(const char *sz)
{
bool ok = false;
size_t n = ::strlen(sz);
if ( (n > 0) && (n <= 5) )
{
ok = true;
for ( size_t i = 0; (i < n) && ok; i++ )
{
ok &= ::isdigit(sz[i]);
}
}
return ok;
}

@ -1,86 +0,0 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
// Copyright © 2021 Doug McLain AD8DP
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "Buffer.h"
#include "Callsign.h"
// compare function for std::map::find
struct CNXDNidDirCallsignCompare
{
bool operator() (const CCallsign &cs1, const CCallsign &cs2) const
{ return cs1.HasLowerCallsign(cs2);}
};
////////////////////////////////////////////////////////////////////////////////////////
class CNXDNidDir
{
public:
// constructor
CNXDNidDir();
// destructor
~CNXDNidDir();
// init & close
virtual bool Init(void);
virtual void Close(void);
// locks
void Lock(void) { m_Mutex.lock(); }
void Unlock(void) { m_Mutex.unlock(); }
// refresh
virtual bool LoadContent(CBuffer *) { return false; }
virtual bool RefreshContent(const CBuffer &) { return false; }
// find
const CCallsign *FindCallsign(uint16_t);
uint16_t FindNXDNid(const CCallsign &);
protected:
// thread
void Thread();
// reload helpers
bool Reload(void);
virtual bool NeedReload(void) { return false; }
bool IsValidNXDNid(const char *);
protected:
// data
std::map <uint16_t, CCallsign> m_CallsignMap;
std::map <CCallsign, uint16_t, CNXDNidDirCallsignCompare> m_NXDNidMap;
// Lock()
std::mutex m_Mutex;
// thread
std::atomic<bool> keep_running;
std::future<void> m_Future;
};

@ -1,159 +0,0 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "Main.h"
#include "NXDNIdDirFile.h"
#if (NXDNIDDB_USE_RLX_SERVER == 0)
CNXDNidDirFile g_NXDNidDir;
#endif
////////////////////////////////////////////////////////////////////////////////////////
// constructor & destructor
CNXDNidDirFile::CNXDNidDirFile()
{
memset(&m_LastModTime, 0, sizeof(time_t));
}
////////////////////////////////////////////////////////////////////////////////////////
// init & close
bool CNXDNidDirFile::Init(void)
{
return CNXDNidDir::Init();
}
////////////////////////////////////////////////////////////////////////////////////////
// refresh
bool CNXDNidDirFile::NeedReload(void)
{
bool needReload = false;
time_t time;
if ( GetLastModTime(&time) )
{
needReload = time != m_LastModTime;
}
return needReload;
}
bool CNXDNidDirFile::LoadContent(CBuffer *buffer)
{
bool ok = false;
std::ifstream file;
std::streampos size;
// open file
file.open(NXDNIDDB_PATH, std::ios::in | std::ios::binary | std::ios::ate);
if ( file.is_open() )
{
// read file
size = file.tellg();
if ( size > 0 )
{
// read file into buffer
buffer->resize((int)size+1);
file.seekg (0, std::ios::beg);
file.read((char *)buffer->data(), (int)size);
// close file
file.close();
// update time
GetLastModTime(&m_LastModTime);
// done
ok = true;
}
}
// done
return ok;
}
bool CNXDNidDirFile::RefreshContent(const CBuffer &buffer)
{
bool ok = false;
// clear directory
m_CallsignMap.clear();
m_NXDNidMap.clear();
// scan buffer
if ( buffer.size() > 0 )
{
// crack it
char *ptr1 = (char *)buffer.data();
char *ptr2;
// get next line
while ( (ptr2 = ::strchr(ptr1, '\n')) != nullptr )
{
*ptr2 = 0;
// get items
char *nxdnid;
char *callsign;
if ( ((nxdnid = ::strtok(ptr1, ",")) != nullptr) && IsValidNXDNid(nxdnid) )
{
if ( ((callsign = ::strtok(nullptr, ",")) != nullptr) )
{
// new entry
uint16_t us = atoi(nxdnid);
CCallsign cs(callsign, 0, us);
if ( cs.IsValid() )
{
m_CallsignMap.insert(std::pair<uint32_t,CCallsign>(us, cs));
m_NXDNidMap.insert(std::pair<CCallsign,uint32_t>(cs,us));
}
}
}
// next line
ptr1 = ptr2+1;
}
// done
ok = true;
}
// report
std::cout << "Read " << m_NXDNidMap.size() << " NXDN ids from file " << NXDNIDDB_PATH << std::endl;
// done
return ok;
}
bool CNXDNidDirFile::GetLastModTime(time_t *time)
{
bool ok = false;
struct stat fileStat;
if( ::stat(NXDNIDDB_PATH, &fileStat) != -1 )
{
*time = fileStat.st_mtime;
ok = true;
}
return ok;
}

@ -1,177 +0,0 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h"
#include "Reflector.h"
#include "NXDNIdDirHttp.h"
#if (NXDNIDDB_USE_RLX_SERVER == 1)
CNXDNidDirHttp g_NXDNidDir;
#endif
////////////////////////////////////////////////////////////////////////////////////////
// refresh
bool CNXDNidDirHttp::LoadContent(CBuffer *buffer)
{
// get file from xlxapi server
return HttpGet("www.dudetronics.com", "ar-dns/NXDN.csv", 80, buffer);
}
bool CNXDNidDirHttp::RefreshContent(const CBuffer &buffer)
{
bool ok = false;
// clear directory
m_CallsignMap.clear();
m_NXDNidMap.clear();
// scan file
if ( buffer.size() > 0 )
{
char *ptr1 = (char *)buffer.data();
char *ptr2;
// get next line
while ( (ptr2 = ::strchr(ptr1, '\n')) != nullptr )
{
std::cout << "newline: " << std::string(ptr2) << std::endl;
*ptr2 = 0;
// get items
char *nxdnid;
char *callsign;
if ( ((nxdnid = ::strtok(ptr1, ",")) != nullptr) && IsValidNXDNid(nxdnid) )
{
if ( ((callsign = ::strtok(nullptr, ",")) != nullptr) )
{
// new entry
uint16_t us = atoi(nxdnid);
CCallsign cs(callsign, 0, us);
if ( cs.IsValid() )
{
m_CallsignMap.insert(std::pair<uint16_t,CCallsign>(us, cs));
m_NXDNidMap.insert(std::pair<CCallsign,uint16_t>(cs,us));
}
}
}
// next line
ptr1 = ptr2+1;
}
// done
ok = true;
}
// report
std::cout << "Read " << m_NXDNidMap.size() << " NXDN ids from xlxapi.rlx.lu database " << std::endl;
// done
return ok;
}
////////////////////////////////////////////////////////////////////////////////////////
// httpd helpers
#define NXDNID_HTTPGET_SIZEMAX (256)
bool CNXDNidDirHttp::HttpGet(const char *hostname, const char *filename, int port, CBuffer *buffer)
{
bool ok = false;
int sock_id;
// open socket
if ( (sock_id = ::socket(AF_INET, SOCK_STREAM, 0)) >= 0 )
{
// get hostname address
struct sockaddr_in servaddr;
struct hostent *hp;
memset(&servaddr,0,sizeof(servaddr));
if( (hp = gethostbyname(hostname)) != nullptr )
{
// dns resolved
memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
servaddr.sin_port = htons(port);
servaddr.sin_family = AF_INET;
// connect
if ( ::connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0)
{
// send the GET request
char request[NXDNID_HTTPGET_SIZEMAX];
::sprintf(request, "GET /%s HTTP/1.0\r\nFrom: %s\r\nUser-Agent: urfd\r\n\r\n",
filename, (const char *)g_Reflector.GetCallsign());
::write(sock_id, request, strlen(request));
// config receive timeouts
fd_set read_set;
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
FD_ZERO(&read_set);
FD_SET(sock_id, &read_set);
// get the reply back
buffer->clear();
bool done = false;
do
{
char buf[1440];
ssize_t len = 0;
select(sock_id+1, &read_set, nullptr, nullptr, &timeout);
//if ( (ret > 0) || ((ret < 0) && (errno == EINPROGRESS)) )
//if ( ret >= 0 )
//{
usleep(5000);
len = read(sock_id, buf, 1440);
if ( len > 0 )
{
buffer->Append((uint8_t *)buf, (int)len);
ok = true;
}
//}
done = (len <= 0);
}
while (!done);
buffer->Append((uint8_t)0);
// and disconnect
close(sock_id);
}
else
{
std::cout << "Cannot establish connection with host " << hostname << std::endl;
}
}
else
{
std::cout << "Host " << hostname << " not found" << std::endl;
}
}
else
{
std::cout << "Failed to open wget socket" << std::endl;
}
// done
return ok;
}

@ -17,7 +17,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "NXDNClient.h"
#include "NXDNProtocol.h"
@ -103,7 +103,7 @@ void CNXDNProtocol::Task(void)
else if ( IsValidDvHeaderPacket(Ip, Buffer, Header) )
{
// node linked and callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::nxdn, Header->GetRpt2Module()) )
if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::nxdn, Header->GetRpt2Module()) )
{
// handle it
OnDvHeaderPacketIn(Header, Ip);
@ -116,10 +116,10 @@ void CNXDNProtocol::Task(void)
else if ( IsValidConnectPacket(Buffer, &Callsign) )
{
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::nxdn) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::nxdn) )
{
// add client if needed
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Callsign, Ip, EProtocol::nxdn);
// client already connected ?
if ( client == nullptr )
@ -141,11 +141,11 @@ void CNXDNProtocol::Task(void)
{
client->Alive();
}
// acknowledge the request -- NXDNReflector simply echoes the packet
Send(Buffer, Ip);
// and done
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
else if ( IsValidDisconnectPacket(Buffer) )
@ -153,14 +153,14 @@ void CNXDNProtocol::Task(void)
std::cout << "NXDN disconnect packet from " << Ip << std::endl;
// find client
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::nxdn);
if ( client != nullptr )
{
// remove it
clients->RemoveClient(client);
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else
{
@ -210,7 +210,7 @@ void CNXDNProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
CCallsign rpt2(Header->GetRpt2Callsign());
// find this client
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, EProtocol::nxdn);
std::shared_ptr<CClient>client = g_Refl..GetClients()->FindClient(Ip, EProtocol::nxdn);
if ( client )
{
// get client callsign
@ -221,20 +221,20 @@ void CNXDNProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
rpt2.SetCSModule(m);
// and try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams[stream->GetStreamId()] = stream;
}
}
// release
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// update last heard
if ( g_Reflector.IsValidModule(rpt2.GetCSModule()) )
if ( g_Refl..IsValidModule(rpt2.GetCSModule()) )
{
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers();
g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Refl..ReleaseUsers();
}
}
}
@ -292,7 +292,7 @@ void CNXDNProtocol::HandleQueue(void)
if ( buffer.size() > 0 )
{
// and push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::nxdn, it)) != nullptr )
@ -305,7 +305,7 @@ void CNXDNProtocol::HandleQueue(void)
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
m_Queue.Unlock();
@ -321,7 +321,7 @@ void CNXDNProtocol::HandleKeepalives(void)
// and disconnect them if not
// iterate on clients
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::nxdn, it)) != nullptr )
@ -341,7 +341,7 @@ void CNXDNProtocol::HandleKeepalives(void)
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -408,24 +408,24 @@ bool CNXDNProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer, s
rpt1.SetCSModule(NXDN_MODULE_ID);
rpt2.SetCSModule(' ');
header = std::unique_ptr<CDvHeaderPacket>(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, false));
if ( g_GateKeeper.MayTransmit(header->GetMyCallsign(), Ip, EProtocol::nxdn, header->GetRpt2Module()) )
if ( g_Gate.MayTransmit(header->GetMyCallsign(), Ip, EProtocol::nxdn, header->GetRpt2Module()) )
{
OnDvHeaderPacketIn(header, Ip);
OnDvHeaderPacketIn(header, Ip);
}
}
// get DV frames
uint8_t ambe49[7];
uint8_t ambe0[9];
uint8_t ambe1[9];
uint8_t ambe2[9];
uint8_t ambe3[9];
memcpy(ambe49, Buffer.data() + 15, 7);
encode(ambe49, ambe0);
uint8_t t[7];
const uint8_t *d = &(Buffer.data()[21]);
for(int i = 0; i < 6; ++i){
@ -436,10 +436,10 @@ bool CNXDNProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer, s
memcpy(ambe49, t, 7);
encode(ambe49, ambe1);
memcpy(ambe49, Buffer.data() + 29, 7);
encode(ambe49, ambe2);
d = &(Buffer.data()[35]);
for(int i = 0; i < 6; ++i){
t[i] = d[i] << 1;
@ -480,14 +480,14 @@ bool CNXDNProtocol::EncodeNXDNHeaderPacket(const CDvHeaderPacket &Header, CBuffe
Buffer.resize(43);
uint16_t NXDNId = Header.GetMyCallsign().GetNXDNid();
uint16_t RptrId = NXDN_REFID;
memcpy(Buffer.data(), "NXDND", 5);
Buffer.data()[5U] = (NXDNId >> 8) & 0xFFU;
Buffer.data()[6U] = (NXDNId >> 0) & 0xFFU;
Buffer.data()[7U] = (RptrId >> 8) & 0xFFU;
Buffer.data()[8U] = (RptrId >> 0) & 0xFFU;
Buffer.data()[9U] = 0x01U;
const uint8_t idle[3U] = {0x10, 0x00, 0x00};
m_lich = 0;
memset(m_sacch, 0, 5U);
@ -514,7 +514,7 @@ bool CNXDNProtocol::EncodeNXDNHeaderPacket(const CDvHeaderPacket &Header, CBuffe
set_layer3_blks(0U);
memcpy(&Buffer.data()[15U], m_layer3, 14U);
memcpy(&Buffer.data()[29U], m_layer3, 14U);
if (Buffer.data()[10U] == 0x81U || Buffer.data()[10U] == 0x83U) {
Buffer.data()[9U] |= Buffer.data()[15U] == 0x01U ? 0x04U : 0x00U;
Buffer.data()[9U] |= Buffer.data()[15U] == 0x08U ? 0x08U : 0x00U;
@ -526,7 +526,7 @@ bool CNXDNProtocol::EncodeNXDNHeaderPacket(const CDvHeaderPacket &Header, CBuffe
Buffer.data()[9U] |= Buffer.data()[12U] == 0x08U ? 0x08U : 0x00U;
}
}
return true;
}
@ -536,14 +536,14 @@ bool CNXDNProtocol::EncodeNXDNPacket(const CDvHeaderPacket &Header, uint32_t seq
Buffer.resize(43);
uint16_t NXDNId = Header.GetMyCallsign().GetNXDNid();
uint16_t RptrId = NXDN_REFID;
memcpy(Buffer.data(), "NXDND", 5);
Buffer.data()[5U] = (NXDNId >> 8) & 0xFFU;
Buffer.data()[6U] = (NXDNId >> 0) & 0xFFU;
Buffer.data()[7U] = (RptrId >> 8) & 0xFFU;
Buffer.data()[8U] = (RptrId >> 0) & 0xFFU;
Buffer.data()[9U] = 0x01U;
uint8_t msg[3U];
m_lich = 0;
memset(m_sacch, 0, 5U);
@ -590,7 +590,7 @@ bool CNXDNProtocol::EncodeNXDNPacket(const CDvHeaderPacket &Header, uint32_t seq
for(int i = 0; i < 4; ++i){
decode(DvFrames[i].GetCodecData(ECodecType::dmr), ambe+(i*7));
}
memcpy(&Buffer.data()[15], ambe, 7);
for(int i = 0; i < 7; ++i){
Buffer.data()[21+i] |= (ambe[7+i] >> 1);
@ -604,7 +604,7 @@ bool CNXDNProtocol::EncodeNXDNPacket(const CDvHeaderPacket &Header, uint32_t seq
Buffer.data()[36+i] = (ambe[21+i] & 1) << 7;
}
Buffer.data()[41] |= (ambe[27] >> 2);
return true;
}
@ -657,11 +657,11 @@ void CNXDNProtocol::decode(const unsigned char* in, unsigned char* out) const
void CNXDNProtocol::encode(const unsigned char* in, unsigned char* out) const
{
unsigned int aOrig = 0U;
unsigned int bOrig = 0U;
unsigned int cOrig = 0U;
unsigned int MASK = 0x000800U;
for (unsigned int i = 0U; i < 12U; i++, MASK >>= 1) {
unsigned int n1 = i + 0U;
@ -838,4 +838,3 @@ void CNXDNProtocol::encode_crc6(uint8_t *d, uint8_t len)
WRITE_BIT(d, n, b);
}
}

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "Notification.h"
CNotification::CNotification()

@ -17,7 +17,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "P25Client.h"

@ -17,7 +17,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "P25Client.h"
#include "P25Protocol.h"
@ -93,7 +93,7 @@ void CP25Protocol::Task(void)
if( !m_uiStreamId && IsValidDvHeaderPacket(Ip, Buffer, Header) )
{
// callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::p25) )
if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::p25) )
{
OnDvHeaderPacketIn(Header, Ip);
}
@ -104,10 +104,10 @@ void CP25Protocol::Task(void)
else if ( IsValidConnectPacket(Buffer, &Callsign) )
{
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::p25) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::p25) )
{
// add client if needed
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Callsign, Ip, EProtocol::p25);
// client already connected ?
if ( client == nullptr )
@ -129,11 +129,11 @@ void CP25Protocol::Task(void)
{
client->Alive();
}
// acknowledge the request -- P25Reflector simply echoes the packet
Send(Buffer, Ip);
// and done
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
else if ( IsValidDisconnectPacket(Buffer, &Callsign) )
@ -141,14 +141,14 @@ void CP25Protocol::Task(void)
std::cout << "P25 disconnect packet from " << Callsign << " at " << Ip << std::endl;
// find client
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::p25);
if ( client != nullptr )
{
// remove it
clients->RemoveClient(client);
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else
{
@ -197,7 +197,7 @@ void CP25Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
CCallsign rpt2(Header->GetRpt2Callsign());
// find this client
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, EProtocol::p25);
std::shared_ptr<CClient>client = g_Refl..GetClients()->FindClient(Ip, EProtocol::p25);
if ( client )
{
// get client callsign
@ -206,18 +206,18 @@ void CP25Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
Header->SetRpt2Module(m);
rpt2.SetCSModule(m);
// and try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams[stream->GetStreamId()] = stream;
}
}
// release
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers();
g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Refl..ReleaseUsers();
}
}
@ -256,7 +256,7 @@ void CP25Protocol::HandleQueue(void)
if ( buffer.size() > 0 )
{
// and push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::p25, it)) != nullptr )
@ -269,7 +269,7 @@ void CP25Protocol::HandleQueue(void)
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
}
@ -308,7 +308,7 @@ bool CP25Protocol::IsValidDvPacket(const CIp &Ip, const CBuffer &Buffer, std::un
{
int offset = 0;
bool last = false;
switch (Buffer.data()[0U]) {
case 0x62U:
offset = 10U;
@ -357,7 +357,7 @@ bool CP25Protocol::IsValidDvPacket(const CIp &Ip, const CBuffer &Buffer, std::un
default:
break;
}
frame = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(&(Buffer.data()[offset]), m_uiStreamId, last));
return true;
}
@ -388,18 +388,18 @@ void CP25Protocol::EncodeP25Packet(const CDvHeaderPacket &Header, const CDvFrame
{
uint32_t uiSrcId = Header.GetMyCallsign().GetDmrid();
uint32_t uiRptrId = P25_REFID;
if(uiSrcId == 0){
uiSrcId = DMRMMDVM_DEFAULTID;
}
if(islast)
{
Buffer.resize(17);
::memcpy(Buffer.data(), REC80, 17U);
return;
}
switch (iSeq % 18) {
case 0x00U:
Buffer.resize(22);
@ -506,7 +506,7 @@ void CP25Protocol::EncodeP25Packet(const CDvHeaderPacket &Header, const CDvFrame
void CP25Protocol::HandleKeepalives(void)
{
// iterate on clients
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::p25, it)) != nullptr )
@ -526,6 +526,5 @@ void CP25Protocol::HandleKeepalives(void)
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "Packet.h"
// default constructor

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "PacketStream.h"
////////////////////////////////////////////////////////////////////////////////////////
@ -32,10 +32,15 @@ CPacketStream::CPacketStream()
m_uiStreamId = 0;
m_uiPacketCntr = 0;
m_OwnerClient = nullptr;
#ifdef TRANSCODED_MODULES
m_CodecStream = nullptr;
m_TCReader = reader;
#endif
}
bool CPacketStream::InitPacketStream(bool is_transcoded)
{
if (is_transcoded)
m_CodecStream = std::unique_ptr<CCodecStream>(new CCodecStream(this));
return nullptr == m_CodecStream;
}
////////////////////////////////////////////////////////////////////////////////////////
@ -53,16 +58,6 @@ bool CPacketStream::OpenPacketStream(const CDvHeaderPacket &DvHeader, std::share
m_DvHeader = DvHeader;
m_OwnerClient = client;
m_LastPacketTime.start();
#ifdef TRANSCODED_MODULES
if (DvHeader.IsLocalOrigin()) // we only need transcoding if the source is local
{
auto mod = DvHeader.GetRpt2Module();
if (std::string::npos != std::string(TRANSCODED_MODULES).find(mod))
{
m_CodecStream = std::unique_ptr<CCodecStream>(new CCodecStream(this, m_uiStreamId, DvHeader.GetCodecIn(), m_TCReader));
}
}
#endif
return true;
}
@ -75,9 +70,8 @@ void CPacketStream::ClosePacketStream(void)
m_bOpen = false;
m_uiStreamId = 0;
m_OwnerClient.reset();
#ifdef TRANSCODED_MODULES
m_CodecStream.reset();
#endif
if (m_CodecStream)
m_CodecStream.reset();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -92,7 +86,6 @@ void CPacketStream::Push(std::unique_ptr<CPacket> Packet)
Packet->UpdatePids(m_uiPacketCntr++);
}
// transcoder avaliable ?
#ifdef TRANSCODED_MODULES
if ( m_CodecStream )
{
// todo: verify no possibilty of double lock here
@ -115,7 +108,6 @@ void CPacketStream::Push(std::unique_ptr<CPacket> Packet)
m_CodecStream->Unlock();
}
else
#endif
{
// otherwise, push direct push
push(Packet);

@ -22,10 +22,7 @@
#include "Timer.h"
#include "DVHeaderPacket.h"
#include "Client.h"
#ifdef TRANSCODED_MODULES
#include "UnixDgramSocket.h"
#include "CodecStream.h"
#endif
////////////////////////////////////////////////////////////////////////////////////////
@ -38,12 +35,8 @@
class CPacketStream : public CPacketQueue
{
public:
// constructor
#ifdef TRANSCODED_MODULES
CPacketStream(std::shared_ptr<CUnixDgramReader>);
#else
CPacketStream();
#endif
bool InitPacketStream(bool is_transcoded);
// open / close
bool OpenPacketStream(const CDvHeaderPacket &, std::shared_ptr<CClient>);
@ -70,8 +63,5 @@ protected:
CTimer m_LastPacketTime;
CDvHeaderPacket m_DvHeader;
std::shared_ptr<CClient> m_OwnerClient;
#ifdef TRANSCODED_MODULES
std::shared_ptr<CUnixDgramReader> m_TCReader;
std::unique_ptr<CCodecStream> m_CodecStream;
#endif
};

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "Reflector.h"
#include "Peer.h"

@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h"
#include "PeerCallsignList.h"
bool CPeerCallsignList::LoadFromFile(const char *filename)

@ -18,7 +18,7 @@
#pragma once
#include "Main.h"
#include "CallsignList.h"
////////////////////////////////////////////////////////////////////////////////////////

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "Reflector.h"
#include "Peers.h"
@ -60,15 +60,15 @@ void CPeers::AddPeer(std::shared_ptr<CPeer> peer)
std::cout << "New peer " << peer->GetCallsign() << " at " << peer->GetIp() << " added with protocol " << peer->GetProtocolName() << std::endl;
// and append all peer's client to reflector client list
// it is double lock safe to lock Clients list after Peers list
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
for ( auto cit=peer->cbegin(); cit!=peer->cend(); cit++ )
{
clients->AddClient(*cit);
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// notify
g_Reflector.OnPeersChanged();
g_Refl..OnPeersChanged();
}
void CPeers::RemovePeer(std::shared_ptr<CPeer> peer)
@ -81,7 +81,7 @@ void CPeers::RemovePeer(std::shared_ptr<CPeer> peer)
{
// remove all clients from reflector client list
// it is double lock safe to lock Clients list after Peers list
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
for ( auto cit=peer->begin(); cit!=peer->end(); cit++ )
{
// this also delete the client object
@ -89,13 +89,13 @@ void CPeers::RemovePeer(std::shared_ptr<CPeer> peer)
}
// so clear it then
(*pit)->ClearClients();
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// remove it
std::cout << "Peer " << (*pit)->GetCallsign() << " at " << (*pit)->GetIp() << " removed" << std::endl;
pit = m_Peers.erase(pit);
// notify
g_Reflector.OnPeersChanged();
g_Refl..OnPeersChanged();
}
else
{

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "Protocol.h"
#include "Clients.h"
#include "Reflector.h"
@ -52,7 +52,7 @@ CProtocol::~CProtocol()
bool CProtocol::Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6)
{
// init reflector apparent callsign
m_ReflectorCallsign = g_Reflector.GetCallsign();
m_ReflectorCallsign = g_Refl..GetCallsign();
// reset stop flag
keep_running = true;
@ -179,7 +179,7 @@ void CProtocol::CheckStreamsTimeout(void)
{
// yes, close it
it->second->Unlock();
g_Reflector.CloseStream(it->second);
g_Refl..CloseStream(it->second);
// and remove it from the m_Streams map
it = m_Streams.erase(it);
}

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "DExtraProtocol.h"
#include "DPlusProtocol.h"
#include "DCSProtocol.h"
@ -80,15 +80,15 @@ bool CProtocols::Init(void)
m_Protocols.emplace_back(std::unique_ptr<CM17Protocol>(new CM17Protocol));
if (! m_Protocols.back()->Initialize("URF", EProtocol::m17, M17_PORT, M17_IPV4, M17_IPV6))
return false;
m_Protocols.emplace_back(std::unique_ptr<CP25Protocol>(new CP25Protocol));
if (! m_Protocols.back()->Initialize("P25", EProtocol::p25, P25_PORT, P25_IPV4, P25_IPV6))
return false;
m_Protocols.emplace_back(std::unique_ptr<CNXDNProtocol>(new CNXDNProtocol));
if (! m_Protocols.back()->Initialize("NXDN", EProtocol::nxdn, NXDN_PORT, NXDN_IPV4, NXDN_IPV6))
return false;
m_Protocols.emplace_back(std::unique_ptr<CUSRPProtocol>(new CUSRPProtocol));
if (! m_Protocols.back()->Initialize("USRP", EProtocol::usrp, USRP_PORT, USRP_IPV4, USRP_IPV6))
return false;

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "Reflector.h"
#include "RawSocket.h"

@ -16,26 +16,10 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "Reflector.h"
#include "GateKeeper.h"
#include "DMRIdDirFile.h"
#include "DMRIdDirHttp.h"
#include "NXDNIdDirFile.h"
#include "NXDNIdDirHttp.h"
#include "YSFNodeDirFile.h"
#include "YSFNodeDirHttp.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CReflector::CReflector() : m_Callsign(CALLSIGN), m_Modules(ACTIVE_MODULES), keep_running(true)
{
}
#include <string.h>
#include "Global.h"
////////////////////////////////////////////////////////////////////////////////////////
// destructor
@ -46,12 +30,7 @@ CReflector::~CReflector()
{
m_XmlReportFuture.get();
}
#ifdef JSON_MONITOR
if ( m_JsonReportFuture.valid() )
{
m_JsonReportFuture.get();
}
#endif
for (auto it=m_Modules.cbegin(); it!=m_Modules.cend(); it++)
{
if (m_RouterFuture[*it].valid())
@ -59,11 +38,6 @@ CReflector::~CReflector()
}
m_RouterFuture.clear();
m_Stream.clear();
#ifdef TRANSCODED_MODULES
m_TCReader.clear();
#endif
}
@ -72,55 +46,68 @@ CReflector::~CReflector()
bool CReflector::Start(void)
{
// get config stuff
m_Callsign = CCallsign(g_Conf.GetString(g_Conf.j.names.cs).c_str(), false);
m_Modules.assign(g_Conf.GetString(g_Conf.j.modules.modules));
std::string tcmods(g_Conf.GetString(g_Conf.j.modules.tcmodules));
// let's go!
keep_running = true;
// init gate keeper. It can only return true!
g_GateKeeper.Init();
g_Gate.Init();
// init dmrid directory. No need to check the return value.
g_DmridDir.Init();
g_LDid.LookupInit();
// init dmrid directory. No need to check the return value.
g_NXDNidDir.Init();
g_LNid.LookupInit();
// init wiresx node directory. Likewise with the return vale.
g_YsfNodeDir.Init();
g_LYtr.LookupInit();
// create protocols
if (! m_Protocols.Init())
{
m_Protocols.Close();
return false;
return true;
}
// start one thread per reflector module
for (auto it=m_Modules.cbegin(); it!=m_Modules.cend(); it++)
for (auto c : m_Modules)
{
#ifdef TRANSCODED_MODULES
m_TCReader[*it] = std::make_shared<CUnixDgramReader>();
std::string readername(TC2REF);
readername.append(1, *it);
if (m_TCReader[*it]->Open(readername.c_str()))
auto stream = std::make_shared<CPacketStream>();
if (stream)
{
stream->InitPacketStream(std::string::npos != tcmods.find(c));
}
else
{
std::cerr << "ERROR: Reflector can't open " << readername << std::endl;
m_TCReader[*it].reset();
return false;
return true;
}
try
{
m_RouterFuture[c] = std::async(std::launch::async, &CReflector::RouterThread, this, c);
}
catch(const std::exception& e)
{
std::cerr << "Cannot start module '" << c << "' thread: " << e.what() << '\n';
keep_running = false;
return true;
}
m_Stream[*it] = std::make_shared<CPacketStream>(m_TCReader[*it]);
#else
m_Stream[*it] = std::make_shared<CPacketStream>();
#endif
m_RouterFuture[*it] = std::async(std::launch::async, &CReflector::RouterThread, this, *it);
}
// start the reporting threads
m_XmlReportFuture = std::async(std::launch::async, &CReflector::XmlReportThread, this);
#ifdef JSON_MONITOR
m_JsonReportFuture = std::async(std::launch::async, &CReflector::JsonReportThread, this);
#endif
try
{
m_XmlReportFuture = std::async(std::launch::async, &CReflector::XmlReportThread, this);
}
catch(const std::exception& e)
{
std::cerr << "Cannot start the dashboard data report thread: " << e.what() << '\n';
}
return true;
return false;
}
void CReflector::Stop(void)
@ -133,30 +120,24 @@ void CReflector::Stop(void)
{
m_XmlReportFuture.get();
}
#ifdef JSON_MONITOR
if ( m_JsonReportFuture.valid() )
{
m_JsonReportFuture.get();
}
#endif
// stop & delete all router thread
for (auto it=m_Modules.cbegin(); it!=m_Modules.cend(); it++)
for (auto c : m_Modules)
{
if (m_RouterFuture[*it].valid())
m_RouterFuture[*it].get();
if (m_RouterFuture[c].valid())
m_RouterFuture[c].get();
}
// close protocols
m_Protocols.Close();
// close gatekeeper
g_GateKeeper.Close();
g_Gate.Close();
// close databases
g_DmridDir.Close();
g_NXDNidDir.Close();
g_YsfNodeDir.Close();
g_LDid.LookupClose();
g_LNid.LookupClose();
g_LYtr.LookupClose();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -338,13 +319,16 @@ void CReflector::RouterThread(const char ThisModule)
////////////////////////////////////////////////////////////////////////////////////////
// report threads
#define XML_UPDATE_PERIOD 10
void CReflector::XmlReportThread()
{
const std::string path(g_Conf.GetString(g_Conf.j.files.json));
while (keep_running)
{
// report to xml file
std::ofstream xmlFile;
xmlFile.open(XML_PATH, std::ios::out | std::ios::trunc);
xmlFile.open(path, std::ios::out | std::ios::trunc);
if ( xmlFile.is_open() )
{
// write xml file
@ -353,12 +337,10 @@ void CReflector::XmlReportThread()
// and close file
xmlFile.close();
}
#ifndef DEBUG_NO_ERROR_ON_XML_OPEN_FAIL
else
{
std::cout << "Failed to open " << XML_PATH << std::endl;
std::cout << "Failed to open " << path << std::endl;
}
#endif
// and wait a bit
for (int i=0; i< XML_UPDATE_PERIOD && keep_running; i++)
@ -366,100 +348,6 @@ void CReflector::XmlReportThread()
}
}
#ifdef JSON_MONITOR
void CReflector::JsonReportThread()
{
CUdpSocket Socket;
CBuffer Buffer;
CIp Ip;
bool bOn;
// init variable
bOn = false;
// create listening socket
if ( Socket.Open(JSON_PORT) )
{
// and loop
while (keep_running)
{
// any command ?
if ( Socket.Receive(Buffer, Ip, 50) )
{
// check verb
if ( Buffer.Compare((uint8_t *)"hello", 5) == 0 )
{
std::cout << "Monitor socket connected with " << Ip << std::endl;
// connected
bOn = true;
// announce ourselves
SendJsonReflectorObject(Socket, Ip);
// dump tables
SendJsonNodesObject(Socket, Ip);
SendJsonStationsObject(Socket, Ip);
}
else if ( Buffer.Compare((uint8_t *)"bye", 3) == 0 )
{
std::cout << "Monitor socket disconnected" << std::endl;
// diconnected
bOn = false;
}
}
// any notifications ?
CNotification notification;
m_Notifications.Lock();
if ( !m_Notifications.empty() )
{
// get the packet
notification = m_Notifications.front();
m_Notifications.pop();
}
m_Notifications.Unlock();
// handle it
if ( bOn )
{
switch ( notification.GetId() )
{
case NOTIFICATION_CLIENTS:
case NOTIFICATION_PEERS:
//std::cout << "Monitor updating nodes table" << std::endl;
SendJsonNodesObject(Socket, Ip);
break;
case NOTIFICATION_USERS:
//std::cout << "Monitor updating stations table" << std::endl;
SendJsonStationsObject(Socket, Ip);
break;
case NOTIFICATION_STREAM_OPEN:
//std::cout << "Monitor notify station " << notification.GetCallsign() << "going ON air" << std::endl;
SendJsonStationsObject(Socket, Ip);
SendJsonOnairObject(Socket, Ip, notification.GetCallsign());
break;
case NOTIFICATION_STREAM_CLOSE:
//std::cout << "Monitor notify station " << notification.GetCallsign() << "going OFF air" << std::endl;
SendJsonOffairObject(Socket, Ip, notification.GetCallsign());
break;
case NOTIFICATION_NONE:
default:
// nothing to do, just sleep a bit
std::this_thread::sleep_for(std::chrono::milliseconds(250);
break;
}
}
}
}
else
{
std::cout << "Error creating monitor socket" << std::endl;
}
}
#endif
////////////////////////////////////////////////////////////////////////////////////////
// notifications
@ -549,9 +437,7 @@ void CReflector::WriteXmlFile(std::ofstream &xmlFile)
xmlFile << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
// software version
char sz[64];
::sprintf(sz, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
xmlFile << "<Version>" << sz << "</Version>" << std::endl;
xmlFile << "<Version>" << g_Vers << "</Version>" << std::endl;
CCallsign cs = m_Callsign;
cs.PatchCallsign(0, "XLX", 3);
@ -598,120 +484,3 @@ void CReflector::WriteXmlFile(std::ofstream &xmlFile)
ReleaseUsers();
xmlFile << "</" << cs << "heard users>" << std::endl;
}
#ifdef JSON_MONITOR
////////////////////////////////////////////////////////////////////////////////////////
// json helpers
void CReflector::SendJsonReflectorObject(CUdpSocket &Socket, CIp &Ip)
{
char Buffer[1024];
char cs[CALLSIGN_LEN+1];
char mod[8] = "\"A\"";
// get reflector callsign
m_Callsign.GetCallsign((uint8_t *)cs);
cs[CALLSIGN_LEN] = 0;
// build string
::sprintf(Buffer, "{\"reflector\":\"%s\",\"modules\":[", cs);
for ( int i = 0; i < NB_OF_MODULES; i++ )
{
::strcat(Buffer, mod);
mod[1]++;
if ( i < NB_OF_MODULES-1 )
{
::strcat(Buffer, ",");
}
}
::strcat(Buffer, "]}");
// and send
Socket.Send(Buffer, Ip);
}
#define JSON_NBMAX_NODES 250
void CReflector::SendJsonNodesObject(CUdpSocket &Socket, CIp &Ip)
{
char Buffer[12+(JSON_NBMAX_NODES*94)];
// nodes object table
::sprintf(Buffer, "{\"nodes\":[");
// lock
CClients *clients = GetClients();
// iterate on clients
for ( auto it=clients->cbegin(); it!=clients->cend(); )
{
(*it++)->GetJsonObject(Buffer);
if ( it != clients->cend() )
{
::strcat(Buffer, ",");
}
}
// unlock
ReleaseClients();
::strcat(Buffer, "]}");
// and send
//std::cout << Buffer << std::endl;
Socket.Send(Buffer, Ip);
}
void CReflector::SendJsonStationsObject(CUdpSocket &Socket, CIp &Ip)
{
char Buffer[15+(LASTHEARD_USERS_MAX_SIZE*94)];
// stations object table
::sprintf(Buffer, "{\"stations\":[");
// lock
CUsers *users = GetUsers();
// iterate on users
for ( auto it=users->begin(); it!=users->end(); )
{
(*it++).GetJsonObject(Buffer);
if ( it != users->end() )
{
::strcat(Buffer, ",");
}
}
// unlock
ReleaseUsers();
::strcat(Buffer, "]}");
// and send
//std::cout << Buffer << std::endl;
Socket.Send(Buffer, Ip);
}
void CReflector::SendJsonOnairObject(CUdpSocket &Socket, CIp &Ip, const CCallsign &Callsign)
{
char Buffer[128];
char sz[CALLSIGN_LEN+1];
// onair object
Callsign.GetCallsignString(sz);
::sprintf(Buffer, "{\"onair\":\"%s\"}", sz);
// and send
//std::cout << Buffer << std::endl;
Socket.Send(Buffer, Ip);
}
void CReflector::SendJsonOffairObject(CUdpSocket &Socket, CIp &Ip, const CCallsign &Callsign)
{
char Buffer[128];
char sz[CALLSIGN_LEN+1];
// offair object
Callsign.GetCallsignString(sz);
::sprintf(Buffer, "{\"offair\":\"%s\"}", sz);
// and send
//std::cout << Buffer << std::endl;
Socket.Send(Buffer, Ip);
}
#endif

@ -18,6 +18,8 @@
#pragma once
#include <unordered_map>
#include "Users.h"
#include "Clients.h"
#include "Peers.h"
@ -40,19 +42,8 @@
class CReflector
{
public:
// constructor
CReflector();
// destructor
virtual ~CReflector();
//
const CCallsign &GetCallsign(void) const { return m_Callsign; }
#ifdef TRANSCODER_IP
void SetTranscoderIp(const char *a, const int n) { memset(m_AmbedIp, 0, n); strncpy(m_AmbedIp, a, n-1); }
const char *GetTranscoderIp(void) const { return m_AmbedIp; }
#endif
~CReflector();
// operation
bool Start(void);
@ -71,7 +62,8 @@ public:
bool IsStreaming(char);
void CloseStream(std::shared_ptr<CPacketStream>);
// users
// get
const CCallsign &GetCallsign(void) const { return m_Callsign; }
CUsers *GetUsers(void) { m_Users.Lock(); return &m_Users; }
void ReleaseUsers(void) { m_Users.Unlock(); }
@ -90,9 +82,6 @@ protected:
// threads
void RouterThread(const char);
void XmlReportThread(void);
#ifdef JSON_MONITOR
void JsonReportThread(void);
#endif
// streams
std::shared_ptr<CPacketStream> GetStream(char);
@ -102,22 +91,10 @@ protected:
// xml helpers
void WriteXmlFile(std::ofstream &);
#ifdef JSON_MONITOR
// json helpers
void SendJsonReflectorObject(CUdpSocket &, CIp &);
void SendJsonNodesObject(CUdpSocket &, CIp &);
void SendJsonStationsObject(CUdpSocket &, CIp &);
void SendJsonOnairObject(CUdpSocket &, CIp &, const CCallsign &);
void SendJsonOffairObject(CUdpSocket &, CIp &, const CCallsign &);
#endif
protected:
// identity
const CCallsign m_Callsign;
const std::string m_Modules;
#ifdef TRANSCODER_IP
char m_AmbedIp[INET6_ADDRSTRLEN];
#endif
CCallsign m_Callsign;
std::string m_Modules, m_TCmodules;
// objects
CUsers m_Users; // sorted list of lastheard stations
@ -127,22 +104,12 @@ protected:
// queues
std::unordered_map<char, std::shared_ptr<CPacketStream>> m_Stream;
#ifdef TRANSCODED_MODULES
std::unordered_map<char, std::shared_ptr<CUnixDgramReader>> m_TCReader;
#endif
// threads
std::atomic<bool> keep_running;
std::unordered_map<char, std::future<void>> m_RouterFuture;
std::future<void> m_XmlReportFuture;
#ifdef JSON_MONITOR
std::future<void> m_JsonReportFuture;
#endif
// notifications
CNotificationQueue m_Notifications;
public:
#ifdef DEBUG_DUMPFILE
std::ofstream m_DebugFile;
#endif
};

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "Semaphore.h"
////////////////////////////////////////////////////////////////////////////////////////

@ -18,7 +18,7 @@
#pragma once
#include "Main.h"
class CSemaphore
{

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "UDPMsgSocket.h"

@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h"
#include "UDPSocket.h"

@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h"
#include "URFClient.h"

@ -18,7 +18,7 @@
#include <string.h>
#include "Main.h"
#include "Reflector.h"
#include "URFPeer.h"
#include "URFClient.h"

@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <cstring>
#include "Main.h"
#include "URFPeer.h"
#include "URFProtocol.h"
#include "Reflector.h"
@ -73,19 +73,19 @@ void CURFProtocol::Task(void)
else if ( IsValidKeepAlivePacket(Buffer, &Callsign) )
{
// find peer
CPeers *peers = g_Reflector.GetPeers();
CPeers *peers = g_Refl..GetPeers();
std::shared_ptr<CPeer>peer = peers->FindPeer(Ip, EProtocol::urf);
if ( peer != nullptr )
{
// keep it alive
peer->Alive();
}
g_Reflector.ReleasePeers();
g_Refl..ReleasePeers();
}
else if ( IsValidDvHeaderPacket(Buffer, Header) )
{
// callsign allowed?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip) )
if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip) )
{
OnDvHeaderPacketIn(Header, Ip);
}
@ -95,7 +95,7 @@ void CURFProtocol::Task(void)
std::cout << "URF (" << Version.GetMajor() << "." << Version.GetMinor() << "." << Version.GetRevision() << ") connect packet for modules " << Modules << " from " << Callsign << " at " << Ip << std::endl;
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::urf, Modules) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::urf, Modules) )
{
// acknowledge connecting request
// following is version dependent
@ -123,10 +123,10 @@ void CURFProtocol::Task(void)
std::cout << "URF ack packet for modules " << Modules << " from " << Callsign << " at " << Ip << std::endl;
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::urf, Modules) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::urf, Modules) )
{
// already connected ?
CPeers *peers = g_Reflector.GetPeers();
CPeers *peers = g_Refl..GetPeers();
if ( peers->FindPeer(Callsign, Ip, EProtocol::urf) == nullptr )
{
// create the new peer
@ -137,7 +137,7 @@ void CURFProtocol::Task(void)
// this also add all new clients to reflector client list
peers->AddPeer(peer);
}
g_Reflector.ReleasePeers();
g_Refl..ReleasePeers();
}
}
else if ( IsValidDisconnectPacket(Buffer, &Callsign) )
@ -145,7 +145,7 @@ void CURFProtocol::Task(void)
std::cout << "URF disconnect packet from " << Callsign << " at " << Ip << std::endl;
// find peer
CPeers *peers = g_Reflector.GetPeers();
CPeers *peers = g_Refl..GetPeers();
std::shared_ptr<CPeer>peer = peers->FindPeer(Ip, EProtocol::urf);
if ( peer != nullptr )
{
@ -154,7 +154,7 @@ void CURFProtocol::Task(void)
// and delete them
peers->RemovePeer(peer);
}
g_Reflector.ReleasePeers();
g_Refl..ReleasePeers();
}
else if ( IsValidNackPacket(Buffer, &Callsign) )
{
@ -216,7 +216,7 @@ void CURFProtocol::HandleQueue(void)
if ( EncodeDvPacket(*packet, buffer) )
{
// and push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::urf, it)) != nullptr )
@ -232,7 +232,7 @@ void CURFProtocol::HandleQueue(void)
}
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
}
@ -251,7 +251,7 @@ void CURFProtocol::HandleKeepalives(void)
EncodeKeepAlivePacket(&keepalive);
// iterate on peers
CPeers *peers = g_Reflector.GetPeers();
CPeers *peers = g_Refl..GetPeers();
auto pit = peers->begin();
std::shared_ptr<CPeer>peer = nullptr;
while ( (peer = peers->FindNextPeer(EProtocol::urf, pit)) != nullptr )
@ -278,7 +278,7 @@ void CURFProtocol::HandleKeepalives(void)
peers->RemovePeer(peer);
}
}
g_Reflector.ReleasePeers();
g_Refl..ReleasePeers();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -289,8 +289,8 @@ void CURFProtocol::HandlePeerLinks(void)
CBuffer buffer;
// get the list of peers
CPeerCallsignList *list = g_GateKeeper.GetPeerList();
CPeers *peers = g_Reflector.GetPeers();
CPeerCallsignList *list = g_Gate.GetPeerList();
CPeers *peers = g_Refl..GetPeers();
// check if all our connected peers are still listed by gatekeeper
// if not, disconnect
@ -330,8 +330,8 @@ void CURFProtocol::HandlePeerLinks(void)
}
// done
g_Reflector.ReleasePeers();
g_GateKeeper.ReleasePeerList();
g_Refl..ReleasePeers();
g_Gate.ReleasePeerList();
}
@ -363,11 +363,11 @@ void CURFProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
CCallsign rpt2(Header->GetRpt2Callsign());
// no stream open yet, open a new one
// find this client
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, EProtocol::urf, Header->GetRpt2Module());
std::shared_ptr<CClient>client = g_Refl..GetClients()->FindClient(Ip, EProtocol::urf, Header->GetRpt2Module());
if ( client )
{
// and try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams[stream->GetStreamId()] = stream;
@ -376,10 +376,10 @@ void CURFProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
peer = client->GetCallsign();
}
// release
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2, peer);
g_Reflector.ReleaseUsers();
g_Refl..GetUsers()->Hearing(my, rpt1, rpt2, peer);
g_Refl..ReleaseUsers();
}
}
@ -521,7 +521,7 @@ void CURFProtocol::EncodeKeepAlivePacket(CBuffer *Buffer)
{
Buffer->Set("PING");
Buffer->resize(10);
g_Reflector.GetCallsign().CodeOut(Buffer->data()+4);
g_Refl..GetCallsign().CodeOut(Buffer->data()+4);
}
void CURFProtocol::EncodeConnectPacket(CBuffer *Buffer, const char *Modules)
@ -530,7 +530,7 @@ void CURFProtocol::EncodeConnectPacket(CBuffer *Buffer, const char *Modules)
Buffer->Set("CONN");
// our callsign
Buffer->resize(37);
g_Reflector.GetCallsign().CodeOut(Buffer->data()+4);
g_Refl..GetCallsign().CodeOut(Buffer->data()+4);
// our version
Buffer->ReplaceAt(10, (uint8_t *)Modules, strlen(Modules));
Buffer->Append((uint8_t)VERSION_MAJOR);
@ -543,7 +543,7 @@ void CURFProtocol::EncodeDisconnectPacket(CBuffer *Buffer)
Buffer->Set("DISC");
// our callsign
Buffer->resize(10);
g_Reflector.GetCallsign().CodeOut(Buffer->data()+4);
g_Refl..GetCallsign().CodeOut(Buffer->data()+4);
}
void CURFProtocol::EncodeConnectAckPacket(CBuffer *Buffer, const char *Modules)
@ -551,7 +551,7 @@ void CURFProtocol::EncodeConnectAckPacket(CBuffer *Buffer, const char *Modules)
Buffer->Set("ACKN");
// our callsign
Buffer->resize(37);
g_Reflector.GetCallsign().CodeOut(Buffer->data()+4);
g_Refl..GetCallsign().CodeOut(Buffer->data()+4);
// the shared modules
Buffer->ReplaceAt(10, (uint8_t *)Modules, strlen(Modules));
// our version
@ -564,5 +564,5 @@ void CURFProtocol::EncodeConnectNackPacket(CBuffer *Buffer)
{
Buffer->Set("NACK");
Buffer->resize(10);
g_Reflector.GetCallsign().CodeOut(Buffer->data()+4);
g_Refl..GetCallsign().CodeOut(Buffer->data()+4);
}

@ -17,7 +17,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "USRPClient.h"

@ -17,7 +17,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "USRPClient.h"
#include "USRPProtocol.h"
@ -41,14 +41,14 @@ bool CUSRPProtocol::Initialize(const char *type, const EProtocol ptype, const ui
CBuffer buffer;
m_uiStreamId = 0;
CCallsign cs(USRP_DEFAULT_CALLSIGN);
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::ifstream file;
std::streampos size;
// base class
if (! CProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6))
return false;
file.open(USRPCLIENTS_PATH, std::ios::in | std::ios::binary | std::ios::ate);
if ( file.is_open() )
{
@ -93,7 +93,7 @@ bool CUSRPProtocol::Initialize(const char *type, const EProtocol ptype, const ui
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// update time
m_LastKeepaliveTime.start();
@ -135,7 +135,7 @@ void CUSRPProtocol::Task(void)
else if( IsValidDvHeaderPacket(Ip, Buffer, Header) )
{
// callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::usrp) )
if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::usrp) )
{
OnDvHeaderPacketIn(Header, Ip);
}
@ -192,7 +192,7 @@ void CUSRPProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
CCallsign rpt2(Header->GetRpt2Callsign());
// find this client
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, EProtocol::usrp);
std::shared_ptr<CClient>client = g_Refl..GetClients()->FindClient(Ip, EProtocol::usrp);
if ( client )
{
// get client callsign
@ -201,18 +201,18 @@ void CUSRPProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
Header->SetRpt2Module(m);
rpt2.SetCSModule(m);
// and try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams[stream->GetStreamId()] = stream;
}
}
// release
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers();
g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Refl..ReleaseUsers();
}
}
@ -249,7 +249,7 @@ void CUSRPProtocol::HandleQueue(void)
if ( buffer.size() > 0 )
{
// and push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::usrp, it)) != nullptr )
@ -261,7 +261,7 @@ void CUSRPProtocol::HandleQueue(void)
Send(buffer, client->GetIp());
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
m_Queue.Unlock();
@ -285,14 +285,14 @@ bool CUSRPProtocol::IsValidDvPacket(const CIp &Ip, const CBuffer &Buffer, std::u
rpt1.SetCSModule(USRP_MODULE_ID);
rpt2.SetCSModule(' ');
header = std::unique_ptr<CDvHeaderPacket>(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, true));
OnDvHeaderPacketIn(header, Ip);
OnDvHeaderPacketIn(header, Ip);
}
int16_t pcm[160];
for(int i = 0; i < 160; ++i){
pcm[i] = (Buffer.data()[32+(i*2)+1] << 8) | Buffer.data()[32+(i*2)];
}
frame = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(pcm, m_uiStreamId, false));
return true;
}
@ -354,7 +354,7 @@ void CUSRPProtocol::EncodeUSRPPacket(const CDvHeaderPacket &Header, const CDvFra
memcpy(Buffer.data(), "USRP", 4);
memcpy(Buffer.data() + 4, &cnt, 4);
Buffer.data()[15] = USRP_KEYUP_FALSE;
}
else
{
@ -375,7 +375,7 @@ void CUSRPProtocol::EncodeUSRPPacket(const CDvHeaderPacket &Header, const CDvFra
void CUSRPProtocol::HandleKeepalives(void)
{
// iterate on clients
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::usrp, it)) != nullptr )
@ -395,6 +395,5 @@ void CUSRPProtocol::HandleKeepalives(void)
//}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "User.h"

@ -33,7 +33,7 @@ public:
~CUser() {}
// operation
void HeardNow(void) { m_LastHeardTime = std::time(nullptr); }
void HeardNow(void) { m_LastHeardTime = time(nullptr); }
// operators
bool operator ==(const CUser &) const;
@ -49,5 +49,5 @@ protected:
CCallsign m_Rpt1;
CCallsign m_Rpt2;
CCallsign m_Xlx;
std::time_t m_LastHeardTime;
time_t m_LastHeardTime;
};

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "Users.h"
#include "Reflector.h"
@ -40,7 +40,7 @@ void CUsers::AddUser(const CUser &user)
}
// notify
g_Reflector.OnUsersChanged();
g_Refl..OnUsersChanged();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -48,7 +48,7 @@ void CUsers::AddUser(const CUser &user)
void CUsers::Hearing(const CCallsign &my, const CCallsign &rpt1, const CCallsign &rpt2)
{
Hearing(my, rpt1, rpt2, g_Reflector.GetCallsign());
Hearing(my, rpt1, rpt2, g_Refl..GetCallsign());
}
void CUsers::Hearing(const CCallsign &my, const CCallsign &rpt1, const CCallsign &rpt2, const CCallsign &xlx)

@ -18,6 +18,9 @@
#pragma once
#include <list>
#include <mutex>
#include "User.h"
class CUsers

@ -1,73 +1,89 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
// Copyright © 2023 Thomas A. Early N7TAE.
//
// ----------------------------------------------------------------------------
// This file is part of m17ref.
//
// 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 3 of the License, or
// (at your option) any later version.
// m17ref 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 3 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.
// m17ref 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, see <https://www.gnu.org/licenses/>.
// You should have received a copy of the GNU General Public License
// with this software. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include "Main.h"
#include "Version.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CVersion::CVersion() : version(0) {}
CVersion::CVersion(uint8_t maj, uint8_t min, uint8_t rev)
{
Set(maj, min, rev);
}
int CVersion::GetMajor(void) const
{
return version / 0x10000;
}
int CVersion::GetMinor(void) const
{
return version / 0x100 % 0x100;
}
int CVersion::GetRevision(void) const
{
return version % 0x100;
}
CVersion::CVersion()
int CVersion::GetVersion(void) const
{
m_iMajor = 0;
m_iMinor = 0;
m_iRevision = 0;
return version;
}
CVersion::CVersion(int iMajor, int iMinor, int iRevision)
void CVersion::Set(uint8_t maj, uint8_t min, uint8_t rev)
{
m_iMajor = iMajor;
m_iMinor = iMinor;
m_iRevision = iRevision;
version = 0x10000*maj + 0x100*min + rev;
}
////////////////////////////////////////////////////////////////////////////////////////
// comparaison
bool CVersion::operator ==(const CVersion &v) const
{
return v.version == version;
};
bool CVersion::operator !=(const CVersion &v) const
{
return v.version != version;
};
bool CVersion::operator >=(const CVersion &v) const
{
return v.version >= version;
}
bool CVersion::IsEqualOrHigherTo(const CVersion &version) const
bool CVersion::operator <=(const CVersion &v) const
{
if ( m_iMajor > version.m_iMajor )
{
return true;
}
else if ( m_iMajor == version.m_iMajor )
{
if ( m_iMinor > version.m_iMinor )
{
return true;
}
else if ( m_iMinor == version.m_iMinor )
{
if ( m_iRevision >= version.m_iRevision )
{
return true;
}
}
}
return false;
return v.version <= version;
}
////////////////////////////////////////////////////////////////////////////////////////
// operator
bool CVersion::operator >(const CVersion &v) const
{
return v.version > version;
}
bool CVersion::operator ==(const CVersion &Version) const
bool CVersion::operator <(const CVersion &v) const
{
return ( (Version.m_iMajor == m_iMajor) &&
(Version.m_iMinor == m_iMinor) &&
(Version.m_iRevision == m_iRevision )) ;
return v.version < version;
}
// output
std::ostream &operator <<(std::ostream &os, const CVersion &v)
{
os << v.GetMajor() << '.' << v.GetMinor() << '.' << v.GetRevision();
return os;
};

@ -1,44 +1,56 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
// Copyright © 2023 Thomas A. Early N7TAE.
//
// ----------------------------------------------------------------------------
// This file is part of m17ref.
//
// 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 3 of the License, or
// (at your option) any later version.
// m17ref 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 3 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.
// m17ref 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, see <https://www.gnu.org/licenses/>.
// You should have received a copy of the GNU General Public License
// with this software. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#pragma once
#include <cstdint>
#include <iostream>
class CVersion
{
public:
// constructor
// constructors
CVersion();
CVersion(int, int, int);
CVersion(uint8_t maj, uint8_t min, uint8_t rev);
// get
int GetMajor(void) const { return m_iMajor; }
int GetMinor(void) const { return m_iMinor; }
int GetRevision(void) const { return m_iRevision; }
int GetMajor(void) const;
int GetMinor(void) const;
int GetRevision(void) const;
int GetVersion(void) const;
// set
void Set(uint8_t, uint8_t, uint8_t);
// comparaison operators
bool operator ==(const CVersion &v) const;
bool operator !=(const CVersion &v) const;
bool operator >=(const CVersion &v) const;
bool operator <=(const CVersion &v) const;
bool operator >(const CVersion &v) const;
bool operator <(const CVersion &v) const;
// comparaison
bool IsEqualOrHigherTo(const CVersion &) const;
// output
friend std::ostream &operator <<(std::ostream &os, const CVersion &v);
// operator
bool operator ==(const CVersion &) const;
protected:
// data
int m_iMajor;
int m_iMinor;
int m_iRevision;
int version;
};

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "WiresXCmd.h"

@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h"
#include "CRC.h"
#include "YSFFich.h"
#include "YSFPayload.h"
@ -61,8 +61,8 @@ CWiresxCmdHandler::~CWiresxCmdHandler()
bool CWiresxCmdHandler::Init(void)
{
// fill our wiresx info
m_ReflectorWiresxInfo.SetCallsign(g_Reflector.GetCallsign());
m_ReflectorWiresxInfo.SetNode(g_Reflector.GetCallsign());
m_ReflectorWiresxInfo.SetCallsign(g_Refl..GetCallsign());
m_ReflectorWiresxInfo.SetNode(g_Refl..GetCallsign());
m_ReflectorWiresxInfo.SetName("Reflector");
// reset stop flag
@ -144,18 +144,18 @@ void CWiresxCmdHandler::Task(void)
const char *modules = ACTIVE_MODULES;
// fill our info object
Info = m_ReflectorWiresxInfo;
g_YsfNodeDir.FindFrequencies(Cmd.GetCallsign(), &uiNodeTxFreq, &uiNodeRxFreq);
g_LYtr.FindFrequencies(Cmd.GetCallsign(), &uiNodeTxFreq, &uiNodeRxFreq);
Info.SetFrequencies(uiNodeTxFreq, uiNodeRxFreq);
// find our client and the module it's currentlink linked to
cModule = ' ';
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Cmd.GetCallsign(), Cmd.GetIp(), EProtocol::ysf);
if ( client )
{
cModule = client->GetReflectorModule();
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// and crack the cmd
switch ( Cmd.GetCmd() )
@ -179,13 +179,13 @@ void CWiresxCmdHandler::Task(void)
// acknowledge
ReplyToWiresxConnReqPacket(Cmd.GetIp(), Info, cModule);
// change client's module
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Cmd.GetCallsign(), Cmd.GetIp(), EProtocol::ysf);
if ( client )
{
client->SetReflectorModule(cModule);
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else
{
@ -198,13 +198,13 @@ void CWiresxCmdHandler::Task(void)
ReplyToWiresxDiscReqPacket(Cmd.GetIp(), Info);
// change client's module
{
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Cmd.GetCallsign(), Cmd.GetIp(), EProtocol::ysf);
if ( client != nullptr )
{
client->SetReflectorModule(' ');
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
break;
case WIRESX_CMD_UNKNOWN:
@ -741,8 +741,8 @@ bool CWiresxCmdHandler::DebugTestDecodePacket(const CBuffer &Buffer)
std::cout << "Trailer" << std::endl;
std::cout << "length of payload : " << len << std::endl;
dump.Set(command, len);
dump.DebugDump(g_Reflector.m_DebugFile);
dump.DebugDumpAscii(g_Reflector.m_DebugFile);
dump.DebugDump(g_Refl..m_DebugFile);
dump.DebugDumpAscii(g_Refl..m_DebugFile);
break;
case YSF_FI_COMMUNICATIONS:
if ( Fich.getDT() == YSF_DT_DATA_FR_MODE )

@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h"
#include "Callsign.h"
#include "WiresXInfo.h"

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "YSFClient.h"

@ -17,7 +17,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h"
#include "YSFNode.h"

@ -18,7 +18,7 @@
#pragma once
#include "Main.h"
class CYsfNode
{

@ -1,176 +0,0 @@
// Copyright © 2019 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include <mysql/mysql.h>
#include "Main.h"
#include "Reflector.h"
#include "YSFNodeDir.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor & destructor
CYsfNodeDir::CYsfNodeDir()
{
keep_running = true;
}
CYsfNodeDir::~CYsfNodeDir()
{
// kill threads
Close();
}
////////////////////////////////////////////////////////////////////////////////////////
// init & close
bool CYsfNodeDir::Init(void)
{
// load content
Reload();
// reset run flag
keep_running = true;
// start thread;
m_Future = std::async(std::launch::async, &CYsfNodeDir::Thread, this);
return true;
}
void CYsfNodeDir::Close(void)
{
keep_running = false;
if ( m_Future.valid() )
{
m_Future.get();
}
}
////////////////////////////////////////////////////////////////////////////////////////
// thread
void CYsfNodeDir::Thread()
{
while (keep_running)
{
// Wait YSFNODEDB_REFRESH_RATE minutes
for (int i=0; keep_running && (i < 30*YSFNODEDB_REFRESH_RATE); i++)
{
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
#if YSF_DB_SUPPORT==true
if (keep_running && (0 == i % 450))
{
ReadDb(); // update from the db every 15 minutes
}
#endif
}
// have lists files changed ?
if (keep_running && NeedReload())
{
Reload();
}
}
}
////////////////////////////////////////////////////////////////////////////////////////
// Reload
bool CYsfNodeDir::Reload(void)
{
CBuffer buffer;
bool ok = false;
if ( LoadContent(&buffer) )
{
Lock();
ok = RefreshContent(buffer);
Unlock();
}
return ok;
}
////////////////////////////////////////////////////////////////////////////////////////
// find
bool CYsfNodeDir::FindFrequencies(const CCallsign &callsign, uint32_t *txfreq, uint32_t *rxfreq)
{
auto found = find(callsign);
if ( found != end() )
{
*txfreq = found->second.GetTxFrequency();
*rxfreq = found->second.GetRxFrequency();
return true;
}
else
{
*txfreq = YSF_DEFAULT_NODE_TX_FREQ;
*rxfreq = YSF_DEFAULT_NODE_RX_FREQ;
return false;
}
}
#if YSF_DB_SUPPORT==true
void CYsfNodeDir::ReadDb()
{
MYSQL *con = mysql_init(NULL);
if (con)
{
if (mysql_real_connect(con, "localhost", YSF_DB_USER, YSF_DB_PASSWORD, YSF_DB_NAME, 0, NULL, 0))
{
if (0 == mysql_query(con, "SELECT callsign,txfreq,rxfreq FROM ysfnodes"))
{
MYSQL_RES *result = mysql_store_result(con);
if (result)
{
std::cout << "Adding " << mysql_num_rows(result) << " registered YSF stations from database " << YSF_DB_NAME << std::endl;
MYSQL_ROW row;
while ((row = mysql_fetch_row(result)))
{
CCallsign cs(row[0]);
CYsfNode node(atoi(row[1]), atoi(row[2]));
m_map[cs] = node;
}
mysql_free_result(result);
}
else
{
std::cerr << "Could not fetch MySQL rows" << std::endl;
}
}
else
{
std::cerr << "MySQL query failed: " << mysql_error(con) << std::endl;
}
}
else
{
std::cerr << "Could not connect to database " << YSF_DB_NAME << ": " << mysql_error(con) << std::endl;
}
mysql_close(con);
}
else
{
std::cerr << "Could not init mysql." << std::endl;;
}
}
#endif

@ -1,94 +0,0 @@
// Copyright © 2019 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#pragma once
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "Buffer.h"
#include "Callsign.h"
#include "YSFNode.h"
////////////////////////////////////////////////////////////////////////////////////////
// compare function for std::map::find
struct CYsfNodeDirCallsignCompare
{
bool operator() (const CCallsign &cs1, const CCallsign &cs2) const
{ return cs1.HasLowerCallsign(cs2);}
};
////////////////////////////////////////////////////////////////////////////////////////
// class
using CsNodeMap = std::map<CCallsign, CYsfNode, CYsfNodeDirCallsignCompare>;
class CYsfNodeDir
{
public:
// constructor
CYsfNodeDir();
// destructor
virtual ~CYsfNodeDir();
// init & close
virtual bool Init(void);
virtual void Close(void);
// locks
void Lock(void) { m_Mutex.lock(); }
void Unlock(void) { m_Mutex.unlock(); }
// refresh
virtual bool LoadContent(CBuffer *) { return false; }
virtual bool RefreshContent(const CBuffer &) { return false; }
// find
bool FindFrequencies(const CCallsign &, uint32_t *, uint32_t *);
// pass-thru
void clear() { m_map.clear(); }
size_t size() { return m_map.size(); }
CsNodeMap::iterator find(const CCallsign &cs) { return m_map.find(cs); }
CsNodeMap::iterator end() { return m_map.end(); }
std::pair<CsNodeMap::iterator, bool> insert(const std::pair<CCallsign, CYsfNode> &pair) { return m_map.insert(pair); }
protected:
// thread
void Thread();
// reload helpers
bool Reload(void);
virtual bool NeedReload(void) { return false; }
#if YSF_DB_SUPPORT==true
void ReadDb(void);
#endif
//bool IsValidDmrid(const char *);
protected:
// Lock()
std::mutex m_Mutex;
// thread
std::atomic<bool> keep_running;
std::future<void> m_Future;
CsNodeMap m_map;
};

@ -1,161 +0,0 @@
// Copyright © 2019 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "Main.h"
#include "YSFNodeDirFile.h"
#if (YSFNODEDB_USE_RLX_SERVER == 0)
CYsfNodeDirFile g_YsfNodeDir;
#endif
////////////////////////////////////////////////////////////////////////////////////////
// constructor & destructor
CYsfNodeDirFile::CYsfNodeDirFile()
{
memset(&m_LastModTime, 0, sizeof(time_t));
}
////////////////////////////////////////////////////////////////////////////////////////
// init & close
bool CYsfNodeDirFile::Init(void)
{
return CYsfNodeDir::Init();
}
////////////////////////////////////////////////////////////////////////////////////////
// refresh
bool CYsfNodeDirFile::NeedReload(void)
{
bool needReload = false;
time_t time;
if ( GetLastModTime(&time) )
{
needReload = time != m_LastModTime;
}
return needReload;
}
bool CYsfNodeDirFile::LoadContent(CBuffer *buffer)
{
bool ok = false;
std::ifstream file;
std::streampos size;
// open file
file.open(YSFNODEDB_PATH, std::ios::in | std::ios::binary | std::ios::ate);
if ( file.is_open() )
{
// read file
size = file.tellg();
if ( size > 0 )
{
// read file into buffer
buffer->resize((int)size+1);
file.seekg (0, std::ios::beg);
file.read((char *)buffer->data(), (int)size);
// close file
file.close();
// update time
GetLastModTime(&m_LastModTime);
// done
ok = true;
}
}
// done
return ok;
}
bool CYsfNodeDirFile::RefreshContent(const CBuffer &buffer)
{
bool ok = false;
// clear directory
clear();
// scan buffer
if ( buffer.size() > 0 )
{
// crack it
char *ptr1 = (char *)buffer.data();
char *ptr2;
// get next line
while ( (ptr2 = ::strchr(ptr1, '\n')) != nullptr )
{
*ptr2 = 0;
// get items
char *callsign;
char *txfreq;
char *rxfreq;
if ( ((callsign = ::strtok(ptr1, ";")) != nullptr) )
{
if ( ((txfreq = ::strtok(nullptr, ";")) != nullptr) )
{
if ( ((rxfreq = ::strtok(nullptr, ";")) != nullptr) )
{
// new entry
CCallsign cs(callsign);
CYsfNode node(atoi(txfreq), atoi(rxfreq));
if ( cs.IsValid() && node.IsValid() )
{
insert(std::pair<CCallsign, CYsfNode>(cs, node));
}
}
}
}
// next line
ptr1 = ptr2+1;
}
// done
ok = true;
}
// report
std::cout << "Read " << size() << " YSF nodes from file " << YSFNODEDB_PATH << std::endl;
// done
return ok;
}
bool CYsfNodeDirFile::GetLastModTime(time_t *time)
{
bool ok = false;
struct stat fileStat;
if( ::stat(YSFNODEDB_PATH, &fileStat) != -1 )
{
*time = fileStat.st_mtime;
ok = true;
}
return ok;
}

@ -1,47 +0,0 @@
// Copyright © 2019 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#pragma once
#include "YSFNodeDir.h"
class CYsfNodeDirFile : public CYsfNodeDir
{
public:
// constructor
CYsfNodeDirFile();
// destructor
~CYsfNodeDirFile() {}
// init & close
bool Init(void);
// refresh
bool LoadContent(CBuffer *);
bool RefreshContent(const CBuffer &);
protected:
// reload helpers
bool NeedReload(void);
bool GetLastModTime(time_t *);
protected:
// data
time_t m_LastModTime;
};

@ -1,179 +0,0 @@
// Copyright © 2019 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#include <string.h>
#include "Main.h"
#include "Reflector.h"
#include "YSFNodeDirHttp.h"
#if (YSFNODEDB_USE_RLX_SERVER == 1)
CYsfNodeDirHttp g_YsfNodeDir;
#endif
////////////////////////////////////////////////////////////////////////////////////////
// refresh
bool CYsfNodeDirHttp::LoadContent(CBuffer *buffer)
{
// get file from xlxapi server
return HttpGet("xlxapi.rlx.lu", "api/exportysfrepeaters.php", 80, buffer);
}
bool CYsfNodeDirHttp::RefreshContent(const CBuffer &buffer)
{
bool ok = false;
// clear directory
clear();
// scan buffer
if ( buffer.size() > 0 )
{
// crack it
char *ptr1 = (char *)buffer.data();
char *ptr2;
// get next line
while ( (ptr2 = ::strchr(ptr1, '\n')) != nullptr )
{
*ptr2 = 0;
// get items
char *callsign;
char *txfreq;
char *rxfreq;
if ( ((callsign = ::strtok(ptr1, ";")) != nullptr) )
{
if ( ((txfreq = ::strtok(nullptr, ";")) != nullptr) )
{
if ( ((rxfreq = ::strtok(nullptr, ";")) != nullptr) )
{
// new entry
CCallsign cs(callsign);
CYsfNode node(atoi(txfreq), atoi(rxfreq));
if ( cs.IsValid() && node.IsValid() )
{
insert(std::pair<CCallsign, CYsfNode>(cs, node));
}
}
}
}
// next line
ptr1 = ptr2+1;
}
// done
ok = true;
}
// report
std::cout << "Read " << size() << " YSF nodes from xlxapi.rlx.lu database " << std::endl;
// done
return ok;
}
////////////////////////////////////////////////////////////////////////////////////////
// httpd helpers
#define YSFNODE_HTTPGET_SIZEMAX (256)
bool CYsfNodeDirHttp::HttpGet(const char *hostname, const char *filename, int port, CBuffer *buffer)
{
bool ok = false;
int sock_id;
// open socket
if ( (sock_id = ::socket(AF_INET, SOCK_STREAM, 0)) >= 0 )
{
// get hostname address
struct sockaddr_in servaddr;
struct hostent *hp;
memset(&servaddr,0,sizeof(servaddr));
if( (hp = gethostbyname(hostname)) != nullptr )
{
// dns resolved
memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
servaddr.sin_port = htons(port);
servaddr.sin_family = AF_INET;
// connect
if ( ::connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0)
{
// send the GET request
char request[YSFNODE_HTTPGET_SIZEMAX];
::sprintf(request, "GET /%s HTTP/1.0\r\nFrom: %s\r\nUser-Agent: urfd\r\n\r\n",
filename, (const char *)g_Reflector.GetCallsign());
::write(sock_id, request, strlen(request));
// config receive timeouts
fd_set read_set;
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
FD_ZERO(&read_set);
FD_SET(sock_id, &read_set);
// get the reply back
buffer->clear();
bool done = false;
do
{
char buf[1440];
ssize_t len = 0;
select(sock_id+1, &read_set, nullptr, nullptr, &timeout);
//if ( (ret > 0) || ((ret < 0) && (errno == EINPROGRESS)) )
//if ( ret >= 0 )
//{
usleep(5000);
len = read(sock_id, buf, 1440);
if ( len > 0 )
{
buffer->Append((uint8_t *)buf, (int)len);
ok = true;
}
//}
done = (len <= 0);
}
while (!done);
buffer->Append((uint8_t)0);
// and disconnect
close(sock_id);
}
else
{
std::cout << "Cannot establish connection with host " << hostname << std::endl;
}
}
else
{
std::cout << "Host " << hostname << " not found" << std::endl;
}
}
else
{
std::cout << "Failed to open wget socket" << std::endl;
}
// done
return ok;
}

@ -1,40 +0,0 @@
// Copyright © 2019 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector
// Copyright © 2021 Thomas A. Early N7TAE
//
// 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 3 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, see <https://www.gnu.org/licenses/>.
#pragma once
#include "YSFNodeDir.h"
class CYsfNodeDirHttp : public CYsfNodeDir
{
public:
// constructor
CYsfNodeDirHttp() {}
// destructor
~CYsfNodeDirHttp() {}
// refresh
bool LoadContent(CBuffer *);
bool RefreshContent(const CBuffer &);
protected:
// reload helpers
bool NeedReload(void) { return true; }
bool HttpGet(const char *, const char *, int, CBuffer *);
};

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "CRC.h"
#include "YSFPayload.h"
@ -119,7 +119,7 @@ void CYsfProtocol::Task(void)
else if ( IsValidDvHeaderPacket(Ip, Fich, Buffer, Header, Frames) )
{
// node linked and callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::ysf, Header->GetRpt2Module()) )
if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::ysf, Header->GetRpt2Module()) )
{
// handle it
OnDvHeaderPacketIn(Header, Ip);
@ -138,14 +138,14 @@ void CYsfProtocol::Task(void)
//std::cout << "YSF keepalive/connect packet from " << Callsign << " at " << Ip << std::endl;
// callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::ysf) )
if ( g_Gate.MayLink(Callsign, Ip, EProtocol::ysf) )
{
// acknowledge the request
EncodeConnectAckPacket(&Buffer);
Send(Buffer, Ip);
// add client if needed
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Callsign, Ip, EProtocol::ysf);
// client already connected ?
if ( client == nullptr )
@ -168,7 +168,7 @@ void CYsfProtocol::Task(void)
client->Alive();
}
// and done
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
else if ( IsValidDisconnectPacket(Buffer) )
@ -176,7 +176,7 @@ void CYsfProtocol::Task(void)
std::cout << "YSF disconnect packet from " << Ip << std::endl;
// find client
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::ysf);
if ( client != nullptr )
{
@ -186,7 +186,7 @@ void CYsfProtocol::Task(void)
//EncodeDisconnectPacket(&Buffer);
//Send(Buffer, Ip);
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
else if ( IsValidwirexPacket(Buffer, &Fich, &Callsign, &iWiresxCmd, &iWiresxArg) )
{
@ -263,7 +263,7 @@ void CYsfProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
CCallsign rpt2(Header->GetRpt2Callsign());
// find this client
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, EProtocol::ysf);
std::shared_ptr<CClient>client = g_Refl..GetClients()->FindClient(Ip, EProtocol::ysf);
if ( client )
{
// get client callsign
@ -274,20 +274,20 @@ void CYsfProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
rpt2.SetCSModule(m);
// and try to open the stream
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr )
{
// keep the handle
m_Streams[stream->GetStreamId()] = stream;
}
}
// release
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
// update last heard
if ( g_Reflector.IsValidModule(rpt2.GetCSModule()) )
if ( g_Refl..IsValidModule(rpt2.GetCSModule()) )
{
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers();
g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Refl..ReleaseUsers();
}
}
}
@ -346,7 +346,7 @@ void CYsfProtocol::HandleQueue(void)
if ( buffer.size() > 0 )
{
// and push it to all our clients linked to the module and who are not streaming in
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::ysf, it)) != nullptr )
@ -359,7 +359,7 @@ void CYsfProtocol::HandleQueue(void)
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
}
m_Queue.Unlock();
@ -375,7 +375,7 @@ void CYsfProtocol::HandleKeepalives(void)
// and disconnect them if not
// iterate on clients
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::ysf, it)) != nullptr )
@ -395,7 +395,7 @@ void CYsfProtocol::HandleKeepalives(void)
}
}
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
}
////////////////////////////////////////////////////////////////////////////////////////
@ -506,7 +506,7 @@ bool CYsfProtocol::IsValidDvFramePacket(const CIp &Ip, const CYSFFICH &Fich, con
{
// get stream id
//uint32_t uiStreamId = IpToStreamId(Ip);
auto stream = GetStream(m_uiStreamId, &Ip);
if ( !stream )
{
@ -531,10 +531,10 @@ bool CYsfProtocol::IsValidDvFramePacket(const CIp &Ip, const CYSFFICH &Fich, con
CCallsign rpt2 = m_ReflectorCallsign;
rpt2.SetCSModule(' ');
header = std::unique_ptr<CDvHeaderPacket>(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, Fich.getFN()));
if ( g_GateKeeper.MayTransmit(header->GetMyCallsign(), Ip, EProtocol::ysf, header->GetRpt2Module()) )
if ( g_Gate.MayTransmit(header->GetMyCallsign(), Ip, EProtocol::ysf, header->GetRpt2Module()) )
{
OnDvHeaderPacketIn(header, Ip);
OnDvHeaderPacketIn(header, Ip);
}
}
@ -998,7 +998,7 @@ bool CYsfProtocol::EncodeServerStatusPacket(CBuffer *Buffer) const
const std::string cs = YSF_REFLECTOR_NAME;
memcpy(callsign, cs.c_str(), cs.size() > 16 ? 16 : cs.size());
#else
g_Reflector.GetCallsign().GetCallsign(callsign);
g_Refl..GetCallsign().GetCallsign(callsign);
#endif
char sz[16];
::sprintf(sz, "%05u", CalcHash(callsign, 16) % 100000U);
@ -1010,9 +1010,9 @@ bool CYsfProtocol::EncodeServerStatusPacket(CBuffer *Buffer) const
memcpy(description, desc.c_str(), desc.size() > 14 ? 14 : desc.size());
Buffer->Append(description, 14);
// connected clients
CClients *clients = g_Reflector.GetClients();
CClients *clients = g_Refl..GetClients();
int count = MIN(999, clients->GetSize());
g_Reflector.ReleaseClients();
g_Refl..ReleaseClients();
::sprintf(sz, "%03u", count);
Buffer->Append((uint8_t *)sz, 3);
@ -1090,8 +1090,8 @@ bool CYsfProtocol::DebugTestDecodePacket(const CBuffer &Buffer)
std::cout << "Trailer" << std::endl;
std::cout << "length of payload : " << len << std::endl;
dump.Set(command, len);
dump.DebugDump(g_Reflector.m_DebugFile);
dump.DebugDumpAscii(g_Reflector.m_DebugFile);
dump.DebugDump(g_Refl..m_DebugFile);
dump.DebugDumpAscii(g_Refl..m_DebugFile);
break;
case YSF_FI_COMMUNICATIONS:
if ( Fich.getDT() == YSF_DT_DATA_FR_MODE )

@ -19,7 +19,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h>
#include "YSFDefines.h"
#include "YSFUtils.h"

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save

Powered by TurnKey Linux.