Databases have switched to unordered_map, based on a new union in CCallsign

pull/1/head
Tom Early 3 years ago
parent 7664b7305c
commit 991d4899a0

1
.gitignore vendored

@ -12,3 +12,4 @@ reflector.cfg
wiresx/configure.php
urfd*
inicheck
dbutil

@ -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<CALLSIGN_LEN; i++)
{
auto c = m_Callsign.c[i];
if (IsLetter(c) || IsNumber(c))
rval.c[i] = c;
else
break;
}
return rval;
}
void CCallsign::GetCallsign(uint8_t *buffer) const
{
memcpy(buffer, m_Callsign, CALLSIGN_LEN);
memcpy(buffer, m_Callsign.c, CALLSIGN_LEN);
if ( HasModule() )
{
buffer[CALLSIGN_LEN-1] = m_Module;
@ -342,51 +371,52 @@ void CCallsign::GetCallsign(uint8_t *buffer) const
void CCallsign::GetCallsignString(char *sz) const
{
unsigned i;
for ( i = 0; (i < CALLSIGN_LEN) && (m_Callsign[i] != ' '); i++ )
for ( i = 0; (i < CALLSIGN_LEN) && (m_Callsign.c[i] != ' '); i++ )
{
sz[i] = m_Callsign[i];
sz[i] = m_Callsign.c[i];
}
sz[i] = 0;
}
const std::string CCallsign::GetCS(unsigned len) const
const std::string CCallsign::GetCS() const
{
std::string rval(m_Callsign, CALLSIGN_LEN);
rval.append(1, m_Module);
std::string rval(m_Callsign.c, CALLSIGN_LEN);
if (' ' != m_Module)
rval.append(1, m_Module);
return rval;
}
void CCallsign::GetSuffix(uint8_t *buffer) const
{
memcpy(buffer, m_Suffix, CALLSUFFIX_LEN);
memcpy(buffer, m_Suffix.c, CALLSUFFIX_LEN);
}
////////////////////////////////////////////////////////////////////////////////////////
// compare
bool CCallsign::HasSameCallsign(const CCallsign &Callsign) const
bool CCallsign::HasSameCallsign(const CCallsign &cs) const
{
return (memcmp(m_Callsign, Callsign.m_Callsign, CALLSIGN_LEN) == 0);
return (memcmp(m_Callsign.c, cs.m_Callsign.c, CALLSIGN_LEN) == 0);
}
bool CCallsign::HasSameCallsignWithWildcard(const CCallsign &callsign) const
bool CCallsign::HasSameCallsignWithWildcard(const CCallsign &cs) const
{
bool same = true;
bool done = false;
for ( unsigned i = 0; (i < CALLSIGN_LEN) && same && !done; i++ )
{
if ( !(done = ((m_Callsign[i] == '*') || (callsign[i] == '*'))) )
if ( !(done = ((m_Callsign.c[i] == '*') || (cs.m_Callsign.c[i] == '*'))) )
{
same &= (m_Callsign[i] == callsign[i]);
same = same && (m_Callsign.c[i] == cs.m_Callsign.c[i]);
}
}
return same;
}
bool CCallsign::HasLowerCallsign(const CCallsign &Callsign) const
bool CCallsign::HasLowerCallsign(const CCallsign &cs) const
{
return (memcmp(m_Callsign, Callsign.m_Callsign, CALLSIGN_LEN) < 0);
return (memcmp(m_Callsign.c, cs.m_Callsign.c, CALLSIGN_LEN) < 0);
}
bool CCallsign::HasSameModule(const CCallsign &Callsign) const
@ -398,36 +428,33 @@ bool CCallsign::HasSameModule(const CCallsign &Callsign) const
////////////////////////////////////////////////////////////////////////////////////////
// operators
bool CCallsign::operator ==(const CCallsign &callsign) const
bool CCallsign::operator ==(const CCallsign &cs) const
{
return ((memcmp(callsign.m_Callsign, m_Callsign, CALLSIGN_LEN) == 0) && (m_Module == callsign.m_Module)
&& (memcmp(callsign.m_Suffix, m_Suffix, CALLSUFFIX_LEN) == 0)
&& (m_uiDmrid == callsign.m_uiDmrid)
);
return (cs.m_Callsign.l == m_Callsign.l) && (m_Module == cs.m_Module) && (cs.m_Suffix.u == m_Suffix.u) && (m_uiDmrid == cs.m_uiDmrid) && (m_uiNXDNid == cs.m_uiNXDNid);
}
CCallsign::operator const char *() const
{
static char m_sz[CALLSIGN_LEN+CALLSUFFIX_LEN+5];
static char sz[CALLSIGN_LEN+CALLSUFFIX_LEN+5];
// empty
memset(m_sz, 0, sizeof(m_sz));
memset(sz, 0, sizeof(sz));
// callsign
memcpy(m_sz, m_Callsign, CALLSIGN_LEN);
memcpy(sz, m_Callsign.c, CALLSIGN_LEN);
// module
if ( HasModule() )
{
m_sz[CALLSIGN_LEN] = m_Module;
sz[CALLSIGN_LEN] = m_Module;
}
// suffix
if ( HasSuffix() )
{
::strcat(m_sz, " / ");
::strncat(m_sz, m_Suffix, CALLSUFFIX_LEN);
::strcat(sz, " / ");
::strncat(sz, m_Suffix.c, CALLSUFFIX_LEN);
}
// done
return m_sz;
return sz;
}
////////////////////////////////////////////////////////////////////////////////////////
@ -499,7 +526,7 @@ void CCallsign::CSIn()
m_coded = pos;
m_coded *= 40;
for( int i=CALLSIGN_LEN-2; 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;
}

@ -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
};

@ -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();

@ -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<std::string> hash;
return hash(cs.GetCS());
std::hash<uint64_t> 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;

@ -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;
}

@ -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<uint32_t, CCallsign> m_CallsignMap;
std::unordered_map<CCallsign, uint32_t, CCallsignHash> m_DmridMap;
std::unordered_map<uint32_t, UCallsign> m_CallsignMap;
std::unordered_map<UCallsign, uint32_t, CCallsignHash> m_DmridMap;
};

@ -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;
}

@ -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 <uint32_t, CCallsign> m_CallsignMap;
std::unordered_map <CCallsign, uint32_t, CCallsignHash> m_NxdnidMap;
std::unordered_map <uint32_t, UCallsign> m_CallsignMap;
std::unordered_map <UCallsign, uint32_t, CCallsignHash> m_NxdnidMap;
};

@ -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();

@ -21,7 +21,7 @@
#include "YSFNode.h"
#include "Lookup.h"
using CsNodeMap = std::unordered_map<CCallsign, CYsfNode, CCallsignHash>;
using CsNodeMap = std::unordered_map<UCallsign, CYsfNode, CCallsignHash>;
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;

@ -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 <unistd.h>
////////////////////////////////////////////////////////////////////////////////////////
// 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

@ -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)

@ -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

Loading…
Cancel
Save

Powered by TurnKey Linux.