parent
de244cd5f3
commit
b68a899510
@ -0,0 +1,274 @@
|
||||
/*
|
||||
* Copyright (C) 2012,2013,2015 by Jonathan Naylor G4KLX
|
||||
* Copyright (c) 2021 by Geoffrey Merck F4FXL / KC3FRA
|
||||
*
|
||||
* 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 "DPlusAuthenticator.h"
|
||||
#include "UDPReaderWriter.h"
|
||||
#include "DStarDefines.h"
|
||||
#include "Utils.h"
|
||||
#include "Defs.h"
|
||||
|
||||
const wxString OPENDSTAR_HOSTNAME = wxT("auth.dstargateway.org");
|
||||
const unsigned int OPENDSTAR_PORT = 20001U;
|
||||
|
||||
const unsigned int TCP_TIMEOUT = 10U;
|
||||
|
||||
CDPlusAuthenticator::CDPlusAuthenticator(const wxString& loginCallsign, const wxString& gatewayCallsign, const wxString& address, CCacheManager* cache) :
|
||||
wxThread(wxTHREAD_JOINABLE),
|
||||
m_loginCallsign(loginCallsign),
|
||||
m_gatewayCallsign(gatewayCallsign),
|
||||
m_address(address),
|
||||
m_cache(cache),
|
||||
m_timer(1U, 6U * 3600U), // 6 hours
|
||||
m_killed(false)
|
||||
{
|
||||
wxASSERT(!loginCallsign.IsEmpty());
|
||||
wxASSERT(!gatewayCallsign.IsEmpty());
|
||||
wxASSERT(cache != NULL);
|
||||
|
||||
m_gatewayCallsign.Truncate(LONG_CALLSIGN_LENGTH - 1U);
|
||||
|
||||
m_loginCallsign.Trim();
|
||||
m_gatewayCallsign.Trim();
|
||||
|
||||
if (m_loginCallsign.IsEmpty())
|
||||
m_loginCallsign = m_gatewayCallsign;
|
||||
}
|
||||
|
||||
CDPlusAuthenticator::~CDPlusAuthenticator()
|
||||
{
|
||||
}
|
||||
|
||||
void CDPlusAuthenticator::start()
|
||||
{
|
||||
Create();
|
||||
Run();
|
||||
}
|
||||
|
||||
void* CDPlusAuthenticator::Entry()
|
||||
{
|
||||
wxLogMessage(wxT("Starting the D-Plus Authenticator thread"));
|
||||
|
||||
authenticate(m_loginCallsign, OPENDSTAR_HOSTNAME, OPENDSTAR_PORT, '2', true);
|
||||
|
||||
m_timer.start();
|
||||
|
||||
try {
|
||||
while (!m_killed) {
|
||||
if (m_timer.hasExpired()) {
|
||||
authenticate(m_loginCallsign, OPENDSTAR_HOSTNAME, OPENDSTAR_PORT, '2', true);
|
||||
m_timer.start();
|
||||
}
|
||||
|
||||
Sleep(1000UL);
|
||||
|
||||
m_timer.clock();
|
||||
}
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
wxString message(e.what(), wxConvLocal);
|
||||
wxLogError(wxT("Exception raised in the D-Plus Authenticator thread - \"%s\""), message.c_str());
|
||||
}
|
||||
catch (...) {
|
||||
wxLogError(wxT("Unknown exception raised in the D-Plus Authenticator thread"));
|
||||
}
|
||||
|
||||
wxLogMessage(wxT("Stopping the D-Plus Authenticator thread"));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CDPlusAuthenticator::stop()
|
||||
{
|
||||
m_killed = true;
|
||||
|
||||
Wait();
|
||||
}
|
||||
|
||||
bool CDPlusAuthenticator::authenticate(const wxString& callsign, const wxString& hostname, unsigned int port, unsigned char id, bool writeToCache)
|
||||
{
|
||||
CTCPReaderWriterClient socket(hostname, port, m_address);
|
||||
|
||||
bool ret = socket.open();
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
unsigned char* buffer = new unsigned char[4096U];
|
||||
::memset(buffer, ' ', 56U);
|
||||
|
||||
buffer[0U] = 0x38U;
|
||||
buffer[1U] = 0xC0U;
|
||||
buffer[2U] = 0x01U;
|
||||
buffer[3U] = 0x00U;
|
||||
|
||||
for (unsigned int i = 0U; i < callsign.Len(); i++)
|
||||
buffer[i + 4U] = callsign.GetChar(i);
|
||||
|
||||
buffer[12U] = 'D';
|
||||
buffer[13U] = 'V';
|
||||
buffer[14U] = '0';
|
||||
buffer[15U] = '1';
|
||||
buffer[16U] = '9';
|
||||
buffer[17U] = '9';
|
||||
buffer[18U] = '9';
|
||||
buffer[19U] = '9';
|
||||
|
||||
buffer[28U] = 'W';
|
||||
buffer[29U] = '7';
|
||||
buffer[30U] = 'I';
|
||||
buffer[31U] = 'B';
|
||||
buffer[32U] = id;
|
||||
|
||||
buffer[40U] = 'D';
|
||||
buffer[41U] = 'H';
|
||||
buffer[42U] = 'S';
|
||||
buffer[43U] = '0';
|
||||
buffer[44U] = '2';
|
||||
buffer[45U] = '5';
|
||||
buffer[46U] = '7';
|
||||
|
||||
ret = socket.write(buffer, 56U);
|
||||
if (!ret) {
|
||||
socket.close();
|
||||
delete[] buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = read(socket, buffer + 0U, 2U);
|
||||
|
||||
while (ret) {
|
||||
unsigned int len = (buffer[1U] & 0x0FU) * 256U + buffer[0U];
|
||||
|
||||
// Ensure that we get exactly len - 2U bytes from the TCP stream
|
||||
ret = read(socket, buffer + 2U, len - 2U);
|
||||
if (!ret) {
|
||||
wxLogError(wxT("Short read from %s:%u"), hostname.c_str(), port);
|
||||
break;
|
||||
}
|
||||
|
||||
if ((buffer[1U] & 0xC0U) != 0xC0U || buffer[2U] != 0x01U) {
|
||||
wxLogError(wxT("Invalid packet received from %s:%u"), hostname.c_str(), port);
|
||||
CUtils::dump(wxT("Details:"), buffer, len);
|
||||
break;
|
||||
}
|
||||
|
||||
for (unsigned int i = 8U; (i + 25U) < len; i += 26U) {
|
||||
wxString address = wxString((char*)(buffer + i + 0U), wxConvLocal, 16U);
|
||||
wxString name = wxString((char*)(buffer + i + 16U), wxConvLocal, LONG_CALLSIGN_LENGTH);
|
||||
|
||||
address.Trim();
|
||||
name.Trim();
|
||||
|
||||
// Get the active flag
|
||||
bool active = (buffer[i + 25U] & 0x80U) == 0x80U;
|
||||
|
||||
// An empty name or IP address or an inactive gateway/reflector is not written out
|
||||
if (address.Len() > 0U && name.Len() > 0U && !name.Left(3U).IsSameAs(wxT("XRF")) && active && writeToCache){
|
||||
if (name.Left(3U).IsSameAs(wxT("REF")))
|
||||
wxLogMessage(wxT("D-Plus: %s\t%s"), name.c_str(), address.c_str());
|
||||
|
||||
name.Append(wxT(" "));
|
||||
name.Truncate(LONG_CALLSIGN_LENGTH - 1U);
|
||||
name.Append(wxT("G"));
|
||||
m_cache->updateGateway(name, address, DP_DPLUS, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
ret = read(socket, buffer + 0U, 2U);
|
||||
}
|
||||
|
||||
wxLogMessage(wxT("Registered with %s using callsign %s"), hostname.c_str(), callsign.c_str());
|
||||
|
||||
socket.close();
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDPlusAuthenticator::poll(const wxString& callsign, const wxString& hostname, unsigned int port, unsigned char id)
|
||||
{
|
||||
CUDPReaderWriter socket(m_address, 0U);
|
||||
bool ret = socket.open();
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
unsigned char buffer[56U];
|
||||
::memset(buffer, ' ', 56U);
|
||||
|
||||
buffer[0U] = 0x38U;
|
||||
buffer[1U] = 0x20U;
|
||||
buffer[2U] = 0x01U;
|
||||
buffer[3U] = 0x01U;
|
||||
|
||||
for (unsigned int i = 0U; i < callsign.Len(); i++)
|
||||
buffer[i + 4U] = callsign.GetChar(i);
|
||||
|
||||
buffer[12U] = 'D';
|
||||
buffer[13U] = 'V';
|
||||
buffer[14U] = '0';
|
||||
buffer[15U] = '1';
|
||||
buffer[16U] = '9';
|
||||
buffer[17U] = '9';
|
||||
buffer[18U] = '9';
|
||||
buffer[19U] = '9';
|
||||
|
||||
for (unsigned int i = 0U; i < callsign.Len(); i++)
|
||||
buffer[i + 20U] = callsign.GetChar(i);
|
||||
|
||||
buffer[28U] = 'W';
|
||||
buffer[29U] = '7';
|
||||
buffer[30U] = 'I';
|
||||
buffer[31U] = 'B';
|
||||
buffer[32U] = id;
|
||||
|
||||
buffer[40U] = 'D';
|
||||
buffer[41U] = 'H';
|
||||
buffer[42U] = 'S';
|
||||
buffer[43U] = '0';
|
||||
buffer[44U] = '2';
|
||||
buffer[45U] = '5';
|
||||
buffer[46U] = '7';
|
||||
|
||||
in_addr address = socket.lookup(hostname);
|
||||
if (address.s_addr == INADDR_NONE) {
|
||||
socket.close();
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = socket.write(buffer, 56U, address, port);
|
||||
|
||||
socket.close();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CDPlusAuthenticator::read(CTCPReaderWriterClient &socket, unsigned char *buffer, unsigned int len) const
|
||||
{
|
||||
unsigned int offset = 0U;
|
||||
|
||||
do {
|
||||
int n = socket.read(buffer + offset, len - offset, TCP_TIMEOUT);
|
||||
if (n < 0)
|
||||
return false;
|
||||
|
||||
offset += n;
|
||||
} while ((len - offset) > 0U);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2012,2013,2015 by Jonathan Naylor G4KLX
|
||||
* Copyright (c) 2021 by Geoffrey Merck F4FXL / KC3FRA
|
||||
*
|
||||
* 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 DPlusAuthenticator_H
|
||||
#define DPlusAuthenticator_H
|
||||
|
||||
#include "TCPReaderWriterClient.h"
|
||||
#include "CacheManager.h"
|
||||
#include "Timer.h"
|
||||
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
class CDPlusAuthenticator : public wxThread {
|
||||
public:
|
||||
CDPlusAuthenticator(const wxString& loginCallsign, const wxString& gatewayCallsign, const wxString& address, CCacheManager* cache);
|
||||
virtual ~CDPlusAuthenticator();
|
||||
|
||||
virtual void start();
|
||||
|
||||
virtual void* Entry();
|
||||
|
||||
virtual void stop();
|
||||
|
||||
private:
|
||||
wxString m_loginCallsign;
|
||||
wxString m_gatewayCallsign;
|
||||
wxString m_address;
|
||||
CCacheManager* m_cache;
|
||||
CTimer m_timer;
|
||||
bool m_killed;
|
||||
|
||||
bool poll(const wxString& callsign, const wxString& hostname, unsigned int port, unsigned char id);
|
||||
bool authenticate(const wxString& callsign, const wxString& hostname, unsigned int port, unsigned char id, bool writeToCache);
|
||||
bool read(CTCPReaderWriterClient& socket, unsigned char* buffer, unsigned int len) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,954 @@
|
||||
/*
|
||||
* Copyright (C) 2012,2013,2015 by Jonathan Naylor G4KLX
|
||||
* Copyright (c) 2021 by Geoffrey Merck F4FXL / KC3FRA
|
||||
*
|
||||
* 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 "DPlusHandler.h"
|
||||
#include "DStarDefines.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include <wx/filename.h>
|
||||
|
||||
unsigned int CDPlusHandler::m_maxReflectors = 0U;
|
||||
unsigned int CDPlusHandler::m_maxDongles = 0U;
|
||||
CDPlusHandler** CDPlusHandler::m_reflectors = NULL;
|
||||
|
||||
wxString CDPlusHandler::m_gatewayCallsign;
|
||||
wxString CDPlusHandler::m_dplusLogin;
|
||||
CDPlusProtocolHandlerPool* CDPlusHandler::m_pool = NULL;
|
||||
CDPlusProtocolHandler* CDPlusHandler::m_incoming = NULL;
|
||||
|
||||
bool CDPlusHandler::m_stateChange = false;
|
||||
|
||||
CDPlusAuthenticator* CDPlusHandler::m_authenticator = NULL;
|
||||
CHeaderLogger* CDPlusHandler::m_headerLogger = NULL;
|
||||
|
||||
CCallsignList* CDPlusHandler::m_whiteList = NULL;
|
||||
CCallsignList* CDPlusHandler::m_blackList = NULL;
|
||||
|
||||
|
||||
CDPlusHandler::CDPlusHandler(IReflectorCallback* handler, const wxString& repeater, const wxString& reflector, CDPlusProtocolHandler* protoHandler, const in_addr& address, unsigned int port) :
|
||||
m_repeater(repeater.Clone()),
|
||||
m_callsign(m_dplusLogin.Clone()),
|
||||
m_reflector(reflector.Clone()),
|
||||
m_handler(protoHandler),
|
||||
m_yourAddress(address),
|
||||
m_yourPort(port),
|
||||
m_myPort(0U),
|
||||
m_direction(DIR_OUTGOING),
|
||||
m_linkState(DPLUS_LINKING),
|
||||
m_destination(handler),
|
||||
m_time(),
|
||||
m_pollTimer(1000U, 1U), // 1s
|
||||
m_pollInactivityTimer(1000U, 30U),
|
||||
m_tryTimer(1000U, 1U),
|
||||
m_tryCount(0U),
|
||||
m_dPlusId(0x00U),
|
||||
m_dPlusSeq(0x00U),
|
||||
m_inactivityTimer(1000U, NETWORK_TIMEOUT),
|
||||
m_header(NULL)
|
||||
{
|
||||
wxASSERT(protoHandler != NULL);
|
||||
wxASSERT(handler != NULL);
|
||||
wxASSERT(port > 0U);
|
||||
|
||||
m_myPort = protoHandler->getPort();
|
||||
|
||||
m_pollInactivityTimer.start();
|
||||
m_tryTimer.start();
|
||||
|
||||
m_time = ::time(NULL);
|
||||
|
||||
m_callsign.resize(LONG_CALLSIGN_LENGTH, ' ');
|
||||
wxChar band = m_repeater.GetChar(LONG_CALLSIGN_LENGTH - 1U);
|
||||
m_callsign.SetChar(LONG_CALLSIGN_LENGTH - 1U, band);
|
||||
}
|
||||
|
||||
CDPlusHandler::CDPlusHandler(CDPlusProtocolHandler* protoHandler, const in_addr& address, unsigned int port) :
|
||||
m_repeater(),
|
||||
m_callsign(),
|
||||
m_reflector(),
|
||||
m_handler(protoHandler),
|
||||
m_yourAddress(address),
|
||||
m_yourPort(port),
|
||||
m_myPort(0U),
|
||||
m_direction(DIR_INCOMING),
|
||||
m_linkState(DPLUS_LINKING),
|
||||
m_destination(NULL),
|
||||
m_time(),
|
||||
m_pollTimer(1000U, 1U), // 1s
|
||||
m_pollInactivityTimer(1000U, 10U), // 10s
|
||||
m_tryTimer(1000U),
|
||||
m_tryCount(0U),
|
||||
m_dPlusId(0x00U),
|
||||
m_dPlusSeq(0x00U),
|
||||
m_inactivityTimer(1000U, NETWORK_TIMEOUT),
|
||||
m_header(NULL)
|
||||
{
|
||||
wxASSERT(protoHandler != NULL);
|
||||
wxASSERT(port > 0U);
|
||||
|
||||
m_myPort = protoHandler->getPort();
|
||||
|
||||
m_pollTimer.start();
|
||||
m_pollInactivityTimer.start();
|
||||
|
||||
m_time = ::time(NULL);
|
||||
}
|
||||
|
||||
CDPlusHandler::~CDPlusHandler()
|
||||
{
|
||||
if (m_direction == DIR_OUTGOING)
|
||||
m_pool->release(m_handler);
|
||||
|
||||
delete m_header;
|
||||
}
|
||||
|
||||
void CDPlusHandler::initialise(unsigned int maxReflectors)
|
||||
{
|
||||
wxASSERT(maxReflectors > 0U);
|
||||
|
||||
m_maxReflectors = maxReflectors;
|
||||
|
||||
m_reflectors = new CDPlusHandler*[m_maxReflectors];
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++)
|
||||
m_reflectors[i] = NULL;
|
||||
}
|
||||
|
||||
void CDPlusHandler::startAuthenticator(const wxString& address, CCacheManager* cache)
|
||||
{
|
||||
wxASSERT(cache != NULL);
|
||||
|
||||
m_authenticator = new CDPlusAuthenticator(m_dplusLogin, m_gatewayCallsign, address, cache);
|
||||
m_authenticator->start();
|
||||
}
|
||||
|
||||
void CDPlusHandler::setCallsign(const wxString& callsign)
|
||||
{
|
||||
m_gatewayCallsign = callsign;
|
||||
}
|
||||
|
||||
void CDPlusHandler::setDPlusProtocolHandlerPool(CDPlusProtocolHandlerPool* pool)
|
||||
{
|
||||
wxASSERT(pool != NULL);
|
||||
|
||||
m_pool = pool;
|
||||
}
|
||||
|
||||
void CDPlusHandler::setDPlusProtocolIncoming(CDPlusProtocolHandler* handler)
|
||||
{
|
||||
wxASSERT(handler != NULL);
|
||||
|
||||
m_incoming = handler;
|
||||
}
|
||||
|
||||
void CDPlusHandler::setDPlusLogin(const wxString& dplusLogin)
|
||||
{
|
||||
m_dplusLogin = dplusLogin;
|
||||
}
|
||||
|
||||
void CDPlusHandler::setHeaderLogger(CHeaderLogger* logger)
|
||||
{
|
||||
m_headerLogger = logger;
|
||||
}
|
||||
|
||||
void CDPlusHandler::setMaxDongles(unsigned int maxDongles)
|
||||
{
|
||||
m_maxDongles = maxDongles;
|
||||
}
|
||||
|
||||
void CDPlusHandler::setWhiteList(CCallsignList* list)
|
||||
{
|
||||
wxASSERT(list != NULL);
|
||||
|
||||
m_whiteList = list;
|
||||
}
|
||||
|
||||
void CDPlusHandler::setBlackList(CCallsignList* list)
|
||||
{
|
||||
wxASSERT(list != NULL);
|
||||
|
||||
m_blackList = list;
|
||||
}
|
||||
|
||||
void CDPlusHandler::getInfo(IReflectorCallback* handler, CRemoteRepeaterData& data)
|
||||
{
|
||||
wxASSERT(handler != NULL);
|
||||
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
CDPlusHandler* reflector = m_reflectors[i];
|
||||
if (reflector != NULL) {
|
||||
if (reflector->m_destination == handler && reflector->m_linkState != DPLUS_UNLINKING)
|
||||
data.addLink(reflector->m_reflector, PROTO_DPLUS, reflector->m_linkState == DPLUS_LINKED, reflector->m_direction, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxString CDPlusHandler::getDongles()
|
||||
{
|
||||
wxString dongles;
|
||||
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
CDPlusHandler* reflector = m_reflectors[i];
|
||||
|
||||
if (reflector != NULL && reflector->m_direction == DIR_INCOMING) {
|
||||
dongles.Append(wxT("P:"));
|
||||
dongles.Append(reflector->m_reflector);
|
||||
dongles.Append(wxT(" "));
|
||||
}
|
||||
}
|
||||
|
||||
return dongles;
|
||||
}
|
||||
|
||||
void CDPlusHandler::process(CHeaderData& header)
|
||||
{
|
||||
in_addr yourAddress = header.getYourAddress();
|
||||
unsigned int yourPort = header.getYourPort();
|
||||
unsigned int myPort = header.getMyPort();
|
||||
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
CDPlusHandler* reflector = m_reflectors[i];
|
||||
|
||||
if (reflector != NULL) {
|
||||
if (reflector->m_yourAddress.s_addr == yourAddress.s_addr &&
|
||||
reflector->m_yourPort == yourPort &&
|
||||
reflector->m_myPort == myPort) {
|
||||
reflector->processInt(header);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDPlusHandler::process(CAMBEData& data)
|
||||
{
|
||||
in_addr yourAddress = data.getYourAddress();
|
||||
unsigned int yourPort = data.getYourPort();
|
||||
unsigned int myPort = data.getMyPort();
|
||||
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
CDPlusHandler* reflector = m_reflectors[i];
|
||||
|
||||
if (reflector != NULL) {
|
||||
if (reflector->m_yourAddress.s_addr == yourAddress.s_addr &&
|
||||
reflector->m_yourPort == yourPort &&
|
||||
reflector->m_myPort == myPort) {
|
||||
reflector->processInt(data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDPlusHandler::process(const CPollData& poll)
|
||||
{
|
||||
in_addr yourAddress = poll.getYourAddress();
|
||||
unsigned int yourPort = poll.getYourPort();
|
||||
unsigned int myPort = poll.getMyPort();
|
||||
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
CDPlusHandler* reflector = m_reflectors[i];
|
||||
|
||||
if (reflector != NULL) {
|
||||
if (reflector->m_yourAddress.s_addr == yourAddress.s_addr &&
|
||||
reflector->m_yourPort == yourPort &&
|
||||
reflector->m_myPort == myPort) {
|
||||
reflector->m_pollInactivityTimer.start();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we cannot find an existing link, we ignore the poll
|
||||
wxLogMessage(wxT("Incoming poll from unknown D-Plus dongle"));
|
||||
}
|
||||
|
||||
void CDPlusHandler::process(CConnectData& connect)
|
||||
{
|
||||
CD_TYPE type = connect.getType();
|
||||
in_addr yourAddress = connect.getYourAddress();
|
||||
unsigned int yourPort = connect.getYourPort();
|
||||
unsigned int myPort = connect.getMyPort();
|
||||
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
CDPlusHandler* reflector = m_reflectors[i];
|
||||
|
||||
if (reflector != NULL) {
|
||||
if (reflector->m_yourAddress.s_addr == yourAddress.s_addr &&
|
||||
reflector->m_yourPort == yourPort &&
|
||||
reflector->m_myPort == myPort) {
|
||||
bool res = m_reflectors[i]->processInt(connect, type);
|
||||
if (res) {
|
||||
delete m_reflectors[i];
|
||||
m_reflectors[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that it isn't a duplicate
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
CDPlusHandler* reflector = m_reflectors[i];
|
||||
|
||||
if (reflector != NULL) {
|
||||
if (reflector->m_yourAddress.s_addr == yourAddress.s_addr &&
|
||||
reflector->m_yourPort == yourPort &&
|
||||
reflector->m_myPort == myPort)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (type == CT_UNLINK)
|
||||
return;
|
||||
|
||||
if (type != CT_LINK1) {
|
||||
wxLogMessage(wxT("Incoming D-Plus message from unknown source"));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if we are allowed to accept it
|
||||
unsigned int count = 0U;
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
if (m_reflectors[i] != NULL &&
|
||||
m_reflectors[i]->m_direction == DIR_INCOMING)
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count >= m_maxDongles)
|
||||
return;
|
||||
|
||||
CDPlusHandler* dplus = new CDPlusHandler(m_incoming, yourAddress, yourPort);
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
if (m_reflectors[i] == NULL) {
|
||||
m_reflectors[i] = dplus;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
CConnectData connect(CT_LINK1, yourAddress, yourPort);
|
||||
m_incoming->writeConnect(connect);
|
||||
} else {
|
||||
wxLogError(wxT("No space to add new D-Plus dongle, ignoring"));
|
||||
delete dplus;
|
||||
}
|
||||
}
|
||||
|
||||
void CDPlusHandler::link(IReflectorCallback* handler, const wxString& repeater, const wxString &gateway, const in_addr& address)
|
||||
{
|
||||
CDPlusProtocolHandler* protoHandler = m_pool->getHandler();
|
||||
if (protoHandler == NULL)
|
||||
return;
|
||||
|
||||
CDPlusHandler* dplus = new CDPlusHandler(handler, repeater, gateway, protoHandler, address, DPLUS_PORT);
|
||||
|
||||
bool found = false;
|
||||
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
if (m_reflectors[i] == NULL) {
|
||||
m_reflectors[i] = dplus;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
CConnectData connect(CT_LINK1, address, DPLUS_PORT);
|
||||
protoHandler->writeConnect(connect);
|
||||
m_stateChange = true;
|
||||
} else {
|
||||
wxLogError(wxT("No space to add new D-Plus reflector, ignoring"));
|
||||
delete dplus;
|
||||
}
|
||||
}
|
||||
|
||||
void CDPlusHandler::relink(IReflectorCallback* handler, const wxString &gateway)
|
||||
{
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
if (m_reflectors[i] != NULL && m_reflectors[i]->m_direction == DIR_OUTGOING) {
|
||||
if (m_reflectors[i]->m_destination == handler) {
|
||||
m_reflectors[i]->m_reflector = gateway;
|
||||
m_reflectors[i]->m_dPlusId = 0x00U;
|
||||
m_reflectors[i]->m_dPlusSeq = 0x00U;
|
||||
m_stateChange = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDPlusHandler::unlink(IReflectorCallback* handler, const wxString& callsign, bool exclude)
|
||||
{
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
CDPlusHandler* reflector = m_reflectors[i];
|
||||
|
||||
if (reflector != NULL) {
|
||||
bool found = false;
|
||||
|
||||
if (exclude) {
|
||||
if (reflector->m_direction == DIR_OUTGOING && reflector->m_destination == handler && !reflector->m_reflector.IsSameAs(callsign)) {
|
||||
wxLogMessage(wxT("Removing outgoing D-Plus link %s, %s"), reflector->m_repeater.c_str(), reflector->m_reflector.c_str());
|
||||
|
||||
if (reflector->m_linkState == DPLUS_LINKING || reflector->m_linkState == DPLUS_LINKED) {
|
||||
CConnectData connect(CT_UNLINK, reflector->m_yourAddress, DPLUS_PORT);
|
||||
reflector->m_handler->writeConnect(connect);
|
||||
reflector->m_handler->writeConnect(connect);
|
||||
|
||||
reflector->m_linkState = DPLUS_UNLINKING;
|
||||
reflector->m_tryTimer.start(1U);
|
||||
reflector->m_pollTimer.stop();
|
||||
reflector->m_pollInactivityTimer.stop();
|
||||
reflector->m_tryCount = 0U;
|
||||
}
|
||||
|
||||
found = true;
|
||||
}
|
||||
} else {
|
||||
if (reflector->m_destination == handler && reflector->m_reflector.IsSameAs(callsign)) {
|
||||
wxLogMessage(wxT("Removing D-Plus link %s, %s"), reflector->m_repeater.c_str(), reflector->m_reflector.c_str());
|
||||
|
||||
if (reflector->m_linkState == DPLUS_LINKING || reflector->m_linkState == DPLUS_LINKED) {
|
||||
CConnectData connect(CT_UNLINK, reflector->m_yourAddress, DPLUS_PORT);
|
||||
reflector->m_handler->writeConnect(connect);
|
||||
reflector->m_handler->writeConnect(connect);
|
||||
|
||||
reflector->m_linkState = DPLUS_UNLINKING;
|
||||
reflector->m_tryTimer.start(1U);
|
||||
reflector->m_pollTimer.stop();
|
||||
reflector->m_pollInactivityTimer.stop();
|
||||
reflector->m_tryCount = 0U;
|
||||
}
|
||||
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If an active link with incoming traffic, send an EOT to the repeater
|
||||
if (found) {
|
||||
if (reflector->m_dPlusId != 0x00U) {
|
||||
unsigned int seq = reflector->m_dPlusSeq + 1U;
|
||||
if (seq == 21U)
|
||||
seq = 0U;
|
||||
|
||||
CAMBEData data;
|
||||
data.setData(END_PATTERN_BYTES, DV_FRAME_LENGTH_BYTES);
|
||||
data.setSeq(seq);
|
||||
data.setEnd(true);
|
||||
data.setId(reflector->m_dPlusId);
|
||||
|
||||
reflector->m_destination->process(data, reflector->m_direction, AS_DPLUS);
|
||||
}
|
||||
|
||||
m_stateChange = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDPlusHandler::unlink()
|
||||
{
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
CDPlusHandler* reflector = m_reflectors[i];
|
||||
if (reflector != NULL) {
|
||||
if (!reflector->m_reflector.IsEmpty())
|
||||
wxLogMessage(wxT("Unlinking from D-Plus reflector or dongle %s"), reflector->m_reflector.c_str());
|
||||
|
||||
CConnectData connect(CT_UNLINK, reflector->m_yourAddress, reflector->m_yourPort);
|
||||
reflector->m_handler->writeConnect(connect);
|
||||
reflector->m_handler->writeConnect(connect);
|
||||
reflector->m_tryTimer.start(1U);
|
||||
reflector->m_pollTimer.stop();
|
||||
reflector->m_pollInactivityTimer.stop();
|
||||
reflector->m_tryCount = 0U;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDPlusHandler::writeHeader(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction)
|
||||
{
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
if (m_reflectors[i] != NULL)
|
||||
m_reflectors[i]->writeHeaderInt(handler, header, direction);
|
||||
}
|
||||
}
|
||||
|
||||
void CDPlusHandler::writeAMBE(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction)
|
||||
{
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
if (m_reflectors[i] != NULL)
|
||||
m_reflectors[i]->writeAMBEInt(handler, data, direction);
|
||||
}
|
||||
}
|
||||
|
||||
void CDPlusHandler::gatewayUpdate(const wxString& gateway, const wxString& address)
|
||||
{
|
||||
wxString gatewayBase = gateway;
|
||||
gatewayBase.Truncate(LONG_CALLSIGN_LENGTH - 1U);
|
||||
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
CDPlusHandler* reflector = m_reflectors[i];
|
||||
if (reflector != NULL) {
|
||||
if (!reflector->m_reflector.IsEmpty() && reflector->m_reflector.Left(LONG_CALLSIGN_LENGTH - 1U).IsSameAs(gatewayBase)) {
|
||||
if (!address.IsEmpty()) {
|
||||
// A new address, change the value
|
||||
wxLogMessage(wxT("Changing IP address of D-Plus gateway or reflector %s to %s"), gatewayBase.c_str(), address.c_str());
|
||||
reflector->m_yourAddress.s_addr = ::inet_addr(address.mb_str());
|
||||
} else {
|
||||
wxLogMessage(wxT("IP address for D-Plus gateway or reflector %s has been removed"), gatewayBase.c_str());
|
||||
|
||||
// No address, this probably shouldn't happen....
|
||||
if (reflector->m_direction == DIR_OUTGOING && reflector->m_destination != NULL)
|
||||
reflector->m_destination->linkFailed(DP_DPLUS, reflector->m_reflector, false);
|
||||
|
||||
m_stateChange = true;
|
||||
|
||||
delete m_reflectors[i];
|
||||
m_reflectors[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDPlusHandler::clock(unsigned int ms)
|
||||
{
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
if (m_reflectors[i] != NULL) {
|
||||
bool ret = m_reflectors[i]->clockInt(ms);
|
||||
if (ret) {
|
||||
delete m_reflectors[i];
|
||||
m_reflectors[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDPlusHandler::finalise()
|
||||
{
|
||||
if (m_authenticator != NULL)
|
||||
m_authenticator->stop();
|
||||
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++)
|
||||
delete m_reflectors[i];
|
||||
|
||||
delete[] m_reflectors;
|
||||
}
|
||||
|
||||
void CDPlusHandler::processInt(CHeaderData& header)
|
||||
{
|
||||
wxString my = header.getMyCall1();
|
||||
wxString rpt1 = header.getRptCall1();
|
||||
wxString rpt2 = header.getRptCall2();
|
||||
unsigned int id = header.getId();
|
||||
|
||||
if (m_whiteList != NULL) {
|
||||
bool res = m_whiteList->isInList(my);
|
||||
if (!res) {
|
||||
wxLogMessage(wxT("%s rejected from D-Plus as not found in the white list"), my.c_str());
|
||||
m_dPlusId = 0x00U;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_blackList != NULL) {
|
||||
bool res = m_blackList->isInList(my);
|
||||
if (res) {
|
||||
wxLogMessage(wxT("%s rejected from D-Plus as found in the black list"), my.c_str());
|
||||
m_dPlusId = 0x00U;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_linkState != DPLUS_LINKED)
|
||||
return;
|
||||
|
||||
switch (m_direction) {
|
||||
case DIR_OUTGOING:
|
||||
if (m_reflector.IsSameAs(rpt1) || m_reflector.IsSameAs(rpt2)) {
|
||||
// If we're already processing, ignore the new header
|
||||
if (m_dPlusId != 0x00U)
|
||||
return;
|
||||
|
||||
// Write to Header.log if it's enabled
|
||||
if (m_headerLogger != NULL)
|
||||
m_headerLogger->write(wxT("DPlus"), header);
|
||||
|
||||
m_dPlusId = id;
|
||||
m_dPlusSeq = 0x00U;
|
||||
m_inactivityTimer.start();
|
||||
m_pollInactivityTimer.start();
|
||||
|
||||
delete m_header;
|
||||
|
||||
m_header = new CHeaderData(header);
|
||||
m_header->setCQCQCQ();
|
||||
m_header->setFlags(0x00U, 0x00U, 0x00U);
|
||||
|
||||
m_destination->process(*m_header, m_direction, AS_DPLUS);
|
||||
}
|
||||
break;
|
||||
|
||||
case DIR_INCOMING: {
|
||||
m_destination = CRepeaterHandler::findDVRepeater(rpt1);
|
||||
if (m_destination == NULL) {
|
||||
m_destination = CRepeaterHandler::findDVRepeater(rpt2);
|
||||
if (m_destination == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_dPlusId != 0x00U)
|
||||
return;
|
||||
|
||||
// Write to Header.log if it's enabled
|
||||
if (m_headerLogger != NULL)
|
||||
m_headerLogger->write(wxT("DPlus"), header);
|
||||
|
||||
m_dPlusId = id;
|
||||
m_dPlusSeq = 0x00U;
|
||||
m_inactivityTimer.start();
|
||||
m_pollInactivityTimer.start();
|
||||
|
||||
delete m_header;
|
||||
|
||||
m_header = new CHeaderData(header);
|
||||
m_header->setCQCQCQ();
|
||||
m_header->setFlags(0x00U, 0x00U, 0x00U);
|
||||
|
||||
m_destination->process(*m_header, m_direction, AS_DPLUS);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CDPlusHandler::processInt(CAMBEData& data)
|
||||
{
|
||||
unsigned int id = data.getId();
|
||||
|
||||
if (m_dPlusId != id)
|
||||
return;
|
||||
|
||||
m_dPlusSeq = data.getSeq();
|
||||
|
||||
// Send the header every 21 frames, if we have it
|
||||
if (m_dPlusSeq == 0U && m_header != NULL)
|
||||
m_destination->process(*m_header, m_direction, AS_DUP);
|
||||
|
||||
m_inactivityTimer.start();
|
||||
m_pollInactivityTimer.start();
|
||||
|
||||
m_destination->process(data, m_direction, AS_DPLUS);
|
||||
|
||||
if (data.isEnd()) {
|
||||
m_dPlusId = 0x00U;
|
||||
m_dPlusSeq = 0x00U;
|
||||
|
||||
delete m_header;
|
||||
m_header = NULL;
|
||||
|
||||
m_inactivityTimer.stop();
|
||||
}
|
||||
}
|
||||
|
||||
bool CDPlusHandler::processInt(CConnectData& connect, CD_TYPE type)
|
||||
{
|
||||
switch (m_direction) {
|
||||
case DIR_OUTGOING:
|
||||
switch (type) {
|
||||
case CT_ACK:
|
||||
if (m_linkState == DPLUS_LINKING) {
|
||||
wxLogMessage(wxT("D-Plus ACK message received from %s"), m_reflector.c_str());
|
||||
m_destination->linkUp(DP_DPLUS, m_reflector);
|
||||
m_stateChange = true;
|
||||
m_linkState = DPLUS_LINKED;
|
||||
m_tryTimer.stop();
|
||||
m_pollTimer.start();
|
||||
m_pollInactivityTimer.start();
|
||||
}
|
||||
return false;
|
||||
|
||||
case CT_NAK:
|
||||
if (m_linkState == DPLUS_LINKING) {
|
||||
wxLogMessage(wxT("D-Plus NAK message received from %s"), m_reflector.c_str());
|
||||
m_destination->linkRefused(DP_DPLUS, m_reflector);
|
||||
CConnectData reply(CT_UNLINK, connect.getYourAddress(), connect.getYourPort());
|
||||
m_handler->writeConnect(reply);
|
||||
m_tryTimer.stop();
|
||||
}
|
||||
return true;
|
||||
|
||||
case CT_UNLINK:
|
||||
if (m_linkState == DPLUS_UNLINKING) {
|
||||
wxLogMessage(wxT("D-Plus disconnect acknowledgement received from %s"), m_reflector.c_str());
|
||||
m_destination->linkFailed(DP_DPLUS, m_reflector, false);
|
||||
m_stateChange = true;
|
||||
m_tryTimer.stop();
|
||||
}
|
||||
return true;
|
||||
|
||||
case CT_LINK1: {
|
||||
CConnectData reply(m_dplusLogin, CT_LINK2, connect.getYourAddress(), connect.getYourPort());
|
||||
m_handler->writeConnect(reply);
|
||||
m_tryTimer.stop();
|
||||
}
|
||||
return false;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case DIR_INCOMING:
|
||||
switch (type) {
|
||||
case CT_LINK2: {
|
||||
m_reflector = connect.getRepeater();
|
||||
wxLogMessage(wxT("D-Plus dongle link to %s has started"), m_reflector.c_str());
|
||||
CConnectData reply(CT_ACK, m_yourAddress, m_yourPort);
|
||||
m_handler->writeConnect(reply);
|
||||
m_linkState = DPLUS_LINKED;
|
||||
m_stateChange = true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case CT_UNLINK:
|
||||
if (m_linkState == DPLUS_LINKED) {
|
||||
wxLogMessage(wxT("D-Plus dongle link to %s has ended (unlinked)"), m_reflector.c_str());
|
||||
m_stateChange = true;
|
||||
m_handler->writeConnect(connect);
|
||||
}
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDPlusHandler::clockInt(unsigned int ms)
|
||||
{
|
||||
m_tryTimer.clock(ms);
|
||||
m_pollTimer.clock(ms);
|
||||
m_inactivityTimer.clock(ms);
|
||||
m_pollInactivityTimer.clock(ms);
|
||||
|
||||
if (m_pollInactivityTimer.isRunning() && m_pollInactivityTimer.hasExpired()) {
|
||||
m_pollInactivityTimer.start();
|
||||
|
||||
delete m_header;
|
||||
m_header = NULL;
|
||||
|
||||
m_stateChange = true;
|
||||
m_dPlusId = 0x00U;
|
||||
m_dPlusSeq = 0x00U;
|
||||
|
||||
if (!m_reflector.IsEmpty()) {
|
||||
switch (m_linkState) {
|
||||
case DPLUS_LINKING:
|
||||
wxLogMessage(wxT("D-Plus link to %s has failed to connect"), m_reflector.c_str());
|
||||
break;
|
||||
case DPLUS_LINKED:
|
||||
wxLogMessage(wxT("D-Plus link to %s has failed (poll inactivity)"), m_reflector.c_str());
|
||||
break;
|
||||
case DPLUS_UNLINKING:
|
||||
wxLogMessage(wxT("D-Plus link to %s has failed to disconnect cleanly"), m_reflector.c_str());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_direction == DIR_OUTGOING) {
|
||||
bool reconnect = m_destination->linkFailed(DP_DPLUS, m_reflector, true);
|
||||
if (reconnect) {
|
||||
CConnectData connect(CT_LINK1, m_yourAddress, DPLUS_PORT);
|
||||
m_handler->writeConnect(connect);
|
||||
m_linkState = DPLUS_LINKING;
|
||||
m_tryTimer.start(1U);
|
||||
m_tryCount = 0U;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_pollTimer.isRunning() && m_pollTimer.hasExpired()) {
|
||||
CPollData poll(m_yourAddress, m_yourPort);
|
||||
m_handler->writePoll(poll);
|
||||
|
||||
m_pollTimer.start();
|
||||
}
|
||||
|
||||
if (m_tryTimer.isRunning() && m_tryTimer.hasExpired()) {
|
||||
switch (m_linkState) {
|
||||
case DPLUS_LINKING: {
|
||||
CConnectData connect(CT_LINK1, m_yourAddress, DPLUS_PORT);
|
||||
m_handler->writeConnect(connect);
|
||||
}
|
||||
break;
|
||||
|
||||
case DPLUS_UNLINKING: {
|
||||
CConnectData connect(CT_UNLINK, m_yourAddress, m_yourPort);
|
||||
m_handler->writeConnect(connect);
|
||||
m_handler->writeConnect(connect);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned int timeout = calcBackoff();
|
||||
m_tryTimer.start(timeout);
|
||||
}
|
||||
|
||||
if (m_inactivityTimer.isRunning() && m_inactivityTimer.hasExpired()) {
|
||||
delete m_header;
|
||||
m_header = NULL;
|
||||
|
||||
m_dPlusId = 0x00U;
|
||||
m_dPlusSeq = 0x00U;
|
||||
|
||||
m_inactivityTimer.stop();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CDPlusHandler::writeHeaderInt(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction)
|
||||
{
|
||||
wxASSERT(handler != NULL);
|
||||
|
||||
if (m_linkState != DPLUS_LINKED)
|
||||
return;
|
||||
|
||||
if (direction != m_direction)
|
||||
return;
|
||||
|
||||
// Already is use?
|
||||
if (m_dPlusId != 0x00U)
|
||||
return;
|
||||
|
||||
switch (m_direction) {
|
||||
case DIR_OUTGOING:
|
||||
if (m_destination == handler) {
|
||||
header.setRepeaters(m_callsign, m_reflector);
|
||||
header.setDestination(m_yourAddress, m_yourPort);
|
||||
m_handler->writeHeader(header);
|
||||
}
|
||||
break;
|
||||
|
||||
case DIR_INCOMING:
|
||||
header.setDestination(m_yourAddress, m_yourPort);
|
||||
m_handler->writeHeader(header);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CDPlusHandler::writeAMBEInt(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction)
|
||||
{
|
||||
if (m_linkState != DPLUS_LINKED)
|
||||
return;
|
||||
|
||||
if (direction != m_direction)
|
||||
return;
|
||||
|
||||
// Already in use?
|
||||
if (m_dPlusId != 0x00U)
|
||||
return;
|
||||
|
||||
switch (m_direction) {
|
||||
case DIR_OUTGOING:
|
||||
if (m_destination == handler) {
|
||||
data.setDestination(m_yourAddress, m_yourPort);
|
||||
m_handler->writeAMBE(data);
|
||||
}
|
||||
break;
|
||||
|
||||
case DIR_INCOMING:
|
||||
data.setDestination(m_yourAddress, m_yourPort);
|
||||
m_handler->writeAMBE(data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool CDPlusHandler::stateChange()
|
||||
{
|
||||
bool stateChange = m_stateChange;
|
||||
|
||||
m_stateChange = false;
|
||||
|
||||
return stateChange;
|
||||
}
|
||||
|
||||
void CDPlusHandler::writeStatus(wxFFile& file)
|
||||
{
|
||||
for (unsigned int i = 0U; i < m_maxReflectors; i++) {
|
||||
CDPlusHandler* reflector = m_reflectors[i];
|
||||
if (reflector != NULL) {
|
||||
wxString text;
|
||||
|
||||
struct tm* tm = ::gmtime(&reflector->m_time);
|
||||
|
||||
if (reflector->m_linkState == DPLUS_LINKED) {
|
||||
switch (reflector->m_direction) {
|
||||
case DIR_OUTGOING:
|
||||
text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: DPlus link - Type: Dongle Rptr: %s Refl: %s Dir: Outgoing\n"),
|
||||
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
|
||||
reflector->m_repeater.c_str(), reflector->m_reflector.c_str());
|
||||
break;
|
||||
|
||||
case DIR_INCOMING:
|
||||
text.Printf(wxT("%04d-%02d-%02d %02d:%02d:%02d: DPlus link - Type: Dongle User: %s Dir: Incoming\n"),
|
||||
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
|
||||
reflector->m_reflector.c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
file.Write(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CDPlusHandler::calcBackoff()
|
||||
{
|
||||
if (m_tryCount >= 7U) {
|
||||
m_tryCount++;
|
||||
return 60U;
|
||||
}
|
||||
|
||||
unsigned int timeout = 1U;
|
||||
|
||||
for (unsigned int i = 0U; i < m_tryCount; i++)
|
||||
timeout *= 2U;
|
||||
|
||||
m_tryCount++;
|
||||
|
||||
if (timeout > 60U)
|
||||
return 60U;
|
||||
else
|
||||
return timeout;
|
||||
}
|
||||
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (C) 2012,2013,2015 by Jonathan Naylor G4KLX
|
||||
* Copyright (c) 2021 by Geoffrey Merck F4FXL / KC3FRA
|
||||
*
|
||||
* 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 DPlusHandler_H
|
||||
#define DPlusHandler_H
|
||||
|
||||
#include "DPlusProtocolHandlerPool.h"
|
||||
#include "DPlusAuthenticator.h"
|
||||
#include "ReflectorCallback.h"
|
||||
#include "CacheManager.h"
|
||||
#include "DStarDefines.h"
|
||||
#include "HeaderLogger.h"
|
||||
#include "CallsignList.h"
|
||||
#include "ConnectData.h"
|
||||
#include "HeaderData.h"
|
||||
#include "AMBEData.h"
|
||||
#include "PollData.h"
|
||||
#include "Timer.h"
|
||||
#include "Defs.h"
|
||||
|
||||
#if defined(__WINDOWS__)
|
||||
#include "Inaddr.h"
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <wx/wx.h>
|
||||
#include <wx/ffile.h>
|
||||
|
||||
enum DPLUS_STATE {
|
||||
DPLUS_LINKING,
|
||||
DPLUS_LINKED,
|
||||
DPLUS_UNLINKING
|
||||
};
|
||||
|
||||
class CDPlusHandler {
|
||||
public:
|
||||
static void initialise(unsigned int maxReflectors);
|
||||
|
||||
static void setCallsign(const wxString& callsign);
|
||||
static void setDPlusProtocolHandlerPool(CDPlusProtocolHandlerPool* pool);
|
||||
static void setDPlusProtocolIncoming(CDPlusProtocolHandler* handler);
|
||||
static void setDPlusLogin(const wxString& dplusLogin);
|
||||
static void setHeaderLogger(CHeaderLogger* logger);
|
||||
static void setMaxDongles(unsigned int maxDongles);
|
||||
|
||||
static void startAuthenticator(const wxString& address, CCacheManager* cache);
|
||||
|
||||
static void link(IReflectorCallback* handler, const wxString& repeater, const wxString& reflector, const in_addr& address);
|
||||
static void relink(IReflectorCallback* handler, const wxString& reflector);
|
||||
static void unlink(IReflectorCallback* handler, const wxString& reflector = wxEmptyString, bool exclude = true);
|
||||
static void unlink();
|
||||
|
||||
static void writeHeader(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction);
|
||||
static void writeAMBE(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction);
|
||||
|
||||
static void process(CHeaderData& header);
|
||||
static void process(CAMBEData& header);
|
||||
static void process(const CPollData& header);
|
||||
static void process(CConnectData& process);
|
||||
|
||||
static void gatewayUpdate(const wxString& gateway, const wxString& address);
|
||||
static void clock(unsigned int ms);
|
||||
|
||||
static bool stateChange();
|
||||
static void writeStatus(wxFFile& file);
|
||||
|
||||
static void setWhiteList(CCallsignList* list);
|
||||
static void setBlackList(CCallsignList* list);
|
||||
|
||||
static void finalise();
|
||||
|
||||
static void getInfo(IReflectorCallback* handler, CRemoteRepeaterData& data);
|
||||
|
||||
static wxString getDongles();
|
||||
|
||||
protected:
|
||||
CDPlusHandler(IReflectorCallback* handler, const wxString& repeater, const wxString& reflector, CDPlusProtocolHandler* protoHandler, const in_addr& address, unsigned int port);
|
||||
CDPlusHandler(CDPlusProtocolHandler* protoHandler, const in_addr& address, unsigned int port);
|
||||
~CDPlusHandler();
|
||||
|
||||
void processInt(CHeaderData& header);
|
||||
void processInt(CAMBEData& data);
|
||||
bool processInt(CConnectData& connect, CD_TYPE type);
|
||||
|
||||
void writeHeaderInt(IReflectorCallback* handler, CHeaderData& header, DIRECTION direction);
|
||||
void writeAMBEInt(IReflectorCallback* handler, CAMBEData& data, DIRECTION direction);
|
||||
|
||||
bool clockInt(unsigned int ms);
|
||||
|
||||
private:
|
||||
static unsigned int m_maxReflectors;
|
||||
static unsigned int m_maxDongles;
|
||||
static CDPlusHandler** m_reflectors;
|
||||
|
||||
static wxString m_gatewayCallsign;
|
||||
static wxString m_dplusLogin;
|
||||
static CDPlusProtocolHandlerPool* m_pool;
|
||||
static CDPlusProtocolHandler* m_incoming;
|
||||
|
||||
static bool m_stateChange;
|
||||
|
||||
static CHeaderLogger* m_headerLogger;
|
||||
static CDPlusAuthenticator* m_authenticator;
|
||||
|
||||
static CCallsignList* m_whiteList;
|
||||
static CCallsignList* m_blackList;
|
||||
|
||||
wxString m_repeater;
|
||||
wxString m_callsign;
|
||||
wxString m_reflector;
|
||||
CDPlusProtocolHandler* m_handler;
|
||||
in_addr m_yourAddress;
|
||||
unsigned int m_yourPort;
|
||||
unsigned int m_myPort;
|
||||
DIRECTION m_direction;
|
||||
DPLUS_STATE m_linkState;
|
||||
IReflectorCallback* m_destination;
|
||||
time_t m_time;
|
||||
CTimer m_pollTimer;
|
||||
CTimer m_pollInactivityTimer;
|
||||
CTimer m_tryTimer;
|
||||
unsigned int m_tryCount;
|
||||
unsigned int m_dPlusId;
|
||||
unsigned int m_dPlusSeq;
|
||||
CTimer m_inactivityTimer;
|
||||
CHeaderData* m_header;
|
||||
|
||||
unsigned int calcBackoff();
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* Copyright (C) 2012,2013,2015 by Jonathan Naylor G4KLX
|
||||
* Copyright (c) 2021 by Geoffrey Merck F4FXL / KC3FRA
|
||||
*
|
||||
* 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 "DPlusProtocolHandler.h"
|
||||
|
||||
#include "DStarDefines.h"
|
||||
#include "Utils.h"
|
||||
|
||||
// #define DUMP_TX
|
||||
|
||||
const unsigned int BUFFER_LENGTH = 1000U;
|
||||
|
||||
CDPlusProtocolHandler::CDPlusProtocolHandler(unsigned int port, const wxString& addr) :
|
||||
m_socket(addr, port),
|
||||
m_type(DP_NONE),
|
||||
m_buffer(NULL),
|
||||
m_length(0U),
|
||||
m_yourAddress(),
|
||||
m_yourPort(0U),
|
||||
m_myPort(port)
|
||||
{
|
||||
m_buffer = new unsigned char[BUFFER_LENGTH];
|
||||
}
|
||||
|
||||
CDPlusProtocolHandler::~CDPlusProtocolHandler()
|
||||
{
|
||||
delete[] m_buffer;
|
||||
}
|
||||
|
||||
bool CDPlusProtocolHandler::open()
|
||||
{
|
||||
return m_socket.open();
|
||||
}
|
||||
|
||||
unsigned int CDPlusProtocolHandler::getPort() const
|
||||
{
|
||||
return m_myPort;
|
||||
}
|
||||
|
||||
bool CDPlusProtocolHandler::writeHeader(const CHeaderData& header)
|
||||
{
|
||||
unsigned char buffer[60U];
|
||||
unsigned int length = header.getDPlusData(buffer, 60U, true);
|
||||
|
||||
#if defined(DUMP_TX)
|
||||
CUtils::dump(wxT("Sending Header"), buffer, length);
|
||||
#endif
|
||||
|
||||
for (unsigned int i = 0U; i < 5U; i++) {
|
||||
bool res = m_socket.write(buffer, length, header.getYourAddress(), header.getYourPort());
|
||||
if (!res)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDPlusProtocolHandler::writeAMBE(const CAMBEData& data)
|
||||
{
|
||||
unsigned char buffer[40U];
|
||||
unsigned int length = data.getDPlusData(buffer, 40U);
|
||||
|
||||
#if defined(DUMP_TX)
|
||||
CUtils::dump(wxT("Sending Data"), buffer, length);
|
||||
#endif
|
||||
|
||||
return m_socket.write(buffer, length, data.getYourAddress(), data.getYourPort());
|
||||
}
|
||||
|
||||
bool CDPlusProtocolHandler::writePoll(const CPollData& poll)
|
||||
{
|
||||
unsigned char buffer[10U];
|
||||
unsigned int length = poll.getDPlusData(buffer, 10U);
|
||||
|
||||
#if defined(DUMP_TX)
|
||||
CUtils::dump(wxT("Sending Poll"), buffer, length);
|
||||
#endif
|
||||
|
||||
return m_socket.write(buffer, length, poll.getYourAddress(), poll.getYourPort());
|
||||
}
|
||||
|
||||
bool CDPlusProtocolHandler::writeConnect(const CConnectData& connect)
|
||||
{
|
||||
unsigned char buffer[40U];
|
||||
unsigned int length = connect.getDPlusData(buffer, 40U);
|
||||
|
||||
#if defined(DUMP_TX)
|
||||
CUtils::dump(wxT("Sending Connect"), buffer, length);
|
||||
#endif
|
||||
|
||||
return m_socket.write(buffer, length, connect.getYourAddress(), connect.getYourPort());
|
||||
}
|
||||
|
||||
DPLUS_TYPE CDPlusProtocolHandler::read()
|
||||
{
|
||||
bool res = true;
|
||||
|
||||
// Loop until we have no more data from the socket or we have data for the higher layers
|
||||
while (res)
|
||||
res = readPackets();
|
||||
|
||||
return m_type;
|
||||
}
|
||||
|
||||
bool CDPlusProtocolHandler::readPackets()
|
||||
{
|
||||
m_type = DP_NONE;
|
||||
|
||||
// No more data?
|
||||
int length = m_socket.read(m_buffer, BUFFER_LENGTH, m_yourAddress, m_yourPort);
|
||||
if (length <= 0)
|
||||
return false;
|
||||
|
||||
m_length = length;
|
||||
|
||||
if (m_buffer[2] != 'D' || m_buffer[3] != 'S' || m_buffer[4] != 'V' || m_buffer[5] != 'T') {
|
||||
switch (m_length) {
|
||||
case 3U:
|
||||
m_type = DP_POLL;
|
||||
return false;
|
||||
case 5U:
|
||||
case 8U:
|
||||
case 28U:
|
||||
m_type = DP_CONNECT;
|
||||
return false;
|
||||
default:
|
||||
// An unknown type
|
||||
// CUtils::dump(wxT("Unknown packet type from D-Plus"), m_buffer, m_length);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// Header or data packet type?
|
||||
if (m_buffer[0] == 0x3A && m_buffer[1] == 0x80) {
|
||||
m_type = DP_HEADER;
|
||||
return false;
|
||||
} else if (m_buffer[0] == 0x1D && m_buffer[1] == 0x80) {
|
||||
m_type = DP_AMBE;
|
||||
return false;
|
||||
} else if (m_buffer[0] == 0x20 && m_buffer[1] == 0x80) {
|
||||
m_type = DP_AMBE;
|
||||
return false;
|
||||
} else {
|
||||
// An unknown type
|
||||
CUtils::dump(wxT("Unknown packet type from D-Plus"), m_buffer, m_length);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHeaderData* CDPlusProtocolHandler::readHeader()
|
||||
{
|
||||
if (m_type != DP_HEADER)
|
||||
return NULL;
|
||||
|
||||
CHeaderData* header = new CHeaderData;
|
||||
|
||||
// DPlus checksums are unreliable
|
||||
bool res = header->setDPlusData(m_buffer, m_length, false, m_yourAddress, m_yourPort, m_myPort);
|
||||
if (!res) {
|
||||
delete header;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
CAMBEData* CDPlusProtocolHandler::readAMBE()
|
||||
{
|
||||
if (m_type != DP_AMBE)
|
||||
return NULL;
|
||||
|
||||
CAMBEData* data = new CAMBEData;
|
||||
|
||||
bool res = data->setDPlusData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort);
|
||||
if (!res) {
|
||||
delete data;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
CPollData* CDPlusProtocolHandler::readPoll()
|
||||
{
|
||||
if (m_type != DP_POLL)
|
||||
return NULL;
|
||||
|
||||
CPollData* poll = new CPollData;
|
||||
|
||||
bool res = poll->setDPlusData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort);
|
||||
if (!res) {
|
||||
delete poll;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return poll;
|
||||
}
|
||||
|
||||
CConnectData* CDPlusProtocolHandler::readConnect()
|
||||
{
|
||||
if (m_type != DP_CONNECT)
|
||||
return NULL;
|
||||
|
||||
CConnectData* connect = new CConnectData;
|
||||
|
||||
bool res = connect->setDPlusData(m_buffer, m_length, m_yourAddress, m_yourPort, m_myPort);
|
||||
if (!res) {
|
||||
delete connect;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return connect;
|
||||
}
|
||||
|
||||
void CDPlusProtocolHandler::close()
|
||||
{
|
||||
m_socket.close();
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2010,2011,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.
|
||||
*/
|
||||
|
||||
#ifndef DPlusProtocolHandler_H
|
||||
#define DPlusProtocolHandler_H
|
||||
|
||||
#include "UDPReaderWriter.h"
|
||||
#include "DStarDefines.h"
|
||||
#include "ConnectData.h"
|
||||
#include "HeaderData.h"
|
||||
#include "AMBEData.h"
|
||||
#include "PollData.h"
|
||||
|
||||
#if defined(__WINDOWS__)
|
||||
#include "Inaddr.h"
|
||||
#else
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <wx/wx.h>
|
||||
|
||||
enum DPLUS_TYPE {
|
||||
DP_NONE,
|
||||
DP_HEADER,
|
||||
DP_AMBE,
|
||||
DP_POLL,
|
||||
DP_CONNECT
|
||||
};
|
||||
|
||||
class CDPlusProtocolHandler {
|
||||
public:
|
||||
CDPlusProtocolHandler(unsigned int port, const wxString& addr = wxEmptyString);
|
||||
~CDPlusProtocolHandler();
|
||||
|
||||
bool open();
|
||||
|
||||
unsigned int getPort() const;
|
||||
|
||||
bool writeHeader(const CHeaderData& header);
|
||||
bool writeAMBE(const CAMBEData& data);
|
||||
bool writeConnect(const CConnectData& connect);
|
||||
bool writePoll(const CPollData& poll);
|
||||
|
||||
DPLUS_TYPE read();
|
||||
CHeaderData* readHeader();
|
||||
CAMBEData* readAMBE();
|
||||
CPollData* readPoll();
|
||||
CConnectData* readConnect();
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
CUDPReaderWriter m_socket;
|
||||
DPLUS_TYPE m_type;
|
||||
unsigned char* m_buffer;
|
||||
unsigned int m_length;
|
||||
in_addr m_yourAddress;
|
||||
unsigned int m_yourPort;
|
||||
unsigned int m_myPort;
|
||||
|
||||
bool readPackets();
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2012,2013,2015 by Jonathan Naylor G4KLX
|
||||
* Copyright (c) 2021 by Geoffrey Merck F4FXL / KC3FRA
|
||||
*
|
||||
* 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 "DPlusProtocolHandlerPool.h"
|
||||
|
||||
CDPlusProtocolHandlerPool::CDPlusProtocolHandlerPool(unsigned int n, unsigned int port, const wxString& addr) :
|
||||
m_pool(NULL),
|
||||
m_n(n),
|
||||
m_index(0U)
|
||||
{
|
||||
wxASSERT(port > 0U);
|
||||
wxASSERT(n > 0U);
|
||||
|
||||
m_pool = new CDPlusProtocolHandlerEntry[n];
|
||||
|
||||
for (unsigned int i = 0U; i < n; i++) {
|
||||
m_pool[i].m_handler = new CDPlusProtocolHandler(port + i, addr);
|
||||
m_pool[i].m_port = port + i;
|
||||
m_pool[i].m_inUse = false;
|
||||
}
|
||||
|
||||
wxLogMessage(wxT("Allocated UDP ports %u-%u to D-Plus"), port, port + n - 1U);
|
||||
}
|
||||
|
||||
CDPlusProtocolHandlerPool::~CDPlusProtocolHandlerPool()
|
||||
{
|
||||
for (unsigned int i = 0U; i < m_n; i++)
|
||||
delete m_pool[i].m_handler;
|
||||
|
||||
delete[] m_pool;
|
||||
}
|
||||
|
||||
bool CDPlusProtocolHandlerPool::open()
|
||||
{
|
||||
for (unsigned int i = 0U; i < m_n; i++) {
|
||||
bool ret = m_pool[i].m_handler->open();
|
||||
if (!ret)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CDPlusProtocolHandler* CDPlusProtocolHandlerPool::getHandler(unsigned int port)
|
||||
{
|
||||
if (port == 0U) {
|
||||
for (unsigned int i = 0U; i < m_n; i++) {
|
||||
if (!m_pool[i].m_inUse) {
|
||||
m_pool[i].m_inUse = true;
|
||||
return m_pool[i].m_handler;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (unsigned int i = 0U; i < m_n; i++) {
|
||||
if (m_pool[i].m_port == port) {
|
||||
m_pool[i].m_inUse = true;
|
||||
return m_pool[i].m_handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxLogError(wxT("Cannot find a free D-Plus port in the pool"));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CDPlusProtocolHandlerPool::release(CDPlusProtocolHandler* handler)
|
||||
{
|
||||
wxASSERT(handler != NULL);
|
||||
|
||||
for (unsigned int i = 0U; i < m_n; i++) {
|
||||
if (m_pool[i].m_handler == handler && m_pool[i].m_inUse) {
|
||||
m_pool[i].m_inUse = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
wxLogError(wxT("Trying to release an unused D-Plus port"));
|
||||
}
|
||||
|
||||
DPLUS_TYPE CDPlusProtocolHandlerPool::read()
|
||||
{
|
||||
while (m_index < m_n) {
|
||||
if (m_pool[m_index].m_inUse) {
|
||||
DPLUS_TYPE type = m_pool[m_index].m_handler->read();
|
||||
if (type != DP_NONE)
|
||||
return type;
|
||||
}
|
||||
|
||||
m_index++;
|
||||
}
|
||||
|
||||
m_index = 0U;
|
||||
|
||||
return DP_NONE;
|
||||
}
|
||||
|
||||
CHeaderData* CDPlusProtocolHandlerPool::readHeader()
|
||||
{
|
||||
return m_pool[m_index].m_handler->readHeader();
|
||||
}
|
||||
|
||||
CAMBEData* CDPlusProtocolHandlerPool::readAMBE()
|
||||
{
|
||||
return m_pool[m_index].m_handler->readAMBE();
|
||||
}
|
||||
|
||||
CPollData* CDPlusProtocolHandlerPool::readPoll()
|
||||
{
|
||||
return m_pool[m_index].m_handler->readPoll();
|
||||
}
|
||||
|
||||
CConnectData* CDPlusProtocolHandlerPool::readConnect()
|
||||
{
|
||||
return m_pool[m_index].m_handler->readConnect();
|
||||
}
|
||||
|
||||
void CDPlusProtocolHandlerPool::close()
|
||||
{
|
||||
for (unsigned int i = 0U; i < m_n; i++)
|
||||
m_pool[i].m_handler->close();
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2012,2013,2015 by Jonathan Naylor G4KLX
|
||||
* Copyright (c) 2021 by Geoffrey Merck F4FXL / KC3FRA
|
||||
*
|
||||
* 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 DPlusProtocolHandlerPool_H
|
||||
#define DPlusProtocolHandlerPool_H
|
||||
|
||||
#include <wx/wx.h>
|
||||
|
||||
#include "DPlusProtocolHandler.h"
|
||||
|
||||
class CDPlusProtocolHandlerEntry {
|
||||
public:
|
||||
CDPlusProtocolHandler* m_handler;
|
||||
unsigned int m_port;
|
||||
bool m_inUse;
|
||||
};
|
||||
|
||||
class CDPlusProtocolHandlerPool {
|
||||
public:
|
||||
CDPlusProtocolHandlerPool(unsigned int n, unsigned int port, const wxString& addr = wxEmptyString);
|
||||
~CDPlusProtocolHandlerPool();
|
||||
|
||||
bool open();
|
||||
|
||||
CDPlusProtocolHandler* getHandler(unsigned int port = 0U);
|
||||
void release(CDPlusProtocolHandler* handler);
|
||||
|
||||
DPLUS_TYPE read();
|
||||
CHeaderData* readHeader();
|
||||
CAMBEData* readAMBE();
|
||||
CPollData* readPoll();
|
||||
CConnectData* readConnect();
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
CDPlusProtocolHandlerEntry* m_pool;
|
||||
unsigned int m_n;
|
||||
unsigned int m_index;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in new issue