Version 0.7.2

pull/2/head
Tom Early 3 years ago
parent 09a80406c1
commit 9465842bf3

@ -12,6 +12,9 @@ Country = GB
Sponsor = My Home Club
# DashboardURL is where your dashboard for this reflector is avaiable on the WWW.
DashboardUrl = https://YourDashboard.net
# Bootstrap is the internet address of any existing DHT client.
# Usually, choose a frequented, or close, reflector if it's already a DHT
# client. If that's not possible, you can use xrf757.openquad.net

@ -50,6 +50,8 @@ public:
char GetCSModule(void) const { return m_Callsign.GetCSModule(); }
bool HasReflectorModule(void) const { return m_ReflectorModule != ' '; }
char GetReflectorModule(void) const { return m_ReflectorModule; }
std::time_t GetConnectTime(void) const { return m_ConnectTime; }
std::time_t GetLastHeardTime(void) const { return m_LastHeardTime; }
// set
void SetCSModule(char c) { m_Callsign.SetCSModule(c); }

@ -37,6 +37,7 @@
#define JBRANDMEISTER "Brandmeister"
#define JCALLSIGN "Callsign"
#define JCOUNTRY "Country"
#define JDASHBOARDURL "DashboardUrl"
#define JDCS "DCS"
#define JDEFAULTID "DefaultId"
#define JDEFAULTRXFREQ "DefaultRxFreq"
@ -253,6 +254,8 @@ bool CConfigure::ReadData(const std::string &path)
data[g_Keys.names.callsign] = value;
else if (0 == key.compare(JBOOTSTRAP))
data[g_Keys.names.bootstrap] = value;
else if (0 == key.compare(JDASHBOARDURL))
data[g_Keys.names.url] = value;
else if (0 == key.compare(JSYSOPEMAIL))
data[g_Keys.names.email] = value;
else if (0 == key.compare(JCOUNTRY))
@ -512,6 +515,7 @@ bool CConfigure::ReadData(const std::string &path)
#ifndef NO_DHT
isDefined(ErrorLevel::fatal, JNAMES, JBOOTSTRAP, g_Keys.names.bootstrap, rval);
#endif
isDefined(ErrorLevel::fatal, JNAMES, JDASHBOARDURL, g_Keys.names.url, rval);
isDefined(ErrorLevel::mild, JNAMES, JSYSOPEMAIL, g_Keys.names.email, rval);
isDefined(ErrorLevel::mild, JNAMES, JCOUNTRY, g_Keys.names.country, rval);
isDefined(ErrorLevel::mild, JNAMES, JSPONSOR, g_Keys.names.sponsor, rval);

@ -39,8 +39,8 @@ struct SJsonKeys {
struct MMDVM { const std::string port, defaultid; }
mmdvm { "MMDVMPort", "mmdvmdefaultid" };
struct NAMES { const std::string callsign, bootstrap, email, country, sponsor; }
names { "Callsign", "bootstrap", "SysopEmail", "Country", "Sponsor" };
struct NAMES { const std::string callsign, bootstrap, url, email, country, sponsor; }
names { "Callsign", "bootstrap", "DashboardUrl", "SysopEmail", "Country", "Sponsor" };
struct IP { const std::string ipv4bind, ipv4address, ipv6bind, ipv6address, transcoder; }
ip { "ipv4bind", "IPv4Address", "ipv6bind", "IPv6Address", "tcaddress" };

@ -42,6 +42,7 @@ public:
const CCallsign &GetCallsign(void) const { return m_Callsign; }
const CIp &GetIp(void) const { return m_Ip; }
char *GetReflectorModules(void) { return m_ReflectorModules; }
std::time_t GetConnectTime(void) const { return m_ConnectTime; }
// set

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

@ -46,6 +46,7 @@
class CReflector
{
public:
CReflector();
// destructor
~CReflector();

@ -34,6 +34,13 @@ public:
// destructor
~CUser() {}
// get
const std::string GetCallsign(void) const { return m_My.GetCS(); }
const std::string GetViaNode(void) const { return m_Rpt1.GetCS(); }
char GetOnModule(void) const { return m_Rpt2.GetCSModule(); }
const std::string GetViaPeer(void) const { return m_Xlx.GetCS(); }
std::time_t GetLastHeardTime(void) const { return m_LastHeardTime; }
// operation
void HeardNow(void) { m_LastHeardTime = time(nullptr); }

@ -43,6 +43,8 @@ public:
// pass-thru
std::list<CUser>::iterator begin() { return m_Users.begin(); }
std::list<CUser>::iterator end() { return m_Users.end(); }
std::list<CUser>::const_iterator cbegin() { return m_Users.cbegin(); }
std::list<CUser>::const_iterator cend() { return m_Users.cend(); }
// operation
void Hearing(const CCallsign &, const CCallsign &, const CCallsign &);

@ -54,8 +54,8 @@ struct SUrfdClients0
};
/* USERS */
using UserTuple = std::tuple<std::string, std::string, std::string, std::time_t>;
enum class EUrfdUserFields { Source, Destination, Reflector, LastHeardTime };
using UserTuple = std::tuple<std::string, std::string, char, std::string, std::time_t>;
enum class EUrfdUserFields { Callsign, ViaNode, OnModule, ViaPeer, LastHeardTime };
struct SUrfdUsers0
{
std::time_t timestamp;
@ -66,21 +66,21 @@ struct SUrfdUsers0
};
/* CONFIGURATION */
// 'SIZE' has to be last!!
enum class EUrfdPorts : unsigned { dcs, dextra, dmrplus, dplus, m17, mmdvm, nxdn, p25, urf, usrprx, usrptx, ysf, SIZE };
// 'SIZE' has to be last for these scoped enums
enum class EUrfdPorts : unsigned { dcs, dextra, dmrplus, dplus, m17, mmdvm, nxdn, p25, urf, ysf, SIZE };
enum class EUrfdAlMod : unsigned { nxdn, p25, ysf, SIZE };
enum class EUrfdTxRx : unsigned { rx, tx, SIZE };
enum class EUrfdRefId : unsigned { nxdn, p25, SIZE };
struct SUrfdConfig0
{
std::time_t timestamp;
std::string cs, ipv4, ipv6, mods, url, email, sponsor, country, version;
std::array<unsigned, toUType(EUrfdPorts::SIZE)> port;
std::string cs, ipv4, ipv6, mods, tcmods, url, email, sponsor, country, version;
std::array<uint16_t, toUType(EUrfdPorts::SIZE)> port;
std::array<char, toUType(EUrfdAlMod::SIZE)> almod;
std::array<unsigned long, toUType(EUrfdTxRx::SIZE)> ysffreq;
std::array<unsigned, toUType(EUrfdRefId::SIZE)> refid;
std::unordered_map<char, std::string> description;
bool g3enabled;
MSGPACK_DEFINE(timestamp, cs, ipv4, ipv6, mods, url, email, sponsor, country, version, almod, ysffreq, refid, g3enabled, port, description)
MSGPACK_DEFINE(timestamp, cs, ipv4, ipv6, mods, tcmods, url, email, sponsor, country, version, almod, ysffreq, refid, g3enabled, port, description)
};

Loading…
Cancel
Save

Powered by TurnKey Linux.