diff --git a/.gitignore b/.gitignore index 2971bab..df15a05 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ configure.h configure.sql reflector.cfg wiresx/configure.php -urfd +urfd* +inicheck diff --git a/reflector/BMClient.cpp b/reflector/BMClient.cpp index ed5caaa..59b037c 100644 --- a/reflector/BMClient.cpp +++ b/reflector/BMClient.cpp @@ -17,7 +17,7 @@ // along with this program. If not, see . #include -#include "Main.h" + #include "BMClient.h" diff --git a/reflector/BMPeer.cpp b/reflector/BMPeer.cpp index e688697..6bcd756 100644 --- a/reflector/BMPeer.cpp +++ b/reflector/BMPeer.cpp @@ -17,7 +17,7 @@ // along with this program. If not, see . -#include "Main.h" + #include #include "Reflector.h" #include "BMPeer.h" diff --git a/reflector/BMProtocol.cpp b/reflector/BMProtocol.cpp index 13a2c09..dae8b90 100644 --- a/reflector/BMProtocol.cpp +++ b/reflector/BMProtocol.cpp @@ -18,7 +18,7 @@ #include -#include "Main.h" + #include "BMPeer.h" #include "BMProtocol.h" #include "Reflector.h" @@ -73,7 +73,7 @@ void CBMProtocol::Task(void) else if ( IsValidDvHeaderPacket(Buffer, Header) ) { // callsign allowed? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip) ) + if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip) ) { OnDvHeaderPacketIn(Header, Ip); } @@ -83,7 +83,7 @@ void CBMProtocol::Task(void) std::cout << "XLX (" << Version.GetMajor() << "." << Version.GetMinor() << "." << Version.GetRevision() << ") connect packet for modules " << Modules << " from " << Callsign << " at " << Ip << std::endl; // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::bm, Modules) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::bm, Modules) ) { // acknowledge the request EncodeConnectAckPacket(&Buffer, Modules); @@ -101,10 +101,10 @@ void CBMProtocol::Task(void) std::cout << "XLX ack packet for modules " << Modules << " from " << Callsign << " at " << Ip << std::endl; // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::bm, Modules) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::bm, Modules) ) { // already connected ? - CPeers *peers = g_Reflector.GetPeers(); + CPeers *peers = g_Refl..GetPeers(); if ( peers->FindPeer(Callsign, Ip, EProtocol::bm) == nullptr ) { // create the new peer @@ -115,7 +115,7 @@ void CBMProtocol::Task(void) // this also add all new clients to reflector client list peers->AddPeer(peer); } - g_Reflector.ReleasePeers(); + g_Refl..ReleasePeers(); } } else if ( IsValidDisconnectPacket(Buffer, &Callsign) ) @@ -123,7 +123,7 @@ void CBMProtocol::Task(void) std::cout << "XLX disconnect packet from " << Callsign << " at " << Ip << std::endl; // find peer - CPeers *peers = g_Reflector.GetPeers(); + CPeers *peers = g_Refl..GetPeers(); std::shared_ptrpeer = peers->FindPeer(Ip, EProtocol::bm); if ( peer != nullptr ) { @@ -132,7 +132,7 @@ void CBMProtocol::Task(void) // and delete them peers->RemovePeer(peer); } - g_Reflector.ReleasePeers(); + g_Refl..ReleasePeers(); } else if ( IsValidNackPacket(Buffer, &Callsign) ) { @@ -143,14 +143,14 @@ void CBMProtocol::Task(void) //std::cout << "XLX keepalive packet from " << Callsign << " at " << Ip << std::endl; // find peer - CPeers *peers = g_Reflector.GetPeers(); + CPeers *peers = g_Refl..GetPeers(); std::shared_ptrpeer = peers->FindPeer(Ip, EProtocol::bm); if ( peer != nullptr ) { // keep it alive peer->Alive(); } - g_Reflector.ReleasePeers(); + g_Refl..ReleasePeers(); } else { @@ -210,7 +210,7 @@ void CBMProtocol::HandleQueue(void) } // and push it to all our clients linked to the module and who are not streaming in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::bm, it)) != nullptr ) @@ -237,7 +237,7 @@ void CBMProtocol::HandleQueue(void) } } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } m_Queue.Unlock(); @@ -255,7 +255,7 @@ void CBMProtocol::HandleKeepalives(void) EncodeKeepAlivePacket(&keepalive); // iterate on peers - CPeers *peers = g_Reflector.GetPeers(); + CPeers *peers = g_Refl..GetPeers(); auto pit = peers->begin(); std::shared_ptrpeer = nullptr; while ( (peer = peers->FindNextPeer(EProtocol::bm, pit)) != nullptr ) @@ -282,7 +282,7 @@ void CBMProtocol::HandleKeepalives(void) peers->RemovePeer(peer); } } - g_Reflector.ReleasePeers(); + g_Refl..ReleasePeers(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -293,8 +293,8 @@ void CBMProtocol::HandlePeerLinks(void) CBuffer buffer; // get the list of peers - CPeerCallsignList *list = g_GateKeeper.GetPeerList(); - CPeers *peers = g_Reflector.GetPeers(); + CPeerCallsignList *list = g_Gate.GetPeerList(); + CPeers *peers = g_Refl..GetPeers(); // check if all our connected peers are still listed by gatekeeper // if not, disconnect @@ -330,8 +330,8 @@ void CBMProtocol::HandlePeerLinks(void) } // done - g_Reflector.ReleasePeers(); - g_GateKeeper.ReleasePeerList(); + g_Refl..ReleasePeers(); + g_Gate.ReleasePeerList(); } @@ -360,11 +360,11 @@ void CBMProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header, c CCallsign rpt2(Header->GetRpt2Callsign()); // no stream open yet, open a new one // find this client - std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::bm, Header->GetRpt2Module()); + std::shared_ptrclient = g_Refl..GetClients()->FindClient(Ip, EProtocol::bm, Header->GetRpt2Module()); if ( client ) { // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr ) { // keep the handle m_Streams[stream->GetStreamId()] = stream; @@ -373,10 +373,10 @@ void CBMProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header, c peer = client->GetCallsign(); } // release - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // update last heard - g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2, peer); - g_Reflector.ReleaseUsers(); + g_Refl..GetUsers()->Hearing(my, rpt1, rpt2, peer); + g_Refl..ReleaseUsers(); } } diff --git a/reflector/Buffer.h b/reflector/Buffer.h index deec049..12eb495 100644 --- a/reflector/Buffer.h +++ b/reflector/Buffer.h @@ -20,7 +20,6 @@ #include #include -#include "Main.h" //////////////////////////////////////////////////////////////////////////////////////// diff --git a/reflector/Callsign.cpp b/reflector/Callsign.cpp index a1b256b..c8749b3 100644 --- a/reflector/Callsign.cpp +++ b/reflector/Callsign.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include #include "DMRIdDirFile.h" @@ -67,62 +67,62 @@ CCallsign::CCallsign(const char *sz, uint32_t dmrid, uint16_t nxdnid) // dmrid ok ? if ( m_uiDmrid == 0 ) { - g_DmridDir.Lock(); + g_LDid.Lock(); { - m_uiDmrid = g_DmridDir.FindDmrid(*this); + m_uiDmrid = g_LDid.FindDmrid(*this); } - g_DmridDir.Unlock(); + g_LDid.Unlock(); } if ( m_uiNXDNid == 0 ) { - g_NXDNidDir.Lock(); + g_LNid.Lock(); { - m_uiNXDNid = g_NXDNidDir.FindNXDNid(*this); + m_uiNXDNid = g_LNid.FindNXDNid(*this); } - g_NXDNidDir.Unlock(); + g_LNid.Unlock(); } } else if ( m_uiDmrid != 0 ) { - g_DmridDir.Lock(); + g_LDid.Lock(); { - const CCallsign *callsign = g_DmridDir.FindCallsign(m_uiDmrid); + const CCallsign *callsign = g_LDid.FindCallsign(m_uiDmrid); if ( callsign != nullptr ) { memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN); } } - g_DmridDir.Unlock(); - + g_LDid.Unlock(); + if ( m_uiNXDNid == 0 ) { - g_NXDNidDir.Lock(); + g_LNid.Lock(); { - m_uiNXDNid = g_NXDNidDir.FindNXDNid(*this); + m_uiNXDNid = g_LNid.FindNXDNid(*this); } - g_NXDNidDir.Unlock(); + g_LNid.Unlock(); } CSIn(); } else if ( m_uiNXDNid != 0 ) { - g_NXDNidDir.Lock(); + g_LNid.Lock(); { - const CCallsign *callsign = g_NXDNidDir.FindCallsign(m_uiNXDNid); + const CCallsign *callsign = g_LNid.FindCallsign(m_uiNXDNid); if ( callsign != nullptr ) { memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN); } } - g_NXDNidDir.Unlock(); - + g_LNid.Unlock(); + if ( m_uiDmrid == 0 ) { - g_DmridDir.Lock(); + g_LDid.Lock(); { - m_uiDmrid = g_DmridDir.FindDmrid(*this); + m_uiDmrid = g_LDid.FindDmrid(*this); } - g_DmridDir.Unlock(); + g_LDid.Unlock(); } CSIn(); } @@ -201,16 +201,16 @@ void CCallsign::SetCallsign(const char *sz, bool UpdateDmrid) // and update dmrid if ( UpdateDmrid ) { - g_DmridDir.Lock(); + g_LDid.Lock(); { - m_uiDmrid = g_DmridDir.FindDmrid(*this); + m_uiDmrid = g_LDid.FindDmrid(*this); } - g_DmridDir.Unlock(); - g_NXDNidDir.Lock(); + g_LDid.Unlock(); + g_LNid.Lock(); { - m_uiNXDNid = g_NXDNidDir.FindNXDNid(*this); + m_uiNXDNid = g_LNid.FindNXDNid(*this); } - g_NXDNidDir.Unlock(); + g_LNid.Unlock(); } } @@ -234,16 +234,16 @@ void CCallsign::SetCallsign(const uint8_t *buffer, int len, bool UpdateDmrid) CSIn(); if ( UpdateDmrid ) { - g_DmridDir.Lock(); + g_LDid.Lock(); { - m_uiDmrid = g_DmridDir.FindDmrid(*this); + m_uiDmrid = g_LDid.FindDmrid(*this); } - g_DmridDir.Unlock(); - g_NXDNidDir.Lock(); + g_LDid.Unlock(); + g_LNid.Lock(); { - m_uiNXDNid = g_NXDNidDir.FindNXDNid(*this); + m_uiNXDNid = g_LNid.FindNXDNid(*this); } - g_NXDNidDir.Unlock(); + g_LNid.Unlock(); } } @@ -252,15 +252,15 @@ void CCallsign::SetDmrid(uint32_t dmrid, bool UpdateCallsign) m_uiDmrid = dmrid; if ( UpdateCallsign ) { - g_DmridDir.Lock(); + g_LDid.Lock(); { - const CCallsign *callsign = g_DmridDir.FindCallsign(dmrid); + const CCallsign *callsign = g_LDid.FindCallsign(dmrid); if ( callsign != nullptr ) { memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN); } } - g_DmridDir.Unlock(); + g_LDid.Unlock(); } } @@ -277,15 +277,15 @@ void CCallsign::SetNXDNid(uint16_t nxdnid, bool UpdateCallsign) m_uiNXDNid = nxdnid; if ( UpdateCallsign ) { - g_DmridDir.Lock(); + g_LDid.Lock(); { - const CCallsign *callsign = g_NXDNidDir.FindCallsign(nxdnid); + const CCallsign *callsign = g_LNid.FindCallsign(nxdnid); if ( callsign != nullptr ) { memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN); } } - g_NXDNidDir.Unlock(); + g_LNid.Unlock(); } } diff --git a/reflector/CallsignList.cpp b/reflector/CallsignList.cpp index cb4423b..2fff96b 100644 --- a/reflector/CallsignList.cpp +++ b/reflector/CallsignList.cpp @@ -19,7 +19,7 @@ #include #include #include -#include "Main.h" + #include "CallsignList.h" //////////////////////////////////////////////////////////////////////////////////////// diff --git a/reflector/CallsignList.h b/reflector/CallsignList.h index 8ed2c9c..c9ba29a 100644 --- a/reflector/CallsignList.h +++ b/reflector/CallsignList.h @@ -17,7 +17,7 @@ // along with this program. If not, see . #pragma once -#include "Main.h" + #include "CallsignListItem.h" //////////////////////////////////////////////////////////////////////////////////////// diff --git a/reflector/CallsignListItem.cpp b/reflector/CallsignListItem.cpp index ac0034c..c6a5808 100644 --- a/reflector/CallsignListItem.cpp +++ b/reflector/CallsignListItem.cpp @@ -17,7 +17,7 @@ // along with this program. If not, see . #include -#include "Main.h" + #include "CallsignListItem.h" //////////////////////////////////////////////////////////////////////////////////////// diff --git a/reflector/CallsignListItem.h b/reflector/CallsignListItem.h index 2699567..daa5478 100644 --- a/reflector/CallsignListItem.h +++ b/reflector/CallsignListItem.h @@ -18,7 +18,7 @@ #pragma once -#include "Main.h" + #include "Callsign.h" #include "IP.h" diff --git a/reflector/Client.cpp b/reflector/Client.cpp index 71c6a84..93f27ad 100644 --- a/reflector/Client.cpp +++ b/reflector/Client.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "Client.h" diff --git a/reflector/Clients.cpp b/reflector/Clients.cpp index e058070..eb83e53 100644 --- a/reflector/Clients.cpp +++ b/reflector/Clients.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "Reflector.h" #include "Clients.h" @@ -66,7 +66,7 @@ void CClients::AddClient(std::shared_ptr client) } std::cout << std::endl; // notify - g_Reflector.OnClientsChanged(); + g_Refl..OnClientsChanged(); } void CClients::RemoveClient(std::shared_ptr client) @@ -90,7 +90,7 @@ void CClients::RemoveClient(std::shared_ptr client) std::cout << std::endl; m_Clients.erase(it); // notify - g_Reflector.OnClientsChanged(); + g_Refl..OnClientsChanged(); break; } } diff --git a/reflector/CodecStream.cpp b/reflector/CodecStream.cpp index 3d7aa1e..a1f641f 100644 --- a/reflector/CodecStream.cpp +++ b/reflector/CodecStream.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "CodecStream.h" #include "DVFramePacket.h" @@ -25,7 +25,12 @@ //////////////////////////////////////////////////////////////////////////////////////// // constructor -CCodecStream::CCodecStream(CPacketStream *PacketStream, uint16_t streamid, ECodecType type, std::shared_ptr reader) +CCodecStream::CCodecStream(CPacketStream *PacketStream) +{ + m_PacketStream = PacketStream; +} + +void CCodecStream::ResetStats(uint16_t streamid, ECodecType type) { keep_running = true; m_uiStreamId = streamid; @@ -36,9 +41,6 @@ CCodecStream::CCodecStream(CPacketStream *PacketStream, uint16_t streamid, ECode m_RTSum = 0; m_RTCount = 0; m_uiTotalPackets = 0; - m_PacketStream = PacketStream; - m_TCReader = reader; - InitCodecStream(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -52,7 +54,12 @@ CCodecStream::~CCodecStream() { m_Future.get(); } + // and close the socket + m_TCReader.Close(); +} +void CCodecStream::ReportStats() +{ // display stats if (m_RTCount > 0) { @@ -69,11 +76,24 @@ CCodecStream::~CCodecStream() //////////////////////////////////////////////////////////////////////////////////////// // initialization -void CCodecStream::InitCodecStream(void) +bool CCodecStream::InitCodecStream(char module) { m_TCWriter.SetUp(REF2TC); + std::string name(TC2REF); + name.append(1, module); + if (m_TCReader.Open(name.c_str())) + return true; keep_running = true; - m_Future = std::async(std::launch::async, &CCodecStream::Thread, this); + try + { + m_Future = std::async(std::launch::async, &CCodecStream::Thread, this); + } + catch(const std::exception& e) + { + std::cerr << "Could not start Codec processing on module '" << module << "': " << e.what() << std::endl; + return true; + } + return false; } //////////////////////////////////////////////////////////////////////////////////////// @@ -92,21 +112,21 @@ void CCodecStream::Task(void) STCPacket pack; // any packet from transcoder - if (m_TCReader->Receive(&pack, 5)) + if (m_TCReader.Receive(&pack, 5)) { // update statistics double rt = pack.rt_timer.time(); // the round-trip time - if ( m_RTMin == -1 ) + if (0 == m_RTCount) { m_RTMin = rt; m_RTMax = rt; - } else { - m_RTMin = MIN(m_RTMin, rt); - m_RTMax = MAX(m_RTMax, rt); - + if (rt < m_RTMin) + m_RTMin = rt; + else if (rt > m_RTMax) + m_RTMax = rt; } m_RTSum += rt; m_RTCount++; diff --git a/reflector/CodecStream.h b/reflector/CodecStream.h index 04e706f..e4652c4 100644 --- a/reflector/CodecStream.h +++ b/reflector/CodecStream.h @@ -18,6 +18,9 @@ #pragma once +#include +#include + #include "UnixDgramSocket.h" #include "PacketQueue.h" @@ -30,7 +33,11 @@ class CCodecStream : public CPacketQueue { public: // constructor - CCodecStream(CPacketStream *packetstream, uint16_t streamid, ECodecType codectype, std::shared_ptr reader); + CCodecStream(CPacketStream *packetstream); + bool InitCodecStream(char module); + + void ResetStats(uint16_t streamid, ECodecType codectype); + void ReportStats(); // destructor virtual ~CCodecStream(); @@ -44,7 +51,6 @@ public: protected: // initialization - void InitCodecStream(void); // data uint16_t m_uiStreamId; uint16_t m_uiPort; @@ -52,7 +58,7 @@ protected: ECodecType m_eCodecIn; // sockets - std::shared_ptr m_TCReader; + CUnixDgramReader m_TCReader; CUnixDgramWriter m_TCWriter; // associated packet stream diff --git a/reflector/Configure.cpp b/reflector/Configure.cpp new file mode 100644 index 0000000..968c722 --- /dev/null +++ b/reflector/Configure.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 &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(userp); + std::streamsize len = size * nmemb; + if(os.write(static_cast(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 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(); + 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(), IPv4RegEx)) + { + if (data.contains(j.ip.ipv4address)) + { + auto v4 = data[j.ip.ipv4address].get(); + 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() << ", 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(), IPv6RegEx)) + { + if (data.contains(j.ip.ipv6address)) + { + auto v6 = data[j.ip.ipv6address].get(); + 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() << ", 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()); + if (data.contains(j.modules.tcmodules)) + { + const auto tcmods(data[j.modules.tcmodules].get()); + + // 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> 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 §ion, 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 §ion, 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() : ""); + const auto c = data[key].get().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(); + 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()); + } + 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(); + } + 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().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 diff --git a/reflector/Configure.h b/reflector/Configure.h new file mode 100644 index 0000000..dee5086 --- /dev/null +++ b/reflector/Configure.h @@ -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 +#include +#include +#include + +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 ¶m) const; + bool checkModules(std::string &m) const; + void setAutolink(const std::string §ion, const std::string &key, const std::string &value); + bool isDefined(ErrorLevel level, const std::string §ion, const std::string &pname, const std::string &key, bool &rval); + void checkAutoLink(const std::string §ion, const std::string &pname, const std::string &key, bool &rval); +}; diff --git a/reflector/DCSClient.cpp b/reflector/DCSClient.cpp index a30f140..200c04e 100644 --- a/reflector/DCSClient.cpp +++ b/reflector/DCSClient.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "DCSClient.h" diff --git a/reflector/DCSProtocol.cpp b/reflector/DCSProtocol.cpp index 8bb54e0..0a3f5b6 100644 --- a/reflector/DCSProtocol.cpp +++ b/reflector/DCSProtocol.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "DCSClient.h" #include "DCSProtocol.h" @@ -68,7 +68,7 @@ void CDcsProtocol::Task(void) if ( IsValidDvPacket(Buffer, Header, Frame) ) { // callsign muted? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dcs, Header->GetRpt2Module()) ) + if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dcs, Header->GetRpt2Module()) ) { OnDvHeaderPacketIn(Header, Ip); @@ -80,18 +80,18 @@ void CDcsProtocol::Task(void) std::cout << "DCS connect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl; // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::dcs) && g_Reflector.IsValidModule(ToLinkModule) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::dcs) && g_Refl..IsValidModule(ToLinkModule) ) { // valid module ? - if ( g_Reflector.IsValidModule(ToLinkModule) ) + if ( g_Refl..IsValidModule(ToLinkModule) ) { // acknowledge the request EncodeConnectAckPacket(Callsign, ToLinkModule, &Buffer); Send(Buffer, Ip); // create the client and append - g_Reflector.GetClients()->AddClient(std::make_shared(Callsign, Ip, ToLinkModule)); - g_Reflector.ReleaseClients(); + g_Refl..GetClients()->AddClient(std::make_shared(Callsign, Ip, ToLinkModule)); + g_Refl..ReleaseClients(); } else { @@ -115,7 +115,7 @@ void CDcsProtocol::Task(void) std::cout << "DCS disconnect packet from " << Callsign << " at " << Ip << std::endl; // find client - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Ip, EProtocol::dcs); if ( client != nullptr ) { @@ -125,21 +125,21 @@ void CDcsProtocol::Task(void) EncodeConnectNackPacket(Callsign, ' ', &Buffer); Send(Buffer, Ip); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else if ( IsValidKeepAlivePacket(Buffer, &Callsign) ) { //std::cout << "DCS keepalive packet from " << Callsign << " at " << Ip << std::endl; // find all clients with that callsign & ip and keep them alive - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(Callsign, Ip, EProtocol::dcs, it)) != nullptr ) { client->Alive(); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else if ( IsIgnorePacket(Buffer) ) { @@ -193,24 +193,24 @@ void CDcsProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header, CCallsign rpt2(Header->GetRpt2Callsign()); // find this client - std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::dcs); + std::shared_ptrclient = g_Refl..GetClients()->FindClient(Ip, EProtocol::dcs); if ( client ) { // get client callsign rpt1 = client->GetCallsign(); // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr ) { // keep the handle m_Streams[stream->GetStreamId()] = stream; } } // release - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // update last heard - g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); - g_Reflector.ReleaseUsers(); + g_Refl..GetUsers()->Hearing(my, rpt1, rpt2); + g_Refl..ReleaseUsers(); } } @@ -253,7 +253,7 @@ void CDcsProtocol::HandleQueue(void) if ( buffer.size() > 0 ) { // and push it to all our clients linked to the module and who are not streaming in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::dcs, it)) != nullptr ) @@ -266,7 +266,7 @@ void CDcsProtocol::HandleQueue(void) } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } } @@ -285,7 +285,7 @@ void CDcsProtocol::HandleKeepalives(void) EncodeKeepAlivePacket(&keepalive1); // iterate on clients - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::dcs, it)) != nullptr ) @@ -318,7 +318,7 @@ void CDcsProtocol::HandleKeepalives(void) } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } //////////////////////////////////////////////////////////////////////////////////////// diff --git a/reflector/DExtraClient.cpp b/reflector/DExtraClient.cpp index 579352b..fc6b008 100644 --- a/reflector/DExtraClient.cpp +++ b/reflector/DExtraClient.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "DExtraClient.h" diff --git a/reflector/DExtraPeer.cpp b/reflector/DExtraPeer.cpp index e8c04a5..1a72a60 100644 --- a/reflector/DExtraPeer.cpp +++ b/reflector/DExtraPeer.cpp @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "Reflector.h" #include "DExtraPeer.h" diff --git a/reflector/DExtraProtocol.cpp b/reflector/DExtraProtocol.cpp index 3b55594..9b47e2b 100644 --- a/reflector/DExtraProtocol.cpp +++ b/reflector/DExtraProtocol.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "DExtraPeer.h" #include "DExtraClient.h" @@ -74,7 +74,7 @@ void CDextraProtocol::Task(void) else if ( IsValidDvHeaderPacket(Buffer, Header) ) { // callsign muted? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dextra, Header->GetRpt2Module()) ) + if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dextra, Header->GetRpt2Module()) ) { OnDvHeaderPacketIn(Header, Ip); } @@ -98,20 +98,20 @@ void CDextraProtocol::Task(void) } // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::dextra) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::dextra) ) { // valid module ? - if ( g_Reflector.IsValidModule(ToLinkModule) ) + if ( g_Refl..IsValidModule(ToLinkModule) ) { // is this an ack for a link request? - CPeerCallsignList *list = g_GateKeeper.GetPeerList(); + CPeerCallsignList *list = g_Gate.GetPeerList(); CCallsignListItem *item = list->FindListItem(Callsign); if ( item != nullptr && Callsign.GetCSModule() == item->GetModules()[1] && ToLinkModule == item->GetModules()[0] ) { std::cout << "DExtra ack packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl; // already connected ? - CPeers *peers = g_Reflector.GetPeers(); + CPeers *peers = g_Refl..GetPeers(); if ( peers->FindPeer(Callsign, Ip, EProtocol::dextra) == nullptr ) { // create the new peer @@ -120,7 +120,7 @@ void CDextraProtocol::Task(void) // this also add all new clients to reflector client list peers->AddPeer(std::make_shared(Callsign, Ip, std::string(1, ToLinkModule).c_str(), CVersion(2, 0, 0))); } - g_Reflector.ReleasePeers(); + g_Refl..ReleasePeers(); } else { @@ -129,10 +129,10 @@ void CDextraProtocol::Task(void) Send(Buffer, Ip); // create the client and append - g_Reflector.GetClients()->AddClient(std::make_shared(Callsign, Ip, ToLinkModule, ProtRev)); - g_Reflector.ReleaseClients(); + g_Refl..GetClients()->AddClient(std::make_shared(Callsign, Ip, ToLinkModule, ProtRev)); + g_Refl..ReleaseClients(); } - g_GateKeeper.ReleasePeerList(); + g_Gate.ReleasePeerList(); } else { @@ -155,7 +155,7 @@ void CDextraProtocol::Task(void) std::cout << "DExtra disconnect packet from " << Callsign << " at " << Ip << std::endl; // find client & remove it - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Ip, EProtocol::dextra); if ( client != nullptr ) { @@ -172,21 +172,21 @@ void CDextraProtocol::Task(void) // and remove it clients->RemoveClient(client); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else if ( IsValidKeepAlivePacket(Buffer, &Callsign) ) { //std::cout << "DExtra keepalive packet from " << Callsign << " at " << Ip << std::endl; // find all clients with that callsign & ip and keep them alive - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(Callsign, Ip, EProtocol::dextra, it)) != nullptr ) { client->Alive(); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else { @@ -239,7 +239,7 @@ void CDextraProtocol::HandleQueue(void) if ( EncodeDvPacket(*packet, buffer) ) { // and push it to all our clients linked to the module and who are not streaming in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::dextra, it)) != nullptr ) @@ -255,7 +255,7 @@ void CDextraProtocol::HandleQueue(void) } } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } m_Queue.Unlock(); @@ -273,7 +273,7 @@ void CDextraProtocol::HandleKeepalives(void) EncodeKeepAlivePacket(&keepalive); // iterate on clients - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::dextra, it)) != nullptr ) @@ -290,7 +290,7 @@ void CDextraProtocol::HandleKeepalives(void) // otherwise check if still with us else if ( !client->IsAlive() ) { - CPeers *peers = g_Reflector.GetPeers(); + CPeers *peers = g_Refl..GetPeers(); std::shared_ptrpeer = peers->FindPeer(client->GetCallsign(), client->GetIp(), EProtocol::dextra); if ( peer != nullptr && peer->GetReflectorModules()[0] == client->GetReflectorModule() ) { @@ -307,14 +307,14 @@ void CDextraProtocol::HandleKeepalives(void) std::cout << "DExtra client " << client->GetCallsign() << " keepalive timeout" << std::endl; clients->RemoveClient(client); } - g_Reflector.ReleasePeers(); + g_Refl..ReleasePeers(); } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // iterate on peers - CPeers *peers = g_Reflector.GetPeers(); + CPeers *peers = g_Refl..GetPeers(); auto pit = peers->begin(); std::shared_ptrpeer = nullptr; while ( (peer = peers->FindNextPeer(EProtocol::dextra, pit)) != nullptr ) @@ -327,19 +327,19 @@ void CDextraProtocol::HandleKeepalives(void) // no, disconnect all clients CBuffer disconnect; EncodeDisconnectPacket(&disconnect, peer->GetReflectorModules()[0]); - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); for ( auto cit=peer->cbegin(); cit!=peer->cend(); cit++ ) { Send(disconnect, (*cit)->GetIp()); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // remove it std::cout << "DExtra peer " << peer->GetCallsign() << " keepalive timeout" << std::endl; peers->RemovePeer(peer); } } - g_Reflector.ReleasePeers(); + g_Refl..ReleasePeers(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -350,8 +350,8 @@ void CDextraProtocol::HandlePeerLinks(void) CBuffer buffer; // get the list of peers - CPeerCallsignList *list = g_GateKeeper.GetPeerList(); - CPeers *peers = g_Reflector.GetPeers(); + CPeerCallsignList *list = g_Gate.GetPeerList(); + CPeers *peers = g_Refl..GetPeers(); // check if all our connected peers are still listed by gatekeeper // if not, disconnect @@ -390,8 +390,8 @@ void CDextraProtocol::HandlePeerLinks(void) } // done - g_Reflector.ReleasePeers(); - g_GateKeeper.ReleasePeerList(); + g_Refl..ReleasePeers(); + g_Gate.ReleasePeerList(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -415,7 +415,7 @@ void CDextraProtocol::OnDvHeaderPacketIn(std::unique_ptr &Heade CCallsign rpt2(Header->GetRpt2Callsign()); // find this client - std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::dextra); + std::shared_ptrclient = g_Refl..GetClients()->FindClient(Ip, EProtocol::dextra); if ( client ) { // get client callsign @@ -430,18 +430,18 @@ void CDextraProtocol::OnDvHeaderPacketIn(std::unique_ptr &Heade rpt2.SetCSModule(m); } // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr ) { // keep the handle m_Streams[stream->GetStreamId()] = stream; } } // release - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // update last heard - g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); - g_Reflector.ReleaseUsers(); + g_Refl..GetUsers()->Hearing(my, rpt1, rpt2); + g_Refl..ReleaseUsers(); } } diff --git a/reflector/DMRIdDir.cpp b/reflector/DMRIdDir.cpp deleted file mode 100644 index 886a840..0000000 --- a/reflector/DMRIdDir.cpp +++ /dev/null @@ -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 . - -#include -#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; -} diff --git a/reflector/DMRIdDirFile.cpp b/reflector/DMRIdDirFile.cpp deleted file mode 100644 index d378ef5..0000000 --- a/reflector/DMRIdDirFile.cpp +++ /dev/null @@ -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 . - -#include -#include -#include -#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(ui, cs)); - m_DmridMap.insert(std::pair(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; -} diff --git a/reflector/DMRIdDirHttp.cpp b/reflector/DMRIdDirHttp.cpp deleted file mode 100644 index b0b4f36..0000000 --- a/reflector/DMRIdDirHttp.cpp +++ /dev/null @@ -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 . - -#include -#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(ui, cs)); - m_DmridMap.insert(std::pair(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; -} diff --git a/reflector/DMRMMDVMClient.cpp b/reflector/DMRMMDVMClient.cpp index 9f8b1f9..0c1cc1b 100644 --- a/reflector/DMRMMDVMClient.cpp +++ b/reflector/DMRMMDVMClient.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "DMRMMDVMClient.h" diff --git a/reflector/DMRMMDVMProtocol.cpp b/reflector/DMRMMDVMProtocol.cpp index a71d2b9..c3f8acd 100644 --- a/reflector/DMRMMDVMProtocol.cpp +++ b/reflector/DMRMMDVMProtocol.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "DMRMMDVMClient.h" #include "DMRMMDVMProtocol.h" @@ -93,7 +93,7 @@ void CDmrmmdvmProtocol::Task(void) if ( Receive4(Buffer, Ip, 20) ) #endif { - //Buffer.DebugDump(g_Reflector.m_DebugFile); + //Buffer.DebugDump(g_Refl..m_DebugFile); // crack the packet if ( IsValidDvFramePacket(Buffer, Frames) ) { @@ -105,7 +105,7 @@ void CDmrmmdvmProtocol::Task(void) else if ( IsValidDvHeaderPacket(Buffer, Header, &Cmd, &CallType) ) { // callsign muted? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dmrmmdvm) ) + if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dmrmmdvm) ) { // handle it OnDvHeaderPacketIn(Header, Ip, Cmd, CallType); @@ -120,7 +120,7 @@ void CDmrmmdvmProtocol::Task(void) std::cout << "DMRmmdvm connect packet from " << Callsign << " at " << Ip << std::endl; // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::dmrmmdvm) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::dmrmmdvm) ) { // acknowledge the request EncodeConnectAckPacket(&Buffer, Callsign, m_uiAuthSeed); @@ -139,14 +139,14 @@ void CDmrmmdvmProtocol::Task(void) std::cout << "DMRmmdvm authentication packet from " << Callsign << " at " << Ip << std::endl; // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::dmrmmdvm) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::dmrmmdvm) ) { // acknowledge the request EncodeAckPacket(&Buffer, Callsign); Send(Buffer, Ip); // add client if needed - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Callsign, Ip, EProtocol::dmrmmdvm); // client already connected ? if ( client == nullptr ) @@ -161,7 +161,7 @@ void CDmrmmdvmProtocol::Task(void) client->Alive(); } // and done - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else { @@ -176,13 +176,13 @@ void CDmrmmdvmProtocol::Task(void) std::cout << "DMRmmdvm disconnect packet from " << Callsign << " at " << Ip << std::endl; // find client & remove it - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Ip, EProtocol::dmrmmdvm); if ( client != nullptr ) { clients->RemoveClient(client); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else if ( IsValidConfigPacket(Buffer, &Callsign, Ip) ) { @@ -197,7 +197,7 @@ void CDmrmmdvmProtocol::Task(void) //std::cout << "DMRmmdvm keepalive packet from " << Callsign << " at " << Ip << std::endl; // find all clients with that callsign & ip and keep them alive - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(Callsign, Ip, EProtocol::dmrmmdvm, it)) != nullptr ) @@ -209,7 +209,7 @@ void CDmrmmdvmProtocol::Task(void) // and mark as alive client->Alive(); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else if ( IsValidRssiPacket(Buffer, &Callsign, &iRssi) ) { @@ -273,7 +273,7 @@ void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr &Hea CCallsign rpt2(Header->GetRpt2Callsign()); // no stream open yet, open a new one // firstfind this client - std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::dmrmmdvm); + std::shared_ptrclient = g_Refl..GetClients()->FindClient(Ip, EProtocol::dmrmmdvm); if ( client ) { // process cmd if any @@ -282,7 +282,7 @@ void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr &Hea // not linked yet if ( cmd == CMD_LINK ) { - if ( g_Reflector.IsValidModule(rpt2.GetCSModule()) ) + if ( g_Refl..IsValidModule(rpt2.GetCSModule()) ) { std::cout << "DMRmmdvm client " << client->GetCallsign() << " linking on module " << rpt2.GetCSModule() << std::endl; // link @@ -313,10 +313,10 @@ void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr &Hea } // and now, re-check module is valid && that it's not a private call - if ( g_Reflector.IsValidModule(rpt2.GetCSModule()) && (CallType == DMR_GROUP_CALL) ) + if ( g_Refl..IsValidModule(rpt2.GetCSModule()) && (CallType == DMR_GROUP_CALL) ) { // yes, try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr ) { // keep the handle m_Streams[stream->GetStreamId()] = stream; @@ -330,13 +330,13 @@ void CDmrmmdvmProtocol::OnDvHeaderPacketIn(std::unique_ptr &Hea } // release - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // update last heard if ( lastheard ) { - g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); - g_Reflector.ReleaseUsers(); + g_Refl..GetUsers()->Hearing(my, rpt1, rpt2); + g_Refl..ReleaseUsers(); } } } @@ -403,7 +403,7 @@ void CDmrmmdvmProtocol::HandleQueue(void) if ( buffer.size() > 0 ) { // and push it to all our clients linked to the module and who are not streaming in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::dmrmmdvm, it)) != nullptr ) @@ -416,7 +416,7 @@ void CDmrmmdvmProtocol::HandleQueue(void) } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } m_Queue.Unlock(); @@ -432,7 +432,7 @@ void CDmrmmdvmProtocol::HandleKeepalives(void) // and disconnect them if not // iterate on clients - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = 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::arraySet(tag, sizeof(tag)); uint8_t cs[12]; - + // DMR header // uiSeqId Buffer->Append((uint8_t)seqid); // uiSrcId uint32_t uiSrcId = Header.GetMyCallsign().GetDmrid(); DvFrame0.GetMyCallsign().GetCallsign(cs); - + if(uiSrcId == 0){ uiSrcId = DvFrame0.GetMyCallsign().GetDmrid(); } @@ -880,7 +880,7 @@ void CDmrmmdvmProtocol::EncodeMMDVMPacket(const CDvHeaderPacket &Header, const C if(uiSrcId == 0){ uiSrcId = DMRMMDVM_DEFAULTID; } - + AppendDmrIdToBuffer(Buffer, uiSrcId); // uiDstId = TG9 uint32_t uiDstId = 9; // ModuleToDmrDestId(Header.GetRpt2Module()); @@ -924,7 +924,7 @@ void CDmrmmdvmProtocol::EncodeMMDVMPacket(const CDvHeaderPacket &Header, const C // debug //CBuffer dump; //dump.Set(&(Buffer->data()[33]), 7); - //dump.DebugDump(g_Reflector.m_DebugFile); + //dump.DebugDump(g_Refl..m_DebugFile); // BER Buffer->Append((uint8_t)0); diff --git a/reflector/DMRPlusClient.cpp b/reflector/DMRPlusClient.cpp index d5c709a..7ae4a63 100644 --- a/reflector/DMRPlusClient.cpp +++ b/reflector/DMRPlusClient.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "DMRPlusClient.h" diff --git a/reflector/DMRPlusProtocol.cpp b/reflector/DMRPlusProtocol.cpp index a6bb453..db96a50 100644 --- a/reflector/DMRPlusProtocol.cpp +++ b/reflector/DMRPlusProtocol.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "DMRPlusClient.h" #include "DMRPlusProtocol.h" @@ -93,7 +93,7 @@ void CDmrplusProtocol::Task(void) else if ( IsValidDvHeaderPacket(Ip, Buffer, Header) ) { // callsign muted? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dmrplus) ) + if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dmrplus) ) { // handle it OnDvHeaderPacketIn(Header, Ip); @@ -104,14 +104,14 @@ void CDmrplusProtocol::Task(void) //std::cout << "DMRplus keepalive/connect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl; // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::dmrplus) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::dmrplus) ) { // acknowledge the request EncodeConnectAckPacket(&Buffer); Send(Buffer, Ip); // add client if needed - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Callsign, Ip, EProtocol::dmrplus); // client already connected ? if ( client == nullptr ) @@ -126,7 +126,7 @@ void CDmrplusProtocol::Task(void) client->Alive(); } // and done - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else { @@ -141,13 +141,13 @@ void CDmrplusProtocol::Task(void) std::cout << "DMRplus disconnect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl; // find client & remove it - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Ip, EProtocol::dmrplus); if ( client != nullptr ) { clients->RemoveClient(client); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else { @@ -196,21 +196,21 @@ void CDmrplusProtocol::OnDvHeaderPacketIn(std::unique_ptr &Head // no stream open yet, open a new one // find this client - std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::dmrplus); + std::shared_ptrclient = g_Refl..GetClients()->FindClient(Ip, EProtocol::dmrplus); if ( client ) { // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr ) { // keep the handle m_Streams[stream->GetStreamId()] = stream; } } // release - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // update last heard - g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); - g_Reflector.ReleaseUsers(); + g_Refl..GetUsers()->Hearing(my, rpt1, rpt2); + g_Refl..ReleaseUsers(); } } @@ -268,7 +268,7 @@ void CDmrplusProtocol::HandleQueue(void) if ( buffer.size() > 0 ) { // and push it to all our clients linked to the module and who are not streaming in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::dmrplus, it)) != nullptr ) @@ -280,10 +280,10 @@ void CDmrplusProtocol::HandleQueue(void) Send(buffer, client->GetIp()); } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // debug - //buffer.DebugDump(g_Reflector.m_DebugFile); + //buffer.DebugDump(g_Refl..m_DebugFile); } } m_Queue.Unlock(); @@ -294,7 +294,7 @@ void CDmrplusProtocol::SendBufferToClients(const CBuffer &buffer, uint8_t module if ( buffer.size() > 0 ) { // and push it to all our clients linked to the module and who are not streaming in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::dmrplus, it)) != nullptr ) @@ -306,10 +306,10 @@ void CDmrplusProtocol::SendBufferToClients(const CBuffer &buffer, uint8_t module Send(buffer, client->GetIp()); } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // debug - //buffer.DebugDump(g_Reflector.m_DebugFile); + //buffer.DebugDump(g_Refl..m_DebugFile); } } @@ -324,7 +324,7 @@ void CDmrplusProtocol::HandleKeepalives(void) // and disconnect them if not // iterate on clients - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::dmrplus, it)) != nullptr ) @@ -349,7 +349,7 @@ void CDmrplusProtocol::HandleKeepalives(void) } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } //////////////////////////////////////////////////////////////////////////////////////// diff --git a/reflector/DPlusClient.cpp b/reflector/DPlusClient.cpp index 098b86a..8e62ecd 100644 --- a/reflector/DPlusClient.cpp +++ b/reflector/DPlusClient.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "DPlusClient.h" diff --git a/reflector/DPlusProtocol.cpp b/reflector/DPlusProtocol.cpp index 1f135dd..a162229 100644 --- a/reflector/DPlusProtocol.cpp +++ b/reflector/DPlusProtocol.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "DPlusClient.h" #include "DPlusProtocol.h" @@ -72,7 +72,7 @@ void CDplusProtocol::Task(void) else if ( IsValidDvHeaderPacket(Buffer, Header) ) { // is muted? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dplus, Header->GetRpt2Module()) ) + if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::dplus, Header->GetRpt2Module()) ) { // handle it OnDvHeaderPacketIn(Header, Ip); @@ -90,15 +90,15 @@ void CDplusProtocol::Task(void) std::cout << "DPlus login packet from " << Callsign << " at " << Ip << std::endl; // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::dplus) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::dplus) ) { // acknowledge the request EncodeLoginAckPacket(&Buffer); Send(Buffer, Ip); // create the client and append - g_Reflector.GetClients()->AddClient(std::make_shared(Callsign, Ip)); - g_Reflector.ReleaseClients(); + g_Refl..GetClients()->AddClient(std::make_shared(Callsign, Ip)); + g_Refl..ReleaseClients(); } else { @@ -113,7 +113,7 @@ void CDplusProtocol::Task(void) std::cout << "DPlus disconnect packet from " << Ip << std::endl; // find client - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Ip, EProtocol::dplus); if ( client != nullptr ) { @@ -123,21 +123,21 @@ void CDplusProtocol::Task(void) EncodeDisconnectPacket(&Buffer); Send(Buffer, Ip); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else if ( IsValidKeepAlivePacket(Buffer) ) { //std::cout << "DPlus keepalive packet from " << Ip << std::endl; // find all clients with that callsign & ip and keep them alive - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(Ip, EProtocol::dplus, it)) != nullptr ) { client->Alive(); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else { @@ -185,10 +185,10 @@ void CDplusProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header CCallsign rpt2(Header->GetRpt2Callsign()); // first, check module is valid - if ( g_Reflector.IsValidModule(rpt2.GetCSModule()) ) + if ( g_Refl..IsValidModule(rpt2.GetCSModule()) ) { // find this client - std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::dplus); + std::shared_ptrclient = g_Refl..GetClients()->FindClient(Ip, EProtocol::dplus); if ( client ) { // now we know if it's a dextra dongle or a genuine dplus node @@ -204,18 +204,18 @@ void CDplusProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header // get client callsign rpt1 = client->GetCallsign(); // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr ) { // keep the handle m_Streams[stream->GetStreamId()] = stream; } } // release - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // update last heard - g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); - g_Reflector.ReleaseUsers(); + g_Refl..GetUsers()->Hearing(my, rpt1, rpt2); + g_Refl..ReleaseUsers(); } else { @@ -253,7 +253,7 @@ void CDplusProtocol::HandleQueue(void) // and push it to all our clients who are not streaming in // note that for dplus protocol, all stream of all modules are push to all clients // it's client who decide which stream he's interrrested in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::dplus, it)) != nullptr ) @@ -290,7 +290,7 @@ void CDplusProtocol::HandleQueue(void) } } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } m_Queue.Unlock(); @@ -343,7 +343,7 @@ void CDplusProtocol::HandleKeepalives(void) EncodeKeepAlivePacket(&keepalive); // iterate on clients - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::dplus, it)) != nullptr ) @@ -371,7 +371,7 @@ void CDplusProtocol::HandleKeepalives(void) clients->RemoveClient(client); } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } //////////////////////////////////////////////////////////////////////////////////////// diff --git a/reflector/DVFramePacket.cpp b/reflector/DVFramePacket.cpp index 9db20b5..86f1d61 100644 --- a/reflector/DVFramePacket.cpp +++ b/reflector/DVFramePacket.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "DVFramePacket.h" diff --git a/reflector/DVHeaderPacket.cpp b/reflector/DVHeaderPacket.cpp index ab47c3b..7bf6082 100644 --- a/reflector/DVHeaderPacket.cpp +++ b/reflector/DVHeaderPacket.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include #include "DMRIdDir.h" @@ -90,7 +90,7 @@ CDvHeaderPacket::CDvHeaderPacket(const struct dstar_header *buffer, uint16_t sid m_uiFlag2 = buffer->Flag2; m_uiFlag3 = buffer->Flag3; m_csUR.SetCallsign(buffer->UR, CALLSIGN_LEN); - + if((buffer->RPT1)[7] == 0x20){ char rptr1[8]; memcpy(rptr1, buffer->RPT1, 8); @@ -100,7 +100,7 @@ CDvHeaderPacket::CDvHeaderPacket(const struct dstar_header *buffer, uint16_t sid else{ m_csRPT1.SetCallsign(buffer->RPT1, CALLSIGN_LEN); } - + m_csRPT1.SetCallsign(buffer->RPT1, CALLSIGN_LEN); m_csRPT2.SetCallsign(buffer->RPT2, CALLSIGN_LEN); m_csMY.SetCallsign(buffer->MY, CALLSIGN_LEN); diff --git a/reflector/Defines.h b/reflector/Defines.h new file mode 100644 index 0000000..690b01f --- /dev/null +++ b/reflector/Defines.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 . + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//////////////////////////////////////////////////////////////////////////////////////// +// 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)) diff --git a/reflector/G3Client.cpp b/reflector/G3Client.cpp index 9b6cbc5..f69e6fc 100644 --- a/reflector/G3Client.cpp +++ b/reflector/G3Client.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "G3Client.h" diff --git a/reflector/G3Protocol.cpp b/reflector/G3Protocol.cpp index 1368e54..0d5f62c 100644 --- a/reflector/G3Protocol.cpp +++ b/reflector/G3Protocol.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include #include "G3Client.h" @@ -37,7 +37,7 @@ bool CG3Protocol::Initialize(const char */*type*/, const EProtocol /*type*/, con ReadOptions(); // init reflector apparent callsign - m_ReflectorCallsign = g_Reflector.GetCallsign(); + m_ReflectorCallsign = g_Refl..GetCallsign(); // reset stop flag keep_running = true; @@ -177,7 +177,7 @@ void CG3Protocol::PresenceTask(void) Buffer.Append(m_GwAddress); } - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrextant = nullptr; while ( (extant = clients->FindNextClient(EProtocol::g3, it)) != nullptr ) @@ -219,7 +219,7 @@ void CG3Protocol::PresenceTask(void) clients->AddClient(std::make_shared(Terminal, Ip)); } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); m_PresenceSocket.Send(Buffer, ReqIp); } @@ -260,7 +260,7 @@ void CG3Protocol::ConfigTask(void) if (isRepeaterCall) { - if ((Call.HasSameCallsign(GetReflectorCallsign())) && (g_Reflector.IsValidModule(Call.GetCSModule()))) + if ((Call.HasSameCallsign(GetReflectorCallsign())) && (g_Refl..IsValidModule(Call.GetCSModule()))) { Buffer.data()[3] = 0x00; // ok } @@ -343,7 +343,7 @@ void CG3Protocol::IcmpTask(void) { if (iIcmpType == ICMP_DEST_UNREACH) { - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::g3, it)) != nullptr ) @@ -354,7 +354,7 @@ void CG3Protocol::IcmpTask(void) clients->RemoveClient(client); } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } } @@ -378,7 +378,7 @@ void CG3Protocol::Task(void) { CIp ClIp; CIp *BaseIp = nullptr; - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::g3, it)) != nullptr ) @@ -394,7 +394,7 @@ void CG3Protocol::Task(void) break; } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); if (BaseIp != nullptr) { @@ -406,7 +406,7 @@ void CG3Protocol::Task(void) else if ( IsValidDvHeaderPacket(Buffer, Header) ) { // callsign muted? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::g3, Header->GetRpt2Module()) ) + if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::g3, Header->GetRpt2Module()) ) { // handle it OnDvHeaderPacketIn(Header, *BaseIp); @@ -454,7 +454,7 @@ void CG3Protocol::HandleQueue(void) if ( EncodeDvPacket(*packet, buffer) ) { // and push it to all our clients linked to the module and who are not streaming in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::g3, it)) != nullptr ) @@ -470,7 +470,7 @@ void CG3Protocol::HandleQueue(void) } } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } m_Queue.Unlock(); @@ -487,7 +487,7 @@ void CG3Protocol::HandleKeepalives(void) CBuffer keepalive((uint8_t *)"PING", 4); // iterate on clients - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::g3, it)) != nullptr ) @@ -502,7 +502,7 @@ void CG3Protocol::HandleKeepalives(void) Send(keepalive, client->GetIp()); } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -527,7 +527,7 @@ void CG3Protocol::OnDvHeaderPacketIn(std::unique_ptr &Header, c CCallsign rpt2(Header->GetRpt2Callsign()); // find this client - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::g3, it)) != nullptr ) @@ -554,7 +554,7 @@ void CG3Protocol::OnDvHeaderPacketIn(std::unique_ptr &Header, c } else { - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); return; } } @@ -563,19 +563,19 @@ void CG3Protocol::OnDvHeaderPacketIn(std::unique_ptr &Header, c rpt1 = client->GetCallsign(); // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr ) { // keep the handle m_Streams[stream->GetStreamId()] = stream; } // update last heard - g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); - g_Reflector.ReleaseUsers(); + g_Refl..GetUsers()->Hearing(my, rpt1, rpt2); + g_Refl..ReleaseUsers(); } } // release - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } @@ -679,7 +679,7 @@ void CG3Protocol::NeedReload(void) ReadOptions(); // we have new options - iterate on clients for potential removal - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::g3, it)) != nullptr ) @@ -690,7 +690,7 @@ void CG3Protocol::NeedReload(void) clients->RemoveClient(client); } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } } diff --git a/reflector/GateKeeper.cpp b/reflector/GateKeeper.cpp index e00043a..2e96e04 100644 --- a/reflector/GateKeeper.cpp +++ b/reflector/GateKeeper.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "Timer.h" #include "GateKeeper.h" diff --git a/reflector/GateKeeper.h b/reflector/GateKeeper.h index a35316f..4b5814d 100644 --- a/reflector/GateKeeper.h +++ b/reflector/GateKeeper.h @@ -19,7 +19,7 @@ #pragma once -#include "Main.h" +#include "Defines.h" #include "Callsign.h" #include "IP.h" #include "CallsignList.h" diff --git a/reflector/DMRIdDirHttp.h b/reflector/Global.h similarity index 58% rename from reflector/DMRIdDirHttp.h rename to reflector/Global.h index 54d2577..39c515d 100644 --- a/reflector/DMRIdDirHttp.h +++ b/reflector/Global.h @@ -1,7 +1,5 @@ -// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. - // urfd -- The universal reflector -// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2023 Thomas A. Early N7TAE // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -16,25 +14,18 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#pragma once - -#include "DMRIdDir.h" - -class CDmridDirHttp : public CDmridDir -{ -public: - // constructor - CDmridDirHttp() {} - - // destructor - ~CDmridDirHttp() {} - - // refresh - bool LoadContent(CBuffer *); - bool RefreshContent(const CBuffer &); +#include "Reflector.h" +#include "GateKeeper.h" +#include "Configure.h" +#include "Version.h" +#include "LookupDmr.h" +#include "LookupNxdn.h" +#include "LookupYsf.h" -protected: - // reload helpers - bool NeedReload(void) { return true; } - bool HttpGet(const char *, const char *, int, CBuffer *); -}; +extern CReflector g_Refl; +extern CGateKeeper g_Gate; +extern CConfigure g_Conf; +extern CVersion g_Vers; +extern CLookupDmr g_LDid; +extern CLookupNxdn g_LNid; +extern CLookupYsf g_LYtr; diff --git a/reflector/Lookup.cpp b/reflector/Lookup.cpp new file mode 100644 index 0000000..fa85586 --- /dev/null +++ b/reflector/Lookup.cpp @@ -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 . + +#include +#include +#include +#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)); + } +} diff --git a/reflector/DMRIdDir.h b/reflector/Lookup.h similarity index 54% rename from reflector/DMRIdDir.h rename to reflector/Lookup.h index e4b8935..86ef905 100644 --- a/reflector/DMRIdDir.h +++ b/reflector/Lookup.h @@ -1,7 +1,7 @@ // Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. // urfd -- The universal reflector -// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2023 Thomas A. Early N7TAE // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,68 +18,60 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include #include "Buffer.h" #include "Callsign.h" +#include "Configure.h" // compare function for std::map::find -struct CDmridDirCallsignCompare +struct CCallsignCompare { bool operator() (const CCallsign &cs1, const CCallsign &cs2) const - { return cs1.HasLowerCallsign(cs2);} + { + return cs1.HasLowerCallsign(cs2); + } }; //////////////////////////////////////////////////////////////////////////////////////// -class CDmridDir +class CLookup { public: // constructor - CDmridDir(); + CLookup() : keep_running(true), m_LastModTime(0) {} // destructor - ~CDmridDir(); + virtual ~CLookup(); - // init & close - virtual bool Init(void); - virtual void Close(void); + void LookupInit(); + void LookupClose(); // locks - void Lock(void) { m_Mutex.lock(); } - void Unlock(void) { m_Mutex.unlock(); } - - // refresh - virtual bool LoadContent(CBuffer *) { return false; } - virtual bool RefreshContent(const CBuffer &) { return false; } - - // find - const CCallsign *FindCallsign(uint32_t); - uint32_t FindDmrid(const CCallsign &); + void Lock(void) { m_Mutex.lock(); } + void Unlock(void) { m_Mutex.unlock(); } protected: - // thread + std::time_t GetLastModTime(); + virtual void LoadParameters() = 0; + virtual void ClearContents() = 0; void Thread(); - // reload helpers - bool Reload(void); - virtual bool NeedReload(void) { return false; } - bool IsValidDmrid(const char *); - -protected: - // data - std::map m_CallsignMap; - std::map m_DmridMap; + // refresh + virtual bool LoadContentFile(CBuffer &buf) = 0; + virtual bool LoadContentHttp(CBuffer &buf) = 0; + virtual void RefreshContentFile(const CBuffer &) = 0; + virtual void RefreshContentHttp(const CBuffer &) = 0; - // Lock() std::mutex m_Mutex; + ERefreshType m_Type; + unsigned m_Refresh; + std::string m_Path, m_Host, m_Suffix; + std::time_t m_LastModTime; - // thread std::atomic keep_running; std::future m_Future; - }; diff --git a/reflector/LookupDmr.cpp b/reflector/LookupDmr.cpp new file mode 100644 index 0000000..af61349 --- /dev/null +++ b/reflector/LookupDmr.cpp @@ -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 . + +#include +#include +#include +#include + +#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(ui, cs)); + m_DmridMap.insert(std::pair(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(ui, cs)); + m_DmridMap.insert(std::pair(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; +} diff --git a/reflector/NXDNIdDirHttp.h b/reflector/LookupDmr.h similarity index 56% rename from reflector/NXDNIdDirHttp.h rename to reflector/LookupDmr.h index c26311c..d0e478b 100644 --- a/reflector/NXDNIdDirHttp.h +++ b/reflector/LookupDmr.h @@ -1,7 +1,7 @@ // Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. // urfd -- The universal reflector -// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2023 Thomas A. Early N7TAE // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,23 +18,26 @@ #pragma once -#include "NXDNIdDir.h" +#include "Lookup.h" -class CNXDNidDirHttp : public CNXDNidDir +class CLookupDmr : public CLookup { public: - // constructor - CNXDNidDirHttp() {} + uint32_t FindDmrid(const CCallsign &cs); + const CCallsign *FindCallsign(uint32_t dmrid); - // destructor - ~CNXDNidDirHttp() {} +protected: + void ClearContents(); + void LoadParameters(); + bool LoadContentFile(CBuffer &buf); + bool LoadContentHttp(CBuffer &buf); + void RefreshContentFile(const CBuffer &); + void RefreshContentHttp(const CBuffer &); - // refresh - bool LoadContent(CBuffer *); - bool RefreshContent(const CBuffer &); +private: + std::map m_CallsignMap; + std::map m_DmridMap; -protected: - // reload helpers - bool NeedReload(void) { return true; } - bool HttpGet(const char *, const char *, int, CBuffer *); + bool IsValidDmrId(const char *); + bool HttpGet(const char *, const char *, int, CBuffer &); }; diff --git a/reflector/LookupNxdn.cpp b/reflector/LookupNxdn.cpp new file mode 100644 index 0000000..624cdbd --- /dev/null +++ b/reflector/LookupNxdn.cpp @@ -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 . + +#include +#include +#include +#include + +#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(us, cs)); + m_NxdnidMap.insert(std::pair(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(us, cs)); + m_NxdnidMap.insert(std::pair(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; +} diff --git a/reflector/DMRIdDirFile.h b/reflector/LookupNxdn.h similarity index 56% rename from reflector/DMRIdDirFile.h rename to reflector/LookupNxdn.h index e4f4054..36f2be6 100644 --- a/reflector/DMRIdDirFile.h +++ b/reflector/LookupNxdn.h @@ -1,7 +1,7 @@ // Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. // urfd -- The universal reflector -// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2023 Thomas A. Early N7TAE // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,30 +18,25 @@ #pragma once -#include "DMRIdDir.h" +#include "Lookup.h" -class CDmridDirFile : public CDmridDir +class CLookupNxdn : public CLookup { public: - // constructor - CDmridDirFile(); - - // destructor - ~CDmridDirFile() {} - - // init & close - bool Init(void); - - // refresh - bool LoadContent(CBuffer *); - bool RefreshContent(const CBuffer &); - -protected: - // reload helpers - bool NeedReload(void); - bool GetLastModTime(time_t *); - + uint16_t FindNXDNid(const CCallsign &callsign); + const CCallsign *FindCallsign(uint16_t id); protected: - // data - time_t m_LastModTime; + void ClearContents(); + void LoadParameters(); + bool LoadContentFile(CBuffer &buf); + bool LoadContentHttp(CBuffer &buf); + void RefreshContentFile(const CBuffer &); + void RefreshContentHttp(const CBuffer &); + +private: + std::map m_CallsignMap; + std::map m_NxdnidMap; + + bool IsValidNxdnId(const char *); + bool HttpGet(const char *, const char *, int, CBuffer &); }; diff --git a/reflector/LookupYsf.cpp b/reflector/LookupYsf.cpp new file mode 100644 index 0000000..96e556c --- /dev/null +++ b/reflector/LookupYsf.cpp @@ -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 . + +#include +#include +#include +#include +#include + +#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(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(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; + } +} diff --git a/reflector/NXDNIdDirFile.h b/reflector/LookupYsf.h similarity index 59% rename from reflector/NXDNIdDirFile.h rename to reflector/LookupYsf.h index f4fe8c9..3501309 100644 --- a/reflector/NXDNIdDirFile.h +++ b/reflector/LookupYsf.h @@ -1,7 +1,7 @@ // Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. // urfd -- The universal reflector -// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2023 Thomas A. Early N7TAE // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -18,30 +18,26 @@ #pragma once -#include "NXDNIdDir.h" +#include "YSFNode.h" +#include "Lookup.h" -class CNXDNidDirFile : public CNXDNidDir +using CsNodeMap = std::map; + +class CLookupYsf : public CLookup { public: - // constructor - CNXDNidDirFile(); - - // destructor - ~CNXDNidDirFile() {} - - // init & close - bool Init(void); - - // refresh - bool LoadContent(CBuffer *); - bool RefreshContent(const CBuffer &); + bool FindFrequencies(const CCallsign &, uint32_t *, uint32_t *); protected: - // reload helpers - bool NeedReload(void); - bool GetLastModTime(time_t *); + void ClearContents(); + void LoadParameters(); + bool LoadContentFile(CBuffer &buf); + bool LoadContentHttp(CBuffer &buf); + void RefreshContentFile(const CBuffer &); + void RefreshContentHttp(const CBuffer &); -protected: - // data - time_t m_LastModTime; +private: + CsNodeMap m_map; + + bool HttpGet(const char *, const char *, int, CBuffer &); }; diff --git a/reflector/M17Client.cpp b/reflector/M17Client.cpp index c4cb8c4..888e469 100644 --- a/reflector/M17Client.cpp +++ b/reflector/M17Client.cpp @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "M17Client.h" diff --git a/reflector/M17Protocol.cpp b/reflector/M17Protocol.cpp index df228f9..ce3b1b8 100644 --- a/reflector/M17Protocol.cpp +++ b/reflector/M17Protocol.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "M17Client.h" #include "M17Protocol.h" @@ -69,7 +69,7 @@ void CM17Protocol::Task(void) if ( IsValidDvPacket(Buffer, Header, Frame) ) { // callsign muted? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::m17, Header->GetRpt2Module()) ) + if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::m17, Header->GetRpt2Module()) ) { OnDvHeaderPacketIn(Header, Ip); @@ -93,17 +93,17 @@ void CM17Protocol::Task(void) std::cout << "M17 connect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl; // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::m17) && g_Reflector.IsValidModule(ToLinkModule) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::m17) && g_Refl..IsValidModule(ToLinkModule) ) { // valid module ? - if ( g_Reflector.IsValidModule(ToLinkModule) ) + if ( g_Refl..IsValidModule(ToLinkModule) ) { // acknowledge the request Send("ACKN", Ip); // create the client and append - g_Reflector.GetClients()->AddClient(std::make_shared(Callsign, Ip, ToLinkModule)); - g_Reflector.ReleaseClients(); + g_Refl..GetClients()->AddClient(std::make_shared(Callsign, Ip, ToLinkModule)); + g_Refl..ReleaseClients(); } else { @@ -125,7 +125,7 @@ void CM17Protocol::Task(void) std::cout << "M17 disconnect packet from " << Callsign << " at " << Ip << std::endl; // find client - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Ip, EProtocol::m17); if ( client != nullptr ) { @@ -134,19 +134,19 @@ void CM17Protocol::Task(void) // and acknowledge the disconnect Send("DISC", Ip); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else if ( IsValidKeepAlivePacket(Buffer, Callsign) ) { // find all clients with that callsign & ip and keep them alive - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(Callsign, Ip, EProtocol::m17, it)) != nullptr ) { client->Alive(); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else { @@ -196,24 +196,24 @@ void CM17Protocol::OnDvHeaderPacketIn(std::unique_ptr &Header, CCallsign rpt2(Header->GetRpt2Callsign()); // find this client - std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::m17); + std::shared_ptrclient = g_Refl..GetClients()->FindClient(Ip, EProtocol::m17); if ( client ) { // get client callsign rpt1 = client->GetCallsign(); // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr ) { // keep the handle m_Streams[stream->GetStreamId()] = stream; } } // release - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // update last heard - g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); - g_Reflector.ReleaseUsers(); + g_Refl..GetUsers()->Hearing(my, rpt1, rpt2); + g_Refl..ReleaseUsers(); } } @@ -249,7 +249,7 @@ void CM17Protocol::HandleQueue(void) EncodeM17Packet(frame, m_StreamsCache[module].m_dvHeader, (CDvFramePacket *)packet.get(), m_StreamsCache[module].m_iSeqCounter); // push it to all our clients linked to the module and who are not streaming in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::m17, it)) != nullptr ) @@ -266,7 +266,7 @@ void CM17Protocol::HandleQueue(void) } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } m_StreamsCache[module].m_iSeqCounter++; } @@ -286,7 +286,7 @@ void CM17Protocol::HandleKeepalives(void) EncodeKeepAlivePacket(keepalive); // iterate on clients - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::m17, it)) != nullptr ) @@ -312,7 +312,7 @@ void CM17Protocol::HandleKeepalives(void) } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -389,7 +389,7 @@ void CM17Protocol::EncodeKeepAlivePacket(CBuffer &Buffer) { Buffer.resize(10); memcpy(Buffer.data(), "PING", 4); - g_Reflector.GetCallsign().CodeOut(Buffer.data() + 4); + g_Refl..GetCallsign().CodeOut(Buffer.data() + 4); } void CM17Protocol::EncodeM17Packet(SM17Frame &frame, const CDvHeaderPacket &Header, const CDvFramePacket *DvFrame, uint32_t iSeq) const diff --git a/reflector/Main.cpp b/reflector/Main.cpp index 8a19a5d..556c2ab 100644 --- a/reflector/Main.cpp +++ b/reflector/Main.cpp @@ -16,59 +16,59 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" -#include "Reflector.h" - #include +#include "Global.h" //////////////////////////////////////////////////////////////////////////////////////// // global objects -CReflector g_Reflector; +CReflector g_Refl; +CGateKeeper g_Gate; +CConfigure g_Conf; +CVersion g_Vers(3,0,0); // The major byte should only change if the interlink packet changes! +CLookupDmr g_LDid; +CLookupNxdn g_LNid; +CLookupYsf g_LYtr; //////////////////////////////////////////////////////////////////////////////////////// -// function declaration - -#include "Users.h" -int main() +int main(int argc, char *argv[]) { - const std::string cs(CALLSIGN); - if ((cs.size() != 6) || cs.compare(0, 3, "URF")) + if (argc != 2) { - std::cerr << "Malformed reflector callsign: '" << cs << "', aborting!" << std::endl; + std::cerr << "No configuration file specifed! Usage: " << argv[0] << " /pathname/to/configuration/file" << std::endl; return EXIT_FAILURE; } + if (g_Conf.ReadData(argv[1])) + return EXIT_FAILURE; + // remove pidfile - remove(PIDFILE_PATH); + const std::string pidpath(g_Conf.GetString(g_Conf.j.files.pid)); + const std::string callsign(g_Conf.GetString(g_Conf.j.names.cs)); + remove(pidpath.c_str()); // splash - std::cout << "Starting " << cs << " " << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_REVISION << std::endl << std::endl; - -#ifdef TRANSCODER_IS_REMOTE - g_Reflector.SetTranscoderIp(TRANSCODER_IP, INET6_ADDRSTRLEN); -#endif - + std::cout << "Starting " << callsign << " " << g_Vers << std::endl; // and let it run - if ( !g_Reflector.Start() ) + if (g_Refl.Start()) { std::cout << "Error starting reflector" << std::endl; return EXIT_FAILURE; } - std::cout << "Reflector " << g_Reflector.GetCallsign() << "started and listening" << std::endl; + std::cout << "Reflector " << callsign << "started and listening" << std::endl; // write new pid file - std::ofstream ofs(PIDFILE_PATH, std::ofstream::out); + std::ofstream ofs(pidpath, std::ofstream::out); ofs << getpid() << std::endl; ofs.close(); pause(); // wait for any signal - g_Reflector.Stop(); + g_Refl.Stop(); std::cout << "Reflector stopped" << std::endl; // done diff --git a/reflector/Main.h b/reflector/Main.h deleted file mode 100644 index 0392c5a..0000000 --- a/reflector/Main.h +++ /dev/null @@ -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 . - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 diff --git a/reflector/NXDNClient.cpp b/reflector/NXDNClient.cpp index 64cb428..37b933e 100644 --- a/reflector/NXDNClient.cpp +++ b/reflector/NXDNClient.cpp @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "NXDNClient.h" diff --git a/reflector/NXDNIdDir.cpp b/reflector/NXDNIdDir.cpp deleted file mode 100644 index 2d5d8d3..0000000 --- a/reflector/NXDNIdDir.cpp +++ /dev/null @@ -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 . - -#include -#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; -} diff --git a/reflector/NXDNIdDir.h b/reflector/NXDNIdDir.h deleted file mode 100644 index 4d9a8af..0000000 --- a/reflector/NXDNIdDir.h +++ /dev/null @@ -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 . - -#pragma once - -#include -#include -#include -#include -#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 m_CallsignMap; - std::map m_NXDNidMap; - - // Lock() - std::mutex m_Mutex; - - // thread - std::atomic keep_running; - std::future m_Future; - -}; diff --git a/reflector/NXDNIdDirFile.cpp b/reflector/NXDNIdDirFile.cpp deleted file mode 100644 index 73b4d95..0000000 --- a/reflector/NXDNIdDirFile.cpp +++ /dev/null @@ -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 . - -#include -#include -#include -#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(us, cs)); - m_NXDNidMap.insert(std::pair(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; -} diff --git a/reflector/NXDNIdDirHttp.cpp b/reflector/NXDNIdDirHttp.cpp deleted file mode 100644 index 94bbc22..0000000 --- a/reflector/NXDNIdDirHttp.cpp +++ /dev/null @@ -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 . - -#include -#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(us, cs)); - m_NXDNidMap.insert(std::pair(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; -} diff --git a/reflector/NXDNProtocol.cpp b/reflector/NXDNProtocol.cpp index e26135c..8b2fcfc 100644 --- a/reflector/NXDNProtocol.cpp +++ b/reflector/NXDNProtocol.cpp @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "NXDNClient.h" #include "NXDNProtocol.h" @@ -103,7 +103,7 @@ void CNXDNProtocol::Task(void) else if ( IsValidDvHeaderPacket(Ip, Buffer, Header) ) { // node linked and callsign muted? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::nxdn, Header->GetRpt2Module()) ) + if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::nxdn, Header->GetRpt2Module()) ) { // handle it OnDvHeaderPacketIn(Header, Ip); @@ -116,10 +116,10 @@ void CNXDNProtocol::Task(void) else if ( IsValidConnectPacket(Buffer, &Callsign) ) { // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::nxdn) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::nxdn) ) { // add client if needed - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Callsign, Ip, EProtocol::nxdn); // client already connected ? if ( client == nullptr ) @@ -141,11 +141,11 @@ void CNXDNProtocol::Task(void) { client->Alive(); } - + // acknowledge the request -- NXDNReflector simply echoes the packet Send(Buffer, Ip); // and done - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } else if ( IsValidDisconnectPacket(Buffer) ) @@ -153,14 +153,14 @@ void CNXDNProtocol::Task(void) std::cout << "NXDN disconnect packet from " << Ip << std::endl; // find client - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Ip, EProtocol::nxdn); if ( client != nullptr ) { // remove it clients->RemoveClient(client); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else { @@ -210,7 +210,7 @@ void CNXDNProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header, CCallsign rpt2(Header->GetRpt2Callsign()); // find this client - std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::nxdn); + std::shared_ptrclient = g_Refl..GetClients()->FindClient(Ip, EProtocol::nxdn); if ( client ) { // get client callsign @@ -221,20 +221,20 @@ void CNXDNProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header, rpt2.SetCSModule(m); // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr ) { // keep the handle m_Streams[stream->GetStreamId()] = stream; } } // release - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // update last heard - if ( g_Reflector.IsValidModule(rpt2.GetCSModule()) ) + if ( g_Refl..IsValidModule(rpt2.GetCSModule()) ) { - g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); - g_Reflector.ReleaseUsers(); + g_Refl..GetUsers()->Hearing(my, rpt1, rpt2); + g_Refl..ReleaseUsers(); } } } @@ -292,7 +292,7 @@ void CNXDNProtocol::HandleQueue(void) if ( buffer.size() > 0 ) { // and push it to all our clients linked to the module and who are not streaming in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::nxdn, it)) != nullptr ) @@ -305,7 +305,7 @@ void CNXDNProtocol::HandleQueue(void) } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } m_Queue.Unlock(); @@ -321,7 +321,7 @@ void CNXDNProtocol::HandleKeepalives(void) // and disconnect them if not // iterate on clients - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::nxdn, it)) != nullptr ) @@ -341,7 +341,7 @@ void CNXDNProtocol::HandleKeepalives(void) } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -408,24 +408,24 @@ bool CNXDNProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer, s rpt1.SetCSModule(NXDN_MODULE_ID); rpt2.SetCSModule(' '); header = std::unique_ptr(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, false)); - - if ( g_GateKeeper.MayTransmit(header->GetMyCallsign(), Ip, EProtocol::nxdn, header->GetRpt2Module()) ) + + if ( g_Gate.MayTransmit(header->GetMyCallsign(), Ip, EProtocol::nxdn, header->GetRpt2Module()) ) { - OnDvHeaderPacketIn(header, Ip); + OnDvHeaderPacketIn(header, Ip); } } // get DV frames uint8_t ambe49[7]; - + uint8_t ambe0[9]; uint8_t ambe1[9]; uint8_t ambe2[9]; uint8_t ambe3[9]; - + memcpy(ambe49, Buffer.data() + 15, 7); encode(ambe49, ambe0); - + uint8_t t[7]; const uint8_t *d = &(Buffer.data()[21]); for(int i = 0; i < 6; ++i){ @@ -436,10 +436,10 @@ bool CNXDNProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer, s memcpy(ambe49, t, 7); encode(ambe49, ambe1); - + memcpy(ambe49, Buffer.data() + 29, 7); encode(ambe49, ambe2); - + d = &(Buffer.data()[35]); for(int i = 0; i < 6; ++i){ t[i] = d[i] << 1; @@ -480,14 +480,14 @@ bool CNXDNProtocol::EncodeNXDNHeaderPacket(const CDvHeaderPacket &Header, CBuffe Buffer.resize(43); uint16_t NXDNId = Header.GetMyCallsign().GetNXDNid(); uint16_t RptrId = NXDN_REFID; - + memcpy(Buffer.data(), "NXDND", 5); Buffer.data()[5U] = (NXDNId >> 8) & 0xFFU; Buffer.data()[6U] = (NXDNId >> 0) & 0xFFU; Buffer.data()[7U] = (RptrId >> 8) & 0xFFU; Buffer.data()[8U] = (RptrId >> 0) & 0xFFU; Buffer.data()[9U] = 0x01U; - + const uint8_t idle[3U] = {0x10, 0x00, 0x00}; m_lich = 0; memset(m_sacch, 0, 5U); @@ -514,7 +514,7 @@ bool CNXDNProtocol::EncodeNXDNHeaderPacket(const CDvHeaderPacket &Header, CBuffe set_layer3_blks(0U); memcpy(&Buffer.data()[15U], m_layer3, 14U); memcpy(&Buffer.data()[29U], m_layer3, 14U); - + if (Buffer.data()[10U] == 0x81U || Buffer.data()[10U] == 0x83U) { Buffer.data()[9U] |= Buffer.data()[15U] == 0x01U ? 0x04U : 0x00U; Buffer.data()[9U] |= Buffer.data()[15U] == 0x08U ? 0x08U : 0x00U; @@ -526,7 +526,7 @@ bool CNXDNProtocol::EncodeNXDNHeaderPacket(const CDvHeaderPacket &Header, CBuffe Buffer.data()[9U] |= Buffer.data()[12U] == 0x08U ? 0x08U : 0x00U; } } - + return true; } @@ -536,14 +536,14 @@ bool CNXDNProtocol::EncodeNXDNPacket(const CDvHeaderPacket &Header, uint32_t seq Buffer.resize(43); uint16_t NXDNId = Header.GetMyCallsign().GetNXDNid(); uint16_t RptrId = NXDN_REFID; - + memcpy(Buffer.data(), "NXDND", 5); Buffer.data()[5U] = (NXDNId >> 8) & 0xFFU; Buffer.data()[6U] = (NXDNId >> 0) & 0xFFU; Buffer.data()[7U] = (RptrId >> 8) & 0xFFU; Buffer.data()[8U] = (RptrId >> 0) & 0xFFU; Buffer.data()[9U] = 0x01U; - + uint8_t msg[3U]; m_lich = 0; memset(m_sacch, 0, 5U); @@ -590,7 +590,7 @@ bool CNXDNProtocol::EncodeNXDNPacket(const CDvHeaderPacket &Header, uint32_t seq for(int i = 0; i < 4; ++i){ decode(DvFrames[i].GetCodecData(ECodecType::dmr), ambe+(i*7)); } - + memcpy(&Buffer.data()[15], ambe, 7); for(int i = 0; i < 7; ++i){ Buffer.data()[21+i] |= (ambe[7+i] >> 1); @@ -604,7 +604,7 @@ bool CNXDNProtocol::EncodeNXDNPacket(const CDvHeaderPacket &Header, uint32_t seq Buffer.data()[36+i] = (ambe[21+i] & 1) << 7; } Buffer.data()[41] |= (ambe[27] >> 2); - + return true; } @@ -657,11 +657,11 @@ void CNXDNProtocol::decode(const unsigned char* in, unsigned char* out) const void CNXDNProtocol::encode(const unsigned char* in, unsigned char* out) const { - + unsigned int aOrig = 0U; unsigned int bOrig = 0U; unsigned int cOrig = 0U; - + unsigned int MASK = 0x000800U; for (unsigned int i = 0U; i < 12U; i++, MASK >>= 1) { unsigned int n1 = i + 0U; @@ -838,4 +838,3 @@ void CNXDNProtocol::encode_crc6(uint8_t *d, uint8_t len) WRITE_BIT(d, n, b); } } - diff --git a/reflector/Notification.cpp b/reflector/Notification.cpp index 71208e3..6808a02 100644 --- a/reflector/Notification.cpp +++ b/reflector/Notification.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "Notification.h" CNotification::CNotification() diff --git a/reflector/P25Client.cpp b/reflector/P25Client.cpp index 18a0bcb..91c8041 100644 --- a/reflector/P25Client.cpp +++ b/reflector/P25Client.cpp @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "P25Client.h" diff --git a/reflector/P25Protocol.cpp b/reflector/P25Protocol.cpp index 9cbe14a..e50e007 100644 --- a/reflector/P25Protocol.cpp +++ b/reflector/P25Protocol.cpp @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "P25Client.h" #include "P25Protocol.h" @@ -93,7 +93,7 @@ void CP25Protocol::Task(void) if( !m_uiStreamId && IsValidDvHeaderPacket(Ip, Buffer, Header) ) { // callsign muted? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::p25) ) + if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::p25) ) { OnDvHeaderPacketIn(Header, Ip); } @@ -104,10 +104,10 @@ void CP25Protocol::Task(void) else if ( IsValidConnectPacket(Buffer, &Callsign) ) { // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::p25) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::p25) ) { // add client if needed - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Callsign, Ip, EProtocol::p25); // client already connected ? if ( client == nullptr ) @@ -129,11 +129,11 @@ void CP25Protocol::Task(void) { client->Alive(); } - + // acknowledge the request -- P25Reflector simply echoes the packet Send(Buffer, Ip); // and done - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } else if ( IsValidDisconnectPacket(Buffer, &Callsign) ) @@ -141,14 +141,14 @@ void CP25Protocol::Task(void) std::cout << "P25 disconnect packet from " << Callsign << " at " << Ip << std::endl; // find client - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Ip, EProtocol::p25); if ( client != nullptr ) { // remove it clients->RemoveClient(client); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else { @@ -197,7 +197,7 @@ void CP25Protocol::OnDvHeaderPacketIn(std::unique_ptr &Header, CCallsign rpt2(Header->GetRpt2Callsign()); // find this client - std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::p25); + std::shared_ptrclient = g_Refl..GetClients()->FindClient(Ip, EProtocol::p25); if ( client ) { // get client callsign @@ -206,18 +206,18 @@ void CP25Protocol::OnDvHeaderPacketIn(std::unique_ptr &Header, Header->SetRpt2Module(m); rpt2.SetCSModule(m); // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr ) { // keep the handle m_Streams[stream->GetStreamId()] = stream; } } // release - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // update last heard - g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); - g_Reflector.ReleaseUsers(); + g_Refl..GetUsers()->Hearing(my, rpt1, rpt2); + g_Refl..ReleaseUsers(); } } @@ -256,7 +256,7 @@ void CP25Protocol::HandleQueue(void) if ( buffer.size() > 0 ) { // and push it to all our clients linked to the module and who are not streaming in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::p25, it)) != nullptr ) @@ -269,7 +269,7 @@ void CP25Protocol::HandleQueue(void) } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } } @@ -308,7 +308,7 @@ bool CP25Protocol::IsValidDvPacket(const CIp &Ip, const CBuffer &Buffer, std::un { int offset = 0; bool last = false; - + switch (Buffer.data()[0U]) { case 0x62U: offset = 10U; @@ -357,7 +357,7 @@ bool CP25Protocol::IsValidDvPacket(const CIp &Ip, const CBuffer &Buffer, std::un default: break; } - + frame = std::unique_ptr(new CDvFramePacket(&(Buffer.data()[offset]), m_uiStreamId, last)); return true; } @@ -388,18 +388,18 @@ void CP25Protocol::EncodeP25Packet(const CDvHeaderPacket &Header, const CDvFrame { uint32_t uiSrcId = Header.GetMyCallsign().GetDmrid(); uint32_t uiRptrId = P25_REFID; - + if(uiSrcId == 0){ uiSrcId = DMRMMDVM_DEFAULTID; } - + if(islast) { Buffer.resize(17); ::memcpy(Buffer.data(), REC80, 17U); return; } - + switch (iSeq % 18) { case 0x00U: Buffer.resize(22); @@ -506,7 +506,7 @@ void CP25Protocol::EncodeP25Packet(const CDvHeaderPacket &Header, const CDvFrame void CP25Protocol::HandleKeepalives(void) { // iterate on clients - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::p25, it)) != nullptr ) @@ -526,6 +526,5 @@ void CP25Protocol::HandleKeepalives(void) } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } - diff --git a/reflector/Packet.cpp b/reflector/Packet.cpp index 9ca9b10..c77208b 100644 --- a/reflector/Packet.cpp +++ b/reflector/Packet.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "Packet.h" // default constructor diff --git a/reflector/PacketStream.cpp b/reflector/PacketStream.cpp index bcd2ef5..7253218 100644 --- a/reflector/PacketStream.cpp +++ b/reflector/PacketStream.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "PacketStream.h" //////////////////////////////////////////////////////////////////////////////////////// @@ -32,10 +32,15 @@ CPacketStream::CPacketStream() m_uiStreamId = 0; m_uiPacketCntr = 0; m_OwnerClient = nullptr; -#ifdef TRANSCODED_MODULES m_CodecStream = nullptr; - m_TCReader = reader; -#endif +} + +bool CPacketStream::InitPacketStream(bool is_transcoded) +{ + if (is_transcoded) + m_CodecStream = std::unique_ptr(new CCodecStream(this)); + + return nullptr == m_CodecStream; } //////////////////////////////////////////////////////////////////////////////////////// @@ -53,16 +58,6 @@ bool CPacketStream::OpenPacketStream(const CDvHeaderPacket &DvHeader, std::share m_DvHeader = DvHeader; m_OwnerClient = client; m_LastPacketTime.start(); -#ifdef TRANSCODED_MODULES - if (DvHeader.IsLocalOrigin()) // we only need transcoding if the source is local - { - auto mod = DvHeader.GetRpt2Module(); - if (std::string::npos != std::string(TRANSCODED_MODULES).find(mod)) - { - m_CodecStream = std::unique_ptr(new CCodecStream(this, m_uiStreamId, DvHeader.GetCodecIn(), m_TCReader)); - } - } -#endif return true; } @@ -75,9 +70,8 @@ void CPacketStream::ClosePacketStream(void) m_bOpen = false; m_uiStreamId = 0; m_OwnerClient.reset(); -#ifdef TRANSCODED_MODULES - m_CodecStream.reset(); -#endif + if (m_CodecStream) + m_CodecStream.reset(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -92,7 +86,6 @@ void CPacketStream::Push(std::unique_ptr Packet) Packet->UpdatePids(m_uiPacketCntr++); } // transcoder avaliable ? -#ifdef TRANSCODED_MODULES if ( m_CodecStream ) { // todo: verify no possibilty of double lock here @@ -115,7 +108,6 @@ void CPacketStream::Push(std::unique_ptr Packet) m_CodecStream->Unlock(); } else -#endif { // otherwise, push direct push push(Packet); diff --git a/reflector/PacketStream.h b/reflector/PacketStream.h index d35fad4..ac067b3 100644 --- a/reflector/PacketStream.h +++ b/reflector/PacketStream.h @@ -22,10 +22,7 @@ #include "Timer.h" #include "DVHeaderPacket.h" #include "Client.h" -#ifdef TRANSCODED_MODULES -#include "UnixDgramSocket.h" #include "CodecStream.h" -#endif //////////////////////////////////////////////////////////////////////////////////////// @@ -38,12 +35,8 @@ class CPacketStream : public CPacketQueue { public: - // constructor -#ifdef TRANSCODED_MODULES - CPacketStream(std::shared_ptr); -#else CPacketStream(); -#endif + bool InitPacketStream(bool is_transcoded); // open / close bool OpenPacketStream(const CDvHeaderPacket &, std::shared_ptr); @@ -70,8 +63,5 @@ protected: CTimer m_LastPacketTime; CDvHeaderPacket m_DvHeader; std::shared_ptr m_OwnerClient; -#ifdef TRANSCODED_MODULES - std::shared_ptr m_TCReader; std::unique_ptr m_CodecStream; -#endif }; diff --git a/reflector/Peer.cpp b/reflector/Peer.cpp index e4b7c86..9b24722 100644 --- a/reflector/Peer.cpp +++ b/reflector/Peer.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "Reflector.h" #include "Peer.h" diff --git a/reflector/PeerCallsignList.cpp b/reflector/PeerCallsignList.cpp index 7b70951..af07d5d 100644 --- a/reflector/PeerCallsignList.cpp +++ b/reflector/PeerCallsignList.cpp @@ -17,7 +17,7 @@ // along with this program. If not, see . #include -#include "Main.h" + #include "PeerCallsignList.h" bool CPeerCallsignList::LoadFromFile(const char *filename) diff --git a/reflector/PeerCallsignList.h b/reflector/PeerCallsignList.h index 2ec8da6..8ef827e 100644 --- a/reflector/PeerCallsignList.h +++ b/reflector/PeerCallsignList.h @@ -18,7 +18,7 @@ #pragma once -#include "Main.h" + #include "CallsignList.h" //////////////////////////////////////////////////////////////////////////////////////// diff --git a/reflector/Peers.cpp b/reflector/Peers.cpp index 475602e..a371c8f 100644 --- a/reflector/Peers.cpp +++ b/reflector/Peers.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "Reflector.h" #include "Peers.h" @@ -60,15 +60,15 @@ void CPeers::AddPeer(std::shared_ptr peer) std::cout << "New peer " << peer->GetCallsign() << " at " << peer->GetIp() << " added with protocol " << peer->GetProtocolName() << std::endl; // and append all peer's client to reflector client list // it is double lock safe to lock Clients list after Peers list - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); for ( auto cit=peer->cbegin(); cit!=peer->cend(); cit++ ) { clients->AddClient(*cit); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // notify - g_Reflector.OnPeersChanged(); + g_Refl..OnPeersChanged(); } void CPeers::RemovePeer(std::shared_ptr peer) @@ -81,7 +81,7 @@ void CPeers::RemovePeer(std::shared_ptr peer) { // remove all clients from reflector client list // it is double lock safe to lock Clients list after Peers list - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); for ( auto cit=peer->begin(); cit!=peer->end(); cit++ ) { // this also delete the client object @@ -89,13 +89,13 @@ void CPeers::RemovePeer(std::shared_ptr peer) } // so clear it then (*pit)->ClearClients(); - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // remove it std::cout << "Peer " << (*pit)->GetCallsign() << " at " << (*pit)->GetIp() << " removed" << std::endl; pit = m_Peers.erase(pit); // notify - g_Reflector.OnPeersChanged(); + g_Refl..OnPeersChanged(); } else { diff --git a/reflector/Protocol.cpp b/reflector/Protocol.cpp index 99b75fa..817f5b5 100644 --- a/reflector/Protocol.cpp +++ b/reflector/Protocol.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "Protocol.h" #include "Clients.h" #include "Reflector.h" @@ -52,7 +52,7 @@ CProtocol::~CProtocol() bool CProtocol::Initialize(const char *type, const EProtocol ptype, const uint16_t port, const bool has_ipv4, const bool has_ipv6) { // init reflector apparent callsign - m_ReflectorCallsign = g_Reflector.GetCallsign(); + m_ReflectorCallsign = g_Refl..GetCallsign(); // reset stop flag keep_running = true; @@ -179,7 +179,7 @@ void CProtocol::CheckStreamsTimeout(void) { // yes, close it it->second->Unlock(); - g_Reflector.CloseStream(it->second); + g_Refl..CloseStream(it->second); // and remove it from the m_Streams map it = m_Streams.erase(it); } diff --git a/reflector/Protocols.cpp b/reflector/Protocols.cpp index c2f10c1..6dec2ff 100644 --- a/reflector/Protocols.cpp +++ b/reflector/Protocols.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "DExtraProtocol.h" #include "DPlusProtocol.h" #include "DCSProtocol.h" @@ -80,15 +80,15 @@ bool CProtocols::Init(void) m_Protocols.emplace_back(std::unique_ptr(new CM17Protocol)); if (! m_Protocols.back()->Initialize("URF", EProtocol::m17, M17_PORT, M17_IPV4, M17_IPV6)) return false; - + m_Protocols.emplace_back(std::unique_ptr(new CP25Protocol)); if (! m_Protocols.back()->Initialize("P25", EProtocol::p25, P25_PORT, P25_IPV4, P25_IPV6)) return false; - + m_Protocols.emplace_back(std::unique_ptr(new CNXDNProtocol)); if (! m_Protocols.back()->Initialize("NXDN", EProtocol::nxdn, NXDN_PORT, NXDN_IPV4, NXDN_IPV6)) return false; - + m_Protocols.emplace_back(std::unique_ptr(new CUSRPProtocol)); if (! m_Protocols.back()->Initialize("USRP", EProtocol::usrp, USRP_PORT, USRP_IPV4, USRP_IPV6)) return false; diff --git a/reflector/RawSocket.cpp b/reflector/RawSocket.cpp index c8ee654..615786f 100644 --- a/reflector/RawSocket.cpp +++ b/reflector/RawSocket.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "Reflector.h" #include "RawSocket.h" diff --git a/reflector/Reflector.cpp b/reflector/Reflector.cpp index fdfa792..a5605ba 100644 --- a/reflector/Reflector.cpp +++ b/reflector/Reflector.cpp @@ -16,26 +16,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" -#include -#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 +#include "Global.h" //////////////////////////////////////////////////////////////////////////////////////// // destructor @@ -46,12 +30,7 @@ CReflector::~CReflector() { m_XmlReportFuture.get(); } -#ifdef JSON_MONITOR - if ( m_JsonReportFuture.valid() ) - { - m_JsonReportFuture.get(); - } -#endif + for (auto it=m_Modules.cbegin(); it!=m_Modules.cend(); it++) { if (m_RouterFuture[*it].valid()) @@ -59,11 +38,6 @@ CReflector::~CReflector() } m_RouterFuture.clear(); m_Stream.clear(); - -#ifdef TRANSCODED_MODULES - m_TCReader.clear(); -#endif - } @@ -72,55 +46,68 @@ CReflector::~CReflector() bool CReflector::Start(void) { + // get config stuff + m_Callsign = CCallsign(g_Conf.GetString(g_Conf.j.names.cs).c_str(), false); + m_Modules.assign(g_Conf.GetString(g_Conf.j.modules.modules)); + std::string tcmods(g_Conf.GetString(g_Conf.j.modules.tcmodules)); + // let's go! keep_running = true; // init gate keeper. It can only return true! - g_GateKeeper.Init(); + g_Gate.Init(); // init dmrid directory. No need to check the return value. - g_DmridDir.Init(); - + g_LDid.LookupInit(); + // init dmrid directory. No need to check the return value. - g_NXDNidDir.Init(); + g_LNid.LookupInit(); // init wiresx node directory. Likewise with the return vale. - g_YsfNodeDir.Init(); + g_LYtr.LookupInit(); // create protocols if (! m_Protocols.Init()) { m_Protocols.Close(); - return false; + return true; } // start one thread per reflector module - for (auto it=m_Modules.cbegin(); it!=m_Modules.cend(); it++) + for (auto c : m_Modules) { -#ifdef TRANSCODED_MODULES - m_TCReader[*it] = std::make_shared(); - std::string readername(TC2REF); - readername.append(1, *it); - if (m_TCReader[*it]->Open(readername.c_str())) + auto stream = std::make_shared(); + if (stream) + { + stream->InitPacketStream(std::string::npos != tcmods.find(c)); + } + else { - std::cerr << "ERROR: Reflector can't open " << readername << std::endl; - m_TCReader[*it].reset(); - return false; + return true; + } + try + { + m_RouterFuture[c] = std::async(std::launch::async, &CReflector::RouterThread, this, c); + } + catch(const std::exception& e) + { + std::cerr << "Cannot start module '" << c << "' thread: " << e.what() << '\n'; + keep_running = false; + return true; } - m_Stream[*it] = std::make_shared(m_TCReader[*it]); -#else - m_Stream[*it] = std::make_shared(); -#endif - m_RouterFuture[*it] = std::async(std::launch::async, &CReflector::RouterThread, this, *it); } // start the reporting threads - m_XmlReportFuture = std::async(std::launch::async, &CReflector::XmlReportThread, this); -#ifdef JSON_MONITOR - m_JsonReportFuture = std::async(std::launch::async, &CReflector::JsonReportThread, this); -#endif + try + { + m_XmlReportFuture = std::async(std::launch::async, &CReflector::XmlReportThread, this); + } + catch(const std::exception& e) + { + std::cerr << "Cannot start the dashboard data report thread: " << e.what() << '\n'; + } - return true; + return false; } void CReflector::Stop(void) @@ -133,30 +120,24 @@ void CReflector::Stop(void) { m_XmlReportFuture.get(); } -#ifdef JSON_MONITOR - if ( m_JsonReportFuture.valid() ) - { - m_JsonReportFuture.get(); - } -#endif // stop & delete all router thread - for (auto it=m_Modules.cbegin(); it!=m_Modules.cend(); it++) + for (auto c : m_Modules) { - if (m_RouterFuture[*it].valid()) - m_RouterFuture[*it].get(); + if (m_RouterFuture[c].valid()) + m_RouterFuture[c].get(); } // close protocols m_Protocols.Close(); // close gatekeeper - g_GateKeeper.Close(); + g_Gate.Close(); // close databases - g_DmridDir.Close(); - g_NXDNidDir.Close(); - g_YsfNodeDir.Close(); + g_LDid.LookupClose(); + g_LNid.LookupClose(); + g_LYtr.LookupClose(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -338,13 +319,16 @@ void CReflector::RouterThread(const char ThisModule) //////////////////////////////////////////////////////////////////////////////////////// // report threads +#define XML_UPDATE_PERIOD 10 + void CReflector::XmlReportThread() { + const std::string path(g_Conf.GetString(g_Conf.j.files.json)); while (keep_running) { // report to xml file std::ofstream xmlFile; - xmlFile.open(XML_PATH, std::ios::out | std::ios::trunc); + xmlFile.open(path, std::ios::out | std::ios::trunc); if ( xmlFile.is_open() ) { // write xml file @@ -353,12 +337,10 @@ void CReflector::XmlReportThread() // and close file xmlFile.close(); } -#ifndef DEBUG_NO_ERROR_ON_XML_OPEN_FAIL else { - std::cout << "Failed to open " << XML_PATH << std::endl; + std::cout << "Failed to open " << path << std::endl; } -#endif // and wait a bit for (int i=0; i< XML_UPDATE_PERIOD && keep_running; i++) @@ -366,100 +348,6 @@ void CReflector::XmlReportThread() } } -#ifdef JSON_MONITOR -void CReflector::JsonReportThread() -{ - CUdpSocket Socket; - CBuffer Buffer; - CIp Ip; - bool bOn; - - // init variable - bOn = false; - - // create listening socket - if ( Socket.Open(JSON_PORT) ) - { - // and loop - while (keep_running) - { - // any command ? - if ( Socket.Receive(Buffer, Ip, 50) ) - { - // check verb - if ( Buffer.Compare((uint8_t *)"hello", 5) == 0 ) - { - std::cout << "Monitor socket connected with " << Ip << std::endl; - - // connected - bOn = true; - - // announce ourselves - SendJsonReflectorObject(Socket, Ip); - - // dump tables - SendJsonNodesObject(Socket, Ip); - SendJsonStationsObject(Socket, Ip); - } - else if ( Buffer.Compare((uint8_t *)"bye", 3) == 0 ) - { - std::cout << "Monitor socket disconnected" << std::endl; - - // diconnected - bOn = false; - } - } - - // any notifications ? - CNotification notification; - m_Notifications.Lock(); - if ( !m_Notifications.empty() ) - { - // get the packet - notification = m_Notifications.front(); - m_Notifications.pop(); - } - m_Notifications.Unlock(); - - // handle it - if ( bOn ) - { - switch ( notification.GetId() ) - { - case NOTIFICATION_CLIENTS: - case NOTIFICATION_PEERS: - //std::cout << "Monitor updating nodes table" << std::endl; - SendJsonNodesObject(Socket, Ip); - break; - case NOTIFICATION_USERS: - //std::cout << "Monitor updating stations table" << std::endl; - SendJsonStationsObject(Socket, Ip); - break; - case NOTIFICATION_STREAM_OPEN: - //std::cout << "Monitor notify station " << notification.GetCallsign() << "going ON air" << std::endl; - SendJsonStationsObject(Socket, Ip); - SendJsonOnairObject(Socket, Ip, notification.GetCallsign()); - break; - case NOTIFICATION_STREAM_CLOSE: - //std::cout << "Monitor notify station " << notification.GetCallsign() << "going OFF air" << std::endl; - SendJsonOffairObject(Socket, Ip, notification.GetCallsign()); - break; - case NOTIFICATION_NONE: - default: - // nothing to do, just sleep a bit - std::this_thread::sleep_for(std::chrono::milliseconds(250); - break; - } - } - } - } - else - { - std::cout << "Error creating monitor socket" << std::endl; - } -} -#endif - //////////////////////////////////////////////////////////////////////////////////////// // notifications @@ -549,9 +437,7 @@ void CReflector::WriteXmlFile(std::ofstream &xmlFile) xmlFile << "" << std::endl; // software version - char sz[64]; - ::sprintf(sz, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION); - xmlFile << "" << sz << "" << std::endl; + xmlFile << "" << g_Vers << "" << std::endl; CCallsign cs = m_Callsign; cs.PatchCallsign(0, "XLX", 3); @@ -598,120 +484,3 @@ void CReflector::WriteXmlFile(std::ofstream &xmlFile) ReleaseUsers(); xmlFile << "" << 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 diff --git a/reflector/Reflector.h b/reflector/Reflector.h index 4e7d233..30fce3c 100644 --- a/reflector/Reflector.h +++ b/reflector/Reflector.h @@ -18,6 +18,8 @@ #pragma once +#include + #include "Users.h" #include "Clients.h" #include "Peers.h" @@ -40,19 +42,8 @@ class CReflector { public: - // constructor - CReflector(); - // destructor - virtual ~CReflector(); - - // - const CCallsign &GetCallsign(void) const { return m_Callsign; } - -#ifdef TRANSCODER_IP - void SetTranscoderIp(const char *a, const int n) { memset(m_AmbedIp, 0, n); strncpy(m_AmbedIp, a, n-1); } - const char *GetTranscoderIp(void) const { return m_AmbedIp; } -#endif + ~CReflector(); // operation bool Start(void); @@ -71,7 +62,8 @@ public: bool IsStreaming(char); void CloseStream(std::shared_ptr); - // users + // get + const CCallsign &GetCallsign(void) const { return m_Callsign; } CUsers *GetUsers(void) { m_Users.Lock(); return &m_Users; } void ReleaseUsers(void) { m_Users.Unlock(); } @@ -90,9 +82,6 @@ protected: // threads void RouterThread(const char); void XmlReportThread(void); -#ifdef JSON_MONITOR - void JsonReportThread(void); -#endif // streams std::shared_ptr GetStream(char); @@ -102,22 +91,10 @@ protected: // xml helpers void WriteXmlFile(std::ofstream &); -#ifdef JSON_MONITOR - // json helpers - void SendJsonReflectorObject(CUdpSocket &, CIp &); - void SendJsonNodesObject(CUdpSocket &, CIp &); - void SendJsonStationsObject(CUdpSocket &, CIp &); - void SendJsonOnairObject(CUdpSocket &, CIp &, const CCallsign &); - void SendJsonOffairObject(CUdpSocket &, CIp &, const CCallsign &); -#endif - protected: // identity - const CCallsign m_Callsign; - const std::string m_Modules; -#ifdef TRANSCODER_IP - char m_AmbedIp[INET6_ADDRSTRLEN]; -#endif + CCallsign m_Callsign; + std::string m_Modules, m_TCmodules; // objects CUsers m_Users; // sorted list of lastheard stations @@ -127,22 +104,12 @@ protected: // queues std::unordered_map> m_Stream; -#ifdef TRANSCODED_MODULES - std::unordered_map> m_TCReader; -#endif // threads std::atomic keep_running; std::unordered_map> m_RouterFuture; std::future m_XmlReportFuture; -#ifdef JSON_MONITOR - std::future m_JsonReportFuture; -#endif + // notifications CNotificationQueue m_Notifications; - -public: -#ifdef DEBUG_DUMPFILE - std::ofstream m_DebugFile; -#endif }; diff --git a/reflector/Semaphore.cpp b/reflector/Semaphore.cpp index 00c20a6..76c4b84 100644 --- a/reflector/Semaphore.cpp +++ b/reflector/Semaphore.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "Semaphore.h" //////////////////////////////////////////////////////////////////////////////////////// diff --git a/reflector/Semaphore.h b/reflector/Semaphore.h index d7356a4..f3e324f 100644 --- a/reflector/Semaphore.h +++ b/reflector/Semaphore.h @@ -18,7 +18,7 @@ #pragma once -#include "Main.h" + class CSemaphore { diff --git a/reflector/UDPMsgSocket.cpp b/reflector/UDPMsgSocket.cpp index b2b0f29..5571a06 100644 --- a/reflector/UDPMsgSocket.cpp +++ b/reflector/UDPMsgSocket.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "UDPMsgSocket.h" diff --git a/reflector/UDPSocket.cpp b/reflector/UDPSocket.cpp index 9787cff..1b078b6 100644 --- a/reflector/UDPSocket.cpp +++ b/reflector/UDPSocket.cpp @@ -17,7 +17,7 @@ // along with this program. If not, see . #include -#include "Main.h" + #include "UDPSocket.h" diff --git a/reflector/URFClient.cpp b/reflector/URFClient.cpp index b9605b1..dd9feee 100644 --- a/reflector/URFClient.cpp +++ b/reflector/URFClient.cpp @@ -17,7 +17,7 @@ // along with this program. If not, see . #include -#include "Main.h" + #include "URFClient.h" diff --git a/reflector/URFPeer.cpp b/reflector/URFPeer.cpp index 34747c1..fcf5df5 100644 --- a/reflector/URFPeer.cpp +++ b/reflector/URFPeer.cpp @@ -18,7 +18,7 @@ #include -#include "Main.h" + #include "Reflector.h" #include "URFPeer.h" #include "URFClient.h" diff --git a/reflector/URFProtocol.cpp b/reflector/URFProtocol.cpp index 0c5dfa7..f3fda2e 100644 --- a/reflector/URFProtocol.cpp +++ b/reflector/URFProtocol.cpp @@ -17,7 +17,7 @@ // along with this program. If not, see . #include -#include "Main.h" + #include "URFPeer.h" #include "URFProtocol.h" #include "Reflector.h" @@ -73,19 +73,19 @@ void CURFProtocol::Task(void) else if ( IsValidKeepAlivePacket(Buffer, &Callsign) ) { // find peer - CPeers *peers = g_Reflector.GetPeers(); + CPeers *peers = g_Refl..GetPeers(); std::shared_ptrpeer = peers->FindPeer(Ip, EProtocol::urf); if ( peer != nullptr ) { // keep it alive peer->Alive(); } - g_Reflector.ReleasePeers(); + g_Refl..ReleasePeers(); } else if ( IsValidDvHeaderPacket(Buffer, Header) ) { // callsign allowed? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip) ) + if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip) ) { OnDvHeaderPacketIn(Header, Ip); } @@ -95,7 +95,7 @@ void CURFProtocol::Task(void) std::cout << "URF (" << Version.GetMajor() << "." << Version.GetMinor() << "." << Version.GetRevision() << ") connect packet for modules " << Modules << " from " << Callsign << " at " << Ip << std::endl; // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::urf, Modules) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::urf, Modules) ) { // acknowledge connecting request // following is version dependent @@ -123,10 +123,10 @@ void CURFProtocol::Task(void) std::cout << "URF ack packet for modules " << Modules << " from " << Callsign << " at " << Ip << std::endl; // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::urf, Modules) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::urf, Modules) ) { // already connected ? - CPeers *peers = g_Reflector.GetPeers(); + CPeers *peers = g_Refl..GetPeers(); if ( peers->FindPeer(Callsign, Ip, EProtocol::urf) == nullptr ) { // create the new peer @@ -137,7 +137,7 @@ void CURFProtocol::Task(void) // this also add all new clients to reflector client list peers->AddPeer(peer); } - g_Reflector.ReleasePeers(); + g_Refl..ReleasePeers(); } } else if ( IsValidDisconnectPacket(Buffer, &Callsign) ) @@ -145,7 +145,7 @@ void CURFProtocol::Task(void) std::cout << "URF disconnect packet from " << Callsign << " at " << Ip << std::endl; // find peer - CPeers *peers = g_Reflector.GetPeers(); + CPeers *peers = g_Refl..GetPeers(); std::shared_ptrpeer = peers->FindPeer(Ip, EProtocol::urf); if ( peer != nullptr ) { @@ -154,7 +154,7 @@ void CURFProtocol::Task(void) // and delete them peers->RemovePeer(peer); } - g_Reflector.ReleasePeers(); + g_Refl..ReleasePeers(); } else if ( IsValidNackPacket(Buffer, &Callsign) ) { @@ -216,7 +216,7 @@ void CURFProtocol::HandleQueue(void) if ( EncodeDvPacket(*packet, buffer) ) { // and push it to all our clients linked to the module and who are not streaming in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::urf, it)) != nullptr ) @@ -232,7 +232,7 @@ void CURFProtocol::HandleQueue(void) } } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } } @@ -251,7 +251,7 @@ void CURFProtocol::HandleKeepalives(void) EncodeKeepAlivePacket(&keepalive); // iterate on peers - CPeers *peers = g_Reflector.GetPeers(); + CPeers *peers = g_Refl..GetPeers(); auto pit = peers->begin(); std::shared_ptrpeer = nullptr; while ( (peer = peers->FindNextPeer(EProtocol::urf, pit)) != nullptr ) @@ -278,7 +278,7 @@ void CURFProtocol::HandleKeepalives(void) peers->RemovePeer(peer); } } - g_Reflector.ReleasePeers(); + g_Refl..ReleasePeers(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -289,8 +289,8 @@ void CURFProtocol::HandlePeerLinks(void) CBuffer buffer; // get the list of peers - CPeerCallsignList *list = g_GateKeeper.GetPeerList(); - CPeers *peers = g_Reflector.GetPeers(); + CPeerCallsignList *list = g_Gate.GetPeerList(); + CPeers *peers = g_Refl..GetPeers(); // check if all our connected peers are still listed by gatekeeper // if not, disconnect @@ -330,8 +330,8 @@ void CURFProtocol::HandlePeerLinks(void) } // done - g_Reflector.ReleasePeers(); - g_GateKeeper.ReleasePeerList(); + g_Refl..ReleasePeers(); + g_Gate.ReleasePeerList(); } @@ -363,11 +363,11 @@ void CURFProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header, CCallsign rpt2(Header->GetRpt2Callsign()); // no stream open yet, open a new one // find this client - std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::urf, Header->GetRpt2Module()); + std::shared_ptrclient = g_Refl..GetClients()->FindClient(Ip, EProtocol::urf, Header->GetRpt2Module()); if ( client ) { // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr ) { // keep the handle m_Streams[stream->GetStreamId()] = stream; @@ -376,10 +376,10 @@ void CURFProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header, peer = client->GetCallsign(); } // release - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // update last heard - g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2, peer); - g_Reflector.ReleaseUsers(); + g_Refl..GetUsers()->Hearing(my, rpt1, rpt2, peer); + g_Refl..ReleaseUsers(); } } @@ -521,7 +521,7 @@ void CURFProtocol::EncodeKeepAlivePacket(CBuffer *Buffer) { Buffer->Set("PING"); Buffer->resize(10); - g_Reflector.GetCallsign().CodeOut(Buffer->data()+4); + g_Refl..GetCallsign().CodeOut(Buffer->data()+4); } void CURFProtocol::EncodeConnectPacket(CBuffer *Buffer, const char *Modules) @@ -530,7 +530,7 @@ void CURFProtocol::EncodeConnectPacket(CBuffer *Buffer, const char *Modules) Buffer->Set("CONN"); // our callsign Buffer->resize(37); - g_Reflector.GetCallsign().CodeOut(Buffer->data()+4); + g_Refl..GetCallsign().CodeOut(Buffer->data()+4); // our version Buffer->ReplaceAt(10, (uint8_t *)Modules, strlen(Modules)); Buffer->Append((uint8_t)VERSION_MAJOR); @@ -543,7 +543,7 @@ void CURFProtocol::EncodeDisconnectPacket(CBuffer *Buffer) Buffer->Set("DISC"); // our callsign Buffer->resize(10); - g_Reflector.GetCallsign().CodeOut(Buffer->data()+4); + g_Refl..GetCallsign().CodeOut(Buffer->data()+4); } void CURFProtocol::EncodeConnectAckPacket(CBuffer *Buffer, const char *Modules) @@ -551,7 +551,7 @@ void CURFProtocol::EncodeConnectAckPacket(CBuffer *Buffer, const char *Modules) Buffer->Set("ACKN"); // our callsign Buffer->resize(37); - g_Reflector.GetCallsign().CodeOut(Buffer->data()+4); + g_Refl..GetCallsign().CodeOut(Buffer->data()+4); // the shared modules Buffer->ReplaceAt(10, (uint8_t *)Modules, strlen(Modules)); // our version @@ -564,5 +564,5 @@ void CURFProtocol::EncodeConnectNackPacket(CBuffer *Buffer) { Buffer->Set("NACK"); Buffer->resize(10); - g_Reflector.GetCallsign().CodeOut(Buffer->data()+4); + g_Refl..GetCallsign().CodeOut(Buffer->data()+4); } diff --git a/reflector/USRPClient.cpp b/reflector/USRPClient.cpp index f75c866..a94619f 100644 --- a/reflector/USRPClient.cpp +++ b/reflector/USRPClient.cpp @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "USRPClient.h" diff --git a/reflector/USRPProtocol.cpp b/reflector/USRPProtocol.cpp index 75ebdbf..076d7ff 100644 --- a/reflector/USRPProtocol.cpp +++ b/reflector/USRPProtocol.cpp @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "USRPClient.h" #include "USRPProtocol.h" @@ -41,14 +41,14 @@ bool CUSRPProtocol::Initialize(const char *type, const EProtocol ptype, const ui CBuffer buffer; m_uiStreamId = 0; CCallsign cs(USRP_DEFAULT_CALLSIGN); - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::ifstream file; std::streampos size; - + // base class if (! CProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6)) return false; - + file.open(USRPCLIENTS_PATH, std::ios::in | std::ios::binary | std::ios::ate); if ( file.is_open() ) { @@ -93,7 +93,7 @@ bool CUSRPProtocol::Initialize(const char *type, const EProtocol ptype, const ui } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // update time m_LastKeepaliveTime.start(); @@ -135,7 +135,7 @@ void CUSRPProtocol::Task(void) else if( IsValidDvHeaderPacket(Ip, Buffer, Header) ) { // callsign muted? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::usrp) ) + if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::usrp) ) { OnDvHeaderPacketIn(Header, Ip); } @@ -192,7 +192,7 @@ void CUSRPProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header, CCallsign rpt2(Header->GetRpt2Callsign()); // find this client - std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::usrp); + std::shared_ptrclient = g_Refl..GetClients()->FindClient(Ip, EProtocol::usrp); if ( client ) { // get client callsign @@ -201,18 +201,18 @@ void CUSRPProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header, Header->SetRpt2Module(m); rpt2.SetCSModule(m); // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr ) { // keep the handle m_Streams[stream->GetStreamId()] = stream; } } // release - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // update last heard - g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); - g_Reflector.ReleaseUsers(); + g_Refl..GetUsers()->Hearing(my, rpt1, rpt2); + g_Refl..ReleaseUsers(); } } @@ -249,7 +249,7 @@ void CUSRPProtocol::HandleQueue(void) if ( buffer.size() > 0 ) { // and push it to all our clients linked to the module and who are not streaming in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::usrp, it)) != nullptr ) @@ -261,7 +261,7 @@ void CUSRPProtocol::HandleQueue(void) Send(buffer, client->GetIp()); } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } m_Queue.Unlock(); @@ -285,14 +285,14 @@ bool CUSRPProtocol::IsValidDvPacket(const CIp &Ip, const CBuffer &Buffer, std::u rpt1.SetCSModule(USRP_MODULE_ID); rpt2.SetCSModule(' '); header = std::unique_ptr(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, true)); - OnDvHeaderPacketIn(header, Ip); + OnDvHeaderPacketIn(header, Ip); } int16_t pcm[160]; for(int i = 0; i < 160; ++i){ pcm[i] = (Buffer.data()[32+(i*2)+1] << 8) | Buffer.data()[32+(i*2)]; } - + frame = std::unique_ptr(new CDvFramePacket(pcm, m_uiStreamId, false)); return true; } @@ -354,7 +354,7 @@ void CUSRPProtocol::EncodeUSRPPacket(const CDvHeaderPacket &Header, const CDvFra memcpy(Buffer.data(), "USRP", 4); memcpy(Buffer.data() + 4, &cnt, 4); Buffer.data()[15] = USRP_KEYUP_FALSE; - + } else { @@ -375,7 +375,7 @@ void CUSRPProtocol::EncodeUSRPPacket(const CDvHeaderPacket &Header, const CDvFra void CUSRPProtocol::HandleKeepalives(void) { // iterate on clients - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::usrp, it)) != nullptr ) @@ -395,6 +395,5 @@ void CUSRPProtocol::HandleKeepalives(void) //} } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } - diff --git a/reflector/User.cpp b/reflector/User.cpp index 105cd94..c42729e 100644 --- a/reflector/User.cpp +++ b/reflector/User.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "User.h" diff --git a/reflector/User.h b/reflector/User.h index c9869fa..c7e6897 100644 --- a/reflector/User.h +++ b/reflector/User.h @@ -33,7 +33,7 @@ public: ~CUser() {} // operation - void HeardNow(void) { m_LastHeardTime = std::time(nullptr); } + void HeardNow(void) { m_LastHeardTime = time(nullptr); } // operators bool operator ==(const CUser &) const; @@ -49,5 +49,5 @@ protected: CCallsign m_Rpt1; CCallsign m_Rpt2; CCallsign m_Xlx; - std::time_t m_LastHeardTime; + time_t m_LastHeardTime; }; diff --git a/reflector/Users.cpp b/reflector/Users.cpp index 1406e18..beb2106 100644 --- a/reflector/Users.cpp +++ b/reflector/Users.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "Users.h" #include "Reflector.h" @@ -40,7 +40,7 @@ void CUsers::AddUser(const CUser &user) } // notify - g_Reflector.OnUsersChanged(); + g_Refl..OnUsersChanged(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -48,7 +48,7 @@ void CUsers::AddUser(const CUser &user) void CUsers::Hearing(const CCallsign &my, const CCallsign &rpt1, const CCallsign &rpt2) { - Hearing(my, rpt1, rpt2, g_Reflector.GetCallsign()); + Hearing(my, rpt1, rpt2, g_Refl..GetCallsign()); } void CUsers::Hearing(const CCallsign &my, const CCallsign &rpt1, const CCallsign &rpt2, const CCallsign &xlx) diff --git a/reflector/Users.h b/reflector/Users.h index 6216269..f4e3343 100644 --- a/reflector/Users.h +++ b/reflector/Users.h @@ -18,6 +18,9 @@ #pragma once +#include +#include + #include "User.h" class CUsers diff --git a/reflector/Version.cpp b/reflector/Version.cpp index 96d296d..35d3c9d 100644 --- a/reflector/Version.cpp +++ b/reflector/Version.cpp @@ -1,73 +1,89 @@ -// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. - -// urfd -- The universal reflector -// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2023 Thomas A. Early N7TAE. +// +// ---------------------------------------------------------------------------- +// This file is part of m17ref. // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// m17ref is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// m17ref is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// You should have received a copy of the GNU General Public License +// with this software. If not, see . +// ---------------------------------------------------------------------------- -#include "Main.h" #include "Version.h" -//////////////////////////////////////////////////////////////////////////////////////// -// constructor +CVersion::CVersion() : version(0) {} + +CVersion::CVersion(uint8_t maj, uint8_t min, uint8_t rev) +{ + Set(maj, min, rev); +} + +int CVersion::GetMajor(void) const +{ + return version / 0x10000; +} + +int CVersion::GetMinor(void) const +{ + return version / 0x100 % 0x100; +} + +int CVersion::GetRevision(void) const +{ + return version % 0x100; +} -CVersion::CVersion() +int CVersion::GetVersion(void) const { - m_iMajor = 0; - m_iMinor = 0; - m_iRevision = 0; + return version; } -CVersion::CVersion(int iMajor, int iMinor, int iRevision) +void CVersion::Set(uint8_t maj, uint8_t min, uint8_t rev) { - m_iMajor = iMajor; - m_iMinor = iMinor; - m_iRevision = iRevision; + version = 0x10000*maj + 0x100*min + rev; } -//////////////////////////////////////////////////////////////////////////////////////// -// comparaison +bool CVersion::operator ==(const CVersion &v) const +{ + return v.version == version; +}; + +bool CVersion::operator !=(const CVersion &v) const +{ + return v.version != version; +}; + +bool CVersion::operator >=(const CVersion &v) const +{ + return v.version >= version; +} -bool CVersion::IsEqualOrHigherTo(const CVersion &version) const +bool CVersion::operator <=(const CVersion &v) const { - if ( m_iMajor > version.m_iMajor ) - { - return true; - } - else if ( m_iMajor == version.m_iMajor ) - { - if ( m_iMinor > version.m_iMinor ) - { - return true; - } - else if ( m_iMinor == version.m_iMinor ) - { - if ( m_iRevision >= version.m_iRevision ) - { - return true; - } - } - } - return false; + return v.version <= version; } -//////////////////////////////////////////////////////////////////////////////////////// -// operator +bool CVersion::operator >(const CVersion &v) const +{ + return v.version > version; +} -bool CVersion::operator ==(const CVersion &Version) const +bool CVersion::operator <(const CVersion &v) const { - return ( (Version.m_iMajor == m_iMajor) && - (Version.m_iMinor == m_iMinor) && - (Version.m_iRevision == m_iRevision )) ; + return v.version < version; } + +// output +std::ostream &operator <<(std::ostream &os, const CVersion &v) +{ + os << v.GetMajor() << '.' << v.GetMinor() << '.' << v.GetRevision(); + return os; +}; diff --git a/reflector/Version.h b/reflector/Version.h index 256bfd8..84aa8d4 100644 --- a/reflector/Version.h +++ b/reflector/Version.h @@ -1,44 +1,56 @@ -// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved. - -// urfd -- The universal reflector -// Copyright © 2021 Thomas A. Early N7TAE +// Copyright © 2023 Thomas A. Early N7TAE. +// +// ---------------------------------------------------------------------------- +// This file is part of m17ref. // -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. +// m17ref is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. // -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. +// m17ref is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. // -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . +// You should have received a copy of the GNU General Public License +// with this software. If not, see . +// ---------------------------------------------------------------------------- #pragma once +#include +#include + class CVersion { public: - // constructor + // constructors CVersion(); - CVersion(int, int, int); + CVersion(uint8_t maj, uint8_t min, uint8_t rev); // get - int GetMajor(void) const { return m_iMajor; } - int GetMinor(void) const { return m_iMinor; } - int GetRevision(void) const { return m_iRevision; } + int GetMajor(void) const; + int GetMinor(void) const; + int GetRevision(void) const; + int GetVersion(void) const; + + // set + void Set(uint8_t, uint8_t, uint8_t); + + // comparaison operators + bool operator ==(const CVersion &v) const; + bool operator !=(const CVersion &v) const; + bool operator >=(const CVersion &v) const; + bool operator <=(const CVersion &v) const; + bool operator >(const CVersion &v) const; + bool operator <(const CVersion &v) const; - // comparaison - bool IsEqualOrHigherTo(const CVersion &) const; + // output + friend std::ostream &operator <<(std::ostream &os, const CVersion &v); - // operator - bool operator ==(const CVersion &) const; protected: // data - int m_iMajor; - int m_iMinor; - int m_iRevision; + int version; }; diff --git a/reflector/WiresXCmd.cpp b/reflector/WiresXCmd.cpp index 225538f..d94616f 100644 --- a/reflector/WiresXCmd.cpp +++ b/reflector/WiresXCmd.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "WiresXCmd.h" diff --git a/reflector/WiresXCmdHandler.cpp b/reflector/WiresXCmdHandler.cpp index ab1360e..e90b0a3 100644 --- a/reflector/WiresXCmdHandler.cpp +++ b/reflector/WiresXCmdHandler.cpp @@ -17,7 +17,7 @@ // along with this program. If not, see . #include -#include "Main.h" + #include "CRC.h" #include "YSFFich.h" #include "YSFPayload.h" @@ -61,8 +61,8 @@ CWiresxCmdHandler::~CWiresxCmdHandler() bool CWiresxCmdHandler::Init(void) { // fill our wiresx info - m_ReflectorWiresxInfo.SetCallsign(g_Reflector.GetCallsign()); - m_ReflectorWiresxInfo.SetNode(g_Reflector.GetCallsign()); + m_ReflectorWiresxInfo.SetCallsign(g_Refl..GetCallsign()); + m_ReflectorWiresxInfo.SetNode(g_Refl..GetCallsign()); m_ReflectorWiresxInfo.SetName("Reflector"); // reset stop flag @@ -144,18 +144,18 @@ void CWiresxCmdHandler::Task(void) const char *modules = ACTIVE_MODULES; // fill our info object Info = m_ReflectorWiresxInfo; - g_YsfNodeDir.FindFrequencies(Cmd.GetCallsign(), &uiNodeTxFreq, &uiNodeRxFreq); + g_LYtr.FindFrequencies(Cmd.GetCallsign(), &uiNodeTxFreq, &uiNodeRxFreq); Info.SetFrequencies(uiNodeTxFreq, uiNodeRxFreq); // find our client and the module it's currentlink linked to cModule = ' '; - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Cmd.GetCallsign(), Cmd.GetIp(), EProtocol::ysf); if ( client ) { cModule = client->GetReflectorModule(); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // and crack the cmd switch ( Cmd.GetCmd() ) @@ -179,13 +179,13 @@ void CWiresxCmdHandler::Task(void) // acknowledge ReplyToWiresxConnReqPacket(Cmd.GetIp(), Info, cModule); // change client's module - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Cmd.GetCallsign(), Cmd.GetIp(), EProtocol::ysf); if ( client ) { client->SetReflectorModule(cModule); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else { @@ -198,13 +198,13 @@ void CWiresxCmdHandler::Task(void) ReplyToWiresxDiscReqPacket(Cmd.GetIp(), Info); // change client's module { - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Cmd.GetCallsign(), Cmd.GetIp(), EProtocol::ysf); if ( client != nullptr ) { client->SetReflectorModule(' '); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } break; case WIRESX_CMD_UNKNOWN: @@ -741,8 +741,8 @@ bool CWiresxCmdHandler::DebugTestDecodePacket(const CBuffer &Buffer) std::cout << "Trailer" << std::endl; std::cout << "length of payload : " << len << std::endl; dump.Set(command, len); - dump.DebugDump(g_Reflector.m_DebugFile); - dump.DebugDumpAscii(g_Reflector.m_DebugFile); + dump.DebugDump(g_Refl..m_DebugFile); + dump.DebugDumpAscii(g_Refl..m_DebugFile); break; case YSF_FI_COMMUNICATIONS: if ( Fich.getDT() == YSF_DT_DATA_FR_MODE ) diff --git a/reflector/WiresXInfo.cpp b/reflector/WiresXInfo.cpp index 3da1fb6..6fd11c9 100644 --- a/reflector/WiresXInfo.cpp +++ b/reflector/WiresXInfo.cpp @@ -17,7 +17,7 @@ // along with this program. If not, see . #include -#include "Main.h" + #include "Callsign.h" #include "WiresXInfo.h" diff --git a/reflector/YSFClient.cpp b/reflector/YSFClient.cpp index 58c3b47..7f6fc60 100644 --- a/reflector/YSFClient.cpp +++ b/reflector/YSFClient.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include "YSFClient.h" diff --git a/reflector/YSFNode.cpp b/reflector/YSFNode.cpp index 2b4d626..badd37b 100644 --- a/reflector/YSFNode.cpp +++ b/reflector/YSFNode.cpp @@ -17,7 +17,7 @@ // along with this program. If not, see . #include -#include "Main.h" + #include "YSFNode.h" diff --git a/reflector/YSFNode.h b/reflector/YSFNode.h index dd5ca81..ba4889d 100644 --- a/reflector/YSFNode.h +++ b/reflector/YSFNode.h @@ -18,7 +18,7 @@ #pragma once -#include "Main.h" + class CYsfNode { diff --git a/reflector/YSFNodeDir.cpp b/reflector/YSFNodeDir.cpp deleted file mode 100644 index 7f11b34..0000000 --- a/reflector/YSFNodeDir.cpp +++ /dev/null @@ -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 . - -#include -#include -#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 diff --git a/reflector/YSFNodeDir.h b/reflector/YSFNodeDir.h deleted file mode 100644 index 26b5911..0000000 --- a/reflector/YSFNodeDir.h +++ /dev/null @@ -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 . - -#pragma once - -#include -#include -#include -#include -#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; - -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 insert(const std::pair &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 keep_running; - std::future m_Future; - CsNodeMap m_map; -}; diff --git a/reflector/YSFNodeDirFile.cpp b/reflector/YSFNodeDirFile.cpp deleted file mode 100644 index 5879c5e..0000000 --- a/reflector/YSFNodeDirFile.cpp +++ /dev/null @@ -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 . - -#include -#include -#include -#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(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; -} diff --git a/reflector/YSFNodeDirFile.h b/reflector/YSFNodeDirFile.h deleted file mode 100644 index 8b15993..0000000 --- a/reflector/YSFNodeDirFile.h +++ /dev/null @@ -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 . - -#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; -}; diff --git a/reflector/YSFNodeDirHttp.cpp b/reflector/YSFNodeDirHttp.cpp deleted file mode 100644 index f5fb8f3..0000000 --- a/reflector/YSFNodeDirHttp.cpp +++ /dev/null @@ -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 . - -#include -#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(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; -} diff --git a/reflector/YSFNodeDirHttp.h b/reflector/YSFNodeDirHttp.h deleted file mode 100644 index c697f91..0000000 --- a/reflector/YSFNodeDirHttp.h +++ /dev/null @@ -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 . - -#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 *); -}; diff --git a/reflector/YSFProtocol.cpp b/reflector/YSFProtocol.cpp index 462f691..15e9149 100644 --- a/reflector/YSFProtocol.cpp +++ b/reflector/YSFProtocol.cpp @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "CRC.h" #include "YSFPayload.h" @@ -119,7 +119,7 @@ void CYsfProtocol::Task(void) else if ( IsValidDvHeaderPacket(Ip, Fich, Buffer, Header, Frames) ) { // node linked and callsign muted? - if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::ysf, Header->GetRpt2Module()) ) + if ( g_Gate.MayTransmit(Header->GetMyCallsign(), Ip, EProtocol::ysf, Header->GetRpt2Module()) ) { // handle it OnDvHeaderPacketIn(Header, Ip); @@ -138,14 +138,14 @@ void CYsfProtocol::Task(void) //std::cout << "YSF keepalive/connect packet from " << Callsign << " at " << Ip << std::endl; // callsign authorized? - if ( g_GateKeeper.MayLink(Callsign, Ip, EProtocol::ysf) ) + if ( g_Gate.MayLink(Callsign, Ip, EProtocol::ysf) ) { // acknowledge the request EncodeConnectAckPacket(&Buffer); Send(Buffer, Ip); // add client if needed - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Callsign, Ip, EProtocol::ysf); // client already connected ? if ( client == nullptr ) @@ -168,7 +168,7 @@ void CYsfProtocol::Task(void) client->Alive(); } // and done - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } else if ( IsValidDisconnectPacket(Buffer) ) @@ -176,7 +176,7 @@ void CYsfProtocol::Task(void) std::cout << "YSF disconnect packet from " << Ip << std::endl; // find client - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); std::shared_ptrclient = clients->FindClient(Ip, EProtocol::ysf); if ( client != nullptr ) { @@ -186,7 +186,7 @@ void CYsfProtocol::Task(void) //EncodeDisconnectPacket(&Buffer); //Send(Buffer, Ip); } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } else if ( IsValidwirexPacket(Buffer, &Fich, &Callsign, &iWiresxCmd, &iWiresxArg) ) { @@ -263,7 +263,7 @@ void CYsfProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header, CCallsign rpt2(Header->GetRpt2Callsign()); // find this client - std::shared_ptrclient = g_Reflector.GetClients()->FindClient(Ip, EProtocol::ysf); + std::shared_ptrclient = g_Refl..GetClients()->FindClient(Ip, EProtocol::ysf); if ( client ) { // get client callsign @@ -274,20 +274,20 @@ void CYsfProtocol::OnDvHeaderPacketIn(std::unique_ptr &Header, rpt2.SetCSModule(m); // and try to open the stream - if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr ) + if ( (stream = g_Refl..OpenStream(Header, client)) != nullptr ) { // keep the handle m_Streams[stream->GetStreamId()] = stream; } } // release - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); // update last heard - if ( g_Reflector.IsValidModule(rpt2.GetCSModule()) ) + if ( g_Refl..IsValidModule(rpt2.GetCSModule()) ) { - g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2); - g_Reflector.ReleaseUsers(); + g_Refl..GetUsers()->Hearing(my, rpt1, rpt2); + g_Refl..ReleaseUsers(); } } } @@ -346,7 +346,7 @@ void CYsfProtocol::HandleQueue(void) if ( buffer.size() > 0 ) { // and push it to all our clients linked to the module and who are not streaming in - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::ysf, it)) != nullptr ) @@ -359,7 +359,7 @@ void CYsfProtocol::HandleQueue(void) } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } } m_Queue.Unlock(); @@ -375,7 +375,7 @@ void CYsfProtocol::HandleKeepalives(void) // and disconnect them if not // iterate on clients - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); auto it = clients->begin(); std::shared_ptrclient = nullptr; while ( (client = clients->FindNextClient(EProtocol::ysf, it)) != nullptr ) @@ -395,7 +395,7 @@ void CYsfProtocol::HandleKeepalives(void) } } - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); } //////////////////////////////////////////////////////////////////////////////////////// @@ -506,7 +506,7 @@ bool CYsfProtocol::IsValidDvFramePacket(const CIp &Ip, const CYSFFICH &Fich, con { // get stream id //uint32_t uiStreamId = IpToStreamId(Ip); - + auto stream = GetStream(m_uiStreamId, &Ip); if ( !stream ) { @@ -531,10 +531,10 @@ bool CYsfProtocol::IsValidDvFramePacket(const CIp &Ip, const CYSFFICH &Fich, con CCallsign rpt2 = m_ReflectorCallsign; rpt2.SetCSModule(' '); header = std::unique_ptr(new CDvHeaderPacket(csMY, CCallsign("CQCQCQ"), rpt1, rpt2, m_uiStreamId, Fich.getFN())); - - if ( g_GateKeeper.MayTransmit(header->GetMyCallsign(), Ip, EProtocol::ysf, header->GetRpt2Module()) ) + + if ( g_Gate.MayTransmit(header->GetMyCallsign(), Ip, EProtocol::ysf, header->GetRpt2Module()) ) { - OnDvHeaderPacketIn(header, Ip); + OnDvHeaderPacketIn(header, Ip); } } @@ -998,7 +998,7 @@ bool CYsfProtocol::EncodeServerStatusPacket(CBuffer *Buffer) const const std::string cs = YSF_REFLECTOR_NAME; memcpy(callsign, cs.c_str(), cs.size() > 16 ? 16 : cs.size()); #else - g_Reflector.GetCallsign().GetCallsign(callsign); + g_Refl..GetCallsign().GetCallsign(callsign); #endif char sz[16]; ::sprintf(sz, "%05u", CalcHash(callsign, 16) % 100000U); @@ -1010,9 +1010,9 @@ bool CYsfProtocol::EncodeServerStatusPacket(CBuffer *Buffer) const memcpy(description, desc.c_str(), desc.size() > 14 ? 14 : desc.size()); Buffer->Append(description, 14); // connected clients - CClients *clients = g_Reflector.GetClients(); + CClients *clients = g_Refl..GetClients(); int count = MIN(999, clients->GetSize()); - g_Reflector.ReleaseClients(); + g_Refl..ReleaseClients(); ::sprintf(sz, "%03u", count); Buffer->Append((uint8_t *)sz, 3); @@ -1090,8 +1090,8 @@ bool CYsfProtocol::DebugTestDecodePacket(const CBuffer &Buffer) std::cout << "Trailer" << std::endl; std::cout << "length of payload : " << len << std::endl; dump.Set(command, len); - dump.DebugDump(g_Reflector.m_DebugFile); - dump.DebugDumpAscii(g_Reflector.m_DebugFile); + dump.DebugDump(g_Refl..m_DebugFile); + dump.DebugDumpAscii(g_Refl..m_DebugFile); break; case YSF_FI_COMMUNICATIONS: if ( Fich.getDT() == YSF_DT_DATA_FR_MODE ) diff --git a/reflector/YSFUtils.cpp b/reflector/YSFUtils.cpp index a3788ce..32349a9 100644 --- a/reflector/YSFUtils.cpp +++ b/reflector/YSFUtils.cpp @@ -19,7 +19,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "Main.h" + #include #include "YSFDefines.h" #include "YSFUtils.h" diff --git a/reflector/example.ini b/reflector/example.ini new file mode 100644 index 0000000..87913d1 --- /dev/null +++ b/reflector/example.ini @@ -0,0 +1,121 @@ +###### URFD CONFIGURATION Example ###### +# Do not use quotes, unless in a comment! + +[Names] +Callsign = URF??? # where ? is A-Z or 0-9 + +SysopEmail = you@somewhere.com + +# 2-letter country codes are listed at https://www.iban.com/country-codes +Country = US + +Sponsor = My Ham Club + +[IpAddresses] +# Binding addresses are usually the 'any' address +IPv4Binding = 0.0.0.0 + +# define IPv6 if you want a "dual-stack" reflector +# IPv6Binding = :: + +# define if you want to override what urfd finds using ipv4.icanhazip.com +# IPv4External = 1.2.3.4 + +# define if you want to override what urfd finds using ipv6.icanhazip.com +# IPv6External = a:b:c:e:f:0:1:2 + +Transcoder = local # SORRY, but only local TC's are supported right now! + +[Modules] +Modules = ADMSZ +# Modules = ABCDEFGHIJKLMNOPQRSTUVWXYZ +Transcoded = A # comment out if you don't have transcoding hardware +# Create Descriptions as needed... +DescriptionA = Transcoded +DescriptionD = DMR Chat +DescriptionM = M17 Chat +DescriptionS = DStar Chat +DescriptionZ = Temp Meeting + +# Protocols +[Brandmeister] +Port = 10002 + +[DCS] +Port = 30051 + +[DExtra] +Port = 30001 + +[DMRPlus] +Port = 8880 + +[DPlus] +Port = 20001 + +[M17] +Port = 17000 + +[MMDVM] +Port = 62030 +DefaultId = 0 + +[NXDN] +Port = 41400 +AutoLinkModule = A # comment out if you want to disable AL +ReflectorID = 12345 + +[P25] +Port = 41000 +AutoLinkModule = A # comment out if you want to disable AL +ReflectorID = 12345 + +[URF] +Port = 10017 + +[USRP] +Port = 34001 +AutoLinkModule = A # comment out if you want to disable AL +DefaultCallsign = ALLSTAR +ClientFilePath = /usr/local/etc/USRPClients.txt + +[YSF] +Port = 42000 +AutoLinkModule = A # comment out if you want to disable AL +DefaultTxFreq = 446500000 +DefaultRxFreq = 446500000 +# if you've registered your reflector at register.ysfreflector.de: +RegistrationID = 12345 +RegistrationName = US URF??? +RegistrationDescription = URF Reflector + +######## Database files +[DMR ID DB] +Hostname = xlxapi.rlx.lu +Suffix = api/exportdmr.php +Mode = http +RefreshMin = 179 +FilePath = /usr/local/etc/dmrid.dat + +[NXDN ID DB] +Hostname = www.dudetronics.com +Suffix = ar-dns/NXDN.csv +Mode = http +RefreshMin = 181 +FilePath = /usr/local/etc/nxdn.dat + +[YSF TX/RX DB] +Hostname = xlxapi.rlx.lu +Suffix = api/exportysfrepeaters.php +Mode = http +RefreshMin = 191 +FilePath = /usr/local/etc/ysfnode.dat + +######### Other File locations +[Files] +PidPath = /var/run/urfd.pid +JsonPath = /var/log/urfd.json +WhitelistPath = /usr/local/etc/urfd.whitelist +BlacklistPath = /usr/local/etc/urfd.blacklist +InterlinkPath = /usr/local/etc/urfd.interlink +G3TerminalPath = /usr/local/etc/urfd.terminal