mirror of
https://github.com/g4klx/ircDDBGateway.git
synced 2025-12-06 05:32:02 +01:00
355 lines
11 KiB
C++
355 lines
11 KiB
C++
|
|
/*
|
||
|
|
|
||
|
|
CIRCDDBClient - ircDDB client library in C++
|
||
|
|
|
||
|
|
Copyright (C) 2010-2011 Michael Dirska, DL1BFF (dl1bff@mdx.de)
|
||
|
|
Copyright (C) 2011,2012 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, see <http://www.gnu.org/licenses/>.
|
||
|
|
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "IRCDDBMultiClient.h"
|
||
|
|
#include <wx/wx.h>
|
||
|
|
|
||
|
|
CIRCDDBMultiClient::CIRCDDBMultiClient(const CIRCDDB_Array& clients) :
|
||
|
|
m_clients(),
|
||
|
|
m_queriesLock(),
|
||
|
|
m_responseQueueLock()
|
||
|
|
{
|
||
|
|
for (unsigned int i = 0; i < clients.Count(); i++) {
|
||
|
|
if (clients[i] != NULL)
|
||
|
|
m_clients.Add(clients[i]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
CIRCDDBMultiClient::~CIRCDDBMultiClient()
|
||
|
|
{
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
delete m_clients[i];
|
||
|
|
}
|
||
|
|
|
||
|
|
while (m_responseQueue.Count() > 0) {
|
||
|
|
delete m_responseQueue[0];
|
||
|
|
m_responseQueue.RemoveAt(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
for (CIRCDDBMultiClientQuery_HashMap::iterator it = m_userQueries.begin(); it != m_userQueries.end(); it++)
|
||
|
|
delete it->second;
|
||
|
|
m_userQueries.clear();
|
||
|
|
|
||
|
|
for (CIRCDDBMultiClientQuery_HashMap::iterator it = m_repeaterQueries.begin(); it != m_repeaterQueries.end(); it++)
|
||
|
|
delete it->second;
|
||
|
|
m_repeaterQueries.clear();
|
||
|
|
|
||
|
|
for (CIRCDDBMultiClientQuery_HashMap::iterator it = m_gatewayQueries.begin(); it != m_gatewayQueries.end(); it++)
|
||
|
|
delete it->second;
|
||
|
|
m_gatewayQueries.clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CIRCDDBMultiClient::open()
|
||
|
|
{
|
||
|
|
bool result = true;
|
||
|
|
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
result = m_clients[i]->open() && result;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!result) close();
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CIRCDDBMultiClient::rptrQTH(const wxString & callsign, double latitude, double longitude, const wxString & desc1, const wxString & desc2, const wxString & infoURL)
|
||
|
|
{
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
m_clients[i]->rptrQTH(callsign, latitude, longitude, desc1, desc2, infoURL);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CIRCDDBMultiClient::rptrQRG(const wxString & callsign, double txFrequency, double duplexShift, double range, double agl)
|
||
|
|
{
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
m_clients[i]->rptrQRG(callsign, txFrequency, duplexShift, range, agl);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void CIRCDDBMultiClient::kickWatchdog(const wxString & callsign, const wxString & wdInfo)
|
||
|
|
{
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
m_clients[i]->kickWatchdog(callsign, wdInfo);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int CIRCDDBMultiClient::getConnectionState()
|
||
|
|
{
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
int state = m_clients[i]->getConnectionState();
|
||
|
|
if (state != 7)
|
||
|
|
return state;
|
||
|
|
}
|
||
|
|
|
||
|
|
return 7;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CIRCDDBMultiClient::sendHeard(const wxString & myCall, const wxString & myCallExt, const wxString & yourCall, const wxString & rpt1, const wxString & rpt2, unsigned char flag1, unsigned char flag2, unsigned char flag3)
|
||
|
|
{
|
||
|
|
bool result = true;
|
||
|
|
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
result = m_clients[i]->sendHeard(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3) && result;
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CIRCDDBMultiClient::sendHeardWithTXMsg(const wxString & myCall, const wxString & myCallExt, const wxString & yourCall, const wxString & rpt1, const wxString & rpt2, unsigned char flag1, unsigned char flag2, unsigned char flag3, const wxString & network_destination, const wxString & tx_message)
|
||
|
|
{
|
||
|
|
bool result = true;
|
||
|
|
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
result = m_clients[i]->sendHeardWithTXMsg(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, network_destination, tx_message) && result;
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CIRCDDBMultiClient::sendHeardWithTXStats(const wxString & myCall, const wxString & myCallExt, const wxString & yourCall, const wxString & rpt1, const wxString & rpt2, unsigned char flag1, unsigned char flag2, unsigned char flag3, int num_dv_frames, int num_dv_silent_frames, int num_bit_errors)
|
||
|
|
{
|
||
|
|
bool result = true;
|
||
|
|
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
result = m_clients[i]->sendHeardWithTXStats(myCall, myCallExt, yourCall, rpt1, rpt2, flag1, flag2, flag3, num_dv_frames, num_dv_silent_frames, num_bit_errors) && result;
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CIRCDDBMultiClient::findGateway(const wxString & gatewayCallsign)
|
||
|
|
{
|
||
|
|
pushQuery(IDRT_GATEWAY, gatewayCallsign, new CIRCDDBMultiClientQuery(wxEmptyString, wxEmptyString, gatewayCallsign, wxEmptyString, wxEmptyString, IDRT_GATEWAY));
|
||
|
|
bool result = true;
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
result = m_clients[i]->findGateway(gatewayCallsign) && result;
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CIRCDDBMultiClient::findRepeater(const wxString & repeaterCallsign)
|
||
|
|
{
|
||
|
|
pushQuery(IDRT_REPEATER, repeaterCallsign, new CIRCDDBMultiClientQuery(wxEmptyString, repeaterCallsign, wxEmptyString, wxEmptyString, wxEmptyString, IDRT_REPEATER));
|
||
|
|
bool result = true;
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
result = m_clients[i]->findRepeater(repeaterCallsign) && result;
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CIRCDDBMultiClient::findUser(const wxString & userCallsign)
|
||
|
|
{
|
||
|
|
pushQuery(IDRT_USER, userCallsign, new CIRCDDBMultiClientQuery(userCallsign, wxEmptyString, wxEmptyString, wxEmptyString, wxEmptyString, IDRT_USER));
|
||
|
|
bool result = true;
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
result = m_clients[i]->findUser(userCallsign) && result;
|
||
|
|
}
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
IRCDDB_RESPONSE_TYPE CIRCDDBMultiClient::getMessageType()
|
||
|
|
{
|
||
|
|
//procees the inner clients at each call
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
wxString user = wxEmptyString, repeater = wxEmptyString, gateway = wxEmptyString, address = wxEmptyString, timestamp = wxEmptyString, key = wxEmptyString;
|
||
|
|
IRCDDB_RESPONSE_TYPE type = m_clients[i]->getMessageType();
|
||
|
|
|
||
|
|
switch (type) {
|
||
|
|
case IDRT_USER: {
|
||
|
|
if (!m_clients[i]->receiveUser(user, repeater, gateway, address, timestamp))
|
||
|
|
type = IDRT_NONE;
|
||
|
|
key = user;
|
||
|
|
//wxLogMessage(wxT("After receive user : %s %s %s %s %s client idx %d"), user, repeater, gateway, address, timestamp, i);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case IDRT_GATEWAY: {
|
||
|
|
if (!m_clients[i]->receiveGateway(gateway, address))
|
||
|
|
type = IDRT_NONE;
|
||
|
|
key = gateway;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case IDRT_REPEATER: {
|
||
|
|
if (!m_clients[i]->receiveRepeater(repeater, gateway, address))
|
||
|
|
type = IDRT_NONE;
|
||
|
|
key = repeater;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case IDRT_NONE: {
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (type != IDRT_NONE)
|
||
|
|
{
|
||
|
|
wxMutexLocker locker(m_queriesLock);
|
||
|
|
bool canAddToQueue = false;
|
||
|
|
bool wasQuery = false;
|
||
|
|
CIRCDDBMultiClientQuery * item = popQuery(type, key);
|
||
|
|
if (item != NULL) {//is this a response to a query we've sent ?
|
||
|
|
item->Update(user, repeater, gateway, address, timestamp);//update item (if needed)
|
||
|
|
canAddToQueue = (item->incrementResponseCount() >= m_clients.Count()); //did all the clients respond or did we have an answer ?
|
||
|
|
wasQuery = true;
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
item = new CIRCDDBMultiClientQuery(user, repeater, gateway, address, timestamp, type);
|
||
|
|
canAddToQueue = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
//wxLogMessage(wxT("After process : %s %s %s %s %s canAdd %d wasQuery %d"), user, repeater, gateway, address, timestamp, (int)canAddToQueue, (int)wasQuery);
|
||
|
|
if (canAddToQueue) {
|
||
|
|
wxMutexLocker responselocker(m_responseQueueLock);
|
||
|
|
m_responseQueue.Add(item);
|
||
|
|
}
|
||
|
|
else if (wasQuery)
|
||
|
|
pushQuery(type, key, item);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
{ //this is an artificial scope, I'm not sure if compiler optimization would move instantiation of locker or not hence this
|
||
|
|
//finally send the first item we queued
|
||
|
|
wxMutexLocker locker(m_responseQueueLock);
|
||
|
|
if (m_responseQueue.Count() == 0)
|
||
|
|
return IDRT_NONE;
|
||
|
|
|
||
|
|
return m_responseQueue[0]->getType();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CIRCDDBMultiClient::receiveRepeater(wxString & repeaterCallsign, wxString & gatewayCallsign, wxString & address)
|
||
|
|
{
|
||
|
|
CIRCDDBMultiClientQuery * item = checkAndGetNextResponse(IDRT_REPEATER, wxT("CIRCDDBMultiClient::receiveRepeater: unexpected response type"));
|
||
|
|
if (item == NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
repeaterCallsign = item->getRepeater();
|
||
|
|
gatewayCallsign = item->getGateway();
|
||
|
|
address = item->getAddress();
|
||
|
|
delete item;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CIRCDDBMultiClient::receiveGateway(wxString & gatewayCallsign, wxString & address)
|
||
|
|
{
|
||
|
|
CIRCDDBMultiClientQuery * item = checkAndGetNextResponse(IDRT_GATEWAY, wxT("CIRCDDBMultiClient::receiveGateway: unexpected response type"));
|
||
|
|
if (item == NULL)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
gatewayCallsign = item->getGateway();
|
||
|
|
address = item->getAddress();
|
||
|
|
delete item;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CIRCDDBMultiClient::receiveUser(wxString & userCallsign, wxString & repeaterCallsign, wxString & gatewayCallsign, wxString & address)
|
||
|
|
{
|
||
|
|
wxString dummy;
|
||
|
|
return receiveUser(userCallsign, repeaterCallsign, gatewayCallsign, address, dummy);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool CIRCDDBMultiClient::receiveUser(wxString & userCallsign, wxString & repeaterCallsign, wxString & gatewayCallsign, wxString & address, wxString & timeStamp)
|
||
|
|
{
|
||
|
|
CIRCDDBMultiClientQuery * item = checkAndGetNextResponse(IDRT_USER, wxT("CIRCDDBMultiClient::receiveUser: unexpected response type"));
|
||
|
|
if (item == NULL) {
|
||
|
|
//wxLogMessage(wxT("CIRCDDBMultiClient::receiveUser NO USER IN QUEUE"));
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
//wxLogMessage(wxT("CIRCDDBMultiClient::receiveUser : %s"), item->toString());
|
||
|
|
|
||
|
|
userCallsign = item->getUser().Clone();
|
||
|
|
repeaterCallsign = item->getRepeater().Clone();
|
||
|
|
gatewayCallsign = item->getGateway().Clone();
|
||
|
|
address = item->getAddress().Clone();
|
||
|
|
timeStamp = item->getTimestamp().Clone();
|
||
|
|
delete item;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CIRCDDBMultiClient::close()
|
||
|
|
{
|
||
|
|
for (unsigned int i = 0; i < m_clients.Count(); i++) {
|
||
|
|
m_clients[i]->close();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
CIRCDDBMultiClientQuery * CIRCDDBMultiClient::checkAndGetNextResponse(IRCDDB_RESPONSE_TYPE expectedType, wxString errorMessage)
|
||
|
|
{
|
||
|
|
CIRCDDBMultiClientQuery * item = NULL;
|
||
|
|
wxMutexLocker locker(m_responseQueueLock);
|
||
|
|
|
||
|
|
if (m_responseQueue.Count() == 0 || m_responseQueue[0]->getType() != expectedType) {
|
||
|
|
wxLogError(errorMessage);
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
item = m_responseQueue[0];
|
||
|
|
m_responseQueue.RemoveAt(0);
|
||
|
|
}
|
||
|
|
|
||
|
|
return item;
|
||
|
|
}
|
||
|
|
|
||
|
|
void CIRCDDBMultiClient::pushQuery(IRCDDB_RESPONSE_TYPE type, const wxString& key, CIRCDDBMultiClientQuery * query)
|
||
|
|
{
|
||
|
|
CIRCDDBMultiClientQuery_HashMap * queries = getQueriesHashMap(type);
|
||
|
|
wxMutexLocker locker(m_queriesLock);
|
||
|
|
if (queries != NULL && (*queries)[key] == NULL)
|
||
|
|
(*queries)[key] = query;
|
||
|
|
else
|
||
|
|
delete query;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
CIRCDDBMultiClientQuery * CIRCDDBMultiClient::popQuery(IRCDDB_RESPONSE_TYPE type, const wxString & key)
|
||
|
|
{
|
||
|
|
CIRCDDBMultiClientQuery_HashMap * queries = getQueriesHashMap(type);
|
||
|
|
wxMutexLocker locker(m_queriesLock);
|
||
|
|
|
||
|
|
CIRCDDBMultiClientQuery * item = NULL;
|
||
|
|
|
||
|
|
if (queries != NULL && (item = (*queries)[key]) != NULL)
|
||
|
|
queries->erase(key);
|
||
|
|
|
||
|
|
return item;
|
||
|
|
}
|
||
|
|
|
||
|
|
CIRCDDBMultiClientQuery_HashMap * CIRCDDBMultiClient::getQueriesHashMap(IRCDDB_RESPONSE_TYPE type)
|
||
|
|
{
|
||
|
|
switch (type)
|
||
|
|
{
|
||
|
|
case IDRT_USER:
|
||
|
|
return &m_userQueries;
|
||
|
|
case IDRT_GATEWAY:
|
||
|
|
return &m_gatewayQueries;
|
||
|
|
case IDRT_REPEATER:
|
||
|
|
return &m_repeaterQueries;
|
||
|
|
case IDRT_NONE:
|
||
|
|
default:
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|