Upgrade the YSF reflector protocol and use a new .ini file.
This commit is contained in:
parent
f137449ae6
commit
79e006d4b9
15 changed files with 631 additions and 95 deletions
|
@ -7,6 +7,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "YSFParrot", "YSFParrot\YSFP
|
|||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "YSFReflector", "YSFReflector\YSFReflector.vcxproj", "{317D87F1-3485-4739-9F94-A07738B8E19D}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "YSFGateway", "YSFGateway\YSFGateway.vcxproj", "{4F82857B-D2CC-48DC-91A8-6275BDD3081B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
|
@ -31,6 +33,14 @@ Global
|
|||
{317D87F1-3485-4739-9F94-A07738B8E19D}.Release|x64.Build.0 = Release|x64
|
||||
{317D87F1-3485-4739-9F94-A07738B8E19D}.Release|x86.ActiveCfg = Release|Win32
|
||||
{317D87F1-3485-4739-9F94-A07738B8E19D}.Release|x86.Build.0 = Release|Win32
|
||||
{4F82857B-D2CC-48DC-91A8-6275BDD3081B}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4F82857B-D2CC-48DC-91A8-6275BDD3081B}.Debug|x64.Build.0 = Debug|x64
|
||||
{4F82857B-D2CC-48DC-91A8-6275BDD3081B}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{4F82857B-D2CC-48DC-91A8-6275BDD3081B}.Debug|x86.Build.0 = Debug|Win32
|
||||
{4F82857B-D2CC-48DC-91A8-6275BDD3081B}.Release|x64.ActiveCfg = Release|x64
|
||||
{4F82857B-D2CC-48DC-91A8-6275BDD3081B}.Release|x64.Build.0 = Release|x64
|
||||
{4F82857B-D2CC-48DC-91A8-6275BDD3081B}.Release|x86.ActiveCfg = Release|Win32
|
||||
{4F82857B-D2CC-48DC-91A8-6275BDD3081B}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
163
YSFReflector/Conf.cpp
Normal file
163
YSFReflector/Conf.cpp
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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
|
||||
};
|
||||
|
||||
CConf::CConf(const std::string& file) :
|
||||
m_file(file),
|
||||
m_daemon(false),
|
||||
m_name(),
|
||||
m_description(),
|
||||
m_logDisplayLevel(0U),
|
||||
m_logFileLevel(0U),
|
||||
m_logFilePath(),
|
||||
m_logFileRoot(),
|
||||
m_networkPort(0U),
|
||||
m_networkDebug(false)
|
||||
{
|
||||
}
|
||||
|
||||
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
|
||||
section = SECTION_NONE;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
char* key = ::strtok(buffer, " \t=\r\n");
|
||||
if (key == NULL)
|
||||
continue;
|
||||
|
||||
char* value = ::strtok(NULL, "\r\n");
|
||||
if (section == SECTION_GENERAL) {
|
||||
if (::strcmp(key, "Daemon") == 0)
|
||||
m_daemon = ::atoi(value) == 1;
|
||||
} else if (section == SECTION_INFO) {
|
||||
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 (section == SECTION_NETWORK) {
|
||||
if (::strcmp(key, "Port") == 0)
|
||||
m_networkPort = (unsigned int)::atoi(value);
|
||||
else if (::strcmp(key, "Debug") == 0)
|
||||
m_networkDebug = ::atoi(value) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
::fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConf::getDaemon() const
|
||||
{
|
||||
return m_daemon;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
unsigned int CConf::getNetworkPort() const
|
||||
{
|
||||
return m_networkPort;
|
||||
}
|
||||
|
||||
bool CConf::getNetworkDebug() const
|
||||
{
|
||||
return m_networkDebug;
|
||||
}
|
66
YSFReflector/Conf.h
Normal file
66
YSFReflector/Conf.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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(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
|
||||
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;
|
||||
|
||||
// The Network section
|
||||
unsigned int getNetworkPort() const;
|
||||
bool getNetworkDebug() const;
|
||||
|
||||
private:
|
||||
std::string m_file;
|
||||
bool m_daemon;
|
||||
|
||||
std::string m_name;
|
||||
std::string m_description;
|
||||
|
||||
unsigned int m_logDisplayLevel;
|
||||
unsigned int m_logFileLevel;
|
||||
std::string m_logFilePath;
|
||||
std::string m_logFileRoot;
|
||||
|
||||
unsigned int m_networkPort;
|
||||
bool m_networkDebug;
|
||||
};
|
||||
|
||||
#endif
|
136
YSFReflector/Log.cpp
Normal file
136
YSFReflector/Log.cpp
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "Log.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <sys/time.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 FILE* m_fpLog = NULL;
|
||||
|
||||
static unsigned int m_displayLevel = 2U;
|
||||
|
||||
static struct tm m_tm;
|
||||
|
||||
static char LEVELS[] = " DMIWEF";
|
||||
|
||||
static bool LogOpen()
|
||||
{
|
||||
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[50U];
|
||||
#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
|
||||
|
||||
m_fpLog = ::fopen(filename, "a+t");
|
||||
m_tm = *tm;
|
||||
|
||||
return m_fpLog != NULL;
|
||||
}
|
||||
|
||||
bool LogInitialise(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel)
|
||||
{
|
||||
m_filePath = filePath;
|
||||
m_fileRoot = fileRoot;
|
||||
m_fileLevel = fileLevel;
|
||||
m_displayLevel = displayLevel;
|
||||
return ::LogOpen();
|
||||
}
|
||||
|
||||
void LogFinalise()
|
||||
{
|
||||
if (m_fpLog != NULL)
|
||||
::fclose(m_fpLog);
|
||||
}
|
||||
|
||||
void Log(unsigned int level, const char* fmt, ...)
|
||||
{
|
||||
assert(fmt != NULL);
|
||||
|
||||
char buffer[300U];
|
||||
#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.%03lu ", 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 / 1000U);
|
||||
#endif
|
||||
|
||||
va_list vl;
|
||||
va_start(vl, fmt);
|
||||
|
||||
::vsprintf(buffer + ::strlen(buffer), 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);
|
||||
}
|
||||
}
|
36
YSFReflector/Log.h
Normal file
36
YSFReflector/Log.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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(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(const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel);
|
||||
extern void LogFinalise();
|
||||
|
||||
#endif
|
|
@ -4,7 +4,7 @@ CFLAGS = -g -O3 -Wall -std=c++0x
|
|||
LIBS =
|
||||
LDFLAGS = -g
|
||||
|
||||
OBJECTS = Network.o StopWatch.o Timer.o UDPSocket.o Utils.o YSFReflector.o
|
||||
OBJECTS = Conf.o Log.o Network.o StopWatch.o Timer.o UDPSocket.o Utils.o YSFReflector.o
|
||||
|
||||
all: YSFReflector
|
||||
|
||||
|
|
|
@ -26,18 +26,26 @@
|
|||
|
||||
const unsigned int BUFFER_LENGTH = 200U;
|
||||
|
||||
CNetwork::CNetwork(unsigned int port, bool debug) :
|
||||
CNetwork::CNetwork(unsigned int port, const std::string& name, const std::string& description, bool debug) :
|
||||
m_socket(port),
|
||||
m_name(name),
|
||||
m_description(description),
|
||||
m_address(),
|
||||
m_port(0U),
|
||||
m_callsign(),
|
||||
m_debug(debug),
|
||||
m_buffer(1000U, "YSF Network")
|
||||
m_buffer(1000U, "YSF Network"),
|
||||
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()
|
||||
|
@ -101,6 +109,12 @@ void CNetwork::clock(unsigned int ms)
|
|||
return;
|
||||
}
|
||||
|
||||
// Handle incoming status requests
|
||||
if (::memcmp(buffer, "YSFS", 4U) == 0) {
|
||||
m_socket.write(m_status, 42U, address, port);
|
||||
return;
|
||||
}
|
||||
|
||||
// Invalid packet type?
|
||||
if (::memcmp(buffer, "YSFD", 4U) != 0)
|
||||
return;
|
||||
|
@ -142,6 +156,33 @@ bool CNetwork::readPoll(std::string& callsign, in_addr& address, unsigned int& p
|
|||
return true;
|
||||
}
|
||||
|
||||
void CNetwork::setCount(unsigned int count)
|
||||
{
|
||||
if (count > 999U)
|
||||
count = 999U;
|
||||
|
||||
unsigned int hash = 0U;
|
||||
|
||||
for (unsigned int i = 0U; i < m_name.size(); i++) {
|
||||
hash += m_name.at(i);
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0U; i < m_description.size(); i++) {
|
||||
hash += m_description.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();
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
class CNetwork {
|
||||
public:
|
||||
CNetwork(unsigned int port, bool debug);
|
||||
CNetwork(unsigned int port, const std::string& name, const std::string& description, bool debug);
|
||||
~CNetwork();
|
||||
|
||||
bool open();
|
||||
|
@ -44,13 +44,18 @@ public:
|
|||
|
||||
void clock(unsigned int ms);
|
||||
|
||||
void setCount(unsigned int count);
|
||||
|
||||
private:
|
||||
CUDPSocket m_socket;
|
||||
std::string m_name;
|
||||
std::string m_description;
|
||||
in_addr m_address;
|
||||
unsigned int m_port;
|
||||
std::string m_callsign;
|
||||
bool m_debug;
|
||||
CRingBuffer<unsigned char> m_buffer;
|
||||
unsigned char* m_status;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
*/
|
||||
|
||||
#include "UDPSocket.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
|
@ -37,7 +38,7 @@ m_fd(-1)
|
|||
WSAData data;
|
||||
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
|
||||
if (wsaRet != 0)
|
||||
::fprintf(stderr, "Error from WSAStartup\n");
|
||||
LogError("Error from WSAStartup");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -50,7 +51,7 @@ m_fd(-1)
|
|||
WSAData data;
|
||||
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
|
||||
if (wsaRet != 0)
|
||||
::fprintf(stderr, "Error from WSAStartup\n");
|
||||
LogError("Error from WSAStartup");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -77,7 +78,7 @@ in_addr CUDPSocket::lookup(const std::string& hostname)
|
|||
return addr;
|
||||
}
|
||||
|
||||
::fprintf(stderr, "Cannot find address for host %s\n", hostname.c_str());
|
||||
LogError("Cannot find address for host %s", hostname.c_str());
|
||||
|
||||
addr.s_addr = INADDR_NONE;
|
||||
return addr;
|
||||
|
@ -94,7 +95,7 @@ in_addr CUDPSocket::lookup(const std::string& hostname)
|
|||
return addr;
|
||||
}
|
||||
|
||||
::fprintf(stderr, "Cannot find address for host %s\n", hostname.c_str());
|
||||
LogError("Cannot find address for host %s", hostname.c_str());
|
||||
|
||||
addr.s_addr = INADDR_NONE;
|
||||
return addr;
|
||||
|
@ -106,9 +107,9 @@ bool CUDPSocket::open()
|
|||
m_fd = ::socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (m_fd < 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::fprintf(stderr, "Cannot create the UDP socket, err: %lu\n", ::GetLastError());
|
||||
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
|
||||
#else
|
||||
::fprintf(stderr, "Cannot create the UDP socket, err: %d\n", errno);
|
||||
LogError("Cannot create the UDP socket, err: %d", errno);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
@ -127,7 +128,7 @@ bool CUDPSocket::open()
|
|||
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
|
||||
#endif
|
||||
if (addr.sin_addr.s_addr == INADDR_NONE) {
|
||||
::fprintf(stderr, "The local address is invalid - %s\n", m_address.c_str());
|
||||
LogError("The local address is invalid - %s", m_address.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -135,18 +136,18 @@ bool CUDPSocket::open()
|
|||
int reuse = 1;
|
||||
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::fprintf(stderr, "Cannot set the UDP socket option, err: %lu\n", ::GetLastError());
|
||||
LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError());
|
||||
#else
|
||||
::fprintf(stderr, "Cannot set the UDP socket option, err: %d\n", errno);
|
||||
LogError("Cannot set the UDP socket option, err: %d", errno);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::bind(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -1) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::fprintf(stderr, "Cannot bind the UDP address, err: %lu\n", ::GetLastError());
|
||||
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
|
||||
#else
|
||||
::fprintf(stderr, "Cannot bind the UDP address, err: %d\n", errno);
|
||||
LogError("Cannot bind the UDP address, err: %d", errno);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
@ -177,9 +178,9 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& addres
|
|||
int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv);
|
||||
if (ret < 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::fprintf(stderr, "Error returned from UDP select, err: %lu\n", ::GetLastError());
|
||||
LogError("Error returned from UDP select, err: %lu", ::GetLastError());
|
||||
#else
|
||||
::fprintf(stderr, "Error returned from UDP select, err: %d\n", errno);
|
||||
LogError("Error returned from UDP select, err: %d", errno);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
@ -201,9 +202,9 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& addres
|
|||
#endif
|
||||
if (len <= 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::fprintf(stderr, "Error returned from recvfrom, err: %lu\n", ::GetLastError());
|
||||
LogError("Error returned from recvfrom, err: %lu", ::GetLastError());
|
||||
#else
|
||||
::fprintf(stderr, "Error returned from recvfrom, err: %d\n", errno);
|
||||
LogError("Error returned from recvfrom, err: %d", errno);
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
@ -233,9 +234,9 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const i
|
|||
#endif
|
||||
if (ret < 0) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::fprintf(stderr, "Error returned from sendto, err: %lu\n", ::GetLastError());
|
||||
LogError("Error returned from sendto, err: %lu", ::GetLastError());
|
||||
#else
|
||||
::fprintf(stderr, "Error returned from sendto, err: %d\n", errno);
|
||||
LogError("Error returned from sendto, err: %d", errno);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
*/
|
||||
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
@ -27,7 +28,7 @@ void CUtils::dump(int level, const std::string& title, const unsigned char* data
|
|||
{
|
||||
assert(data != NULL);
|
||||
|
||||
::fprintf(stdout, "%s\n", title.c_str());
|
||||
::Log(level, "%s", title.c_str());
|
||||
|
||||
unsigned int offset = 0U;
|
||||
|
||||
|
@ -58,7 +59,7 @@ void CUtils::dump(int level, const std::string& title, const unsigned char* data
|
|||
|
||||
output += '*';
|
||||
|
||||
::fprintf(stdout, "%04X: %s\n", offset, output.c_str());
|
||||
::Log(level, "%04X: %s", offset, output.c_str());
|
||||
|
||||
offset += 16U;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "StopWatch.h"
|
||||
#include "Network.h"
|
||||
#include "Version.h"
|
||||
#include "Log.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <Windows.h>
|
||||
|
@ -27,6 +28,12 @@
|
|||
#include <sys/time.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 <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
|
@ -35,39 +42,34 @@
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc == 1) {
|
||||
::fprintf(stderr, "Usage: YSFReflector <port> [log file]\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned int port = ::atoi(argv[1]);
|
||||
if (port == 0U) {
|
||||
::fprintf(stderr, "YSFReflector: invalid port number\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE* fp = NULL;
|
||||
if (argc > 2) {
|
||||
fp = ::fopen(argv[2], "wt");
|
||||
if (fp == NULL) {
|
||||
::fprintf(stderr, "YSFReflector: cannot open the logging file - %s\n", argv[2]);
|
||||
return 1;
|
||||
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\n", VERSION);
|
||||
return 0;
|
||||
}
|
||||
else if (arg.substr(0, 1) == "-") {
|
||||
::fprintf(stderr, "Usage: YSFReflector [-v|--version] [filename]\n");
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
iniFile = argv[currentArg];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CYSFReflector Reflector(port, fp);
|
||||
Reflector.run();
|
||||
|
||||
if (fp != NULL)
|
||||
::fclose(fp);
|
||||
CYSFReflector* reflector = new CYSFReflector(std::string(iniFile));
|
||||
reflector->run();
|
||||
delete reflector;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CYSFReflector::CYSFReflector(unsigned int port, FILE* fp) :
|
||||
m_port(port),
|
||||
m_repeaters(),
|
||||
m_fp(fp)
|
||||
CYSFReflector::CYSFReflector(const std::string& file) :
|
||||
m_conf(file),
|
||||
m_repeaters()
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -77,9 +79,80 @@ CYSFReflector::~CYSFReflector()
|
|||
|
||||
void CYSFReflector::run()
|
||||
{
|
||||
CNetwork network(m_port, false);
|
||||
bool ret = m_conf.read();
|
||||
if (!ret) {
|
||||
::fprintf(stderr, "YSFRefector: cannot read the .ini file\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bool ret = network.open();
|
||||
ret = ::LogInitialise(m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel());
|
||||
if (!ret) {
|
||||
::fprintf(stderr, "YSFReflector: unable to open the log 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) {
|
||||
::LogWarning("Couldn't fork() , exiting");
|
||||
return -1;
|
||||
}
|
||||
else if (pid != 0)
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
// Create new session and process group
|
||||
if (::setsid() == -1) {
|
||||
::LogWarning("Couldn't setsid(), exiting");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set the working directory to the root directory
|
||||
if (::chdir("/") == -1) {
|
||||
::LogWarning("Couldn't cd /, exiting");
|
||||
return -1;
|
||||
}
|
||||
|
||||
::close(STDIN_FILENO);
|
||||
::close(STDOUT_FILENO);
|
||||
::close(STDERR_FILENO);
|
||||
|
||||
//If we are currently root...
|
||||
if (getuid() == 0) {
|
||||
struct passwd* user = ::getpwnam("mmdvm");
|
||||
if (user == NULL) {
|
||||
::LogError("Could not get the mmdvm user, exiting");
|
||||
return -1;
|
||||
}
|
||||
|
||||
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) {
|
||||
::LogWarning("Could not set mmdvm GID, exiting");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (setuid(mmdvm_uid) != 0) {
|
||||
::LogWarning("Could not set mmdvm UID, exiting");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//Double check it worked (AKA Paranoia)
|
||||
if (setuid(0) != -1) {
|
||||
::LogWarning("It's possible to regain root - something is wrong!, exiting");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
CNetwork network(m_conf.getNetworkPort(), m_conf.getName(), m_conf.getDescription(), m_conf.getNetworkDebug());
|
||||
|
||||
ret = network.open();
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
|
@ -89,7 +162,7 @@ void CYSFReflector::run()
|
|||
CTimer pollTimer(1000U, 5U);
|
||||
pollTimer.start();
|
||||
|
||||
log("Starting YSFReflector-%s", VERSION);
|
||||
LogMessage("Starting YSFReflector-%s", VERSION);
|
||||
|
||||
CTimer watchdogTimer(1000U, 0U, 1500U);
|
||||
|
||||
|
@ -115,7 +188,7 @@ void CYSFReflector::run()
|
|||
else
|
||||
::memcpy(dst, "??????????", YSF_CALLSIGN_LENGTH);
|
||||
|
||||
log("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U);
|
||||
LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U);
|
||||
} else {
|
||||
if (::memcmp(tag, buffer + 4U, YSF_CALLSIGN_LENGTH) == 0) {
|
||||
bool changed = false;
|
||||
|
@ -131,7 +204,7 @@ void CYSFReflector::run()
|
|||
}
|
||||
|
||||
if (changed)
|
||||
log("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U);
|
||||
LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +222,7 @@ void CYSFReflector::run()
|
|||
}
|
||||
|
||||
if (buffer[34U] == 0x01U) {
|
||||
log("Received end of transmission");
|
||||
LogMessage("Received end of transmission");
|
||||
watchdogTimer.stop();
|
||||
}
|
||||
}
|
||||
|
@ -163,13 +236,14 @@ void CYSFReflector::run()
|
|||
if (ret) {
|
||||
CYSFRepeater* rpt = findRepeater(callsign);
|
||||
if (rpt == NULL) {
|
||||
log("Adding %s", callsign.c_str());
|
||||
LogMessage("Adding %s", callsign.c_str());
|
||||
rpt = new CYSFRepeater;
|
||||
rpt->m_timer.start();
|
||||
rpt->m_callsign = callsign;
|
||||
rpt->m_address = address;
|
||||
rpt->m_port = port;
|
||||
m_repeaters.push_back(rpt);
|
||||
network.setCount(m_repeaters.size());
|
||||
} else {
|
||||
rpt->m_timer.start();
|
||||
rpt->m_address = address;
|
||||
|
@ -195,15 +269,16 @@ void CYSFReflector::run()
|
|||
|
||||
for (std::vector<CYSFRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||
if ((*it)->m_timer.hasExpired()) {
|
||||
log("Removing %s", (*it)->m_callsign.c_str());
|
||||
LogMessage("Removing %s", (*it)->m_callsign.c_str());
|
||||
m_repeaters.erase(it);
|
||||
network.setCount(m_repeaters.size());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
watchdogTimer.clock(ms);
|
||||
if (watchdogTimer.isRunning() && watchdogTimer.hasExpired()) {
|
||||
log("Network watchdog has expired");
|
||||
LogMessage("Network watchdog has expired");
|
||||
watchdogTimer.stop();
|
||||
}
|
||||
|
||||
|
@ -217,6 +292,8 @@ void CYSFReflector::run()
|
|||
}
|
||||
|
||||
network.close();
|
||||
|
||||
::LogFinalise();
|
||||
}
|
||||
|
||||
CYSFRepeater* CYSFReflector::findRepeater(const std::string& callsign) const
|
||||
|
@ -228,36 +305,3 @@ CYSFRepeater* CYSFReflector::findRepeater(const std::string& callsign) const
|
|||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CYSFReflector::log(const char* text, ...)
|
||||
{
|
||||
char buffer[300U];
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
SYSTEMTIME st;
|
||||
::GetSystemTime(&st);
|
||||
|
||||
::sprintf(buffer, "%04u-%02u-%02u %02u:%02u:%02u ", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
|
||||
#else
|
||||
struct timeval now;
|
||||
::gettimeofday(&now, NULL);
|
||||
|
||||
struct tm* tm = ::gmtime(&now.tv_sec);
|
||||
|
||||
::sprintf(buffer, "%04d-%02d-%02d %02d:%02d:%02d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
#endif
|
||||
|
||||
va_list vl;
|
||||
va_start(vl, text);
|
||||
|
||||
::vsprintf(buffer + ::strlen(buffer), text, vl);
|
||||
|
||||
va_end(vl);
|
||||
|
||||
if (m_fp != NULL) {
|
||||
::fprintf(m_fp, "%s\n", buffer);
|
||||
::fflush(m_fp);
|
||||
}
|
||||
|
||||
::fprintf(stdout, "%s\n", buffer);
|
||||
::fflush(stdout);
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
#define YSFReflector_H
|
||||
|
||||
#include "Timer.h"
|
||||
#include "Conf.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
|
@ -56,18 +57,17 @@ public:
|
|||
class CYSFReflector
|
||||
{
|
||||
public:
|
||||
CYSFReflector(unsigned int port, FILE* fp);
|
||||
CYSFReflector(const std::string& file);
|
||||
~CYSFReflector();
|
||||
|
||||
void run();
|
||||
|
||||
private:
|
||||
unsigned int m_port;
|
||||
CConf m_conf;
|
||||
std::string m_file;
|
||||
std::vector<CYSFRepeater*> m_repeaters;
|
||||
FILE* m_fp;
|
||||
|
||||
CYSFRepeater* findRepeater(const std::string& callsign) const;
|
||||
void log(const char* text, ...);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
17
YSFReflector/YSFReflector.ini
Normal file
17
YSFReflector/YSFReflector.ini
Normal file
|
@ -0,0 +1,17 @@
|
|||
[General]
|
||||
Daemon=1
|
||||
|
||||
[Info]
|
||||
Name=16 characters max
|
||||
Description=14 characters max
|
||||
|
||||
[Log]
|
||||
# Logging levels, 0=No logging
|
||||
DisplayLevel=1
|
||||
FileLevel=1
|
||||
FilePath=.
|
||||
FileRoot=YSFReflector
|
||||
|
||||
[Network]
|
||||
Port=24000
|
||||
Debug=0
|
|
@ -146,6 +146,8 @@
|
|||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Conf.h" />
|
||||
<ClInclude Include="Log.h" />
|
||||
<ClInclude Include="Network.h" />
|
||||
<ClInclude Include="RingBuffer.h" />
|
||||
<ClInclude Include="StopWatch.h" />
|
||||
|
@ -157,6 +159,8 @@
|
|||
<ClInclude Include="YSFReflector.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Conf.cpp" />
|
||||
<ClCompile Include="Log.cpp" />
|
||||
<ClCompile Include="Network.cpp" />
|
||||
<ClCompile Include="StopWatch.cpp" />
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
|
|
|
@ -38,6 +38,12 @@
|
|||
<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>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Network.cpp">
|
||||
|
@ -58,5 +64,11 @@
|
|||
<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>
|
||||
</ItemGroup>
|
||||
</Project>
|
Loading…
Add table
Reference in a new issue