mirror of
https://github.com/g4klx/ircDDBGateway.git
synced 2026-04-06 06:43:52 +00:00
Initial commit.
This commit is contained in:
commit
12d55cef37
430 changed files with 72067 additions and 0 deletions
394
Common/DDHandler.cpp
Normal file
394
Common/DDHandler.cpp
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
/*
|
||||
* Copyright (C) 2011,2012,2013 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 "RepeaterHandler.h"
|
||||
#include "DDHandler.h"
|
||||
#include "Defs.h"
|
||||
|
||||
#include <wx/filename.h>
|
||||
|
||||
#if !defined(WIN32)
|
||||
// XXX Check these
|
||||
#include <net/if.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
const unsigned int ETHERNET_ADDRESS_LENGTH = 6U;
|
||||
const unsigned int ETHERNET_MTU = 1500U;
|
||||
const unsigned int BUFFER_LENGTH = 2000U;
|
||||
|
||||
const unsigned int MIN_HEARD_TIME_SECS = 120U;
|
||||
|
||||
const int MINIMUM_DD_FRAME_LENGTH = 60;
|
||||
|
||||
const unsigned char ETHERNET_BROADCAST_ADDRESS[] = {0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU};
|
||||
// Multicast address '01:00:5E:00:00:01' - IP: '224.0.0.1' (send to all)
|
||||
const unsigned char TOALL_MULTICAST_ADDRESS[] = {0x01U, 0x00U, 0x5EU, 0x00U, 0x00U, 0x01U};
|
||||
// Multicast address '01:00:5E:00:00:23' - IP: '224.0.0.35' (DX-Cluster)
|
||||
const unsigned char DX_MULTICAST_ADDRESS[] = {0x01U, 0x00U, 0x5EU, 0x00U, 0x00U, 0x23U};
|
||||
|
||||
CIRCDDB* CDDHandler::m_irc = NULL;
|
||||
CHeaderLogger* CDDHandler::m_headerLogger = NULL;
|
||||
int CDDHandler::m_fd = -1;
|
||||
unsigned int CDDHandler::m_maxRoutes = 0U;
|
||||
CEthernet** CDDHandler::m_list = NULL;
|
||||
unsigned char* CDDHandler::m_buffer = NULL;
|
||||
bool CDDHandler::m_logEnabled = false;
|
||||
wxString CDDHandler::m_logDir = wxEmptyString;
|
||||
wxString CDDHandler::m_name = wxEmptyString;
|
||||
CTimer CDDHandler::m_timer = CTimer(1000U, MIN_HEARD_TIME_SECS);
|
||||
|
||||
CEthernet::CEthernet(const unsigned char* address, const wxString& callsign) :
|
||||
m_address(NULL),
|
||||
m_callsign(callsign)
|
||||
{
|
||||
wxASSERT(address != NULL);
|
||||
wxASSERT(!callsign.IsEmpty());
|
||||
|
||||
m_address = new unsigned char[ETHERNET_ADDRESS_LENGTH];
|
||||
::memcpy(m_address, address, ETHERNET_ADDRESS_LENGTH);
|
||||
}
|
||||
|
||||
CEthernet::~CEthernet()
|
||||
{
|
||||
delete[] m_address;
|
||||
}
|
||||
|
||||
unsigned char* CEthernet::getAddress() const
|
||||
{
|
||||
return m_address;
|
||||
}
|
||||
|
||||
wxString CEthernet::getCallsign() const
|
||||
{
|
||||
return m_callsign;
|
||||
}
|
||||
|
||||
void CDDHandler::initialise(unsigned int maxRoutes, const wxString& name)
|
||||
{
|
||||
wxASSERT(maxRoutes > 0U);
|
||||
|
||||
m_maxRoutes = maxRoutes;
|
||||
m_name = name;
|
||||
|
||||
m_buffer = new unsigned char[BUFFER_LENGTH];
|
||||
|
||||
m_list = new CEthernet*[maxRoutes];
|
||||
for (unsigned int i = 0U; i < maxRoutes; i++)
|
||||
m_list[i] = NULL;
|
||||
|
||||
// Add a dummy entry for broadcasts
|
||||
m_list[0] = new CEthernet(ETHERNET_BROADCAST_ADDRESS, wxT(" "));
|
||||
// Add a dummy entry for "to all" multicast
|
||||
m_list[1] = new CEthernet(TOALL_MULTICAST_ADDRESS, wxT("CQCQCQ "));
|
||||
// Add a dummy entry for "DX-Cluster" multicast
|
||||
m_list[2] = new CEthernet(DX_MULTICAST_ADDRESS, wxT("CQCQCQ "));
|
||||
|
||||
#if !defined(WIN32)
|
||||
m_fd = ::open("/dev/net/tun", O_RDWR);
|
||||
if (m_fd < 0) {
|
||||
wxLogError(wxT("Cannot open /dev/net/tun"));
|
||||
return;
|
||||
}
|
||||
|
||||
struct ifreq ifr1;
|
||||
::memset(&ifr1, 0x00, sizeof(struct ifreq));
|
||||
|
||||
ifr1.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
::strcpy(ifr1.ifr_name, "tap%d");
|
||||
|
||||
if (::ioctl(m_fd, TUNSETIFF, (void *)&ifr1) < 0) {
|
||||
wxLogError(wxT("TUNSETIFF ioctl failed, closing the tap device"));
|
||||
::close(m_fd);
|
||||
m_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
wxString device = wxString(ifr1.ifr_name, wxConvLocal);
|
||||
wxLogMessage(wxT("DD mode Tap interface created on %s"), device.c_str());
|
||||
|
||||
int fd = ::socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
wxLogError(wxT("Unable to open the config socket, closing the tap device"));
|
||||
::close(m_fd);
|
||||
m_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
struct ifreq ifr2;
|
||||
::memset(&ifr2, 0x00, sizeof(struct ifreq));
|
||||
::strcpy(ifr2.ifr_name, ifr1.ifr_name);
|
||||
|
||||
ifr2.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_MULTICAST;
|
||||
if (::ioctl(fd, SIOCSIFFLAGS, (void *)&ifr2) < 0) {
|
||||
wxLogError(wxT("SIOCSIFFLAGS ioctl failed, closing the tap device"));
|
||||
::close(m_fd);
|
||||
m_fd = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
::close(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CDDHandler::setLogging(bool enabled, const wxString& dir)
|
||||
{
|
||||
m_logDir = dir;
|
||||
m_logEnabled = enabled;
|
||||
}
|
||||
|
||||
void CDDHandler::setHeaderLogger(CHeaderLogger* logger)
|
||||
{
|
||||
m_headerLogger = logger;
|
||||
}
|
||||
|
||||
void CDDHandler::setIRC(CIRCDDB* irc)
|
||||
{
|
||||
wxASSERT(irc != NULL);
|
||||
|
||||
m_irc = irc;
|
||||
}
|
||||
|
||||
void CDDHandler::process(CDDData& data)
|
||||
{
|
||||
// If we're not initialised, return immediately
|
||||
if (m_maxRoutes == 0U)
|
||||
return;
|
||||
|
||||
unsigned char flag1 = data.getFlag1();
|
||||
unsigned char flag2 = data.getFlag2();
|
||||
unsigned char flag3 = data.getFlag3();
|
||||
wxString myCall1 = data.getMyCall1();
|
||||
wxString myCall2 = data.getMyCall2();
|
||||
wxString yourCall = data.getYourCall();
|
||||
wxString rptCall1 = data.getRptCall1();
|
||||
wxString rptCall2 = data.getRptCall2();
|
||||
|
||||
if (!m_timer.isRunning() || m_timer.hasExpired()) {
|
||||
// Write to Header.log if it's enabled
|
||||
if (m_headerLogger != NULL)
|
||||
m_headerLogger->write(wxT("Repeater"), data);
|
||||
|
||||
if (m_irc != NULL) {
|
||||
m_irc->sendHeardWithTXMsg(myCall1, myCall2, yourCall, rptCall1, rptCall2, flag1, flag2, flag3, wxEmptyString, wxT("Digital Data "));
|
||||
m_irc->sendHeardWithTXStats(myCall1, myCall2, yourCall, rptCall1, rptCall2, flag1, flag2, flag3, 1, 0, -1);
|
||||
}
|
||||
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
// Can we continue?
|
||||
if (m_fd < 0)
|
||||
return;
|
||||
|
||||
unsigned char* address = data.getSourceAddress();
|
||||
|
||||
bool found = false;
|
||||
for (unsigned int i = 0U; i < m_maxRoutes; i++) {
|
||||
if (m_list[i] != NULL) {
|
||||
unsigned char* addr = m_list[i]->getAddress();
|
||||
|
||||
if (::memcmp(addr, address, ETHERNET_ADDRESS_LENGTH) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
wxLogMessage(wxT("Adding DD user %s with ethernet address %02X:%02X:%02X:%02X:%02X:%02X"), myCall1.c_str(),
|
||||
address[0], address[1], address[2], address[3], address[4], address[5]);
|
||||
|
||||
CEthernet* ethernet = new CEthernet(address, myCall1);
|
||||
|
||||
found = false;
|
||||
for (unsigned int i = 0U; i < m_maxRoutes; i++) {
|
||||
if (m_list[i] == NULL) {
|
||||
m_list[i] = ethernet;
|
||||
found = true;
|
||||
if (m_logEnabled)
|
||||
writeStatus(*ethernet);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
wxLogError(wxT("No space to add new DD ethernet address"));
|
||||
delete ethernet;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(WIN32)
|
||||
unsigned int length = data.getEthernetFrame(m_buffer, BUFFER_LENGTH);
|
||||
|
||||
ssize_t len = ::write(m_fd, (char*)m_buffer, length);
|
||||
if (len != ssize_t(length))
|
||||
wxLogError(wxT("Error returned from write()"));
|
||||
#endif
|
||||
}
|
||||
|
||||
CDDData* CDDHandler::read()
|
||||
{
|
||||
// If we're not initialised, return immediately
|
||||
if (m_maxRoutes == 0U)
|
||||
return NULL;
|
||||
|
||||
#if defined(WIN32)
|
||||
return NULL;
|
||||
#else
|
||||
// Check that the read() won't block
|
||||
fd_set readFds;
|
||||
FD_ZERO(&readFds);
|
||||
#if defined(__WINDOWS__)
|
||||
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) {
|
||||
wxLogError(wxT("Error returned from select()"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined(__WINDOWS__)
|
||||
if (!FD_ISSET((unsigned int)m_fd, &readFds))
|
||||
return NULL;
|
||||
#else
|
||||
if (!FD_ISSET(m_fd, &readFds))
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
// Ensure that the minimum length is padded with 0x00s
|
||||
::memset(m_buffer, 0x00U, MINIMUM_DD_FRAME_LENGTH);
|
||||
|
||||
ssize_t len = ::read(m_fd, (char*)m_buffer, BUFFER_LENGTH);
|
||||
if (len <= 0) {
|
||||
wxLogError(wxT("Error returned from read()"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// There seems to be a minimum size with DD mode, so pad with zeroes if it's not reached
|
||||
if (len < MINIMUM_DD_FRAME_LENGTH)
|
||||
len = MINIMUM_DD_FRAME_LENGTH;
|
||||
|
||||
// Point to the destination ethernet address
|
||||
unsigned char* address = m_buffer + 0U;
|
||||
|
||||
// Do destination address to callsign lookup
|
||||
CEthernet* ethernet = NULL;
|
||||
for (unsigned int i = 0U; i < m_maxRoutes; i++) {
|
||||
if (m_list[i] != NULL) {
|
||||
unsigned char* addr = m_list[i]->getAddress();
|
||||
|
||||
if (::memcmp(addr, address, ETHERNET_ADDRESS_LENGTH) == 0) {
|
||||
ethernet = m_list[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ethernet == NULL) {
|
||||
wxLogWarning(wxT("Cannot find the ethernet address of %02X:%02X:%02X:%02X:%02X:%02X in the ethernet list"), address[0], address[1], address[2], address[3], address[4], address[5]);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CRepeaterHandler* handler = CRepeaterHandler::findDDRepeater();
|
||||
if (handler == NULL) {
|
||||
wxLogWarning(wxT("Incoming DD data to unknown repeater"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// wxLogMessage(wxT("Mapping ethernet address %02X:%02X:%02X:%02X:%02X:%02X to user %s"),
|
||||
// address[0], address[1], address[2], address[3], address[4], address[5],
|
||||
// ethernet->getCallsign().c_str());
|
||||
|
||||
CDDData* data = new CDDData;
|
||||
data->setEthernetFrame(m_buffer, len);
|
||||
data->setYourCall(ethernet->getCallsign());
|
||||
|
||||
handler->process(*data);
|
||||
|
||||
return data;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CDDHandler::clock(unsigned int ms)
|
||||
{
|
||||
m_timer.clock(ms);
|
||||
}
|
||||
|
||||
void CDDHandler::finalise()
|
||||
{
|
||||
#if !defined(WIN32)
|
||||
if (m_fd >= 0) {
|
||||
::close(m_fd);
|
||||
m_fd = -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
delete[] m_buffer;
|
||||
|
||||
for (unsigned int i = 0U; i < m_maxRoutes; i++)
|
||||
delete m_list[i];
|
||||
delete[] m_list;
|
||||
}
|
||||
|
||||
void CDDHandler::writeStatus(const CEthernet& ethernet)
|
||||
{
|
||||
wxString fullName = DDMODE_BASE_NAME;
|
||||
|
||||
if (!m_name.IsEmpty()) {
|
||||
fullName.Append(wxT("_"));
|
||||
fullName.Append(m_name);
|
||||
}
|
||||
|
||||
wxFileName fileName(m_logDir, fullName, wxT("log"));
|
||||
|
||||
wxFFile file;
|
||||
bool ret = file.Open(fileName.GetFullPath(), wxT("at"));
|
||||
if (!ret) {
|
||||
wxLogError(wxT("Unable to open %s for writing"), fileName.GetFullPath().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
wxString callsign = ethernet.getCallsign();
|
||||
unsigned char* address = ethernet.getAddress();
|
||||
|
||||
time_t timeNow = ::time(NULL);
|
||||
struct tm* tm = ::gmtime(&timeNow);
|
||||
|
||||
wxString text;
|
||||
text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: %02X:%02X:%02X:%02X:%02X:%02X %s\n"),
|
||||
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
|
||||
address[0], address[1], address[2], address[3], address[4], address[5], callsign.c_str());
|
||||
|
||||
file.Write(text);
|
||||
|
||||
file.Close();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue