parent
3731800162
commit
9eb6d3967f
@ -1,144 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "BlockList.h"
|
||||
#include "YSFDefines.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
const int BUFFER_SIZE = 500;
|
||||
|
||||
CBlockList::CBlockList(const std::string& file, unsigned int time) :
|
||||
m_file(file),
|
||||
m_time(time),
|
||||
m_callsigns(),
|
||||
m_timer(1000U, time * 60U),
|
||||
m_checksum(0U)
|
||||
{
|
||||
}
|
||||
|
||||
CBlockList::~CBlockList()
|
||||
{
|
||||
}
|
||||
|
||||
bool CBlockList::start()
|
||||
{
|
||||
loadFile();
|
||||
|
||||
m_timer.start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CBlockList::check(const unsigned char* callsign) const
|
||||
{
|
||||
assert(callsign != NULL);
|
||||
|
||||
if (m_callsigns.empty())
|
||||
return false;
|
||||
|
||||
std::string call = std::string((char*)callsign, YSF_CALLSIGN_LENGTH);
|
||||
std::for_each(call.begin(), call.end(), [](char& c) {
|
||||
c = std::toupper(c);
|
||||
});
|
||||
|
||||
for (std::vector<std::string>::const_iterator it = m_callsigns.cbegin(); it != m_callsigns.cend(); ++it) {
|
||||
const std::string blocked = *it;
|
||||
if (call.find(blocked) != std::string::npos)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CBlockList::clock(unsigned int ms)
|
||||
{
|
||||
m_timer.clock(ms);
|
||||
|
||||
if (m_timer.isRunning() && m_timer.hasExpired()) {
|
||||
loadFile();
|
||||
m_timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
bool CBlockList::loadFile()
|
||||
{
|
||||
FILE* fp = ::fopen(m_file.c_str(), "rt");
|
||||
if (fp == NULL) {
|
||||
if (!m_callsigns.empty()) {
|
||||
m_callsigns.clear();
|
||||
LogInfo("Loaded %u callsigns from the block list", m_callsigns.size());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
// First perform the checksum (Fletcher 16)
|
||||
uint16_t sum1 = 0U;
|
||||
uint16_t sum2 = 0U;
|
||||
while (::fgets(buffer, BUFFER_SIZE, fp) != NULL) {
|
||||
for (char* p = buffer; *p != '\0'; p++) {
|
||||
sum1 = (sum1 + uint8_t(*p)) % 255U;
|
||||
sum2 = (sum2 + sum1) % 255U;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t checksum = (sum2 << 8) | sum1;
|
||||
if (checksum == m_checksum) {
|
||||
::fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
m_checksum = checksum;
|
||||
|
||||
// Rewind the file
|
||||
::fseek(fp, 0L, SEEK_SET);
|
||||
|
||||
// Read the callsigns into the array
|
||||
m_callsigns.clear();
|
||||
|
||||
while (::fgets(buffer, BUFFER_SIZE, fp) != NULL) {
|
||||
char* p;
|
||||
if ((p = ::strchr(buffer, '\n')) != NULL)
|
||||
*p = '\0';
|
||||
if ((p = ::strchr(buffer, '\r')) != NULL)
|
||||
*p = '\0';
|
||||
|
||||
if (::strlen(buffer) > 0U) {
|
||||
std::string callsign = std::string(buffer);
|
||||
|
||||
std::for_each(callsign.begin(), callsign.end(), [](char& c) {
|
||||
c = std::toupper(c);
|
||||
});
|
||||
|
||||
m_callsigns.push_back(callsign);
|
||||
}
|
||||
}
|
||||
|
||||
::fclose(fp);
|
||||
|
||||
LogInfo("Loaded %u callsigns from the block list", m_callsigns.size());
|
||||
|
||||
return true;
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(BLOCKLIST_H)
|
||||
#define BLOCKLIST_H
|
||||
|
||||
#include "Timer.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class CBlockList
|
||||
{
|
||||
public:
|
||||
CBlockList(const std::string& file, unsigned int time);
|
||||
~CBlockList();
|
||||
|
||||
bool start();
|
||||
|
||||
bool check(const unsigned char* callsign) const;
|
||||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
private:
|
||||
std::string m_file;
|
||||
unsigned int m_time;
|
||||
std::vector<std::string> m_callsigns;
|
||||
CTimer m_timer;
|
||||
uint16_t m_checksum;
|
||||
|
||||
bool loadFile();
|
||||
};
|
||||
|
||||
#endif
|
@ -1,219 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2020,2021 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "Conf.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
|
||||
const int BUFFER_SIZE = 500;
|
||||
|
||||
enum SECTION {
|
||||
SECTION_NONE,
|
||||
SECTION_GENERAL,
|
||||
SECTION_INFO,
|
||||
SECTION_LOG,
|
||||
SECTION_NETWORK,
|
||||
SECTION_BLOCKLIST
|
||||
};
|
||||
|
||||
CConf::CConf(const std::string& file) :
|
||||
m_file(file),
|
||||
m_daemon(false),
|
||||
m_id(0U),
|
||||
m_name(),
|
||||
m_description(),
|
||||
m_logDisplayLevel(0U),
|
||||
m_logFileLevel(0U),
|
||||
m_logFilePath(),
|
||||
m_logFileRoot(),
|
||||
m_logFileRotate(true),
|
||||
m_networkPort(0U),
|
||||
m_networkDebug(false),
|
||||
m_blockListFile(),
|
||||
m_blockListTime(5U)
|
||||
{
|
||||
}
|
||||
|
||||
CConf::~CConf()
|
||||
{
|
||||
}
|
||||
|
||||
bool CConf::read()
|
||||
{
|
||||
FILE* fp = ::fopen(m_file.c_str(), "rt");
|
||||
if (fp == NULL) {
|
||||
::fprintf(stderr, "Couldn't open the .ini file - %s\n", m_file.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
SECTION section = SECTION_NONE;
|
||||
|
||||
char buffer[BUFFER_SIZE];
|
||||
while (::fgets(buffer, BUFFER_SIZE, fp) != NULL) {
|
||||
if (buffer[0U] == '#')
|
||||
continue;
|
||||
|
||||
if (buffer[0U] == '[') {
|
||||
if (::strncmp(buffer, "[General]", 9U) == 0)
|
||||
section = SECTION_GENERAL;
|
||||
else if (::strncmp(buffer, "[Info]", 6U) == 0)
|
||||
section = SECTION_INFO;
|
||||
else if (::strncmp(buffer, "[Log]", 5U) == 0)
|
||||
section = SECTION_LOG;
|
||||
else if (::strncmp(buffer, "[Network]", 9U) == 0)
|
||||
section = SECTION_NETWORK;
|
||||
else if (::strncmp(buffer, "[Block List]", 12U) == 0)
|
||||
section = SECTION_BLOCKLIST;
|
||||
else
|
||||
section = SECTION_NONE;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
char* key = ::strtok(buffer, " \t=\r\n");
|
||||
if (key == NULL)
|
||||
continue;
|
||||
|
||||
char* value = ::strtok(NULL, "\r\n");
|
||||
if (value == NULL)
|
||||
continue;
|
||||
|
||||
// Remove quotes from the value
|
||||
size_t len = ::strlen(value);
|
||||
if (len > 1U && *value == '"' && value[len - 1U] == '"') {
|
||||
value[len - 1U] = '\0';
|
||||
value++;
|
||||
} else {
|
||||
char *p;
|
||||
|
||||
// if value is not quoted, remove after # (to make comment)
|
||||
if ((p = strchr(value, '#')) != NULL)
|
||||
*p = '\0';
|
||||
|
||||
// remove trailing tab/space
|
||||
for (p = value + strlen(value) - 1U; p >= value && (*p == '\t' || *p == ' '); p--)
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
if (section == SECTION_GENERAL) {
|
||||
if (::strcmp(key, "Daemon") == 0)
|
||||
m_daemon = ::atoi(value) == 1;
|
||||
} else if (section == SECTION_INFO) {
|
||||
if (::strcmp(key, "Id") == 0)
|
||||
m_id = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "Name") == 0)
|
||||
m_name = value;
|
||||
else if (::strcmp(key, "Description") == 0)
|
||||
m_description = value;
|
||||
} else if (section == SECTION_LOG) {
|
||||
if (::strcmp(key, "FilePath") == 0)
|
||||
m_logFilePath = value;
|
||||
else if (::strcmp(key, "FileRoot") == 0)
|
||||
m_logFileRoot = value;
|
||||
else if (::strcmp(key, "FileLevel") == 0)
|
||||
m_logFileLevel = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "DisplayLevel") == 0)
|
||||
m_logDisplayLevel = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "FileRotate") == 0)
|
||||
m_logFileRotate = ::atoi(value) == 1;
|
||||
} else if (section == SECTION_NETWORK) {
|
||||
if (::strcmp(key, "Port") == 0)
|
||||
m_networkPort = (unsigned short)::atoi(value);
|
||||
else if (::strcmp(key, "Debug") == 0)
|
||||
m_networkDebug = ::atoi(value) == 1;
|
||||
} else if (section == SECTION_BLOCKLIST) {
|
||||
if (::strcmp(key, "File") == 0)
|
||||
m_blockListFile = value;
|
||||
else if (::strcmp(key, "Time") == 0)
|
||||
m_blockListTime = (unsigned int)::atoi(value);
|
||||
}
|
||||
}
|
||||
|
||||
::fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConf::getDaemon() const
|
||||
{
|
||||
return m_daemon;
|
||||
}
|
||||
|
||||
unsigned int CConf::getId() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
std::string CConf::getName() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
std::string CConf::getDescription() const
|
||||
{
|
||||
return m_description;
|
||||
}
|
||||
|
||||
unsigned int CConf::getLogDisplayLevel() const
|
||||
{
|
||||
return m_logDisplayLevel;
|
||||
}
|
||||
|
||||
unsigned int CConf::getLogFileLevel() const
|
||||
{
|
||||
return m_logFileLevel;
|
||||
}
|
||||
|
||||
std::string CConf::getLogFilePath() const
|
||||
{
|
||||
return m_logFilePath;
|
||||
}
|
||||
|
||||
std::string CConf::getLogFileRoot() const
|
||||
{
|
||||
return m_logFileRoot;
|
||||
}
|
||||
|
||||
bool CConf::getLogFileRotate() const
|
||||
{
|
||||
return m_logFileRotate;
|
||||
}
|
||||
|
||||
unsigned short CConf::getNetworkPort() const
|
||||
{
|
||||
return m_networkPort;
|
||||
}
|
||||
|
||||
bool CConf::getNetworkDebug() const
|
||||
{
|
||||
return m_networkDebug;
|
||||
}
|
||||
|
||||
std::string CConf::getBlockListFile() const
|
||||
{
|
||||
return m_blockListFile;
|
||||
}
|
||||
|
||||
unsigned int CConf::getBlockListTime() const
|
||||
{
|
||||
return m_blockListTime;
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2020,2021 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(CONF_H)
|
||||
#define CONF_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class CConf
|
||||
{
|
||||
public:
|
||||
CConf(const std::string& file);
|
||||
~CConf();
|
||||
|
||||
bool read();
|
||||
|
||||
// The General section
|
||||
bool getDaemon() const;
|
||||
|
||||
// The Info section
|
||||
unsigned int getId() const;
|
||||
std::string getName() const;
|
||||
std::string getDescription() const;
|
||||
|
||||
// The Log section
|
||||
unsigned int getLogDisplayLevel() const;
|
||||
unsigned int getLogFileLevel() const;
|
||||
std::string getLogFilePath() const;
|
||||
std::string getLogFileRoot() const;
|
||||
bool getLogFileRotate() const;
|
||||
|
||||
// The Network section
|
||||
unsigned short getNetworkPort() const;
|
||||
bool getNetworkDebug() const;
|
||||
|
||||
// The Block List section
|
||||
std::string getBlockListFile() const;
|
||||
unsigned int getBlockListTime() const;
|
||||
|
||||
private:
|
||||
std::string m_file;
|
||||
bool m_daemon;
|
||||
|
||||
unsigned int m_id;
|
||||
std::string m_name;
|
||||
std::string m_description;
|
||||
|
||||
unsigned int m_logDisplayLevel;
|
||||
unsigned int m_logFileLevel;
|
||||
std::string m_logFilePath;
|
||||
std::string m_logFileRoot;
|
||||
bool m_logFileRotate;
|
||||
|
||||
unsigned short m_networkPort;
|
||||
bool m_networkDebug;
|
||||
|
||||
std::string m_blockListFile;
|
||||
unsigned int m_blockListTime;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,192 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
#include <ctime>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
static unsigned int m_fileLevel = 2U;
|
||||
static std::string m_filePath;
|
||||
static std::string m_fileRoot;
|
||||
static bool m_fileRotate = true;
|
||||
|
||||
static FILE* m_fpLog = NULL;
|
||||
static bool m_daemon = false;
|
||||
|
||||
static unsigned int m_displayLevel = 2U;
|
||||
|
||||
static struct tm m_tm;
|
||||
|
||||
static char LEVELS[] = " DMIWEF";
|
||||
|
||||
static bool logOpenRotate()
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (m_fileLevel == 0U)
|
||||
return true;
|
||||
|
||||
time_t now;
|
||||
::time(&now);
|
||||
|
||||
struct tm* tm = ::gmtime(&now);
|
||||
|
||||
if (tm->tm_mday == m_tm.tm_mday && tm->tm_mon == m_tm.tm_mon && tm->tm_year == m_tm.tm_year) {
|
||||
if (m_fpLog != NULL)
|
||||
return true;
|
||||
} else {
|
||||
if (m_fpLog != NULL)
|
||||
::fclose(m_fpLog);
|
||||
}
|
||||
|
||||
char filename[200U];
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::sprintf(filename, "%s\\%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
||||
#else
|
||||
::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
|
||||
#endif
|
||||
|
||||
if ((m_fpLog = ::fopen(filename, "a+t")) != NULL) {
|
||||
status = true;
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
if (m_daemon)
|
||||
dup2(fileno(m_fpLog), fileno(stderr));
|
||||
#endif
|
||||
}
|
||||
|
||||
m_tm = *tm;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static bool logOpenNoRotate()
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
if (m_fileLevel == 0U)
|
||||
return true;
|
||||
|
||||
if (m_fpLog != NULL)
|
||||
return true;
|
||||
|
||||
char filename[200U];
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::sprintf(filename, "%s\\%s.log", m_filePath.c_str(), m_fileRoot.c_str());
|
||||
#else
|
||||
::sprintf(filename, "%s/%s.log", m_filePath.c_str(), m_fileRoot.c_str());
|
||||
#endif
|
||||
|
||||
if ((m_fpLog = ::fopen(filename, "a+t")) != NULL) {
|
||||
status = true;
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
if (m_daemon)
|
||||
dup2(fileno(m_fpLog), fileno(stderr));
|
||||
#endif
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool LogOpen()
|
||||
{
|
||||
if (m_fileRotate)
|
||||
return logOpenRotate();
|
||||
else
|
||||
return logOpenNoRotate();
|
||||
}
|
||||
|
||||
bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel, bool rotate)
|
||||
{
|
||||
m_filePath = filePath;
|
||||
m_fileRoot = fileRoot;
|
||||
m_fileLevel = fileLevel;
|
||||
m_displayLevel = displayLevel;
|
||||
m_daemon = daemon;
|
||||
m_fileRotate = rotate;
|
||||
|
||||
if (m_daemon)
|
||||
m_displayLevel = 0U;
|
||||
|
||||
return ::LogOpen();
|
||||
}
|
||||
|
||||
void LogFinalise()
|
||||
{
|
||||
if (m_fpLog != NULL)
|
||||
::fclose(m_fpLog);
|
||||
}
|
||||
|
||||
void Log(unsigned int level, const char* fmt, ...)
|
||||
{
|
||||
assert(fmt != NULL);
|
||||
|
||||
char buffer[501U];
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
SYSTEMTIME st;
|
||||
::GetSystemTime(&st);
|
||||
|
||||
::sprintf(buffer, "%c: %04u-%02u-%02u %02u:%02u:%02u.%03u ", LEVELS[level], st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
|
||||
#else
|
||||
struct timeval now;
|
||||
::gettimeofday(&now, NULL);
|
||||
|
||||
struct tm* tm = ::gmtime(&now.tv_sec);
|
||||
|
||||
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03lld ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000LL);
|
||||
#endif
|
||||
|
||||
va_list vl;
|
||||
va_start(vl, fmt);
|
||||
|
||||
::vsnprintf(buffer + ::strlen(buffer), 500, fmt, vl);
|
||||
|
||||
va_end(vl);
|
||||
|
||||
if (level >= m_fileLevel && m_fileLevel != 0U) {
|
||||
bool ret = ::LogOpen();
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
::fprintf(m_fpLog, "%s\n", buffer);
|
||||
::fflush(m_fpLog);
|
||||
}
|
||||
|
||||
if (level >= m_displayLevel && m_displayLevel != 0U) {
|
||||
::fprintf(stdout, "%s\n", buffer);
|
||||
::fflush(stdout);
|
||||
}
|
||||
|
||||
if (level == 6U) { // Fatal
|
||||
::fclose(m_fpLog);
|
||||
exit(1);
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(LOG_H)
|
||||
#define LOG_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#define LogDebug(fmt, ...) Log(1U, fmt, ##__VA_ARGS__)
|
||||
#define LogMessage(fmt, ...) Log(2U, fmt, ##__VA_ARGS__)
|
||||
#define LogInfo(fmt, ...) Log(3U, fmt, ##__VA_ARGS__)
|
||||
#define LogWarning(fmt, ...) Log(4U, fmt, ##__VA_ARGS__)
|
||||
#define LogError(fmt, ...) Log(5U, fmt, ##__VA_ARGS__)
|
||||
#define LogFatal(fmt, ...) Log(6U, fmt, ##__VA_ARGS__)
|
||||
|
||||
extern void Log(unsigned int level, const char* fmt, ...);
|
||||
|
||||
extern bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel, bool rotate);
|
||||
extern void LogFinalise();
|
||||
|
||||
#endif
|
@ -1,35 +0,0 @@
|
||||
CC = cc
|
||||
CXX = c++
|
||||
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -DUDP_SOCKET_MAX=2
|
||||
LIBS = -lpthread
|
||||
LDFLAGS = -g
|
||||
|
||||
OBJECTS = BlockList.o Conf.o Log.o Network.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o YSFReflector.o
|
||||
|
||||
all: YSFReflector
|
||||
|
||||
YSFReflector: $(OBJECTS)
|
||||
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o YSFReflector
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
YSFReflector.o: GitVersion.h FORCE
|
||||
|
||||
.PHONY: GitVersion.h
|
||||
|
||||
FORCE:
|
||||
|
||||
install:
|
||||
install -m 755 YSFReflector /usr/local/bin/
|
||||
|
||||
clean:
|
||||
$(RM) YSFReflector *.o *.d *.bak *~ GitVersion.h
|
||||
|
||||
# Export the current git version if the index file exists, else 000...
|
||||
GitVersion.h:
|
||||
ifneq ("$(wildcard ../.git/index)","")
|
||||
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
|
||||
else
|
||||
echo "const char *gitversion = \"0000000000000000000000000000000000000000\";" > $@
|
||||
endif
|
@ -1,155 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2014,2016,2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "YSFDefines.h"
|
||||
#include "Network.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
CNetwork::CNetwork(unsigned short port, unsigned int id, const std::string& name, const std::string& description, bool debug) :
|
||||
m_socket(),
|
||||
m_port(port),
|
||||
m_id(id),
|
||||
m_name(name),
|
||||
m_description(description),
|
||||
m_callsign(),
|
||||
m_debug(debug),
|
||||
m_status(NULL)
|
||||
{
|
||||
m_name.resize(16U, ' ');
|
||||
m_description.resize(14U, ' ');
|
||||
|
||||
m_status = new unsigned char[50U];
|
||||
}
|
||||
|
||||
CNetwork::~CNetwork()
|
||||
{
|
||||
delete[] m_status;
|
||||
}
|
||||
|
||||
bool CNetwork::open()
|
||||
{
|
||||
LogInfo("Opening YSF network connection");
|
||||
|
||||
bool status = false;
|
||||
unsigned int af[] = {AF_INET, AF_INET6};
|
||||
|
||||
for (unsigned int i = 0U; i < UDP_SOCKET_MAX && i < (sizeof(af) / sizeof(unsigned int)); i++)
|
||||
status |= m_socket.open(i, af[i], "", m_port);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool CNetwork::writeData(const unsigned char* data, const sockaddr_storage& addr, unsigned int addrLen)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "YSF Network Data Sent", data, 155U);
|
||||
|
||||
return m_socket.write(data, 155U, addr, addrLen);
|
||||
}
|
||||
|
||||
bool CNetwork::writePoll(const sockaddr_storage& addr, unsigned int addrLen)
|
||||
{
|
||||
unsigned char buffer[20U];
|
||||
|
||||
buffer[0] = 'Y';
|
||||
buffer[1] = 'S';
|
||||
buffer[2] = 'F';
|
||||
buffer[3] = 'P';
|
||||
|
||||
buffer[4U] = 'R';
|
||||
buffer[5U] = 'E';
|
||||
buffer[6U] = 'F';
|
||||
buffer[7U] = 'L';
|
||||
buffer[8U] = 'E';
|
||||
buffer[9U] = 'C';
|
||||
buffer[10U] = 'T';
|
||||
buffer[11U] = 'O';
|
||||
buffer[12U] = 'R';
|
||||
buffer[13U] = ' ';
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "YSF Network Poll Sent", buffer, 14U);
|
||||
|
||||
return m_socket.write(buffer, 14U, addr, addrLen);
|
||||
}
|
||||
|
||||
unsigned int CNetwork::readData(unsigned char* data, unsigned int length, sockaddr_storage& addr, unsigned int& addrLen)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
int len = m_socket.read(data, length, addr, addrLen);
|
||||
if (len <= 0)
|
||||
return 0U;
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "YSF Network Data Received", data, len);
|
||||
|
||||
// Throw away any options messages
|
||||
if (::memcmp(data, "YSFO", 4U) == 0)
|
||||
return 0U;
|
||||
|
||||
// Throw away any info messages
|
||||
if (::memcmp(data, "YSFI", 4U) == 0)
|
||||
return 0U;
|
||||
|
||||
// Handle incoming status requests
|
||||
if (::memcmp(data, "YSFS", 4U) == 0) {
|
||||
m_socket.write(m_status, 42U, addr, addrLen);
|
||||
return 0U;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void CNetwork::setCount(unsigned int count)
|
||||
{
|
||||
if (count > 999U)
|
||||
count = 999U;
|
||||
|
||||
unsigned int hash = m_id;
|
||||
|
||||
if (hash == 0U) {
|
||||
for (unsigned int i = 0U; i < m_name.size(); i++) {
|
||||
hash += m_name.at(i);
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
|
||||
// Final avalanche
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
}
|
||||
|
||||
::sprintf((char*)m_status, "YSFS%05u%16.16s%14.14s%03u", hash % 100000U, m_name.c_str(), m_description.c_str(), count);
|
||||
}
|
||||
|
||||
void CNetwork::close()
|
||||
{
|
||||
m_socket.close();
|
||||
|
||||
LogInfo("Closing YSF network connection");
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2014,2016,2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef Network_H
|
||||
#define Network_H
|
||||
|
||||
#include "YSFDefines.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "Timer.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class CNetwork {
|
||||
public:
|
||||
CNetwork(unsigned short port, unsigned int id, const std::string& name, const std::string& description, bool debug);
|
||||
~CNetwork();
|
||||
|
||||
bool open();
|
||||
|
||||
bool writeData(const unsigned char* data, const sockaddr_storage& addr, unsigned int addrLen);
|
||||
bool writePoll(const sockaddr_storage& addr, unsigned int addrLen);
|
||||
|
||||
unsigned int readData(unsigned char* data, unsigned int length, sockaddr_storage& addr, unsigned int& addrLen);
|
||||
|
||||
void close();
|
||||
|
||||
void setCount(unsigned int count);
|
||||
|
||||
private:
|
||||
CUDPSocket m_socket;
|
||||
unsigned short m_port;
|
||||
unsigned int m_id;
|
||||
std::string m_name;
|
||||
std::string m_description;
|
||||
std::string m_callsign;
|
||||
bool m_debug;
|
||||
unsigned char* m_status;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -1,105 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "StopWatch.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
CStopWatch::CStopWatch() :
|
||||
m_frequencyS(),
|
||||
m_frequencyMS(),
|
||||
m_start()
|
||||
{
|
||||
::QueryPerformanceFrequency(&m_frequencyS);
|
||||
|
||||
m_frequencyMS.QuadPart = m_frequencyS.QuadPart / 1000ULL;
|
||||
}
|
||||
|
||||
CStopWatch::~CStopWatch()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned long long CStopWatch::time() const
|
||||
{
|
||||
LARGE_INTEGER now;
|
||||
::QueryPerformanceCounter(&now);
|
||||
|
||||
return (unsigned long long)(now.QuadPart / m_frequencyMS.QuadPart);
|
||||
}
|
||||
|
||||
unsigned long long CStopWatch::start()
|
||||
{
|
||||
::QueryPerformanceCounter(&m_start);
|
||||
|
||||
return (unsigned long long)(m_start.QuadPart / m_frequencyS.QuadPart);
|
||||
}
|
||||
|
||||
unsigned int CStopWatch::elapsed()
|
||||
{
|
||||
LARGE_INTEGER now;
|
||||
::QueryPerformanceCounter(&now);
|
||||
|
||||
LARGE_INTEGER temp;
|
||||
temp.QuadPart = (now.QuadPart - m_start.QuadPart) * 1000;
|
||||
|
||||
return (unsigned int)(temp.QuadPart / m_frequencyS.QuadPart);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
|
||||
CStopWatch::CStopWatch() :
|
||||
m_startMS(0ULL)
|
||||
{
|
||||
}
|
||||
|
||||
CStopWatch::~CStopWatch()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned long long CStopWatch::time() const
|
||||
{
|
||||
struct timeval now;
|
||||
::gettimeofday(&now, NULL);
|
||||
|
||||
return now.tv_sec * 1000ULL + now.tv_usec / 1000ULL;
|
||||
}
|
||||
|
||||
unsigned long long CStopWatch::start()
|
||||
{
|
||||
struct timespec now;
|
||||
::clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
m_startMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL;
|
||||
|
||||
return m_startMS;
|
||||
}
|
||||
|
||||
unsigned int CStopWatch::elapsed()
|
||||
{
|
||||
struct timespec now;
|
||||
::clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
|
||||
unsigned long long nowMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL;
|
||||
|
||||
return nowMS - m_startMS;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2018 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(STOPWATCH_H)
|
||||
#define STOPWATCH_H
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <WS2tcpip.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
class CStopWatch
|
||||
{
|
||||
public:
|
||||
CStopWatch();
|
||||
~CStopWatch();
|
||||
|
||||
unsigned long long time() const;
|
||||
|
||||
unsigned long long start();
|
||||
unsigned int elapsed();
|
||||
|
||||
private:
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LARGE_INTEGER m_frequencyS;
|
||||
LARGE_INTEGER m_frequencyMS;
|
||||
LARGE_INTEGER m_start;
|
||||
#else
|
||||
unsigned long long m_startMS;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
CThread::CThread() :
|
||||
m_handle()
|
||||
{
|
||||
}
|
||||
|
||||
CThread::~CThread()
|
||||
{
|
||||
}
|
||||
|
||||
bool CThread::run()
|
||||
{
|
||||
m_handle = ::CreateThread(NULL, 0, &helper, this, 0, NULL);
|
||||
|
||||
return m_handle != NULL;
|
||||
}
|
||||
|
||||
|
||||
void CThread::wait()
|
||||
{
|
||||
::WaitForSingleObject(m_handle, INFINITE);
|
||||
|
||||
::CloseHandle(m_handle);
|
||||
}
|
||||
|
||||
|
||||
DWORD CThread::helper(LPVOID arg)
|
||||
{
|
||||
CThread* p = (CThread*)arg;
|
||||
|
||||
p->entry();
|
||||
|
||||
return 0UL;
|
||||
}
|
||||
|
||||
void CThread::sleep(unsigned int ms)
|
||||
{
|
||||
::Sleep(ms);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
CThread::CThread() :
|
||||
m_thread()
|
||||
{
|
||||
}
|
||||
|
||||
CThread::~CThread()
|
||||
{
|
||||
}
|
||||
|
||||
bool CThread::run()
|
||||
{
|
||||
return ::pthread_create(&m_thread, NULL, helper, this) == 0;
|
||||
}
|
||||
|
||||
|
||||
void CThread::wait()
|
||||
{
|
||||
::pthread_join(m_thread, NULL);
|
||||
}
|
||||
|
||||
|
||||
void* CThread::helper(void* arg)
|
||||
{
|
||||
CThread* p = (CThread*)arg;
|
||||
|
||||
p->entry();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CThread::sleep(unsigned int ms)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
ts.tv_sec = ms / 1000U;
|
||||
ts.tv_nsec = (ms % 1000U) * 1000000U;
|
||||
|
||||
::nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(THREAD_H)
|
||||
#define THREAD_H
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
class CThread
|
||||
{
|
||||
public:
|
||||
CThread();
|
||||
virtual ~CThread();
|
||||
|
||||
virtual bool run();
|
||||
|
||||
virtual void entry() = 0;
|
||||
|
||||
virtual void wait();
|
||||
|
||||
static void sleep(unsigned int ms);
|
||||
|
||||
private:
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HANDLE m_handle;
|
||||
#else
|
||||
pthread_t m_thread;
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
static DWORD __stdcall helper(LPVOID arg);
|
||||
#else
|
||||
static void* helper(void* arg);
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009,2010,2015 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "Timer.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
CTimer::CTimer(unsigned int ticksPerSec, unsigned int secs, unsigned int msecs) :
|
||||
m_ticksPerSec(ticksPerSec),
|
||||
m_timeout(0U),
|
||||
m_timer(0U)
|
||||
{
|
||||
assert(ticksPerSec > 0U);
|
||||
|
||||
if (secs > 0U || msecs > 0U) {
|
||||
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
|
||||
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
|
||||
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
|
||||
}
|
||||
}
|
||||
|
||||
CTimer::~CTimer()
|
||||
{
|
||||
}
|
||||
|
||||
void CTimer::setTimeout(unsigned int secs, unsigned int msecs)
|
||||
{
|
||||
if (secs > 0U || msecs > 0U) {
|
||||
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
|
||||
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
|
||||
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
|
||||
} else {
|
||||
m_timeout = 0U;
|
||||
m_timer = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CTimer::getTimeout() const
|
||||
{
|
||||
if (m_timeout == 0U)
|
||||
return 0U;
|
||||
|
||||
return (m_timeout - 1U) / m_ticksPerSec;
|
||||
}
|
||||
|
||||
unsigned int CTimer::getTimer() const
|
||||
{
|
||||
if (m_timer == 0U)
|
||||
return 0U;
|
||||
|
||||
return (m_timer - 1U) / m_ticksPerSec;
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009,2010,2011,2014 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef Timer_H
|
||||
#define Timer_H
|
||||
|
||||
class CTimer {
|
||||
public:
|
||||
CTimer(unsigned int ticksPerSec, unsigned int secs = 0U, unsigned int msecs = 0U);
|
||||
~CTimer();
|
||||
|
||||
void setTimeout(unsigned int secs, unsigned int msecs = 0U);
|
||||
|
||||
unsigned int getTimeout() const;
|
||||
unsigned int getTimer() const;
|
||||
|
||||
unsigned int getRemaining()
|
||||
{
|
||||
if (m_timeout == 0U || m_timer == 0U)
|
||||
return 0U;
|
||||
|
||||
if (m_timer >= m_timeout)
|
||||
return 0U;
|
||||
|
||||
return (m_timeout - m_timer) / m_ticksPerSec;
|
||||
}
|
||||
|
||||
bool isRunning()
|
||||
{
|
||||
return m_timer > 0U;
|
||||
}
|
||||
|
||||
void start(unsigned int secs, unsigned int msecs = 0U)
|
||||
{
|
||||
setTimeout(secs, msecs);
|
||||
|
||||
start();
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
if (m_timeout > 0U)
|
||||
m_timer = 1U;
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
m_timer = 0U;
|
||||
}
|
||||
|
||||
bool hasExpired()
|
||||
{
|
||||
if (m_timeout == 0U || m_timer == 0U)
|
||||
return false;
|
||||
|
||||
if (m_timer >= m_timeout)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void clock(unsigned int ticks = 1U)
|
||||
{
|
||||
if (m_timer > 0U && m_timeout > 0U)
|
||||
m_timer += ticks;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int m_ticksPerSec;
|
||||
unsigned int m_timeout;
|
||||
unsigned int m_timer;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,390 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2006-2016,2020,2021 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "UDPSocket.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
#include <cerrno>
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LOG_H)
|
||||
#include "Log.h"
|
||||
#else
|
||||
#define LogError(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__)
|
||||
#define LogInfo(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) :
|
||||
m_address_save(address),
|
||||
m_port_save(port),
|
||||
m_counter(0U)
|
||||
{
|
||||
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
|
||||
m_address[i] = "";
|
||||
m_port[i] = 0U;
|
||||
m_af[i] = 0U;
|
||||
m_fd[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
CUDPSocket::CUDPSocket(unsigned int port) :
|
||||
m_address_save(),
|
||||
m_port_save(port),
|
||||
m_counter(0U)
|
||||
{
|
||||
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
|
||||
m_address[i] = "";
|
||||
m_port[i] = 0U;
|
||||
m_af[i] = 0U;
|
||||
m_fd[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
CUDPSocket::~CUDPSocket()
|
||||
{
|
||||
}
|
||||
|
||||
void CUDPSocket::startup()
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
WSAData data;
|
||||
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
|
||||
if (wsaRet != 0)
|
||||
LogError("Error from WSAStartup");
|
||||
#endif
|
||||
}
|
||||
|
||||
void CUDPSocket::shutdown()
|
||||
{
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& address_length)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
::memset(&hints, 0, sizeof(hints));
|
||||
|
||||
return lookup(hostname, port, addr, address_length, hints);
|
||||
}
|
||||
|
||||
int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& address_length, struct addrinfo& hints)
|
||||
{
|
||||
std::string portstr = std::to_string(port);
|
||||
struct addrinfo *res;
|
||||
|
||||
/* port is always digits, no needs to lookup service */
|
||||
hints.ai_flags |= AI_NUMERICSERV;
|
||||
|
||||
int err = getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
|
||||
if (err != 0) {
|
||||
sockaddr_in* paddr = (sockaddr_in*)&addr;
|
||||
::memset(paddr, 0x00U, address_length = sizeof(sockaddr_in));
|
||||
paddr->sin_family = AF_INET;
|
||||
paddr->sin_port = htons(port);
|
||||
paddr->sin_addr.s_addr = htonl(INADDR_NONE);
|
||||
LogError("Cannot find address for host %s", hostname.c_str());
|
||||
return err;
|
||||
}
|
||||
|
||||
::memcpy(&addr, res->ai_addr, address_length = res->ai_addrlen);
|
||||
|
||||
freeaddrinfo(res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type)
|
||||
{
|
||||
if (addr1.ss_family != addr2.ss_family)
|
||||
return false;
|
||||
|
||||
if (type == IMT_ADDRESS_AND_PORT) {
|
||||
switch (addr1.ss_family) {
|
||||
case AF_INET:
|
||||
struct sockaddr_in *in_1, *in_2;
|
||||
in_1 = (struct sockaddr_in*)&addr1;
|
||||
in_2 = (struct sockaddr_in*)&addr2;
|
||||
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
|
||||
case AF_INET6:
|
||||
struct sockaddr_in6 *in6_1, *in6_2;
|
||||
in6_1 = (struct sockaddr_in6*)&addr1;
|
||||
in6_2 = (struct sockaddr_in6*)&addr2;
|
||||
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else if (type == IMT_ADDRESS_ONLY) {
|
||||
switch (addr1.ss_family) {
|
||||
case AF_INET:
|
||||
struct sockaddr_in *in_1, *in_2;
|
||||
in_1 = (struct sockaddr_in*)&addr1;
|
||||
in_2 = (struct sockaddr_in*)&addr2;
|
||||
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
|
||||
case AF_INET6:
|
||||
struct sockaddr_in6 *in6_1, *in6_2;
|
||||
in6_1 = (struct sockaddr_in6*)&addr1;
|
||||
in6_2 = (struct sockaddr_in6*)&addr2;
|
||||
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CUDPSocket::isNone(const sockaddr_storage& addr)
|
||||
{
|
||||
struct sockaddr_in *in = (struct sockaddr_in *)&addr;
|
||||
|
||||
return ((addr.ss_family == AF_INET) && (in->sin_addr.s_addr == htonl(INADDR_NONE)));
|
||||
}
|
||||
|
||||
char* CUDPSocket::display(const sockaddr_storage& addr, char* buffer, unsigned int length)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
assert(length > INET6_ADDRSTRLEN);
|
||||
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in* in4 = (struct sockaddr_in*)&addr;
|
||||
::inet_ntop(AF_INET, &in4->sin_addr, buffer, length);
|
||||
::sprintf(buffer + ::strlen(buffer), ":%u", in4->sin_port);
|
||||
}
|
||||
break;
|
||||
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6* in6 = (struct sockaddr_in6*)&addr;
|
||||
::inet_ntop(AF_INET6, &in6->sin6_addr, buffer, length);
|
||||
::sprintf(buffer + ::strlen(buffer), ":%u", in6->sin6_port);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
::strcpy(buffer, "Unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
bool CUDPSocket::open(const sockaddr_storage& address)
|
||||
{
|
||||
return open(address.ss_family);
|
||||
}
|
||||
|
||||
bool CUDPSocket::open(unsigned int af)
|
||||
{
|
||||
return open(0, af, m_address_save, m_port_save);
|
||||
}
|
||||
|
||||
bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port)
|
||||
{
|
||||
sockaddr_storage addr;
|
||||
unsigned int addrlen;
|
||||
struct addrinfo hints;
|
||||
|
||||
::memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
hints.ai_family = af;
|
||||
|
||||
/* to determine protocol family, call lookup() first. */
|
||||
int err = lookup(address, port, addr, addrlen, hints);
|
||||
if (err != 0) {
|
||||
LogError("The local address is invalid - %s", address.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
close(index);
|
||||
|
||||
int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
|
||||
#else
|
||||
LogError("Cannot create the UDP socket, err: %d", errno);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
m_address[index] = address;
|
||||
m_port[index] = port;
|
||||
m_af[index] = addr.ss_family;
|
||||
m_fd[index] = fd;
|
||||
|
||||
if (port > 0U) {
|
||||
int reuse = 1;
|
||||
if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError());
|
||||
#else
|
||||
LogError("Cannot set the UDP socket option, err: %d", errno);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::bind(fd, (sockaddr*)&addr, addrlen) == -1) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
|
||||
#else
|
||||
LogError("Cannot bind the UDP address, err: %d", errno);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
LogInfo("Opening UDP port on %u", port);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
// Check that the readfrom() won't block
|
||||
int i, n;
|
||||
struct pollfd pfd[UDP_SOCKET_MAX];
|
||||
for (i = n = 0; i < UDP_SOCKET_MAX; i++) {
|
||||
if (m_fd[i] >= 0) {
|
||||
pfd[n].fd = m_fd[i];
|
||||
pfd[n].events = POLLIN;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
// no socket descriptor to receive
|
||||
if (n == 0)
|
||||
return 0;
|
||||
|
||||
// Return immediately
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
int ret = WSAPoll(pfd, n, 0);
|
||||
#else
|
||||
int ret = ::poll(pfd, n, 0);
|
||||
#endif
|
||||
if (ret < 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Error returned from UDP poll, err: %lu", ::GetLastError());
|
||||
#else
|
||||
LogError("Error returned from UDP poll, err: %d", errno);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
int index;
|
||||
for (i = 0; i < n; i++) {
|
||||
// round robin
|
||||
index = (i + m_counter) % n;
|
||||
if (pfd[index].revents & POLLIN)
|
||||
break;
|
||||
}
|
||||
if (i == n)
|
||||
return 0;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
int size = sizeof(sockaddr_storage);
|
||||
#else
|
||||
socklen_t size = sizeof(sockaddr_storage);
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
int len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
|
||||
#else
|
||||
ssize_t len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
|
||||
#endif
|
||||
if (len <= 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Error returned from recvfrom, err: %lu", ::GetLastError());
|
||||
#else
|
||||
LogError("Error returned from recvfrom, err: %d", errno);
|
||||
|
||||
if (len == -1 && errno == ENOTSOCK) {
|
||||
LogMessage("Re-opening UDP port on %u", m_port);
|
||||
close();
|
||||
open();
|
||||
}
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_counter++;
|
||||
address_length = size;
|
||||
return len;
|
||||
}
|
||||
|
||||
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
bool result = false;
|
||||
|
||||
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
|
||||
if (m_fd[i] < 0 || m_af[i] != address.ss_family)
|
||||
continue;
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
int ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
|
||||
#else
|
||||
ssize_t ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
|
||||
#endif
|
||||
|
||||
if (ret < 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
LogError("Error returned from sendto, err: %lu", ::GetLastError());
|
||||
#else
|
||||
LogError("Error returned from sendto, err: %d", errno);
|
||||
#endif
|
||||
} else {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (ret == int(length))
|
||||
result = true;
|
||||
#else
|
||||
if (ret == ssize_t(length))
|
||||
result = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CUDPSocket::close()
|
||||
{
|
||||
for (unsigned int i = 0; i < UDP_SOCKET_MAX; i++)
|
||||
close(i);
|
||||
}
|
||||
|
||||
void CUDPSocket::close(const unsigned int index)
|
||||
{
|
||||
if ((index < UDP_SOCKET_MAX) && (m_fd[index] >= 0)) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::closesocket(m_fd[index]);
|
||||
#else
|
||||
::close(m_fd[index]);
|
||||
#endif
|
||||
m_fd[index] = -1;
|
||||
}
|
||||
}
|
@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef UDPSocket_H
|
||||
#define UDPSocket_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
#include <netdb.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#else
|
||||
#include <ws2tcpip.h>
|
||||
#endif
|
||||
|
||||
#if !defined(UDP_SOCKET_MAX)
|
||||
#define UDP_SOCKET_MAX 1
|
||||
#endif
|
||||
|
||||
enum IPMATCHTYPE {
|
||||
IMT_ADDRESS_AND_PORT,
|
||||
IMT_ADDRESS_ONLY
|
||||
};
|
||||
|
||||
class CUDPSocket {
|
||||
public:
|
||||
CUDPSocket(const std::string& address, unsigned int port = 0U);
|
||||
CUDPSocket(unsigned int port = 0U);
|
||||
~CUDPSocket();
|
||||
|
||||
bool open(unsigned int af = AF_UNSPEC);
|
||||
bool open(const sockaddr_storage& address);
|
||||
bool open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port);
|
||||
|
||||
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length);
|
||||
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length);
|
||||
|
||||
void close();
|
||||
void close(const unsigned int index);
|
||||
|
||||
static void startup();
|
||||
static void shutdown();
|
||||
|
||||
static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length);
|
||||
static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length, struct addrinfo& hints);
|
||||
|
||||
static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IMT_ADDRESS_AND_PORT);
|
||||
|
||||
static bool isNone(const sockaddr_storage& addr);
|
||||
|
||||
static char* display(const sockaddr_storage& address, char* buffer, unsigned int length);
|
||||
|
||||
private:
|
||||
std::string m_address_save;
|
||||
unsigned short m_port_save;
|
||||
std::string m_address[UDP_SOCKET_MAX];
|
||||
unsigned short m_port[UDP_SOCKET_MAX];
|
||||
unsigned int m_af[UDP_SOCKET_MAX];
|
||||
int m_fd[UDP_SOCKET_MAX];
|
||||
unsigned int m_counter;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,146 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009,2014,2015,2016 Jonathan Naylor, G4KLX
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
void CUtils::dump(const std::string& title, const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
dump(2U, title, data, length);
|
||||
}
|
||||
|
||||
void CUtils::dump(int level, const std::string& title, const unsigned char* data, unsigned int length)
|
||||
{
|
||||
assert(data != NULL);
|
||||
|
||||
::Log(level, "%s", title.c_str());
|
||||
|
||||
unsigned int offset = 0U;
|
||||
|
||||
while (length > 0U) {
|
||||
std::string output;
|
||||
|
||||
unsigned int bytes = (length > 16U) ? 16U : length;
|
||||
|
||||
for (unsigned i = 0U; i < bytes; i++) {
|
||||
char temp[10U];
|
||||
::sprintf(temp, "%02X ", data[offset + i]);
|
||||
output += temp;
|
||||
}
|
||||
|
||||
for (unsigned int i = bytes; i < 16U; i++)
|
||||
output += " ";
|
||||
|
||||
output += " *";
|
||||
|
||||
for (unsigned i = 0U; i < bytes; i++) {
|
||||
unsigned char c = data[offset + i];
|
||||
|
||||
if (::isprint(c))
|
||||
output += c;
|
||||
else
|
||||
output += '.';
|
||||
}
|
||||
|
||||
output += '*';
|
||||
|
||||
::Log(level, "%04X: %s", offset, output.c_str());
|
||||
|
||||
offset += 16U;
|
||||
|
||||
if (length >= 16U)
|
||||
length -= 16U;
|
||||
else
|
||||
length = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
void CUtils::dump(const std::string& title, const bool* bits, unsigned int length)
|
||||
{
|
||||
assert(bits != NULL);
|
||||
|
||||
dump(2U, title, bits, length);
|
||||
}
|
||||
|
||||
void CUtils::dump(int level, const std::string& title, const bool* bits, unsigned int length)
|
||||
{
|
||||
assert(bits != NULL);
|
||||
|
||||
unsigned char bytes[100U];
|
||||
unsigned int nBytes = 0U;
|
||||
for (unsigned int n = 0U; n < length; n += 8U, nBytes++)
|
||||
bitsToByteBE(bits + n, bytes[nBytes]);
|
||||
|
||||
dump(level, title, bytes, nBytes);
|
||||
}
|
||||
|
||||
void CUtils::byteToBitsBE(unsigned char byte, bool* bits)
|
||||
{
|
||||
assert(bits != NULL);
|
||||
|
||||
bits[0U] = (byte & 0x80U) == 0x80U;
|
||||
bits[1U] = (byte & 0x40U) == 0x40U;
|
||||
bits[2U] = (byte & 0x20U) == 0x20U;
|
||||
bits[3U] = (byte & 0x10U) == 0x10U;
|
||||
bits[4U] = (byte & 0x08U) == 0x08U;
|
||||
bits[5U] = (byte & 0x04U) == 0x04U;
|
||||
bits[6U] = (byte & 0x02U) == 0x02U;
|
||||
bits[7U] = (byte & 0x01U) == 0x01U;
|
||||
}
|
||||
|
||||
void CUtils::byteToBitsLE(unsigned char byte, bool* bits)
|
||||
{
|
||||
assert(bits != NULL);
|
||||
|
||||
bits[0U] = (byte & 0x01U) == 0x01U;
|
||||
bits[1U] = (byte & 0x02U) == 0x02U;
|
||||
bits[2U] = (byte & 0x04U) == 0x04U;
|
||||
bits[3U] = (byte & 0x08U) == 0x08U;
|
||||
bits[4U] = (byte & 0x10U) == 0x10U;
|
||||
bits[5U] = (byte & 0x20U) == 0x20U;
|
||||
bits[6U] = (byte & 0x40U) == 0x40U;
|
||||
bits[7U] = (byte & 0x80U) == 0x80U;
|
||||
}
|
||||
|
||||
void CUtils::bitsToByteBE(const bool* bits, unsigned char& byte)
|
||||
{
|
||||
assert(bits != NULL);
|
||||
|
||||
byte = bits[0U] ? 0x80U : 0x00U;
|
||||
byte |= bits[1U] ? 0x40U : 0x00U;
|
||||
byte |= bits[2U] ? 0x20U : 0x00U;
|
||||
byte |= bits[3U] ? 0x10U : 0x00U;
|
||||
byte |= bits[4U] ? 0x08U : 0x00U;
|
||||
byte |= bits[5U] ? 0x04U : 0x00U;
|
||||
byte |= bits[6U] ? 0x02U : 0x00U;
|
||||
byte |= bits[7U] ? 0x01U : 0x00U;
|
||||
}
|
||||
|
||||
void CUtils::bitsToByteLE(const bool* bits, unsigned char& byte)
|
||||
{
|
||||
assert(bits != NULL);
|
||||
|
||||
byte = bits[0U] ? 0x01U : 0x00U;
|
||||
byte |= bits[1U] ? 0x02U : 0x00U;
|
||||
byte |= bits[2U] ? 0x04U : 0x00U;
|
||||
byte |= bits[3U] ? 0x08U : 0x00U;
|
||||
byte |= bits[4U] ? 0x10U : 0x00U;
|
||||
byte |= bits[5U] ? 0x20U : 0x00U;
|
||||
byte |= bits[6U] ? 0x40U : 0x00U;
|
||||
byte |= bits[7U] ? 0x80U : 0x00U;
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2009,2014,2015 by Jonathan Naylor, G4KLX
|
||||
*
|
||||
* 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; version 2 of the License.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef Utils_H
|
||||
#define Utils_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class CUtils {
|
||||
public:
|
||||
static void dump(const std::string& title, const unsigned char* data, unsigned int length);
|
||||
static void dump(int level, const std::string& title, const unsigned char* data, unsigned int length);
|
||||
|
||||
static void dump(const std::string& title, const bool* bits, unsigned int length);
|
||||
static void dump(int level, const std::string& title, const bool* bits, unsigned int length);
|
||||
|
||||
static void byteToBitsBE(unsigned char byte, bool* bits);
|
||||
static void byteToBitsLE(unsigned char byte, bool* bits);
|
||||
|
||||
static void bitsToByteBE(const bool* bits, unsigned char& byte);
|
||||
static void bitsToByteLE(const bool* bits, unsigned char& byte);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
#endif
|
@ -1,24 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015,2016,2020,2021 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(VERSION_H)
|
||||
#define VERSION_H
|
||||
|
||||
const char* VERSION = "20210824";
|
||||
|
||||
#endif
|
@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(YSFDefines_H)
|
||||
#define YSFDefines_H
|
||||
|
||||
const unsigned int YSF_FRAME_LENGTH_BYTES = 120U;
|
||||
|
||||
const unsigned char YSF_SYNC_BYTES[] = {0xD4U, 0x71U, 0xC9U, 0x63U, 0x4DU};
|
||||
const unsigned int YSF_SYNC_LENGTH_BYTES = 5U;
|
||||
|
||||
const unsigned int YSF_FICH_LENGTH_BYTES = 25U;
|
||||
|
||||
const unsigned char YSF_SYNC_OK = 0x01U;
|
||||
|
||||
const unsigned int YSF_CALLSIGN_LENGTH = 10U;
|
||||
|
||||
const unsigned char YSF_FI_HEADER = 0x00U;
|
||||
const unsigned char YSF_FI_COMMUNICATIONS = 0x01U;
|
||||
const unsigned char YSF_FI_TERMINATOR = 0x02U;
|
||||
const unsigned char YSF_FI_TEST = 0x03U;
|
||||
|
||||
const unsigned char YSF_DT_VD_MODE1 = 0x00U;
|
||||
const unsigned char YSF_DT_DATA_FR_MODE = 0x01U;
|
||||
const unsigned char YSF_DT_VD_MODE2 = 0x02U;
|
||||
const unsigned char YSF_DT_VOICE_FR_MODE = 0x03U;
|
||||
|
||||
const unsigned char YSF_CM_GROUP = 0x00U;
|
||||
const unsigned char YSF_CM_INDIVIDUAL = 0x03U;
|
||||
|
||||
const unsigned char YSF_MR_NOT_BUSY = 0x01U;
|
||||
const unsigned char YSF_MR_BUSY = 0x02U;
|
||||
|
||||
#endif
|
@ -1,375 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016,2018,2020,2021 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "YSFReflector.h"
|
||||
#include "BlockList.h"
|
||||
#include "StopWatch.h"
|
||||
#include "Network.h"
|
||||
#include "Version.h"
|
||||
#include "Thread.h"
|
||||
#include "Log.h"
|
||||
#include "GitVersion.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
const char* DEFAULT_INI_FILE = "YSFReflector.ini";
|
||||
#else
|
||||
const char* DEFAULT_INI_FILE = "/etc/YSFReflector.ini";
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
#include <ctime>
|
||||
#include <cstring>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
const char* iniFile = DEFAULT_INI_FILE;
|
||||
if (argc > 1) {
|
||||
for (int currentArg = 1; currentArg < argc; ++currentArg) {
|
||||
std::string arg = argv[currentArg];
|
||||
if ((arg == "-v") || (arg == "--version")) {
|
||||
::fprintf(stdout, "YSFReflector version %s git #%.7s\n", VERSION, gitversion);
|
||||
return 0;
|
||||
} else if (arg.substr(0, 1) == "-") {
|
||||
::fprintf(stderr, "Usage: YSFReflector [-v|--version] [filename]\n");
|
||||
return 1;
|
||||
} else {
|
||||
iniFile = argv[currentArg];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CYSFReflector* reflector = new CYSFReflector(std::string(iniFile));
|
||||
reflector->run();
|
||||
delete reflector;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CYSFReflector::CYSFReflector(const std::string& file) :
|
||||
m_conf(file),
|
||||
m_repeaters()
|
||||
{
|
||||
CUDPSocket::startup();
|
||||
}
|
||||
|
||||
CYSFReflector::~CYSFReflector()
|
||||
{
|
||||
CUDPSocket::shutdown();
|
||||
}
|
||||
|
||||
void CYSFReflector::run()
|
||||
{
|
||||
bool ret = m_conf.read();
|
||||
if (!ret) {
|
||||
::fprintf(stderr, "YSFReflector: cannot read the .ini file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
bool m_daemon = m_conf.getDaemon();
|
||||
if (m_daemon) {
|
||||
// Create new process
|
||||
pid_t pid = ::fork();
|
||||
if (pid == -1) {
|
||||
::fprintf(stderr, "Couldn't fork() , exiting\n");
|
||||
return;
|
||||
} else if (pid != 0) {
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
// Create new session and process group
|
||||
if (::setsid() == -1) {
|
||||
::fprintf(stderr, "Couldn't setsid(), exiting\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the working directory to the root directory
|
||||
if (::chdir("/") == -1) {
|
||||
::fprintf(stderr, "Couldn't cd /, exiting\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are currently root...
|
||||
if (getuid() == 0) {
|
||||
struct passwd* user = ::getpwnam("mmdvm");
|
||||
if (user == NULL) {
|
||||
::fprintf(stderr, "Could not get the mmdvm user, exiting\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uid_t mmdvm_uid = user->pw_uid;
|
||||
gid_t mmdvm_gid = user->pw_gid;
|
||||
|
||||
// Set user and group ID's to mmdvm:mmdvm
|
||||
if (setgid(mmdvm_gid) != 0) {
|
||||
::fprintf(stderr, "Could not set mmdvm GID, exiting\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (setuid(mmdvm_uid) != 0) {
|
||||
::fprintf(stderr, "Could not set mmdvm UID, exiting\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Double check it worked (AKA Paranoia)
|
||||
if (setuid(0) != -1) {
|
||||
::fprintf(stderr, "It's possible to regain root - something is wrong!, exiting\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
ret = ::LogInitialise(m_daemon, m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel(), m_conf.getLogFileRotate());
|
||||
#else
|
||||
ret = ::LogInitialise(false, m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel(), m_conf.getLogFileRotate());
|
||||
#endif
|
||||
if (!ret) {
|
||||
::fprintf(stderr, "YSFReflector: unable to open the log file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
if (m_daemon) {
|
||||
::close(STDIN_FILENO);
|
||||
::close(STDOUT_FILENO);
|
||||
::close(STDERR_FILENO);
|
||||
}
|
||||
#endif
|
||||
|
||||
CNetwork network(m_conf.getNetworkPort(), m_conf.getId(), m_conf.getName(), m_conf.getDescription(), m_conf.getNetworkDebug());
|
||||
|
||||
ret = network.open();
|
||||
if (!ret) {
|
||||
::LogFinalise();
|
||||
return;
|
||||
}
|
||||
|
||||
CBlockList blockList(m_conf.getBlockListFile(), m_conf.getBlockListTime());
|
||||
blockList.start();
|
||||
|
||||
network.setCount(0);
|
||||
|
||||
CStopWatch stopWatch;
|
||||
stopWatch.start();
|
||||
|
||||
CTimer dumpTimer(1000U, 120U);
|
||||
dumpTimer.start();
|
||||
|
||||
CTimer pollTimer(1000U, 5U);
|
||||
pollTimer.start();
|
||||
|
||||
LogMessage("YSFReflector-%s is starting", VERSION);
|
||||
LogMessage("Built %s %s (GitID #%.7s)", __TIME__, __DATE__, gitversion);
|
||||
|
||||
CTimer watchdogTimer(1000U, 0U, 1500U);
|
||||
|
||||
unsigned char tag[YSF_CALLSIGN_LENGTH];
|
||||
unsigned char src[YSF_CALLSIGN_LENGTH];
|
||||
unsigned char dst[YSF_CALLSIGN_LENGTH];
|
||||
|
||||
bool blocked = false;
|
||||
|
||||
for (;;) {
|
||||
unsigned char buffer[200U];
|
||||
sockaddr_storage addr;
|
||||
unsigned int addrLen;
|
||||
|
||||
unsigned int len = network.readData(buffer, 200U, addr, addrLen);
|
||||
if (len > 0U) {
|
||||
CYSFRepeater* rpt = findRepeater(addr);
|
||||
if (::memcmp(buffer, "YSFP", 4U) == 0) {
|
||||
if (rpt == NULL) {
|
||||
rpt = new CYSFRepeater;
|
||||
rpt->m_callsign = std::string((char*)(buffer + 4U), 10U);
|
||||
::memcpy(&rpt->m_addr, &addr, sizeof(struct sockaddr_storage));
|
||||
rpt->m_addrLen = addrLen;
|
||||
m_repeaters.push_back(rpt);
|
||||
network.setCount(m_repeaters.size());
|
||||
|
||||
char buff[80U];
|
||||
LogMessage("Adding %s (%s)", rpt->m_callsign.c_str(), CUDPSocket::display(addr, buff, 80U));
|
||||
}
|
||||
rpt->m_timer.start();
|
||||
network.writePoll(addr, addrLen);
|
||||
} else if (::memcmp(buffer + 0U, "YSFU", 4U) == 0 && rpt != NULL) {
|
||||
char buff[80U];
|
||||
LogMessage("Removing %s (%s) unlinked", rpt->m_callsign.c_str(), CUDPSocket::display(addr, buff, 80U));
|
||||
|
||||
for (std::vector<CYSFRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||
if (CUDPSocket::match((*it)->m_addr, rpt->m_addr)) {
|
||||
delete *it;
|
||||
m_repeaters.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
network.setCount(m_repeaters.size());
|
||||
} else if (::memcmp(buffer + 0U, "YSFD", 4U) == 0 && rpt != NULL) {
|
||||
if (!watchdogTimer.isRunning()) {
|
||||
::memcpy(tag, buffer + 4U, YSF_CALLSIGN_LENGTH);
|
||||
|
||||
if (::memcmp(buffer + 14U, " ", YSF_CALLSIGN_LENGTH) != 0)
|
||||
::memcpy(src, buffer + 14U, YSF_CALLSIGN_LENGTH);
|
||||
else
|
||||
::memcpy(src, "??????????", YSF_CALLSIGN_LENGTH);
|
||||
|
||||
if (::memcmp(buffer + 24U, " ", YSF_CALLSIGN_LENGTH) != 0)
|
||||
::memcpy(dst, buffer + 24U, YSF_CALLSIGN_LENGTH);
|
||||
else
|
||||
::memcpy(dst, "??????????", YSF_CALLSIGN_LENGTH);
|
||||
|
||||
blocked = blockList.check(src);
|
||||
if (blocked)
|
||||
LogMessage("Data from %10.10s at %10.10s blocked", src, tag);
|
||||
else
|
||||
LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, tag);
|
||||
} else {
|
||||
if (::memcmp(tag, buffer + 4U, YSF_CALLSIGN_LENGTH) == 0) {
|
||||
bool changed = false;
|
||||
|
||||
if (::memcmp(buffer + 14U, " ", YSF_CALLSIGN_LENGTH) != 0 && ::memcmp(src, "??????????", YSF_CALLSIGN_LENGTH) == 0) {
|
||||
::memcpy(src, buffer + 14U, YSF_CALLSIGN_LENGTH);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (::memcmp(buffer + 24U, " ", YSF_CALLSIGN_LENGTH) != 0 && ::memcmp(dst, "??????????", YSF_CALLSIGN_LENGTH) == 0) {
|
||||
::memcpy(dst, buffer + 24U, YSF_CALLSIGN_LENGTH);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
blocked = blockList.check(src);
|
||||
if (blocked)
|
||||
LogMessage("Data from %10.10s at %10.10s blocked", src, tag);
|
||||
else
|
||||
LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!blocked) {
|
||||
watchdogTimer.start();
|
||||
|
||||
for (std::vector<CYSFRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||
if (!CUDPSocket::match((*it)->m_addr, addr))
|
||||
network.writeData(buffer, (*it)->m_addr, (*it)->m_addrLen);
|
||||
}
|
||||
|
||||
if ((buffer[34U] & 0x01U) == 0x01U) {
|
||||
LogMessage("Received end of transmission");
|
||||
watchdogTimer.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int ms = stopWatch.elapsed();
|
||||
stopWatch.start();
|
||||
|
||||
pollTimer.clock(ms);
|
||||
if (pollTimer.hasExpired()) {
|
||||
for (std::vector<CYSFRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it)
|
||||
network.writePoll((*it)->m_addr, (*it)->m_addrLen);
|
||||
pollTimer.start();
|
||||
}
|
||||
|
||||
// Remove any repeaters that haven't reported for a while
|
||||
for (std::vector<CYSFRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it)
|
||||
(*it)->m_timer.clock(ms);
|
||||
|
||||
for (std::vector<CYSFRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||
if ((*it)->m_timer.hasExpired()) {
|
||||
char buff[80U];
|
||||
LogMessage("Removing %s (%s) disappeared", (*it)->m_callsign.c_str(),
|
||||
CUDPSocket::display((*it)->m_addr, buff, 80U));
|
||||
|
||||
delete *it;
|
||||
m_repeaters.erase(it);
|
||||
network.setCount(m_repeaters.size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
watchdogTimer.clock(ms);
|
||||
if (watchdogTimer.isRunning() && watchdogTimer.hasExpired()) {
|
||||
LogMessage("Network watchdog has expired");
|
||||
watchdogTimer.stop();
|
||||
}
|
||||
|
||||
dumpTimer.clock(ms);
|
||||
if (dumpTimer.hasExpired()) {
|
||||
dumpRepeaters();
|
||||
dumpTimer.start();
|
||||
}
|
||||
|
||||
blockList.clock(ms);
|
||||
|
||||
if (ms < 5U)
|
||||
CThread::sleep(5U);
|
||||
}
|
||||
|
||||
network.close();
|
||||
|
||||
::LogFinalise();
|
||||
}
|
||||
|
||||
CYSFRepeater* CYSFReflector::findRepeater(const sockaddr_storage& addr) const
|
||||
{
|
||||
for (std::vector<CYSFRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||
if (CUDPSocket::match(addr, (*it)->m_addr))
|
||||
return *it;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CYSFReflector::dumpRepeaters() const
|
||||
{
|
||||
if (m_repeaters.size() == 0U) {
|
||||
LogMessage("No repeaters/gateways linked");
|
||||
return;
|
||||
}
|
||||
|
||||
LogMessage("Currently linked repeaters/gateways:");
|
||||
|
||||
for (std::vector<CYSFRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||
char buffer[80U];
|
||||
LogMessage(" %s: %s %u/%u", (*it)->m_callsign.c_str(),
|
||||
CUDPSocket::display((*it)->m_addr, buffer, 80U),
|
||||
(*it)->m_timer.getTimer(),
|
||||
(*it)->m_timer.getTimeout());
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016,2020 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#if !defined(YSFReflector_H)
|
||||
#define YSFReflector_H
|
||||
|
||||
#include "Timer.h"
|
||||
#include "Conf.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if !defined(_WIN32) && !defined(_WIN64)
|
||||
#include <netdb.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#else
|
||||
#include <WS2tcpip.h>
|
||||
#endif
|
||||
|
||||
class CYSFRepeater {
|
||||
public:
|
||||
CYSFRepeater() :
|
||||
m_callsign(),
|
||||
m_addr(),
|
||||
m_addrLen(0U),
|
||||
m_timer(1000U, 60U)
|
||||
{
|
||||
}
|
||||
|
||||
std::string m_callsign;
|
||||
sockaddr_storage m_addr;
|
||||
unsigned int m_addrLen;
|
||||
CTimer m_timer;
|
||||
};
|
||||
|
||||
class CYSFReflector
|
||||
{
|
||||
public:
|
||||
CYSFReflector(const std::string& file);
|
||||
~CYSFReflector();
|
||||
|
||||
void run();
|
||||
|
||||
private:
|
||||
CConf m_conf;
|
||||
std::vector<CYSFRepeater*> m_repeaters;
|
||||
|
||||
CYSFRepeater* findRepeater(const sockaddr_storage& addr) const;
|
||||
void dumpRepeaters() const;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,25 +0,0 @@
|
||||
[General]
|
||||
Daemon=1
|
||||
|
||||
[Info]
|
||||
# Remember to register your YSFReflector at:
|
||||
# https://register.ysfreflector.de
|
||||
# Id=5 digits only
|
||||
Name=16 characters max
|
||||
Description=14 characters max
|
||||
|
||||
[Log]
|
||||
# Logging levels, 0=No logging
|
||||
DisplayLevel=1
|
||||
FileLevel=1
|
||||
FilePath=.
|
||||
FileRoot=YSFReflector
|
||||
FileRotate=1
|
||||
|
||||
[Network]
|
||||
Port=42000
|
||||
Debug=0
|
||||
|
||||
[Block List]
|
||||
File=BlockList.txt
|
||||
Time=5
|
@ -1,76 +0,0 @@
|
||||
#!/bin/bash
|
||||
### BEGIN INIT INFO
|
||||
#
|
||||
# Provides: YSFReflector
|
||||
# Required-Start: $all
|
||||
# Required-Stop:
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Example startscript YSFReflector
|
||||
|
||||
#
|
||||
### END INIT INFO
|
||||
## Fill in name of program here.
|
||||
PROG="YSFReflector"
|
||||
PROG_PATH="/usr/local/bin/"
|
||||
PROG_ARGS="/etc/YSFReflector.ini"
|
||||
PIDFILE="/var/run/YSFReflector.pid"
|
||||
USER="root"
|
||||
|
||||
start() {
|
||||
if [ -e $PIDFILE ]; then
|
||||
## Program is running, exit with error.
|
||||
echo "Error! $PROG is currently running!" 1>&2
|
||||
exit 1
|
||||
else
|
||||
cd $PROG_PATH
|
||||
./$PROG $PROG_ARGS
|
||||
echo "$PROG started"
|
||||
touch $PIDFILE
|
||||
fi
|
||||
}
|
||||
|
||||
stop() {
|
||||
if [ -e $PIDFILE ]; then
|
||||
## Program is running, so stop it
|
||||
echo "$PROG is running"
|
||||
rm -f $PIDFILE
|
||||
killall $PROG
|
||||
echo "$PROG stopped"
|
||||
else
|
||||
## Program is not running, exit with error.
|
||||
echo "Error! $PROG not started!" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
## Check to see if we are running as root first.
|
||||
## Found at
|
||||
## http://www.cyberciti.biz/tips/shell-root-user-check-script.html
|
||||
if [ "$(id -u)" != "0" ]; then
|
||||
echo "This script must be run as root" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
exit 0
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
exit 0
|
||||
;;
|
||||
reload|restart|force-reload)
|
||||
stop
|
||||
sleep 5
|
||||
start
|
||||
exit 0
|
||||
;;
|
||||
**)
|
||||
echo "Usage: $0 {start|stop|reload}" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
### END
|
@ -1,83 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Network.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Timer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="UDPSocket.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Utils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="YSFDefines.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="YSFReflector.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="StopWatch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Version.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Log.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Conf.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Thread.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BlockList.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Network.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Timer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="UDPSocket.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Utils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="YSFReflector.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="StopWatch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Log.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Conf.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Thread.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BlockList.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -1,29 +0,0 @@
|
||||
FROM debian:buster-slim AS builder
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y build-essential git
|
||||
|
||||
RUN mkdir /code && \
|
||||
git clone https://github.com/g4klx/YSFClients.git /code && \
|
||||
cd /code/YSFReflector/ && \
|
||||
make clean all
|
||||
|
||||
FROM debian:buster-slim
|
||||
|
||||
ENV REFLECTOR_NAME set_me
|
||||
ENV REFLECTOR_DESCRIPTION set_me
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y procps && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
|
||||
mkdir /app
|
||||
|
||||
COPY --from=builder /code/YSFReflector/YSFReflector.ini /app/YSFReflector.ini
|
||||
COPY --from=builder /code/YSFReflector/YSFReflector /app/YSFReflector
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
|
||||
EXPOSE 42000/udp
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["/app/YSFReflector", "/app/YSFReflector.ini"]
|
||||
HEALTHCHECK CMD ps aux | grep [Y]SFReflector || exit 1
|
@ -1,25 +0,0 @@
|
||||
# YSFReflector Docker Image
|
||||
|
||||
The `Dockerfile` here is intended to produce an image which will be stored on [Docker Hub](https://hub.docker.com/).
|
||||
|
||||
# Requirements
|
||||
|
||||
* [Docker](https://docs.docker.com/install/)
|
||||
* Firewall setup to accept 42000 (UDP)
|
||||
|
||||
# Usage
|
||||
|
||||
`docker run -e REFLECTOR_NAME=YOUR_NAME_HERE -eREFLECTOR_DESCRIPTION=YOUR_DESCRIPTION_HERE -p 42000:42000/udp neilbartley/ysfreflector:latest`
|
||||
|
||||
# How to build
|
||||
|
||||
Building isn't required unless you need a newer image or have made changes.
|
||||
|
||||
```
|
||||
cd YSFReflector/docker
|
||||
YSF_TAG=$(date +'%Y%m%d')-$(git rev-parse --short HEAD)
|
||||
docker build --rm -t neilbartley/ysfreflector:$YSF_TAG .
|
||||
docker tag neilbartley/ysfreflector:$YSF_TAG neilbartley/ysfreflector:latest
|
||||
docker push neilbartley/ysfreflector:$YSF_TAG
|
||||
docker push neilbartley/ysfreflector:latest
|
||||
```
|
@ -1,18 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Disable daemon mode
|
||||
sed -i -e "s/Daemon=1/Daemon=0/g" /app/YSFReflector.ini
|
||||
|
||||
# Reflector name and description validation
|
||||
if [ "${REFLECTOR_NAME}" == "set_me" ] ; then echo "Please set REFLECTOR_NAME environment variable with -e (max 16 characters)"; exit 1 ; fi
|
||||
if [ ${#REFLECTOR_NAME} -gt 16 ] ; then echo "REFLECTOR_NAME environment variable can be at most 16 characters"; exit 1 ; fi
|
||||
if [ "${REFLECTOR_DESCRIPTION}" == "set_me" ] ; then echo "Please set REFLECTOR_DESCRIPTION environment variable with -e (min 14 characters)"; exit 1 ; fi
|
||||
if [ ${#REFLECTOR_DESCRIPTION} -gt 14 ] ; then echo "REFLECTOR_DESCRIPTION environment variable can be at most 14 characters"; exit 1 ; fi
|
||||
|
||||
# Reflector name and description replacement in config file
|
||||
sed -i -e "s/Name=.*/Name=${REFLECTOR_NAME}/g" /app/YSFReflector.ini
|
||||
sed -i -e "s/Description=.*/Description=${REFLECTOR_DESCRIPTION}/g" /app/YSFReflector.ini
|
||||
|
||||
echo "Remember to register your YSFReflector at: https://register.ysfreflector.de"
|
||||
|
||||
exec "$@"
|
Loading…
Reference in new issue