|
|
|
|
@ -20,8 +20,13 @@
|
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
|
|
#include "Global.h"
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// destructor
|
|
|
|
|
|
|
|
|
|
CReflector::CReflector()
|
|
|
|
|
{
|
|
|
|
|
#ifndef NO_DHT
|
|
|
|
|
peers_put_count = clients_put_count = users_put_count = 0;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CReflector::~CReflector()
|
|
|
|
|
{
|
|
|
|
|
@ -47,10 +52,18 @@ CReflector::~CReflector()
|
|
|
|
|
bool CReflector::Start(void)
|
|
|
|
|
{
|
|
|
|
|
// get config stuff
|
|
|
|
|
m_Callsign = CCallsign(g_Configure.GetString(g_Keys.names.callsign).c_str(), false);
|
|
|
|
|
const auto cs(g_Configure.GetString(g_Keys.names.callsign));
|
|
|
|
|
m_Callsign.SetCallsign(cs, false);
|
|
|
|
|
m_Modules.assign(g_Configure.GetString(g_Keys.modules.modules));
|
|
|
|
|
std::string tcmods(g_Configure.GetString(g_Keys.modules.tcmodules));
|
|
|
|
|
|
|
|
|
|
#ifndef NO_DHT
|
|
|
|
|
// start the dht instance
|
|
|
|
|
refhash = dht::InfoHash::get(cs);
|
|
|
|
|
node.run(17171, dht::crypto::generateIdentity(cs), true);
|
|
|
|
|
node.bootstrap(g_Configure.GetString(g_Keys.names.bootstrap), "17171");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// let's go!
|
|
|
|
|
keep_running = true;
|
|
|
|
|
|
|
|
|
|
@ -114,6 +127,10 @@ bool CReflector::Start(void)
|
|
|
|
|
std::cerr << "Cannot start the dashboard data report thread: " << e.what() << '\n';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef NO_DHT
|
|
|
|
|
PutDHTConfig();
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -145,6 +162,16 @@ void CReflector::Stop(void)
|
|
|
|
|
g_LDid.LookupClose();
|
|
|
|
|
g_LNid.LookupClose();
|
|
|
|
|
g_LYtr.LookupClose();
|
|
|
|
|
|
|
|
|
|
#ifndef NO_DHT
|
|
|
|
|
// kill the DHT
|
|
|
|
|
node.cancelPut(refhash, toUType(EUrfdValueID::Config));
|
|
|
|
|
node.cancelPut(refhash, toUType(EUrfdValueID::Peers));
|
|
|
|
|
node.cancelPut(refhash, toUType(EUrfdValueID::Clients));
|
|
|
|
|
node.cancelPut(refhash, toUType(EUrfdValueID::Users));
|
|
|
|
|
node.shutdown({}, true);
|
|
|
|
|
node.join();
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
@ -512,3 +539,186 @@ void CReflector::WriteXmlFile(std::ofstream &xmlFile)
|
|
|
|
|
ReleaseUsers();
|
|
|
|
|
xmlFile << "</" << cs << "heard users>" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifndef NO_DHT
|
|
|
|
|
// DHT put() and get()
|
|
|
|
|
void CReflector::PutDHTPeers()
|
|
|
|
|
{
|
|
|
|
|
const std::string cs(g_Configure.GetString(g_Keys.names.callsign));
|
|
|
|
|
// load it up
|
|
|
|
|
SUrfdPeers0 p;
|
|
|
|
|
time(&p.timestamp);
|
|
|
|
|
p.sequence = peers_put_count++;
|
|
|
|
|
auto peers = GetPeers();
|
|
|
|
|
for (auto pit=peers->cbegin(); pit!=peers->cend(); pit++)
|
|
|
|
|
{
|
|
|
|
|
p.list.emplace_back((*pit)->GetCallsign().GetCS(), (*pit)->GetReflectorModules(), (*pit)->GetConnectTime());
|
|
|
|
|
}
|
|
|
|
|
ReleasePeers();
|
|
|
|
|
|
|
|
|
|
auto nv = std::make_shared<dht::Value>(p);
|
|
|
|
|
nv->user_type.assign("urfd-peers-0");
|
|
|
|
|
nv->id = toUType(EUrfdValueID::Peers);
|
|
|
|
|
|
|
|
|
|
node.putSigned(
|
|
|
|
|
refhash,
|
|
|
|
|
nv,
|
|
|
|
|
[](bool success){ std::cout << "PutDHTPeers() " << (success ? "successful" : "unsuccessful") << std::endl; },
|
|
|
|
|
true // permanent!
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CReflector::PutDHTClients()
|
|
|
|
|
{
|
|
|
|
|
const std::string cs(g_Configure.GetString(g_Keys.names.callsign));
|
|
|
|
|
SUrfdClients0 c;
|
|
|
|
|
time(&c.timestamp);
|
|
|
|
|
c.sequence = clients_put_count++;
|
|
|
|
|
auto clients = GetClients();
|
|
|
|
|
for (auto cit=clients->cbegin(); cit!=clients->cend(); cit++)
|
|
|
|
|
{
|
|
|
|
|
c.list.emplace_back((*cit)->GetCallsign().GetCS(), std::string((*cit)->GetIp().GetAddress()), (*cit)->GetReflectorModule(), (*cit)->GetConnectTime(), (*cit)->GetLastHeardTime());
|
|
|
|
|
}
|
|
|
|
|
ReleaseClients();
|
|
|
|
|
|
|
|
|
|
auto nv = std::make_shared<dht::Value>(c);
|
|
|
|
|
nv->user_type.assign("urfd-clients-0");
|
|
|
|
|
nv->id = toUType(EUrfdValueID::Clients);
|
|
|
|
|
|
|
|
|
|
node.putSigned(
|
|
|
|
|
refhash,
|
|
|
|
|
nv,
|
|
|
|
|
[](bool success){ std::cout << "PutDHTClients() " << (success ? "successful" : "unsuccessful") << std::endl; },
|
|
|
|
|
true // permanent!
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CReflector::PutDHTUsers()
|
|
|
|
|
{
|
|
|
|
|
const std::string cs(g_Configure.GetString(g_Keys.names.callsign));
|
|
|
|
|
SUrfdUsers0 u;
|
|
|
|
|
time(&u.timestamp);
|
|
|
|
|
u.sequence = users_put_count++;
|
|
|
|
|
auto users = GetUsers();
|
|
|
|
|
for (auto uit=users->cbegin(); uit!=users->cend(); uit++)
|
|
|
|
|
{
|
|
|
|
|
u.list.emplace_back((*uit).GetCallsign(), std::string((*uit).GetViaNode()), (*uit).GetOnModule(), (*uit).GetViaPeer(), (*uit).GetLastHeardTime());
|
|
|
|
|
}
|
|
|
|
|
ReleaseUsers();
|
|
|
|
|
|
|
|
|
|
auto nv = std::make_shared<dht::Value>(u);
|
|
|
|
|
nv->user_type.assign("urfd-users-0");
|
|
|
|
|
nv->id = toUType(EUrfdValueID::Users);
|
|
|
|
|
|
|
|
|
|
node.putSigned(
|
|
|
|
|
refhash,
|
|
|
|
|
nv,
|
|
|
|
|
[](bool success){ std::cout << "PutDHTUsers() " << (success ? "successful" : "unsuccessful") << std::endl; },
|
|
|
|
|
true // permanent!
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CReflector::PutDHTConfig()
|
|
|
|
|
{
|
|
|
|
|
const std::string cs(g_Configure.GetString(g_Keys.names.callsign));
|
|
|
|
|
SUrfdConfig0 cfg;
|
|
|
|
|
time(&cfg.timestamp);
|
|
|
|
|
cfg.cs.assign(cs);
|
|
|
|
|
cfg.ipv4.assign(g_Configure.GetString(g_Keys.ip.ipv4address));
|
|
|
|
|
cfg.ipv6.assign(g_Configure.GetString(g_Keys.ip.ipv6address));
|
|
|
|
|
cfg.mods.assign(g_Configure.GetString(g_Keys.modules.modules));
|
|
|
|
|
cfg.tcmods.assign(g_Configure.GetString(g_Keys.modules.tcmodules));
|
|
|
|
|
cfg.url.assign(g_Configure.GetString(g_Keys.names.url));
|
|
|
|
|
cfg.email.assign(g_Configure.GetString(g_Keys.names.email));
|
|
|
|
|
cfg.country.assign(g_Configure.GetString(g_Keys.names.country));
|
|
|
|
|
cfg.sponsor.assign(g_Configure.GetString(g_Keys.names.sponsor));
|
|
|
|
|
std::ostringstream ss;
|
|
|
|
|
ss << g_Version;
|
|
|
|
|
cfg.version.assign(ss.str());
|
|
|
|
|
cfg.almod[toUType(EUrfdAlMod::nxdn)] = g_Configure.GetString(g_Keys.nxdn.autolinkmod).at(0);
|
|
|
|
|
cfg.almod[toUType(EUrfdAlMod::p25)] = g_Configure.GetString(g_Keys.p25.autolinkmod).at(0);
|
|
|
|
|
cfg.almod[toUType(EUrfdAlMod::ysf)] = g_Configure.GetString(g_Keys.ysf.autolinkmod).at(0);
|
|
|
|
|
cfg.ysffreq[toUType(EUrfdTxRx::rx)] = g_Configure.GetUnsigned(g_Keys.ysf.defaultrxfreq);
|
|
|
|
|
cfg.ysffreq[toUType(EUrfdTxRx::tx)] = g_Configure.GetUnsigned(g_Keys.ysf.defaulttxfreq);
|
|
|
|
|
cfg.refid[toUType(EUrfdRefId::nxdn)] = g_Configure.GetUnsigned(g_Keys.nxdn.reflectorid);
|
|
|
|
|
cfg.refid[toUType(EUrfdRefId::p25)] = g_Configure.GetUnsigned(g_Keys.p25.reflectorid);
|
|
|
|
|
cfg.g3enabled = g_Configure.GetBoolean(g_Keys.g3.enable);
|
|
|
|
|
cfg.port[toUType(EUrfdPorts::dcs)] = (uint16_t)g_Configure.GetUnsigned(g_Keys.dcs.port);
|
|
|
|
|
cfg.port[toUType(EUrfdPorts::dextra)] = (uint16_t)g_Configure.GetUnsigned(g_Keys.dextra.port);
|
|
|
|
|
cfg.port[toUType(EUrfdPorts::dmrplus)] = (uint16_t)g_Configure.GetUnsigned(g_Keys.dmrplus.port);
|
|
|
|
|
cfg.port[toUType(EUrfdPorts::dplus)] = (uint16_t)g_Configure.GetUnsigned(g_Keys.dplus.port);
|
|
|
|
|
cfg.port[toUType(EUrfdPorts::m17)] = (uint16_t)g_Configure.GetUnsigned(g_Keys.m17.port);
|
|
|
|
|
cfg.port[toUType(EUrfdPorts::mmdvm)] = (uint16_t)g_Configure.GetUnsigned(g_Keys.mmdvm.port);
|
|
|
|
|
cfg.port[toUType(EUrfdPorts::nxdn)] = (uint16_t)g_Configure.GetUnsigned(g_Keys.nxdn.port);
|
|
|
|
|
cfg.port[toUType(EUrfdPorts::p25)] = (uint16_t)g_Configure.GetUnsigned(g_Keys.p25.port);
|
|
|
|
|
cfg.port[toUType(EUrfdPorts::urf)] = (uint16_t)g_Configure.GetUnsigned(g_Keys.urf.port);
|
|
|
|
|
cfg.port[toUType(EUrfdPorts::ysf)] = (uint16_t)g_Configure.GetUnsigned(g_Keys.ysf.port);
|
|
|
|
|
for (const auto m : cfg.mods)
|
|
|
|
|
cfg.description[m] = g_Configure.GetString(g_Keys.modules.descriptor[m-'A']);
|
|
|
|
|
|
|
|
|
|
auto nv = std::make_shared<dht::Value>(cfg);
|
|
|
|
|
nv->user_type.assign("urfd-config-0");
|
|
|
|
|
nv->id = toUType(EUrfdValueID::Config);
|
|
|
|
|
|
|
|
|
|
node.putSigned(
|
|
|
|
|
refhash,
|
|
|
|
|
nv,
|
|
|
|
|
[](bool success){ std::cout << "PutDHTConfig() " << (success ? "successful" : "unsuccessful") << std::endl; },
|
|
|
|
|
true
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CReflector::GetDHTConfig(const std::string &cs)
|
|
|
|
|
{
|
|
|
|
|
static SUrfdConfig0 cfg;
|
|
|
|
|
cfg.timestamp = 0; // everytime this is called, zero the timestamp
|
|
|
|
|
auto item = g_IFile.FindMapItem(cs);
|
|
|
|
|
if (nullptr == item)
|
|
|
|
|
{
|
|
|
|
|
std::cerr << "Can't Get() for " << cs << " because it doesn't exist" << std::endl;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
std::cout << "Getting " << cs << " connection info..." << std::endl;
|
|
|
|
|
|
|
|
|
|
// we only want the configuration section of the reflector's document
|
|
|
|
|
dht::Where w;
|
|
|
|
|
w.id(toUType(EUrfdValueID::Config));
|
|
|
|
|
|
|
|
|
|
node.get(
|
|
|
|
|
dht::InfoHash::get(cs),
|
|
|
|
|
[](const std::shared_ptr<dht::Value> &v) {
|
|
|
|
|
if (0 == v->user_type.compare("mrefd-config-1"))
|
|
|
|
|
{
|
|
|
|
|
auto rdat = dht::Value::unpack<SUrfdConfig0>(*v);
|
|
|
|
|
if (rdat.timestamp > cfg.timestamp)
|
|
|
|
|
{
|
|
|
|
|
// the time stamp is the newest so far, so put it in the static cfg struct
|
|
|
|
|
cfg = dht::Value::unpack<SUrfdConfig0>(*v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::cerr << "Get() returned unknown user_type: '" << v->user_type << "'" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
return true; // check all the values returned
|
|
|
|
|
},
|
|
|
|
|
[](bool success) {
|
|
|
|
|
if (success)
|
|
|
|
|
{
|
|
|
|
|
if (cfg.timestamp)
|
|
|
|
|
{
|
|
|
|
|
// if the get() call was successful and there is a nonzero timestamp, then do the update
|
|
|
|
|
g_IFile.Update(cfg.cs, cfg.mods, cfg.ipv4, cfg.ipv6, cfg.port, cfg.emods);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Get() was unsuccessful" << std::endl;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{}, // empty filter
|
|
|
|
|
w // just the configuration section
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|