mirror of
https://github.com/nostar/urfd.git
synced 2026-11-08 04:19:39 +00:00
Merge pull request #2 from n7tae/main
Add the ability to put and get information from a existing distributed hash table
This commit is contained in:
56 files changed
+1455
-1010
No files matched your search
@@ -51,6 +51,29 @@ sudo apt install build-essential
|
||||
sudo apt install nlohmann-json3-dev
|
||||
```
|
||||
|
||||
### DVIN support (optional, but highly recommended)
|
||||
|
||||
**DVIN**, the Digital Voice Information Network, is implemented using a distributed hash table provided by OpenDHT.
|
||||
|
||||
OpenDHT is available [here](https://github./com/savoirfairelinux/opendht.git). Building and installing instructions are in the [OpenDHT Wiki](https://github.com/savoirfairelinux/opendht/wiki/Build-the-library). Pascal support and proxy-server support (RESTinio) is not required for urfd and so can be considered optional. With this in mind, this should work on Debian/Ubuntu-based systems:
|
||||
|
||||
```bash
|
||||
# Install OpenDHT dependencies
|
||||
sudo apt install libncurses5-dev libreadline-dev nettle-dev libgnutls28-dev libargon2-0-dev libmsgpack-dev libssl-dev libfmt-dev libjsoncpp-dev libhttp-parser-dev libasio-dev cmake pkg-config libcppunit-dev
|
||||
|
||||
# clone the repo
|
||||
git clone https://github.com/savoirfairelinux/opendht.git
|
||||
|
||||
# build and install
|
||||
cd opendht
|
||||
mkdir build && cd build
|
||||
cmake -DOPENDHT_PYTHON=OFF -DCMAKE_INSTALL_PREFIX=/usr ..
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
Please note that there is no easy way to uninstall OpenDHT once it's been installed.
|
||||
|
||||
### Download and build the repository and
|
||||
|
||||
```bash
|
||||
|
||||
@@ -12,6 +12,14 @@ 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
|
||||
Bootstrap = xrf757.openquad.net
|
||||
|
||||
[IP Addresses]
|
||||
# Binding addresses are usually the 'any' address
|
||||
IPv4Binding = 0.0.0.0
|
||||
|
||||
+14
-8
@@ -1,14 +1,20 @@
|
||||
##############################################################################
|
||||
# URFD interlink file
|
||||
#
|
||||
# one line per entry
|
||||
# each entry specifies a remote XLX or XRF to peer with
|
||||
# format:
|
||||
# <URF callsign> <ip> <list of modules shared>
|
||||
# example:
|
||||
# URF270 158.64.26.132 ACD
|
||||
# One line per entry.
|
||||
# Each entry specifies a remote URF to peer with.
|
||||
# If no Port is specified, 10017 will be used.
|
||||
# If DHT is enabled and the target is also DHT-enabled, then you only
|
||||
# need to specify the URF-Callsign and the Shared-Modules.
|
||||
# Format:
|
||||
# <URF-Callsign> <IP-Address> <Shared-Mdoules> <Port>
|
||||
# Examples:
|
||||
# URF270 158.64.26.132 EF
|
||||
# URF280 ABC
|
||||
#
|
||||
# note: the remote URFD must list this in its interlink file
|
||||
# for the link to be established
|
||||
# Brandmeister links use three params, no port is specified. Example:
|
||||
# BM3104 162.248.88.117 E
|
||||
#
|
||||
# note: Remote URFD must list this in its interlink file
|
||||
# for the link to be established.
|
||||
#############################################################################
|
||||
@@ -4,3 +4,6 @@ BINDIR = /usr/local/bin
|
||||
# besides making an executable that gdb can use,
|
||||
# this will also provide some additional log messsage
|
||||
debug = false
|
||||
|
||||
# To disable DHT support, set DHT to false.
|
||||
DHT = true
|
||||
+10
-12
@@ -288,16 +288,16 @@ void CBMProtocol::HandlePeerLinks(void)
|
||||
CBuffer buffer;
|
||||
|
||||
// get the list of peers
|
||||
CPeerCallsignList *list = g_GateKeeper.GetPeerList();
|
||||
auto ilmap = g_GateKeeper.GetInterlinkMap();
|
||||
CPeers *peers = g_Reflector.GetPeers();
|
||||
|
||||
// check if all our connected peers are still listed by gatekeeper
|
||||
// if not, disconnect
|
||||
auto pit = peers->begin();
|
||||
std::shared_ptr<CPeer>peer = nullptr;
|
||||
while ( (peer = peers->FindNextPeer(EProtocol::bm, pit)) != nullptr )
|
||||
while ( nullptr != (peer = peers->FindNextPeer(EProtocol::bm, pit)) )
|
||||
{
|
||||
if ( list->FindListItem(peer->GetCallsign()) == nullptr )
|
||||
if ( nullptr == ilmap->FindMapItem(peer->GetCallsign().GetBase()) )
|
||||
{
|
||||
// send disconnect packet
|
||||
EncodeDisconnectPacket(&buffer);
|
||||
@@ -310,23 +310,21 @@ void CBMProtocol::HandlePeerLinks(void)
|
||||
|
||||
// check if all ours peers listed by gatekeeper are connected
|
||||
// if not, connect or reconnect
|
||||
for ( auto it=list->begin(); it!=list->end(); it++ )
|
||||
for ( auto it=ilmap->begin(); it!=ilmap->end(); it++ )
|
||||
{
|
||||
CCallsign cs = it->GetCallsign();
|
||||
if (cs.HasSameCallsignWithWildcard(CCallsign("BM*")) && (nullptr==peers->FindPeer(cs, EProtocol::bm)))
|
||||
const auto cs = it->first;
|
||||
if (0 == cs.substr(0, 2).compare("BM") && (nullptr==peers->FindPeer(CCallsign(cs), EProtocol::bm)))
|
||||
{
|
||||
// resolve again peer's IP in case it's a dynamic IP
|
||||
it->ResolveIp();
|
||||
// send connect packet to re-initiate peer link
|
||||
EncodeConnectPacket(&buffer, it->GetModules());
|
||||
Send(buffer, it->GetIp(), m_Port);
|
||||
std::cout << "Sending connect packet to BM peer " << cs << " @ " << it->GetIp() << " for modules " << it->GetModules() << std::endl;
|
||||
EncodeConnectPacket(&buffer, it->second.GetModules().c_str());
|
||||
Send(buffer, it->second.GetIp(), m_Port);
|
||||
std::cout << "Sending connect packet to BM peer " << cs << " @ " << it->second.GetIp() << " for modules " << it->second.GetModules() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// done
|
||||
g_Reflector.ReleasePeers();
|
||||
g_GateKeeper.ReleasePeerList();
|
||||
g_GateKeeper.ReleaseInterlinkMap();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
//
|
||||
// ccallsignlist.cpp
|
||||
// m17ref
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 30/12/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of m17ref.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// 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
|
||||
// with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "BlackWhiteSet.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// file io
|
||||
|
||||
bool CBlackWhiteSet::LoadFromFile(const std::string &filename)
|
||||
{
|
||||
bool ok = false;
|
||||
char sz[256];
|
||||
|
||||
// and load
|
||||
std::ifstream file(filename);
|
||||
if ( file.is_open() )
|
||||
{
|
||||
Lock();
|
||||
|
||||
// empty list
|
||||
m_Callsigns.clear();
|
||||
// fill with file content
|
||||
while ( file.getline(sz, sizeof(sz)).good() )
|
||||
{
|
||||
// remove leading & trailing spaces
|
||||
char *szt = TrimWhiteSpaces(sz);
|
||||
|
||||
// crack it
|
||||
if ( (strlen(szt) > 0) && (szt[0] != '#') )
|
||||
{
|
||||
// 1st token is callsign
|
||||
if ( (szt = strtok(szt, " ,\t")) != nullptr )
|
||||
{
|
||||
std::string cs(ToUpper(szt));
|
||||
if (m_Callsigns.end() == m_Callsigns.find(cs))
|
||||
{
|
||||
m_Callsigns.insert(cs);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Duplicate ," << cs << " in " << filename << " will be ignored." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// close file
|
||||
file.close();
|
||||
|
||||
// keep file path
|
||||
m_Filename = filename;
|
||||
|
||||
// update time
|
||||
GetLastModTime(&m_LastModTime);
|
||||
|
||||
// and done
|
||||
Unlock();
|
||||
ok = true;
|
||||
std::cout << "Gatekeeper loaded " << m_Callsigns.size() << " lines from " << filename << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Gatekeeper cannot find " << filename << std::endl;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CBlackWhiteSet::ReloadFromFile(void)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if ( ! m_Filename.empty() )
|
||||
{
|
||||
ok = LoadFromFile(m_Filename);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CBlackWhiteSet::NeedReload(void)
|
||||
{
|
||||
bool needReload = false;
|
||||
|
||||
time_t time;
|
||||
if ( GetLastModTime(&time) )
|
||||
{
|
||||
needReload = time != m_LastModTime;
|
||||
}
|
||||
return needReload;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// compare
|
||||
|
||||
bool CBlackWhiteSet::IsMatched(const std::string &cs) const
|
||||
{
|
||||
for ( const auto &item : m_Callsigns )
|
||||
{
|
||||
auto pos = item.find('*');
|
||||
switch (pos)
|
||||
{
|
||||
case 0:
|
||||
return true;
|
||||
case std::string::npos:
|
||||
if (0 == item.compare(cs))
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
if (0 == item.compare(0, pos, cs, 0, pos))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// helpers
|
||||
|
||||
char *CBlackWhiteSet::TrimWhiteSpaces(char *str)
|
||||
{
|
||||
char *end;
|
||||
|
||||
// Trim leading space & tabs
|
||||
while((*str == ' ') || (*str == '\t')) str++;
|
||||
|
||||
// All spaces?
|
||||
if(*str == 0)
|
||||
return str;
|
||||
|
||||
// Trim trailing space, tab or lf
|
||||
end = str + ::strlen(str) - 1;
|
||||
while((end > str) && ((*end == ' ') || (*end == '\t') || (*end == '\r'))) end--;
|
||||
|
||||
// Write new null terminator
|
||||
*(end+1) = 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
bool CBlackWhiteSet::GetLastModTime(time_t *time)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if ( !m_Filename.empty() )
|
||||
{
|
||||
struct stat fileStat;
|
||||
if( ::stat(m_Filename.c_str(), &fileStat) != -1 )
|
||||
{
|
||||
*time = fileStat.st_mtime;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
char *CBlackWhiteSet::ToUpper(char *str)
|
||||
{
|
||||
constexpr auto diff = 'a' - 'A';
|
||||
for (char *p=str; *p; p++)
|
||||
{
|
||||
if (*p >= 'a' && *p <= 'z')
|
||||
*p -= diff;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of m17ref.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// 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
|
||||
// with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CBlackWhiteSet
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CBlackWhiteSet() : m_LastModTime(0) {}
|
||||
|
||||
// locks
|
||||
void Lock(void) const { m_Mutex.lock(); }
|
||||
void Unlock(void) const { m_Mutex.unlock(); }
|
||||
|
||||
// file io
|
||||
bool LoadFromFile(const std::string &filename);
|
||||
bool ReloadFromFile(void);
|
||||
bool NeedReload(void);
|
||||
|
||||
// pass-through
|
||||
bool empty() const { return m_Callsigns.empty(); }
|
||||
|
||||
// compare
|
||||
bool IsMatched(const std::string &) const;
|
||||
|
||||
protected:
|
||||
bool GetLastModTime(time_t *);
|
||||
char *TrimWhiteSpaces(char *);
|
||||
char *ToUpper(char *str);
|
||||
|
||||
// data
|
||||
mutable std::mutex m_Mutex;
|
||||
std::string m_Filename;
|
||||
time_t m_LastModTime;
|
||||
std::set<std::string> m_Callsigns;
|
||||
};
|
||||
@@ -1,49 +0,0 @@
|
||||
// Copyright © 2015 Jean-Luc. 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
|
||||
#include "Notification.h"
|
||||
|
||||
class CNotificationQueue
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CNotificationQueue() {}
|
||||
|
||||
// destructor
|
||||
~CNotificationQueue() {}
|
||||
|
||||
// lock
|
||||
void Lock() { m_Mutex.lock(); }
|
||||
void Unlock() { m_Mutex.unlock(); }
|
||||
|
||||
// pass thru
|
||||
CNotification front() { return queue.front(); }
|
||||
void pop() { queue.pop(); }
|
||||
void push(CNotification note) { queue.push(note); }
|
||||
bool empty() const { return queue.empty(); }
|
||||
|
||||
protected:
|
||||
// data
|
||||
std::mutex m_Mutex;
|
||||
std::queue<CNotification> queue;
|
||||
};
|
||||
+10
-10
@@ -349,6 +349,16 @@ UCallsign CCallsign::GetKey() const
|
||||
return rval;
|
||||
}
|
||||
|
||||
std::string CCallsign::GetBase() const
|
||||
{
|
||||
auto u = GetKey();
|
||||
std::string rval(u.c, CALLSIGN_LEN);
|
||||
auto pos = rval.find(' ');
|
||||
if (std::string::npos != pos)
|
||||
rval.resize(pos);
|
||||
return rval;
|
||||
}
|
||||
|
||||
void CCallsign::GetCallsign(uint8_t *buffer) const
|
||||
{
|
||||
memcpy(buffer, m_Callsign.c, CALLSIGN_LEN);
|
||||
@@ -404,16 +414,6 @@ bool CCallsign::HasSameCallsignWithWildcard(const CCallsign &cs) const
|
||||
return same;
|
||||
}
|
||||
|
||||
bool CCallsign::HasLowerCallsign(const CCallsign &cs) const
|
||||
{
|
||||
return (memcmp(m_Callsign.c, cs.m_Callsign.c, CALLSIGN_LEN) < 0);
|
||||
}
|
||||
|
||||
bool CCallsign::HasSameModule(const CCallsign &Callsign) const
|
||||
{
|
||||
return (m_Module == Callsign.m_Module);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operators
|
||||
|
||||
+19
-3
@@ -39,6 +39,23 @@ union USuffix
|
||||
uint32_t u;
|
||||
};
|
||||
|
||||
// functions for unordered containers
|
||||
struct CCallsignHash
|
||||
{
|
||||
std::size_t operator() (const UCallsign &ucs) const
|
||||
{
|
||||
std::hash<uint64_t> hash;
|
||||
return hash(ucs.l);
|
||||
}
|
||||
};
|
||||
|
||||
struct CCallsignEqual
|
||||
{
|
||||
bool operator() (const UCallsign &ucs1, const UCallsign &ucs2) const
|
||||
{
|
||||
return ucs1.l == ucs2.l;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
@@ -46,7 +63,7 @@ union USuffix
|
||||
class CCallsign
|
||||
{
|
||||
public:
|
||||
// contructors
|
||||
// constructors
|
||||
CCallsign();
|
||||
CCallsign(const UCallsign &cs); // no id lookup
|
||||
CCallsign(const CCallsign &cs);
|
||||
@@ -73,6 +90,7 @@ public:
|
||||
|
||||
// get
|
||||
UCallsign GetKey() const;
|
||||
std::string GetBase() const;
|
||||
void GetCallsign(uint8_t *) const;
|
||||
void GetCallsignString(char *) const;
|
||||
const std::string GetCS() const;
|
||||
@@ -84,8 +102,6 @@ public:
|
||||
// compare
|
||||
bool HasSameCallsign(const CCallsign &) const;
|
||||
bool HasSameCallsignWithWildcard(const CCallsign &) const;
|
||||
bool HasLowerCallsign(const CCallsign &) const;
|
||||
bool HasSameModule(const CCallsign &) const;
|
||||
|
||||
// operators
|
||||
CCallsign &operator = (const CCallsign &cs);
|
||||
|
||||
@@ -1,223 +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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <fstream>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "CallsignList.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CCallsignList::CCallsignList()
|
||||
{
|
||||
memset(&m_LastModTime, 0, sizeof(time_t));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// file io
|
||||
|
||||
bool CCallsignList::LoadFromFile(const std::string &filename)
|
||||
{
|
||||
bool ok = false;
|
||||
char sz[256];
|
||||
char szStar[2] = "*";
|
||||
|
||||
// and load
|
||||
std::ifstream file (filename);
|
||||
if ( file.is_open() )
|
||||
{
|
||||
Lock();
|
||||
|
||||
// empty list
|
||||
m_Callsigns.clear();
|
||||
// fill with file content
|
||||
while ( file.getline(sz, sizeof(sz)).good() )
|
||||
{
|
||||
// remove leading & trailing spaces
|
||||
char *szt = TrimWhiteSpaces(sz);
|
||||
|
||||
// crack it
|
||||
if ( (::strlen(szt) > 0) && (szt[0] != '#') )
|
||||
{
|
||||
// 1st token is callsign
|
||||
if ( (szt = ::strtok(szt, " ,\t")) != nullptr )
|
||||
{
|
||||
CCallsign callsign(szt);
|
||||
// 2nd token is modules list
|
||||
szt = ::strtok(nullptr, " ,\t");
|
||||
// if token absent, use wildcard
|
||||
if ( szt == nullptr )
|
||||
{
|
||||
szt = szStar;
|
||||
}
|
||||
// and add to list
|
||||
m_Callsigns.push_back(CCallsignListItem(callsign, CIp(), szt));
|
||||
}
|
||||
}
|
||||
}
|
||||
// close file
|
||||
file.close();
|
||||
|
||||
// keep file path
|
||||
m_Filename.assign(filename);
|
||||
|
||||
// update time
|
||||
GetLastModTime(&m_LastModTime);
|
||||
|
||||
// and done
|
||||
Unlock();
|
||||
ok = true;
|
||||
std::cout << "Gatekeeper loaded " << m_Callsigns.size() << " lines from " << filename << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Gatekeeper cannot find " << filename << std::endl;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CCallsignList::ReloadFromFile(void)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if (! m_Filename.empty())
|
||||
{
|
||||
ok = LoadFromFile(m_Filename);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CCallsignList::NeedReload(void)
|
||||
{
|
||||
bool needReload = false;
|
||||
|
||||
time_t time;
|
||||
if ( GetLastModTime(&time) )
|
||||
{
|
||||
needReload = time != m_LastModTime;
|
||||
}
|
||||
return needReload;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// compare
|
||||
|
||||
bool CCallsignList::IsCallsignListedWithWildcard(const CCallsign &callsign) const
|
||||
{
|
||||
for ( const auto &item : m_Callsigns )
|
||||
{
|
||||
if (item.HasSameCallsignWithWildcard(callsign))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCallsignList::IsCallsignListedWithWildcard(const CCallsign &callsign, char module) const
|
||||
{
|
||||
for ( const auto &item : m_Callsigns )
|
||||
{
|
||||
if (item.HasSameCallsignWithWildcard(callsign) && ((module == ' ') || item.HasModuleListed(module)) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCallsignList::IsCallsignListed(const CCallsign &callsign, char module) const
|
||||
{
|
||||
for ( const auto &item : m_Callsigns )
|
||||
{
|
||||
if (item.HasSameCallsign(callsign) && item.HasModuleListed(module))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCallsignList::IsCallsignListed(const CCallsign &callsign, char *modules) const
|
||||
{
|
||||
for ( const auto &item : m_Callsigns )
|
||||
{
|
||||
if (item.HasSameCallsign(callsign) && item.CheckListedModules(modules))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// find
|
||||
|
||||
CCallsignListItem *CCallsignList::FindListItem(const CCallsign &Callsign)
|
||||
{
|
||||
for ( auto &item : m_Callsigns )
|
||||
{
|
||||
if ( item.GetCallsign().HasSameCallsign(Callsign) )
|
||||
{
|
||||
return &item;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// helpers
|
||||
|
||||
char *CCallsignList::TrimWhiteSpaces(char *str)
|
||||
{
|
||||
char *end;
|
||||
|
||||
// Trim leading space & tabs
|
||||
while((*str == ' ') || (*str == '\t')) str++;
|
||||
|
||||
// All spaces?
|
||||
if(*str == 0)
|
||||
return str;
|
||||
|
||||
// Trim trailing space, tab or lf
|
||||
end = str + ::strlen(str) - 1;
|
||||
while((end > str) && ((*end == ' ') || (*end == '\t') || (*end == '\r'))) end--;
|
||||
|
||||
// Write new null terminator
|
||||
*(end+1) = 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
bool CCallsignList::GetLastModTime(time_t *time)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if (! m_Filename.empty())
|
||||
{
|
||||
struct stat fileStat;
|
||||
if( ::stat(m_Filename.c_str(), &fileStat) != -1 )
|
||||
{
|
||||
*time = fileStat.st_mtime;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@@ -1,67 +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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
|
||||
#include "CallsignListItem.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CCallsignList
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CCallsignList();
|
||||
|
||||
// locks
|
||||
void Lock(void) const { m_Mutex.lock(); }
|
||||
void Unlock(void) const { m_Mutex.unlock(); }
|
||||
|
||||
// file io
|
||||
virtual bool LoadFromFile(const std::string &str);
|
||||
bool ReloadFromFile(void);
|
||||
bool NeedReload(void);
|
||||
|
||||
// compare
|
||||
bool IsCallsignListedWithWildcard(const CCallsign &) const;
|
||||
bool IsCallsignListedWithWildcard(const CCallsign &, char) const;
|
||||
bool IsCallsignListed(const CCallsign &, char) const;
|
||||
bool IsCallsignListed(const CCallsign &, char*) const;
|
||||
|
||||
// pass-thru
|
||||
bool empty() const { return m_Callsigns.empty(); }
|
||||
std::list<CCallsignListItem>::iterator begin() { return m_Callsigns.begin(); }
|
||||
std::list<CCallsignListItem>::iterator end() { return m_Callsigns.end(); }
|
||||
|
||||
// find
|
||||
CCallsignListItem *FindListItem(const CCallsign &);
|
||||
|
||||
protected:
|
||||
bool GetLastModTime(time_t *);
|
||||
char *TrimWhiteSpaces(char *);
|
||||
|
||||
// data
|
||||
mutable std::mutex m_Mutex;
|
||||
std::string m_Filename;
|
||||
time_t m_LastModTime;
|
||||
std::list<CCallsignListItem> m_Callsigns;
|
||||
};
|
||||
@@ -1,136 +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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Global.h"
|
||||
|
||||
#include "CallsignListItem.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CCallsignListItem::CCallsignListItem()
|
||||
{
|
||||
memset(m_Modules, 0, sizeof(m_Modules));
|
||||
memset(m_szUrl, 0, sizeof(m_szUrl));
|
||||
}
|
||||
|
||||
CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const CIp &ip, const char *modules)
|
||||
{
|
||||
const std::string mods(g_Configure.GetString(g_Keys.modules.modules));
|
||||
m_Callsign = callsign;
|
||||
memset(m_szUrl, 0, sizeof(m_szUrl));
|
||||
m_Ip = ip;
|
||||
if ( modules != nullptr )
|
||||
{
|
||||
memset(m_Modules, 0, sizeof(m_Modules));
|
||||
if ( modules[0] == '*' )
|
||||
{
|
||||
memcpy(m_Modules, mods.c_str(), mods.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
int n = MIN(::strlen(modules), sizeof(m_Modules)-1);
|
||||
for (int i=0, j=0; i<n; i++)
|
||||
{
|
||||
if (std::string::npos != mods.find(modules[i]))
|
||||
{
|
||||
m_Modules[j++] = modules[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const char *url, const char *modules)
|
||||
{
|
||||
const std::string mods(g_Configure.GetString(g_Keys.modules.modules));
|
||||
m_Callsign = callsign;
|
||||
::strncpy(m_szUrl, url, URL_MAXLEN);
|
||||
m_Ip = CIp(m_szUrl);
|
||||
if ( modules != nullptr )
|
||||
{
|
||||
memset(m_Modules, 0, sizeof(m_Modules));
|
||||
if ( modules[0] == '*' )
|
||||
{
|
||||
memcpy(m_Modules, mods.c_str(), mods.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
int n = MIN(::strlen(modules), sizeof(m_Modules)-1);
|
||||
for (int i=0, j=0; i<n; i++)
|
||||
{
|
||||
if (std::string::npos != mods.find(modules[i]))
|
||||
{
|
||||
m_Modules[j++] = modules[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCallsignListItem::CCallsignListItem(const CCallsignListItem &item)
|
||||
{
|
||||
m_Callsign = item.m_Callsign;
|
||||
memcpy(m_szUrl, item.m_szUrl, sizeof(m_szUrl));
|
||||
m_Ip = item.m_Ip;
|
||||
memcpy(m_Modules, item.m_Modules, sizeof(m_Modules));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// compare
|
||||
|
||||
bool CCallsignListItem::HasSameCallsign(const CCallsign &callsign) const
|
||||
{
|
||||
return m_Callsign.HasSameCallsign(callsign);
|
||||
}
|
||||
|
||||
bool CCallsignListItem::HasSameCallsignWithWildcard(const CCallsign &callsign) const
|
||||
{
|
||||
return m_Callsign.HasSameCallsignWithWildcard(callsign);
|
||||
}
|
||||
|
||||
bool CCallsignListItem::HasModuleListed(char module) const
|
||||
{
|
||||
return (::strchr(m_Modules, (int)module) != nullptr);
|
||||
}
|
||||
|
||||
bool CCallsignListItem::CheckListedModules(char *Modules) const
|
||||
{
|
||||
bool listed = false;
|
||||
|
||||
if ( Modules != nullptr )
|
||||
{
|
||||
// build a list of common modules
|
||||
char list[27];
|
||||
list[0] = 0;
|
||||
//
|
||||
for ( unsigned i = 0; i < ::strlen(Modules); i++ )
|
||||
{
|
||||
if ( HasModuleListed(Modules[i]) )
|
||||
{
|
||||
::strncat(list, &(Modules[i]), 1);
|
||||
listed = true;
|
||||
}
|
||||
}
|
||||
::strcpy(Modules, list);
|
||||
}
|
||||
return listed;
|
||||
}
|
||||
@@ -1,65 +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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "Callsign.h"
|
||||
#include "IP.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
#define URL_MAXLEN 256
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CCallsignListItem
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CCallsignListItem();
|
||||
CCallsignListItem(const CCallsign &, const CIp &, const char *);
|
||||
CCallsignListItem(const CCallsign &, const char *, const char *);
|
||||
CCallsignListItem(const CCallsignListItem &);
|
||||
|
||||
// destructor
|
||||
virtual ~CCallsignListItem() {}
|
||||
|
||||
// compare
|
||||
bool HasSameCallsign(const CCallsign &) const;
|
||||
bool HasSameCallsignWithWildcard(const CCallsign &) const;
|
||||
bool HasModuleListed(char) const;
|
||||
bool CheckListedModules(char*) const;
|
||||
|
||||
// get
|
||||
const CCallsign &GetCallsign(void) const { return m_Callsign; }
|
||||
const CIp &GetIp(void) const { return m_Ip; }
|
||||
const char *GetModules(void) { return m_Modules; }
|
||||
|
||||
// update
|
||||
void ResolveIp(void) { m_Ip = CIp(m_szUrl); }
|
||||
|
||||
protected:
|
||||
// data
|
||||
CCallsign m_Callsign;
|
||||
char m_szUrl[URL_MAXLEN+1];
|
||||
CIp m_Ip;
|
||||
char m_Modules[27];
|
||||
};
|
||||
@@ -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); }
|
||||
|
||||
@@ -73,7 +73,7 @@ void CClients::RemoveClient(std::shared_ptr<CClient> client)
|
||||
bool found = false;
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
// compare objetc pointers
|
||||
// compare object pointers
|
||||
if ( *it == client )
|
||||
{
|
||||
// found it !
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@ public:
|
||||
void RemoveClient(std::shared_ptr<CClient>);
|
||||
bool IsClient(std::shared_ptr<CClient>) const;
|
||||
|
||||
// pass-thru
|
||||
// pass-through
|
||||
std::list<std::shared_ptr<CClient>>::iterator begin() { return m_Clients.begin(); }
|
||||
std::list<std::shared_ptr<CClient>>::iterator end() { return m_Clients.end(); }
|
||||
std::list<std::shared_ptr<CClient>>::const_iterator cbegin() const { return m_Clients.cbegin(); }
|
||||
|
||||
@@ -50,7 +50,7 @@ public:
|
||||
void Thread(void);
|
||||
void Task(void);
|
||||
|
||||
// pass-thru
|
||||
// pass-through
|
||||
void Push(std::unique_ptr<CPacket> p) { m_Queue.Push(std::move(p)); }
|
||||
|
||||
protected:
|
||||
|
||||
+13
-3
@@ -33,9 +33,11 @@
|
||||
// ini file keywords
|
||||
#define JAUTOLINKMODULE "AutoLinkModule"
|
||||
#define JBLACKLISTPATH "BlacklistPath"
|
||||
#define JBOOTSTRAP "Bootstrap"
|
||||
#define JBRANDMEISTER "Brandmeister"
|
||||
#define JCALLSIGN "Callsign"
|
||||
#define JCOUNTRY "Country"
|
||||
#define JDASHBOARDURL "DashboardUrl"
|
||||
#define JDCS "DCS"
|
||||
#define JDEFAULTID "DefaultId"
|
||||
#define JDEFAULTRXFREQ "DefaultRxFreq"
|
||||
@@ -250,6 +252,10 @@ bool CConfigure::ReadData(const std::string &path)
|
||||
case ESection::names:
|
||||
if (0 == key.compare(JCALLSIGN))
|
||||
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))
|
||||
@@ -487,7 +493,7 @@ bool CConfigure::ReadData(const std::string &path)
|
||||
badParam(key);
|
||||
break;
|
||||
default:
|
||||
std::cout << "WARNING: parameter '" << line << "' defined befor any [section]" << std::endl;
|
||||
std::cout << "WARNING: parameter '" << line << "' defined before any [section]" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -506,6 +512,10 @@ 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);
|
||||
@@ -526,7 +536,7 @@ bool CConfigure::ReadData(const std::string &path)
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: specifed IPv4 external address, " << v4 << ", is malformed" << std::endl;
|
||||
std::cerr << "ERROR: specified IPv4 external address, " << v4 << ", is malformed" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
@@ -564,7 +574,7 @@ bool CConfigure::ReadData(const std::string &path)
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "ERROR: the specifed IPv6 address [" << v6 << "] is malformed" << std::endl;
|
||||
std::cerr << "ERROR: the specified IPv6 address [" << v6 << "] is malformed" << std::endl;
|
||||
rval = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -449,7 +449,7 @@ bool CDmrplusProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer
|
||||
uint8_t dmrsync[7];
|
||||
// get the 33 bytes ambe
|
||||
memcpy(dmrframe, &(Buffer.data()[26]), 33);
|
||||
// handle endianess
|
||||
// handle endianness
|
||||
SwapEndianess(dmrframe, sizeof(dmrframe));
|
||||
// extract the 3 ambe frames
|
||||
memcpy(dmr3ambe, dmrframe, 14);
|
||||
|
||||
@@ -390,7 +390,7 @@ void CG3Protocol::Task(void)
|
||||
{
|
||||
BaseIp = &ClIp;
|
||||
client->Alive();
|
||||
// supress host checks - no ping needed to trigger potential ICMPs
|
||||
// suppress host checks - no ping needed to trigger potential ICMPs
|
||||
// the regular data flow will do it
|
||||
m_LastKeepaliveTime.start();
|
||||
break;
|
||||
@@ -444,7 +444,7 @@ void CG3Protocol::HandleQueue(void)
|
||||
{
|
||||
while (! m_Queue.IsEmpty())
|
||||
{
|
||||
// supress host checks
|
||||
// suppress host checks
|
||||
m_LastKeepaliveTime.start();
|
||||
|
||||
// get the packet
|
||||
|
||||
+38
-39
@@ -44,9 +44,9 @@ bool CGateKeeper::Init(void)
|
||||
{
|
||||
|
||||
// load lists from files
|
||||
m_NodeWhiteList.LoadFromFile(g_Configure.GetString(g_Keys.files.white));
|
||||
m_NodeBlackList.LoadFromFile(g_Configure.GetString(g_Keys.files.black));
|
||||
m_PeerList.LoadFromFile(g_Configure.GetString(g_Keys.files.interlink));
|
||||
m_WhiteSet.LoadFromFile(g_Configure.GetString(g_Keys.files.white));
|
||||
m_BlackSet.LoadFromFile(g_Configure.GetString(g_Keys.files.black));
|
||||
m_InterlinkMap.LoadFromFile(g_Configure.GetString(g_Keys.files.interlink));
|
||||
|
||||
// reset run flag
|
||||
keep_running = true;
|
||||
@@ -72,7 +72,8 @@ void CGateKeeper::Close(void)
|
||||
|
||||
bool CGateKeeper::MayLink(const CCallsign &callsign, const CIp &ip, EProtocol protocol, char *modules) const
|
||||
{
|
||||
bool ok = true;
|
||||
bool ok;
|
||||
const std::string base(callsign.GetBase());
|
||||
|
||||
switch (protocol)
|
||||
{
|
||||
@@ -88,26 +89,24 @@ bool CGateKeeper::MayLink(const CCallsign &callsign, const CIp &ip, EProtocol pr
|
||||
case EProtocol::usrp:
|
||||
case EProtocol::nxdn:
|
||||
case EProtocol::g3:
|
||||
// first check is IP & callsigned listed OK
|
||||
ok &= IsNodeListedOk(callsign, ip);
|
||||
// todo: then apply any protocol specific authorisation for the operation
|
||||
// is callsign listed OK
|
||||
ok = IsNodeListedOk(base);
|
||||
break;
|
||||
|
||||
// URF and BM interlinks
|
||||
case EProtocol::bm:
|
||||
case EProtocol::urf:
|
||||
ok &= IsPeerListedOk(callsign, ip, modules);
|
||||
ok = IsPeerListedOk(base, ip, modules);
|
||||
break;
|
||||
|
||||
// unsupported
|
||||
case EProtocol::none:
|
||||
default:
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// report
|
||||
if ( !ok )
|
||||
if ( ! ok )
|
||||
{
|
||||
std::cout << "Gatekeeper blocking linking of " << callsign << " @ " << ip << " using protocol " << ProtocolName(protocol) << std::endl;
|
||||
}
|
||||
@@ -118,7 +117,9 @@ bool CGateKeeper::MayLink(const CCallsign &callsign, const CIp &ip, EProtocol pr
|
||||
|
||||
bool CGateKeeper::MayTransmit(const CCallsign &callsign, const CIp &ip, const EProtocol protocol, char module) const
|
||||
{
|
||||
bool ok = true;
|
||||
bool ok;
|
||||
|
||||
const std::string base(callsign.GetBase());
|
||||
|
||||
switch (protocol)
|
||||
{
|
||||
@@ -136,14 +137,14 @@ bool CGateKeeper::MayTransmit(const CCallsign &callsign, const CIp &ip, const EP
|
||||
case EProtocol::usrp:
|
||||
case EProtocol::g3:
|
||||
// first check is IP & callsigned listed OK
|
||||
ok = ok && IsNodeListedOk(callsign, ip, module);
|
||||
ok = IsNodeListedOk(base);
|
||||
// todo: then apply any protocol specific authorisation for the operation
|
||||
break;
|
||||
|
||||
// URF interlinks
|
||||
case EProtocol::urf:
|
||||
case EProtocol::bm:
|
||||
ok = ok && IsPeerListedOk(callsign, ip, module);
|
||||
ok = IsPeerListedOk(base, module);
|
||||
break;
|
||||
|
||||
// unsupported
|
||||
@@ -175,17 +176,17 @@ void CGateKeeper::Thread()
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
|
||||
|
||||
// have lists files changed ?
|
||||
if ( m_NodeWhiteList.NeedReload() )
|
||||
if ( m_WhiteSet.NeedReload() )
|
||||
{
|
||||
m_NodeWhiteList.ReloadFromFile();
|
||||
m_WhiteSet.ReloadFromFile();
|
||||
}
|
||||
if ( m_NodeBlackList.NeedReload() )
|
||||
if ( m_BlackSet.NeedReload() )
|
||||
{
|
||||
m_NodeBlackList.ReloadFromFile();
|
||||
m_BlackSet.ReloadFromFile();
|
||||
}
|
||||
if ( m_PeerList.NeedReload() )
|
||||
if ( m_InterlinkMap.NeedReload() )
|
||||
{
|
||||
m_PeerList.ReloadFromFile();
|
||||
m_InterlinkMap.ReloadFromFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,30 +194,28 @@ void CGateKeeper::Thread()
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operation helpers
|
||||
|
||||
bool CGateKeeper::IsNodeListedOk(const CCallsign &callsign, const CIp &ip, char module) const
|
||||
bool CGateKeeper::IsNodeListedOk(const std::string &callsign) const
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
// first check IP
|
||||
|
||||
// next, check callsign
|
||||
if ( ok )
|
||||
{
|
||||
// first check if callsign is in white list
|
||||
// note if white list is empty, everybody is authorized
|
||||
m_NodeWhiteList.Lock();
|
||||
if ( !m_NodeWhiteList.empty() )
|
||||
m_WhiteSet.Lock();
|
||||
if ( ! m_WhiteSet.empty() )
|
||||
{
|
||||
ok = m_NodeWhiteList.IsCallsignListedWithWildcard(callsign, module);
|
||||
ok = m_WhiteSet.IsMatched(callsign);
|
||||
}
|
||||
m_NodeWhiteList.Unlock();
|
||||
m_WhiteSet.Unlock();
|
||||
|
||||
// then check if not blacklisted
|
||||
if (ok)
|
||||
{
|
||||
m_NodeBlackList.Lock();
|
||||
ok = !m_NodeBlackList.IsCallsignListedWithWildcard(callsign);
|
||||
m_NodeBlackList.Unlock();
|
||||
m_BlackSet.Lock();
|
||||
ok = ! m_BlackSet.IsMatched(callsign);
|
||||
m_BlackSet.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,7 +224,7 @@ bool CGateKeeper::IsNodeListedOk(const CCallsign &callsign, const CIp &ip, char
|
||||
|
||||
}
|
||||
|
||||
bool CGateKeeper::IsPeerListedOk(const CCallsign &callsign, const CIp &ip, char module) const
|
||||
bool CGateKeeper::IsPeerListedOk(const std::string &callsign, char module) const
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
@@ -235,19 +234,19 @@ bool CGateKeeper::IsPeerListedOk(const CCallsign &callsign, const CIp &ip, char
|
||||
if ( ok )
|
||||
{
|
||||
// look for an exact match in the list
|
||||
m_PeerList.Lock();
|
||||
if ( !m_PeerList.empty() )
|
||||
m_InterlinkMap.Lock();
|
||||
if ( !m_InterlinkMap.empty() )
|
||||
{
|
||||
ok = m_PeerList.IsCallsignListed(callsign, module);
|
||||
ok = m_InterlinkMap.IsCallsignListed(callsign, module);
|
||||
}
|
||||
m_PeerList.Unlock();
|
||||
m_InterlinkMap.Unlock();
|
||||
}
|
||||
|
||||
// done
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CGateKeeper::IsPeerListedOk(const CCallsign &callsign, const CIp &ip, char *modules) const
|
||||
bool CGateKeeper::IsPeerListedOk(const std::string &callsign, const CIp &ip, char *modules) const
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
@@ -257,12 +256,12 @@ bool CGateKeeper::IsPeerListedOk(const CCallsign &callsign, const CIp &ip, char
|
||||
if ( ok )
|
||||
{
|
||||
// look for an exact match in the list
|
||||
m_PeerList.Lock();
|
||||
if ( !m_PeerList.empty() )
|
||||
m_InterlinkMap.Lock();
|
||||
if ( ! m_InterlinkMap.empty() )
|
||||
{
|
||||
ok = m_PeerList.IsCallsignListed(callsign, modules);
|
||||
ok = m_InterlinkMap.IsCallsignListed(callsign, ip, modules);
|
||||
}
|
||||
m_PeerList.Unlock();
|
||||
m_InterlinkMap.Unlock();
|
||||
}
|
||||
|
||||
// done
|
||||
|
||||
+10
-12
@@ -22,8 +22,8 @@
|
||||
#include "Defines.h"
|
||||
#include "Callsign.h"
|
||||
#include "IP.h"
|
||||
#include "CallsignList.h"
|
||||
#include "PeerCallsignList.h"
|
||||
#include "BlackWhiteSet.h"
|
||||
#include "InterlinkMap.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
@@ -41,29 +41,27 @@ public:
|
||||
bool Init(void);
|
||||
void Close(void);
|
||||
|
||||
CInterlinkMap *GetInterlinkMap(void) { m_InterlinkMap.Lock(); return &m_InterlinkMap; }
|
||||
void ReleaseInterlinkMap(void) { m_InterlinkMap.Unlock(); }
|
||||
|
||||
// authorizations
|
||||
bool MayLink(const CCallsign &, const CIp &, const EProtocol, char * = nullptr) const;
|
||||
bool MayTransmit(const CCallsign &, const CIp &, EProtocol = EProtocol::any, char = ' ') const;
|
||||
|
||||
// peer list handeling
|
||||
CPeerCallsignList *GetPeerList(void) { m_PeerList.Lock(); return &m_PeerList; }
|
||||
void ReleasePeerList(void) { m_PeerList.Unlock(); }
|
||||
|
||||
protected:
|
||||
// thread
|
||||
void Thread();
|
||||
|
||||
// operation helpers
|
||||
bool IsNodeListedOk(const CCallsign &, const CIp &, char = ' ') const;
|
||||
bool IsPeerListedOk(const CCallsign &, const CIp &, char) const;
|
||||
bool IsPeerListedOk(const CCallsign &, const CIp &, char *) const;
|
||||
bool IsNodeListedOk(const std::string &) const;
|
||||
bool IsPeerListedOk(const std::string &, char) const;
|
||||
bool IsPeerListedOk(const std::string &, const CIp &, char *) const;
|
||||
const std::string ProtocolName(EProtocol) const;
|
||||
|
||||
protected:
|
||||
// data
|
||||
CCallsignList m_NodeWhiteList;
|
||||
CCallsignList m_NodeBlackList;
|
||||
CPeerCallsignList m_PeerList;
|
||||
CBlackWhiteSet m_WhiteSet, m_BlackSet;
|
||||
CInterlinkMap m_InterlinkMap;
|
||||
|
||||
// thread
|
||||
std::atomic<bool> keep_running;
|
||||
|
||||
@@ -219,7 +219,7 @@ unsigned int CGolay2087::getSyndrome1987(unsigned int pattern)
|
||||
* Compute the syndrome corresponding to the given pattern, i.e., the
|
||||
* remainder after dividing the pattern (when considering it as the vector
|
||||
* representation of a polynomial) by the generator polynomial, GENPOL.
|
||||
* In the program this pattern has several meanings: (1) pattern = infomation
|
||||
* In the program this pattern has several meanings: (1) pattern = information
|
||||
* bits, when constructing the encoding table; (2) pattern = error pattern,
|
||||
* when constructing the decoding table; and (3) pattern = received vector, to
|
||||
* obtain its syndrome in decoding.
|
||||
|
||||
@@ -1055,7 +1055,7 @@ static unsigned int get_syndrome_23127(unsigned int pattern)
|
||||
* Compute the syndrome corresponding to the given pattern, i.e., the
|
||||
* remainder after dividing the pattern (when considering it as the vector
|
||||
* representation of a polynomial) by the generator polynomial, GENPOL.
|
||||
* In the program this pattern has several meanings: (1) pattern = infomation
|
||||
* In the program this pattern has several meanings: (1) pattern = information
|
||||
* bits, when constructing the encoding table; (2) pattern = error pattern,
|
||||
* when constructing the decoding table; and (3) pattern = received vector, to
|
||||
* obtain its syndrome in decoding.
|
||||
|
||||
@@ -224,7 +224,7 @@ bool CHamming::decode1393(bool* d)
|
||||
d[12] = !d[12];
|
||||
return true;
|
||||
|
||||
// Data bit erros
|
||||
// Data bit errors
|
||||
case 0x0FU:
|
||||
d[0] = !d[0];
|
||||
return true;
|
||||
@@ -303,7 +303,7 @@ bool CHamming::decode1063(bool* d)
|
||||
d[9] = !d[9];
|
||||
return true;
|
||||
|
||||
// Data bit erros
|
||||
// Data bit errors
|
||||
case 0x07U:
|
||||
d[0] = !d[0];
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
//
|
||||
// ccallsignlist.cpp
|
||||
// m17ref
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 30/12/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020,2022 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of m17ref.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// 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
|
||||
// with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <fstream>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "Global.h"
|
||||
#include "InterlinkMap.h"
|
||||
|
||||
CInterlinkMap::CInterlinkMap()
|
||||
{
|
||||
m_Filename.clear();
|
||||
::memset(&m_LastModTime, 0, sizeof(time_t));
|
||||
}
|
||||
|
||||
bool CInterlinkMap::LoadFromFile(const std::string &filename)
|
||||
{
|
||||
bool ok = false;
|
||||
char line[256];
|
||||
|
||||
// and load
|
||||
std::ifstream file(filename);
|
||||
if ( file.is_open() )
|
||||
{
|
||||
Lock();
|
||||
|
||||
// empty list
|
||||
m_InterlinkMap.clear();
|
||||
// fill with file content
|
||||
while ( file.getline(line, sizeof(line)).good() )
|
||||
{
|
||||
char *token[4];
|
||||
// remove leading & trailing spaces
|
||||
token[0] = ToUpper(TrimWhiteSpaces(line));
|
||||
// crack it
|
||||
if ( (strlen(token[0]) > 0) && (token[0][0] != '#') )
|
||||
{
|
||||
const char *delim = " \t\r";
|
||||
// 1st token is callsign
|
||||
if ( (token[0] = strtok(token[0], delim)) != nullptr )
|
||||
{
|
||||
if (strcmp(token[0], g_Configure.GetString(g_Keys.names.callsign).c_str()))
|
||||
{
|
||||
// the default port depends on the protocol type (URF or BM)
|
||||
int default_port = (0 == memcmp(token[0], "URF", 3)) ? 10017 : 10002;
|
||||
if (m_InterlinkMap.end() == m_InterlinkMap.find(token[0]))
|
||||
{
|
||||
// read remaining tokens
|
||||
// 1=IP 2=Modules 3=Port Port is optional and defaults to 10017
|
||||
// OR... 1=Modules and the dht will be used
|
||||
for (int i=1; i<4; i++)
|
||||
{
|
||||
token[i] = strtok(nullptr, delim);
|
||||
}
|
||||
|
||||
if (token[2])
|
||||
{
|
||||
int port = default_port;
|
||||
if (token[3])
|
||||
{
|
||||
port = std::atoi(token[3]);
|
||||
if (port < 1024 || port > 49000)
|
||||
{
|
||||
std::cout << token[0] << " Port " << port << " is out of range, resetting to " << default_port << std::endl;
|
||||
port = default_port;
|
||||
}
|
||||
}
|
||||
m_InterlinkMap[token[0]] = CInterlinkMapItem(token[1], token[2], (uint16_t)port);
|
||||
}
|
||||
#ifndef NO_DHT
|
||||
else if (token[1])
|
||||
{
|
||||
m_InterlinkMap[token[0]] = CInterlinkMapItem(token[1]);
|
||||
}
|
||||
#endif
|
||||
else
|
||||
{
|
||||
std::cout << token[0] << " has insufficient parameters!" << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Duplicate found: " << token[0] << " in " << filename << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Self linking is not allowed! You cannot use " << token[0] << " in " << filename << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// close file
|
||||
file.close();
|
||||
|
||||
// keep file path
|
||||
m_Filename.assign(filename);
|
||||
|
||||
// update time
|
||||
GetLastModTime(&m_LastModTime);
|
||||
|
||||
// and done
|
||||
Unlock();
|
||||
ok = true;
|
||||
std::cout << "Gatekeeper loaded " << m_InterlinkMap.size() << " lines from " << filename << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Gatekeeper cannot find " << filename << std::endl;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CInterlinkMap::ReloadFromFile(void)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if ( ! m_Filename.empty() )
|
||||
{
|
||||
ok = LoadFromFile(m_Filename);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CInterlinkMap::NeedReload(void)
|
||||
{
|
||||
bool needReload = false;
|
||||
|
||||
time_t time;
|
||||
if ( GetLastModTime(&time) )
|
||||
{
|
||||
needReload = time != m_LastModTime;
|
||||
}
|
||||
return needReload;
|
||||
}
|
||||
|
||||
bool CInterlinkMap::IsCallsignListed(const std::string &callsign, char module) const
|
||||
{
|
||||
const auto item = m_InterlinkMap.find(callsign);
|
||||
if (m_InterlinkMap.cend() == item)
|
||||
return false;
|
||||
else
|
||||
return item->second.HasModuleListed(module);
|
||||
}
|
||||
|
||||
bool CInterlinkMap::IsCallsignListed(const std::string &callsign, const CIp &ip, const char *modules) const
|
||||
{
|
||||
const auto item = m_InterlinkMap.find(callsign);
|
||||
if (m_InterlinkMap.cend() != item)
|
||||
{
|
||||
if ( item->second.CheckListedModules(modules) )
|
||||
{
|
||||
if ( ip == item->second.GetIp() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "'" << callsign << "' not found in interlink map\n";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CInterlinkMapItem *CInterlinkMap::FindMapItem(const std::string &cs)
|
||||
{
|
||||
auto it = m_InterlinkMap.find(cs);
|
||||
if (m_InterlinkMap.end() == it)
|
||||
return nullptr;
|
||||
return &it->second;
|
||||
}
|
||||
|
||||
char *CInterlinkMap::TrimWhiteSpaces(char *str)
|
||||
{
|
||||
char *end;
|
||||
|
||||
// Trim leading space & tabs
|
||||
while((*str == ' ') || (*str == '\t')) str++;
|
||||
|
||||
// All spaces?
|
||||
if(*str == 0)
|
||||
return str;
|
||||
|
||||
// Trim trailing space, tab or lf
|
||||
end = str + ::strlen(str) - 1;
|
||||
while((end > str) && ((*end == ' ') || (*end == '\t') || (*end == '\r'))) end--;
|
||||
|
||||
// Write new null terminator
|
||||
*(end+1) = 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
bool CInterlinkMap::GetLastModTime(time_t *time)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if ( ! m_Filename.empty() )
|
||||
{
|
||||
struct stat fileStat;
|
||||
if( ::stat(m_Filename.c_str(), &fileStat) != -1 )
|
||||
{
|
||||
*time = fileStat.st_mtime;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
char *CInterlinkMap::ToUpper(char *str)
|
||||
{
|
||||
constexpr auto diff = 'a' - 'A';
|
||||
for (char *p=str; *p; p++)
|
||||
{
|
||||
if (*p >= 'a' && *p <= 'z')
|
||||
*p -= diff;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
#ifndef NO_DHT
|
||||
void CInterlinkMap::Update(const std::string &cs, const std::string &cmods, const std::string &ipv4, const std::string &ipv6, uint16_t port, const std::string &emods)
|
||||
{
|
||||
auto it = m_InterlinkMap.find(cs);
|
||||
if (m_InterlinkMap.end() == it)
|
||||
{
|
||||
std::cerr << "Can't Update CInterlinkMap item '" << cs << "' because it doesn't exist!";
|
||||
}
|
||||
else
|
||||
{
|
||||
it->second.UpdateItem(cmods, ipv4, ipv6, port, emods);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 30/12/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of m17ref.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// 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
|
||||
// with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
|
||||
#include "InterlinkMapItem.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CInterlinkMap
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CInterlinkMap();
|
||||
|
||||
// destructor
|
||||
virtual ~CInterlinkMap() {}
|
||||
|
||||
// locks
|
||||
void Lock(void) const { m_Mutex.lock(); }
|
||||
void Unlock(void) const { m_Mutex.unlock(); }
|
||||
|
||||
// file io
|
||||
virtual bool LoadFromFile(const std::string &filename);
|
||||
bool ReloadFromFile(void);
|
||||
bool NeedReload(void);
|
||||
|
||||
#ifndef NO_DHT
|
||||
void Update(const std::string &cs, const std::string &mods, const std::string &ipv4, const std::string &ipv6, uint16_t port, const std::string &tcmods);
|
||||
#endif
|
||||
|
||||
// compare
|
||||
bool IsCallsignListed(const std::string &, const char) const;
|
||||
bool IsCallsignListed(const std::string &, const CIp &ip, const char*) const;
|
||||
|
||||
// pass-through
|
||||
bool empty() const { return m_InterlinkMap.empty(); }
|
||||
std::map<std::string, CInterlinkMapItem>::iterator begin() { return m_InterlinkMap.begin(); }
|
||||
std::map<std::string, CInterlinkMapItem>::iterator end() { return m_InterlinkMap.end(); }
|
||||
std::map<std::string, CInterlinkMapItem>::const_iterator cbegin() { return m_InterlinkMap.cbegin(); }
|
||||
std::map<std::string, CInterlinkMapItem>::const_iterator cend() { return m_InterlinkMap.cend(); }
|
||||
|
||||
// find
|
||||
CInterlinkMapItem *FindMapItem(const std::string &);
|
||||
|
||||
protected:
|
||||
bool GetLastModTime(time_t *);
|
||||
char *TrimWhiteSpaces(char *);
|
||||
char *ToUpper(char *str);
|
||||
|
||||
// data
|
||||
mutable std::mutex m_Mutex;
|
||||
std::string m_Filename;
|
||||
time_t m_LastModTime;
|
||||
std::map<std::string, CInterlinkMapItem> m_InterlinkMap;
|
||||
};
|
||||
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// ccallsignlistitem.cpp
|
||||
// m17ref
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/01/2016.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020,2022 Thomas A. Early N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of m17ref.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// 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
|
||||
// with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "Configure.h"
|
||||
#include "InterlinkMapItem.h"
|
||||
#include "Reflector.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
#ifdef NO_DHT
|
||||
CInterlinkMapItem::CInterlinkMapItem()
|
||||
{
|
||||
m_UsesDHT = false;
|
||||
}
|
||||
#else
|
||||
CInterlinkMapItem::CInterlinkMapItem()
|
||||
{
|
||||
m_UsesDHT = false;
|
||||
m_Updated = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NO_DHT
|
||||
CInterlinkMapItem::CInterlinkMapItem(const char *mods)
|
||||
{
|
||||
m_UsesDHT = true;
|
||||
m_Updated = false;
|
||||
m_Mods.assign(mods);
|
||||
}
|
||||
#endif
|
||||
|
||||
CInterlinkMapItem::CInterlinkMapItem(const char *addr, const char *mods, uint16_t port) : CInterlinkMapItem()
|
||||
{
|
||||
m_Mods.assign(mods);
|
||||
m_Ip.Initialize(strchr(addr, ':') ? AF_INET6 : AF_INET, port, addr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// compare
|
||||
|
||||
bool CInterlinkMapItem::HasModuleListed(char module) const
|
||||
{
|
||||
return m_Mods.npos != m_Mods.find(module);
|
||||
}
|
||||
|
||||
bool CInterlinkMapItem::HasSameIp(const CIp &ip)
|
||||
{
|
||||
return ip == m_Ip;
|
||||
}
|
||||
|
||||
bool CInterlinkMapItem::CheckListedModules(const char *mods) const
|
||||
{
|
||||
if (mods == nullptr)
|
||||
return false;
|
||||
|
||||
// make sure every mods character is matched in m_Mods
|
||||
const auto count = m_Mods.size();
|
||||
bool found[count];
|
||||
for (unsigned i=0; i<count; i++)
|
||||
found[i] = false;
|
||||
for (auto p=mods; *p; p++)
|
||||
{
|
||||
auto pos = m_Mods.find(*p);
|
||||
if (pos == m_Mods.npos)
|
||||
return false;
|
||||
else
|
||||
found[pos] = true;
|
||||
}
|
||||
for (unsigned i=0; i<count; i++)
|
||||
{
|
||||
if (! found[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef NO_DHT
|
||||
void CInterlinkMapItem::UpdateItem(const std::string &cmods, const std::string &ipv4, const std::string &ipv6, uint16_t port, const std::string &tcmods)
|
||||
{
|
||||
if (m_CMods.compare(cmods))
|
||||
{
|
||||
m_CMods.assign(cmods);
|
||||
m_Updated = true;
|
||||
}
|
||||
if (m_IPv4.compare(ipv4))
|
||||
{
|
||||
m_IPv4.assign(ipv4);
|
||||
m_Updated = true;
|
||||
}
|
||||
if (m_IPv6.compare(ipv6))
|
||||
{
|
||||
m_IPv6.assign(ipv6);
|
||||
m_Updated = true;
|
||||
}
|
||||
if (m_Port != port)
|
||||
{
|
||||
m_Port = port;
|
||||
m_Updated = true;
|
||||
}
|
||||
if (m_TCMods.compare(tcmods))
|
||||
{
|
||||
m_TCMods.assign(tcmods);
|
||||
m_Updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CInterlinkMapItem::UpdateIP(bool IPv6NotConfigured)
|
||||
{
|
||||
if (m_Updated)
|
||||
{
|
||||
if (IPv6NotConfigured || m_IPv6.empty())
|
||||
m_Ip.Initialize(AF_INET, m_Port, m_IPv4.c_str());
|
||||
else
|
||||
m_Ip.Initialize(AF_INET6, m_Port, m_IPv6.c_str());
|
||||
|
||||
m_Updated = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,74 @@
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/01/2016.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of m17ref.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// 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
|
||||
// with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "Callsign.h"
|
||||
#include "IP.h"
|
||||
|
||||
class CInterlinkMapItem
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CInterlinkMapItem();
|
||||
#ifndef NO_DHT
|
||||
CInterlinkMapItem(const char *mods);
|
||||
#endif
|
||||
CInterlinkMapItem(const char *addr, const char *mods, uint16_t port);
|
||||
|
||||
// Update things
|
||||
#ifndef NO_DHT
|
||||
void UpdateIP(bool IPv6NotConfigured);
|
||||
void UpdateItem(const std::string &cmods, const std::string &ipv4, const std::string &ipv6, uint16_t port, const std::string &tcmods);
|
||||
#endif
|
||||
|
||||
// compare
|
||||
bool HasSameIp(const CIp &ip);
|
||||
bool HasModuleListed(char) const;
|
||||
bool CheckListedModules(const char*) const;
|
||||
|
||||
// get
|
||||
const CIp &GetIp(void) const { return m_Ip; }
|
||||
const std::string &GetModules(void) const { return m_Mods; }
|
||||
bool UsesDHT(void) const { return m_UsesDHT; }
|
||||
uint16_t GetPort(void) const { return m_Port; }
|
||||
#ifndef NO_DHT
|
||||
const std::string &GetIPv4(void) const { return m_IPv4; }
|
||||
const std::string &GetIPv6(void) const { return m_IPv6; }
|
||||
const std::string &GetTCMods(void) const { return m_TCMods; }
|
||||
const std::string &GetCMods(void) const { return m_CMods; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
// data
|
||||
CIp m_Ip;
|
||||
std::string m_Mods;
|
||||
uint16_t m_Port;
|
||||
bool m_UsesDHT;
|
||||
|
||||
#ifndef NO_DHT
|
||||
bool m_Updated;
|
||||
std::string m_CMods, m_TCMods, m_IPv4, m_IPv6;
|
||||
#endif
|
||||
};
|
||||
@@ -39,8 +39,8 @@ struct SJsonKeys {
|
||||
struct MMDVM { const std::string port, defaultid; }
|
||||
mmdvm { "MMDVMPort", "mmdvmdefaultid" };
|
||||
|
||||
struct NAMES { const std::string callsign, email, country, sponsor; }
|
||||
names { "Callsign", "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" };
|
||||
|
||||
@@ -27,26 +27,6 @@
|
||||
enum class Eaction { normal, parse, error_only };
|
||||
enum class Esource { http, file };
|
||||
|
||||
// compare function for std::map::find
|
||||
|
||||
struct CCallsignHash
|
||||
{
|
||||
std::size_t operator() (const UCallsign &ucs) const
|
||||
{
|
||||
std::hash<uint64_t> hash;
|
||||
return hash(ucs.l);
|
||||
}
|
||||
};
|
||||
|
||||
struct CCallsignEqual
|
||||
{
|
||||
bool operator() (const UCallsign &ucs1, const UCallsign &ucs2) const
|
||||
{
|
||||
return ucs1.l == ucs2.l;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CLookup
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
* Description
|
||||
* -----------
|
||||
* The source file contains routines which calculate the CCITT CRC
|
||||
* values for an incomming byte string.
|
||||
* values for an incoming byte string.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
* Description
|
||||
* -----------
|
||||
* The source file contains routines which calculate the CCITT CRC
|
||||
* values for an incomming byte string.
|
||||
* values for an incoming byte string.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
+4
-4
@@ -28,7 +28,7 @@ SJsonKeys g_Keys;
|
||||
CReflector g_Reflector;
|
||||
CGateKeeper g_GateKeeper;
|
||||
CConfigure g_Configure;
|
||||
CVersion g_Version(3,0,1); // The major byte should only change if the interlink packet changes!
|
||||
CVersion g_Version(3,1,0); // The major byte should only change if the interlink packet changes!
|
||||
CLookupDmr g_LDid;
|
||||
CLookupNxdn g_LNid;
|
||||
CLookupYsf g_LYtr;
|
||||
@@ -39,7 +39,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
std::cerr << "No configuration file specifed! Usage: " << argv[0] << " /pathname/to/configuration/file" << std::endl;
|
||||
std::cerr << "No configuration file specified! Usage: " << argv[0] << " /pathname/to/configuration/file" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@@ -98,13 +98,13 @@ static void usage(std::ostream &os, const char *name)
|
||||
" ysf : The Callsign => Tx/Rx frequency database.\n"
|
||||
"SOURCE (choose one)\n"
|
||||
" file : The file specified by the FilePath ini parameter.\n"
|
||||
" http : The URL specified by the URL ini paramater.\n"
|
||||
" http : The URL specified by the URL ini parameter.\n"
|
||||
"ACTION (choose one)\n"
|
||||
" print : Print all lines from the SOURCE that are syntactically correct.\n"
|
||||
" error : Print only the lines with failed syntax.\n"
|
||||
"INIFILE : an error-free urfd ini file (check it first with inicheck).\n\n"
|
||||
"Only the first character of DATABASE, SOURCE and ACTION is read.\n"
|
||||
"Example: " << name << " y f e urfd.ini # Check your YSF Tx/Rx database file specifed in urfd.ini for syntax errors.\n\n";
|
||||
"Example: " << name << " y f e urfd.ini # Check your YSF Tx/Rx database file specified in urfd.ini for syntax errors.\n\n";
|
||||
}
|
||||
|
||||
enum class Edb { none, dmr, nxdn, ysf };
|
||||
|
||||
+8
-2
@@ -27,13 +27,19 @@ DBUTIL = dbutil
|
||||
include urfd.mk
|
||||
|
||||
ifeq ($(debug), true)
|
||||
CFLAGS = -ggdb3 -DDEBUG -W -Werror -std=c++11 -MMD -MD
|
||||
CFLAGS = -ggdb3 -DDEBUG -W -Werror -std=c++17 -MMD -MD
|
||||
else
|
||||
CFLAGS = -W -Werror -std=c++11 -MMD -MD
|
||||
CFLAGS = -W -Werror -std=c++17 -MMD -MD
|
||||
endif
|
||||
|
||||
LDFLAGS=-pthread -lcurl
|
||||
|
||||
ifeq ($(DHT), true)
|
||||
LDFLAGS += -lopendht
|
||||
else
|
||||
CFLAGS += -DNO_DHT
|
||||
endif
|
||||
|
||||
SRCS = $(wildcard *.cpp)
|
||||
OBJS = $(SRCS:.cpp=.o)
|
||||
DEPS = $(SRCS:.cpp=.d)
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
// Copyright © 2015 Jean-Luc. 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#include "Notification.h"
|
||||
|
||||
CNotification::CNotification()
|
||||
{
|
||||
// init variables
|
||||
m_iId = NOTIFICATION_NONE;
|
||||
}
|
||||
|
||||
CNotification::CNotification(int iId)
|
||||
{
|
||||
m_iId = iId;
|
||||
}
|
||||
|
||||
CNotification::CNotification(int iId, const CCallsign &Callsign)
|
||||
{
|
||||
m_iId = iId;
|
||||
m_Callsign = Callsign;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright © 2015 Jean-Luc. 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Callsign.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Id
|
||||
#define NOTIFICATION_NONE 0
|
||||
#define NOTIFICATION_CLIENTS 1
|
||||
#define NOTIFICATION_USERS 2
|
||||
#define NOTIFICATION_STREAM_OPEN 3
|
||||
#define NOTIFICATION_STREAM_CLOSE 4
|
||||
#define NOTIFICATION_PEERS 5
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CNotification
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CNotification();
|
||||
CNotification(int);
|
||||
CNotification(int, const CCallsign &);
|
||||
|
||||
// get
|
||||
int GetId(void) const { return m_iId; }
|
||||
const CCallsign &GetCallsign(void) const { return m_Callsign; }
|
||||
|
||||
protected:
|
||||
// data
|
||||
int m_iId;
|
||||
CCallsign m_Callsign;
|
||||
|
||||
};
|
||||
@@ -1,49 +0,0 @@
|
||||
// Copyright © 2015 Jean-Luc. 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
|
||||
#include "Notification.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CNotificationQueue
|
||||
{
|
||||
public:
|
||||
// lock
|
||||
void Lock() { m_Mutex.lock(); }
|
||||
void Unlock() { m_Mutex.unlock(); }
|
||||
|
||||
// pass thru
|
||||
CNotification front() { return queue.front(); }
|
||||
void pop() { queue.pop(); }
|
||||
void push(CNotification note) { queue.push(note); }
|
||||
bool empty() const { return queue.empty(); }
|
||||
|
||||
protected:
|
||||
// data
|
||||
std::mutex m_Mutex;
|
||||
std::queue<CNotification> queue;
|
||||
};
|
||||
@@ -88,7 +88,7 @@ void CPacket::EncodeInterlinkPacket(const char *magic, CBuffer &buf) const
|
||||
data[19] = m_uiYsfPacketFrameId;
|
||||
}
|
||||
|
||||
// dstar contstructor
|
||||
// dstar constructor
|
||||
CPacket::CPacket(uint16_t sid, uint8_t dstarpid)
|
||||
{
|
||||
m_uiStreamId = sid;
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
@@ -60,7 +61,7 @@ public:
|
||||
int GetNbClients(void) const { return (int)m_Clients.size(); }
|
||||
void ClearClients(void) { m_Clients.clear(); }
|
||||
|
||||
// pass-thru
|
||||
// pass-through
|
||||
std::list<std::shared_ptr<CClient>>::iterator begin() { return m_Clients.begin(); }
|
||||
std::list<std::shared_ptr<CClient>>::iterator end() { return m_Clients.end(); }
|
||||
std::list<std::shared_ptr<CClient>>::const_iterator cbegin() const { return m_Clients.cbegin(); }
|
||||
|
||||
@@ -1,84 +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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <fstream>
|
||||
#include <string.h>
|
||||
|
||||
#include "PeerCallsignList.h"
|
||||
|
||||
bool CPeerCallsignList::LoadFromFile(const std::string &filename)
|
||||
{
|
||||
bool ok = false;
|
||||
char sz[256];
|
||||
|
||||
// and load
|
||||
std::ifstream file (filename);
|
||||
if ( file.is_open() )
|
||||
{
|
||||
Lock();
|
||||
|
||||
// empty list
|
||||
m_Callsigns.clear();
|
||||
// fill with file content
|
||||
while ( file.getline(sz, sizeof(sz)).good() )
|
||||
{
|
||||
// remove leading & trailing spaces
|
||||
char *szt = TrimWhiteSpaces(sz);
|
||||
|
||||
// crack it
|
||||
if ( (::strlen(szt) > 0) && (szt[0] != '#') )
|
||||
{
|
||||
// 1st token is callsign
|
||||
if ( (szt = ::strtok(szt, " ,\t")) != nullptr )
|
||||
{
|
||||
CCallsign callsign(szt);
|
||||
// 2nd token is ip
|
||||
char *szip;
|
||||
if ( (szip = ::strtok(nullptr, " ,\t")) != nullptr )
|
||||
{
|
||||
// 3rd token is modules list
|
||||
if ( (szt = ::strtok(nullptr, " ,\t")) != nullptr )
|
||||
{
|
||||
// and load
|
||||
m_Callsigns.push_back(CCallsignListItem(callsign, szip, szt));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// close file
|
||||
file.close();
|
||||
|
||||
// keep file path
|
||||
m_Filename = filename;
|
||||
|
||||
// update time
|
||||
GetLastModTime(&m_LastModTime);
|
||||
|
||||
// and done
|
||||
Unlock();
|
||||
ok = true;
|
||||
std::cout << "Gatekeeper loaded " << m_Callsigns.size() << " lines from " << filename << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Gatekeeper cannot find " << filename << std::endl;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
@@ -1,38 +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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "CallsignList.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CPeerCallsignList : public CCallsignList
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CPeerCallsignList() {}
|
||||
|
||||
// destructor
|
||||
virtual ~CPeerCallsignList() {}
|
||||
|
||||
// file io
|
||||
bool LoadFromFile(const std::string &filename);
|
||||
};
|
||||
+1
-1
@@ -38,7 +38,7 @@ public:
|
||||
void AddPeer(std::shared_ptr<CPeer>);
|
||||
void RemovePeer(std::shared_ptr<CPeer>);
|
||||
|
||||
// pass-thru
|
||||
// pass-through
|
||||
std::list<std::shared_ptr<CPeer>>::iterator begin() { return m_Peers.begin(); }
|
||||
std::list<std::shared_ptr<CPeer>>::iterator end() { return m_Peers.end(); }
|
||||
std::list<std::shared_ptr<CPeer>>::const_iterator cbegin() const { return m_Peers.cbegin(); }
|
||||
|
||||
@@ -32,7 +32,7 @@ public:
|
||||
void Lock(void) { m_Mutex.lock(); }
|
||||
void Unlock(void) { m_Mutex.unlock(); }
|
||||
|
||||
// pass-thru
|
||||
// pass-through
|
||||
std::list<std::unique_ptr<CProtocol>>::iterator begin() { return m_Protocols.begin(); }
|
||||
std::list<std::unique_ptr<CProtocol>>::iterator end() { return m_Protocols.end(); }
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ unsigned int CQR1676::getSyndrome1576(unsigned int pattern)
|
||||
* Compute the syndrome corresponding to the given pattern, i.e., the
|
||||
* remainder after dividing the pattern (when considering it as the vector
|
||||
* representation of a polynomial) by the generator polynomial, GENPOL.
|
||||
* In the program this pattern has several meanings: (1) pattern = infomation
|
||||
* In the program this pattern has several meanings: (1) pattern = information
|
||||
* bits, when constructing the encoding table; (2) pattern = error pattern,
|
||||
* when constructing the decoding table; and (3) pattern = received vector, to
|
||||
* obtain its syndrome in decoding.
|
||||
|
||||
+267
-43
@@ -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;
|
||||
|
||||
@@ -107,13 +120,17 @@ bool CReflector::Start(void)
|
||||
// start the reporting thread
|
||||
try
|
||||
{
|
||||
m_XmlReportFuture = std::async(std::launch::async, &CReflector::XmlReportThread, this);
|
||||
m_XmlReportFuture = std::async(std::launch::async, &CReflector::StateReportThread, this);
|
||||
}
|
||||
catch(const std::exception& e)
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -155,7 +182,7 @@ bool CReflector::IsStreaming(char module)
|
||||
return false;
|
||||
}
|
||||
|
||||
// clients MUST have bee locked by the caller so we can freely access it within the fuction
|
||||
// clients MUST have bee locked by the caller so we can freely access it within the function
|
||||
std::shared_ptr<CPacketStream> CReflector::OpenStream(std::unique_ptr<CDvHeaderPacket> &DvHeader, std::shared_ptr<CClient>client)
|
||||
{
|
||||
// check sid is not zero
|
||||
@@ -209,7 +236,7 @@ std::shared_ptr<CPacketStream> CReflector::OpenStream(std::unique_ptr<CDvHeaderP
|
||||
stream->Push(std::move(DvHeader));
|
||||
|
||||
// notify
|
||||
OnStreamOpen(stream->GetUserCallsign());
|
||||
//OnStreamOpen(stream->GetUserCallsign());
|
||||
|
||||
}
|
||||
return stream;
|
||||
@@ -237,7 +264,7 @@ void CReflector::CloseStream(std::shared_ptr<CPacketStream> stream)
|
||||
client->NotAMaster();
|
||||
|
||||
// notify
|
||||
OnStreamClose(stream->GetUserCallsign());
|
||||
//OnStreamClose(stream->GetUserCallsign());
|
||||
|
||||
std::cout << "Closing stream of module " << GetStreamModule(stream) << std::endl;
|
||||
}
|
||||
@@ -296,10 +323,12 @@ void CReflector::RouterThread(const char ThisModule)
|
||||
|
||||
#define XML_UPDATE_PERIOD 10
|
||||
|
||||
void CReflector::XmlReportThread()
|
||||
void CReflector::StateReportThread()
|
||||
{
|
||||
std::string xmlpath, jsonpath;
|
||||
|
||||
#ifndef NO_DHT
|
||||
peers_changed = clients_changed = users_changed = true;
|
||||
#endif
|
||||
if (g_Configure.Contains(g_Keys.files.xml))
|
||||
xmlpath.assign(g_Configure.GetString(g_Keys.files.xml));
|
||||
if (g_Configure.Contains(g_Keys.files.json))
|
||||
@@ -343,9 +372,29 @@ void CReflector::XmlReportThread()
|
||||
}
|
||||
}
|
||||
|
||||
// and wait a bit
|
||||
// and wait a bit and do something useful at the same time
|
||||
for (int i=0; i< XML_UPDATE_PERIOD && keep_running; i++)
|
||||
{
|
||||
#ifndef NO_DHT
|
||||
// update the dht data, if needed
|
||||
if (peers_changed)
|
||||
{
|
||||
PutDHTPeers();
|
||||
peers_changed = false;
|
||||
}
|
||||
if (clients_changed)
|
||||
{
|
||||
PutDHTClients();
|
||||
clients_changed = false;
|
||||
}
|
||||
if (users_changed)
|
||||
{
|
||||
PutDHTUsers();
|
||||
users_changed = false;
|
||||
}
|
||||
#endif
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,47 +403,23 @@ void CReflector::XmlReportThread()
|
||||
|
||||
void CReflector::OnPeersChanged(void)
|
||||
{
|
||||
CNotification notification(NOTIFICATION_PEERS);
|
||||
|
||||
m_Notifications.Lock();
|
||||
m_Notifications.push(notification);
|
||||
m_Notifications.Unlock();
|
||||
#ifndef NO_DHT
|
||||
peers_changed = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CReflector::OnClientsChanged(void)
|
||||
{
|
||||
CNotification notification(NOTIFICATION_CLIENTS);
|
||||
|
||||
m_Notifications.Lock();
|
||||
m_Notifications.push(notification);
|
||||
m_Notifications.Unlock();
|
||||
#ifndef NO_DHT
|
||||
clients_changed = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CReflector::OnUsersChanged(void)
|
||||
{
|
||||
CNotification notification(NOTIFICATION_USERS);
|
||||
|
||||
m_Notifications.Lock();
|
||||
m_Notifications.push(notification);
|
||||
m_Notifications.Unlock();
|
||||
}
|
||||
|
||||
void CReflector::OnStreamOpen(const CCallsign &callsign)
|
||||
{
|
||||
CNotification notification(NOTIFICATION_STREAM_OPEN, callsign);
|
||||
|
||||
m_Notifications.Lock();
|
||||
m_Notifications.push(notification);
|
||||
m_Notifications.Unlock();
|
||||
}
|
||||
|
||||
void CReflector::OnStreamClose(const CCallsign &callsign)
|
||||
{
|
||||
CNotification notification(NOTIFICATION_STREAM_CLOSE, callsign);
|
||||
|
||||
m_Notifications.Lock();
|
||||
m_Notifications.push(notification);
|
||||
m_Notifications.Unlock();
|
||||
#ifndef NO_DHT
|
||||
users_changed = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -512,3 +537,202 @@ 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
|
||||
SUrfdPeers1 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-1");
|
||||
nv->id = toUType(EUrfdValueID::Peers);
|
||||
|
||||
node.putSigned(
|
||||
refhash,
|
||||
nv,
|
||||
#ifdef DEBUG
|
||||
[](bool success){ std::cout << "PutDHTPeers() " << (success ? "successful" : "unsuccessful") << std::endl; },
|
||||
#else
|
||||
[](bool success){ if (! success) std::cout << "PutDHTPeers() unsuccessful" << std::endl; },
|
||||
#endif
|
||||
true // permanent!
|
||||
);
|
||||
}
|
||||
|
||||
void CReflector::PutDHTClients()
|
||||
{
|
||||
const std::string cs(g_Configure.GetString(g_Keys.names.callsign));
|
||||
SUrfdClients1 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-1");
|
||||
nv->id = toUType(EUrfdValueID::Clients);
|
||||
|
||||
node.putSigned(
|
||||
refhash,
|
||||
nv,
|
||||
#ifdef DEBUG
|
||||
[](bool success){ std::cout << "PutDHTClients() " << (success ? "successful" : "unsuccessful") << std::endl; },
|
||||
#else
|
||||
[](bool success){ if (! success) std::cout << "PutDHTClients() unsuccessful" << std::endl; },
|
||||
#endif
|
||||
true // permanent!
|
||||
);
|
||||
}
|
||||
|
||||
void CReflector::PutDHTUsers()
|
||||
{
|
||||
const std::string cs(g_Configure.GetString(g_Keys.names.callsign));
|
||||
SUrfdUsers1 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-1");
|
||||
nv->id = toUType(EUrfdValueID::Users);
|
||||
|
||||
node.putSigned(
|
||||
refhash,
|
||||
nv,
|
||||
#ifdef DEBUG
|
||||
[](bool success){ std::cout << "PutDHTUsers() " << (success ? "successful" : "unsuccessful") << std::endl; },
|
||||
#else
|
||||
[](bool success){ if (! success) std::cout << "PutDHTUsers() unsuccessful" << std::endl; },
|
||||
#endif
|
||||
true // permanent!
|
||||
);
|
||||
}
|
||||
|
||||
void CReflector::PutDHTConfig()
|
||||
{
|
||||
const std::string cs(g_Configure.GetString(g_Keys.names.callsign));
|
||||
SUrfdConfig1 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.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);
|
||||
cfg.g3enabled = g_Configure.GetBoolean(g_Keys.g3.enable);
|
||||
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-1");
|
||||
nv->id = toUType(EUrfdValueID::Config);
|
||||
|
||||
node.putSigned(
|
||||
refhash,
|
||||
nv,
|
||||
#ifdef DEBUG
|
||||
[](bool success){ std::cout << "PutDHTConfig() " << (success ? "successful" : "unsuccessful") << std::endl; },
|
||||
#else
|
||||
[](bool success){ if(! success) std::cout << "PutDHTConfig() unsuccessful" << std::endl; },
|
||||
#endif
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
void CReflector::GetDHTConfig(const std::string &cs)
|
||||
{
|
||||
static SUrfdConfig1 cfg;
|
||||
cfg.timestamp = 0; // every time this is called, zero the timestamp
|
||||
|
||||
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("urfd-config-1"))
|
||||
{
|
||||
auto rdat = dht::Value::unpack<SUrfdConfig1>(*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<SUrfdConfig1>(*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_GateKeeper.GetInterlinkMap()->Update(cfg.cs, cfg.mods, cfg.ipv4, cfg.ipv6, cfg.port[toUType(EUrfdPorts::urf)], cfg.tcmods);
|
||||
g_GateKeeper.ReleaseInterlinkMap();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "node.Get() was successful, but the timestamp was zero" << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Get() was unsuccessful" << std::endl;
|
||||
}
|
||||
},
|
||||
{}, // empty filter
|
||||
w // just the configuration section
|
||||
);
|
||||
}
|
||||
|
||||
#endif
|
||||
+24
-7
@@ -25,7 +25,10 @@
|
||||
#include "Peers.h"
|
||||
#include "Protocols.h"
|
||||
#include "PacketStream.h"
|
||||
#include "NotificationQueue.h"
|
||||
|
||||
#ifndef NO_DHT
|
||||
#include "urfd-dht-values.h"
|
||||
#endif
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -42,6 +45,7 @@
|
||||
class CReflector
|
||||
{
|
||||
public:
|
||||
CReflector();
|
||||
// destructor
|
||||
~CReflector();
|
||||
|
||||
@@ -75,13 +79,22 @@ public:
|
||||
void OnPeersChanged(void);
|
||||
void OnClientsChanged(void);
|
||||
void OnUsersChanged(void);
|
||||
void OnStreamOpen(const CCallsign &);
|
||||
void OnStreamClose(const CCallsign &);
|
||||
#ifndef NO_DHT
|
||||
void GetDHTConfig(const std::string &cs);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
#ifndef NO_DHT
|
||||
// Publish DHT
|
||||
void PutDHTConfig();
|
||||
void PutDHTPeers();
|
||||
void PutDHTClients();
|
||||
void PutDHTUsers();
|
||||
#endif
|
||||
|
||||
// threads
|
||||
void RouterThread(const char);
|
||||
void XmlReportThread(void);
|
||||
void StateReportThread(void);
|
||||
|
||||
// streams
|
||||
std::shared_ptr<CPacketStream> GetStream(char);
|
||||
@@ -92,7 +105,6 @@ protected:
|
||||
void WriteXmlFile(std::ofstream &);
|
||||
void JsonReport(nlohmann::json &report);
|
||||
|
||||
protected:
|
||||
// identity
|
||||
CCallsign m_Callsign;
|
||||
std::string m_Modules, m_TCmodules;
|
||||
@@ -111,6 +123,11 @@ protected:
|
||||
std::unordered_map<char, std::future<void>> m_RouterFuture;
|
||||
std::future<void> m_XmlReportFuture;
|
||||
|
||||
// notifications
|
||||
CNotificationQueue m_Notifications;
|
||||
#ifndef NO_DHT
|
||||
// Distributed Hash Table
|
||||
dht::DhtRunner node;
|
||||
dht::InfoHash refhash;
|
||||
unsigned int peers_put_count, clients_put_count, users_put_count;
|
||||
std::atomic<bool> peers_changed, clients_changed, users_changed;
|
||||
#endif
|
||||
};
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
/************************************************************
|
||||
* THIS IS IMPORTANT
|
||||
* This template is primarly designed for std::unique_ptr!
|
||||
* This template is primarily designed for std::unique_ptr!
|
||||
* If you are going to use it for std::shared_ptr, then
|
||||
* please consider that when you Push(), what you pushed
|
||||
* from will be nullptr after the Push()!
|
||||
@@ -56,13 +56,13 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// If the queue is empty, wait until an element is avaiable.
|
||||
// If the queue is empty, wait until an element is available.
|
||||
T PopWait(void)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m);
|
||||
while(q.empty())
|
||||
{
|
||||
// release lock as long as the wait and reaquire it afterwards.
|
||||
// release lock as long as the wait and reacquire it afterwards.
|
||||
c.wait(lock);
|
||||
}
|
||||
T val = std::move(q.front());
|
||||
|
||||
@@ -40,7 +40,7 @@ CUdpSocket::~CUdpSocket()
|
||||
// returns true on error
|
||||
bool CUdpSocket::Open(const CIp &Ip)
|
||||
{
|
||||
// check for a vaild family
|
||||
// check for a valid family
|
||||
if (AF_UNSPEC == Ip.GetFamily())
|
||||
return true;
|
||||
|
||||
|
||||
+64
-21
@@ -287,16 +287,16 @@ void CURFProtocol::HandlePeerLinks(void)
|
||||
CBuffer buffer;
|
||||
|
||||
// get the list of peers
|
||||
CPeerCallsignList *list = g_GateKeeper.GetPeerList();
|
||||
auto ilmap = g_GateKeeper.GetInterlinkMap();
|
||||
CPeers *peers = g_Reflector.GetPeers();
|
||||
|
||||
// check if all our connected peers are still listed by gatekeeper
|
||||
// if not, disconnect
|
||||
auto pit = peers->begin();
|
||||
std::shared_ptr<CPeer>peer = nullptr;
|
||||
while ( (peer = peers->FindNextPeer(EProtocol::urf, pit)) != nullptr )
|
||||
while (nullptr != (peer = peers->FindNextPeer(EProtocol::urf, pit)))
|
||||
{
|
||||
if ( list->FindListItem(peer->GetCallsign()) == nullptr )
|
||||
if (nullptr == ilmap->FindMapItem(peer->GetCallsign().GetBase()))
|
||||
{
|
||||
// send disconnect packet
|
||||
EncodeDisconnectPacket(&buffer);
|
||||
@@ -307,29 +307,64 @@ void CURFProtocol::HandlePeerLinks(void)
|
||||
}
|
||||
}
|
||||
|
||||
// check if all ours peers listed by gatekeeper are connected
|
||||
// check if all ours peers listed by interlink file are connected
|
||||
// if not, connect or reconnect
|
||||
for ( auto it=list->begin(); it!=list->end(); it++ )
|
||||
for ( auto it=ilmap->begin(); it!=ilmap->end(); it++ )
|
||||
{
|
||||
if ( it->GetCallsign().HasSameCallsignWithWildcard(CCallsign("XRF*")) )
|
||||
continue;
|
||||
if ( it->GetCallsign().HasSameCallsignWithWildcard(CCallsign("BM*")) )
|
||||
continue;
|
||||
CCallsign cs = it->GetCallsign();
|
||||
if (cs.HasSameCallsignWithWildcard(CCallsign("URF*")) && (nullptr==peers->FindPeer(cs, EProtocol::urf)))
|
||||
const auto cs = it->first;
|
||||
CCallsign callsign;
|
||||
callsign.SetCallsign(cs, false);
|
||||
if ((0 == cs.substr(0, 3).compare("URF")) && (nullptr==peers->FindPeer(callsign, EProtocol::urf)))
|
||||
{
|
||||
// resolve again peer's IP in case it's a dynamic IP
|
||||
it->ResolveIp();
|
||||
// send connect packet to re-initiate peer link
|
||||
EncodeConnectPacket(&buffer, it->GetModules());
|
||||
Send(buffer, it->GetIp(), m_Port);
|
||||
std::cout << "Sending connect packet to URF peer " << cs << " @ " << it->GetIp() << " for modules " << it->GetModules() << std::endl;
|
||||
#ifndef NO_DHT
|
||||
it->second.UpdateIP(g_Configure.GetString(g_Keys.ip.ipv6address).empty());
|
||||
if (it->second.GetIp().IsSet())
|
||||
{
|
||||
bool ok = true;
|
||||
// does everything match up?
|
||||
for (const auto c : it->second.GetModules())
|
||||
{
|
||||
if (std::string::npos == g_Configure.GetString(g_Keys.modules.modules).find(c))
|
||||
{ // is the local module not config'ed?
|
||||
ok = false;
|
||||
std::cerr << "This reflector has no module '" << c << "', so it can't interlink with " << it->first << std::endl;
|
||||
}
|
||||
else if (it->second.UsesDHT())
|
||||
{
|
||||
if (std::string::npos == it->second.GetCMods().find(c))
|
||||
{ // the remote module not config'ed!
|
||||
ok = false;
|
||||
std::cerr << it->first << " has no module '" << c << "'" << std::endl;
|
||||
}
|
||||
else if ((std::string::npos == it->second.GetTCMods().find(c)) != (std::string::npos == g_Configure.GetString(g_Keys.modules.tcmodules).find(c)))
|
||||
{ // are the transcoding states on both sides mismatched?
|
||||
ok = false;
|
||||
std::cerr << "The transcode states for module '" << c << "' don't match for this reflector and " << it->first << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ok)
|
||||
{
|
||||
|
||||
#endif
|
||||
// send connect packet to re-initiate peer link
|
||||
EncodeConnectPacket(&buffer, it->second.GetModules().c_str());
|
||||
Send(buffer, it->second.GetIp());
|
||||
std::cout << "Sent connect packet to URF peer " << cs << " @ " << it->second.GetIp() << " for modules " << it->second.GetModules() << std::endl;
|
||||
#ifndef NO_DHT
|
||||
}
|
||||
}
|
||||
else // m_Ip is not set!
|
||||
{
|
||||
g_Reflector.GetDHTConfig(it->first);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// done
|
||||
g_Reflector.ReleasePeers();
|
||||
g_GateKeeper.ReleasePeerList();
|
||||
g_GateKeeper.ReleaseInterlinkMap();
|
||||
}
|
||||
|
||||
|
||||
@@ -415,10 +450,18 @@ bool CURFProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *callsi
|
||||
callsign->CodeIn(Buffer.data()+4);
|
||||
valid = callsign->IsValid();
|
||||
*version = CVersion(Buffer.at(37), Buffer.at(38), Buffer.at(39));
|
||||
memcpy(modules, Buffer.data()+10, 27);
|
||||
for ( unsigned i = 0; i < strlen(modules); i++ )
|
||||
if (valid)
|
||||
{
|
||||
valid = valid && (g_Reflector.IsValidModule (modules[i]));
|
||||
memcpy(modules, Buffer.data()+10, 27);
|
||||
for ( unsigned i = 0; i < strlen(modules); i++ )
|
||||
{
|
||||
auto moduleok = g_Reflector.IsValidModule(modules[i]);
|
||||
if (! moduleok)
|
||||
{
|
||||
valid = false;
|
||||
std::cout << "Requested module '" << modules[i] << "' is not confgured\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
|
||||
@@ -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); }
|
||||
|
||||
|
||||
+3
-1
@@ -40,9 +40,11 @@ public:
|
||||
int GetSize(void) const { return (int)m_Users.size(); }
|
||||
void AddUser(const CUser &);
|
||||
|
||||
// pass-thru
|
||||
// pass-through
|
||||
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 &);
|
||||
|
||||
@@ -85,5 +85,8 @@ bool CVersion::operator <(const CVersion &v) const
|
||||
std::ostream &operator <<(std::ostream &os, const CVersion &v)
|
||||
{
|
||||
os << v.GetMajor() << '.' << v.GetMinor() << '.' << v.GetRevision();
|
||||
#ifndef NO_DHT
|
||||
os << "-dht";
|
||||
#endif
|
||||
return os;
|
||||
};
|
||||
+1
-1
@@ -38,7 +38,7 @@ public:
|
||||
// set
|
||||
void Set(uint8_t, uint8_t, uint8_t);
|
||||
|
||||
// comparaison operators
|
||||
// comparison operators
|
||||
bool operator ==(const CVersion &v) const;
|
||||
bool operator !=(const CVersion &v) const;
|
||||
bool operator >=(const CVersion &v) const;
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
// Copyright © 2023 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of urfd.
|
||||
//
|
||||
// M17Refd 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.
|
||||
//
|
||||
// M17Refd 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
|
||||
// with this software. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <opendht.h>
|
||||
|
||||
/* HELPERS */
|
||||
#ifndef TO_U_TYPE_DEF
|
||||
#define TO_U_TYPE_DEF
|
||||
template<typename E> constexpr auto toUType(E enumerator) noexcept
|
||||
{
|
||||
return static_cast<std::underlying_type_t<E>>(enumerator);
|
||||
} // Item #10 in "Effective Modern C++", by Scott Meyers, O'REILLY
|
||||
#endif
|
||||
|
||||
enum class EUrfdValueID : uint64_t { Config=1, Peers=2, Clients=3, Users=4 };
|
||||
|
||||
/* PEERS */
|
||||
using UrfdPeerTuple = std::tuple<std::string, std::string, std::time_t>;
|
||||
enum class EUrfdPeerFields { Callsign, Modules, ConnectTime };
|
||||
struct SUrfdPeers1
|
||||
{
|
||||
std::time_t timestamp;
|
||||
unsigned int sequence;
|
||||
std::list<UrfdPeerTuple> list;
|
||||
|
||||
MSGPACK_DEFINE(timestamp, sequence, list)
|
||||
};
|
||||
|
||||
/* CLIENTS */
|
||||
using UrfdClientTuple = std::tuple<std::string, std::string, char, std::time_t, std::time_t>;
|
||||
enum class EUrfdClientFields { Callsign, Ip, Module, ConnectTime, LastHeardTime };
|
||||
struct SUrfdClients1
|
||||
{
|
||||
std::time_t timestamp;
|
||||
unsigned int sequence;
|
||||
std::list<UrfdClientTuple> list;
|
||||
|
||||
MSGPACK_DEFINE(timestamp, sequence, list)
|
||||
};
|
||||
|
||||
/* USERS */
|
||||
using UrfdUserTuple = std::tuple<std::string, std::string, char, std::string, std::time_t>;
|
||||
enum class EUrfdUserFields { Callsign, ViaNode, OnModule, ViaPeer, LastHeardTime };
|
||||
struct SUrfdUsers1
|
||||
{
|
||||
std::time_t timestamp;
|
||||
unsigned int sequence;
|
||||
std::list<UrfdUserTuple> list;
|
||||
|
||||
MSGPACK_DEFINE(timestamp, sequence, list)
|
||||
};
|
||||
|
||||
/* CONFIGURATION */
|
||||
// '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 SUrfdConfig1
|
||||
{
|
||||
std::time_t timestamp;
|
||||
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, tcmods, url, email, sponsor, country, version, almod, ysffreq, refid, g3enabled, port, description)
|
||||
};
|
||||
Reference in new issue
Block a user