Browse Source

first commit

master
Tom Early 1 year ago
parent
commit
eab126739a
  1. 13
      .gitignore
  2. 78
      Makefile
  3. 327
      callsign.cpp
  4. 93
      callsign.h
  5. 231
      callsignlist.cpp
  6. 72
      callsignlist.h
  7. 147
      callsignlistitem.cpp
  8. 69
      callsignlistitem.h
  9. 105
      client.cpp
  10. 93
      client.h
  11. 247
      clients.cpp
  12. 77
      clients.h
  13. 211
      gatekeeper.cpp
  14. 75
      gatekeeper.h
  15. 296
      ip.cpp
  16. 75
      ip.h
  17. 47
      m17client.cpp
  18. 51
      m17client.h
  19. 69
      m17peer.cpp
  20. 52
      m17peer.h
  21. 500
      m17protocol.cpp
  22. 70
      m17protocol.h
  23. 79
      main.cpp
  24. 111
      main.h
  25. 46
      notification.cpp
  26. 60
      notification.h
  27. 64
      notificationqueue.h
  28. 96
      packet.h
  29. 62
      packetqueue.h
  30. 92
      packetstream.cpp
  31. 67
      packetstream.h
  32. 130
      peer.cpp
  33. 96
      peer.h
  34. 93
      peercallsignlist.cpp
  35. 51
      peercallsignlist.h
  36. 171
      peers.cpp
  37. 74
      peers.h
  38. 328
      protocol.cpp
  39. 112
      protocol.h
  40. 454
      reflector.cpp
  41. 123
      reflector.h
  42. 53
      timepoint.cpp
  43. 48
      timepoint.h
  44. 171
      udpsocket.cpp
  45. 75
      udpsocket.h
  46. 84
      user.cpp
  47. 55
      user.h
  48. 76
      users.cpp
  49. 54
      users.h
  50. 79
      version.cpp
  51. 60
      version.h

13
.gitignore

@ -0,0 +1,13 @@
*.o
*.d
.vscode
./*.blacklist
./*.whitelist
./*.interlink
./*.terminal
./*.service
configure.mk
configure.h
configure.sql
reflector.cfg
mrefd

78
Makefile

@ -0,0 +1,78 @@
# Copyright (c) 2020 by 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 2 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 <http://www.gnu.org/licenses/>.
# locations for the executibles and other files are set here
# NOTE: IF YOU CHANGE THESE, YOU WILL NEED TO UPDATE THE service.* FILES AND
# if you change these locations, make sure the sgs.service file is updated!
# you will also break hard coded paths in the dashboard file, index.php.
include configure.mk
# if you make changed in these two variable, you'll need to change things
# in the main.h file as well as the systemd service file.
BINDIR = /usr/local/bin
CFGDIR = /usr/local/etc
DATADIR = /var/lib/m17ref
CC = g++
ifeq ($(debug), true)
CFLAGS = -ggdb3 -W -c -std=c++11 -MMD -MD -c
else
CFLAGS = -c -W -std=c++11 -MMD -MD -c
endif
LDFLAGS=-pthread
SRCS = callsign.cpp callsignlist.cpp callsignlistitem.cpp client.cpp clients.cpp gatekeeper.cpp ip.cpp m17client.cpp m17peer.cpp m17protocol.cpp notification.cpp packetstream.cpp peer.cpp peers.cpp peercallsignlist.cpp protocol.cpp reflector.cpp timepoint.cpp udpsocket.cpp user.cpp users.cpp version.cpp main.cpp
OBJS = $(SRCS:.cpp=.o)
DEPS = $(SRCS:.cpp=.d)
EXE=mrefd
all : $(EXE)
$(EXE) : $(OBJS)
$(CC) $^ -o $@ $(LDFLAGS)
%.o : %.cpp
g++ $(CFLAGS) $< -o $@
clean :
$(RM) *.o *.d $(EXE)
-include $(DEPS)
install :
ln -s $(shell pwd)/$(EXE).blacklist $(CFGDIR)/$(EXE).blacklist
ln -s $(shell pwd)/$(EXE).whitelist $(CFGDIR)/$(EXE).whitelist
ln -s $(shell pwd)/$(EXE).interlink $(CFGDIR)/$(EXE).interlink
cp -f ../systemd/$(EXE).service /etc/systemd/system/
cp -f $(EXE) $(BINDIR)
mkdir -p $(DATADIR)
systemctl enable $(EXE).service
systemctl daemon-reload
systemctl start $(EXE)
uninstall :
rm -f $(CFGDIR)/$(EXE).blacklist
rm -f $(CFGDIR)/$(EXE).whitelist
rm -f $(CFGDIR)/$(EXE).interlink
systemctl stop $(EXE).service
rm -f $(CFGDIR)/dmrid.dat
systemctl disable $(EXE).service
rm -f /etc/systemd/system/$(EXE).service
systemctl daemon-reload

327
callsign.cpp

@ -0,0 +1,327 @@
//
// ccallsign.cpp
// m17ref
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/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 <string.h>
#include <cctype>
#include "callsign.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructors
CCallsign::CCallsign()
{
// blank all
::memset(m_Callsign, ' ', sizeof(m_Callsign));
::memset(m_Suffix, ' ', sizeof(m_Suffix));
m_Module = ' ';
}
CCallsign::CCallsign(const char *sz)
{
// blank all
::memset(m_Callsign, ' ', sizeof(m_Callsign));
::memset(m_Suffix, ' ', sizeof(m_Suffix));
m_Module = ' ';
// and populate
if ( ::strlen(sz) > 0 )
{
// callsign valid
::memcpy(m_Callsign, sz, MIN(strlen(sz), sizeof(m_Callsign)));
if ( strlen(sz) >= sizeof(m_Callsign) )
{
m_Module = sz[sizeof(m_Callsign)];
}
}
}
////////////////////////////////////////////////////////////////////////////////////////
// status
bool CCallsign::IsValid(void) const
{
bool valid = true;
int i;
// callsign
// first 3 chars are letter or number but cannot be all number
int iNum = 0;
for ( i = 0; i < 3; i++ )
{
valid &= IsLetter(m_Callsign[i]) || IsNumber(m_Callsign[i]);
if ( IsNumber(m_Callsign[i]) )
{
iNum++;
}
}
valid &= (iNum < 3);
// all remaining char are letter, number or space
for ( ; i < CALLSIGN_LEN; i++)
{
valid &= IsLetter(m_Callsign[i]) || IsNumber(m_Callsign[i]) || IsSpace(m_Callsign[i]);
}
// prefix
// all chars are number, uppercase or space
for ( i = 0; i < CALLSUFFIX_LEN; i++ )
{
valid &= IsLetter(m_Suffix[i]) || IsNumber(m_Suffix[i]) || IsSpace(m_Suffix[i]);
}
// module
// is an letter or space
valid &= IsLetter(m_Module) || IsSpace(m_Module);
// dmrid is not tested, as it can be nullptr
// if station does is not dmr registered
// done
return valid;
}
bool CCallsign::HasSuffix(void) const
{
bool has = false;
for ( int i = 0; (i < CALLSUFFIX_LEN) && ! has; i++ )
{
has = has && (m_Suffix[i] != ' ');
}
return has;
}
////////////////////////////////////////////////////////////////////////////////////////
// set
void CCallsign::DecodeCallsign(const uint8_t *in)
{
const char *m17_alphabet = M17CHARACTERS;
char cs[9] = { ' ' };
uint64_t coded = in[0];
for (int i=1; i<6; i++)
coded = (coded << 8) | in[i];
int index = 0;
while (coded) {
cs[index++] = m17_alphabet[coded % 40];
coded /= 40;
}
strncpy(m_Callsign, cs, 8);
m_Module = cs[8];
::memset(m_Suffix, ' ', sizeof(m_Suffix));
}
void CCallsign::SetCallsign(const char *sz)
{
// set callsign
::memset(m_Callsign, ' ', sizeof(m_Callsign));
m_Module = ' ';
::memcpy(m_Callsign, sz, MIN(strlen(sz), sizeof(m_Callsign)-1));
if ( strlen(sz) >= sizeof(m_Callsign) )
{
m_Module = sz[sizeof(m_Callsign)-1];
}
}
void CCallsign::SetCallsign(const uint8_t *buffer, int len)
{
// set callsign
::memset(m_Callsign, ' ', sizeof(m_Callsign));
m_Module = ' ';
::memcpy(m_Callsign, buffer, MIN(len, sizeof(m_Callsign)-1));
for ( unsigned i = 0; i < sizeof(m_Callsign); i++ )
{
if ( m_Callsign[i] == 0 )
{
m_Callsign[i] = ' ';
}
}
if ( (len >= (int)sizeof(m_Callsign)) && ((char)buffer[sizeof(m_Callsign)-1] != 0) )
{
m_Module = (char)buffer[sizeof(m_Callsign)-1];
}
}
void CCallsign::SetModule(char c)
{
m_Module = c;
}
void CCallsign::SetSuffix(const char *sz)
{
::memset(m_Suffix, ' ', sizeof(m_Suffix));
::memcpy(m_Suffix, sz, MIN(strlen(sz), sizeof(m_Suffix)));
}
void CCallsign::SetSuffix(const uint8_t *buffer, int len)
{
len = MIN(len, sizeof(m_Suffix));
::memset(m_Suffix, ' ', sizeof(m_Suffix));
::memcpy(m_Suffix, buffer, len);
}
////////////////////////////////////////////////////////////////////////////////////////
// modify
void CCallsign::PatchCallsign(int off, const uint8_t *patch, int len)
{
if ( off < CALLSIGN_LEN )
{
::memcpy(m_Callsign, patch, MIN(len, sizeof(m_Callsign) - off));
}
}
////////////////////////////////////////////////////////////////////////////////////////
// get
void CCallsign::GetCallsign(uint8_t *buffer) const
{
::memcpy(buffer, m_Callsign, sizeof(m_Callsign));
if ( HasModule() )
{
buffer[sizeof(m_Callsign)-1] = m_Module;
}
}
void CCallsign::GetCallsignString(char *sz) const
{
unsigned i;
for ( i = 0; (i < sizeof(m_Callsign)) && (m_Callsign[i] != ' '); i++ )
{
sz[i] = m_Callsign[i];
}
sz[i] = 0;
}
void CCallsign::GetSuffix(uint8_t *buffer) const
{
::memcpy(buffer, m_Suffix, sizeof(m_Suffix));
}
void CCallsign::EncodeCallsign(uint8_t *out) const
{
const char *alphabet = M17CHARACTERS;
uint64_t encoded = 0;
for( int i=0; i<9; i++)
{
encoded *= 40u;
const char *pos;
if (i)
pos = strchr(alphabet, m_Callsign[8-i]);
else
pos = strchr(alphabet, m_Module);
if (nullptr != pos)
encoded += pos - alphabet;
}
for (int i=0; i<6; i++) {
out[i] = (encoded >> (8*(5-i)) & 0xFFU);
}
}
////////////////////////////////////////////////////////////////////////////////////////
// compare
bool CCallsign::HasSameCallsign(const CCallsign &Callsign) const
{
return (::memcmp(m_Callsign, Callsign.m_Callsign, sizeof(m_Callsign)) == 0);
}
bool CCallsign::HasSameCallsignWithWildcard(const CCallsign &callsign) const
{
bool same = true;
bool done = false;
for ( unsigned i = 0; (i < sizeof(m_Callsign)) && same && !done; i++ )
{
if ( !(done = ((m_Callsign[i] == '*') || (callsign[i] == '*'))) )
{
same &= (m_Callsign[i] == callsign[i]);
}
}
return same;
}
bool CCallsign::HasLowerCallsign(const CCallsign &Callsign) const
{
return (::memcmp(m_Callsign, Callsign.m_Callsign, sizeof(m_Callsign)) < 0);
}
bool CCallsign::HasSameModule(const CCallsign &Callsign) const
{
return (m_Module == Callsign.m_Module);
}
////////////////////////////////////////////////////////////////////////////////////////
// operators
bool CCallsign::operator ==(const CCallsign &callsign) const
{
return ((::memcmp(callsign.m_Callsign, m_Callsign, sizeof(m_Callsign)) == 0) && (m_Module == callsign.m_Module)
&& (::memcmp(callsign.m_Suffix, m_Suffix, sizeof(m_Suffix)) == 0)
);
}
CCallsign::operator const char *() const
{
// empty
::memset(m_sz, 0, sizeof(m_sz));
// callsign
::memcpy(m_sz, m_Callsign, sizeof(m_Callsign));
// module
if ( HasModule() )
{
m_sz[sizeof(m_Callsign)] = m_Module;
}
// suffix
if ( HasSuffix() )
{
::strcat(m_sz, " / ");
::strncat(m_sz, m_Suffix, sizeof(m_Suffix));
}
// done
return m_sz;
}
////////////////////////////////////////////////////////////////////////////////////////
// helper
bool CCallsign::IsNumber(char c) const
{
return ((c >= '0') && (c <= '9'));
}
bool CCallsign::IsLetter(char c) const
{
return ((c >= 'A') && (c <= 'Z'));
}
bool CCallsign::IsSpace(char c) const
{
return (c == ' ');
}

93
callsign.h

@ -0,0 +1,93 @@
//
// ccallsign.h
// m17ref
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/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 "main.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
#define CALLSIGN_LEN 8
#define CALLSUFFIX_LEN 4
#define M17CHARACTERS " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-/."
////////////////////////////////////////////////////////////////////////////////////////
// class
class CCallsign
{
public:
// contructors
CCallsign();
CCallsign(const char *);
// status
bool IsValid(void) const;
bool HasSuffix(void) const;
bool HasModule(void) const { return m_Module != ' '; }
// set
void SetCallsign(const char *);
void SetCallsign(const uint8_t *, int);
void SetModule(char);
void SetSuffix(const char *);
void SetSuffix(const uint8_t *, int);
// modify
void PatchCallsign(int, const uint8_t *, int);
// get
void GetCallsign(uint8_t *) const;
void GetCallsignString(char *) const;
void GetSuffix(uint8_t *) const;
char GetModule(void) const { return m_Module; }
void EncodeCallsign(uint8_t *) const; // M17
void DecodeCallsign(const uint8_t *); // M17
// compare
bool HasSameCallsign(const CCallsign &) const;
bool HasSameCallsignWithWildcard(const CCallsign &) const;
bool HasLowerCallsign(const CCallsign &) const;
bool HasSameModule(const CCallsign &) const;
// operators
bool operator ==(const CCallsign &) const;
operator const char *() const;
protected:
// helper
bool IsNumber(char) const;
bool IsLetter(char) const;
bool IsSpace(char) const;
protected:
// data
char m_Callsign[CALLSIGN_LEN];
char m_Suffix[CALLSUFFIX_LEN];
char m_Module;
mutable char m_sz[CALLSIGN_LEN+CALLSUFFIX_LEN+5];
};

231
callsignlist.cpp

@ -0,0 +1,231 @@
//
// 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 <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "main.h"
#include "callsignlist.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CCallsignList::CCallsignList()
{
m_Filename = nullptr;
::memset(&m_LastModTime, 0, sizeof(time_t));
}
////////////////////////////////////////////////////////////////////////////////////////
// file io
bool CCallsignList::LoadFromFile(const char *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 = 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 != nullptr )
{
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 != nullptr )
{
struct stat fileStat;
if( ::stat(m_Filename, &fileStat) != -1 )
{
*time = fileStat.st_mtime;
ok = true;
}
}
return ok;
}

72
callsignlist.h

@ -0,0 +1,72 @@
//
// 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 "main.h"
#include "callsignlistitem.h"
////////////////////////////////////////////////////////////////////////////////////////
// class
class CCallsignList
{
public:
// constructor
CCallsignList();
// destructor
virtual ~CCallsignList() {}
// locks
void Lock(void) { m_Mutex.lock(); }
void Unlock(void) { m_Mutex.unlock(); }
// file io
virtual bool LoadFromFile(const char *);
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
std::mutex m_Mutex;
const char * m_Filename;
time_t m_LastModTime;
std::list<CCallsignListItem> m_Callsigns;
};

147
callsignlistitem.cpp

@ -0,0 +1,147 @@
//
// ccallsignlistitem.cpp
// m17ref
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/01/2016.
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
//
// ----------------------------------------------------------------------------
// 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 "main.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)
{
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] == '*' )
{
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];
}
}
}
}
}
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];
}
}
}
}
}
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;
}

69
callsignlistitem.h

@ -0,0 +1,69 @@
//
// 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 "main.h"
#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];
};

105
client.cpp

@ -0,0 +1,105 @@
//
// cclient.cpp
// m17ref
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/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 "main.h"
#include <string.h>
#include "client.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructors
CClient::CClient()
{
m_ReflectorModule = ' ';
m_ModuleMastered = ' ';
m_LastKeepaliveTime.Now();
m_ConnectTime = std::time(nullptr);
m_LastHeardTime = std::time(nullptr);
}
CClient::CClient(const CCallsign &callsign, const CIp &ip, char reflectorModule)
{
m_ReflectorModule = reflectorModule;
m_Callsign = callsign;
m_Ip = ip;
m_ModuleMastered = ' ';
m_LastKeepaliveTime.Now();
m_ConnectTime = std::time(nullptr);
m_LastHeardTime = std::time(nullptr);
}
CClient::CClient(const CClient &client)
{
m_Callsign = client.m_Callsign;
m_Ip = client.m_Ip;
m_ReflectorModule = client.m_ReflectorModule;
m_ModuleMastered = client.m_ModuleMastered;
m_LastKeepaliveTime = client.m_LastKeepaliveTime;
m_ConnectTime = client.m_ConnectTime;
m_LastHeardTime = client.m_LastHeardTime;
}
////////////////////////////////////////////////////////////////////////////////////////
// status
void CClient::Alive(void)
{
m_LastKeepaliveTime.Now();
}
////////////////////////////////////////////////////////////////////////////////////////
// operators
bool CClient::operator ==(const CClient &client) const
{
return ((client.m_Callsign == m_Callsign) &&
(client.m_Ip == m_Ip) &&
(client.m_ReflectorModule == m_ReflectorModule));
}
////////////////////////////////////////////////////////////////////////////////////////
// reporting
void CClient::WriteXml(std::ofstream &xmlFile)
{
xmlFile << "<NODE>" << std::endl;
xmlFile << "\t<Callsign>" << m_Callsign << "</Callsign>" << std::endl;
xmlFile << "\t<IP>" << m_Ip.GetAddress() << "</IP>" << std::endl;
xmlFile << "\t<LinkedModule>" << m_ReflectorModule << "</LinkedModule>" << std::endl;
xmlFile << "\t<Protocol>" << GetProtocolName() << "</Protocol>" << std::endl;
char mbstr[100];
if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_ConnectTime)))
{
xmlFile << "\t<ConnectTime>" << mbstr << "</ConnectTime>" << std::endl;
}
if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_LastHeardTime)))
{
xmlFile << "\t<LastHeardTime>" << mbstr << "</LastHeardTime>" << std::endl;
}
xmlFile << "</NODE>" << std::endl;
}

93
client.h

@ -0,0 +1,93 @@
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/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 "timepoint.h"
#include "ip.h"
#include "callsign.h"
////////////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////////////
// class
class CClient
{
public:
// constructors
CClient();
CClient(const CCallsign &, const CIp &, char);
CClient(const CClient &);
// destructor
virtual ~CClient() {};
// operators
bool operator ==(const CClient &) const;
// get
const CCallsign &GetCallsign(void) const { return m_Callsign; }
const CIp &GetIp(void) const { return m_Ip; }
bool HasModule(void) const { return m_Callsign.HasModule(); }
char GetModule(void) const { return m_Callsign.GetModule(); }
bool HasReflectorModule(void) const { return m_ReflectorModule != ' '; }
char GetReflectorModule(void) const { return m_ReflectorModule; }
// set
void SetModule(char c) { m_Callsign.SetModule(c); }
void SetReflectorModule(char c) { m_ReflectorModule = c; }
// identity
virtual int GetProtocol(void) const { return PROTOCOL_NONE; }
virtual const char *GetProtocolName(void) const { return "none"; }
virtual bool IsNode(void) const { return false; }
virtual bool IsPeer(void) const { return false; }
virtual bool IsDextraDongle(void) const { return false; }
virtual void SetDextraDongle(void) { }
// status
virtual void Alive(void);
virtual bool IsAlive(void) const { return false; }
virtual bool IsAMaster(void) const { return (m_ModuleMastered != ' '); }
virtual void SetMasterOfModule(char c) { m_ModuleMastered = c; }
virtual void NotAMaster(void) { m_ModuleMastered = ' '; }
virtual void Heard(void) { m_LastHeardTime = std::time(nullptr); }
// reporting
virtual void WriteXml(std::ofstream &);
protected:
// data
CCallsign m_Callsign;
CIp m_Ip;
// linked to
char m_ReflectorModule;
// status
char m_ModuleMastered;
CTimePoint m_LastKeepaliveTime;
std::time_t m_ConnectTime;
std::time_t m_LastHeardTime;
};

247
clients.cpp

@ -0,0 +1,247 @@
//
// cclients.cpp
// m17ref
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/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 "main.h"
#include "reflector.h"
#include "clients.h"
////////////////////////////////////////////////////////////////////////////////////////
// constructor
CClients::CClients()
{
}
////////////////////////////////////////////////////////////////////////////////////////
// destructors
CClients::~CClients()
{
m_Mutex.lock();
m_Clients.clear();
m_Mutex.unlock();
}
////////////////////////////////////////////////////////////////////////////////////////
// manage Clients
void CClients::AddClient(std::shared_ptr<CClient> client)
{
// first check if client already exists
for ( auto it=begin(); it!=end(); it++ )
{
if (*client == *(*it))
// if found, just do nothing
// so *client keep pointing on a valid object
// on function return
{
// delete new one
return;
}
}
// and append
m_Clients.push_back(client);
std::cout << "New client " << client->GetCallsign() << " at " << client->GetIp() << " added with protocol " << client->GetProtocolName();
if ( client->GetReflectorModule() != ' ' )
{
std::cout << " on module " << client->GetReflectorModule();
}
std::cout << std::endl;
// notify
g_Reflector.OnClientsChanged();
}
void CClients::RemoveClient(std::shared_ptr<CClient> client)
{
// look for the client
bool found = false;
for ( auto it=begin(); it!=end(); it++ )
{
// compare objetc pointers
if ( *it == client )
{
// found it !
if ( !(*it)->IsAMaster() )
{
// remove it
std::cout << "Client " << (*it)->GetCallsign() << " at " << (*it)->GetIp() << " removed with protocol " << (*it)->GetProtocolName();
if ( (*it)->GetReflectorModule() != ' ' )
{
std::cout << " on module " << (*it)->GetReflectorModule();
}
std::cout << std::endl;
m_Clients.erase(it);
// notify
g_Reflector.OnClientsChanged();
break;
}
}
}
}
bool CClients::IsClient(std::shared_ptr<CClient> client) const
{
for ( auto it=cbegin(); it!=cend(); it++ )
{
if (*it == client)
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////
// find Clients
std::shared_ptr<CClient> CClients::FindClient(const CIp &Ip)
{
// find client
for ( auto it=begin(); it!=end(); it++ )
{
if ( (*it)->GetIp() == Ip )
{
return *it;
}
}
// done
return nullptr;
}
std::shared_ptr<CClient> CClients::FindClient(const CIp &Ip, int Protocol)
{
// find client
for ( auto it=begin(); it!=end(); it++ )
{
if ( ((*it)->GetIp() == Ip) && ((*it)->GetProtocol() == Protocol))
{
return *it;
}
}
// done
return nullptr;
}
std::shared_ptr<CClient> CClients::FindClient(const CIp &Ip, int Protocol, char ReflectorModule)
{
// find client
for ( auto it=begin(); it!=end(); it++ )
{
if ( ((*it)->GetIp() == Ip) && ((*it)->GetReflectorModule() == ReflectorModule) && ((*it)->GetProtocol() == Protocol) )
{
return *it;
}
}
// done
return nullptr;
}
std::shared_ptr<CClient> CClients::FindClient(const CCallsign &Callsign, const CIp &Ip, int Protocol)
{
// find client
for ( auto it=begin(); it!=end(); it++ )
{
if ( (*it)->GetCallsign().HasSameCallsign(Callsign) && ((*it)->GetIp() == Ip) && ((*it)->GetProtocol() == Protocol) )
{
return *it;
}
}
return nullptr;
}
std::shared_ptr<CClient> CClients::FindClient(const CCallsign &Callsign, char module, const CIp &Ip, int Protocol)
{
// find client
for ( auto it=begin(); it!=end(); it++ )
{
if ( (*it)->GetCallsign().HasSameCallsign(Callsign) && ((*it)->GetModule() == module) && ((*it)->GetIp() == Ip) && ((*it)->GetProtocol() == Protocol) )
{
return *it;
}
}
return nullptr;
}
std::shared_ptr<CClient> CClients::FindClient(const CCallsign &Callsign, int Protocol)
{
// find client
for ( auto it=begin(); it!=end(); it++ )
{
if ( ((*it)->GetProtocol() == Protocol) && (*it)->GetCallsign().HasSameCallsign(Callsign) )
{
return *it;
}
}
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////////////
// iterate on clients
std::shared_ptr<CClient> CClients::FindNextClient(int Protocol, std::list<std::shared_ptr<CClient>>::iterator &it)
{
while ( it != end() )
{
if ( (*it)->GetProtocol() == Protocol )
{
return *it++;
}
it++;
}
return nullptr;
}
std::shared_ptr<CClient> CClients::FindNextClient(const CIp &Ip, int Protocol, std::list<std::shared_ptr<CClient>>::iterator &it)
{
while ( it != end() )
{
if ( ((*it)->GetProtocol() == Protocol) && ((*it)->GetIp() == Ip) )
{
return *it++;
}
it++;
}
return nullptr;
}
std::shared_ptr<CClient> CClients::FindNextClient(const CCallsign &Callsign, const CIp &Ip, int Protocol, std::list<std::shared_ptr<CClient>>::iterator &it)
{
while ( it != end() )
{
if ( ((*it)->GetProtocol() == Protocol) && ((*it)->GetIp() == Ip) && (*it)->GetCallsign().HasSameCallsign(Callsign) )
{
return *it++;
}
it++;
}
return nullptr;
}

77
clients.h

@ -0,0 +1,77 @@
//
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/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 "client.h"
////////////////////////////////////////////////////////////////////////////////////////
// define
////////////////////////////////////////////////////////////////////////////////////////
// class
class CClients