mirror of
https://github.com/ShaYmez/P25Clients.git
synced 2024-11-21 19:55:22 -05:00
First commit of the simple P25 gateway.
This commit is contained in:
parent
f1c68255c8
commit
3065c98f29
@ -5,6 +5,8 @@ VisualStudioVersion = 14.0.25420.1
|
|||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "P25Parrot", "P25Parrot\P25Parrot.vcxproj", "{2AE94EAA-FD57-45C9-8555-6425CFA777A3}"
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "P25Parrot", "P25Parrot\P25Parrot.vcxproj", "{2AE94EAA-FD57-45C9-8555-6425CFA777A3}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "P25Gateway", "P25Gateway\P25Gateway.vcxproj", "{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|x64 = Debug|x64
|
Debug|x64 = Debug|x64
|
||||||
@ -21,6 +23,14 @@ Global
|
|||||||
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Release|x64.Build.0 = Release|x64
|
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Release|x64.Build.0 = Release|x64
|
||||||
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Release|x86.ActiveCfg = Release|Win32
|
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Release|x86.ActiveCfg = Release|Win32
|
||||||
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Release|x86.Build.0 = Release|Win32
|
{2AE94EAA-FD57-45C9-8555-6425CFA777A3}.Release|x86.Build.0 = Release|Win32
|
||||||
|
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Debug|x86.ActiveCfg = Debug|Win32
|
||||||
|
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Debug|x86.Build.0 = Debug|Win32
|
||||||
|
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Release|x64.Build.0 = Release|x64
|
||||||
|
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Release|x86.ActiveCfg = Release|Win32
|
||||||
|
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Release|x86.Build.0 = Release|Win32
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
246
P25Gateway/Conf.cpp
Normal file
246
P25Gateway/Conf.cpp
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
/*
|
||||||
|
* 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_ID_LOOKUP,
|
||||||
|
SECTION_LOG,
|
||||||
|
SECTION_NETWORK
|
||||||
|
};
|
||||||
|
|
||||||
|
CConf::CConf(const std::string& file) :
|
||||||
|
m_file(file),
|
||||||
|
m_callsign(),
|
||||||
|
m_rptAddress(),
|
||||||
|
m_rptPort(0U),
|
||||||
|
m_myPort(0U),
|
||||||
|
m_daemon(false),
|
||||||
|
m_lookupName(),
|
||||||
|
m_lookupTime(0U),
|
||||||
|
m_logDisplayLevel(0U),
|
||||||
|
m_logFileLevel(0U),
|
||||||
|
m_logFilePath(),
|
||||||
|
m_logFileRoot(),
|
||||||
|
m_networkEnabled(false),
|
||||||
|
m_networkDataPort(0U),
|
||||||
|
m_networkHosts(),
|
||||||
|
m_networkReloadTime(0U),
|
||||||
|
m_networkParrotAddress("127.0.0.1"),
|
||||||
|
m_networkParrotPort(0U),
|
||||||
|
m_networkStartup(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, "[Id Lookup]", 11U) == 0)
|
||||||
|
section = SECTION_ID_LOOKUP;
|
||||||
|
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, "Callsign") == 0) {
|
||||||
|
// Convert the callsign to upper case
|
||||||
|
for (unsigned int i = 0U; value[i] != 0; i++)
|
||||||
|
value[i] = ::toupper(value[i]);
|
||||||
|
m_callsign = value;
|
||||||
|
} else if (::strcmp(key, "RptAddress") == 0)
|
||||||
|
m_rptAddress = value;
|
||||||
|
else if (::strcmp(key, "RptPort") == 0)
|
||||||
|
m_rptPort = (unsigned int)::atoi(value);
|
||||||
|
else if (::strcmp(key, "LocalPort") == 0)
|
||||||
|
m_myPort = (unsigned int)::atoi(value);
|
||||||
|
else if (::strcmp(key, "Daemon") == 0)
|
||||||
|
m_daemon = ::atoi(value) == 1;
|
||||||
|
} else if (section == SECTION_ID_LOOKUP) {
|
||||||
|
if (::strcmp(key, "Name") == 0)
|
||||||
|
m_lookupName = value;
|
||||||
|
else if (::strcmp(key, "Time") == 0)
|
||||||
|
m_lookupTime = (unsigned int)::atoi(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, "Enable") == 0)
|
||||||
|
m_networkEnabled = ::atoi(value) == 1;
|
||||||
|
else if (::strcmp(key, "DataPort") == 0)
|
||||||
|
m_networkDataPort = (unsigned int)::atoi(value);
|
||||||
|
else if (::strcmp(key, "Hosts") == 0)
|
||||||
|
m_networkHosts = value;
|
||||||
|
else if (::strcmp(key, "ReloadTime") == 0)
|
||||||
|
m_networkReloadTime = (unsigned int)::atoi(value);
|
||||||
|
else if (::strcmp(key, "ParrotAddress") == 0)
|
||||||
|
m_networkParrotAddress = value;
|
||||||
|
else if (::strcmp(key, "ParrotPort") == 0)
|
||||||
|
m_networkParrotPort = (unsigned int)::atoi(value);
|
||||||
|
else if (::strcmp(key, "Startup") == 0)
|
||||||
|
m_networkStartup = (unsigned int)::atoi(value);
|
||||||
|
else if (::strcmp(key, "Debug") == 0)
|
||||||
|
m_networkDebug = ::atoi(value) == 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::fclose(fp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CConf::getCallsign() const
|
||||||
|
{
|
||||||
|
return m_callsign;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CConf::getRptAddress() const
|
||||||
|
{
|
||||||
|
return m_rptAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CConf::getRptPort() const
|
||||||
|
{
|
||||||
|
return m_rptPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CConf::getMyPort() const
|
||||||
|
{
|
||||||
|
return m_myPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CConf::getDaemon() const
|
||||||
|
{
|
||||||
|
return m_daemon;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CConf::getLookupName() const
|
||||||
|
{
|
||||||
|
return m_lookupName;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CConf::getLookupTime() const
|
||||||
|
{
|
||||||
|
return m_lookupTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
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::getNetworkEnabled() const
|
||||||
|
{
|
||||||
|
return m_networkEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CConf::getNetworkDataPort() const
|
||||||
|
{
|
||||||
|
return m_networkDataPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CConf::getNetworkHosts() const
|
||||||
|
{
|
||||||
|
return m_networkHosts;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CConf::getNetworkReloadTime() const
|
||||||
|
{
|
||||||
|
return m_networkReloadTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CConf::getNetworkParrotAddress() const
|
||||||
|
{
|
||||||
|
return m_networkParrotAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CConf::getNetworkParrotPort() const
|
||||||
|
{
|
||||||
|
return m_networkParrotPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CConf::getNetworkStartup() const
|
||||||
|
{
|
||||||
|
return m_networkStartup;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CConf::getNetworkDebug() const
|
||||||
|
{
|
||||||
|
return m_networkDebug;
|
||||||
|
}
|
86
P25Gateway/Conf.h
Normal file
86
P25Gateway/Conf.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
std::string getCallsign() const;
|
||||||
|
std::string getRptAddress() const;
|
||||||
|
unsigned int getRptPort() const;
|
||||||
|
unsigned int getMyPort() const;
|
||||||
|
bool getDaemon() const;
|
||||||
|
|
||||||
|
// The Id Lookup section
|
||||||
|
std::string getLookupName() const;
|
||||||
|
unsigned int getLookupTime() const;
|
||||||
|
|
||||||
|
// The Log section
|
||||||
|
unsigned int getLogDisplayLevel() const;
|
||||||
|
unsigned int getLogFileLevel() const;
|
||||||
|
std::string getLogFilePath() const;
|
||||||
|
std::string getLogFileRoot() const;
|
||||||
|
|
||||||
|
// The Network section
|
||||||
|
bool getNetworkEnabled() const;
|
||||||
|
unsigned int getNetworkDataPort() const;
|
||||||
|
std::string getNetworkHosts() const;
|
||||||
|
unsigned int getNetworkReloadTime() const;
|
||||||
|
std::string getNetworkParrotAddress() const;
|
||||||
|
unsigned int getNetworkParrotPort() const;
|
||||||
|
unsigned int getNetworkStartup() const;
|
||||||
|
bool getNetworkDebug() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_file;
|
||||||
|
std::string m_callsign;
|
||||||
|
std::string m_rptAddress;
|
||||||
|
unsigned int m_rptPort;
|
||||||
|
unsigned int m_myPort;
|
||||||
|
bool m_daemon;
|
||||||
|
|
||||||
|
std::string m_lookupName;
|
||||||
|
unsigned int m_lookupTime;
|
||||||
|
|
||||||
|
unsigned int m_logDisplayLevel;
|
||||||
|
unsigned int m_logFileLevel;
|
||||||
|
std::string m_logFilePath;
|
||||||
|
std::string m_logFileRoot;
|
||||||
|
|
||||||
|
bool m_networkEnabled;
|
||||||
|
unsigned int m_networkDataPort;
|
||||||
|
std::string m_networkHosts;
|
||||||
|
unsigned int m_networkReloadTime;
|
||||||
|
std::string m_networkParrotAddress;
|
||||||
|
unsigned int m_networkParrotPort;
|
||||||
|
unsigned int m_networkStartup;
|
||||||
|
bool m_networkDebug;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
44228
P25Gateway/DMRIds.dat
Normal file
44228
P25Gateway/DMRIds.dat
Normal file
File diff suppressed because it is too large
Load Diff
147
P25Gateway/DMRLookup.cpp
Normal file
147
P25Gateway/DMRLookup.cpp
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 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 "DMRLookup.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
CDMRLookup::CDMRLookup(const std::string& filename, unsigned int reloadTime) :
|
||||||
|
CThread(),
|
||||||
|
m_filename(filename),
|
||||||
|
m_reloadTime(reloadTime),
|
||||||
|
m_table(),
|
||||||
|
m_mutex(),
|
||||||
|
m_stop(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CDMRLookup::~CDMRLookup()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRLookup::read()
|
||||||
|
{
|
||||||
|
bool ret = load();
|
||||||
|
|
||||||
|
if (m_reloadTime > 0U)
|
||||||
|
run();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRLookup::entry()
|
||||||
|
{
|
||||||
|
LogInfo("Started the DMR Id lookup reload thread");
|
||||||
|
|
||||||
|
CTimer timer(1U, 3600U * m_reloadTime);
|
||||||
|
timer.start();
|
||||||
|
|
||||||
|
while (!m_stop) {
|
||||||
|
sleep(1000U);
|
||||||
|
|
||||||
|
timer.clock();
|
||||||
|
if (timer.hasExpired()) {
|
||||||
|
load();
|
||||||
|
timer.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogInfo("Stopped the DMR Id lookup reload thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CDMRLookup::stop()
|
||||||
|
{
|
||||||
|
if (m_reloadTime == 0U) {
|
||||||
|
delete this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_stop = true;
|
||||||
|
|
||||||
|
wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CDMRLookup::find(unsigned int id)
|
||||||
|
{
|
||||||
|
std::string callsign;
|
||||||
|
|
||||||
|
if (id == 0xFFFFFFU)
|
||||||
|
return std::string("ALL");
|
||||||
|
|
||||||
|
m_mutex.lock();
|
||||||
|
|
||||||
|
try {
|
||||||
|
callsign = m_table.at(id);
|
||||||
|
} catch (...) {
|
||||||
|
char text[10U];
|
||||||
|
::sprintf(text, "%u", id);
|
||||||
|
callsign = std::string(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_mutex.unlock();
|
||||||
|
|
||||||
|
return callsign;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CDMRLookup::load()
|
||||||
|
{
|
||||||
|
FILE* fp = ::fopen(m_filename.c_str(), "rt");
|
||||||
|
if (fp == NULL) {
|
||||||
|
LogWarning("Cannot open the Id lookup file - %s", m_filename.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_mutex.lock();
|
||||||
|
|
||||||
|
// Remove the old entries
|
||||||
|
m_table.clear();
|
||||||
|
|
||||||
|
char buffer[100U];
|
||||||
|
while (::fgets(buffer, 100U, fp) != NULL) {
|
||||||
|
if (buffer[0U] == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char* p1 = ::strtok(buffer, " \t\r\n");
|
||||||
|
char* p2 = ::strtok(NULL, " \t\r\n");
|
||||||
|
|
||||||
|
if (p1 != NULL && p2 != NULL) {
|
||||||
|
unsigned int id = (unsigned int)::atoi(p1);
|
||||||
|
for (char* p = p2; *p != 0x00U; p++)
|
||||||
|
*p = ::toupper(*p);
|
||||||
|
|
||||||
|
m_table[id] = std::string(p2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_mutex.unlock();
|
||||||
|
|
||||||
|
::fclose(fp);
|
||||||
|
|
||||||
|
size_t size = m_table.size();
|
||||||
|
if (size == 0U)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LogInfo("Loaded %u Ids to the callsign lookup table", size);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
51
P25Gateway/DMRLookup.h
Normal file
51
P25Gateway/DMRLookup.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DMRLookup_H
|
||||||
|
#define DMRLookup_H
|
||||||
|
|
||||||
|
#include "Thread.h"
|
||||||
|
#include "Mutex.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
class CDMRLookup : public CThread {
|
||||||
|
public:
|
||||||
|
CDMRLookup(const std::string& filename, unsigned int reloadTime);
|
||||||
|
virtual ~CDMRLookup();
|
||||||
|
|
||||||
|
bool read();
|
||||||
|
|
||||||
|
virtual void entry();
|
||||||
|
|
||||||
|
std::string find(unsigned int id);
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_filename;
|
||||||
|
unsigned int m_reloadTime;
|
||||||
|
std::unordered_map<unsigned int, std::string> m_table;
|
||||||
|
CMutex m_mutex;
|
||||||
|
bool m_stop;
|
||||||
|
|
||||||
|
bool load();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
136
P25Gateway/Log.cpp
Normal file
136
P25Gateway/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
P25Gateway/Log.h
Normal file
36
P25Gateway/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
|
19
P25Gateway/Makefile
Normal file
19
P25Gateway/Makefile
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
CC = gcc
|
||||||
|
CXX = g++
|
||||||
|
CFLAGS = -g -O3 -Wall -std=c++0x -pthread
|
||||||
|
LIBS = -lpthread
|
||||||
|
LDFLAGS = -g
|
||||||
|
|
||||||
|
OBJECTS = Conf.o DMRLookup.o Log.o Mutex.o Network.o P25Gateway.o Reflectors.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o
|
||||||
|
|
||||||
|
all: P25Gateway
|
||||||
|
|
||||||
|
P25Gateway: $(OBJECTS)
|
||||||
|
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o P25Gateway
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) P25Gateway *.o *.d *.bak *~
|
||||||
|
|
18
P25Gateway/Makefile.Solaris
Normal file
18
P25Gateway/Makefile.Solaris
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
CC = gcc
|
||||||
|
CXX = g++
|
||||||
|
CFLAGS = -g -O3 -Wall -std=c++0x -pthread
|
||||||
|
LIBS = -lsocket -lpthread
|
||||||
|
LDFLAGS = -g
|
||||||
|
|
||||||
|
OBJECTS = Conf.o DMRLookup.o Log.o Mutex.o Network.o P25Gateway.o Reflectors.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o
|
||||||
|
|
||||||
|
all: P25Gateway
|
||||||
|
|
||||||
|
P25Gateway: $(OBJECTS)
|
||||||
|
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o P25Gateway
|
||||||
|
|
||||||
|
%.o: %.cpp
|
||||||
|
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) P25Gateway *.o *.d *.bak *~
|
65
P25Gateway/Mutex.cpp
Normal file
65
P25Gateway/Mutex.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* 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 "Mutex.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
|
||||||
|
CMutex::CMutex() :
|
||||||
|
m_handle()
|
||||||
|
{
|
||||||
|
m_handle = ::CreateMutex(NULL, FALSE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
CMutex::~CMutex()
|
||||||
|
{
|
||||||
|
::CloseHandle(m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMutex::lock()
|
||||||
|
{
|
||||||
|
::WaitForSingleObject(m_handle, INFINITE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMutex::unlock()
|
||||||
|
{
|
||||||
|
::ReleaseMutex(m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
CMutex::CMutex() :
|
||||||
|
m_mutex(PTHREAD_MUTEX_INITIALIZER)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CMutex::~CMutex()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMutex::lock()
|
||||||
|
{
|
||||||
|
::pthread_mutex_lock(&m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMutex::unlock()
|
||||||
|
{
|
||||||
|
::pthread_mutex_unlock(&m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
45
P25Gateway/Mutex.h
Normal file
45
P25Gateway/Mutex.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* 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(MUTEX_H)
|
||||||
|
#define MUTEX_H
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CMutex
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CMutex();
|
||||||
|
~CMutex();
|
||||||
|
|
||||||
|
void lock();
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
HANDLE m_handle;
|
||||||
|
#else
|
||||||
|
pthread_mutex_t m_mutex;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
77
P25Gateway/Network.cpp
Normal file
77
P25Gateway/Network.cpp
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,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 "Network.h"
|
||||||
|
#include "Utils.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
CNetwork::CNetwork(unsigned int port, bool debug) :
|
||||||
|
m_socket(port),
|
||||||
|
m_debug(debug)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CNetwork::~CNetwork()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetwork::open()
|
||||||
|
{
|
||||||
|
LogInfo("Opening P25 network connection");
|
||||||
|
|
||||||
|
return m_socket.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CNetwork::writeData(const unsigned char* data, unsigned int length, const in_addr& address, unsigned int port)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
assert(length > 0U);
|
||||||
|
assert(port > 0U);
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "P25 Network Data Sent", data, length);
|
||||||
|
|
||||||
|
return m_socket.write(data, length, address, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CNetwork::readData(unsigned char* data, unsigned int length, in_addr& address, unsigned int& port)
|
||||||
|
{
|
||||||
|
assert(data != NULL);
|
||||||
|
assert(length > 0U);
|
||||||
|
assert(port > 0U);
|
||||||
|
|
||||||
|
int len = m_socket.read(data, length, address, port);
|
||||||
|
if (len <= 0)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
if (m_debug)
|
||||||
|
CUtils::dump(1U, "P25 Network Data Received", data, len);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNetwork::close()
|
||||||
|
{
|
||||||
|
m_socket.close();
|
||||||
|
|
||||||
|
LogInfo("Closing P25 network connection");
|
||||||
|
}
|
45
P25Gateway/Network.h
Normal file
45
P25Gateway/Network.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2014,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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef Network_H
|
||||||
|
#define Network_H
|
||||||
|
|
||||||
|
#include "UDPSocket.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CNetwork {
|
||||||
|
public:
|
||||||
|
CNetwork(unsigned int port, bool debug);
|
||||||
|
~CNetwork();
|
||||||
|
|
||||||
|
bool open();
|
||||||
|
|
||||||
|
bool writeData(const unsigned char* data, unsigned int length, const in_addr& address, unsigned int port);
|
||||||
|
|
||||||
|
unsigned int readData(unsigned char* data, unsigned int length, in_addr& address, unsigned int& port);
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CUDPSocket m_socket;
|
||||||
|
bool m_debug;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
296
P25Gateway/P25Gateway.cpp
Normal file
296
P25Gateway/P25Gateway.cpp
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 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 "P25Gateway.h"
|
||||||
|
#include "Reflectors.h"
|
||||||
|
#include "StopWatch.h"
|
||||||
|
#include "DMRLookup.h"
|
||||||
|
#include "Network.h"
|
||||||
|
#include "Version.h"
|
||||||
|
#include "Log.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 = "P25Gateway.ini";
|
||||||
|
#else
|
||||||
|
const char* DEFAULT_INI_FILE = "/etc/P25Gateway.ini";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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, "P25Gateway version %s\n", VERSION);
|
||||||
|
return 0;
|
||||||
|
} else if (arg.substr(0, 1) == "-") {
|
||||||
|
::fprintf(stderr, "Usage: P25Gateway [-v|--version] [filename]\n");
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
iniFile = argv[currentArg];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CP25Gateway* gateway = new CP25Gateway(std::string(iniFile));
|
||||||
|
gateway->run();
|
||||||
|
delete gateway;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CP25Gateway::CP25Gateway(const std::string& file) :
|
||||||
|
m_conf(file)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CP25Gateway::~CP25Gateway()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CP25Gateway::run()
|
||||||
|
{
|
||||||
|
bool ret = m_conf.read();
|
||||||
|
if (!ret) {
|
||||||
|
::fprintf(stderr, "P25Gateway: cannot read the .ini file\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ::LogInitialise(m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel());
|
||||||
|
if (!ret) {
|
||||||
|
::fprintf(stderr, "P25Gateway: 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;
|
||||||
|
}
|
||||||
|
else if (pid != 0)
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
|
||||||
|
// Create new session and process group
|
||||||
|
if (::setsid() == -1) {
|
||||||
|
::LogWarning("Couldn't setsid(), exiting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the working directory to the root directory
|
||||||
|
if (::chdir("/") == -1) {
|
||||||
|
::LogWarning("Couldn't cd /, exiting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setuid(mmdvm_uid) != 0) {
|
||||||
|
::LogWarning("Could not set mmdvm UID, exiting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Double check it worked (AKA Paranoia)
|
||||||
|
if (setuid(0) != -1) {
|
||||||
|
::LogWarning("It's possible to regain root - something is wrong!, exiting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
in_addr rptAddr = CUDPSocket::lookup(m_conf.getRptAddress());
|
||||||
|
unsigned int rptPort = m_conf.getRptPort();
|
||||||
|
|
||||||
|
CNetwork localNetwork(m_conf.getMyPort(), false);
|
||||||
|
|
||||||
|
ret = localNetwork.open();
|
||||||
|
if (!ret) {
|
||||||
|
::LogFinalise();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CNetwork* remoteNetwork = NULL;
|
||||||
|
if (m_conf.getNetworkEnabled()) {
|
||||||
|
remoteNetwork = new CNetwork(m_conf.getNetworkDataPort(), m_conf.getNetworkDebug());
|
||||||
|
ret = remoteNetwork->open();
|
||||||
|
if (!ret) {
|
||||||
|
localNetwork.close();
|
||||||
|
::LogFinalise();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CReflectors reflectors(m_conf.getNetworkHosts(), m_conf.getNetworkReloadTime());
|
||||||
|
if (m_conf.getNetworkParrotPort() > 0U)
|
||||||
|
reflectors.setParrot(m_conf.getNetworkParrotAddress(), m_conf.getNetworkParrotPort());
|
||||||
|
reflectors.load();
|
||||||
|
|
||||||
|
CDMRLookup* lookup = new CDMRLookup(m_conf.getLookupName(), m_conf.getLookupTime());
|
||||||
|
lookup->read();
|
||||||
|
|
||||||
|
CStopWatch stopWatch;
|
||||||
|
stopWatch.start();
|
||||||
|
|
||||||
|
LogMessage("Starting P25Gateway-%s", VERSION);
|
||||||
|
|
||||||
|
bool displayed = false;
|
||||||
|
bool seen64 = false;
|
||||||
|
bool seen65 = false;
|
||||||
|
|
||||||
|
unsigned int currentId = 0U;
|
||||||
|
in_addr currentAddr;
|
||||||
|
unsigned int currentPort = 0U;
|
||||||
|
if (remoteNetwork != NULL) {
|
||||||
|
currentId = m_conf.getNetworkStartup();
|
||||||
|
CP25Reflector* reflector = reflectors.find(currentId);
|
||||||
|
if (reflector != NULL) {
|
||||||
|
currentAddr = reflector->m_address;
|
||||||
|
currentPort = reflector->m_port;
|
||||||
|
} else {
|
||||||
|
LogInfo("Startup reflector with id of %u, not found", currentId);
|
||||||
|
currentId = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
unsigned char buffer[200U];
|
||||||
|
in_addr address;
|
||||||
|
unsigned int port;
|
||||||
|
|
||||||
|
// From the reflector to the MMDVM
|
||||||
|
if (remoteNetwork != NULL) {
|
||||||
|
unsigned int len = remoteNetwork->readData(buffer, 200U, address, port);
|
||||||
|
if (len > 0U) {
|
||||||
|
// If we're linked and it's from the right place, send it on
|
||||||
|
if (currentId != 0U && currentAddr.s_addr == address.s_addr && currentPort == port) {
|
||||||
|
// Rewrite the LCF and the destination TG
|
||||||
|
if (buffer[0U] == 0x64U) {
|
||||||
|
buffer[1U] = 0x00U; // LCF is for TGs
|
||||||
|
} else if (buffer[0U] == 0x65U) {
|
||||||
|
buffer[1U] = (currentId >> 16) & 0xFFU;
|
||||||
|
buffer[2U] = (currentId >> 8) & 0xFFU;
|
||||||
|
buffer[3U] = (currentId >> 0) & 0xFFU;
|
||||||
|
}
|
||||||
|
|
||||||
|
localNetwork.writeData(buffer, len, rptAddr, rptPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// From the MMDVM to the reflector or control data
|
||||||
|
unsigned int len = localNetwork.readData(buffer, 200U, address, port);
|
||||||
|
if (len > 0U) {
|
||||||
|
if (buffer[0U] == 0x65U) {
|
||||||
|
unsigned int id = 0U;
|
||||||
|
id |= (buffer[1U] << 16) & 0xFF0000U;
|
||||||
|
id |= (buffer[2U] << 8) & 0x00FF00U;
|
||||||
|
id |= (buffer[3U] << 0) & 0x0000FFU;
|
||||||
|
|
||||||
|
if (id != currentId) {
|
||||||
|
CP25Reflector* reflector = reflectors.find(id);
|
||||||
|
if (reflector != NULL) {
|
||||||
|
currentId = id;
|
||||||
|
currentAddr = reflector->m_address;
|
||||||
|
currentPort = reflector->m_port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rewrite the LCF and the destination TG
|
||||||
|
if (buffer[0U] == 0x64U) {
|
||||||
|
buffer[1U] = 0x00U; // LCF is for TGs
|
||||||
|
} else if (buffer[0U] == 0x65U) {
|
||||||
|
buffer[1U] = (currentId >> 16) & 0xFFU;
|
||||||
|
buffer[2U] = (currentId >> 8) & 0xFFU;
|
||||||
|
buffer[3U] = (currentId >> 0) & 0xFFU;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're linked and we have a network, send it on
|
||||||
|
if (currentId != 0U && remoteNetwork != NULL)
|
||||||
|
remoteNetwork->writeData(buffer, len, currentAddr, currentPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ms = stopWatch.elapsed();
|
||||||
|
stopWatch.start();
|
||||||
|
|
||||||
|
reflectors.clock(ms);
|
||||||
|
|
||||||
|
if (ms < 5U) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::Sleep(5UL); // 5ms
|
||||||
|
#else
|
||||||
|
::usleep(5000); // 5ms
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
localNetwork.close();
|
||||||
|
|
||||||
|
if (remoteNetwork != NULL) {
|
||||||
|
remoteNetwork->close();
|
||||||
|
delete remoteNetwork;
|
||||||
|
}
|
||||||
|
|
||||||
|
lookup->stop();
|
||||||
|
|
||||||
|
::LogFinalise();
|
||||||
|
}
|
53
P25Gateway/P25Gateway.h
Normal file
53
P25Gateway/P25Gateway.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 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(P25Gateway_H)
|
||||||
|
#define P25Gateway_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 <winsock.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CP25Gateway
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CP25Gateway(const std::string& file);
|
||||||
|
~CP25Gateway();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CConf m_conf;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
27
P25Gateway/P25Gateway.ini
Normal file
27
P25Gateway/P25Gateway.ini
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
[General]
|
||||||
|
Callsign=G9BF
|
||||||
|
RptAddress=127.0.0.1
|
||||||
|
RptPort=32010
|
||||||
|
LocalPort=42020
|
||||||
|
Daemon=1
|
||||||
|
|
||||||
|
[Id Lookup]
|
||||||
|
Name=DMRIds.dat
|
||||||
|
Time=24
|
||||||
|
|
||||||
|
[Log]
|
||||||
|
# Logging levels, 0=No logging
|
||||||
|
DisplayLevel=1
|
||||||
|
FileLevel=1
|
||||||
|
FilePath=.
|
||||||
|
FileRoot=P25Gateway
|
||||||
|
|
||||||
|
[Network]
|
||||||
|
Enable=1
|
||||||
|
DataPort=42010
|
||||||
|
Hosts=P25Hosts.txt
|
||||||
|
ReloadTime=60
|
||||||
|
ParrotAddress=127.0.0.1
|
||||||
|
ParrotPort=42011
|
||||||
|
Startup=10100
|
||||||
|
Debug=0
|
181
P25Gateway/P25Gateway.vcxproj
Normal file
181
P25Gateway/P25Gateway.vcxproj
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<ItemGroup Label="ProjectConfigurations">
|
||||||
|
<ProjectConfiguration Include="Debug|Win32">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|Win32">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Win32</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Debug|x64">
|
||||||
|
<Configuration>Debug</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
<ProjectConfiguration Include="Release|x64">
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>x64</Platform>
|
||||||
|
</ProjectConfiguration>
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup Label="Globals">
|
||||||
|
<ProjectGuid>{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}</ProjectGuid>
|
||||||
|
<Keyword>Win32Proj</Keyword>
|
||||||
|
<RootNamespace>P25Gateway</RootNamespace>
|
||||||
|
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>true</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||||
|
<ConfigurationType>Application</ConfigurationType>
|
||||||
|
<UseDebugLibraries>false</UseDebugLibraries>
|
||||||
|
<PlatformToolset>v140</PlatformToolset>
|
||||||
|
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||||
|
<CharacterSet>Unicode</CharacterSet>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||||
|
<ImportGroup Label="ExtensionSettings">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="Shared">
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||||
|
</ImportGroup>
|
||||||
|
<PropertyGroup Label="UserMacros" />
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<LinkIncremental>true</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<LinkIncremental>false</LinkIncremental>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<Optimization>Disabled</Optimization>
|
||||||
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||||
|
<ClCompile>
|
||||||
|
<WarningLevel>Level3</WarningLevel>
|
||||||
|
<PrecompiledHeader>
|
||||||
|
</PrecompiledHeader>
|
||||||
|
<Optimization>MaxSpeed</Optimization>
|
||||||
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
|
</ClCompile>
|
||||||
|
<Link>
|
||||||
|
<SubSystem>Console</SubSystem>
|
||||||
|
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||||
|
<OptimizeReferences>true</OptimizeReferences>
|
||||||
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
|
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
|
</Link>
|
||||||
|
</ItemDefinitionGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="Conf.h" />
|
||||||
|
<ClInclude Include="DMRLookup.h" />
|
||||||
|
<ClInclude Include="Log.h" />
|
||||||
|
<ClInclude Include="Mutex.h" />
|
||||||
|
<ClInclude Include="Network.h" />
|
||||||
|
<ClInclude Include="P25Gateway.h" />
|
||||||
|
<ClInclude Include="Reflectors.h" />
|
||||||
|
<ClInclude Include="RingBuffer.h" />
|
||||||
|
<ClInclude Include="StopWatch.h" />
|
||||||
|
<ClInclude Include="Thread.h" />
|
||||||
|
<ClInclude Include="Timer.h" />
|
||||||
|
<ClInclude Include="UDPSocket.h" />
|
||||||
|
<ClInclude Include="Utils.h" />
|
||||||
|
<ClInclude Include="Version.h" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Conf.cpp" />
|
||||||
|
<ClCompile Include="DMRLookup.cpp" />
|
||||||
|
<ClCompile Include="Log.cpp" />
|
||||||
|
<ClCompile Include="Mutex.cpp" />
|
||||||
|
<ClCompile Include="Network.cpp" />
|
||||||
|
<ClCompile Include="P25Gateway.cpp" />
|
||||||
|
<ClCompile Include="Reflectors.cpp" />
|
||||||
|
<ClCompile Include="StopWatch.cpp" />
|
||||||
|
<ClCompile Include="Thread.cpp" />
|
||||||
|
<ClCompile Include="Timer.cpp" />
|
||||||
|
<ClCompile Include="UDPSocket.cpp" />
|
||||||
|
<ClCompile Include="Utils.cpp" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
<ImportGroup Label="ExtensionTargets">
|
||||||
|
</ImportGroup>
|
||||||
|
</Project>
|
95
P25Gateway/P25Gateway.vcxproj.filters
Normal file
95
P25Gateway/P25Gateway.vcxproj.filters
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
<?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="Conf.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="DMRLookup.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Log.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Mutex.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Network.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="P25Gateway.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="RingBuffer.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="StopWatch.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Thread.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="Version.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Reflectors.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClCompile Include="Conf.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="DMRLookup.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Log.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Mutex.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Network.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="P25Gateway.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="StopWatch.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Thread.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="Reflectors.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
6
P25Gateway/P25Hosts.txt
Normal file
6
P25Gateway/P25Hosts.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# P25Hosts.txt
|
||||||
|
#
|
||||||
|
# The format of this file is the number of the Talk Group followed by the host name or address and port
|
||||||
|
#
|
||||||
|
|
||||||
|
10100 m1geo.com 41000
|
129
P25Gateway/Reflectors.cpp
Normal file
129
P25Gateway/Reflectors.cpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 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 "Reflectors.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
#include <cctype>
|
||||||
|
|
||||||
|
CReflectors::CReflectors(const std::string& hostsFile, unsigned int reloadTime) :
|
||||||
|
m_hostsFile(hostsFile),
|
||||||
|
m_parrotAddress(),
|
||||||
|
m_parrotPort(0U),
|
||||||
|
m_reflectors(),
|
||||||
|
m_timer(1000U, reloadTime * 60U)
|
||||||
|
{
|
||||||
|
if (reloadTime > 0U)
|
||||||
|
m_timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
CReflectors::~CReflectors()
|
||||||
|
{
|
||||||
|
for (std::vector<CP25Reflector*>::iterator it = m_reflectors.begin(); it != m_reflectors.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
|
||||||
|
m_reflectors.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CReflectors::setParrot(const std::string& address, unsigned int port)
|
||||||
|
{
|
||||||
|
m_parrotAddress = address;
|
||||||
|
m_parrotPort = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CReflectors::load()
|
||||||
|
{
|
||||||
|
// Clear out the old reflector list
|
||||||
|
for (std::vector<CP25Reflector*>::iterator it = m_reflectors.begin(); it != m_reflectors.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
|
||||||
|
m_reflectors.clear();
|
||||||
|
|
||||||
|
FILE* fp = ::fopen(m_hostsFile.c_str(), "rt");
|
||||||
|
if (fp != NULL) {
|
||||||
|
char buffer[100U];
|
||||||
|
while (::fgets(buffer, 100U, fp) != NULL) {
|
||||||
|
if (buffer[0U] == '#')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
char* p1 = ::strtok(buffer, "\t\r\n");
|
||||||
|
char* p2 = ::strtok(NULL, "\t\r\n");
|
||||||
|
char* p3 = ::strtok(NULL, "\t\r\n");
|
||||||
|
|
||||||
|
if (p1 != NULL && p2 != NULL && p3 != NULL) {
|
||||||
|
std::string host = std::string(p2);
|
||||||
|
|
||||||
|
in_addr address = CUDPSocket::lookup(host);
|
||||||
|
if (address.s_addr != INADDR_NONE) {
|
||||||
|
CP25Reflector* refl = new CP25Reflector;
|
||||||
|
refl->m_id = (unsigned int)::atoi(p1);
|
||||||
|
refl->m_address = address;
|
||||||
|
refl->m_port = (unsigned int)::atoi(p3);
|
||||||
|
|
||||||
|
m_reflectors.push_back(refl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the Parrot entry
|
||||||
|
if (m_parrotPort > 0U) {
|
||||||
|
CP25Reflector* refl = new CP25Reflector;
|
||||||
|
refl->m_id = 1U;
|
||||||
|
refl->m_address = CUDPSocket::lookup(m_parrotAddress);
|
||||||
|
refl->m_port = m_parrotPort;
|
||||||
|
m_reflectors.push_back(refl);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size = m_reflectors.size();
|
||||||
|
if (size == 0U)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
LogInfo("Loaded %u P25 reflectors", size);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CP25Reflector* CReflectors::find(unsigned int id)
|
||||||
|
{
|
||||||
|
for (std::vector<CP25Reflector*>::iterator it = m_reflectors.begin(); it != m_reflectors.end(); ++it) {
|
||||||
|
if (id == (*it)->m_id)
|
||||||
|
return *it;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogMessage("Trying to find non existent reflector with an id of %u", id);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CReflectors::clock(unsigned int ms)
|
||||||
|
{
|
||||||
|
m_timer.clock(ms);
|
||||||
|
|
||||||
|
if (m_timer.isRunning() && m_timer.hasExpired()) {
|
||||||
|
load();
|
||||||
|
m_timer.start();
|
||||||
|
}
|
||||||
|
}
|
63
P25Gateway/Reflectors.h
Normal file
63
P25Gateway/Reflectors.h
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 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(Reflectors_H)
|
||||||
|
#define Reflectors_H
|
||||||
|
|
||||||
|
#include "UDPSocket.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CP25Reflector {
|
||||||
|
public:
|
||||||
|
CP25Reflector() :
|
||||||
|
m_id(),
|
||||||
|
m_address(),
|
||||||
|
m_port(0U)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int m_id;
|
||||||
|
in_addr m_address;
|
||||||
|
unsigned int m_port;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CReflectors {
|
||||||
|
public:
|
||||||
|
CReflectors(const std::string& hostsFile, unsigned int reloadTime);
|
||||||
|
~CReflectors();
|
||||||
|
|
||||||
|
void setParrot(const std::string& address, unsigned int port);
|
||||||
|
|
||||||
|
bool load();
|
||||||
|
|
||||||
|
CP25Reflector* find(unsigned int id);
|
||||||
|
|
||||||
|
void clock(unsigned int ms);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_hostsFile;
|
||||||
|
std::string m_parrotAddress;
|
||||||
|
unsigned int m_parrotPort;
|
||||||
|
std::vector<CP25Reflector*> m_reflectors;
|
||||||
|
CTimer m_timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
147
P25Gateway/RingBuffer.h
Normal file
147
P25Gateway/RingBuffer.h
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006-2009,2012,2013,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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RingBuffer_H
|
||||||
|
#define RingBuffer_H
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
template<class T> class CRingBuffer {
|
||||||
|
public:
|
||||||
|
CRingBuffer(unsigned int length, const char* name) :
|
||||||
|
m_length(length),
|
||||||
|
m_name(name),
|
||||||
|
m_buffer(NULL),
|
||||||
|
m_iPtr(0U),
|
||||||
|
m_oPtr(0U)
|
||||||
|
{
|
||||||
|
assert(length > 0U);
|
||||||
|
assert(name != NULL);
|
||||||
|
|
||||||
|
m_buffer = new T[length];
|
||||||
|
|
||||||
|
::memset(m_buffer, 0x00, m_length * sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
~CRingBuffer()
|
||||||
|
{
|
||||||
|
delete[] m_buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool addData(const T* buffer, unsigned int nSamples)
|
||||||
|
{
|
||||||
|
if (nSamples >= freeSpace()) {
|
||||||
|
::fprintf(stderr, "**** Overflow in %s ring buffer, %u >= %u\n", m_name, nSamples, freeSpace());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||||
|
m_buffer[m_iPtr++] = buffer[i];
|
||||||
|
|
||||||
|
if (m_iPtr == m_length)
|
||||||
|
m_iPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getData(T* buffer, unsigned int nSamples)
|
||||||
|
{
|
||||||
|
if (dataSize() < nSamples) {
|
||||||
|
::fprintf(stderr, "**** Underflow in %s ring buffer, %u < %u\n", m_name, dataSize(), nSamples);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||||
|
buffer[i] = m_buffer[m_oPtr++];
|
||||||
|
|
||||||
|
if (m_oPtr == m_length)
|
||||||
|
m_oPtr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool peek(T* buffer, unsigned int nSamples)
|
||||||
|
{
|
||||||
|
if (dataSize() < nSamples) {
|
||||||
|
::fprintf(stderr, "**** Underflow peek in %s ring buffer, %u < %u\n", m_name, dataSize(), nSamples);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ptr = m_oPtr;
|
||||||
|
for (unsigned int i = 0U; i < nSamples; i++) {
|
||||||
|
buffer[i] = m_buffer[ptr++];
|
||||||
|
|
||||||
|
if (ptr == m_length)
|
||||||
|
ptr = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
m_iPtr = 0U;
|
||||||
|
m_oPtr = 0U;
|
||||||
|
|
||||||
|
::memset(m_buffer, 0x00, m_length * sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int freeSpace() const
|
||||||
|
{
|
||||||
|
if (m_oPtr == m_iPtr)
|
||||||
|
return m_length;
|
||||||
|
|
||||||
|
if (m_oPtr > m_iPtr)
|
||||||
|
return m_oPtr - m_iPtr;
|
||||||
|
|
||||||
|
return (m_length + m_oPtr) - m_iPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int dataSize() const
|
||||||
|
{
|
||||||
|
return m_length - freeSpace();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasSpace(unsigned int length) const
|
||||||
|
{
|
||||||
|
return freeSpace() > length;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasData() const
|
||||||
|
{
|
||||||
|
return m_oPtr != m_iPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isEmpty() const
|
||||||
|
{
|
||||||
|
return m_oPtr == m_iPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned int m_length;
|
||||||
|
const char* m_name;
|
||||||
|
T* m_buffer;
|
||||||
|
unsigned int m_iPtr;
|
||||||
|
unsigned int m_oPtr;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
84
P25Gateway/StopWatch.cpp
Normal file
84
P25Gateway/StopWatch.cpp
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* 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 "StopWatch.h"
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
|
||||||
|
CStopWatch::CStopWatch() :
|
||||||
|
m_frequency(),
|
||||||
|
m_start()
|
||||||
|
{
|
||||||
|
::QueryPerformanceFrequency(&m_frequency);
|
||||||
|
}
|
||||||
|
|
||||||
|
CStopWatch::~CStopWatch()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long CStopWatch::start()
|
||||||
|
{
|
||||||
|
::QueryPerformanceCounter(&m_start);
|
||||||
|
|
||||||
|
return (unsigned long)(m_start.QuadPart / m_frequency.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_frequency.QuadPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
CStopWatch::CStopWatch() :
|
||||||
|
m_start()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
CStopWatch::~CStopWatch()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long CStopWatch::start()
|
||||||
|
{
|
||||||
|
::gettimeofday(&m_start, NULL);
|
||||||
|
|
||||||
|
return m_start.tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int CStopWatch::elapsed()
|
||||||
|
{
|
||||||
|
struct timeval now;
|
||||||
|
::gettimeofday(&now, NULL);
|
||||||
|
|
||||||
|
unsigned int elapsed = (now.tv_sec - m_start.tv_sec) * 1000U;
|
||||||
|
elapsed += now.tv_usec / 1000U;
|
||||||
|
elapsed -= m_start.tv_usec / 1000U;
|
||||||
|
|
||||||
|
return elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
46
P25Gateway/StopWatch.h
Normal file
46
P25Gateway/StopWatch.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* 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(STOPWATCH_H)
|
||||||
|
#define STOPWATCH_H
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CStopWatch
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CStopWatch();
|
||||||
|
~CStopWatch();
|
||||||
|
|
||||||
|
unsigned long start();
|
||||||
|
unsigned int elapsed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
LARGE_INTEGER m_frequency;
|
||||||
|
LARGE_INTEGER m_start;
|
||||||
|
#else
|
||||||
|
struct timeval m_start;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
101
P25Gateway/Thread.cpp
Normal file
101
P25Gateway/Thread.cpp
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* 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 "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)
|
||||||
|
{
|
||||||
|
::usleep(ms * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
56
P25Gateway/Thread.h
Normal file
56
P25Gateway/Thread.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
68
P25Gateway/Timer.cpp
Normal file
68
P25Gateway/Timer.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
89
P25Gateway/Timer.h
Normal file
89
P25Gateway/Timer.h
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
262
P25Gateway/UDPSocket.cpp
Normal file
262
P25Gateway/UDPSocket.cpp
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2006-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 "UDPSocket.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstring>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) :
|
||||||
|
m_address(address),
|
||||||
|
m_port(port),
|
||||||
|
m_fd(-1)
|
||||||
|
{
|
||||||
|
assert(!address.empty());
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
WSAData data;
|
||||||
|
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
|
||||||
|
if (wsaRet != 0)
|
||||||
|
LogError("Error from WSAStartup");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CUDPSocket::CUDPSocket(unsigned int port) :
|
||||||
|
m_address(),
|
||||||
|
m_port(port),
|
||||||
|
m_fd(-1)
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
WSAData data;
|
||||||
|
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
|
||||||
|
if (wsaRet != 0)
|
||||||
|
LogError("Error from WSAStartup");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
CUDPSocket::~CUDPSocket()
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::WSACleanup();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
in_addr CUDPSocket::lookup(const std::string& hostname)
|
||||||
|
{
|
||||||
|
in_addr addr;
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
unsigned long address = ::inet_addr(hostname.c_str());
|
||||||
|
if (address != INADDR_NONE && address != INADDR_ANY) {
|
||||||
|
addr.s_addr = address;
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hostent* hp = ::gethostbyname(hostname.c_str());
|
||||||
|
if (hp != NULL) {
|
||||||
|
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogError("Cannot find address for host %s", hostname.c_str());
|
||||||
|
|
||||||
|
addr.s_addr = INADDR_NONE;
|
||||||
|
return addr;
|
||||||
|
#else
|
||||||
|
in_addr_t address = ::inet_addr(hostname.c_str());
|
||||||
|
if (address != in_addr_t(-1)) {
|
||||||
|
addr.s_addr = address;
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct hostent* hp = ::gethostbyname(hostname.c_str());
|
||||||
|
if (hp != NULL) {
|
||||||
|
::memcpy(&addr, hp->h_addr_list[0], sizeof(struct in_addr));
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
LogError("Cannot find address for host %s", hostname.c_str());
|
||||||
|
|
||||||
|
addr.s_addr = INADDR_NONE;
|
||||||
|
return addr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CUDPSocket::open()
|
||||||
|
{
|
||||||
|
m_fd = ::socket(PF_INET, SOCK_DGRAM, 0);
|
||||||
|
if (m_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_port > 0U) {
|
||||||
|
sockaddr_in addr;
|
||||||
|
::memset(&addr, 0x00, sizeof(sockaddr_in));
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_port = htons(m_port);
|
||||||
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
|
||||||
|
if (!m_address.empty()) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
|
||||||
|
#else
|
||||||
|
addr.sin_addr.s_addr = ::inet_addr(m_address.c_str());
|
||||||
|
#endif
|
||||||
|
if (addr.sin_addr.s_addr == INADDR_NONE) {
|
||||||
|
LogError("The local address is invalid - %s", m_address.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int reuse = 1;
|
||||||
|
if (::setsockopt(m_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(m_fd, (sockaddr*)&addr, sizeof(sockaddr_in)) == -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CUDPSocket::read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port)
|
||||||
|
{
|
||||||
|
assert(buffer != NULL);
|
||||||
|
assert(length > 0U);
|
||||||
|
|
||||||
|
// Check that the readfrom() won't block
|
||||||
|
fd_set readFds;
|
||||||
|
FD_ZERO(&readFds);
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
FD_SET((unsigned int)m_fd, &readFds);
|
||||||
|
#else
|
||||||
|
FD_SET(m_fd, &readFds);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Return immediately
|
||||||
|
timeval tv;
|
||||||
|
tv.tv_sec = 0L;
|
||||||
|
tv.tv_usec = 0L;
|
||||||
|
|
||||||
|
int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv);
|
||||||
|
if (ret < 0) {
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
LogError("Error returned from UDP select, err: %lu", ::GetLastError());
|
||||||
|
#else
|
||||||
|
LogError("Error returned from UDP select, err: %d", errno);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
sockaddr_in addr;
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
int size = sizeof(sockaddr_in);
|
||||||
|
#else
|
||||||
|
socklen_t size = sizeof(sockaddr_in);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &size);
|
||||||
|
#else
|
||||||
|
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&addr, &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);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
address = addr.sin_addr;
|
||||||
|
port = ntohs(addr.sin_port);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port)
|
||||||
|
{
|
||||||
|
assert(buffer != NULL);
|
||||||
|
assert(length > 0U);
|
||||||
|
|
||||||
|
sockaddr_in addr;
|
||||||
|
::memset(&addr, 0x00, sizeof(sockaddr_in));
|
||||||
|
|
||||||
|
addr.sin_family = AF_INET;
|
||||||
|
addr.sin_addr = address;
|
||||||
|
addr.sin_port = htons(port);
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
|
||||||
|
#else
|
||||||
|
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&addr, sizeof(sockaddr_in));
|
||||||
|
#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
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
if (ret != int(length))
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
if (ret != ssize_t(length))
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CUDPSocket::close()
|
||||||
|
{
|
||||||
|
#if defined(_WIN32) || defined(_WIN64)
|
||||||
|
::closesocket(m_fd);
|
||||||
|
#else
|
||||||
|
::close(m_fd);
|
||||||
|
#endif
|
||||||
|
}
|
58
P25Gateway/UDPSocket.h
Normal file
58
P25Gateway/UDPSocket.h
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2011,2013,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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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 <unistd.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#else
|
||||||
|
#include <winsock.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class CUDPSocket {
|
||||||
|
public:
|
||||||
|
CUDPSocket(const std::string& address, unsigned int port = 0U);
|
||||||
|
CUDPSocket(unsigned int port = 0U);
|
||||||
|
~CUDPSocket();
|
||||||
|
|
||||||
|
bool open();
|
||||||
|
|
||||||
|
int read(unsigned char* buffer, unsigned int length, in_addr& address, unsigned int& port);
|
||||||
|
bool write(const unsigned char* buffer, unsigned int length, const in_addr& address, unsigned int port);
|
||||||
|
|
||||||
|
void close();
|
||||||
|
|
||||||
|
static in_addr lookup(const std::string& hostName);
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_address;
|
||||||
|
unsigned short m_port;
|
||||||
|
int m_fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
146
P25Gateway/Utils.cpp
Normal file
146
P25Gateway/Utils.cpp
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
36
P25Gateway/Utils.h
Normal file
36
P25Gateway/Utils.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
24
P25Gateway/Version.h
Normal file
24
P25Gateway/Version.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* 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(VERSION_H)
|
||||||
|
#define VERSION_H
|
||||||
|
|
||||||
|
const char* VERSION = "20161010";
|
||||||
|
|
||||||
|
#endif
|
@ -87,7 +87,7 @@
|
|||||||
</PrecompiledHeader>
|
</PrecompiledHeader>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
@ -101,7 +101,7 @@
|
|||||||
</PrecompiledHeader>
|
</PrecompiledHeader>
|
||||||
<WarningLevel>Level3</WarningLevel>
|
<WarningLevel>Level3</WarningLevel>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
@ -117,7 +117,7 @@
|
|||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
@ -135,7 +135,7 @@
|
|||||||
<Optimization>MaxSpeed</Optimization>
|
<Optimization>MaxSpeed</Optimization>
|
||||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<SubSystem>Console</SubSystem>
|
<SubSystem>Console</SubSystem>
|
||||||
|
Loading…
Reference in New Issue
Block a user