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 configure.sql
reflector.cfg reflector.cfg
wiresx/configure.php wiresx/configure.php
urfd urfd*
inicheck

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

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

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

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

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

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

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

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

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

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

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

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

@ -18,6 +18,9 @@
#pragma once #pragma once
#include <atomic>
#include <future>
#include "UnixDgramSocket.h" #include "UnixDgramSocket.h"
#include "PacketQueue.h" #include "PacketQueue.h"
@ -30,7 +33,11 @@ class CCodecStream : public CPacketQueue
{ {
public: public:
// constructor // 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 // destructor
virtual ~CCodecStream(); virtual ~CCodecStream();
@ -44,7 +51,6 @@ public:
protected: protected:
// initialization // initialization
void InitCodecStream(void);
// data // data
uint16_t m_uiStreamId; uint16_t m_uiStreamId;
uint16_t m_uiPort; uint16_t m_uiPort;
@ -52,7 +58,7 @@ protected:
ECodecType m_eCodecIn; ECodecType m_eCodecIn;
// sockets // sockets
std::shared_ptr<CUnixDgramReader> m_TCReader; CUnixDgramReader m_TCReader;
CUnixDgramWriter m_TCWriter; CUnixDgramWriter m_TCWriter;
// associated packet stream // 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 // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "DCSClient.h" #include "DCSClient.h"

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

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

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

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

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

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

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

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

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

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

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

@ -1,7 +1,5 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector // 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 // This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
@ -16,25 +14,18 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#pragma once #include "Reflector.h"
#include "GateKeeper.h"
#include "DMRIdDir.h" #include "Configure.h"
#include "Version.h"
class CDmridDirHttp : public CDmridDir #include "LookupDmr.h"
{ #include "LookupNxdn.h"
public: #include "LookupYsf.h"
// constructor
CDmridDirHttp() {}
// destructor
~CDmridDirHttp() {}
// refresh
bool LoadContent(CBuffer *);
bool RefreshContent(const CBuffer &);
protected: extern CReflector g_Refl;
// reload helpers extern CGateKeeper g_Gate;
bool NeedReload(void) { return true; } extern CConfigure g_Conf;
bool HttpGet(const char *, const char *, int, CBuffer *); 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. // Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector // 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 // This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
@ -18,68 +18,60 @@
#pragma once #pragma once
#include <sys/types.h> #include <map>
#include <sys/socket.h> #include <atomic>
#include <netinet/in.h> #include <future>
#include <netdb.h>
#include "Buffer.h" #include "Buffer.h"
#include "Callsign.h" #include "Callsign.h"
#include "Configure.h"
// compare function for std::map::find // compare function for std::map::find
struct CDmridDirCallsignCompare struct CCallsignCompare
{ {
bool operator() (const CCallsign &cs1, const CCallsign &cs2) const bool operator() (const CCallsign &cs1, const CCallsign &cs2) const
{ return cs1.HasLowerCallsign(cs2);} {
return cs1.HasLowerCallsign(cs2);
}
}; };
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
class CDmridDir class CLookup
{ {
public: public:
// constructor // constructor
CDmridDir(); CLookup() : keep_running(true), m_LastModTime(0) {}
// destructor // destructor
~CDmridDir(); virtual ~CLookup();
// init & close void LookupInit();
virtual bool Init(void); void LookupClose();
virtual void Close(void);
// locks // locks
void Lock(void) { m_Mutex.lock(); } void Lock(void) { m_Mutex.lock(); }
void Unlock(void) { m_Mutex.unlock(); } 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 &);
protected: protected:
// thread std::time_t GetLastModTime();
virtual void LoadParameters() = 0;
virtual void ClearContents() = 0;
void Thread(); void Thread();
// reload helpers // refresh
bool Reload(void); virtual bool LoadContentFile(CBuffer &buf) = 0;
virtual bool NeedReload(void) { return false; } virtual bool LoadContentHttp(CBuffer &buf) = 0;
bool IsValidDmrid(const char *); virtual void RefreshContentFile(const CBuffer &) = 0;
virtual void RefreshContentHttp(const CBuffer &) = 0;
protected:
// data
std::map <uint32_t, CCallsign> m_CallsignMap;
std::map <CCallsign, uint32_t, CDmridDirCallsignCompare> m_DmridMap;
// Lock()
std::mutex m_Mutex; 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::atomic<bool> keep_running;
std::future<void> m_Future; 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. // Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector // 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 // This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
@ -18,23 +18,26 @@
#pragma once #pragma once
#include "NXDNIdDir.h" #include "Lookup.h"
class CNXDNidDirHttp : public CNXDNidDir class CLookupDmr : public CLookup
{ {
public: public:
// constructor uint32_t FindDmrid(const CCallsign &cs);
CNXDNidDirHttp() {} const CCallsign *FindCallsign(uint32_t dmrid);
// destructor protected:
~CNXDNidDirHttp() {} void ClearContents();
void LoadParameters();
bool LoadContentFile(CBuffer &buf);
bool LoadContentHttp(CBuffer &buf);
void RefreshContentFile(const CBuffer &);
void RefreshContentHttp(const CBuffer &);
// refresh private:
bool LoadContent(CBuffer *); std::map <uint32_t, CCallsign> m_CallsignMap;
bool RefreshContent(const CBuffer &); std::map <CCallsign, uint32_t, CCallsignCompare> m_DmridMap;
protected: bool IsValidDmrId(const char *);
// reload helpers bool HttpGet(const char *, const char *, int, CBuffer &);
bool NeedReload(void) { return true; }
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. // Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector // 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 // This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
@ -18,30 +18,25 @@
#pragma once #pragma once
#include "DMRIdDir.h" #include "Lookup.h"
class CDmridDirFile : public CDmridDir class CLookupNxdn : public CLookup
{ {
public: public:
// constructor uint16_t FindNXDNid(const CCallsign &callsign);
CDmridDirFile(); const CCallsign *FindCallsign(uint16_t id);
// 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 *);
protected: protected:
// data void ClearContents();
time_t m_LastModTime; 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. // Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
// urfd -- The universal reflector // 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 // This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
@ -18,30 +18,26 @@
#pragma once #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: public:
// constructor bool FindFrequencies(const CCallsign &, uint32_t *, uint32_t *);
CNXDNidDirFile();
// destructor
~CNXDNidDirFile() {}
// init & close
bool Init(void);
// refresh
bool LoadContent(CBuffer *);
bool RefreshContent(const CBuffer &);
protected: protected:
// reload helpers void ClearContents();
bool NeedReload(void); void LoadParameters();
bool GetLastModTime(time_t *); bool LoadContentFile(CBuffer &buf);
bool LoadContentHttp(CBuffer &buf);
void RefreshContentFile(const CBuffer &);
void RefreshContentHttp(const CBuffer &);
protected: private:
// data CsNodeMap m_map;
time_t m_LastModTime;
bool HttpGet(const char *, const char *, int, CBuffer &);
}; };

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

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h> #include <string.h>
#include "M17Client.h" #include "M17Client.h"
#include "M17Protocol.h" #include "M17Protocol.h"
@ -69,7 +69,7 @@ void CM17Protocol::Task(void)
if ( IsValidDvPacket(Buffer, Header, Frame) ) if ( IsValidDvPacket(Buffer, Header, Frame) )
{ {
// callsign muted? // 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); 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; std::cout << "M17 connect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
// callsign authorized? // 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 ? // valid module ?
if ( g_Reflector.IsValidModule(ToLinkModule) ) if ( g_Refl..IsValidModule(ToLinkModule) )
{ {
// acknowledge the request // acknowledge the request
Send("ACKN", Ip); Send("ACKN", Ip);
// create the client and append // create the client and append
g_Reflector.GetClients()->AddClient(std::make_shared<CM17Client>(Callsign, Ip, ToLinkModule)); g_Refl..GetClients()->AddClient(std::make_shared<CM17Client>(Callsign, Ip, ToLinkModule));
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
} }
else else
{ {
@ -125,7 +125,7 @@ void CM17Protocol::Task(void)
std::cout << "M17 disconnect packet from " << Callsign << " at " << Ip << std::endl; std::cout << "M17 disconnect packet from " << Callsign << " at " << Ip << std::endl;
// find client // find client
CClients *clients = g_Reflector.GetClients(); CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::m17); std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::m17);
if ( client != nullptr ) if ( client != nullptr )
{ {
@ -134,19 +134,19 @@ void CM17Protocol::Task(void)
// and acknowledge the disconnect // and acknowledge the disconnect
Send("DISC", Ip); Send("DISC", Ip);
} }
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
} }
else if ( IsValidKeepAlivePacket(Buffer, Callsign) ) else if ( IsValidKeepAlivePacket(Buffer, Callsign) )
{ {
// find all clients with that callsign & ip and keep them alive // 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(); auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr; std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(Callsign, Ip, EProtocol::m17, it)) != nullptr ) while ( (client = clients->FindNextClient(Callsign, Ip, EProtocol::m17, it)) != nullptr )
{ {
client->Alive(); client->Alive();
} }
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
} }
else else
{ {
@ -196,24 +196,24 @@ void CM17Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
CCallsign rpt2(Header->GetRpt2Callsign()); CCallsign rpt2(Header->GetRpt2Callsign());
// find this client // 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 ) if ( client )
{ {
// get client callsign // get client callsign
rpt1 = client->GetCallsign(); rpt1 = client->GetCallsign();
// and try to open the stream // 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 // keep the handle
m_Streams[stream->GetStreamId()] = stream; m_Streams[stream->GetStreamId()] = stream;
} }
} }
// release // release
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
// update last heard // update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers(); 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); 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 // 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(); auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr; std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::m17, it)) != 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++; m_StreamsCache[module].m_iSeqCounter++;
} }
@ -286,7 +286,7 @@ void CM17Protocol::HandleKeepalives(void)
EncodeKeepAlivePacket(keepalive); EncodeKeepAlivePacket(keepalive);
// iterate on clients // iterate on clients
CClients *clients = g_Reflector.GetClients(); CClients *clients = g_Refl..GetClients();
auto it = clients->begin(); auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr; std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::m17, it)) != 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); Buffer.resize(10);
memcpy(Buffer.data(), "PING", 4); 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 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 // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "Reflector.h"
#include <sys/stat.h> #include <sys/stat.h>
#include "Global.h"
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// global objects // 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 (argc != 2)
if ((cs.size() != 6) || cs.compare(0, 3, "URF"))
{ {
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; return EXIT_FAILURE;
} }
if (g_Conf.ReadData(argv[1]))
return EXIT_FAILURE;
// remove pidfile // 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 // splash
std::cout << "Starting " << cs << " " << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_REVISION << std::endl << std::endl; std::cout << "Starting " << callsign << " " << g_Vers << std::endl;
#ifdef TRANSCODER_IS_REMOTE
g_Reflector.SetTranscoderIp(TRANSCODER_IP, INET6_ADDRSTRLEN);
#endif
// and let it run // and let it run
if ( !g_Reflector.Start() ) if (g_Refl.Start())
{ {
std::cout << "Error starting reflector" << std::endl; std::cout << "Error starting reflector" << std::endl;
return EXIT_FAILURE; 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 // write new pid file
std::ofstream ofs(PIDFILE_PATH, std::ofstream::out); std::ofstream ofs(pidpath, std::ofstream::out);
ofs << getpid() << std::endl; ofs << getpid() << std::endl;
ofs.close(); ofs.close();
pause(); // wait for any signal pause(); // wait for any signal
g_Reflector.Stop(); g_Refl.Stop();
std::cout << "Reflector stopped" << std::endl; std::cout << "Reflector stopped" << std::endl;
// done // 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 // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "NXDNClient.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 // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h> #include <string.h>
#include "NXDNClient.h" #include "NXDNClient.h"
#include "NXDNProtocol.h" #include "NXDNProtocol.h"
@ -103,7 +103,7 @@ void CNXDNProtocol::Task(void)
else if ( IsValidDvHeaderPacket(Ip, Buffer, Header) ) else if ( IsValidDvHeaderPacket(Ip, Buffer, Header) )
{ {
// node linked and callsign muted? // 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 // handle it
OnDvHeaderPacketIn(Header, Ip); OnDvHeaderPacketIn(Header, Ip);
@ -116,10 +116,10 @@ void CNXDNProtocol::Task(void)
else if ( IsValidConnectPacket(Buffer, &Callsign) ) else if ( IsValidConnectPacket(Buffer, &Callsign) )
{ {
// callsign authorized? // callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::nxdn) ) if ( g_Gate.MayLink(Callsign, Ip, EProtocol::nxdn) )
{ {
// add client if needed // 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); std::shared_ptr<CClient>client = clients->FindClient(Callsign, Ip, EProtocol::nxdn);
// client already connected ? // client already connected ?
if ( client == nullptr ) if ( client == nullptr )
@ -145,7 +145,7 @@ void CNXDNProtocol::Task(void)
// acknowledge the request -- NXDNReflector simply echoes the packet // acknowledge the request -- NXDNReflector simply echoes the packet
Send(Buffer, Ip); Send(Buffer, Ip);
// and done // and done
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
} }
} }
else if ( IsValidDisconnectPacket(Buffer) ) else if ( IsValidDisconnectPacket(Buffer) )
@ -153,14 +153,14 @@ void CNXDNProtocol::Task(void)
std::cout << "NXDN disconnect packet from " << Ip << std::endl; std::cout << "NXDN disconnect packet from " << Ip << std::endl;
// find client // find client
CClients *clients = g_Reflector.GetClients(); CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::nxdn); std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::nxdn);
if ( client != nullptr ) if ( client != nullptr )
{ {
// remove it // remove it
clients->RemoveClient(client); clients->RemoveClient(client);
} }
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
} }
else else
{ {
@ -210,7 +210,7 @@ void CNXDNProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
CCallsign rpt2(Header->GetRpt2Callsign()); CCallsign rpt2(Header->GetRpt2Callsign());
// find this client // 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 ) if ( client )
{ {
// get client callsign // get client callsign
@ -221,20 +221,20 @@ void CNXDNProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
rpt2.SetCSModule(m); rpt2.SetCSModule(m);
// and try to open the stream // 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 // keep the handle
m_Streams[stream->GetStreamId()] = stream; m_Streams[stream->GetStreamId()] = stream;
} }
} }
// release // release
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
// update last heard // update last heard
if ( g_Reflector.IsValidModule(rpt2.GetCSModule()) ) if ( g_Refl..IsValidModule(rpt2.GetCSModule()) )
{ {
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers(); g_Refl..ReleaseUsers();
} }
} }
} }
@ -292,7 +292,7 @@ void CNXDNProtocol::HandleQueue(void)
if ( buffer.size() > 0 ) if ( buffer.size() > 0 )
{ {
// and push it to all our clients linked to the module and who are not streaming in // 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(); auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr; std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::nxdn, it)) != 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(); m_Queue.Unlock();
@ -321,7 +321,7 @@ void CNXDNProtocol::HandleKeepalives(void)
// and disconnect them if not // and disconnect them if not
// iterate on clients // iterate on clients
CClients *clients = g_Reflector.GetClients(); CClients *clients = g_Refl..GetClients();
auto it = clients->begin(); auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr; std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::nxdn, it)) != nullptr ) while ( (client = clients->FindNextClient(EProtocol::nxdn, it)) != nullptr )
@ -341,7 +341,7 @@ void CNXDNProtocol::HandleKeepalives(void)
} }
} }
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -409,7 +409,7 @@ bool CNXDNProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer, s
rpt2.SetCSModule(' '); rpt2.SetCSModule(' ');
header = std::unique_ptr<CDvHeaderPacket>(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, false)); 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);
} }
@ -838,4 +838,3 @@ void CNXDNProtocol::encode_crc6(uint8_t *d, uint8_t len)
WRITE_BIT(d, n, b); WRITE_BIT(d, n, b);
} }
} }

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

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

@ -17,7 +17,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h> #include <string.h>
#include "P25Client.h" #include "P25Client.h"
#include "P25Protocol.h" #include "P25Protocol.h"
@ -93,7 +93,7 @@ void CP25Protocol::Task(void)
if( !m_uiStreamId && IsValidDvHeaderPacket(Ip, Buffer, Header) ) if( !m_uiStreamId && IsValidDvHeaderPacket(Ip, Buffer, Header) )
{ {
// callsign muted? // callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::p25) ) if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::p25) )
{ {
OnDvHeaderPacketIn(Header, Ip); OnDvHeaderPacketIn(Header, Ip);
} }
@ -104,10 +104,10 @@ void CP25Protocol::Task(void)
else if ( IsValidConnectPacket(Buffer, &Callsign) ) else if ( IsValidConnectPacket(Buffer, &Callsign) )
{ {
// callsign authorized? // callsign authorized?
if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::p25) ) if ( g_Gate.MayLink(Callsign, Ip, EProtocol::p25) )
{ {
// add client if needed // 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); std::shared_ptr<CClient>client = clients->FindClient(Callsign, Ip, EProtocol::p25);
// client already connected ? // client already connected ?
if ( client == nullptr ) if ( client == nullptr )
@ -133,7 +133,7 @@ void CP25Protocol::Task(void)
// acknowledge the request -- P25Reflector simply echoes the packet // acknowledge the request -- P25Reflector simply echoes the packet
Send(Buffer, Ip); Send(Buffer, Ip);
// and done // and done
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
} }
} }
else if ( IsValidDisconnectPacket(Buffer, &Callsign) ) else if ( IsValidDisconnectPacket(Buffer, &Callsign) )
@ -141,14 +141,14 @@ void CP25Protocol::Task(void)
std::cout << "P25 disconnect packet from " << Callsign << " at " << Ip << std::endl; std::cout << "P25 disconnect packet from " << Callsign << " at " << Ip << std::endl;
// find client // find client
CClients *clients = g_Reflector.GetClients(); CClients *clients = g_Refl..GetClients();
std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::p25); std::shared_ptr<CClient>client = clients->FindClient(Ip, EProtocol::p25);
if ( client != nullptr ) if ( client != nullptr )
{ {
// remove it // remove it
clients->RemoveClient(client); clients->RemoveClient(client);
} }
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
} }
else else
{ {
@ -197,7 +197,7 @@ void CP25Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
CCallsign rpt2(Header->GetRpt2Callsign()); CCallsign rpt2(Header->GetRpt2Callsign());
// find this client // 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 ) if ( client )
{ {
// get client callsign // get client callsign
@ -206,18 +206,18 @@ void CP25Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
Header->SetRpt2Module(m); Header->SetRpt2Module(m);
rpt2.SetCSModule(m); rpt2.SetCSModule(m);
// and try to open the stream // 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 // keep the handle
m_Streams[stream->GetStreamId()] = stream; m_Streams[stream->GetStreamId()] = stream;
} }
} }
// release // release
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
// update last heard // update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers(); g_Refl..ReleaseUsers();
} }
} }
@ -256,7 +256,7 @@ void CP25Protocol::HandleQueue(void)
if ( buffer.size() > 0 ) if ( buffer.size() > 0 )
{ {
// and push it to all our clients linked to the module and who are not streaming in // 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(); auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr; std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::p25, it)) != nullptr ) while ( (client = clients->FindNextClient(EProtocol::p25, it)) != nullptr )
@ -269,7 +269,7 @@ void CP25Protocol::HandleQueue(void)
} }
} }
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
} }
} }
} }
@ -506,7 +506,7 @@ void CP25Protocol::EncodeP25Packet(const CDvHeaderPacket &Header, const CDvFrame
void CP25Protocol::HandleKeepalives(void) void CP25Protocol::HandleKeepalives(void)
{ {
// iterate on clients // iterate on clients
CClients *clients = g_Reflector.GetClients(); CClients *clients = g_Refl..GetClients();
auto it = clients->begin(); auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr; std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::p25, it)) != 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 // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "Packet.h" #include "Packet.h"
// default constructor // default constructor

@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "PacketStream.h" #include "PacketStream.h"
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -32,10 +32,15 @@ CPacketStream::CPacketStream()
m_uiStreamId = 0; m_uiStreamId = 0;
m_uiPacketCntr = 0; m_uiPacketCntr = 0;
m_OwnerClient = nullptr; m_OwnerClient = nullptr;
#ifdef TRANSCODED_MODULES
m_CodecStream = nullptr; 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_DvHeader = DvHeader;
m_OwnerClient = client; m_OwnerClient = client;
m_LastPacketTime.start(); 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; return true;
} }
@ -75,9 +70,8 @@ void CPacketStream::ClosePacketStream(void)
m_bOpen = false; m_bOpen = false;
m_uiStreamId = 0; m_uiStreamId = 0;
m_OwnerClient.reset(); m_OwnerClient.reset();
#ifdef TRANSCODED_MODULES if (m_CodecStream)
m_CodecStream.reset(); m_CodecStream.reset();
#endif
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -92,7 +86,6 @@ void CPacketStream::Push(std::unique_ptr<CPacket> Packet)
Packet->UpdatePids(m_uiPacketCntr++); Packet->UpdatePids(m_uiPacketCntr++);
} }
// transcoder avaliable ? // transcoder avaliable ?
#ifdef TRANSCODED_MODULES
if ( m_CodecStream ) if ( m_CodecStream )
{ {
// todo: verify no possibilty of double lock here // todo: verify no possibilty of double lock here
@ -115,7 +108,6 @@ void CPacketStream::Push(std::unique_ptr<CPacket> Packet)
m_CodecStream->Unlock(); m_CodecStream->Unlock();
} }
else else
#endif
{ {
// otherwise, push direct push // otherwise, push direct push
push(Packet); push(Packet);

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

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

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

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

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

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

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

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

@ -16,26 +16,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // 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 // destructor
@ -46,12 +30,7 @@ CReflector::~CReflector()
{ {
m_XmlReportFuture.get(); 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++) for (auto it=m_Modules.cbegin(); it!=m_Modules.cend(); it++)
{ {
if (m_RouterFuture[*it].valid()) if (m_RouterFuture[*it].valid())
@ -59,11 +38,6 @@ CReflector::~CReflector()
} }
m_RouterFuture.clear(); m_RouterFuture.clear();
m_Stream.clear(); m_Stream.clear();
#ifdef TRANSCODED_MODULES
m_TCReader.clear();
#endif
} }
@ -72,55 +46,68 @@ CReflector::~CReflector()
bool CReflector::Start(void) 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! // let's go!
keep_running = true; keep_running = true;
// init gate keeper. It can only return 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. // 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. // 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. // init wiresx node directory. Likewise with the return vale.
g_YsfNodeDir.Init(); g_LYtr.LookupInit();
// create protocols // create protocols
if (! m_Protocols.Init()) if (! m_Protocols.Init())
{ {
m_Protocols.Close(); m_Protocols.Close();
return false; return true;
} }
// start one thread per reflector module // 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 auto stream = std::make_shared<CPacketStream>();
m_TCReader[*it] = std::make_shared<CUnixDgramReader>(); if (stream)
std::string readername(TC2REF);
readername.append(1, *it);
if (m_TCReader[*it]->Open(readername.c_str()))
{ {
std::cerr << "ERROR: Reflector can't open " << readername << std::endl; stream->InitPacketStream(std::string::npos != tcmods.find(c));
m_TCReader[*it].reset(); }
return false; else
{
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 // start the reporting threads
try
{
m_XmlReportFuture = std::async(std::launch::async, &CReflector::XmlReportThread, this); m_XmlReportFuture = std::async(std::launch::async, &CReflector::XmlReportThread, this);
#ifdef JSON_MONITOR }
m_JsonReportFuture = std::async(std::launch::async, &CReflector::JsonReportThread, this); catch(const std::exception& e)
#endif {
std::cerr << "Cannot start the dashboard data report thread: " << e.what() << '\n';
}
return true; return false;
} }
void CReflector::Stop(void) void CReflector::Stop(void)
@ -133,30 +120,24 @@ void CReflector::Stop(void)
{ {
m_XmlReportFuture.get(); m_XmlReportFuture.get();
} }
#ifdef JSON_MONITOR
if ( m_JsonReportFuture.valid() )
{
m_JsonReportFuture.get();
}
#endif
// stop & delete all router thread // 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()) if (m_RouterFuture[c].valid())
m_RouterFuture[*it].get(); m_RouterFuture[c].get();
} }
// close protocols // close protocols
m_Protocols.Close(); m_Protocols.Close();
// close gatekeeper // close gatekeeper
g_GateKeeper.Close(); g_Gate.Close();
// close databases // close databases
g_DmridDir.Close(); g_LDid.LookupClose();
g_NXDNidDir.Close(); g_LNid.LookupClose();
g_YsfNodeDir.Close(); g_LYtr.LookupClose();
} }
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
@ -338,13 +319,16 @@ void CReflector::RouterThread(const char ThisModule)
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////
// report threads // report threads
#define XML_UPDATE_PERIOD 10
void CReflector::XmlReportThread() void CReflector::XmlReportThread()
{ {
const std::string path(g_Conf.GetString(g_Conf.j.files.json));
while (keep_running) while (keep_running)
{ {
// report to xml file // report to xml file
std::ofstream xmlFile; 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() ) if ( xmlFile.is_open() )
{ {
// write xml file // write xml file
@ -353,12 +337,10 @@ void CReflector::XmlReportThread()
// and close file // and close file
xmlFile.close(); xmlFile.close();
} }
#ifndef DEBUG_NO_ERROR_ON_XML_OPEN_FAIL
else else
{ {
std::cout << "Failed to open " << XML_PATH << std::endl; std::cout << "Failed to open " << path << std::endl;
} }
#endif
// and wait a bit // and wait a bit
for (int i=0; i< XML_UPDATE_PERIOD && keep_running; i++) 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 // notifications
@ -549,9 +437,7 @@ void CReflector::WriteXmlFile(std::ofstream &xmlFile)
xmlFile << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl; xmlFile << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
// software version // software version
char sz[64]; xmlFile << "<Version>" << g_Vers << "</Version>" << std::endl;
::sprintf(sz, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
xmlFile << "<Version>" << sz << "</Version>" << std::endl;
CCallsign cs = m_Callsign; CCallsign cs = m_Callsign;
cs.PatchCallsign(0, "XLX", 3); cs.PatchCallsign(0, "XLX", 3);
@ -598,120 +484,3 @@ void CReflector::WriteXmlFile(std::ofstream &xmlFile)
ReleaseUsers(); ReleaseUsers();
xmlFile << "</" << cs << "heard users>" << std::endl; 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 #pragma once
#include <unordered_map>
#include "Users.h" #include "Users.h"
#include "Clients.h" #include "Clients.h"
#include "Peers.h" #include "Peers.h"
@ -40,19 +42,8 @@
class CReflector class CReflector
{ {
public: public:
// constructor
CReflector();
// destructor // destructor
virtual ~CReflector(); ~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
// operation // operation
bool Start(void); bool Start(void);
@ -71,7 +62,8 @@ public:
bool IsStreaming(char); bool IsStreaming(char);
void CloseStream(std::shared_ptr<CPacketStream>); 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; } CUsers *GetUsers(void) { m_Users.Lock(); return &m_Users; }
void ReleaseUsers(void) { m_Users.Unlock(); } void ReleaseUsers(void) { m_Users.Unlock(); }
@ -90,9 +82,6 @@ protected:
// threads // threads
void RouterThread(const char); void RouterThread(const char);
void XmlReportThread(void); void XmlReportThread(void);
#ifdef JSON_MONITOR
void JsonReportThread(void);
#endif
// streams // streams
std::shared_ptr<CPacketStream> GetStream(char); std::shared_ptr<CPacketStream> GetStream(char);
@ -102,22 +91,10 @@ protected:
// xml helpers // xml helpers
void WriteXmlFile(std::ofstream &); 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: protected:
// identity // identity
const CCallsign m_Callsign; CCallsign m_Callsign;
const std::string m_Modules; std::string m_Modules, m_TCmodules;
#ifdef TRANSCODER_IP
char m_AmbedIp[INET6_ADDRSTRLEN];
#endif
// objects // objects
CUsers m_Users; // sorted list of lastheard stations CUsers m_Users; // sorted list of lastheard stations
@ -127,22 +104,12 @@ protected:
// queues // queues
std::unordered_map<char, std::shared_ptr<CPacketStream>> m_Stream; 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 // threads
std::atomic<bool> keep_running; std::atomic<bool> keep_running;
std::unordered_map<char, std::future<void>> m_RouterFuture; std::unordered_map<char, std::future<void>> m_RouterFuture;
std::future<void> m_XmlReportFuture; std::future<void> m_XmlReportFuture;
#ifdef JSON_MONITOR
std::future<void> m_JsonReportFuture;
#endif
// notifications // notifications
CNotificationQueue m_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 // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "Semaphore.h" #include "Semaphore.h"
//////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////

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

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

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

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

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

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

@ -17,7 +17,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h> #include <string.h>
#include "USRPClient.h" #include "USRPClient.h"
#include "USRPProtocol.h" #include "USRPProtocol.h"
@ -41,7 +41,7 @@ bool CUSRPProtocol::Initialize(const char *type, const EProtocol ptype, const ui
CBuffer buffer; CBuffer buffer;
m_uiStreamId = 0; m_uiStreamId = 0;
CCallsign cs(USRP_DEFAULT_CALLSIGN); CCallsign cs(USRP_DEFAULT_CALLSIGN);
CClients *clients = g_Reflector.GetClients(); CClients *clients = g_Refl..GetClients();
std::ifstream file; std::ifstream file;
std::streampos size; std::streampos size;
@ -93,7 +93,7 @@ bool CUSRPProtocol::Initialize(const char *type, const EProtocol ptype, const ui
} }
} }
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
// update time // update time
m_LastKeepaliveTime.start(); m_LastKeepaliveTime.start();
@ -135,7 +135,7 @@ void CUSRPProtocol::Task(void)
else if( IsValidDvHeaderPacket(Ip, Buffer, Header) ) else if( IsValidDvHeaderPacket(Ip, Buffer, Header) )
{ {
// callsign muted? // callsign muted?
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::usrp) ) if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::usrp) )
{ {
OnDvHeaderPacketIn(Header, Ip); OnDvHeaderPacketIn(Header, Ip);
} }
@ -192,7 +192,7 @@ void CUSRPProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
CCallsign rpt2(Header->GetRpt2Callsign()); CCallsign rpt2(Header->GetRpt2Callsign());
// find this client // 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 ) if ( client )
{ {
// get client callsign // get client callsign
@ -201,18 +201,18 @@ void CUSRPProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header,
Header->SetRpt2Module(m); Header->SetRpt2Module(m);
rpt2.SetCSModule(m); rpt2.SetCSModule(m);
// and try to open the stream // 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 // keep the handle
m_Streams[stream->GetStreamId()] = stream; m_Streams[stream->GetStreamId()] = stream;
} }
} }
// release // release
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
// update last heard // update last heard
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); g_Refl..GetUsers()->Hearing(my, rpt1, rpt2);
g_Reflector.ReleaseUsers(); g_Refl..ReleaseUsers();
} }
} }
@ -249,7 +249,7 @@ void CUSRPProtocol::HandleQueue(void)
if ( buffer.size() > 0 ) if ( buffer.size() > 0 )
{ {
// and push it to all our clients linked to the module and who are not streaming in // 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(); auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr; std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::usrp, it)) != nullptr ) while ( (client = clients->FindNextClient(EProtocol::usrp, it)) != nullptr )
@ -261,7 +261,7 @@ void CUSRPProtocol::HandleQueue(void)
Send(buffer, client->GetIp()); Send(buffer, client->GetIp());
} }
} }
g_Reflector.ReleaseClients(); g_Refl..ReleaseClients();
} }
} }
m_Queue.Unlock(); m_Queue.Unlock();
@ -375,7 +375,7 @@ void CUSRPProtocol::EncodeUSRPPacket(const CDvHeaderPacket &Header, const CDvFra
void CUSRPProtocol::HandleKeepalives(void) void CUSRPProtocol::HandleKeepalives(void)
{ {
// iterate on clients // iterate on clients
CClients *clients = g_Reflector.GetClients(); CClients *clients = g_Refl..GetClients();
auto it = clients->begin(); auto it = clients->begin();
std::shared_ptr<CClient>client = nullptr; std::shared_ptr<CClient>client = nullptr;
while ( (client = clients->FindNextClient(EProtocol::usrp, it)) != 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 // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include <string.h> #include <string.h>
#include "User.h" #include "User.h"

@ -33,7 +33,7 @@ public:
~CUser() {} ~CUser() {}
// operation // operation
void HeardNow(void) { m_LastHeardTime = std::time(nullptr); } void HeardNow(void) { m_LastHeardTime = time(nullptr); }
// operators // operators
bool operator ==(const CUser &) const; bool operator ==(const CUser &) const;
@ -49,5 +49,5 @@ protected:
CCallsign m_Rpt1; CCallsign m_Rpt1;
CCallsign m_Rpt2; CCallsign m_Rpt2;
CCallsign m_Xlx; 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 // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Main.h"
#include "Users.h" #include "Users.h"
#include "Reflector.h" #include "Reflector.h"
@ -40,7 +40,7 @@ void CUsers::AddUser(const CUser &user)
} }
// notify // 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) 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) void CUsers::Hearing(const CCallsign &my, const CCallsign &rpt1, const CCallsign &rpt2, const CCallsign &xlx)

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

@ -1,73 +1,89 @@
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. // Copyright © 2023 Thomas A. Early N7TAE.
//
// urfd -- The universal reflector // ----------------------------------------------------------------------------
// Copyright © 2021 Thomas A. Early N7TAE // This file is part of m17ref.
// //
// This program is free software: you can redistribute it and/or modify // m17ref is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // m17ref is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // with this software. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include "Main.h"
#include "Version.h" #include "Version.h"
//////////////////////////////////////////////////////////////////////////////////////// CVersion::CVersion() : version(0) {}
// constructor
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; return version;
m_iMinor = 0;
m_iRevision = 0;
} }
CVersion::CVersion(int iMajor, int iMinor, int iRevision) void CVersion::Set(uint8_t maj, uint8_t min, uint8_t rev)
{ {
m_iMajor = iMajor; version = 0x10000*maj + 0x100*min + rev;
m_iMinor = iMinor;
m_iRevision = iRevision;
} }
//////////////////////////////////////////////////////////////////////////////////////// bool CVersion::operator ==(const CVersion &v) const
// comparaison {
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 v.version <= version;
{
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;
} }
//////////////////////////////////////////////////////////////////////////////////////// bool CVersion::operator >(const CVersion &v) const
// operator {
return v.version > version;
}
bool CVersion::operator ==(const CVersion &Version) const bool CVersion::operator <(const CVersion &v) const
{ {
return ( (Version.m_iMajor == m_iMajor) && return v.version < version;
(Version.m_iMinor == m_iMinor) &&
(Version.m_iRevision == m_iRevision )) ;
} }
// 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. // Copyright © 2023 Thomas A. Early N7TAE.
//
// urfd -- The universal reflector // ----------------------------------------------------------------------------
// Copyright © 2021 Thomas A. Early N7TAE // This file is part of m17ref.
// //
// This program is free software: you can redistribute it and/or modify // m17ref is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// This program is distributed in the hope that it will be useful, // m17ref is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // with this software. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#pragma once #pragma once
#include <cstdint>
#include <iostream>
class CVersion class CVersion
{ {
public: public:
// constructor // constructors
CVersion(); CVersion();
CVersion(int, int, int); CVersion(uint8_t maj, uint8_t min, uint8_t rev);
// get // get
int GetMajor(void) const { return m_iMajor; } int GetMajor(void) const;
int GetMinor(void) const { return m_iMinor; } int GetMinor(void) const;
int GetRevision(void) const { return m_iRevision; } 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 // output
bool IsEqualOrHigherTo(const CVersion &) const; friend std::ostream &operator <<(std::ostream &os, const CVersion &v);
// operator
bool operator ==(const CVersion &) const;
protected: protected:
// data // data
int m_iMajor; int version;
int m_iMinor;
int m_iRevision;
}; };

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

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

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

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

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

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

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