From 991d4899a010bcbe7533c78ae4beccc211d55520 Mon Sep 17 00:00:00 2001 From: Tom Early Date: Sat, 18 Feb 2023 12:37:29 -0700 Subject: [PATCH] Databases have switched to unordered_map, based on a new union in CCallsign --- .gitignore | 1 + reflector/Callsign.cpp | 253 ++++++++++++++++++++++----------------- reflector/Callsign.h | 36 ++++-- reflector/Lookup.cpp | 4 +- reflector/Lookup.h | 12 +- reflector/LookupDmr.cpp | 55 ++++++--- reflector/LookupDmr.h | 10 +- reflector/LookupNxdn.cpp | 56 ++++++--- reflector/LookupNxdn.h | 10 +- reflector/LookupYsf.cpp | 29 +++-- reflector/LookupYsf.h | 4 +- reflector/Main.cpp | 149 ++++++++++++++++++++++- reflector/Makefile | 9 +- reflector/example.ini | 51 ++++---- 14 files changed, 462 insertions(+), 217 deletions(-) diff --git a/.gitignore b/.gitignore index df15a05..6e6d5ab 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ reflector.cfg wiresx/configure.php urfd* inicheck +dbutil diff --git a/reflector/Callsign.cpp b/reflector/Callsign.cpp index 74a83d9..79d3065 100644 --- a/reflector/Callsign.cpp +++ b/reflector/Callsign.cpp @@ -31,98 +31,113 @@ CCallsign::CCallsign() { // blank all - memset(m_Callsign, ' ', CALLSIGN_LEN); - memset(m_Suffix, ' ', CALLSUFFIX_LEN); + memset(m_Callsign.c, ' ', CALLSIGN_LEN); + memset(m_Suffix.c, ' ', CALLSUFFIX_LEN); m_Module = ' '; m_uiDmrid = 0; m_coded = 0; } -CCallsign::CCallsign(const char *sz, uint32_t dmrid, uint16_t nxdnid) +CCallsign::CCallsign(const CCallsign &cs) { - // blank all - memset(m_Callsign, ' ', CALLSIGN_LEN); - memset(m_Suffix, ' ', CALLSUFFIX_LEN); - m_Module = ' '; - m_uiDmrid = dmrid; - m_uiNXDNid = nxdnid; + m_Callsign.l = cs.m_Callsign.l; + m_Suffix.u = cs.m_Suffix.u; + m_Module = cs.m_Module; + if (m_Callsign.l) + CSIn(); +} +CCallsign::CCallsign(const std::string &cs, uint32_t dmrid, uint16_t nxdnid) : CCallsign() +{ // and populate - auto len = strlen(sz); + m_uiDmrid = dmrid; + m_uiNXDNid = nxdnid; + auto len = cs.size(); if ( len > 0 ) { // callsign valid - memcpy(m_Callsign, sz, MIN(len, CALLSIGN_LEN-1)); - if ( len > CALLSIGN_LEN ) + memcpy(m_Callsign.c, cs.c_str(), MIN(len, CALLSIGN_LEN-1)); + if ( len >= CALLSIGN_LEN ) { - m_Module = sz[len-1]; + m_Module = cs.back(); } - // Calculate the M17 coded callsign - CSIn(); - - // dmrid ok ? - if ( m_uiDmrid == 0 ) + auto key = GetKey(); + if (0 == m_uiDmrid) { g_LDid.Lock(); - { - m_uiDmrid = g_LDid.FindDmrid(*this); - } + m_uiDmrid = g_LDid.FindDmrid(key); g_LDid.Unlock(); } - if ( m_uiNXDNid == 0 ) + + if (0 == m_uiNXDNid) { g_LNid.Lock(); - { - m_uiNXDNid = g_LNid.FindNXDNid(*this); - } + m_uiNXDNid = g_LNid.FindNXDNid(key); g_LNid.Unlock(); } } - else if ( m_uiDmrid != 0 ) + else if (dmrid) { g_LDid.Lock(); - { - const CCallsign *callsign = g_LDid.FindCallsign(m_uiDmrid); - if ( callsign != nullptr ) - { - memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN); - } - } + auto pItem = g_LDid.FindCallsign(dmrid); + if (pItem) + m_Callsign = *pItem; g_LDid.Unlock(); - if ( m_uiNXDNid == 0 ) + if (m_Callsign.l && 0 == nxdnid) { g_LNid.Lock(); - { - m_uiNXDNid = g_LNid.FindNXDNid(*this); - } + m_uiNXDNid = g_LNid.FindNXDNid(GetKey()); g_LNid.Unlock(); } - CSIn(); } - else if ( m_uiNXDNid != 0 ) + else if (nxdnid) { g_LNid.Lock(); - { - const CCallsign *callsign = g_LNid.FindCallsign(m_uiNXDNid); - if ( callsign != nullptr ) - { - memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN); - } - } + auto pItem = g_LNid.FindCallsign(nxdnid); + if (pItem) + m_Callsign = *pItem; g_LNid.Unlock(); - if ( m_uiDmrid == 0 ) + if (m_Callsign.l && 0 == dmrid) { g_LDid.Lock(); - { - m_uiDmrid = g_LDid.FindDmrid(*this); - } + m_uiDmrid = g_LDid.FindDmrid(GetKey()); g_LDid.Unlock(); } + } + if (m_Callsign.l) CSIn(); +} + +CCallsign::CCallsign(const CCallsign &cs) +{ + m_Callsign.l = cs.m_Callsign.l; + m_Suffix.u = cs.m_Suffix.u; + m_Module = cs.m_Module; + m_uiDmrid = cs.m_uiDmrid; + m_uiNXDNid = cs.m_uiNXDNid; + m_coded = cs.m_coded; +} + +CCallsign::CCallsign(const UCallsign &ucs) : CCallsign() +{ + m_Callsign.l = ucs.l; +} + +CCallsign &CCallsign::operator = (const CCallsign &cs) +{ + if (this != &cs) + { + m_Callsign.l = cs.m_Callsign.l; + m_Suffix.u = cs.m_Suffix.u; + m_Module = cs.m_Module; + m_uiDmrid = cs.m_uiDmrid; + m_uiNXDNid = cs.m_uiNXDNid; + m_coded = cs.m_coded; } + return *this; } //////////////////////////////////////////////////////////////////////////////////////// @@ -138,8 +153,8 @@ bool CCallsign::IsValid(void) const int iNum = 0; for ( i = 0; i < 3; i++ ) { - valid &= IsLetter(m_Callsign[i]) || IsNumber(m_Callsign[i]); - if ( IsNumber(m_Callsign[i]) ) + valid = valid && (IsLetter(m_Callsign.c[i]) || IsNumber(m_Callsign.c[i])); + if ( IsNumber(m_Callsign.c[i]) ) { iNum++; } @@ -148,19 +163,19 @@ bool CCallsign::IsValid(void) const // all remaining char are letter, number or space for ( ; i < CALLSIGN_LEN; i++) { - valid &= IsLetter(m_Callsign[i]) || IsNumber(m_Callsign[i]) || IsSpace(m_Callsign[i]); + valid = valid && (IsLetter(m_Callsign.c[i]) || IsNumber(m_Callsign.c[i]) || IsSpace(m_Callsign.c[i])); } // prefix // all chars are number, letter, special char, or space for ( i = 0; i < CALLSUFFIX_LEN; i++ ) { - valid &= IsLetter(m_Suffix[i]) || IsNumber(m_Suffix[i]) || IsSpace(m_Suffix[i]) || IsLetterLC(m_Suffix[i]) || IsSpecialChar(m_Suffix[i]); + valid = valid && (IsLetter(m_Suffix.c[i]) || IsNumber(m_Suffix.c[i]) || IsSpace(m_Suffix.c[i]) || IsLetterLC(m_Suffix.c[i]) || IsSpecialChar(m_Suffix.c[i])); } // module // is an letter or space - valid &= IsLetter(m_Module) || IsSpace(m_Module); + valid = valid && (IsLetter(m_Module) || IsSpace(m_Module)); // dmrid is not tested, as it can be nullptr // if station does is not dmr registered @@ -171,41 +186,37 @@ bool CCallsign::IsValid(void) const bool CCallsign::HasSuffix(void) const { - bool has = false; - for ( int i = 0; i < CALLSUFFIX_LEN; i++ ) - { - has |= (m_Suffix[i] != ' '); - } - return has; + return 0 == memcmp(m_Suffix.c, " ", 4); } //////////////////////////////////////////////////////////////////////////////////////// // set -void CCallsign::SetCallsign(const char *sz, bool UpdateDmrid) +void CCallsign::SetCallsign(const std::string &s, bool updateids) { // set callsign - memset(m_Callsign, ' ', CALLSIGN_LEN); + memset(m_Callsign.c, ' ', CALLSIGN_LEN); m_Module = ' '; - auto len = strlen(sz); - memcpy(m_Callsign, sz, MIN(len, CALLSIGN_LEN-1)); - if ( len > CALLSIGN_LEN ) + auto len = s.size(); + memcpy(m_Callsign.c, s.c_str(), MIN(len, CALLSIGN_LEN-1)); + if ( len >= CALLSIGN_LEN ) { - m_Module = sz[len-1]; + m_Module = s.back(); } // update M17 coded callsign CSIn(); // and update dmrid - if ( UpdateDmrid ) + if (updateids) { + auto key = GetKey(); g_LDid.Lock(); { - m_uiDmrid = g_LDid.FindDmrid(*this); + m_uiDmrid = g_LDid.FindDmrid(key); } g_LDid.Unlock(); g_LNid.Lock(); { - m_uiNXDNid = g_LNid.FindNXDNid(*this); + m_uiNXDNid = g_LNid.FindNXDNid(key); } g_LNid.Unlock(); } @@ -214,14 +225,14 @@ void CCallsign::SetCallsign(const char *sz, bool UpdateDmrid) void CCallsign::SetCallsign(const uint8_t *buffer, int len, bool UpdateDmrid) { // set callsign - memset(m_Callsign, ' ', CALLSIGN_LEN); + memset(m_Callsign.c, ' ', CALLSIGN_LEN); m_Module = ' '; - memcpy(m_Callsign, buffer, MIN(len, (int)CALLSIGN_LEN-1)); + memcpy(m_Callsign.c, buffer, MIN(len, (int)CALLSIGN_LEN-1)); for ( unsigned i = 0; i < CALLSIGN_LEN; i++ ) { - if ( m_Callsign[i] == 0 ) + if ( m_Callsign.c[i] == 0 ) { - m_Callsign[i] = ' '; + m_Callsign.c[i] = ' '; } } if ( (len >= (int)CALLSIGN_LEN) && ((char)buffer[CALLSIGN_LEN-1] != 0) ) @@ -231,14 +242,15 @@ void CCallsign::SetCallsign(const uint8_t *buffer, int len, bool UpdateDmrid) CSIn(); if ( UpdateDmrid ) { + auto key = GetKey(); g_LDid.Lock(); { - m_uiDmrid = g_LDid.FindDmrid(*this); + m_uiDmrid = g_LDid.FindDmrid(key); } g_LDid.Unlock(); g_LNid.Lock(); { - m_uiNXDNid = g_LNid.FindNXDNid(*this); + m_uiNXDNid = g_LNid.FindNXDNid(key); } g_LNid.Unlock(); } @@ -251,13 +263,14 @@ void CCallsign::SetDmrid(uint32_t dmrid, bool UpdateCallsign) { g_LDid.Lock(); { - const CCallsign *callsign = g_LDid.FindCallsign(dmrid); + auto callsign = g_LDid.FindCallsign(dmrid); if ( callsign != nullptr ) { - memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN); + m_Callsign.l = callsign->l; } } g_LDid.Unlock(); + CSIn(); } } @@ -276,13 +289,14 @@ void CCallsign::SetNXDNid(uint16_t nxdnid, bool UpdateCallsign) { g_LNid.Lock(); { - const CCallsign *callsign = g_LNid.FindCallsign(nxdnid); + auto callsign = g_LNid.FindCallsign(nxdnid); if ( callsign != nullptr ) { - memcpy(m_Callsign, callsign->m_Callsign, CALLSIGN_LEN); + m_Callsign.l = callsign->l; } } g_LNid.Unlock(); + CSIn(); } } @@ -301,17 +315,17 @@ void CCallsign::SetCSModule(char c) } -void CCallsign::SetSuffix(const char *sz) +void CCallsign::SetSuffix(const std::string &s) { - memset(m_Suffix, ' ', CALLSUFFIX_LEN); - memcpy(m_Suffix, sz, MIN(strlen(sz), CALLSUFFIX_LEN)); + memset(m_Suffix.c, ' ', CALLSUFFIX_LEN); + memcpy(m_Suffix.c, s.c_str(), MIN(s.size(), CALLSUFFIX_LEN)); } void CCallsign::SetSuffix(const uint8_t *buffer, int len) { len = MIN(len, (int)CALLSUFFIX_LEN); - memset(m_Suffix, ' ', CALLSUFFIX_LEN); - memcpy(m_Suffix, buffer, len); + memset(m_Suffix.c, ' ', CALLSUFFIX_LEN); + memcpy(m_Suffix.c, buffer, len); } //////////////////////////////////////////////////////////////////////////////////////// @@ -321,7 +335,7 @@ void CCallsign::PatchCallsign(int off, const char *patch, int len) { if ( off < CALLSIGN_LEN ) { - memcpy(m_Callsign, patch, MIN(len, (int)CALLSIGN_LEN - off)); + memcpy(m_Callsign.c, patch, MIN(len, (int)CALLSIGN_LEN - off)); } CSIn(); } @@ -330,9 +344,24 @@ void CCallsign::PatchCallsign(int off, const char *patch, int len) //////////////////////////////////////////////////////////////////////////////////////// // get +const UCallsign CCallsign::GetKey() const +{ + UCallsign rval; + rval.l = 0; + for (unsigned i=0; i=0; i-- ) { - pos = m17_alphabet.find(m_Callsign[i]); + pos = m17_alphabet.find(m_Callsign.c[i]); if (pos == std::string::npos) { pos = 0; } diff --git a/reflector/Callsign.h b/reflector/Callsign.h index 6e5d734..c0a6901 100644 --- a/reflector/Callsign.h +++ b/reflector/Callsign.h @@ -27,6 +27,18 @@ #define CALLSIGN_LEN 8 #define CALLSUFFIX_LEN 4 +union UCallsign +{ + char c[CALLSIGN_LEN]; + uint64_t l; +}; + +union USuffix +{ + char c[CALLSUFFIX_LEN]; + uint32_t u; +}; + //////////////////////////////////////////////////////////////////////////////////////// // class @@ -36,7 +48,9 @@ class CCallsign public: // contructors CCallsign(); - CCallsign(const char *, uint32_t = 0, uint16_t = 0); + CCallsign(const UCallsign &cs); // no id lookup + CCallsign(const CCallsign &cs); + CCallsign(const std::string &cs, uint32_t dmrid = 0, uint16_t nxdnid = 0); // status bool IsValid(void) const; @@ -44,23 +58,24 @@ public: bool HasModule(void) const { return m_Module != ' '; } // set - void SetCallsign(const char *, bool = true); + void SetCallsign(const std::string &s, bool updateids = true); void SetCallsign(const uint8_t *, int, bool = true); void SetDmrid(uint32_t, bool = true); void SetDmrid(const uint8_t *, bool = true); void SetNXDNid(uint16_t, bool = true); void SetNXDNid(const uint8_t *, bool = true); void SetCSModule(char); - void SetSuffix(const char *); + void SetSuffix(const std::string &s); void SetSuffix(const uint8_t *, int); // modify void PatchCallsign(int, const char *, int); // get + const UCallsign GetKey() const; void GetCallsign(uint8_t *) const; void GetCallsignString(char *) const; - const std::string GetCS(unsigned len = 9) const; + const std::string GetCS() const; uint32_t GetDmrid(void) const { return m_uiDmrid; } uint16_t GetNXDNid(void) const { return m_uiNXDNid; } void GetSuffix(uint8_t *) const; @@ -73,6 +88,7 @@ public: bool HasSameModule(const CCallsign &) const; // operators + CCallsign &operator = (const CCallsign &cs); bool operator ==(const CCallsign &) const; operator const char *() const; @@ -92,10 +108,10 @@ protected: protected: // data - char m_Callsign[CALLSIGN_LEN]; - char m_Suffix[CALLSUFFIX_LEN]; - char m_Module; - uint32_t m_uiDmrid; - uint16_t m_uiNXDNid; - uint64_t m_coded; // M17 encoded callsign + UCallsign m_Callsign; + USuffix m_Suffix; + char m_Module; + uint32_t m_uiDmrid; + uint16_t m_uiNXDNid; + uint64_t m_coded; // M17 encoded callsign }; diff --git a/reflector/Lookup.cpp b/reflector/Lookup.cpp index 5d4d07e..f70bfa3 100644 --- a/reflector/Lookup.cpp +++ b/reflector/Lookup.cpp @@ -86,7 +86,7 @@ void CLookup::Thread() // It would be a lot of work (iterating on an unordered_map) to do otherwise! if (http_loaded || ERefreshType::file == m_Type) ClearContents(); - UpdateContent(ss); + UpdateContent(ss, Eaction::normal); Unlock(); } @@ -115,7 +115,7 @@ bool CLookup::LoadContentFile(std::stringstream &ss) return rval; } -bool CLookup::Dump() +bool CLookup::Utility(Eaction action) { std::stringstream ss; LoadParameters(); diff --git a/reflector/Lookup.h b/reflector/Lookup.h index f921c81..bbc86bb 100644 --- a/reflector/Lookup.h +++ b/reflector/Lookup.h @@ -24,14 +24,16 @@ #include "Callsign.h" #include "Configure.h" +enum class Eaction { normal, parse, error_only }; + // compare function for std::map::find struct CCallsignHash { - std::size_t operator() (const CCallsign &cs) const + std::size_t operator() (const UCallsign &ucs) const { - std::hash hash; - return hash(cs.GetCS()); + std::hash hash; + return hash(ucs.l); } }; @@ -50,7 +52,7 @@ public: // locks void Lock(void) { m_Mutex.lock(); } void Unlock(void) { m_Mutex.unlock(); } - bool Dump(void); + bool Utility(Eaction action); protected: std::time_t GetLastModTime(); @@ -61,7 +63,7 @@ protected: // refresh bool LoadContentHttp(std::stringstream &ss); bool LoadContentFile(std::stringstream &ss); - virtual void UpdateContent(std::stringstream &ss) = 0; + virtual void UpdateContent(std::stringstream &ss, Eaction action) = 0; std::mutex m_Mutex; ERefreshType m_Type; diff --git a/reflector/LookupDmr.cpp b/reflector/LookupDmr.cpp index 14b3a0f..e71a7de 100644 --- a/reflector/LookupDmr.cpp +++ b/reflector/LookupDmr.cpp @@ -37,10 +37,9 @@ void CLookupDmr::LoadParameters() m_Url.assign(g_Conf.GetString(g_Keys.dmriddb.url)); } -uint32_t CLookupDmr::FindDmrid(const CCallsign &callsign) +const uint32_t CLookupDmr::FindDmrid(const UCallsign &ucs) const { - - auto found = m_DmridMap.find(callsign); + auto found = m_DmridMap.find(ucs); if ( found != m_DmridMap.end() ) { return (found->second); @@ -48,7 +47,7 @@ uint32_t CLookupDmr::FindDmrid(const CCallsign &callsign) return 0; } -const CCallsign *CLookupDmr::FindCallsign(uint32_t dmrid) +const UCallsign *CLookupDmr::FindCallsign(const uint32_t dmrid) const { auto found = m_CallsignMap.find(dmrid); if ( found != m_CallsignMap.end() ) @@ -58,27 +57,47 @@ const CCallsign *CLookupDmr::FindCallsign(uint32_t dmrid) return nullptr; } -void CLookupDmr::UpdateContent(std::stringstream &ss) +void CLookupDmr::UpdateContent(std::stringstream &ss, Eaction action) { std::string line; while (std::getline(ss, line)) { - std::string cs_str, id_str; - std::istringstream iss(line); - std::getline(iss, id_str, ';'); - std::getline(iss, cs_str, ';'); - auto lid = stol(id_str); - if (lid > 0 && lid < 0x1000000 && cs_str.size() < CALLSIGN_LEN) + bool failed = true; + auto l = atol(line.c_str()); // no throw guarantee + if (0L < l && l <= 9999999L) { - auto id = uint32_t(lid); - CCallsign cs(cs_str.c_str(), id); - m_DmridMap[cs] = id; - m_CallsignMap[id] = cs; + auto id = uint32_t(l); + auto p1 = line.find(';'); + if (std::string::npos != p1) + { + auto p2 = line.find(';', ++p1); + if (std::string::npos != p2) + { + const auto cs_str(line.substr(p1, p2-p1)); + CCallsign cs; + cs.SetCallsign(cs_str, false); + if (cs.IsValid()) + { + failed = false; + if (Eaction::normal == action) + { + auto key = cs.GetKey(); + m_DmridMap[key] = id; + m_CallsignMap[id] = key; + } + else if (Eaction::parse == action) + { + std::cout << id << ';' << cs_str << ";\n"; + } + } + } + } } - else + if (Eaction::error_only == action && failed) { - std::cout << "DMR Id '" << id_str << ';' << cs_str << ";' is malformed" << std::endl; + std::cout << "Bad syntax at line '" << line << "'\n"; } } - std::cout << "DMR Id database size now is " << m_DmridMap.size() << std::endl; + if (Eaction::normal == action) + std::cout << "DMR Id database size: " << m_DmridMap.size() << std::endl; } diff --git a/reflector/LookupDmr.h b/reflector/LookupDmr.h index 360262f..a0f1851 100644 --- a/reflector/LookupDmr.h +++ b/reflector/LookupDmr.h @@ -24,15 +24,15 @@ class CLookupDmr : public CLookup { public: ~CLookupDmr() {} - uint32_t FindDmrid(const CCallsign &cs); - const CCallsign *FindCallsign(uint32_t dmrid); + const uint32_t FindDmrid(const UCallsign &ucs) const; + const UCallsign *FindCallsign(uint32_t dmrid) const; protected: void ClearContents(); void LoadParameters(); - void UpdateContent(std::stringstream &ss); + void UpdateContent(std::stringstream &ss, Eaction action); private: - std::unordered_map m_CallsignMap; - std::unordered_map m_DmridMap; + std::unordered_map m_CallsignMap; + std::unordered_map m_DmridMap; }; diff --git a/reflector/LookupNxdn.cpp b/reflector/LookupNxdn.cpp index 6f5e7d9..7379c8f 100644 --- a/reflector/LookupNxdn.cpp +++ b/reflector/LookupNxdn.cpp @@ -37,7 +37,7 @@ void CLookupNxdn::LoadParameters() m_Url.assign(g_Conf.GetString(g_Keys.nxdniddb.url)); } -const CCallsign *CLookupNxdn::FindCallsign(uint16_t nxdnid) +const UCallsign *CLookupNxdn::FindCallsign(uint16_t nxdnid) const { auto found = m_CallsignMap.find(nxdnid); if ( found != m_CallsignMap.end() ) @@ -47,37 +47,57 @@ const CCallsign *CLookupNxdn::FindCallsign(uint16_t nxdnid) return nullptr; } -uint16_t CLookupNxdn::FindNXDNid(const CCallsign &callsign) +const uint16_t CLookupNxdn::FindNXDNid(const UCallsign &ucs) const { - auto found = m_NxdnidMap.find(callsign); + auto found = m_NxdnidMap.find(ucs); if ( found != m_NxdnidMap.end() ) { - return (found->second); + return found->second; } return 0; } -void CLookupNxdn::UpdateContent(std::stringstream &ss) +void CLookupNxdn::UpdateContent(std::stringstream &ss, Eaction action) { std::string line; while (std::getline(ss, line)) { - std::string cs_str, id_str; - std::istringstream iss(line); - std::getline(iss, id_str, ','); - std::getline(iss, cs_str, ','); - auto lid = stol(id_str); - if (lid > 0 && lid < 0x10000 && cs_str.size() < CALLSIGN_LEN) + bool failed = true; + auto l = atol(line.c_str()); // no throw guarantee + if (0 < l && l < 0x10000UL) { - auto id = uint16_t(lid); - CCallsign cs(cs_str.c_str(), 0, id); - m_NxdnidMap[cs] = id; - m_CallsignMap[id] = cs; + auto id = uint32_t(l); + auto p1 = line.find(','); + if (std::string::npos != p1) + { + auto p2 = line.find(',', ++p1); + if (std::string::npos != p2) + { + const auto cs_str = line.substr(p1, p2-p1); + CCallsign cs; + cs.SetCallsign(cs_str, false); + if (cs.IsValid()) + { + failed = false; + if (Eaction::normal == action) + { + auto key = cs.GetKey(); + m_NxdnidMap[key] = id; + m_CallsignMap[id] = key; + } + else if (Eaction::parse == action) + { + std::cout << id << ',' << cs_str << ",\n"; + } + } + } + } } - else + if (Eaction::error_only == action && failed) { - std::cout << "NXDN Id '" << id_str << ',' << cs_str << ",' is malformed" << std::endl; + std::cout << "Bad syntax at line '" << line << "'\n"; } } - std::cout << "NXDN Id database size now is " << m_NxdnidMap.size() << std::endl; + if (Eaction::normal == action) + std::cout << "NXDN Id database size: " << m_NxdnidMap.size() << std::endl; } diff --git a/reflector/LookupNxdn.h b/reflector/LookupNxdn.h index 946ab9a..ca503f6 100644 --- a/reflector/LookupNxdn.h +++ b/reflector/LookupNxdn.h @@ -23,14 +23,14 @@ class CLookupNxdn : public CLookup { public: - uint16_t FindNXDNid(const CCallsign &callsign); - const CCallsign *FindCallsign(uint16_t id); + const uint16_t FindNXDNid(const UCallsign &ucs) const; + const UCallsign *FindCallsign(const uint16_t id) const; protected: void ClearContents(); void LoadParameters(); - void UpdateContent(std::stringstream &ss); + void UpdateContent(std::stringstream &ss, Eaction action); private: - std::unordered_map m_CallsignMap; - std::unordered_map m_NxdnidMap; + std::unordered_map m_CallsignMap; + std::unordered_map m_NxdnidMap; }; diff --git a/reflector/LookupYsf.cpp b/reflector/LookupYsf.cpp index 2b45a12..6964bb6 100644 --- a/reflector/LookupYsf.cpp +++ b/reflector/LookupYsf.cpp @@ -39,34 +39,43 @@ void CLookupYsf::LoadParameters() m_DefaultRx = g_Conf.GetUnsigned(g_Keys.ysf.defaultrxfreq); } -void CLookupYsf::UpdateContent(std::stringstream &ss) +void CLookupYsf::UpdateContent(std::stringstream &ss, Eaction action) { std::string line; while (std::getline(ss, line)) { + CCallsign cs; std::string cs_str, tx_str, rx_str; std::istringstream iss(line); std::getline(iss, cs_str, ';'); std::getline(iss, tx_str, ';'); std::getline(iss, rx_str, ';'); - auto ltx = stol(tx_str); - auto lrx = stol(rx_str); - if (ltx > 40000000 && ltx < 0x100000000 && lrx > 40000000 && lrx < 0x100000000 && CCallsign(cs_str.c_str()).IsValid()) + cs.SetCallsign(cs_str, false); + auto ltx = atol(tx_str.c_str()); + auto lrx = atol(rx_str.c_str()); + if (ltx > 40000000 && ltx < 0x100000000 && lrx > 40000000 && lrx < 0x100000000 && cs.IsValid()) { - m_map.emplace(CCallsign(cs_str.c_str()), CYsfNode(uint32_t(ltx), uint32_t(lrx))); + if (Eaction::parse == action) + { + std::cout << cs_str << ';' << tx_str << ';' << rx_str << ";\n"; + } + else if (Eaction::normal == action) + { + m_map[cs.GetKey()] = CYsfNode(ltx, lrx); + } } - else + else if (Eaction::error_only == action) { - std::cout << "YSF value '" << cs_str << ';' << tx_str << ';' << rx_str << ";' is malformed" << std::endl; + std::cout << "YSF value '" << line << ";' is malformed" << std::endl; } } std::cout << "DMR Id database size now is " << m_map.size() << std::endl; } -void CLookupYsf::FindFrequencies(const CCallsign &callsign, uint32_t &txfreq, uint32_t &rxfreq) +void CLookupYsf::FindFrequencies(const CCallsign &cs, uint32_t &txfreq, uint32_t &rxfreq) { - auto found = m_map.find(callsign); - if ( found != m_map.end() ) + auto found = m_map.find(cs.GetKey()); + if (found != m_map.end()) { txfreq = found->second.GetTxFrequency(); rxfreq = found->second.GetRxFrequency(); diff --git a/reflector/LookupYsf.h b/reflector/LookupYsf.h index 8c8fa90..2efc11f 100644 --- a/reflector/LookupYsf.h +++ b/reflector/LookupYsf.h @@ -21,7 +21,7 @@ #include "YSFNode.h" #include "Lookup.h" -using CsNodeMap = std::unordered_map; +using CsNodeMap = std::unordered_map; class CLookupYsf : public CLookup { @@ -31,7 +31,7 @@ public: protected: void ClearContents(); void LoadParameters(); - void UpdateContent(std::stringstream &ss); + void UpdateContent(std::stringstream &ss, Eaction action); private: CsNodeMap m_map; diff --git a/reflector/Main.cpp b/reflector/Main.cpp index 21d8205..d1b82b0 100644 --- a/reflector/Main.cpp +++ b/reflector/Main.cpp @@ -20,9 +20,11 @@ #include "Global.h" +#ifndef UTILITY //////////////////////////////////////////////////////////////////////////////////////// // global objects +SJsonKeys g_Keys; CReflector g_Refl; CGateKeeper g_Gate; CConfigure g_Conf; @@ -30,7 +32,6 @@ CVersion g_Vers(3,0,0); // The major byte should only change if the interlink CLookupDmr g_LDid; CLookupNxdn g_LNid; CLookupYsf g_LYtr; -SJsonKeys g_Keys; //////////////////////////////////////////////////////////////////////////////////////// @@ -75,3 +76,149 @@ int main(int argc, char *argv[]) // done return EXIT_SUCCESS; } + +#else // UTILITY is defined + +#include + +//////////////////////////////////////////////////////////////////////////////////////// +// global objects + +SJsonKeys g_Keys; +CConfigure g_Conf; +CLookupDmr g_LDid; +CLookupNxdn g_LNid; +CLookupYsf g_LYtr; + +static void usage(std::ostream &os, const char *name) +{ + os << "Usage: " << name << " [-d | -n | -y] [-p | -q] inifile\n"; + os << "Where:\n" + " -d - read the DMR Id http source (default)\n" + " -n - read the NXDN Id http source\n" + " -y - read the YSF Tx/Tx http source\n" + " -p - parse the input, removing bad lines\n" + " -q - parse the input, but only output problem lines in the http source\n" + " infile - an error-free urfd ini file (check it first with inicheck)\n" + "Without -p or -q, no parsing is done and the raw http source is output\n" + << std::endl; +} + +enum class Edb { none, dmr, nxdn, ysf }; + +int main(int argc, char *argv[]) +{ + Edb db = Edb::none; + Eaction action = Eaction::normal; + while (1) + { + auto c = getopt(argc, argv, "dnypq"); + if (c < 0) + { + if (1 == argc) + { + usage(std::cout, argv[0]); + return EXIT_SUCCESS; + } + break; + } + else + { + switch (c) + { + // define the input souce + case 'd': + if (Edb::none == db) + db = Edb::dmr; + else + { + std::cerr << "You can only select one database!\n"; + usage(std::cerr, argv[0]); + return EXIT_FAILURE; + } + break; + + case 'n': + if (Edb::none == db) + db = Edb::nxdn; + else + { + std::cerr << "You can only select one database!\n"; + usage(std::cerr, argv[0]); + return EXIT_FAILURE; + } + break; + case 'y': + if (Edb::none == db) + db = Edb::ysf; + else + { + std::cerr << "You can only select one database!\n"; + usage(std::cerr, argv[0]); + return EXIT_FAILURE; + } + break; + + // define the action + case 'p': + if (Eaction::err_only == action) + { + std::cerr << "You can't specify both -p and -q!\n"; + usage(std::cerr, argv[0]); + return EXIT_FAILURE; + } + else + action = Eaction::parse; + break; + + case 'q': + if (Eaction::parse == action) + { + std::cerr << "You can't specify both -p and -q!\n"; + usage(std::cerr, argv[0]); + return EXIT_FAILURE; + } + else + action = Eaction::err_only; + break; + + // finally + default: + usage(std::cerr, argv[0]); + return EXIT_FAILURE; + break; + } + } + } + + if (optind + 1 != argc) + { + std::cerr << argv[0] << ": " << ((optind==argc) ? "No ini file specified!" : "Too many arguments!") << std::endl; + usage(std::cerr, argv[0]); + exit(EXIT_FAILURE); + } + + if (g_Conf.ReadData(argv[optind])) + return EXIT_FAILURE; + + if (Edb::none == db) + db = Edb::dmr; + + switch (db) + { + case Edb::dmr: + g_LDid.Utility(action); + break; + + case Edb::nxdn: + g_LNid.Utility(action); + break; + + case Edb::ysf: + g_LYtr.Utility(action); + break; + } + + return EXIT_SUCCESS; +} +#endif diff --git a/reflector/Makefile b/reflector/Makefile index 333d07a..0ce66d6 100644 --- a/reflector/Makefile +++ b/reflector/Makefile @@ -22,6 +22,8 @@ EXE = urfd INICHECK = inicheck +DBUTIL = dbutil + include configure.mk ifeq ($(debug), true) @@ -36,7 +38,7 @@ SRCS = $(wildcard *.cpp) OBJS = $(SRCS:.cpp=.o) DEPS = $(SRCS:.cpp=.d) -all : $(EXE) $(INICHECK) +all : $(EXE) $(INICHECK) $(DBUTIL) $(EXE) : $(OBJS) $(CXX) $^ -o $@ $(LDFLAGS) @@ -44,11 +46,14 @@ $(EXE) : $(OBJS) $(INICHECK) : Configure.cpp CurlGet.cpp $(CXX) -DINICHECK $(CFLAGS) Configure.cpp CurlGet.cpp -o $(INICHECK) -lcurl +$(DBUTIL) : Main.cpp Configure.cpp CurlGet.cpp Lookup.cpp LookupDmr.cpp LookupNxdn.cpp LookupYsf.cpp YSFNode.cpp Callsign.cpp + $(CXX) -DUTILITY $(CFLAGS) -o dbutil Main.cpp Configure.cpp CurlGet.cpp Lookup.cpp LookupDmr.cpp LookupNxdn.cpp LookupYsf.cpp YSFNode.cpp Callsign.cpp -lcurl + %.o : %.cpp $(CXX) $(CFLAGS) -c $< -o $@ clean : - $(RM) *.o *.d $(EXE) $(INICHECK) + $(RM) *.o *.d $(EXE) $(INICHECK) $(DBUTIL) -include $(DEPS) diff --git a/reflector/example.ini b/reflector/example.ini index b404452..a8d69a2 100644 --- a/reflector/example.ini +++ b/reflector/example.ini @@ -1,15 +1,16 @@ ###### URFD CONFIGURATION Example ###### +# comments begin with '#' # Do not use quotes, unless in a comment! [Names] Callsign = URF??? # where ? is A-Z or 0-9 -SysopEmail = you@somewhere.com +SysopEmail = me@somewhere.com # 2-letter country codes are listed at https://www.iban.com/country-codes -Country = US +Country = GB -Sponsor = My Ham Club +Sponsor = My Home Club [IpAddresses] # Binding addresses are usually the 'any' address @@ -19,16 +20,15 @@ IPv4Binding = 0.0.0.0 # IPv6Binding = :: # define if you want to override what urfd finds using ipv4.icanhazip.com -# IPv4External = 1.2.3.4 - +# IPv4External = 4.3.2.1 # define if you want to override what urfd finds using ipv6.icanhazip.com -# IPv6External = a:b:c:e:f:0:1:2 +# IPv6External = f:e:d:c:b:a:9:0 Transcoder = local # SORRY, but only local TC's are supported right now! [Modules] -Modules = ADMSZ # Modules = ABCDEFGHIJKLMNOPQRSTUVWXYZ +Modules = ADMSZ Transcoded = A # comment out if you don't have transcoding hardware # Create Descriptions as needed... DescriptionA = Transcoded @@ -58,7 +58,7 @@ Port = 17000 [MMDVM] Port = 62030 -DefaultId = 0 # if the DMR id is zero, this will be used (also used for P25) +DefaultId = 0 [NXDN] Port = 41400 @@ -77,7 +77,7 @@ Port = 10017 Port = 34001 AutoLinkModule = A # comment out if you want to disable AL DefaultCallsign = ALLSTAR -ClientFilePath = /home/user/urfd/USRPClients.txt +ClientFilePath = /usr/local/etc/USRPClients.txt [YSF] Port = 42000 @@ -91,31 +91,30 @@ RegistrationDescription = URF Reflector ######## Database files [DMR ID DB] -Hostname = xlxapi.rlx.lu -Suffix = api/exportdmr.php -Mode = http -RefreshMin = 179 -FilePath = /home/user/urfd/dmrid.dat +Mode = http #### Mode is "http", "file", or "both" + #### if "both", the url will be read first +FilePath = /usr/local/etc/dmrid.dat # for you to add your own values + # will be reloaded quickly, about 10s +URL = http://xlxapi.rlx.lu/api/exportdmr.php # if Mode "http" or "both" +RefreshMin = 179 # RefreshMin will only be used if the Mode is "file" [NXDN ID DB] -Hostname = www.dudetronics.com -Suffix = ar-dns/NXDN.csv Mode = http -RefreshMin = 181 -FilePath = /home/user/urfd/nxdn.dat +FilePath = /usr/local/etc/nxdn.dat +URL = https://radioid.net/static/nxdn.csv +RefreshMin = 1440 # radioid.net says this file is updated once/day [YSF TX/RX DB] -Hostname = xlxapi.rlx.lu -Suffix = api/exportysfrepeaters.php Mode = http +FilePath = /usr/local/etc/ysfnode.dat +URL = http://xlxapi.rlx.lu/api/exportysfrepeaters.php RefreshMin = 191 -FilePath = /home/user/urfd/ysfnode.dat ######### Other File locations [Files] -PidPath = /var/run/urfd.pid +PidPath = /var/run/urfd.pid JsonPath = /var/log/urfd.json -WhitelistPath = /home/user/urfd/urfd.whitelist -BlacklistPath = /home/user/urfd/urfd.blacklist -InterlinkPath = /home/user/urfd/urfd.interlink -G3TerminalPath = /home/user/urfd/urfd.terminal +WhitelistPath = /usr/local/etc/urfd.whitelist +BlacklistPath = /usr/local/etc/urfd.blacklist +InterlinkPath = /usr/local/etc/urfd.interlink +G3TerminalPath = /usr/local/etc/urfd.terminal