Browse Source

partial migration to xlx-type interlink

master
Tom Early 12 months ago
parent
commit
bb448a1922
  1. 23
      callsignlist.cpp
  2. 15
      callsignlist.h
  3. 108
      callsignlistitem.cpp
  4. 15
      callsignlistitem.h
  5. 76
      gatekeeper.cpp
  6. 2
      gatekeeper.h
  7. 180
      m17protocol.cpp
  8. 9
      m17protocol.h
  9. 35
      main.cpp
  10. 2
      main.h
  11. 30
      packet.cpp
  12. 30
      packet.h
  13. 12
      peercallsignlist.cpp
  14. 51
      rconfig

23
callsignlist.cpp

@ -63,21 +63,21 @@ bool CCallsignList::LoadFromFile(const char *filename)
char *szt = TrimWhiteSpaces(sz);
// crack it
if ( (::strlen(szt) > 0) && (szt[0] != '#') )
if ( (strlen(szt) > 0) && (szt[0] != '#') )
{
// 1st token is callsign
if ( (szt = ::strtok(szt, " ,\t")) != nullptr )
if ( (szt = strtok(szt, " ,\t")) != nullptr )
{
CCallsign callsign(szt);
CCallsign callsign(ToUpper(szt));
// 2nd token is modules list
szt = ::strtok(nullptr, " ,\t");
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));
m_Callsigns.push_back(CCallsignListItem(callsign, CIp(), ToUpper(szt)));
}
}
}
@ -162,7 +162,7 @@ bool CCallsignList::IsCallsignListed(const CCallsign &callsign, char module) con
return false;
}
bool CCallsignList::IsCallsignListed(const CCallsign &callsign, char *modules) const
bool CCallsignList::IsCallsignListed(const CCallsign &callsign, const CIp &ip, const char *modules) const
{
for ( const auto &item : m_Callsigns )
{
@ -229,3 +229,14 @@ bool CCallsignList::GetLastModTime(time_t *time)
}
return ok;
}
char *CCallsignList::ToUpper(char *str)
{
constexpr auto diff = 'a' - 'A';
for (char *p=str; *p; p++)
{
if (*p >= 'a' && *p <= 'z')
*p -= diff;
}
return str;
}

15
callsignlist.h

@ -38,8 +38,8 @@ public:
virtual ~CCallsignList() {}
// locks
void Lock(void) { m_Mutex.lock(); }
void Unlock(void) { m_Mutex.unlock(); }
void Lock(void) { m_Mutex.lock(); }
void Unlock(void) { m_Mutex.unlock(); }
// file io
virtual bool LoadFromFile(const char *);
@ -49,8 +49,8 @@ public:
// compare
bool IsCallsignListedWithWildcard(const CCallsign &) const;
bool IsCallsignListedWithWildcard(const CCallsign &, char) const;
bool IsCallsignListed(const CCallsign &, char) const;
bool IsCallsignListed(const CCallsign &, char*) const;
bool IsCallsignListed(const CCallsign &, const char) const;
bool IsCallsignListed(const CCallsign &, const CIp &ip, const char*) const;
// pass-thru
bool empty() const { return m_Callsigns.empty(); }
@ -63,10 +63,11 @@ public:
protected:
bool GetLastModTime(time_t *);
char *TrimWhiteSpaces(char *);
char *ToUpper(char *str);
// data
std::mutex m_Mutex;
const char * m_Filename;
time_t m_LastModTime;
std::mutex m_Mutex;
const char *m_Filename;
time_t m_LastModTime;
std::list<CCallsignListItem> m_Callsigns;
};

108
callsignlistitem.cpp

@ -30,37 +30,46 @@
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CCallsignListItem::CCallsignListItem()
{
::memset(m_Modules, 0, sizeof(m_Modules));
::memset(m_szUrl, 0, sizeof(m_szUrl));
}
CCallsignListItem::CCallsignListItem() {}
CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const CIp &ip, const char *modules)
{
m_Callsign = callsign;
::memset(m_szUrl, 0, sizeof(m_szUrl));
m_Ip = ip;
m_Ip.SetPort(M17_PORT);
m_Mods.clear();
if ( modules != nullptr )
{
::memset(m_Modules, 0, sizeof(m_Modules));
if ( modules[0] == '*' )
{
for ( char i = 0; i < NB_OF_MODULES; i++ )
{
m_Modules[i] = 'A' + i;
m_Mods.append(1, 'A' + i);
}
}
else
{
int n = MIN((int)::strlen(modules), sizeof(m_Modules)-1);
int j = 0;
for ( int i = 0; i < n; i++ )
for (const char *p=modules; *p; p++)
{
if ( (modules[i] - 'A') < NB_OF_MODULES )
// duplicates not allowed!
if (m_Mods.npos == (m_Mods.find(*p)))
{
int i = *p - 'A';
// don't add mods that aren't configured
if (i >= 0 && i < NB_OF_MODULES)
{
m_Mods.append(1, *p);
}
else
{
std::cerr << "Peer module " << *p << " is not configured!" << std::endl;
}
}
else
{
m_Modules[j++] = modules[i];
std::cout << "Warning: Module " << *p << " is listed multiple times!" << std::endl;
}
}
}
}
@ -68,40 +77,15 @@ CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const CIp &ip, c
CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const char *url, const char *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] == '*' )
{
for ( char i = 0; i < NB_OF_MODULES; i++ )
{
m_Modules[i] = 'A' + i;
}
}
else
{
int n = MIN((int)::strlen(modules), sizeof(m_Modules)-1);
int j = 0;
for ( int i = 0; i < n; i++ )
{
if ( (modules[i] - 'A') < NB_OF_MODULES )
{
m_Modules[j++] = modules[i];
}
}
}
}
CIp ip(url, M17_PORT);
CCallsignListItem(callsign, ip, modules);
}
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));
m_Mods.assign(item.m_Mods);
}
@ -120,28 +104,34 @@ bool CCallsignListItem::HasSameCallsignWithWildcard(const CCallsign &callsign) c
bool CCallsignListItem::HasModuleListed(char module) const
{
return (::strchr(m_Modules, (int)module) != nullptr);
return m_Mods.npos != m_Mods.find(module);
}
bool CCallsignListItem::HasSameIp(const CIp &ip)
{
return ip == m_Ip;
}
bool CCallsignListItem::CheckListedModules(char *Modules) const
bool CCallsignListItem::CheckListedModules(const char *mods) const
{
bool listed = false;
if (mods == nullptr)
return false;
if ( Modules != nullptr )
// make sure every mods character is matched in m_Mods
const auto count = m_Mods.size();
bool found[count] = { false };
for (auto p=mods; *p; p++)
{
// 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);
auto pos = m_Mods.find(*p);
if (pos == m_Mods.npos)
return false;
else
found[pos] = true;
}
for (auto i=0; i<count; i++)
{
if (! found[i])
return false;
}
return listed;
return true;
}

15
callsignlistitem.h

@ -49,21 +49,18 @@ public:
// compare
bool HasSameCallsign(const CCallsign &) const;
bool HasSameCallsignWithWildcard(const CCallsign &) const;
bool HasSameIp(const CIp &ip);
bool HasModuleListed(char) const;
bool CheckListedModules(char*) const;
bool CheckListedModules(const 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); }
const CCallsign &GetCallsign(void) const { return m_Callsign; }
const CIp &GetIp(void) const { return m_Ip; }
const std::string &GetModules(void) { return m_Mods; }
protected:
// data
CCallsign m_Callsign;
char m_szUrl[URL_MAXLEN+1];
CIp m_Ip;
char m_Modules[27];
std::string m_Mods;
};

76
gatekeeper.cpp

@ -79,11 +79,19 @@ void CGateKeeper::Close(void)
}
////////////////////////////////////////////////////////////////////////////////////////
// authorisations
// authorizations
bool CGateKeeper::MayLink(const CCallsign &callsign, const CIp &ip, int protocol, char *modules) const
{
bool ok = IsNodeListedOk(callsign, ip);
bool ok;
if (callsign.GetCS(4).compare("M17-"))
{
ok = IsNodeListedOk(callsign, ip);
}
else
{
ok = IsPeerListedOk(callsign, ip, modules);
}
if ( !ok )
{
@ -166,46 +174,24 @@ bool CGateKeeper::IsNodeListedOk(const CCallsign &callsign, const CIp &ip, char
}
// bool CGateKeeper::IsPeerListedOk(const CCallsign &callsign, const CIp &ip, char module) const
// {
// bool ok = true;
// // first check IP
// // next, check callsign
// if ( ok )
// {
// // look for an exact match in the list
// const_cast<CPeerCallsignList &>(m_PeerList).Lock();
// if ( !m_PeerList.empty() )
// {
// ok = m_PeerList.IsCallsignListed(callsign, module);
// }
// const_cast<CPeerCallsignList &>(m_PeerList).Unlock();
// }
// // done
// return ok;
// }
// bool CGateKeeper::IsPeerListedOk(const CCallsign &callsign, const CIp &ip, char *modules) const
// {
// bool ok = true;
// // first check IP
// // next, check callsign
// if ( ok )
// {
// // look for an exact match in the list
// const_cast<CPeerCallsignList &>(m_PeerList).Lock();
// if ( !m_PeerList.empty() )
// {
// ok = m_PeerList.IsCallsignListed(callsign, modules);
// }
// const_cast<CPeerCallsignList &>(m_PeerList).Unlock();
// }
// // done
// return ok;
// }
bool CGateKeeper::IsPeerListedOk(const CCallsign &callsign, const CIp &ip, const char *modules) const
{
bool ok = true;
// first check IP
// next, check callsign
if ( ok )
{
// look for an exact match in the list
const_cast<CPeerCallsignList &>(m_PeerList).Lock();
if ( !m_PeerList.empty() )
{
ok = m_PeerList.IsCallsignListed(callsign, ip, modules);
}
const_cast<CPeerCallsignList &>(m_PeerList).Unlock();
}
// done
return ok;
}

2
gatekeeper.h

@ -61,7 +61,7 @@ protected:
// 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 IsPeerListedOk(const CCallsign &, const CIp &, const char *) const;
protected:
// data

180
m17protocol.cpp

@ -56,6 +56,7 @@ void CM17Protocol::Task(void)
CIp ip;
CCallsign cs;
char mod;
char mods[27];
std::unique_ptr<CPacket> pack;
// any incoming packet ?
@ -70,8 +71,9 @@ void CM17Protocol::Task(void)
#endif
//if (len > 0) std::cout << "Received " << len << " bytes from " << ip << std::endl;
switch (len) {
case sizeof(AM17Frame):
if ( IsValidPacket(buf, pack) )
case sizeof(SM17Frame): // a packet from a client
case sizeof(SRefM17Frame): // a packet from a peer
if ( IsValidPacket(buf, (sizeof(SM17Frame) == len) ? false : true, pack) )
{
if (pack->GetDestCallsign().HasSameCallsign(g_Reflector.GetCallsign()))
{ // only if the packet has the destination set properly!
@ -88,6 +90,35 @@ void CM17Protocol::Task(void)
}
}
break;
case sizeof(SInterConnect):
if (IsValidInterlinkConnect(buf, cs, mods))
{
std::cout << "CONN packet for modules " << mods << " from " << cs << " at " << ip << std::endl;
// callsign authorized?
if ( g_GateKeeper.MayLink(cs, ip, PROTOCOL_M17, mods) )
{
// acknowledge the request
EncodeInterlinkAckPacket(buf, mods);
Send(buf, sizeof(SInterConnect), ip);
}
else
{
// deny the request
EncodeInterlinkNackPacket(buf);
Send(buf, 10, ip);
}
}
else if (IsVaildInterlinkAcknowledge(buf, cs, mods))
{
}
else
{
}
case 11:
if ( IsValidConnect(buf, cs, &mod) )
{
@ -99,47 +130,13 @@ void CM17Protocol::Task(void)
// valid module ?
if ( g_Reflector.IsValidModule(mod) )
{
// is this an ack for a link request?
CPeerCallsignList *list = g_GateKeeper.GetPeerList();
CCallsignListItem *item = list->FindListItem(cs);
if ( item != nullptr && cs.GetModule() == item->GetModules()[1] && mod == item->GetModules()[0] )
{
std::cout << "ACK packet for module " << mod << " from " << cs << " at " << ip << std::endl;
// already connected ?
CPeers *peers = g_Reflector.GetPeers();
if ( nullptr == peers->FindPeer(cs, ip, PROTOCOL_M17) )
{
// create the new peer
// this also create one client per module
// append the peer to reflector peer list
// this also add all new clients to reflector client list
peers->AddPeer(std::make_shared<CM17Peer>(cs, ip, std::string(1, mod).c_str()));
}
g_Reflector.ReleasePeers();
}
else // this is a link request, but from who?
{
// is this a request from another M17 reflector?
if (0 == cs.GetCS(4).compare("M17-")) {
// Yes, then it needs a special acknowledgement
std::cout << "Link request from peer " << cs << "@" << ip << " to module " << mod << std::endl;
char modules[3] = { 0 };
modules[0] = mod;
modules[1] = cs.GetModule();
EncodeConnectPacket(buf, modules);
Send(buf, 11, ip);
} else {
// acknowledge a normal request from a repeater/hot-spot/mvoice
EncodeConnectAckPacket(buf);
Send(buf, 4, ip);
}
// create the client and append
g_Reflector.GetClients()->AddClient(std::make_shared<CM17Client>(cs, ip, mod));
g_Reflector.ReleaseClients();
}
g_GateKeeper.ReleasePeerList();
// acknowledge a normal request from a repeater/hot-spot/mvoice
EncodeConnectAckPacket(buf);
Send(buf, 4, ip);
// create the client and append
g_Reflector.GetClients()->AddClient(std::make_shared<CM17Client>(cs, ip, mod));
g_Reflector.ReleaseClients();
}
else
{
@ -187,6 +184,10 @@ void CM17Protocol::Task(void)
clients->RemoveClient(client);
}
g_Reflector.ReleaseClients();
}
else if ( IsValidNAcknowledge(buf, cs))
{
}
break;
default:
@ -241,10 +242,23 @@ void CM17Protocol::HandleQueue(void)
// is this client busy ?
if ( !client->IsAMaster() && (client->GetReflectorModule() == packet->GetDestModule()) )
{
// packet->GetFrame().lich.addr_dst won't be correct after this.
client->GetCallsign().CodeOut(packet->GetFrame().lich.addr_dst); // set the destination
packet->SetCRC(crc.CalcCRC(packet->GetFrame().magic, sizeof(AM17Frame) - 2)); // recalculate the crc
Send(packet->GetFrame().magic, sizeof(AM17Frame), client->GetIp());
auto cs = client->GetCallsign();
auto comp = cs.GetCS(4).compare("M17-");
if (comp) // the client is not a reflector
{
cs.CodeOut(packet->GetFrame().frame.lich.addr_dst);
packet->SetCRC(crc.CalcCRC(packet->GetFrame().frame.magic, sizeof(SM17Frame) - 2));
Send(packet->GetFrame().frame.magic, sizeof(SM17Frame), client->GetIp());
}
else if (! packet->GetRelay())// the client is a reflector and the packet hasn't yet been relayed
{
cs.CodeOut(packet->GetFrame().frame.lich.addr_dst); // set the destination
packet->SetCRC(crc.CalcCRC(packet->GetFrame().frame.magic, sizeof(SM17Frame) - 2)); // recalculate the crc
packet->SetRelay(true); // make sure the destination reflector doesn't send it to other reflectors
Send(packet->GetFrame().frame.magic, sizeof(SRefM17Frame), client->GetIp());
packet->SetRelay(false); // reset for the next client;
}
}
}
g_Reflector.ReleaseClients();
@ -359,21 +373,17 @@ void CM17Protocol::HandlePeerLinks(void)
// check if all ours peers listed by gatekeeper are connected
// if not, connect or reconnect
uint8_t connect[11];
uint8_t connect[sizeof(SInterConnect)];
for ( auto it=list->begin(); it!=list->end(); it++ )
{
if ( !(*it).GetCallsign().HasSameCallsignWithWildcard(CCallsign("M17*")) )
continue;
if ( strlen((*it).GetModules()) != 2 )
if ( !(*it).GetCallsign().HasSameCallsignWithWildcard(CCallsign("M17-*")) )
continue;
if ( nullptr == peers->FindPeer((*it).GetCallsign(), PROTOCOL_M17) )
{
// resolve again peer's IP in case it's a dynamic IP
(*it).ResolveIp();
// send connect packet to re-initiate peer link
EncodeConnectPacket(connect, (*it).GetModules());
EncodeInterlinkConnectPacket(connect, (*it).GetModules());
Send(connect, 11, (*it).GetIp(), M17_PORT);
std::cout << "Sent connect packet to M17 peer " << (*it).GetCallsign() << " @ " << (*it).GetIp() << " for module " << (*it).GetModules()[1] << " (module " << (*it).GetModules()[0] << ")" << std::endl;
std::cout << "Sent connect packet to M17 peer " << (*it).GetCallsign() << " @ " << (*it).GetIp() << " for module(s) " << (*it).GetModules() << std::endl;
}
}
@ -472,12 +482,12 @@ bool CM17Protocol::IsValidKeepAlive(const uint8_t *buf, CCallsign &cs)
return false;
}
bool CM17Protocol::IsValidPacket(const uint8_t *buf, std::unique_ptr<CPacket> &packet)
bool CM17Protocol::IsValidPacket(const uint8_t *buf, bool is_internal, std::unique_ptr<CPacket> &packet)
{
if (0 == memcmp(buf, "M17 ", 4)) // we tested the size before we got here
{
// create packet
packet = std::unique_ptr<CPacket>(new CPacket(buf));
packet = std::unique_ptr<CPacket>(new CPacket(buf, is_internal));
// check validity of packet
if ( packet->GetSourceCallsign().IsValid() )
{ // looks like a valid source
@ -487,6 +497,39 @@ bool CM17Protocol::IsValidPacket(const uint8_t *buf, std::unique_ptr<CPacket> &p
return false;
}
bool CM17Protocol::IsValidInterlinkConnect(const uint8_t *buf, CCallsign &cs, char *mods)
{
if (0 == memcmp(buf, "CONN", 4))
{
cs.CodeIn(buf + 4);
if (cs.GetCS(4).compare("M17-"))
{
std::cout << "Link request from '" << cs << "' denied" << std::endl;
return false;
}
}
strcpy(mods, (const char *)buf+10);
for (unsigned i=0; i<strlen(mods); i++)
{
if (! IsLetter(mods[i]))
{
std::cout << "Illegal module specified in '" << mods << "'" << std::endl;
return false;
}
}
return true;
}
bool CM17Protocol::IsVaildInterlinkAcknowledge(const uint8_t *buf, CCallsign &cs, char *mods)
{
}
bool CM17Protocol::IsValidNAcknowledge(const uint8_t *buf, CCallsign &cs)
{
}
////////////////////////////////////////////////////////////////////////////////////////
// packet encoding helpers
@ -497,13 +540,13 @@ void CM17Protocol::EncodeKeepAlivePacket(uint8_t *buf)
cs.CodeOut(buf + 4);
}
void CM17Protocol::EncodeConnectPacket(uint8_t *buf, const char *Modules)
void CM17Protocol::EncodeInterlinkConnectPacket(uint8_t *buf, const std::string &mods)
{
memset(buf, 0, sizeof(SInterConnect));
memcpy(buf, "CONN", 4);
CCallsign cs(GetReflectorCallsign());
cs.SetModule(Modules[0]);
cs.CodeOut(buf + 4);
buf[10] = Modules[1];
memcpy(buf + 10, mods.c_str(), mods.size());
}
void CM17Protocol::EncodeConnectAckPacket(uint8_t *buf)
@ -511,6 +554,23 @@ void CM17Protocol::EncodeConnectAckPacket(uint8_t *buf)
memcpy(buf, "ACKN", 4);
}
void CM17Protocol::EncodeInterlinkAckPacket(uint8_t *buf, const char *mods)
{
memcpy(buf, "ACKN", 4);
CCallsign cs(GetReflectorCallsign());
cs.CodeOut(buf+4);
memset(buf+10, 0, 27);
for (int i=0; i<26 && mods[i]; i++)
buf[i+10] = mods[i];
}
void CM17Protocol::EncodeInterlinkNackPacket(uint8_t *buf)
{
memcpy(buf, "NACK", 4);
CCallsign cs(GetReflectorCallsign());
cs.CodeOut(buf+4);
}
void CM17Protocol::EncodeConnectNackPacket(uint8_t *buf)
{
memcpy(buf, "NACK", 4);

9
m17protocol.h

@ -54,15 +54,20 @@ protected:
bool IsValidConnect(const uint8_t *, CCallsign &, char *);
bool IsValidDisconnect(const uint8_t *, CCallsign &);
bool IsValidKeepAlive(const uint8_t *, CCallsign &);
bool IsValidPacket(const uint8_t *, std::unique_ptr<CPacket> &);
bool IsValidPacket(const uint8_t *, bool is_internal, std::unique_ptr<CPacket> &);
bool IsValidNAcknowledge(const uint8_t *, CCallsign &);
bool IsValidInterlinkConnect(const uint8_t *, CCallsign &, char *);
bool IsVaildInterlinkAcknowledge(const uint8_t *, CCallsign &, char *);
// packet encoding helpers
void EncodeKeepAlivePacket(uint8_t *);
void EncodeConnectPacket(uint8_t *, const char *);
void EncodeConnectAckPacket(uint8_t *);
void EncodeConnectNackPacket(uint8_t *);
void EncodeDisconnectPacket(uint8_t *, char);
void EncodeDisconnectedPacket(uint8_t *);
void EncodeInterlinkConnectPacket(uint8_t *, const std::string &);
void EncodeInterlinkAckPacket(uint8_t *, const char *);
void EncodeInterlinkNackPacket(uint8_t *);
protected:
// time

35
main.cpp

@ -22,29 +22,47 @@
// with this software. If not, see <http://www.gnu.org/licenses/>.
// ----------------------------------------------------------------------------
#include "main.h"
#include "reflector.h"
#include <regex>
#include <sys/stat.h>
#include "main.h"
#include "reflector.h"
////////////////////////////////////////////////////////////////////////////////////////
// global objects
CReflector g_Reflector;
////////////////////////////////////////////////////////////////////////////////////////
// function declaration
#ifndef CALLSIGN
#define CALLSIGN "CHANGME"
#endif
#ifndef LISTEN_IPV4
#define LISTEN_IPV4 "none"
#endif
#ifndef LISTEN_IPV6
#define LISTEN_IPV6 "none"
#endif
int main()
{
const std::string cs(CALLSIGN);
if ((cs.size() > 7) || (cs.compare(0, 3, "M17")))
auto IPv4RegEx = std::regex("^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\\.){3,3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]){1,1}$", std::regex::extended);
auto IPv6RegEx = std::regex("^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}(:[0-9a-fA-F]{1,4}){1,1}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|([0-9a-fA-F]{1,4}:){1,1}(:[0-9a-fA-F]{1,4}){1,6}|:((:[0-9a-fA-F]{1,4}){1,7}|:))$", std::regex::extended);
auto RefRegEx = std::regex("^M17-([A-Z0-9]){3,3}$", std::regex::extended);
if (! std::regex_match(CALLSIGN, RefRegEx))
{
std::cerr << "Malformed reflector callsign: '" << cs << "', aborting!" << std::endl;
std::cerr << "Malformed reflector callsign: '" << CALLSIGN << "', aborting!" << std::endl;
return EXIT_FAILURE;
}
if (! std::regex_match(LISTEN_IPV4, IPv4RegEx) && ! std::regex_match(LISTEN_IPV6, IPv6RegEx))
{
std::cerr << "No valid IP bind address was specifed:" << std::endl;
std::cerr << "IPv4='" << LISTEN_IPV4 << "' IPV6='" << LISTEN_IPV6 << "'" << std::endl;
return EXIT_FAILURE;
}
const std::string cs(CALLSIGN);
// remove pidfile
remove(PIDFILE_PATH);
@ -61,7 +79,6 @@ int main()
std::cout << "Error starting reflector" << std::endl;
return EXIT_FAILURE;
}
std::cout << "Reflector " << g_Reflector.GetCallsign() << " started and listening" << std::endl;
// write new pid file

2
main.h

@ -49,7 +49,7 @@
// version -----------------------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 2
#define VERSION_MINOR 3
#define VERSION_REVISION 0
// global ------------------------------------------------------

30
packet.cpp

@ -21,11 +21,13 @@
#include "packet.h"
CPacket::CPacket(const uint8_t *buf)
CPacket::CPacket(const uint8_t *buf, bool is_internal)
{
memcpy(m17.magic, buf, sizeof(AM17Frame));
destination.CodeIn(m17.lich.addr_dst);
source.CodeIn(m17.lich.addr_src);
memcpy(m17.frame.magic, buf, is_internal ? sizeof(SRefM17Frame) : sizeof(SM17Frame));
if (! is_internal)
m17.relayed = false;
destination.CodeIn(m17.frame.lich.addr_dst);
source.CodeIn(m17.frame.lich.addr_src);
}
const CCallsign &CPacket::GetDestCallsign() const
@ -45,17 +47,27 @@ const CCallsign &CPacket::GetSourceCallsign() const
uint16_t CPacket::GetStreamId() const
{
return ntohs(m17.streamid);
return ntohs(m17.frame.streamid);
}
uint16_t CPacket::GetCRC() const
{
return ntohs(m17.crc);
return ntohs(m17.frame.crc);
}
void CPacket::SetCRC(uint16_t crc)
{
m17.crc = htons(crc);
m17.frame.crc = htons(crc);
}
void CPacket::SetRelay(bool state)
{
m17.relayed = state;
}
bool CPacket::GetRelay() const
{
return m17.relayed;
}
std::unique_ptr<CPacket> CPacket::Duplicate(void) const
@ -65,10 +77,10 @@ std::unique_ptr<CPacket> CPacket::Duplicate(void) const
bool CPacket::IsLastPacket() const
{
return (0x8000u & m17.framenumber == 0x8000u);
return (0x8000u & m17.frame.framenumber == 0x8000u);
}
AM17Frame &CPacket::GetFrame()
SRefM17Frame &CPacket::GetFrame()
{
return m17;
}

30
packet.h

@ -30,39 +30,53 @@
// M17 Packets
//all structures must be big endian on the wire, so you'll want htonl (man byteorder 3) and such.
using AM17Lich = struct __attribute__((__packed__)) _LICH {
using SM17Lich = struct __attribute__((__packed__)) _LICH {
uint8_t addr_dst[6];
uint8_t addr_src[6];
uint16_t frametype; //frametype flag field per the M17 spec
uint8_t nonce[14]; //bytes for the nonce
}; // 6 + 6 + 2 + 14 = 28 bytes = 224 bits
}; // 6 + 6 + 2 + 14 = 28 bytes
//without SYNC or other parts
using AM17Frame = struct __attribute__((__packed__)) _ip_frame {
using SM17Frame = struct __attribute__((__packed__)) _ip_frame {
uint8_t magic[4];
uint16_t streamid;
AM17Lich lich;
SM17Lich lich;
uint16_t framenumber;
uint8_t payload[16];
uint16_t crc; //16 bit CRC
}; // 4 + 2 + 28 + 2 + 16 + 2 = 54 bytes = 432 bits
}; // 4 + 2 + 28 + 2 + 16 + 2 = 54 bytes
// includes extra bool (1 byte) for enforcing one-hop policy
using SRefM17Frame = struct __attribute__((__packed__)) _ip_frame {
SM17Frame frame;
bool relayed;
}; // 4 + 2 + 28 + 2 + 16 + 2 + 1 = 55 bytes
using SInterConnect = struct __attribute__((__packed__)) interconnect_tag {
uint8_t magic[4];
uint8_t fromcs[6];
uint8_t mods[27];
}; // 37 bytes
class CPacket
{
public:
CPacket() {}
CPacket(const uint8_t *buf);
CPacket(const uint8_t *buf, bool is_internal);
const CCallsign &GetDestCallsign() const;
char GetDestModule() const;
const CCallsign &GetSourceCallsign() const;
uint16_t GetStreamId() const;
uint16_t GetCRC() const;
void SetCRC(uint16_t crc);
void SetRelay(bool state);
bool GetRelay() const;
std::unique_ptr<CPacket> Duplicate(void) const;
bool IsLastPacket() const;
AM17Frame &GetFrame();
SRefM17Frame &GetFrame();
private:
CCallsign destination, source;
AM17Frame m17;
SRefM17Frame m17;
};

12
peercallsignlist.cpp

@ -50,21 +50,21 @@ bool CPeerCallsignList::LoadFromFile(const char *filename)
char *szt = TrimWhiteSpaces(sz);
// crack it
if ( (::strlen(szt) > 0) && (szt[0] != '#') )
if ( (strlen(szt) > 0) && (szt[0] != '#') )
{
// 1st token is callsign
if ( (szt = ::strtok(szt, " ,\t")) != nullptr )
if ( (szt = strtok(szt, " ,\t")) != nullptr )
{
CCallsign callsign(szt);
CCallsign callsign(ToUpper(szt));
// 2nd token is ip
char *szip;
if ( (szip = ::strtok(nullptr, " ,\t")) != nullptr )
if ( (szip = strtok(nullptr, " ,\t")) != nullptr )
{
// 3rd token is modules list
if ( (szt = ::strtok(nullptr, " ,\t")) != nullptr )
if ( (szt = strtok(nullptr, " ,\t")) != nullptr )
{
// and load
m_Callsigns.push_back(CCallsignListItem(callsign, szip, szt));
m_Callsigns.push_back(CCallsignListItem(callsign, szip, ToUpper(szt)));
}
}
}

51
rconfig

@ -158,35 +158,60 @@ while [[ "$key" != q* ]]
do
clear
echo
echo " Reflector Configuration, Version #200821"
echo " Reflector Configuration, Version #201101"
echo
echo " ******* REFLECTOR ********"
echo " ******* REFLECTOR **********"
echo -n "cs : Reflector Callsign = "; EvaluateVar callsign{,_d}
echo -n "nm : Number of Modules = "; EvaluateVar nummod{,_d}
echo " ******* ADDRESSES ********"
echo " ******* IP ADDRESSES ********"
echo " You must set at least one of these addresses!"
echo " Usually, IPv4 is 0.0.0.0 and/or IPv6 is ::"
echo " but might be different in special curcumstances"
echo " where you cannot bind to the 'any' address."
echo -n "i4 : IPv4 Listen Address = "; EvaluateVar ip4addr{,_d}
echo -n "i6 : IPv6 Listen Address = "; EvaluateVar ip6addr{,_d}
echo " ******* DEBUGGING ********"
echo " ******* DEBUGGING ***********"
echo -n "db : Debugging Support = "; EvaluateVar dbsupport{,_d}
echo
if [[ "$callsign" == M17-* ]]; then
if [[ "$callsign" == M17-* ]] && ( [ ! -z ${ip4addr+x} ] || [ ! -z ${ip6addr+x} ] ); then
echo "w : Write configuration files (overwrites any existing files) and quit"
fi
echo "q : Quit without saving"
echo "u : Unset the value of <key> (revert to the default value)."
echo
read -p "Please input <key> <value> - omit value to toggle a true/false : " key value garbage
if [[ "$key" == cs* && ${value^^} == M17-* ]]; then
callsign="${value^^}"
callsign="${callsign:0:7}"
if [[ "$key" == cs* ]]; then
if [[ "${value^^}" =~ ^M17-([0-9A-Z]){3,3}$ ]]; then
callsign="${value^^}"
else
clear
echo "${value^^} is not a valid reflector name"
read -p "<Enter to continue: "
fi
elif [[ "$key" == nm* ]]; then nummod="$value"
elif [[ "$key" == i4* ]]; then ip4addr="$value"
elif [[ "$key" == i6* ]]; then ip6addr="$value"
elif [[ "$key" == i4* ]]; then
if [[ "$value" =~ ^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3,3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9]){1,1}$ ]]; then
ip4addr="$value"
else
clear
echo "$value is not a valid IPv4 address!"
read -p "<Enter> to continue: " garbage
fi
elif [[ "$key" == i6* ]]; then
if [[ "${value^^}" =~ ^(([0-9A-F]{1,4}:){7,7}[0-9A-F]{1,4}|([0-9A-F]{1,4}:){1,7}:|([0-9A-F]{1,4}:){1,6}(:[0-9A-F]{1,4}){1,1}|([0-9A-F]{1,4}:){1,5}(:[0-9A-F]{1,4}){1,2}|([0-9A-F]{1,4}:){1,4}(:[0-9A-F]{1,4}){1,3}|([0-9A-F]{1,4}:){1,3}(:[0-9A-F]{1,4}){1,4}|([0-9A-F]{1,4}:){1,2}(:[0-9A-F]{1,4}){1,5}|([0-9A-F]{1,4}:){1,1}(:[0-9A-F]{1,4}){1,6}|:((:[0-9A-F]{1,4}){1,7}|:))$ ]]; then
ip6addr="$value"
else
clear
echo "$value is not a valid IPv6 address!"
read -p "<Enter> to continue: " garbage
fi
elif [[ "$key" == db* ]]; then SetBooleanValue dbsupport "$value"
elif [[ "$key" == w* ]]; then
WriteCFGFiles
ListCFGFiles
exit 0
if [[ "$callsign" == M17-* ]] && ( [ ! -z ${ip4addr+x} ] || [ ! -z ${ip6addr+x} ] ); then
WriteCFGFiles
ListCFGFiles
exit 0
fi
elif [[ "$key" == u* ]]; then
if [[ "$value" == cs* ]]; then unset callsign
elif [[ "$value" == nm* ]]; then unset nummod

Loading…
Cancel
Save