mirror of https://github.com/nostar/urfd.git
parent
68c30237f8
commit
b296c10ac5
@ -0,0 +1,14 @@
|
||||
*.o
|
||||
*.d
|
||||
.vscode
|
||||
./*.blacklist
|
||||
./*.whitelist
|
||||
./*.interlink
|
||||
./*.terminal
|
||||
./*.service
|
||||
configure.mk
|
||||
configure.h
|
||||
configure.sql
|
||||
reflector.cfg
|
||||
wiresx/configure.php
|
||||
src/ulxd
|
||||
@ -0,0 +1,53 @@
|
||||
//
|
||||
// cbmclient.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 20/01/2017.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <string.h>
|
||||
#include "Main.h"
|
||||
#include "BMClient.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructors
|
||||
|
||||
CBmClient::CBmClient()
|
||||
{
|
||||
}
|
||||
|
||||
CBmClient::CBmClient(const CCallsign &callsign, const CIp &ip, char reflectorModule)
|
||||
: CClient(callsign, ip, reflectorModule)
|
||||
{
|
||||
}
|
||||
|
||||
CBmClient::CBmClient(const CBmClient &client)
|
||||
: CClient(client)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// status
|
||||
|
||||
bool CBmClient::IsAlive(void) const
|
||||
{
|
||||
return (m_LastKeepaliveTime.DurationSinceNow() < XLX_KEEPALIVE_TIMEOUT);
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
|
||||
// ulxd -- The ultimate Reflector
|
||||
// Copyright © 2021 Thomas A. Early N7TAE
|
||||
//
|
||||
// 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 3 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Client.h"
|
||||
#include "ULXClient.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CBmClient : public CClient
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CBmClient();
|
||||
CBmClient(const CCallsign &, const CIp &, char = ' ');
|
||||
CBmClient(const CBmClient &);
|
||||
|
||||
// destructor
|
||||
virtual ~CBmClient() {};
|
||||
|
||||
// identity
|
||||
int GetProtocol(void) const { return PROTOCOL_XLX; }
|
||||
int GetProtocolRevision(void) const { return XLX_PROTOCOL_REVISION_2; }
|
||||
const char *GetProtocolName(void) const { return "XLX"; }
|
||||
int GetCodec(void) const { return CODEC_AMBE2PLUS; }
|
||||
bool IsPeer(void) const { return true; }
|
||||
|
||||
// status
|
||||
bool IsAlive(void) const;
|
||||
|
||||
// reporting
|
||||
void WriteXml(std::ofstream &) {}
|
||||
};
|
||||
@ -0,0 +1,67 @@
|
||||
//
|
||||
// cbmpeer.cpp
|
||||
// xlxd
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 10/12/2016.
|
||||
// Copyright © 2016 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include "Reflector.h"
|
||||
#include "BMPeer.h"
|
||||
#include "BMClient.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
|
||||
CBmPeer::CBmPeer()
|
||||
{
|
||||
}
|
||||
|
||||
CBmPeer::CBmPeer(const CCallsign &callsign, const CIp &ip, const char *modules, const CVersion &version)
|
||||
: CPeer(callsign, ip, modules, version)
|
||||
{
|
||||
std::cout << "Adding BM peer" << std::endl;
|
||||
|
||||
// and construct all xlx clients
|
||||
for ( unsigned i = 0; i < ::strlen(modules); i++ )
|
||||
{
|
||||
// create and append to vector
|
||||
m_Clients.push_back(std::make_shared<CBmClient>(callsign, ip, modules[i]));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// status
|
||||
|
||||
bool CBmPeer::IsAlive(void) const
|
||||
{
|
||||
return (m_LastKeepaliveTime.DurationSinceNow() < XLX_KEEPALIVE_TIMEOUT);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// revision helper
|
||||
|
||||
int CBmPeer::GetProtocolRevision(const CVersion &version)
|
||||
{
|
||||
return XLX_PROTOCOL_REVISION_2;
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
//
|
||||
// BMPeer.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 20/01/2017.
|
||||
// Copyright © 2016 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cbmpeer_h
|
||||
#define cbmpeer_h
|
||||
|
||||
|
||||
#include "Peer.h"
|
||||
#include "BMClient.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CBmPeer : public CPeer
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CBmPeer();
|
||||
CBmPeer(const CCallsign &, const CIp &, const char *, const CVersion &);
|
||||
CBmPeer(const CBmPeer &) = delete;
|
||||
|
||||
// status
|
||||
bool IsAlive(void) const;
|
||||
|
||||
// identity
|
||||
int GetProtocol(void) const { return PROTOCOL_XLX; }
|
||||
const char *GetProtocolName(void) const { return "XLX"; }
|
||||
|
||||
// revision helper
|
||||
static int GetProtocolRevision(const CVersion &);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cbmpeer_h */
|
||||
@ -0,0 +1,267 @@
|
||||
//
|
||||
// cbuffer.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 02/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <string.h>
|
||||
#include "Buffer.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CBuffer::CBuffer(uint8_t *buffer, int len)
|
||||
{
|
||||
m_data.resize(len);
|
||||
::memcpy(m_data.data(), buffer, len);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set
|
||||
|
||||
void CBuffer::Set(uint8_t *buffer, int len)
|
||||
{
|
||||
m_data.resize(len);
|
||||
::memcpy(m_data.data(), buffer, len);
|
||||
}
|
||||
|
||||
void CBuffer::Set(const char *sz)
|
||||
{
|
||||
m_data.resize(::strlen(sz)+1);
|
||||
::strcpy((char *)m_data.data(), sz);
|
||||
}
|
||||
|
||||
void CBuffer::Append(const uint8_t *buffer, int len)
|
||||
{
|
||||
int n = (int)m_data.size();
|
||||
m_data.resize(n+len);
|
||||
::memcpy(&(m_data.data()[n]), buffer, len);
|
||||
}
|
||||
|
||||
void CBuffer::Append(uint8_t ui, int len)
|
||||
{
|
||||
int n = (int)m_data.size();
|
||||
m_data.resize(n+len);
|
||||
::memset(&(m_data.data()[n]), ui, len);
|
||||
}
|
||||
|
||||
void CBuffer::Append(uint8_t ui)
|
||||
{
|
||||
int n = (int)m_data.size();
|
||||
m_data.resize(n+sizeof(uint8_t));
|
||||
::memcpy(&(m_data.data()[n]), &ui, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
void CBuffer::Append(uint16_t ui)
|
||||
{
|
||||
int n = (int)m_data.size();
|
||||
m_data.resize(n+sizeof(uint16_t));
|
||||
::memcpy(&(m_data.data()[n]), &ui, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
void CBuffer::Append(uint32_t ui)
|
||||
{
|
||||
int n = (int)m_data.size();
|
||||
m_data.resize(n+sizeof(uint32_t));
|
||||
::memcpy(&(m_data.data()[n]), &ui, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void CBuffer::Append(const char *sz)
|
||||
{
|
||||
Append((uint8_t *)sz, (int)strlen(sz));
|
||||
Append((uint8_t)0x00);
|
||||
}
|
||||
|
||||
void CBuffer::ReplaceAt(int i, uint8_t ui)
|
||||
{
|
||||
if ( m_data.size() < (i+sizeof(uint8_t)) )
|
||||
{
|
||||
m_data.resize(i+sizeof(uint8_t));
|
||||
}
|
||||
*(uint8_t *)(&(m_data.data()[i])) = ui;
|
||||
}
|
||||
|
||||
void CBuffer::ReplaceAt(int i, uint16_t ui)
|
||||
{
|
||||
if ( m_data.size() < (i+sizeof(uint16_t)) )
|
||||
{
|
||||
m_data.resize(i+sizeof(uint16_t));
|
||||
}
|
||||
*(uint16_t *)(&(m_data.data()[i])) = ui;
|
||||
}
|
||||
|
||||
void CBuffer::ReplaceAt(int i, uint32_t ui)
|
||||
{
|
||||
if ( m_data.size() < (i+sizeof(uint32_t)) )
|
||||
{
|
||||
m_data.resize(i+sizeof(uint32_t));
|
||||
}
|
||||
*(uint32_t *)(&(m_data.data()[i])) = ui;
|
||||
}
|
||||
|
||||
void CBuffer::ReplaceAt(int i, const uint8_t *ptr, int len)
|
||||
{
|
||||
if ( m_data.size() < unsigned(i+len) )
|
||||
{
|
||||
m_data.resize(i+len);
|
||||
}
|
||||
::memcpy(&(m_data.data()[i]), ptr, len);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operation
|
||||
|
||||
int CBuffer::Compare(uint8_t *buffer, int len) const
|
||||
{
|
||||
int result = -1;
|
||||
if ( m_data.size() >= unsigned(len) )
|
||||
{
|
||||
result = ::memcmp(m_data.data(), buffer, len);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int CBuffer::Compare(uint8_t *buffer, int off, int len) const
|
||||
{
|
||||
int result = -1;
|
||||
if ( m_data.size() >= unsigned(off+len) )
|
||||
{
|
||||
result = ::memcmp(&(m_data.data()[off]), buffer, len);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operator
|
||||
|
||||
bool CBuffer::operator ==(const CBuffer &Buffer) const
|
||||
{
|
||||
if ( m_data.size() == Buffer.m_data.size() )
|
||||
{
|
||||
return (::memcmp((const char *)m_data.data(), (const char *)Buffer.m_data.data(), m_data.size()) == 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CBuffer::operator ==(const char *sz) const
|
||||
{
|
||||
if ( m_data.size() == ::strlen(sz) )
|
||||
{
|
||||
return (::memcmp((const char *)m_data.data(), sz, m_data.size()) == 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CBuffer::operator const char *() const
|
||||
{
|
||||
return (const char *)m_data.data();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// debug
|
||||
|
||||
void CBuffer::DebugDump(std::ofstream &debugout) const
|
||||
{
|
||||
// dump an hex line
|
||||
for ( unsigned int i = 0; i < m_data.size(); i++ )
|
||||
{
|
||||
char sz[16];
|
||||
//sprintf(sz, "%02X", m_data.data()[i]);
|
||||
sprintf(sz, "0x%02X", m_data.data()[i]);
|
||||
debugout << sz;
|
||||
if ( i == m_data.size()-1 )
|
||||
{
|
||||
debugout << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
debugout << ',';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBuffer::DebugDumpAscii(std::ofstream &debugout) const
|
||||
{
|
||||
// dump an ascii line
|
||||
for ( unsigned int i = 0; i < m_data.size(); i++ )
|
||||
{
|
||||
char c = m_data.data()[i];
|
||||
if ( isascii(c) )
|
||||
{
|
||||
debugout << c;
|
||||
}
|
||||
else
|
||||
{
|
||||
debugout << '.';
|
||||
}
|
||||
if ( i == m_data.size()-1 )
|
||||
{
|
||||
debugout << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBuffer::Dump(const std::string &title)
|
||||
{
|
||||
std::cout << title << ":" << std::endl;
|
||||
|
||||
unsigned int offset = 0U;
|
||||
unsigned int length = m_data.size();
|
||||
|
||||
while (length > 0U) {
|
||||
std::string output;
|
||||
|
||||
unsigned int bytes = (length > 16U) ? 16U : length;
|
||||
|
||||
char temp[10U];
|
||||
for (unsigned i = 0U; i < bytes; i++) {
|
||||
::sprintf(temp, "%02X ", m_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 = m_data[offset + i];
|
||||
|
||||
if (::isprint(c))
|
||||
output += c;
|
||||
else
|
||||
output += '.';
|
||||
}
|
||||
|
||||
output += '*';
|
||||
|
||||
::sprintf(temp, "%04X: ", offset);
|
||||
std::cout << temp << output << std::endl;
|
||||
|
||||
offset += 16U;
|
||||
|
||||
if (length >= 16U)
|
||||
length -= 16U;
|
||||
else
|
||||
length = 0U;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
//
|
||||
// Buffer.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 02/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cbuffer_h
|
||||
#define cbuffer_h
|
||||
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include "Main.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CBuffer
|
||||
{
|
||||
public:
|
||||
CBuffer() {}
|
||||
CBuffer(uint8_t *, int);
|
||||
|
||||
// destructor
|
||||
virtual ~CBuffer() {};
|
||||
|
||||
// set
|
||||
void Set(uint8_t *, int);
|
||||
void Set(const char *);
|
||||
void Append(const uint8_t *, int);
|
||||
void Append(uint8_t, int);
|
||||
void Append(uint8_t);
|
||||
void Append(uint16_t);
|
||||
void Append(uint32_t);
|
||||
void Append(const char *);
|
||||
void ReplaceAt(int, uint8_t);
|
||||
void ReplaceAt(int, uint16_t);
|
||||
void ReplaceAt(int, uint32_t);
|
||||
void ReplaceAt(int, const uint8_t *, int);
|
||||
|
||||
// operation
|
||||
int Compare(uint8_t *, int) const;
|
||||
int Compare(uint8_t *, int, int) const;
|
||||
|
||||
// operator
|
||||
bool operator ==(const CBuffer &) const;
|
||||
bool operator ==(const char *) const;
|
||||
operator const char *() const;
|
||||
|
||||
// debug
|
||||
void DebugDump(std::ofstream &) const;
|
||||
void DebugDumpAscii(std::ofstream &) const;
|
||||
void Dump(const std::string &title);
|
||||
|
||||
// pass through
|
||||
void clear() { m_data.clear(); }
|
||||
std::vector<uint8_t>::size_type size() const { return m_data.size(); }
|
||||
uint8_t *data() { return m_data.data(); }
|
||||
const uint8_t *data() const { return m_data.data(); }
|
||||
void resize(std::vector<uint8_t>::size_type len, uint8_t val = 0) { m_data.resize(len, val); }
|
||||
uint8_t at(std::vector<uint8_t>::size_type i) const { return m_data.at(i); }
|
||||
|
||||
protected:
|
||||
std::vector<uint8_t> m_data;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cbuffer_h */
|
||||
@ -0,0 +1,354 @@
|
||||
/*
|
||||
* Copyright (C) 2012 by Ian Wraith
|
||||
* Copyright (C) 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 "CBPT19696.h"
|
||||
|
||||
#include "Hamming.h"
|
||||
#include "Utils.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
CBPTC19696::CBPTC19696()
|
||||
{
|
||||
}
|
||||
|
||||
CBPTC19696::~CBPTC19696()
|
||||
{
|
||||
}
|
||||
|
||||
// The main decode function
|
||||
void CBPTC19696::decode(const unsigned char* in, unsigned char* out)
|
||||
{
|
||||
assert(in != nullptr);
|
||||
assert(out != nullptr);
|
||||
|
||||
// Get the raw binary
|
||||
decodeExtractBinary(in);
|
||||
|
||||
// Deinterleave
|
||||
decodeDeInterleave();
|
||||
|
||||
// Error check
|
||||
decodeErrorCheck();
|
||||
|
||||
// Extract Data
|
||||
decodeExtractData(out);
|
||||
}
|
||||
|
||||
// The main encode function
|
||||
void CBPTC19696::encode(const unsigned char* in, unsigned char* out)
|
||||
{
|
||||
assert(in != nullptr);
|
||||
assert(out != nullptr);
|
||||
|
||||
// Extract Data
|
||||
encodeExtractData(in);
|
||||
|
||||
// Error check
|
||||
encodeErrorCheck();
|
||||
|
||||
// Deinterleave
|
||||
encodeInterleave();
|
||||
|
||||
// Get the raw binary
|
||||
encodeExtractBinary(out);
|
||||
}
|
||||
|
||||
void CBPTC19696::decodeExtractBinary(const unsigned char* in)
|
||||
{
|
||||
// First block
|
||||
CUtils::byteToBitsBE(in[0U], m_rawData + 0U);
|
||||
CUtils::byteToBitsBE(in[1U], m_rawData + 8U);
|
||||
CUtils::byteToBitsBE(in[2U], m_rawData + 16U);
|
||||
CUtils::byteToBitsBE(in[3U], m_rawData + 24U);
|
||||
CUtils::byteToBitsBE(in[4U], m_rawData + 32U);
|
||||
CUtils::byteToBitsBE(in[5U], m_rawData + 40U);
|
||||
CUtils::byteToBitsBE(in[6U], m_rawData + 48U);
|
||||
CUtils::byteToBitsBE(in[7U], m_rawData + 56U);
|
||||
CUtils::byteToBitsBE(in[8U], m_rawData + 64U);
|
||||
CUtils::byteToBitsBE(in[9U], m_rawData + 72U);
|
||||
CUtils::byteToBitsBE(in[10U], m_rawData + 80U);
|
||||
CUtils::byteToBitsBE(in[11U], m_rawData + 88U);
|
||||
CUtils::byteToBitsBE(in[12U], m_rawData + 96U);
|
||||
|
||||
// Handle the two bits
|
||||
bool bits[8U];
|
||||
CUtils::byteToBitsBE(in[20U], bits);
|
||||
m_rawData[98U] = bits[6U];
|
||||
m_rawData[99U] = bits[7U];
|
||||
|
||||
// Second block
|
||||
CUtils::byteToBitsBE(in[21U], m_rawData + 100U);
|
||||
CUtils::byteToBitsBE(in[22U], m_rawData + 108U);
|
||||
CUtils::byteToBitsBE(in[23U], m_rawData + 116U);
|
||||
CUtils::byteToBitsBE(in[24U], m_rawData + 124U);
|
||||
CUtils::byteToBitsBE(in[25U], m_rawData + 132U);
|
||||
CUtils::byteToBitsBE(in[26U], m_rawData + 140U);
|
||||
CUtils::byteToBitsBE(in[27U], m_rawData + 148U);
|
||||
CUtils::byteToBitsBE(in[28U], m_rawData + 156U);
|
||||
CUtils::byteToBitsBE(in[29U], m_rawData + 164U);
|
||||
CUtils::byteToBitsBE(in[30U], m_rawData + 172U);
|
||||
CUtils::byteToBitsBE(in[31U], m_rawData + 180U);
|
||||
CUtils::byteToBitsBE(in[32U], m_rawData + 188U);
|
||||
}
|
||||
|
||||
// Deinterleave the raw data
|
||||
void CBPTC19696::decodeDeInterleave()
|
||||
{
|
||||
for (unsigned int i = 0U; i < 196U; i++)
|
||||
m_deInterData[i] = false;
|
||||
|
||||
// The first bit is R(3) which is not used so can be ignored
|
||||
for (unsigned int a = 0U; a < 196U; a++)
|
||||
{
|
||||
// Calculate the interleave sequence
|
||||
unsigned int interleaveSequence = (a * 181U) % 196U;
|
||||
// Shuffle the data
|
||||
m_deInterData[a] = m_rawData[interleaveSequence];
|
||||
}
|
||||
}
|
||||
|
||||
// Check each row with a Hamming (15,11,3) code and each column with a Hamming (13,9,3) code
|
||||
void CBPTC19696::decodeErrorCheck()
|
||||
{
|
||||
bool fixing;
|
||||
unsigned int count = 0U;
|
||||
do
|
||||
{
|
||||
fixing = false;
|
||||
|
||||
// Run through each of the 15 columns
|
||||
bool col[13U];
|
||||
for (unsigned int c = 0U; c < 15U; c++)
|
||||
{
|
||||
unsigned int pos = c + 1U;
|
||||
for (unsigned int a = 0U; a < 13U; a++)
|
||||
{
|
||||
col[a] = m_deInterData[pos];
|
||||
pos = pos + 15U;
|
||||
}
|
||||
|
||||
if (CHamming::decode1393(col))
|
||||
{
|
||||
unsigned int pos = c + 1U;
|
||||
for (unsigned int a = 0U; a < 13U; a++)
|
||||
{
|
||||
m_deInterData[pos] = col[a];
|
||||
pos = pos + 15U;
|
||||
}
|
||||
|
||||
fixing = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Run through each of the 9 rows containing data
|
||||
for (unsigned int r = 0U; r < 9U; r++)
|
||||
{
|
||||
unsigned int pos = (r * 15U) + 1U;
|
||||
if (CHamming::decode15113_2(m_deInterData + pos))
|
||||
fixing = true;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
while (fixing && count < 5U);
|
||||
}
|
||||
|
||||
// Extract the 96 bits of payload
|
||||
void CBPTC19696::decodeExtractData(unsigned char* data) const
|
||||
{
|
||||
bool bData[96U];
|
||||
unsigned int pos = 0U;
|
||||
for (unsigned int a = 4U; a <= 11U; a++, pos++)
|
||||
bData[pos] = m_deInterData[a];
|
||||
|
||||
for (unsigned int a = 16U; a <= 26U; a++, pos++)
|
||||
bData[pos] = m_deInterData[a];
|
||||
|
||||
for (unsigned int a = 31U; a <= 41U; a++, pos++)
|
||||
bData[pos] = m_deInterData[a];
|
||||
|
||||
for (unsigned int a = 46U; a <= 56U; a++, pos++)
|
||||
bData[pos] = m_deInterData[a];
|
||||
|
||||
for (unsigned int a = 61U; a <= 71U; a++, pos++)
|
||||
bData[pos] = m_deInterData[a];
|
||||
|
||||
for (unsigned int a = 76U; a <= 86U; a++, pos++)
|
||||
bData[pos] = m_deInterData[a];
|
||||
|
||||
for (unsigned int a = 91U; a <= 101U; a++, pos++)
|
||||
bData[pos] = m_deInterData[a];
|
||||
|
||||
for (unsigned int a = 106U; a <= 116U; a++, pos++)
|
||||
bData[pos] = m_deInterData[a];
|
||||
|
||||
for (unsigned int a = 121U; a <= 131U; a++, pos++)
|
||||
bData[pos] = m_deInterData[a];
|
||||
|
||||
CUtils::bitsToByteBE(bData + 0U, data[0U]);
|
||||
CUtils::bitsToByteBE(bData + 8U, data[1U]);
|
||||
CUtils::bitsToByteBE(bData + 16U, data[2U]);
|
||||
CUtils::bitsToByteBE(bData + 24U, data[3U]);
|
||||
CUtils::bitsToByteBE(bData + 32U, data[4U]);
|
||||
CUtils::bitsToByteBE(bData + 40U, data[5U]);
|
||||
CUtils::bitsToByteBE(bData + 48U, data[6U]);
|
||||
CUtils::bitsToByteBE(bData + 56U, data[7U]);
|
||||
CUtils::bitsToByteBE(bData + 64U, data[8U]);
|
||||
CUtils::bitsToByteBE(bData + 72U, data[9U]);
|
||||
CUtils::bitsToByteBE(bData + 80U, data[10U]);
|
||||
CUtils::bitsToByteBE(bData + 88U, data[11U]);
|
||||
}
|
||||
|
||||
// Extract the 96 bits of payload
|
||||
void CBPTC19696::encodeExtractData(const unsigned char* in)
|
||||
{
|
||||
bool bData[96U];
|
||||
CUtils::byteToBitsBE(in[0U], bData + 0U);
|
||||
CUtils::byteToBitsBE(in[1U], bData + 8U);
|
||||
CUtils::byteToBitsBE(in[2U], bData + 16U);
|
||||
CUtils::byteToBitsBE(in[3U], bData + 24U);
|
||||
CUtils::byteToBitsBE(in[4U], bData + 32U);
|
||||
CUtils::byteToBitsBE(in[5U], bData + 40U);
|
||||
CUtils::byteToBitsBE(in[6U], bData + 48U);
|
||||
CUtils::byteToBitsBE(in[7U], bData + 56U);
|
||||
CUtils::byteToBitsBE(in[8U], bData + 64U);
|
||||
CUtils::byteToBitsBE(in[9U], bData + 72U);
|
||||
CUtils::byteToBitsBE(in[10U], bData + 80U);
|
||||
CUtils::byteToBitsBE(in[11U], bData + 88U);
|
||||
|
||||
for (unsigned int i = 0U; i < 196U; i++)
|
||||
m_deInterData[i] = false;
|
||||
|
||||
unsigned int pos = 0U;
|
||||
for (unsigned int a = 4U; a <= 11U; a++, pos++)
|
||||
m_deInterData[a] = bData[pos];
|
||||
|
||||
for (unsigned int a = 16U; a <= 26U; a++, pos++)
|
||||
m_deInterData[a] = bData[pos];
|
||||
|
||||
for (unsigned int a = 31U; a <= 41U; a++, pos++)
|
||||
m_deInterData[a] = bData[pos];
|
||||
|
||||
for (unsigned int a = 46U; a <= 56U; a++, pos++)
|
||||
m_deInterData[a] = bData[pos];
|
||||
|
||||
for (unsigned int a = 61U; a <= 71U; a++, pos++)
|
||||
m_deInterData[a] = bData[pos];
|
||||
|
||||
for (unsigned int a = 76U; a <= 86U; a++, pos++)
|
||||
m_deInterData[a] = bData[pos];
|
||||
|
||||
for (unsigned int a = 91U; a <= 101U; a++, pos++)
|
||||
m_deInterData[a] = bData[pos];
|
||||
|
||||
for (unsigned int a = 106U; a <= 116U; a++, pos++)
|
||||
m_deInterData[a] = bData[pos];
|
||||
|
||||
for (unsigned int a = 121U; a <= 131U; a++, pos++)
|
||||
m_deInterData[a] = bData[pos];
|
||||
}
|
||||
|
||||
// Check each row with a Hamming (15,11,3) code and each column with a Hamming (13,9,3) code
|
||||
void CBPTC19696::encodeErrorCheck()
|
||||
{
|
||||
|
||||
// Run through each of the 9 rows containing data
|
||||
for (unsigned int r = 0U; r < 9U; r++)
|
||||
{
|
||||
unsigned int pos = (r * 15U) + 1U;
|
||||
CHamming::encode15113_2(m_deInterData + pos);
|
||||
}
|
||||
|
||||
// Run through each of the 15 columns
|
||||
bool col[13U];
|
||||
for (unsigned int c = 0U; c < 15U; c++)
|
||||
{
|
||||
unsigned int pos = c + 1U;
|
||||
for (unsigned int a = 0U; a < 13U; a++)
|
||||
{
|
||||
col[a] = m_deInterData[pos];
|
||||
pos = pos + 15U;
|
||||
}
|
||||
|
||||
CHamming::encode1393(col);
|
||||
|
||||
pos = c + 1U;
|
||||
for (unsigned int a = 0U; a < 13U; a++)
|
||||
{
|
||||
m_deInterData[pos] = col[a];
|
||||
pos = pos + 15U;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Interleave the raw data
|
||||
void CBPTC19696::encodeInterleave()
|
||||
{
|
||||
for (unsigned int i = 0U; i < 196U; i++)
|
||||
m_rawData[i] = false;
|
||||
|
||||
// The first bit is R(3) which is not used so can be ignored
|
||||
for (unsigned int a = 0U; a < 196U; a++)
|
||||
{
|
||||
// Calculate the interleave sequence
|
||||
unsigned int interleaveSequence = (a * 181U) % 196U;
|
||||
// Unshuffle the data
|
||||
m_rawData[interleaveSequence] = m_deInterData[a];
|
||||
}
|
||||
}
|
||||
|
||||
void CBPTC19696::encodeExtractBinary(unsigned char* data)
|
||||
{
|
||||
// First block
|
||||
CUtils::bitsToByteBE(m_rawData + 0U, data[0U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 8U, data[1U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 16U, data[2U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 24U, data[3U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 32U, data[4U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 40U, data[5U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 48U, data[6U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 56U, data[7U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 64U, data[8U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 72U, data[9U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 80U, data[10U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 88U, data[11U]);
|
||||
|
||||
// Handle the two bits
|
||||
unsigned char byte;
|
||||
CUtils::bitsToByteBE(m_rawData + 96U, byte);
|
||||
data[12U] = (data[12U] & 0x3FU) | ((byte >> 0) & 0xC0U);
|
||||
data[20U] = (data[20U] & 0xFCU) | ((byte >> 4) & 0x03U);
|
||||
|
||||
// Second block
|
||||
CUtils::bitsToByteBE(m_rawData + 100U, data[21U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 108U, data[22U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 116U, data[23U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 124U, data[24U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 132U, data[25U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 140U, data[26U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 148U, data[27U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 156U, data[28U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 164U, data[29U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 172U, data[30U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 180U, data[31U]);
|
||||
CUtils::bitsToByteBE(m_rawData + 188U, data[32U]);
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
#if !defined(BPTC19696_H)
|
||||
#define BPTC19696_H
|
||||
|
||||
class CBPTC19696
|
||||
{
|
||||
public:
|
||||
CBPTC19696();
|
||||
~CBPTC19696();
|
||||
|
||||
void decode(const unsigned char* in, unsigned char* out);
|
||||
|
||||
void encode(const unsigned char* in, unsigned char* out);
|
||||
|
||||
private:
|
||||
bool m_rawData[196];
|
||||
bool m_deInterData[196];
|
||||
|
||||
void decodeExtractBinary(const unsigned char* in);
|
||||
void decodeErrorCheck();
|
||||
void decodeDeInterleave();
|
||||
void decodeExtractData(unsigned char* data) const;
|
||||
|
||||
void encodeExtractData(const unsigned char* in);
|
||||
void encodeInterleave();
|
||||
void encodeErrorCheck();
|
||||
void encodeExtractBinary(unsigned char* data);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,68 @@
|
||||
//
|
||||
// NotificationQueue.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc on 05/12/2015.
|
||||
// Copyright © 2015 Jean-Luc. All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#ifndef cnotificationqueue_h
|
||||
#define cnotificationqueue_h
|
||||
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
|
||||
#include "Notification.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CNotificationQueue
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CNotificationQueue() {}
|
||||
|
||||
// destructor
|
||||
~CNotificationQueue() {}
|
||||
|
||||
// lock
|
||||
void Lock() { m_Mutex.lock(); }
|
||||
void Unlock() { m_Mutex.unlock(); }
|
||||
|
||||
// pass thru
|
||||
CNotification front() { return queue.front(); }
|
||||
void pop() { queue.pop(); }
|
||||
void push(CNotification note) { queue.push(note); }
|
||||
bool empty() const { return queue.empty(); }
|
||||
|
||||
protected:
|
||||
// data
|
||||
std::mutex m_Mutex;
|
||||
std::queue<CNotification> queue;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cnotificationqueue_h */
|
||||
@ -0,0 +1,262 @@
|
||||
/*
|
||||
* 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 "CRC.h"
|
||||
|
||||
#include "Utils.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
const uint8_t CRC8_TABLE[] =
|
||||
{
|
||||
0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31,
|
||||
0x24, 0x23, 0x2A, 0x2D, 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
|
||||
0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 0xE0, 0xE7, 0xEE, 0xE9,
|
||||
0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
|
||||
0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1,
|
||||
0xB4, 0xB3, 0xBA, 0xBD, 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
|
||||
0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 0xB7, 0xB0, 0xB9, 0xBE,
|
||||
0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
|
||||
0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16,
|
||||
0x03, 0x04, 0x0D, 0x0A, 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
|
||||
0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, 0x89, 0x8E, 0x87, 0x80,
|
||||
0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
|
||||
0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8,
|
||||
0xDD, 0xDA, 0xD3, 0xD4, 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
|
||||
0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 0x19, 0x1E, 0x17, 0x10,
|
||||
0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
|
||||
0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F,
|
||||
0x6A, 0x6D, 0x64, 0x63, 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
|
||||
0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 0xAE, 0xA9, 0xA0, 0xA7,
|
||||
0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
|
||||
0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF,
|
||||
0xFA, 0xFD, 0xF4, 0xF3, 0x01
|
||||
};
|
||||
|
||||
const uint16_t CCITT16_TABLE1[] =
|
||||
{
|
||||
0x0000U, 0x1189U, 0x2312U, 0x329bU, 0x4624U, 0x57adU, 0x6536U, 0x74bfU,
|
||||
0x8c48U, 0x9dc1U, 0xaf5aU, 0xbed3U, 0xca6cU, 0xdbe5U, 0xe97eU, 0xf8f7U,
|
||||
0x1081U, 0x0108U, 0x3393U, 0x221aU, 0x56a5U, 0x472cU, 0x75b7U, 0x643eU,
|
||||
0x9cc9U, 0x8d40U, 0xbfdbU, 0xae52U, 0xdaedU, 0xcb64U, 0xf9ffU, 0xe876U,
|
||||
0x2102U, 0x308bU, 0x0210U, 0x1399U, 0x6726U, 0x76afU, 0x4434U, 0x55bdU,
|
||||
0xad4aU, 0xbcc3U, 0x8e58U, 0x9fd1U, 0xeb6eU, 0xfae7U, 0xc87cU, 0xd9f5U,
|
||||
0x3183U, 0x200aU, 0x1291U, 0x0318U, 0x77a7U, 0x662eU, 0x54b5U, 0x453cU,
|
||||
0xbdcbU, 0xac42U, 0x9ed9U, 0x8f50U, 0xfbefU, 0xea66U, 0xd8fdU, 0xc974U,
|
||||
0x4204U, 0x538dU, 0x6116U, 0x709fU, 0x0420U, 0x15a9U, 0x2732U, 0x36bbU,
|
||||
0xce4cU, 0xdfc5U, 0xed5eU, 0xfcd7U, 0x8868U, 0x99e1U, 0xab7aU, 0xbaf3U,
|
||||
0x5285U, 0x430cU, 0x7197U, 0x601eU, 0x14a1U, 0x0528U, 0x37b3U, 0x263aU,
|
||||
0xdecdU, 0xcf44U, 0xfddfU, 0xec56U, 0x98e9U, 0x8960U, 0xbbfbU, 0xaa72U,
|
||||
0x6306U, 0x728fU, 0x4014U, 0x519dU, 0x2522U, 0x34abU, 0x0630U, 0x17b9U,
|
||||
0xef4eU, 0xfec7U, 0xcc5cU, 0xddd5U, 0xa96aU, 0xb8e3U, 0x8a78U, 0x9bf1U,
|
||||
0x7387U, 0x620eU, 0x5095U, 0x411cU, 0x35a3U, 0x242aU, 0x16b1U, 0x0738U,
|
||||
0xffcfU, 0xee46U, 0xdcddU, 0xcd54U, 0xb9ebU, 0xa862U, 0x9af9U, 0x8b70U,
|
||||
0x8408U, 0x9581U, 0xa71aU, 0xb693U, 0xc22cU, 0xd3a5U, 0xe13eU, 0xf0b7U,
|
||||
0x0840U, 0x19c9U, 0x2b52U, 0x3adbU, 0x4e64U, 0x5fedU, 0x6d76U, 0x7cffU,
|
||||
0x9489U, 0x8500U, 0xb79bU, 0xa612U, 0xd2adU, 0xc324U, 0xf1bfU, 0xe036U,
|
||||
0x18c1U, 0x0948U, 0x3bd3U, 0x2a5aU, 0x5ee5U, 0x4f6cU, 0x7df7U, 0x6c7eU,
|
||||
0xa50aU, 0xb483U, 0x8618U, 0x9791U, 0xe32eU, 0xf2a7U, 0xc03cU, 0xd1b5U,
|
||||
0x2942U, 0x38cbU, 0x0a50U, 0x1bd9U, 0x6f66U, 0x7eefU, 0x4c74U, 0x5dfdU,
|
||||
0xb58bU, 0xa402U, 0x9699U, 0x8710U, 0xf3afU, 0xe226U, 0xd0bdU, 0xc134U,
|
||||
0x39c3U, 0x284aU, 0x1ad1U, 0x0b58U, 0x7fe7U, 0x6e6eU, 0x5cf5U, 0x4d7cU,
|
||||
0xc60cU, 0xd785U, 0xe51eU, 0xf497U, 0x8028U, 0x91a1U, 0xa33aU, 0xb2b3U,
|
||||
0x4a44U, 0x5bcdU, 0x6956U, 0x78dfU, 0x0c60U, 0x1de9U, 0x2f72U, 0x3efbU,
|
||||
0xd68dU, 0xc704U, 0xf59fU, 0xe416U, 0x90a9U, 0x8120U, 0xb3bbU, 0xa232U,
|
||||
0x5ac5U, 0x4b4cU, 0x79d7U, 0x685eU, 0x1ce1U, 0x0d68U, 0x3ff3U, 0x2e7aU,
|
||||
0xe70eU, 0xf687U, 0xc41cU, 0xd595U, 0xa12aU, 0xb0a3U, 0x8238U, 0x93b1U,
|
||||
0x6b46U, 0x7acfU, 0x4854U, 0x59ddU, 0x2d62U, 0x3cebU, 0x0e70U, 0x1ff9U,
|
||||
0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U,
|
||||
0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U
|
||||
};
|
||||
|
||||
const uint16_t CCITT16_TABLE2[] =
|
||||
{
|
||||
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
|
||||
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
|
||||
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
|
||||
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
|
||||
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
|
||||
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
|
||||
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
|
||||
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
|
||||
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
|
||||
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
|
||||
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
|
||||
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
|
||||
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
|
||||
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
|
||||
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
|
||||
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
|
||||
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
|
||||
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
|
||||
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
|
||||
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
|
||||
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
|
||||
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
|
||||
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
|
||||
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
|
||||
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
|
||||
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
|
||||
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
|
||||
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
|
||||
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
|
||||
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
|
||||
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
|
||||
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
|
||||
};
|
||||
|
||||
|
||||
bool CCRC::checkFiveBit(bool* in, unsigned int tcrc)
|
||||
{
|
||||
assert(in != nullptr);
|
||||
|
||||
unsigned int crc;
|
||||
encodeFiveBit(in, crc);
|
||||
|
||||
return crc == tcrc;
|
||||
}
|
||||
|
||||
void CCRC::encodeFiveBit(const bool* in, unsigned int& tcrc)
|
||||
{
|
||||
assert(in != nullptr);
|
||||
|
||||
unsigned short total = 0U;
|
||||
for (unsigned int i = 0U; i < 72U; i += 8U)
|
||||
{
|
||||
unsigned char c;
|
||||
CUtils::bitsToByteBE(in + i, c);
|
||||
total += c;
|
||||
}
|
||||
|
||||
total %= 31U;
|
||||
|
||||
tcrc = total;
|
||||
}
|
||||
|
||||
void CCRC::addCCITT162(unsigned char *in, unsigned int length)
|
||||
{
|
||||
assert(in != nullptr);
|
||||
assert(length > 2U);
|
||||
|
||||
union
|
||||
{
|
||||
uint16_t crc16;
|
||||
uint8_t crc8[2U];
|
||||
};
|
||||
|
||||
crc16 = 0U;
|
||||
|
||||
for (unsigned i = 0U; i < (length - 2U); i++)
|
||||
crc16 = (uint16_t(crc8[0U]) << 8) ^ CCITT16_TABLE2[crc8[1U] ^ in[i]];
|
||||
|
||||
crc16 = ~crc16;
|
||||
|
||||
in[length - 1U] = crc8[0U];
|
||||
in[length - 2U] = crc8[1U];
|
||||
}
|
||||
|
||||
bool CCRC::checkCCITT162(const unsigned char *in, unsigned int length)
|
||||
{
|
||||
assert(in != nullptr);
|
||||
assert(length > 2U);
|
||||
|
||||
union
|
||||
{
|
||||
uint16_t crc16;
|
||||
uint8_t crc8[2U];
|
||||
};
|
||||
|
||||
crc16 = 0U;
|
||||
|
||||
for (unsigned i = 0U; i < (length - 2U); i++)
|
||||
crc16 = (uint16_t(crc8[0U]) << 8) ^ CCITT16_TABLE2[crc8[1U] ^ in[i]];
|
||||
|
||||
crc16 = ~crc16;
|
||||
|
||||
return crc8[0U] == in[length - 1U] && crc8[1U] == in[length - 2U];
|
||||
}
|
||||
|
||||
void CCRC::addCCITT161(unsigned char *in, unsigned int length)
|
||||
{
|
||||
assert(in != nullptr);
|
||||
assert(length > 2U);
|
||||
|
||||
union
|
||||
{
|
||||
uint16_t crc16;
|
||||
uint8_t crc8[2U];
|
||||
};
|
||||
|
||||
crc16 = 0xFFFFU;
|
||||
|
||||
for (unsigned int i = 0U; i < (length - 2U); i++)
|
||||
crc16 = uint16_t(crc8[1U]) ^ CCITT16_TABLE1[crc8[0U] ^ in[i]];
|
||||
|
||||
crc16 = ~crc16;
|
||||
|
||||
in[length - 2U] = crc8[0U];
|
||||
in[length - 1U] = crc8[1U];
|
||||
}
|
||||
|
||||
bool CCRC::checkCCITT161(const unsigned char *in, unsigned int length)
|
||||
{
|
||||
assert(in != nullptr);
|
||||
assert(length > 2U);
|
||||
|
||||
union
|
||||
{
|
||||
uint16_t crc16;
|
||||
uint8_t crc8[2U];
|
||||
};
|
||||
|
||||
crc16 = 0xFFFFU;
|
||||
|
||||
for (unsigned int i = 0U; i < (length - 2U); i++)
|
||||
crc16 = uint16_t(crc8[1U]) ^ CCITT16_TABLE1[crc8[0U] ^ in[i]];
|
||||
|
||||
crc16 = ~crc16;
|
||||
|
||||
return crc8[0U] == in[length - 2U] && crc8[1U] == in[length - 1U];
|
||||
}
|
||||
|
||||
unsigned char CCRC::crc8(const unsigned char *in, unsigned int length)
|
||||
{
|
||||
assert(in != nullptr);
|
||||
|
||||
uint8_t crc = 0U;
|
||||
|
||||
for (unsigned int i = 0U; i < length; i++)
|
||||
crc = CRC8_TABLE[crc ^ in[i]];
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
unsigned char CCRC::addCRC(const unsigned char* in, unsigned int length)
|
||||
{
|
||||
assert(in != nullptr);
|
||||
|
||||
unsigned char crc = 0U;
|
||||
|
||||
for (unsigned int i = 0U; i < length; i++)
|
||||
crc += in[i];
|
||||
|
||||
return crc;
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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(CRC_H)
|
||||
#define CRC_H
|
||||
|
||||
class CCRC
|
||||
{
|
||||
public:
|
||||
static bool checkFiveBit(bool* in, unsigned int tcrc);
|
||||
static void encodeFiveBit(const bool* in, unsigned int& tcrc);
|
||||
|
||||
static void addCCITT161(unsigned char* in, unsigned int length);
|
||||
static void addCCITT162(unsigned char* in, unsigned int length);
|
||||
|
||||
static bool checkCCITT161(const unsigned char* in, unsigned int length);
|
||||
static bool checkCCITT162(const unsigned char* in, unsigned int length);
|
||||
|
||||
static unsigned char crc8(const unsigned char* in, unsigned int length);
|
||||
|
||||
static unsigned char addCRC(const unsigned char* in, unsigned int length);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,370 @@
|
||||
//
|
||||
// ccallsign.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include <cctype>
|
||||
#include "cdmriddirfile.h"
|
||||
#include "DMRIdDirHttp.h"
|
||||
#include "Callsign.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructors
|
||||
|
||||
CCallsign::CCallsign()
|
||||
{
|
||||
// blank all
|
||||
::memset(m_Callsign, ' ', sizeof(m_Callsign));
|
||||
::memset(m_Suffix, ' ', sizeof(m_Suffix));
|
||||
m_Module = ' ';
|
||||
#ifndef NO_XLX
|
||||
m_uiDmrid = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
CCallsign::CCallsign(const char *sz, uint32 dmrid)
|
||||
{
|
||||
// blank all
|
||||
::memset(m_Callsign, ' ', sizeof(m_Callsign));
|
||||
::memset(m_Suffix, ' ', sizeof(m_Suffix));
|
||||
m_Module = ' ';
|
||||
#ifndef NO_XLX
|
||||
m_uiDmrid = dmrid;
|
||||
#endif
|
||||
|
||||
// and populate
|
||||
if ( ::strlen(sz) > 0 )
|
||||
{
|
||||
// callsign valid
|
||||
::memcpy(m_Callsign, sz, MIN(strlen(sz), sizeof(m_Callsign)-1));
|
||||
if ( strlen(sz) >= sizeof(m_Callsign) )
|
||||
{
|
||||
m_Module = sz[sizeof(m_Callsign)-1];
|
||||
}
|
||||
#ifndef NO_XLX
|
||||
// dmrid ok ?
|
||||
if ( m_uiDmrid == 0 )
|
||||
{
|
||||
g_DmridDir.Lock();
|
||||
{
|
||||
m_uiDmrid = g_DmridDir.FindDmrid(*this);
|
||||
}
|
||||
g_DmridDir.Unlock();
|
||||
}
|
||||
}
|
||||
else if ( m_uiDmrid != 0 )
|
||||
{
|
||||
g_DmridDir.Lock();
|
||||
{
|
||||
const CCallsign *callsign = g_DmridDir.FindCallsign(m_uiDmrid);
|
||||
if ( callsign != nullptr )
|
||||
{
|
||||
::memcpy(m_Callsign, callsign->m_Callsign, sizeof(m_Callsign));
|
||||
}
|
||||
}
|
||||
g_DmridDir.Unlock();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// status
|
||||
|
||||
bool CCallsign::IsValid(void) const
|
||||
{
|
||||
bool valid = true;
|
||||
int i;
|
||||
|
||||
// callsign
|
||||
// first 3 chars are letter or number but cannot be all number
|
||||
int iNum = 0;
|
||||
for ( i = 0; i < 3; i++ )
|
||||
{
|
||||
valid &= IsLetter(m_Callsign[i]) || IsNumber(m_Callsign[i]);
|
||||
if ( IsNumber(m_Callsign[i]) )
|
||||
{
|
||||
iNum++;
|
||||
}
|
||||
}
|
||||
valid &= (iNum < 3);
|
||||
// all remaining char are letter, number or space
|
||||
for ( ; i < CALLSIGN_LEN; i++)
|
||||
{
|
||||
valid &= IsLetter(m_Callsign[i]) || IsNumber(m_Callsign[i]) || IsSpace(m_Callsign[i]);
|
||||
}
|
||||
|
||||
// prefix
|
||||
// all chars are number, uppercase or space
|
||||
for ( i = 0; i < CALLSUFFIX_LEN; i++ )
|
||||
{
|
||||
valid &= IsLetter(m_Suffix[i]) || IsNumber(m_Suffix[i]) || IsSpace(m_Suffix[i]);
|
||||
}
|
||||
|
||||
// module
|
||||
// is an letter or space
|
||||
valid &= IsLetter(m_Module) || IsSpace(m_Module);
|
||||
|
||||
// dmrid is not tested, as it can be nullptr
|
||||
// if station does is not dmr registered
|
||||
|
||||
// done
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool CCallsign::HasSuffix(void) const
|
||||
{
|
||||
bool has = false;
|
||||
for ( int i = 0; i < CALLSUFFIX_LEN; i++ )
|
||||
{
|
||||
has |= (m_Suffix[i] != ' ');
|
||||
}
|
||||
return has;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set
|
||||
|
||||
void CCallsign::SetCallsign(const char *sz, bool UpdateDmrid)
|
||||
{
|
||||
// set callsign
|
||||
::memset(m_Callsign, ' ', sizeof(m_Callsign));
|
||||
m_Module = ' ';
|
||||
::memcpy(m_Callsign, sz, MIN(strlen(sz), sizeof(m_Callsign)-1));
|
||||
if ( strlen(sz) >= sizeof(m_Callsign) )
|
||||
{
|
||||
m_Module = sz[sizeof(m_Callsign)-1];
|
||||
}
|
||||
#ifndef NO_XLX
|
||||
// and update dmrid
|
||||
if ( UpdateDmrid )
|
||||
{
|
||||
g_DmridDir.Lock();
|
||||
{
|
||||
m_uiDmrid = g_DmridDir.FindDmrid(*this);
|
||||
}
|
||||
g_DmridDir.Unlock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void CCallsign::SetCallsign(const uint8 *buffer, int len, bool UpdateDmrid)
|
||||
{
|
||||
// set callsign
|
||||
::memset(m_Callsign, ' ', sizeof(m_Callsign));
|
||||
m_Module = ' ';
|
||||
::memcpy(m_Callsign, buffer, MIN(len, (int)sizeof(m_Callsign)-1));
|
||||
for ( unsigned i = 0; i < sizeof(m_Callsign); i++ )
|
||||
{
|
||||
if ( m_Callsign[i] == 0 )
|
||||
{
|
||||
m_Callsign[i] = ' ';
|
||||
}
|
||||
}
|
||||
if ( (len >= (int)sizeof(m_Callsign)) && ((char)buffer[sizeof(m_Callsign)-1] != 0) )
|
||||
{
|
||||
m_Module = (char)buffer[sizeof(m_Callsign)-1];
|
||||
}
|
||||
#ifndef NO_XLX
|
||||
if ( UpdateDmrid )
|
||||
{
|
||||
g_DmridDir.Lock();
|
||||
{
|
||||
m_uiDmrid = g_DmridDir.FindDmrid(*this);
|
||||
}
|
||||
g_DmridDir.Unlock();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NO_XLX
|
||||
void CCallsign::SetDmrid(uint32 dmrid, bool UpdateCallsign)
|
||||
{
|
||||
m_uiDmrid = dmrid;
|
||||
if ( UpdateCallsign )
|
||||
{
|
||||
g_DmridDir.Lock();
|
||||
{
|
||||
const CCallsign *callsign = g_DmridDir.FindCallsign(dmrid);
|
||||
if ( callsign != nullptr )
|
||||
{
|
||||
::memcpy(m_Callsign, callsign->m_Callsign, sizeof(m_Callsign));
|
||||
}
|
||||
}
|
||||
g_DmridDir.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
void CCallsign::SetDmrid(const uint8 *buffer, bool UpdateCallsign)
|
||||
{
|
||||
char sz[9];
|
||||
::memcpy(sz, buffer, 8);
|
||||
sz[8] = 0;
|
||||
SetDmrid((uint32)::strtol(sz, nullptr, 16), UpdateCallsign);
|
||||
}
|
||||
#endif
|
||||
|
||||
void CCallsign::SetModule(char c)
|
||||
{
|
||||
m_Module = c;
|
||||
}
|
||||
|
||||
|
||||
void CCallsign::SetSuffix(const char *sz)
|
||||
{
|
||||
::memset(m_Suffix, ' ', sizeof(m_Suffix));
|
||||
::memcpy(m_Suffix, sz, MIN(strlen(sz), sizeof(m_Suffix)));
|
||||
}
|
||||
|
||||
void CCallsign::SetSuffix(const uint8 *buffer, int len)
|
||||
{
|
||||
len = MIN(len, (int)sizeof(m_Suffix));
|
||||
::memset(m_Suffix, ' ', sizeof(m_Suffix));
|
||||
::memcpy(m_Suffix, buffer, len);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// modify
|
||||
|
||||
void CCallsign::PatchCallsign(int off, const uint8 *patch, int len)
|
||||
{
|
||||
if ( off < CALLSIGN_LEN )
|
||||
{
|
||||
::memcpy(m_Callsign, patch, MIN(len, (int)sizeof(m_Callsign) - off));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// get
|
||||
|
||||
void CCallsign::GetCallsign(uint8 *buffer) const
|
||||
{
|
||||
::memcpy(buffer, m_Callsign, sizeof(m_Callsign));
|
||||
if ( HasModule() )
|
||||
{
|
||||
buffer[sizeof(m_Callsign)-1] = m_Module;
|
||||
}
|
||||
}
|
||||
|
||||
void CCallsign::GetCallsignString(char *sz) const
|
||||
{
|
||||
unsigned i;
|
||||
for ( i = 0; (i < sizeof(m_Callsign)) && (m_Callsign[i] != ' '); i++ )
|
||||
{
|
||||
sz[i] = m_Callsign[i];
|
||||
}
|
||||
sz[i] = 0;
|
||||
}
|
||||
|
||||
void CCallsign::GetSuffix(uint8 *buffer) const
|
||||
{
|
||||
::memcpy(buffer, m_Suffix, sizeof(m_Suffix));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// compare
|
||||
|
||||
bool CCallsign::HasSameCallsign(const CCallsign &Callsign) const
|
||||
{
|
||||
return (::memcmp(m_Callsign, Callsign.m_Callsign, sizeof(m_Callsign)) == 0);
|
||||
}
|
||||
|
||||
bool CCallsign::HasSameCallsignWithWildcard(const CCallsign &callsign) const
|
||||
{
|
||||
bool same = true;
|
||||
bool done = false;
|
||||
|
||||
for ( unsigned i = 0; (i < sizeof(m_Callsign)) && same && !done; i++ )
|
||||
{
|
||||
if ( !(done = ((m_Callsign[i] == '*') || (callsign[i] == '*'))) )
|
||||
{
|
||||
same &= (m_Callsign[i] == callsign[i]);
|
||||
}
|
||||
}
|
||||
return same;
|
||||
}
|
||||
|
||||
bool CCallsign::HasLowerCallsign(const CCallsign &Callsign) const
|
||||
{
|
||||
return (::memcmp(m_Callsign, Callsign.m_Callsign, sizeof(m_Callsign)) < 0);
|
||||
}
|
||||
|
||||
bool CCallsign::HasSameModule(const CCallsign &Callsign) const
|
||||
{
|
||||
return (m_Module == Callsign.m_Module);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operators
|
||||
|
||||
bool CCallsign::operator ==(const CCallsign &callsign) const
|
||||
{
|
||||
return ((::memcmp(callsign.m_Callsign, m_Callsign, sizeof(m_Callsign)) == 0) && (m_Module == callsign.m_Module)
|
||||
&& (::memcmp(callsign.m_Suffix, m_Suffix, sizeof(m_Suffix)) == 0)
|
||||
#ifndef NO_XLX
|
||||
&& (m_uiDmrid == callsign.m_uiDmrid)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
CCallsign::operator const char *() const
|
||||
{
|
||||
// empty
|
||||
::memset(m_sz, 0, sizeof(m_sz));
|
||||
// callsign
|
||||
::memcpy(m_sz, m_Callsign, sizeof(m_Callsign));
|
||||
// module
|
||||
if ( HasModule() )
|
||||
{
|
||||
m_sz[sizeof(m_Callsign)] = m_Module;
|
||||
}
|
||||
// suffix
|
||||
if ( HasSuffix() )
|
||||
{
|
||||
::strcat(m_sz, " / ");
|
||||
::strncat(m_sz, m_Suffix, sizeof(m_Suffix));
|
||||
}
|
||||
|
||||
// done
|
||||
return m_sz;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// helper
|
||||
|
||||
bool CCallsign::IsNumber(char c) const
|
||||
{
|
||||
return ((c >= '0') && (c <= '9'));
|
||||
}
|
||||
|
||||
bool CCallsign::IsLetter(char c) const
|
||||
{
|
||||
return ((c >= 'A') && (c <= 'Z'));
|
||||
}
|
||||
|
||||
bool CCallsign::IsSpace(char c) const
|
||||
{
|
||||
return (c == ' ');
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
//
|
||||
// Callsign.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef ccallsign_h
|
||||
#define ccallsign_h
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
#define CALLSIGN_LEN 8
|
||||
#define CALLSUFFIX_LEN 4
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CCallsign
|
||||
{
|
||||
public:
|
||||
// contructors
|
||||
CCallsign();
|
||||
CCallsign(const char *, uint32 = 0);
|
||||
|
||||
// status
|
||||
bool IsValid(void) const;
|
||||
bool HasSuffix(void) const;
|
||||
bool HasModule(void) const { return m_Module != ' '; }
|
||||
|
||||
// set
|
||||
void SetCallsign(const char *, bool = true);
|
||||
void SetCallsign(const uint8 *, int, bool = true);
|
||||
#ifndef NO_XLX
|
||||
void SetDmrid(uint32, bool = true);
|
||||
void SetDmrid(const uint8 *, bool = true);
|
||||
#endif
|
||||
void SetModule(char);
|
||||
void SetSuffix(const char *);
|
||||
void SetSuffix(const uint8 *, int);
|
||||
|
||||
// modify
|
||||
void PatchCallsign(int, const uint8 *, int);
|
||||
|
||||
// get
|
||||
void GetCallsign(uint8 *) const;
|
||||
void GetCallsignString(char *) const;
|
||||
#ifndef NO_XLX
|
||||
uint32 GetDmrid(void) const { return m_uiDmrid; }
|
||||
#endif
|
||||
void GetSuffix(uint8 *) const;
|
||||
char GetModule(void) const { return m_Module; }
|
||||
|
||||
// compare
|
||||
bool HasSameCallsign(const CCallsign &) const;
|
||||
bool HasSameCallsignWithWildcard(const CCallsign &) const;
|
||||
bool HasLowerCallsign(const CCallsign &) const;
|
||||
bool HasSameModule(const CCallsign &) const;
|
||||
|
||||
// operators
|
||||
bool operator ==(const CCallsign &) const;
|
||||
operator const char *() const;
|
||||
|
||||
protected:
|
||||
// helper
|
||||
bool IsNumber(char) const;
|
||||
bool IsLetter(char) const;
|
||||
bool IsSpace(char) const;
|
||||
|
||||
protected:
|
||||
// data
|
||||
char m_Callsign[CALLSIGN_LEN];
|
||||
char m_Suffix[CALLSUFFIX_LEN];
|
||||
char m_Module;
|
||||
mutable char m_sz[CALLSIGN_LEN+CALLSUFFIX_LEN+5];
|
||||
#ifndef NO_XLX
|
||||
uint32 m_uiDmrid;
|
||||
#endif
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* ccallsign_h */
|
||||
@ -0,0 +1,230 @@
|
||||
//
|
||||
// ccallsignlist.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 30/12/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include "Main.h"
|
||||
#include "CallsignList.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CCallsignList::CCallsignList()
|
||||
{
|
||||
m_Filename = nullptr;
|
||||
::memset(&m_LastModTime, 0, sizeof(time_t));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// file io
|
||||
|
||||
bool CCallsignList::LoadFromFile(const char *filename)
|
||||
{
|
||||
bool ok = false;
|
||||
char sz[256];
|
||||
char szStar[2] = "*";
|
||||
|
||||
// and load
|
||||
std::ifstream file (filename);
|
||||
if ( file.is_open() )
|
||||
{
|
||||
Lock();
|
||||
|
||||
// empty list
|
||||
m_Callsigns.clear();
|
||||
// fill with file content
|
||||
while ( file.getline(sz, sizeof(sz)).good() )
|
||||
{
|
||||
// remove leading & trailing spaces
|
||||
char *szt = TrimWhiteSpaces(sz);
|
||||
|
||||
// crack it
|
||||
if ( (::strlen(szt) > 0) && (szt[0] != '#') )
|
||||
{
|
||||
// 1st token is callsign
|
||||
if ( (szt = ::strtok(szt, " ,\t")) != nullptr )
|
||||
{
|
||||
CCallsign callsign(szt);
|
||||
// 2nd token is modules list
|
||||
szt = ::strtok(nullptr, " ,\t");
|
||||
// if token absent, use wildcard
|
||||
if ( szt == nullptr )
|
||||
{
|
||||
szt = szStar;
|
||||
}
|
||||
// and add to list
|
||||
m_Callsigns.push_back(CCallsignListItem(callsign, CIp(), szt));
|
||||
}
|
||||
}
|
||||
}
|
||||
// close file
|
||||
file.close();
|
||||
|
||||
// keep file path
|
||||
m_Filename = filename;
|
||||
|
||||
// update time
|
||||
GetLastModTime(&m_LastModTime);
|
||||
|
||||
// and done
|
||||
Unlock();
|
||||
ok = true;
|
||||
std::cout << "Gatekeeper loaded " << m_Callsigns.size() << " lines from " << filename << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Gatekeeper cannot find " << filename << std::endl;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CCallsignList::ReloadFromFile(void)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if ( m_Filename != nullptr )
|
||||
{
|
||||
ok = LoadFromFile(m_Filename);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool CCallsignList::NeedReload(void)
|
||||
{
|
||||
bool needReload = false;
|
||||
|
||||
time_t time;
|
||||
if ( GetLastModTime(&time) )
|
||||
{
|
||||
needReload = time != m_LastModTime;
|
||||
}
|
||||
return needReload;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// compare
|
||||
|
||||
bool CCallsignList::IsCallsignListedWithWildcard(const CCallsign &callsign) const
|
||||
{
|
||||
for ( const auto &item : m_Callsigns )
|
||||
{
|
||||
if (item.HasSameCallsignWithWildcard(callsign))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCallsignList::IsCallsignListedWithWildcard(const CCallsign &callsign, char module) const
|
||||
{
|
||||
for ( const auto &item : m_Callsigns )
|
||||
{
|
||||
if (item.HasSameCallsignWithWildcard(callsign) && ((module == ' ') || item.HasModuleListed(module)) )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCallsignList::IsCallsignListed(const CCallsign &callsign, char module) const
|
||||
{
|
||||
for ( const auto &item : m_Callsigns )
|
||||
{
|
||||
if (item.HasSameCallsign(callsign) && item.HasModuleListed(module))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CCallsignList::IsCallsignListed(const CCallsign &callsign, char *modules) const
|
||||
{
|
||||
for ( const auto &item : m_Callsigns )
|
||||
{
|
||||
if (item.HasSameCallsign(callsign) && item.CheckListedModules(modules))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// find
|
||||
|
||||
CCallsignListItem *CCallsignList::FindListItem(const CCallsign &Callsign)
|
||||
{
|
||||
for ( auto &item : m_Callsigns )
|
||||
{
|
||||
if ( item.GetCallsign().HasSameCallsign(Callsign) )
|
||||
{
|
||||
return &item;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// helpers
|
||||
|
||||
char *CCallsignList::TrimWhiteSpaces(char *str)
|
||||
{
|
||||
char *end;
|
||||
|
||||
// Trim leading space & tabs
|
||||
while((*str == ' ') || (*str == '\t')) str++;
|
||||
|
||||
// All spaces?
|
||||
if(*str == 0)
|
||||
return str;
|
||||
|
||||
// Trim trailing space, tab or lf
|
||||
end = str + ::strlen(str) - 1;
|
||||
while((end > str) && ((*end == ' ') || (*end == '\t') || (*end == '\r'))) end--;
|
||||
|
||||
// Write new null terminator
|
||||
*(end+1) = 0;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
bool CCallsignList::GetLastModTime(time_t *time)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
if ( m_Filename != nullptr )
|
||||
{
|
||||
struct stat fileStat;
|
||||
if( ::stat(m_Filename, &fileStat) != -1 )
|
||||
{
|
||||
*time = fileStat.st_mtime;
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
//
|
||||
// CallsignList.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 30/12/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef ccallsignlist_h
|
||||
#define ccallsignlist_h
|
||||
|
||||
#include "Main.h"
|
||||
#include "CallsignListItem.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CCallsignList
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CCallsignList();
|
||||
|
||||
// destructor
|
||||
virtual ~CCallsignList() {}
|
||||
|
||||
// locks
|
||||
void Lock(void) { m_Mutex.lock(); }
|
||||
void Unlock(void) { m_Mutex.unlock(); }
|
||||
|
||||
// file io
|
||||
virtual bool LoadFromFile(const char *);
|
||||
bool ReloadFromFile(void);
|
||||
bool NeedReload(void);
|
||||
|
||||
// compare
|
||||
bool IsCallsignListedWithWildcard(const CCallsign &) const;
|
||||
bool IsCallsignListedWithWildcard(const CCallsign &, char) const;
|
||||
bool IsCallsignListed(const CCallsign &, char) const;
|
||||
bool IsCallsignListed(const CCallsign &, char*) const;
|
||||
|
||||
// pass-thru
|
||||
bool empty() const { return m_Callsigns.empty(); }
|
||||
std::list<CCallsignListItem>::iterator begin() { return m_Callsigns.begin(); }
|
||||
std::list<CCallsignListItem>::iterator end() { return m_Callsigns.end(); }
|
||||
|
||||
// find
|
||||
CCallsignListItem *FindListItem(const CCallsign &);
|
||||
|
||||
protected:
|
||||
bool GetLastModTime(time_t *);
|
||||
char *TrimWhiteSpaces(char *);
|
||||
|
||||
// data
|
||||
std::mutex m_Mutex;
|
||||
const char * m_Filename;
|
||||
time_t m_LastModTime;
|
||||
std::list<CCallsignListItem> m_Callsigns;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* ccallsignlist_h */
|
||||
@ -0,0 +1,146 @@
|
||||
//
|
||||
// ccallsignlistitem.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/01/2016.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <string.h>
|
||||
#include "Main.h"
|
||||
#include "CallsignListItem.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CCallsignListItem::CCallsignListItem()
|
||||
{
|
||||
::memset(m_Modules, 0, sizeof(m_Modules));
|
||||
::memset(m_szUrl, 0, sizeof(m_szUrl));
|
||||
}
|
||||
|
||||
CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const CIp &ip, const char *modules)
|
||||
{
|
||||
m_Callsign = callsign;
|
||||
::memset(m_szUrl, 0, sizeof(m_szUrl));
|
||||
m_Ip = ip;
|
||||
if ( modules != nullptr )
|
||||
{
|
||||
::memset(m_Modules, 0, sizeof(m_Modules));
|
||||
if ( modules[0] == '*' )
|
||||
{
|
||||
for ( char i = 0; i < NB_OF_MODULES; i++ )
|
||||
{
|
||||
m_Modules[i] = 'A' + i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int n = MIN(::strlen(modules), sizeof(m_Modules)-1);
|
||||
int j = 0;
|
||||
for ( int i = 0; i < n; i++ )
|
||||
{
|
||||
if ( (modules[i] - 'A') < NB_OF_MODULES )
|
||||
{
|
||||
m_Modules[j++] = modules[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCallsignListItem::CCallsignListItem(const CCallsign &callsign, const char *url, const char *modules)
|
||||
{
|
||||
m_Callsign = callsign;
|
||||
::strncpy(m_szUrl, url, URL_MAXLEN);
|
||||
m_Ip = CIp(m_szUrl);
|
||||
if ( modules != nullptr )
|
||||
{
|
||||
::memset(m_Modules, 0, sizeof(m_Modules));
|
||||
if ( modules[0] == '*' )
|
||||
{
|
||||
for ( char i = 0; i < NB_OF_MODULES; i++ )
|
||||
{
|
||||
m_Modules[i] = 'A' + i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int n = MIN(::strlen(modules), sizeof(m_Modules)-1);
|
||||
int j = 0;
|
||||
for ( int i = 0; i < n; i++ )
|
||||
{
|
||||
if ( (modules[i] - 'A') < NB_OF_MODULES )
|
||||
{
|
||||
m_Modules[j++] = modules[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CCallsignListItem::CCallsignListItem(const CCallsignListItem &item)
|
||||
{
|
||||
m_Callsign = item.m_Callsign;
|
||||
::memcpy(m_szUrl, item.m_szUrl, sizeof(m_szUrl));
|
||||
m_Ip = item.m_Ip;
|
||||
::memcpy(m_Modules, item.m_Modules, sizeof(m_Modules));
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// compare
|
||||
|
||||
bool CCallsignListItem::HasSameCallsign(const CCallsign &callsign) const
|
||||
{
|
||||
return m_Callsign.HasSameCallsign(callsign);
|
||||
}
|
||||
|
||||
bool CCallsignListItem::HasSameCallsignWithWildcard(const CCallsign &callsign) const
|
||||
{
|
||||
return m_Callsign.HasSameCallsignWithWildcard(callsign);
|
||||
}
|
||||
|
||||
bool CCallsignListItem::HasModuleListed(char module) const
|
||||
{
|
||||
return (::strchr(m_Modules, (int)module) != nullptr);
|
||||
}
|
||||
|
||||
bool CCallsignListItem::CheckListedModules(char *Modules) const
|
||||
{
|
||||
bool listed = false;
|
||||
|
||||
if ( Modules != nullptr )
|
||||
{
|
||||
// build a list of common modules
|
||||
char list[27];
|
||||
list[0] = 0;
|
||||
//
|
||||
for ( unsigned i = 0; i < ::strlen(Modules); i++ )
|
||||
{
|
||||
if ( HasModuleListed(Modules[i]) )
|
||||
{
|
||||
::strncat(list, &(Modules[i]), 1);
|
||||
listed = true;
|
||||
}
|
||||
}
|
||||
::strcpy(Modules, list);
|
||||
}
|
||||
return listed;
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
//
|
||||
// CallsignListItem.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/01/2016.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef ccallsignlistitem_h
|
||||
#define ccallsignlistitem_h
|
||||
|
||||
#include "Main.h"
|
||||
#include "Callsign.h"
|
||||
#include "IP.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
#define URL_MAXLEN 256
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CCallsignListItem
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CCallsignListItem();
|
||||
CCallsignListItem(const CCallsign &, const CIp &, const char *);
|
||||
CCallsignListItem(const CCallsign &, const char *, const char *);
|
||||
CCallsignListItem(const CCallsignListItem &);
|
||||
|
||||
// destructor
|
||||
virtual ~CCallsignListItem() {}
|
||||
|
||||
// compare
|
||||
bool HasSameCallsign(const CCallsign &) const;
|
||||
bool HasSameCallsignWithWildcard(const CCallsign &) const;
|
||||
bool HasModuleListed(char) const;
|
||||
bool CheckListedModules(char*) const;
|
||||
|
||||
// get
|
||||
const CCallsign &GetCallsign(void) const { return m_Callsign; }
|
||||
const CIp &GetIp(void) const { return m_Ip; }
|
||||
const char *GetModules(void) { return m_Modules; }
|
||||
|
||||
// update
|
||||
void ResolveIp(void) { m_Ip = CIp(m_szUrl); }
|
||||
|
||||
protected:
|
||||
// data
|
||||
CCallsign m_Callsign;
|
||||
char m_szUrl[URL_MAXLEN+1];
|
||||
CIp m_Ip;
|
||||
char m_Modules[27];
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif /* ccallsignlistitem_h */
|
||||
@ -0,0 +1,122 @@
|
||||
//
|
||||
// cclient.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include "Client.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructors
|
||||
|
||||
CClient::CClient()
|
||||
{
|
||||
m_ReflectorModule = ' ';
|
||||
m_ModuleMastered = ' ';
|
||||
m_LastKeepaliveTime.Now();
|
||||
m_ConnectTime = std::time(nullptr);
|
||||
m_LastHeardTime = std::time(nullptr);
|
||||
}
|
||||
|
||||
CClient::CClient(const CCallsign &callsign, const CIp &ip, char reflectorModule)
|
||||
{
|
||||
m_ReflectorModule = reflectorModule;
|
||||
m_Callsign = callsign;
|
||||
m_Ip = ip;
|
||||
m_ModuleMastered = ' ';
|
||||
m_LastKeepaliveTime.Now();
|
||||
m_ConnectTime = std::time(nullptr);
|
||||
m_LastHeardTime = std::time(nullptr);
|
||||
}
|
||||
|
||||
CClient::CClient(const CClient &client)
|
||||
{
|
||||
m_Callsign = client.m_Callsign;
|
||||
m_Ip = client.m_Ip;
|
||||
m_ReflectorModule = client.m_ReflectorModule;
|
||||
m_ModuleMastered = client.m_ModuleMastered;
|
||||
m_LastKeepaliveTime = client.m_LastKeepaliveTime;
|
||||
m_ConnectTime = client.m_ConnectTime;
|
||||
m_LastHeardTime = client.m_LastHeardTime;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// status
|
||||
|
||||
void CClient::Alive(void)
|
||||
{
|
||||
m_LastKeepaliveTime.Now();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operators
|
||||
|
||||
bool CClient::operator ==(const CClient &client) const
|
||||
{
|
||||
return ((client.m_Callsign == m_Callsign) &&
|
||||
(client.m_Ip == m_Ip) &&
|
||||
(client.m_ReflectorModule == m_ReflectorModule));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// reporting
|
||||
|
||||
void CClient::WriteXml(std::ofstream &xmlFile)
|
||||
{
|
||||
xmlFile << "<NODE>" << std::endl;
|
||||
xmlFile << "\t<Callsign>" << m_Callsign << "</Callsign>" << std::endl;
|
||||
xmlFile << "\t<IP>" << m_Ip.GetAddress() << "</IP>" << std::endl;
|
||||
xmlFile << "\t<LinkedModule>" << m_ReflectorModule << "</LinkedModule>" << std::endl;
|
||||
xmlFile << "\t<Protocol>" << GetProtocolName() << "</Protocol>" << std::endl;
|
||||
char mbstr[100];
|
||||
if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_ConnectTime)))
|
||||
{
|
||||
xmlFile << "\t<ConnectTime>" << mbstr << "</ConnectTime>" << std::endl;
|
||||
}
|
||||
if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_LastHeardTime)))
|
||||
{
|
||||
xmlFile << "\t<LastHeardTime>" << mbstr << "</LastHeardTime>" << std::endl;
|
||||
}
|
||||
xmlFile << "</NODE>" << std::endl;
|
||||
}
|
||||
|
||||
void CClient::GetJsonObject(char *Buffer)
|
||||
{
|
||||
char sz[512];
|
||||
char mbstr[100];
|
||||
char cs[16];
|
||||
|
||||
if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_LastHeardTime)))
|
||||
{
|
||||
m_Callsign.GetCallsignString(cs);
|
||||
|
||||
::sprintf(sz, "{\"callsign\":\"%s\",\"module\":\"%c\",\"linkedto\":\"%c\",\"time\":\"%s\"}",
|
||||
cs,
|
||||
m_Callsign.GetModule(),
|
||||
m_ReflectorModule,
|
||||
mbstr);
|
||||
::strcat(Buffer, sz);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
//
|
||||
// Client.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cclient_h
|
||||
#define cclient_h
|
||||
|
||||
#include "Timer.h"
|
||||
#include "IP.h"
|
||||
#include "Callsign.h"
|
||||
#include "Buffer.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CClient
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CClient();
|
||||
CClient(const CCallsign &, const CIp &, char = ' ');
|
||||
CClient(const CClient &);
|
||||
|
||||
// destructor
|
||||
virtual ~CClient() {};
|
||||
|
||||
// operators
|
||||
bool operator ==(const CClient &) const;
|
||||
|
||||
// get
|
||||
const CCallsign &GetCallsign(void) const { return m_Callsign; }
|
||||
const CIp &GetIp(void) const { return m_Ip; }
|
||||
bool HasModule(void) const { return m_Callsign.HasModule(); }
|
||||
char GetModule(void) const { return m_Callsign.GetModule(); }
|
||||
bool HasReflectorModule(void) const { return m_ReflectorModule != ' '; }
|
||||
char GetReflectorModule(void) const { return m_ReflectorModule; }
|
||||
|
||||
// set
|
||||
void SetModule(char c) { m_Callsign.SetModule(c); }
|
||||
void SetReflectorModule(char c) { m_ReflectorModule = c; }
|
||||
|
||||
// identity
|
||||
virtual int GetProtocol(void) const { return PROTOCOL_NONE; }
|
||||
virtual int GetProtocolRevision(void) const { return 0; }
|
||||
virtual int GetCodec(void) const { return CODEC_NONE; }
|
||||
virtual const char *GetProtocolName(void) const { return "none"; }
|
||||
virtual bool IsNode(void) const { return false; }
|
||||
virtual bool IsPeer(void) const { return false; }
|
||||
virtual bool IsDextraDongle(void) const { return false; }
|
||||
virtual void SetDextraDongle(void) { }
|
||||
|
||||
// status
|
||||
virtual void Alive(void);
|
||||
virtual bool IsAlive(void) const { return false; }
|
||||
virtual bool IsAMaster(void) const { return (m_ModuleMastered != ' '); }
|
||||
virtual void SetMasterOfModule(char c) { m_ModuleMastered = c; }
|
||||
virtual void NotAMaster(void) { m_ModuleMastered = ' '; }
|
||||
virtual void Heard(void) { m_LastHeardTime = std::time(nullptr); }
|
||||
|
||||
// reporting
|
||||
virtual void WriteXml(std::ofstream &);
|
||||
virtual void GetJsonObject(char *);
|
||||
|
||||
protected:
|
||||
// data
|
||||
CCallsign m_Callsign;
|
||||
CIp m_Ip;
|
||||
|
||||
// linked to
|
||||
char m_ReflectorModule;
|
||||
|
||||
// status
|
||||
char m_ModuleMastered;
|
||||
CTimePoint m_LastKeepaliveTime;
|
||||
std::time_t m_ConnectTime;
|
||||
std::time_t m_LastHeardTime;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cclient_h */
|
||||
@ -0,0 +1,247 @@
|
||||
//
|
||||
// cclients.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "Reflector.h"
|
||||
#include "Clients.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
|
||||
CClients::CClients()
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// destructors
|
||||
|
||||
CClients::~CClients()
|
||||
{
|
||||
m_Mutex.lock();
|
||||
m_Clients.clear();
|
||||
m_Mutex.unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// manage Clients
|
||||
|
||||
void CClients::AddClient(std::shared_ptr<CClient> client)
|
||||
{
|
||||
// first check if client already exists
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
if (*client == *(*it))
|
||||
// if found, just do nothing
|
||||
// so *client keep pointing on a valid object
|
||||
// on function return
|
||||
{
|
||||
// delete new one
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// and append
|
||||
m_Clients.push_back(client);
|
||||
std::cout << "New client " << client->GetCallsign() << " at " << client->GetIp() << " added with protocol " << client->GetProtocolName();
|
||||
if ( client->GetReflectorModule() != ' ' )
|
||||
{
|
||||
std::cout << " on module " << client->GetReflectorModule();
|
||||
}
|
||||
std::cout << std::endl;
|
||||
// notify
|
||||
g_Reflector.OnClientsChanged();
|
||||
}
|
||||
|
||||
void CClients::RemoveClient(std::shared_ptr<CClient> client)
|
||||
{
|
||||
// look for the client
|
||||
bool found = false;
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
// compare objetc pointers
|
||||
if ( *it == client )
|
||||
{
|
||||
// found it !
|
||||
if ( !(*it)->IsAMaster() )
|
||||
{
|
||||
// remove it
|
||||
std::cout << "Client " << (*it)->GetCallsign() << " at " << (*it)->GetIp() << " removed with protocol " << (*it)->GetProtocolName();
|
||||
if ( (*it)->GetReflectorModule() != ' ' )
|
||||
{
|
||||
std::cout << " on module " << (*it)->GetReflectorModule();
|
||||
}
|
||||
std::cout << std::endl;
|
||||
m_Clients.erase(it);
|
||||
// notify
|
||||
g_Reflector.OnClientsChanged();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CClients::IsClient(std::shared_ptr<CClient> client) const
|
||||
{
|
||||
for ( auto it=cbegin(); it!=cend(); it++ )
|
||||
{
|
||||
if (*it == client)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// find Clients
|
||||
|
||||
std::shared_ptr<CClient> CClients::FindClient(const CIp &Ip)
|
||||
{
|
||||
// find client
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
if ( (*it)->GetIp() == Ip )
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
// done
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<CClient> CClients::FindClient(const CIp &Ip, int Protocol)
|
||||
{
|
||||
// find client
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
if ( ((*it)->GetIp() == Ip) && ((*it)->GetProtocol() == Protocol))
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
// done
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<CClient> CClients::FindClient(const CIp &Ip, int Protocol, char ReflectorModule)
|
||||
{
|
||||
// find client
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
if ( ((*it)->GetIp() == Ip) && ((*it)->GetReflectorModule() == ReflectorModule) && ((*it)->GetProtocol() == Protocol) )
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
// done
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<CClient> CClients::FindClient(const CCallsign &Callsign, const CIp &Ip, int Protocol)
|
||||
{
|
||||
// find client
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
if ( (*it)->GetCallsign().HasSameCallsign(Callsign) && ((*it)->GetIp() == Ip) && ((*it)->GetProtocol() == Protocol) )
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<CClient> CClients::FindClient(const CCallsign &Callsign, char module, const CIp &Ip, int Protocol)
|
||||
{
|
||||
// find client
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
if ( (*it)->GetCallsign().HasSameCallsign(Callsign) && ((*it)->GetModule() == module) && ((*it)->GetIp() == Ip) && ((*it)->GetProtocol() == Protocol) )
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<CClient> CClients::FindClient(const CCallsign &Callsign, int Protocol)
|
||||
{
|
||||
// find client
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
if ( ((*it)->GetProtocol() == Protocol) && (*it)->GetCallsign().HasSameCallsign(Callsign) )
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// iterate on clients
|
||||
|
||||
std::shared_ptr<CClient> CClients::FindNextClient(int Protocol, std::list<std::shared_ptr<CClient>>::iterator &it)
|
||||
{
|
||||
while ( it != end() )
|
||||
{
|
||||
if ( (*it)->GetProtocol() == Protocol )
|
||||
{
|
||||
return *it++;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<CClient> CClients::FindNextClient(const CIp &Ip, int Protocol, std::list<std::shared_ptr<CClient>>::iterator &it)
|
||||
{
|
||||
while ( it != end() )
|
||||
{
|
||||
if ( ((*it)->GetProtocol() == Protocol) && ((*it)->GetIp() == Ip) )
|
||||
{
|
||||
return *it++;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<CClient> CClients::FindNextClient(const CCallsign &Callsign, const CIp &Ip, int Protocol, std::list<std::shared_ptr<CClient>>::iterator &it)
|
||||
{
|
||||
while ( it != end() )
|
||||
{
|
||||
if ( ((*it)->GetProtocol() == Protocol) && ((*it)->GetIp() == Ip) && (*it)->GetCallsign().HasSameCallsign(Callsign) )
|
||||
{
|
||||
return *it++;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
//
|
||||
// Clients.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cclients_h
|
||||
#define cclients_h
|
||||
|
||||
#include "Client.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CClients
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CClients();
|
||||
|
||||
// destructors
|
||||
virtual ~CClients();
|
||||
|
||||
// locks
|
||||
void Lock(void) { m_Mutex.lock(); }
|
||||
void Unlock(void) { m_Mutex.unlock(); }
|
||||
|
||||
// manage Clients
|
||||
int GetSize(void) const { return (int)m_Clients.size(); }
|
||||
void AddClient(std::shared_ptr<CClient>);
|
||||
void RemoveClient(std::shared_ptr<CClient>);
|
||||
bool IsClient(std::shared_ptr<CClient>) const;
|
||||
|
||||
// pass-thru
|
||||
std::list<std::shared_ptr<CClient>>::iterator begin() { return m_Clients.begin(); }
|
||||
std::list<std::shared_ptr<CClient>>::iterator end() { return m_Clients.end(); }
|
||||
std::list<std::shared_ptr<CClient>>::const_iterator cbegin() const { return m_Clients.cbegin(); }
|
||||
std::list<std::shared_ptr<CClient>>::const_iterator cend() const { return m_Clients.cend(); }
|
||||
|
||||
// find clients
|
||||
std::shared_ptr<CClient> FindClient(const CIp &);
|
||||
std::shared_ptr<CClient> FindClient(const CIp &, int);
|
||||
std::shared_ptr<CClient> FindClient(const CIp &, int, char);
|
||||
std::shared_ptr<CClient> FindClient(const CCallsign &, const CIp &, int);
|
||||
std::shared_ptr<CClient> FindClient(const CCallsign &, char, const CIp &, int);
|
||||
std::shared_ptr<CClient> FindClient(const CCallsign &, int);
|
||||
|
||||
// iterate on clients
|
||||
std::shared_ptr<CClient> FindNextClient(int, std::list<std::shared_ptr<CClient>>::iterator &);
|
||||
std::shared_ptr<CClient> FindNextClient(const CIp &, int, std::list<std::shared_ptr<CClient>>::iterator &);
|
||||
std::shared_ptr<CClient> FindNextClient(const CCallsign &, const CIp &, int, std::list<std::shared_ptr<CClient>>::iterator &);
|
||||
|
||||
protected:
|
||||
// data
|
||||
std::mutex m_Mutex;
|
||||
std::list<std::shared_ptr<CClient>> m_Clients;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cclients_h */
|
||||
@ -0,0 +1,266 @@
|
||||
//
|
||||
// ccodecstream.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 13/04/2017.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include "CodecStream.h"
|
||||
#include "DVFramePacket.h"
|
||||
#include "Reflector.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CCodecStream::CCodecStream(CPacketStream *PacketStream, uint16 uiId, uint8 uiCodecIn, uint8 uiCodecOut)
|
||||
{
|
||||
keep_running = true;
|
||||
m_uiStreamId = uiId;
|
||||
m_uiPid = 0;
|
||||
m_uiCodecIn = uiCodecIn;
|
||||
m_uiCodecOut = uiCodecOut;
|
||||
m_bConnected = false;
|
||||
m_fPingMin = -1;
|
||||
m_fPingMax = -1;
|
||||
m_fPingSum = 0;
|
||||
m_fPingCount = 0;
|
||||
m_uiTotalPackets = 0;
|
||||
m_uiTimeoutPackets = 0;
|
||||
m_PacketStream = PacketStream;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// destructor
|
||||
|
||||
CCodecStream::~CCodecStream()
|
||||
{
|
||||
// close socket
|
||||
m_Socket.Close();
|
||||
|
||||
// kill threads
|
||||
keep_running = false;
|
||||
if ( m_Future.valid() )
|
||||
{
|
||||
m_Future.get();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// initialization
|
||||
|
||||
bool CCodecStream::Init(uint16 uiPort)
|
||||
{
|
||||
m_bConnected = keep_running = false; // prepare for the worst
|
||||
|
||||
// create the send to address
|
||||
m_uiPort = uiPort;
|
||||
auto s = g_Reflector.GetTranscoderIp();
|
||||
m_Ip.Initialize(strchr(s, ':') ? AF_INET6 : AF_INET, m_uiPort, s);
|
||||
|
||||
if (0 == strncasecmp(s, "none", 4))
|
||||
{
|
||||
return false; // the user has disabled the transcoder
|
||||
}
|
||||
|
||||
// create socket address, family based on transcoder listen address
|
||||
#ifdef LISTEN_IPV4
|
||||
#ifdef LISTEN_IPV6
|
||||
const auto paddr = (AF_INET == m_Ip.GetFamily()) ? g_Reflector.m_Address.GetV4Address(PROTOCOL_ANY) : g_Reflector.m_Address.GetV6Address(PROTOCOL_ANY);
|
||||
#else
|
||||
const auto paddr = g_Reflector.m_Address.GetV4Address(PROTOCOL_ANY);
|
||||
#endif
|
||||
#else
|
||||
const auto paddr = g_Reflector.m_Address.GetV6Address(PROTOCOL_ANY);
|
||||
#endif
|
||||
CIp ip(m_Ip.GetFamily(), m_uiPort, paddr.c_str());
|
||||
|
||||
// create our socket
|
||||
if (ip.IsSet())
|
||||
{
|
||||
if (! m_Socket.Open(ip))
|
||||
{
|
||||
std::cerr << "Error opening socket on IP address " << m_Ip << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Could not initialize Codec Stream on " << paddr << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
keep_running = m_bConnected = true;
|
||||
m_Future = std::async(std::launch::async, &CCodecStream::Thread, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCodecStream::Close(void)
|
||||
{
|
||||
// close socket
|
||||
keep_running = m_bConnected = false;
|
||||
m_Socket.Close();
|
||||
|
||||
// kill threads
|
||||
if ( m_Future.valid() )
|
||||
{
|
||||
m_Future.get();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// get
|
||||
|
||||
bool CCodecStream::IsEmpty(void) const
|
||||
{
|
||||
return (m_LocalQueue.empty() && m_PacketStream->empty());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// thread
|
||||
|
||||
void CCodecStream::Thread()
|
||||
{
|
||||
while (keep_running)
|
||||
{
|
||||
Task();
|
||||
}
|
||||
}
|
||||
|
||||
void CCodecStream::Task(void)
|
||||
{
|
||||
CBuffer Buffer;
|
||||
CIp Ip;
|
||||
uint8 Ambe[AMBE_SIZE];
|
||||
uint8 DStarSync[] = { 0x55,0x2D,0x16 };
|
||||
|
||||
// any packet from transcoder
|
||||
if ( m_Socket.Receive(Buffer, Ip, 5) )
|
||||
{
|
||||
// crack
|
||||
if ( IsValidAmbePacket(Buffer, Ambe) )
|
||||
{
|
||||
// tickle
|
||||
m_TimeoutTimer.Now();
|
||||
|
||||
// update statistics
|
||||
double ping = m_StatsTimer.DurationSinceNow();
|
||||
if ( m_fPingMin == -1 )
|
||||
{
|
||||
m_fPingMin = ping;
|
||||
m_fPingMax = ping;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
m_fPingMin = MIN(m_fPingMin, ping);
|
||||
m_fPingMax = MAX(m_fPingMax, ping);
|
||||
|
||||
}
|
||||
m_fPingSum += ping;
|
||||
m_fPingCount += 1;
|
||||
|
||||
// pop the original packet
|
||||
if ( !m_LocalQueue.empty() )
|
||||
{
|
||||
auto Packet = m_LocalQueue.front();
|
||||
auto Frame = (CDvFramePacket *)Packet.get();
|
||||
m_LocalQueue.pop();
|
||||
// todo: check the PID
|
||||
// update content with transcoded ambe
|
||||
Frame->SetAmbe(m_uiCodecOut, Ambe);
|
||||
// tag syncs in DvData
|
||||
if ( (m_uiCodecOut == CODEC_AMBEPLUS) && (Frame->GetPacketId() % 21) == 0 )
|
||||
{
|
||||
Frame->SetDvData(DStarSync);
|
||||
}
|
||||
// and push it back to client
|
||||
m_PacketStream->Lock();
|
||||
m_PacketStream->push(Packet);
|
||||
m_PacketStream->Unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Unexpected transcoded packet received from ambed" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// anything in our queue
|
||||
while ( !empty() )
|
||||
{
|
||||
// yes, pop it from queue
|
||||
auto Packet = front();
|
||||
auto Frame = (CDvFramePacket *)Packet.get();
|
||||
pop();
|
||||
|
||||
// yes, send to ambed
|
||||
// this assume that thread pushing the Packet
|
||||
// have verified that the CodecStream is connected
|
||||
// and that the packet needs transcoding
|
||||
m_StatsTimer.Now();
|
||||
m_uiTotalPackets++;
|
||||
EncodeAmbePacket(&Buffer, Frame->GetAmbe(m_uiCodecIn));
|
||||
m_Socket.Send(Buffer, m_Ip, m_uiPort);
|
||||
|
||||
// and push to our local queue
|
||||
m_LocalQueue.push(Packet);
|
||||
}
|
||||
|
||||
// handle timeout
|
||||
if ( !m_LocalQueue.empty() && (m_TimeoutTimer.DurationSinceNow() >= (TRANSCODER_AMBEPACKET_TIMEOUT/1000.0f)) )
|
||||
{
|
||||
//std::cout << "ambed packet timeout" << std::endl;
|
||||
m_uiTimeoutPackets++;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// packet decoding helpers
|
||||
|
||||
bool CCodecStream::IsValidAmbePacket(const CBuffer &Buffer, uint8 *Ambe)
|
||||
{
|
||||
bool valid = false;
|
||||
|
||||
if ( (Buffer.size() == 11) && (Buffer.data()[0] == m_uiCodecOut) )
|
||||
{
|
||||
::memcpy(Ambe, &(Buffer.data()[2]), 9);
|
||||
valid = true;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// packet encoding helpers
|
||||
|
||||
void CCodecStream::EncodeAmbePacket(CBuffer *Buffer, const uint8 *Ambe)
|
||||
{
|
||||
Buffer->clear();
|
||||
Buffer->Append(m_uiCodecIn);
|
||||
Buffer->Append(m_uiPid);
|
||||
Buffer->Append((uint8 *)Ambe, 9);
|
||||
}
|
||||
@ -0,0 +1,116 @@
|
||||
//
|
||||
// CodecStream.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 13/04/2017.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef ccodecstream_h
|
||||
#define ccodecstream_h
|
||||
|
||||
#include "Semaphore.h"
|
||||
#include "UDPSocket.h"
|
||||
#include "PacketQueue.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
// frame sizes
|
||||
#define AMBE_SIZE 9
|
||||
#define AMBEPLUS_SIZE 9
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CPacketStream;
|
||||
|
||||
class CCodecStream : public CPacketQueue
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CCodecStream(CPacketStream *, uint16, uint8, uint8);
|
||||
|
||||
// destructor
|
||||
virtual ~CCodecStream();
|
||||
|
||||
// initialization
|
||||
bool Init(uint16);
|
||||
void Close(void);
|
||||
|
||||
// get
|
||||
bool IsConnected(void) const { return m_bConnected; }
|
||||
uint16 GetStreamId(void) const { return m_uiStreamId; }
|
||||
double GetPingMin(void) const { return m_fPingMin; }
|
||||
double GetPingMax(void) const { return m_fPingMax; }
|
||||
double GetPingAve(void) const { return (m_fPingCount != 0) ? m_fPingSum/m_fPingCount : 0; }
|
||||
uint32 GetTotalPackets(void) const { return m_uiTotalPackets; }
|
||||
uint32 GetTimeoutPackets(void) const { return m_uiTimeoutPackets; }
|
||||
bool IsEmpty(void) const;
|
||||
|
||||
// task
|
||||
void Thread(void);
|
||||
void Task(void);
|
||||
|
||||
|
||||
protected:
|
||||
// packet decoding helpers
|
||||
bool IsValidAmbePacket(const CBuffer &, uint8 *);
|
||||
|
||||
// packet encoding helpers
|
||||
void EncodeAmbePacket(CBuffer *, const uint8 *);
|
||||
|
||||
|
||||
protected:
|
||||
// data
|
||||
uint16 m_uiStreamId;
|
||||
uint16 m_uiPort;
|
||||
uint8 m_uiPid;
|
||||
uint8 m_uiCodecIn;
|
||||
uint8 m_uiCodecOut;
|
||||
|
||||
// socket
|
||||
CIp m_Ip;
|
||||
CUdpSocket m_Socket;
|
||||
bool m_bConnected;
|
||||
|
||||
// associated packet stream
|
||||
CPacketStream *m_PacketStream;
|
||||
CPacketQueue m_LocalQueue;
|
||||
|
||||
// thread
|
||||
std::atomic<bool> keep_running;
|
||||
std::future<void> m_Future;
|
||||
CTimePoint m_TimeoutTimer;
|
||||
CTimePoint m_StatsTimer;
|
||||
|
||||
// statistics
|
||||
double m_fPingMin;
|
||||
double m_fPingMax;
|
||||
double m_fPingSum;
|
||||
double m_fPingCount;
|
||||
uint32 m_uiTotalPackets;
|
||||
uint32 m_uiTimeoutPackets;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* ccodecstream_h */
|
||||
@ -0,0 +1,52 @@
|
||||
//
|
||||
// cdcsclient.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 07/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "DCSClient.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructors
|
||||
|
||||
CDcsClient::CDcsClient()
|
||||
{
|
||||
}
|
||||
|
||||
CDcsClient::CDcsClient(const CCallsign &callsign, const CIp &ip, char reflectorModule)
|
||||
: CClient(callsign, ip, reflectorModule)
|
||||
{
|
||||
}
|
||||
|
||||
CDcsClient::CDcsClient(const CDcsClient &client)
|
||||
: CClient(client)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// status
|
||||
|
||||
bool CDcsClient::IsAlive(void) const
|
||||
{
|
||||
return (m_LastKeepaliveTime.DurationSinceNow() < DCS_KEEPALIVE_TIMEOUT);
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
//
|
||||
// DCSClient.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 07/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdcsclient_h
|
||||
#define cdcsclient_h
|
||||
|
||||
#include "Client.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDcsClient : public CClient
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CDcsClient();
|
||||
CDcsClient(const CCallsign &, const CIp &, char = ' ');
|
||||
CDcsClient(const CDcsClient &);
|
||||
|
||||
// destructor
|
||||
virtual ~CDcsClient() {};
|
||||
|
||||
// identity
|
||||
int GetProtocol(void) const { return PROTOCOL_DCS; }
|
||||
const char *GetProtocolName(void) const { return "DCS"; }
|
||||
int GetCodec(void) const { return CODEC_AMBEPLUS; }
|
||||
bool IsNode(void) const { return true; }
|
||||
|
||||
// status
|
||||
bool IsAlive(void) const;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif /* cdcsclient_h */
|
||||
@ -0,0 +1,513 @@
|
||||
//
|
||||
// cdcsprotocol.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 07/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include "DCSClient.h"
|
||||
#include "cdcsprotocol.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operation
|
||||
|
||||
bool CDcsProtocol::Initialize(const char *type, const int ptype, const uint16 port, const bool has_ipv4, const bool has_ipv6)
|
||||
{
|
||||
// base class
|
||||
if (! CProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6))
|
||||
return false;
|
||||
|
||||
// update time
|
||||
m_LastKeepaliveTime.Now();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// task
|
||||
|
||||
void CDcsProtocol::Task(void)
|
||||
{
|
||||
CBuffer Buffer;
|
||||
CIp Ip;
|
||||
CCallsign Callsign;
|
||||
char ToLinkModule;
|
||||
std::unique_ptr<CDvHeaderPacket> Header;
|
||||
std::unique_ptr<CDvFramePacket> Frame;
|
||||
|
||||
// handle incoming packets
|
||||
#if DSTAR_IPV6==true
|
||||
#if DSTAR_IPV4==true
|
||||
if ( ReceiveDS(Buffer, Ip, 20) )
|
||||
#else
|
||||
if ( Receive6(Buffer, Ip, 20) )
|
||||
#endif
|
||||
#else
|
||||
if ( Receive4(Buffer, Ip, 20) )
|
||||
#endif
|
||||
{
|
||||
// crack the packet
|
||||
if ( IsValidDvPacket(Buffer, Header, Frame) )
|
||||
{
|
||||
// callsign muted?
|
||||
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, PROTOCOL_DCS, Header->GetRpt2Module()) )
|
||||
{
|
||||
OnDvHeaderPacketIn(Header, Ip);
|
||||
|
||||
if ( !Frame->IsLastPacket() )
|
||||
{
|
||||
//std::cout << "DCS DV frame" << std::endl;
|
||||
OnDvFramePacketIn(Frame, &Ip);
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::cout << "DCS DV last frame" << std::endl;
|
||||
OnDvLastFramePacketIn((std::unique_ptr<CDvLastFramePacket> &)Frame, &Ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( IsValidConnectPacket(Buffer, &Callsign, &ToLinkModule) )
|
||||
{
|
||||
std::cout << "DCS connect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
|
||||
|
||||
// callsign authorized?
|
||||
if ( g_GateKeeper.MayLink(Callsign, Ip, PROTOCOL_DCS) && g_Reflector.IsValidModule(ToLinkModule) )
|
||||
{
|
||||
// valid module ?
|
||||
if ( g_Reflector.IsValidModule(ToLinkModule) )
|
||||
{
|
||||
// acknowledge the request
|
||||
EncodeConnectAckPacket(Callsign, ToLinkModule, &Buffer);
|
||||
Send(Buffer, Ip);
|
||||
|
||||
// create the client and append
|
||||
g_Reflector.GetClients()->AddClient(std::make_shared<CDcsClient>(Callsign, Ip, ToLinkModule));
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "DCS node " << Callsign << " connect attempt on non-existing module" << std::endl;
|
||||
|
||||
// deny the request
|
||||
EncodeConnectNackPacket(Callsign, ToLinkModule, &Buffer);
|
||||
Send(Buffer, Ip);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// deny the request
|
||||
EncodeConnectNackPacket(Callsign, ToLinkModule, &Buffer);
|
||||
Send(Buffer, Ip);
|
||||
}
|
||||
|
||||
}
|
||||
else if ( IsValidDisconnectPacket(Buffer, &Callsign) )
|
||||
{
|
||||
std::cout << "DCS disconnect packet from " << Callsign << " at " << Ip << std::endl;
|
||||
|
||||
// find client
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
std::shared_ptr<CClient>client = clients->FindClient(Ip, PROTOCOL_DCS);
|
||||
if ( client != nullptr )
|
||||
{
|
||||
// remove it
|
||||
clients->RemoveClient(client);
|
||||
// and acknowledge the disconnect
|
||||
EncodeConnectNackPacket(Callsign, ' ', &Buffer);
|
||||
Send(Buffer, Ip);
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
else if ( IsValidKeepAlivePacket(Buffer, &Callsign) )
|
||||
{
|
||||
//std::cout << "DCS keepalive packet from " << Callsign << " at " << Ip << std::endl;
|
||||
|
||||
// find all clients with that callsign & ip and keep them alive
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(Callsign, Ip, PROTOCOL_DCS, it)) != nullptr )
|
||||
{
|
||||
client->Alive();
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
else if ( IsIgnorePacket(Buffer) )
|
||||
{
|
||||
// valid but ignore packet
|
||||
//std::cout << "DCS ignored packet from " << Ip << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
// invalid packet
|
||||
std::string title("Unknown DCS packet from ");
|
||||
title += Ip.GetAddress();
|
||||
Buffer.Dump(title);
|
||||
}
|
||||
}
|
||||
|
||||
// handle end of streaming timeout
|
||||
CheckStreamsTimeout();
|
||||
|
||||
// handle queue from reflector
|
||||
HandleQueue();
|
||||
|
||||
// keep client alive
|
||||
if ( m_LastKeepaliveTime.DurationSinceNow() > DCS_KEEPALIVE_PERIOD )
|
||||
{
|
||||
//
|
||||
HandleKeepalives();
|
||||
|
||||
// update time
|
||||
m_LastKeepaliveTime.Now();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// streams helpers
|
||||
|
||||
void CDcsProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, const CIp &Ip)
|
||||
{
|
||||
// find the stream
|
||||
CPacketStream *stream = GetStream(Header->GetStreamId());
|
||||
if ( stream )
|
||||
{
|
||||
// stream already open
|
||||
// skip packet, but tickle the stream
|
||||
stream->Tickle();
|
||||
}
|
||||
else
|
||||
{
|
||||
// no stream open yet, open a new one
|
||||
CCallsign my(Header->GetMyCallsign());
|
||||
CCallsign rpt1(Header->GetRpt1Callsign());
|
||||
CCallsign rpt2(Header->GetRpt2Callsign());
|
||||
|
||||
// find this client
|
||||
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, PROTOCOL_DCS);
|
||||
if ( client )
|
||||
{
|
||||
// get client callsign
|
||||
rpt1 = client->GetCallsign();
|
||||
// and try to open the stream
|
||||
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
|
||||
{
|
||||
// keep the handle
|
||||
m_Streams.push_back(stream);
|
||||
}
|
||||
}
|
||||
// release
|
||||
g_Reflector.ReleaseClients();
|
||||
|
||||
// update last heard
|
||||
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
|
||||
g_Reflector.ReleaseUsers();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// queue helper
|
||||
|
||||
void CDcsProtocol::HandleQueue(void)
|
||||
{
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
{
|
||||
// get the packet
|
||||
auto packet = m_Queue.front();
|
||||
m_Queue.pop();
|
||||
|
||||
// get our sender's id
|
||||
int iModId = g_Reflector.GetModuleIndex(packet->GetModuleId());
|
||||
|
||||
// check if it's header and update cache
|
||||
if ( packet->IsDvHeader() )
|
||||
{
|
||||
// this relies on queue feeder setting valid module id
|
||||
m_StreamsCache[iModId].m_dvHeader = CDvHeaderPacket((const CDvHeaderPacket &)*packet);
|
||||
m_StreamsCache[iModId].m_iSeqCounter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// encode it
|
||||
CBuffer buffer;
|
||||
if ( packet->IsLastPacket() )
|
||||
{
|
||||
EncodeDvLastPacket(
|
||||
m_StreamsCache[iModId].m_dvHeader,
|
||||
(const CDvFramePacket &)*packet,
|
||||
m_StreamsCache[iModId].m_iSeqCounter++,
|
||||
&buffer);
|
||||
}
|
||||
else if ( packet->IsDvFrame() )
|
||||
{
|
||||
EncodeDvPacket(
|
||||
m_StreamsCache[iModId].m_dvHeader,
|
||||
(const CDvFramePacket &)*packet,
|
||||
m_StreamsCache[iModId].m_iSeqCounter++,
|
||||
&buffer);
|
||||
}
|
||||
|
||||
// send it
|
||||
if ( buffer.size() > 0 )
|
||||
{
|
||||
// and push it to all our clients linked to the module and who are not streaming in
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_DCS, it)) != nullptr )
|
||||
{
|
||||
// is this client busy ?
|
||||
if ( !client->IsAMaster() && (client->GetReflectorModule() == packet->GetModuleId()) )
|
||||
{
|
||||
// no, send the packet
|
||||
Send(buffer, client->GetIp());
|
||||
|
||||
}
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// keepalive helpers
|
||||
|
||||
void CDcsProtocol::HandleKeepalives(void)
|
||||
{
|
||||
// DCS protocol sends and monitors keepalives packets
|
||||
// event if the client is currently streaming
|
||||
// so, send keepalives to all
|
||||
CBuffer keepalive1;
|
||||
EncodeKeepAlivePacket(&keepalive1);
|
||||
|
||||
// iterate on clients
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_DCS, it)) != nullptr )
|
||||
{
|
||||
// encode client's specific keepalive packet
|
||||
CBuffer keepalive2;
|
||||
EncodeKeepAlivePacket(&keepalive2, client);
|
||||
|
||||
// send keepalive
|
||||
Send(keepalive1, client->GetIp());
|
||||
Send(keepalive2, client->GetIp());
|
||||
|
||||
// is this client busy ?
|
||||
if ( client->IsAMaster() )
|
||||
{
|
||||
// yes, just tickle it
|
||||
client->Alive();
|
||||
}
|
||||
// check it's still with us
|
||||
else if ( !client->IsAlive() )
|
||||
{
|
||||
// no, disconnect
|
||||
CBuffer disconnect;
|
||||
EncodeDisconnectPacket(&disconnect, client);
|
||||
Send(disconnect, client->GetIp());
|
||||
|
||||
// remove it
|
||||
std::cout << "DCS client " << client->GetCallsign() << " keepalive timeout" << std::endl;
|
||||
clients->RemoveClient(client);
|
||||
}
|
||||
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// packet decoding helpers
|
||||
|
||||
bool CDcsProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *callsign, char *reflectormodule)
|
||||
{
|
||||
bool valid = false;
|
||||
if ( Buffer.size() == 519 )
|
||||
{
|
||||
callsign->SetCallsign(Buffer.data(), 8);
|
||||
callsign->SetModule(Buffer.data()[8]);
|
||||
*reflectormodule = Buffer.data()[9];
|
||||
valid = (callsign->IsValid() && IsLetter(*reflectormodule));
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool CDcsProtocol::IsValidDisconnectPacket(const CBuffer &Buffer, CCallsign *callsign)
|
||||
{
|
||||
bool valid = false;
|
||||
if ((Buffer.size() == 11) && (Buffer.data()[9] == ' '))
|
||||
{
|
||||
callsign->SetCallsign(Buffer.data(), 8);
|
||||
callsign->SetModule(Buffer.data()[8]);
|
||||
valid = callsign->IsValid();
|
||||
}
|
||||
else if ((Buffer.size() == 19) && (Buffer.data()[9] == ' ') && (Buffer.data()[10] == 0x00))
|
||||
{
|
||||
callsign->SetCallsign(Buffer.data(), 8);
|
||||
callsign->SetModule(Buffer.data()[8]);
|
||||
valid = callsign->IsValid();
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool CDcsProtocol::IsValidKeepAlivePacket(const CBuffer &Buffer, CCallsign *callsign)
|
||||
{
|
||||
bool valid = false;
|
||||
if ( (Buffer.size() == 17) || (Buffer.size() == 15) || (Buffer.size() == 22) )
|
||||
{
|
||||
callsign->SetCallsign(Buffer.data(), 8);
|
||||
valid = callsign->IsValid();
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool CDcsProtocol::IsValidDvPacket(const CBuffer &Buffer, std::unique_ptr<CDvHeaderPacket> &header, std::unique_ptr<CDvFramePacket> &frame)
|
||||
{
|
||||
uint8 tag[] = { '0','0','0','1' };
|
||||
|
||||
if ( (Buffer.size() >= 100) && (Buffer.Compare(tag, sizeof(tag)) == 0) )
|
||||
{
|
||||
// get the header
|
||||
header = std::unique_ptr<CDvHeaderPacket>(new CDvHeaderPacket((struct dstar_header *)&(Buffer.data()[4]), *((uint16 *)&(Buffer.data()[43])), 0x80));
|
||||
|
||||
// get the frame
|
||||
if ( Buffer.data()[45] & 0x40U )
|
||||
{
|
||||
// it's the last frame
|
||||
frame = std::unique_ptr<CDvLastFramePacket>(new CDvLastFramePacket((struct dstar_dvframe *)&(Buffer.data()[46]), *((uint16 *)&(Buffer.data()[43])), Buffer.data()[45]));
|
||||
}
|
||||
else
|
||||
{
|
||||
// it's a regular DV frame
|
||||
frame = std::unique_ptr<CDvFramePacket>(new CDvFramePacket((struct dstar_dvframe *)&(Buffer.data()[46]), *((uint16 *)&(Buffer.data()[43])), Buffer.data()[45]));
|
||||
}
|
||||
|
||||
// check validity of packets
|
||||
if ( header && header->IsValid() && frame && frame->IsValid() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDcsProtocol::IsIgnorePacket(const CBuffer &Buffer)
|
||||
{
|
||||
uint8 tag[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, };
|
||||
|
||||
if ( Buffer.size() == 15 && Buffer.Compare(tag, sizeof(tag)) == 0 )
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// packet encoding helpers
|
||||
|
||||
void CDcsProtocol::EncodeKeepAlivePacket(CBuffer *Buffer)
|
||||
{
|
||||
Buffer->Set(GetReflectorCallsign());
|
||||
}
|
||||
|
||||
void CDcsProtocol::EncodeKeepAlivePacket(CBuffer *Buffer, std::shared_ptr<CClient>Client)
|
||||
{
|
||||
uint8 tag[] = { 0x0A,0x00,0x20,0x20 };
|
||||
|
||||
Buffer->Set((uint8 *)(const char *)GetReflectorCallsign(), CALLSIGN_LEN-1);
|
||||
Buffer->Append((uint8)Client->GetReflectorModule());
|
||||
Buffer->Append((uint8)' ');
|
||||
Buffer->Append((uint8 *)(const char *)Client->GetCallsign(), CALLSIGN_LEN-1);
|
||||
Buffer->Append((uint8)Client->GetModule());
|
||||
Buffer->Append((uint8)Client->GetModule());
|
||||
Buffer->Append(tag, sizeof(tag));
|
||||
}
|
||||
|
||||
void CDcsProtocol::EncodeConnectAckPacket(const CCallsign &Callsign, char ReflectorModule, CBuffer *Buffer)
|
||||
{
|
||||
uint8 tag[] = { 'A','C','K',0x00 };
|
||||
uint8 cs[CALLSIGN_LEN];
|
||||
|
||||
Callsign.GetCallsign(cs);
|
||||
Buffer->Set(cs, CALLSIGN_LEN-1);
|
||||
Buffer->Append((uint8)' ');
|
||||
Buffer->Append((uint8)Callsign.GetModule());
|
||||
Buffer->Append((uint8)ReflectorModule);
|
||||
Buffer->Append(tag, sizeof(tag));
|
||||
}
|
||||
|
||||
void CDcsProtocol::EncodeConnectNackPacket(const CCallsign &Callsign, char ReflectorModule, CBuffer *Buffer)
|
||||
{
|
||||
uint8 tag[] = { 'N','A','K',0x00 };
|
||||
uint8 cs[CALLSIGN_LEN];
|
||||
|
||||
Callsign.GetCallsign(cs);
|
||||
Buffer->Set(cs, CALLSIGN_LEN-1);
|
||||
Buffer->Append((uint8)' ');
|
||||
Buffer->Append((uint8)Callsign.GetModule());
|
||||
Buffer->Append((uint8)ReflectorModule);
|
||||
Buffer->Append(tag, sizeof(tag));
|
||||
}
|
||||
|
||||
void CDcsProtocol::EncodeDisconnectPacket(CBuffer *Buffer, std::shared_ptr<CClient>Client)
|
||||
{
|
||||
Buffer->Set((uint8 *)(const char *)Client->GetCallsign(), CALLSIGN_LEN-1);
|
||||
Buffer->Append((uint8)' ');
|
||||
Buffer->Append((uint8)Client->GetModule());
|
||||
Buffer->Append((uint8)0x00);
|
||||
Buffer->Append((uint8 *)(const char *)GetReflectorCallsign(), CALLSIGN_LEN-1);
|
||||
Buffer->Append((uint8)' ');
|
||||
Buffer->Append((uint8)0x00);
|
||||
}
|
||||
|
||||
void CDcsProtocol::EncodeDvPacket(const CDvHeaderPacket &Header, const CDvFramePacket &DvFrame, uint32 iSeq, CBuffer *Buffer) const
|
||||
{
|
||||
uint8 tag[] = { '0','0','0','1' };
|
||||
struct dstar_header DstarHeader;
|
||||
|
||||
Header.ConvertToDstarStruct(&DstarHeader);
|
||||
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
Buffer->Append((uint8 *)&DstarHeader, sizeof(struct dstar_header) - sizeof(uint16));
|
||||
Buffer->Append(DvFrame.GetStreamId());
|
||||
Buffer->Append((uint8)(DvFrame.GetPacketId() % 21));
|
||||
Buffer->Append((uint8 *)DvFrame.GetAmbe(), AMBE_SIZE);
|
||||
Buffer->Append((uint8 *)DvFrame.GetDvData(), DVDATA_SIZE);
|
||||
Buffer->Append((uint8)((iSeq >> 0) & 0xFF));
|
||||
Buffer->Append((uint8)((iSeq >> 8) & 0xFF));
|
||||
Buffer->Append((uint8)((iSeq >> 16) & 0xFF));
|
||||
Buffer->Append((uint8)0x01);
|
||||
Buffer->Append((uint8)0x00, 38);
|
||||
}
|
||||
|
||||
void CDcsProtocol::EncodeDvLastPacket(const CDvHeaderPacket &Header, const CDvFramePacket &DvFrame, uint32 iSeq, CBuffer *Buffer) const
|
||||
{
|
||||
EncodeDvPacket(Header, DvFrame, iSeq, Buffer);
|
||||
(Buffer->data())[45] |= 0x40;
|
||||
}
|
||||
@ -0,0 +1,94 @@
|
||||
//
|
||||
// cdcsprotocol.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 07/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdcsprotocol_h
|
||||
#define cdcsprotocol_h
|
||||
|
||||
#include "Timer.h"
|
||||
#include "DCSProtocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
#include "DVFramePacket.h"
|
||||
#include "DVLastFramePacket.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDcsStreamCacheItem
|
||||
{
|
||||
public:
|
||||
CDcsStreamCacheItem() { m_iSeqCounter = 0; }
|
||||
~CDcsStreamCacheItem() {}
|
||||
|
||||
CDvHeaderPacket m_dvHeader;
|
||||
uint32 m_iSeqCounter;
|
||||
};
|
||||
|
||||
class CDcsProtocol : public CProtocol
|
||||
{
|
||||
public:
|
||||
// initialization
|
||||
bool Initialize(const char *type, const int ptype, const uint16 port, const bool has_ipv4, const bool has_ipv6);
|
||||
|
||||
// task
|
||||
void Task(void);
|
||||
|
||||
protected:
|
||||
// queue helper
|
||||
void HandleQueue(void);
|
||||
|
||||
// keepalive helpers
|
||||
void HandleKeepalives(void);
|
||||
|
||||
// stream helpers
|
||||
void OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &, const CIp &);
|
||||
|
||||
// packet decoding helpers
|
||||
bool IsValidConnectPacket(const CBuffer &, CCallsign *, char *);
|
||||
bool IsValidDisconnectPacket(const CBuffer &, CCallsign *);
|
||||
bool IsValidKeepAlivePacket(const CBuffer &, CCallsign *);
|
||||
bool IsValidDvPacket(const CBuffer &, std::unique_ptr<CDvHeaderPacket> &, std::unique_ptr<CDvFramePacket> &);
|
||||
bool IsIgnorePacket(const CBuffer &);
|
||||
|
||||
// packet encoding helpers
|
||||
void EncodeKeepAlivePacket(CBuffer *);
|
||||
void EncodeKeepAlivePacket(CBuffer *, std::shared_ptr<CClient>);
|
||||
void EncodeConnectAckPacket(const CCallsign &, char, CBuffer *);
|
||||
void EncodeConnectNackPacket(const CCallsign &, char, CBuffer *);
|
||||
void EncodeDisconnectPacket(CBuffer *, std::shared_ptr<CClient>);
|
||||
void EncodeDvPacket(const CDvHeaderPacket &, const CDvFramePacket &, uint32, CBuffer *) const;
|
||||
void EncodeDvLastPacket(const CDvHeaderPacket &, const CDvFramePacket &, uint32, CBuffer *) const;
|
||||
|
||||
protected:
|
||||
// for keep alive
|
||||
CTimePoint m_LastKeepaliveTime;
|
||||
|
||||
// for queue header caches
|
||||
std::array<CDcsStreamCacheItem, NB_OF_MODULES> m_StreamsCache;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cdcsprotocol_h */
|
||||
@ -0,0 +1,55 @@
|
||||
//
|
||||
// cdextraclient.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "DExtraClient.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructors
|
||||
|
||||
CDextraClient::CDextraClient()
|
||||
{
|
||||
m_ProtRev = 0;
|
||||
}
|
||||
|
||||
CDextraClient::CDextraClient(const CCallsign &callsign, const CIp &ip, char reflectorModule, int protRev)
|
||||
: CClient(callsign, ip, reflectorModule)
|
||||
{
|
||||
m_ProtRev = protRev;
|
||||
}
|
||||
|
||||
CDextraClient::CDextraClient(const CDextraClient &client)
|
||||
: CClient(client)
|
||||
{
|
||||
m_ProtRev = client.m_ProtRev;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// status
|
||||
|
||||
bool CDextraClient::IsAlive(void) const
|
||||
{
|
||||
return (m_LastKeepaliveTime.DurationSinceNow() < DEXTRA_KEEPALIVE_TIMEOUT);
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
//
|
||||
// DExtraClient.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdextraclient_h
|
||||
#define cdextraclient_h
|
||||
|
||||
#include "Client.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDextraClient : public CClient
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CDextraClient();
|
||||
CDextraClient(const CCallsign &, const CIp &, char = ' ', int = 0);
|
||||
CDextraClient(const CDextraClient &);
|
||||
|
||||
// destructor
|
||||
virtual ~CDextraClient() {};
|
||||
|
||||
// identity
|
||||
int GetProtocol(void) const { return PROTOCOL_DEXTRA; }
|
||||
int GetProtocolRevision(void) const { return m_ProtRev; }
|
||||
const char *GetProtocolName(void) const { return "DExtra"; }
|
||||
int GetCodec(void) const { return CODEC_AMBEPLUS; }
|
||||
bool IsNode(void) const { return true; }
|
||||
|
||||
// status
|
||||
bool IsAlive(void) const;
|
||||
|
||||
protected:
|
||||
// data
|
||||
int m_ProtRev;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cdextraclient_h */
|
||||
@ -0,0 +1,73 @@
|
||||
//
|
||||
// cdextrapeer.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Antony Chazapis (SV9OAN) on 25/2/2018.
|
||||
// Copyright © 2016 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include "Reflector.h"
|
||||
#include "DExtraPeer.h"
|
||||
#include "DExtraClient.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
|
||||
CDextraPeer::CDextraPeer()
|
||||
{
|
||||
}
|
||||
|
||||
CDextraPeer::CDextraPeer(const CCallsign &callsign, const CIp &ip, const char *modules, const CVersion &version)
|
||||
: CPeer(callsign, ip, modules, version)
|
||||
{
|
||||
std::cout << "Adding DExtra peer" << std::endl;
|
||||
|
||||
// and construct the DExtra clients
|
||||
for ( unsigned i = 0; i < ::strlen(modules); i++ )
|
||||
{
|
||||
// create and append to vector
|
||||
m_Clients.push_back(std::make_shared<CDextraClient>(callsign, ip, modules[i], version.GetMajor()));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// status
|
||||
|
||||
bool CDextraPeer::IsAlive(void) const
|
||||
{
|
||||
for ( auto it=cbegin(); it!=cend(); it++ )
|
||||
{
|
||||
if (! (*it)->IsAlive())
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// revision helper
|
||||
|
||||
int CDextraPeer::GetProtocolRevision(const CVersion &version)
|
||||
{
|
||||
return version.GetMajor();
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
//
|
||||
// DExtraPeer.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Antony Chazapis (SV9OAN) on 25/2/2018.
|
||||
// Copyright © 2016 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdextrapeer_h
|
||||
#define cdextrapeer_h
|
||||
|
||||
#include "Peer.h"
|
||||
#include "DExtraClient.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDextraPeer : public CPeer
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CDextraPeer();
|
||||
CDextraPeer(const CCallsign &, const CIp &, const char *, const CVersion &);
|
||||
CDextraPeer(const CDextraPeer &) = delete;
|
||||
|
||||
// status
|
||||
bool IsAlive(void) const;
|
||||
|
||||
// identity
|
||||
int GetProtocol(void) const { return PROTOCOL_DEXTRA; }
|
||||
const char *GetProtocolName(void) const { return "DExtra"; }
|
||||
|
||||
// revision helper
|
||||
static int GetProtocolRevision(const CVersion &);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cdextrapeer_h */
|
||||
@ -0,0 +1,641 @@
|
||||
//
|
||||
// cdextraprotocol.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 01/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include "DExtraPeer.h"
|
||||
#include "DExtraClient.h"
|
||||
#include "DExtraProtocol.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operation
|
||||
|
||||
bool CDextraProtocol::Initialize(const char *type, int ptype, const uint16 port, const bool has_ipv4, const bool has_ipv6)
|
||||
{
|
||||
// base class
|
||||
if (! CProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6))
|
||||
return false;
|
||||
|
||||
// update time
|
||||
m_LastKeepaliveTime.Now();
|
||||
m_LastPeersLinkTime.Now();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// task
|
||||
|
||||
void CDextraProtocol::Task(void)
|
||||
{
|
||||
CBuffer Buffer;
|
||||
CIp Ip;
|
||||
CCallsign Callsign;
|
||||
char ToLinkModule;
|
||||
int ProtRev;
|
||||
std::unique_ptr<CDvHeaderPacket> Header;
|
||||
std::unique_ptr<CDvFramePacket> Frame;
|
||||
std::unique_ptr<CDvLastFramePacket> LastFrame;
|
||||
|
||||
// any incoming packet ?
|
||||
#if DSTAR_IPV6==true
|
||||
#if DSTAR_IPV4==true
|
||||
if ( ReceiveDS(Buffer, Ip, 20) )
|
||||
#else
|
||||
if ( Receive6(Buffer, Ip, 20) )
|
||||
#endif
|
||||
#else
|
||||
if ( Receive4(Buffer, Ip, 20) )
|
||||
#endif
|
||||
{
|
||||
// crack the packet
|
||||
if ( IsValidDvFramePacket(Buffer, Frame) )
|
||||
{
|
||||
OnDvFramePacketIn(Frame, &Ip);
|
||||
}
|
||||
else if ( IsValidDvHeaderPacket(Buffer, Header) )
|
||||
{
|
||||
// callsign muted?
|
||||
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, PROTOCOL_DEXTRA, Header->GetRpt2Module()) )
|
||||
{
|
||||
OnDvHeaderPacketIn(Header, Ip);
|
||||
}
|
||||
}
|
||||
else if ( IsValidDvLastFramePacket(Buffer, LastFrame) )
|
||||
{
|
||||
OnDvLastFramePacketIn(LastFrame, &Ip);
|
||||
}
|
||||
else if ( IsValidConnectPacket(Buffer, &Callsign, &ToLinkModule, &ProtRev) )
|
||||
{
|
||||
std::cout << "DExtra connect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << " rev " << ProtRev << std::endl;
|
||||
|
||||
// callsign authorized?
|
||||
if ( g_GateKeeper.MayLink(Callsign, Ip, PROTOCOL_DEXTRA) )
|
||||
{
|
||||
// valid module ?
|
||||
if ( g_Reflector.IsValidModule(ToLinkModule) )
|
||||
{
|
||||
// is this an ack for a link request?
|
||||
CPeerCallsignList *list = g_GateKeeper.GetPeerList();
|
||||
CCallsignListItem *item = list->FindListItem(Callsign);
|
||||
if ( item != nullptr && Callsign.GetModule() == item->GetModules()[1] && ToLinkModule == item->GetModules()[0] )
|
||||
{
|
||||
std::cout << "DExtra ack packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
|
||||
|
||||
// already connected ?
|
||||
CPeers *peers = g_Reflector.GetPeers();
|
||||
if ( peers->FindPeer(Callsign, Ip, PROTOCOL_DEXTRA) == nullptr )
|
||||
{
|
||||
// create the new peer
|
||||
// this also create one client per module
|
||||
// append the peer to reflector peer list
|
||||
// this also add all new clients to reflector client list
|
||||
peers->AddPeer(std::make_shared<CDextraPeer>(Callsign, Ip, std::string(1, ToLinkModule).c_str(), CVersion(2, 0, 0)));
|
||||
}
|
||||
g_Reflector.ReleasePeers();
|
||||
}
|
||||
else
|
||||
{
|
||||
// acknowledge the request
|
||||
EncodeConnectAckPacket(&Buffer, ProtRev);
|
||||
Send(Buffer, Ip);
|
||||
|
||||
// create the client and append
|
||||
g_Reflector.GetClients()->AddClient(std::make_shared<CDextraClient>(Callsign, Ip, ToLinkModule, ProtRev));
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
g_GateKeeper.ReleasePeerList();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "DExtra node " << Callsign << " connect attempt on non-existing module" << std::endl;
|
||||
|
||||
// deny the request
|
||||
EncodeConnectNackPacket(&Buffer);
|
||||
Send(Buffer, Ip);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// deny the request
|
||||
EncodeConnectNackPacket(&Buffer);
|
||||
Send(Buffer, Ip);
|
||||
}
|
||||
}
|
||||
else if ( IsValidDisconnectPacket(Buffer, &Callsign) )
|
||||
{
|
||||
std::cout << "DExtra disconnect packet from " << Callsign << " at " << Ip << std::endl;
|
||||
|
||||
// find client & remove it
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
std::shared_ptr<CClient>client = clients->FindClient(Ip, PROTOCOL_DEXTRA);
|
||||
if ( client != nullptr )
|
||||
{
|
||||
// ack disconnect packet
|
||||
if ( client->GetProtocolRevision() == 1 )
|
||||
{
|
||||
EncodeDisconnectedPacket(&Buffer);
|
||||
Send(Buffer, Ip);
|
||||
}
|
||||
else if ( client->GetProtocolRevision() == 2 )
|
||||
{
|
||||
Send(Buffer, Ip);
|
||||
}
|
||||
// and remove it
|
||||
clients->RemoveClient(client);
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
else if ( IsValidKeepAlivePacket(Buffer, &Callsign) )
|
||||
{
|
||||
//std::cout << "DExtra keepalive packet from " << Callsign << " at " << Ip << std::endl;
|
||||
|
||||
// find all clients with that callsign & ip and keep them alive
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(Callsign, Ip, PROTOCOL_DEXTRA, it)) != nullptr )
|
||||
{
|
||||
client->Alive();
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string title("Unknown DExtra packet from ");
|
||||
title += Ip.GetAddress();
|
||||
Buffer.Dump(title);
|
||||
}
|
||||
}
|
||||
|
||||
// handle end of streaming timeout
|
||||
CheckStreamsTimeout();
|
||||
|
||||
// handle queue from reflector
|
||||
HandleQueue();
|
||||
|
||||
// keep alive
|
||||
if ( m_LastKeepaliveTime.DurationSinceNow() > DEXTRA_KEEPALIVE_PERIOD )
|
||||
{
|
||||
// handle keep alives
|
||||
HandleKeepalives();
|
||||
|
||||
// update time
|
||||
m_LastKeepaliveTime.Now();
|
||||
}
|
||||
|
||||
// peer connections
|
||||
if ( m_LastPeersLinkTime.DurationSinceNow() > DEXTRA_RECONNECT_PERIOD )
|
||||
{
|
||||
// handle remote peers connections
|
||||
HandlePeerLinks();
|
||||
|
||||
// update time
|
||||
m_LastPeersLinkTime.Now();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// queue helper
|
||||
|
||||
void CDextraProtocol::HandleQueue(void)
|
||||
{
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
{
|
||||
// get the packet
|
||||
auto packet = m_Queue.front();
|
||||
m_Queue.pop();
|
||||
|
||||
// encode it
|
||||
CBuffer buffer;
|
||||
if ( EncodeDvPacket(*packet, &buffer) )
|
||||
{
|
||||
// and push it to all our clients linked to the module and who are not streaming in
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_DEXTRA, it)) != nullptr )
|
||||
{
|
||||
// is this client busy ?
|
||||
if ( !client->IsAMaster() && (client->GetReflectorModule() == packet->GetModuleId()) )
|
||||
{
|
||||
// no, send the packet
|
||||
int n = packet->IsDvHeader() ? 5 : 1;
|
||||
for ( int i = 0; i < n; i++ )
|
||||
{
|
||||
Send(buffer, client->GetIp());
|
||||
}
|
||||
}
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// keepalive helpers
|
||||
|
||||
void CDextraProtocol::HandleKeepalives(void)
|
||||
{
|
||||
// DExtra protocol sends and monitors keepalives packets
|
||||
// event if the client is currently streaming
|
||||
// so, send keepalives to all
|
||||
CBuffer keepalive;
|
||||
EncodeKeepAlivePacket(&keepalive);
|
||||
|
||||
// iterate on clients
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_DEXTRA, it)) != nullptr )
|
||||
{
|
||||
// send keepalive
|
||||
Send(keepalive, client->GetIp());
|
||||
|
||||
// client busy ?
|
||||
if ( client->IsAMaster() )
|
||||
{
|
||||
// yes, just tickle it
|
||||
client->Alive();
|
||||
}
|
||||
// otherwise check if still with us
|
||||
else if ( !client->IsAlive() )
|
||||
{
|
||||
CPeers *peers = g_Reflector.GetPeers();
|
||||
std::shared_ptr<CPeer>peer = peers->FindPeer(client->GetCallsign(), client->GetIp(), PROTOCOL_DEXTRA);
|
||||
if ( peer != nullptr && peer->GetReflectorModules()[0] == client->GetReflectorModule() )
|
||||
{
|
||||
// no, but this is a peer client, so it will be handled below
|
||||
}
|
||||
else
|
||||
{
|
||||
// no, disconnect
|
||||
CBuffer disconnect;
|
||||
EncodeDisconnectPacket(&disconnect, client->GetReflectorModule());
|
||||
Send(disconnect, client->GetIp());
|
||||
|
||||
// remove it
|
||||
std::cout << "DExtra client " << client->GetCallsign() << " keepalive timeout" << std::endl;
|
||||
clients->RemoveClient(client);
|
||||
}
|
||||
g_Reflector.ReleasePeers();
|
||||
}
|
||||
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
|
||||
// iterate on peers
|
||||
CPeers *peers = g_Reflector.GetPeers();
|
||||
auto pit = peers->begin();
|
||||
std::shared_ptr<CPeer>peer = nullptr;
|
||||
while ( (peer = peers->FindNextPeer(PROTOCOL_DEXTRA, pit)) != nullptr )
|
||||
{
|
||||
// keepalives are sent between clients
|
||||
|
||||
// some client busy or still with us ?
|
||||
if ( !peer->IsAMaster() && !peer->IsAlive() )
|
||||
{
|
||||
// no, disconnect all clients
|
||||
CBuffer disconnect;
|
||||
EncodeDisconnectPacket(&disconnect, peer->GetReflectorModules()[0]);
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
for ( auto cit=peer->cbegin(); cit!=peer->cend(); cit++ )
|
||||
{
|
||||
Send(disconnect, (*cit)->GetIp());
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
|
||||
// remove it
|
||||
std::cout << "DExtra peer " << peer->GetCallsign() << " keepalive timeout" << std::endl;
|
||||
peers->RemovePeer(peer);
|
||||
}
|
||||
}
|
||||
g_Reflector.ReleasePeers();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Peers helpers
|
||||
|
||||
void CDextraProtocol::HandlePeerLinks(void)
|
||||
{
|
||||
CBuffer buffer;
|
||||
|
||||
// get the list of peers
|
||||
CPeerCallsignList *list = g_GateKeeper.GetPeerList();
|
||||
CPeers *peers = g_Reflector.GetPeers();
|
||||
|
||||
// check if all our connected peers are still listed by gatekeeper
|
||||
// if not, disconnect
|
||||
auto pit = peers->begin();
|
||||
std::shared_ptr<CPeer>peer = nullptr;
|
||||
while ( (peer = peers->FindNextPeer(PROTOCOL_DEXTRA, pit)) != nullptr )
|
||||
{
|
||||
if ( list->FindListItem(peer->GetCallsign()) == nullptr )
|
||||
{
|
||||
// send disconnect packet
|
||||
EncodeDisconnectPacket(&buffer, peer->GetReflectorModules()[0]);
|
||||
Send(buffer, peer->GetIp());
|
||||
std::cout << "Sending disconnect packet to XRF peer " << peer->GetCallsign() << " at " << peer->GetIp() << std::endl;
|
||||
// remove client
|
||||
peers->RemovePeer(peer);
|
||||
}
|
||||
}
|
||||
|
||||
// check if all ours peers listed by gatekeeper are connected
|
||||
// if not, connect or reconnect
|
||||
for ( auto it=list->begin(); it!=list->end(); it++ )
|
||||
{
|
||||
if ( !(*it).GetCallsign().HasSameCallsignWithWildcard(CCallsign("XRF*")) )
|
||||
continue;
|
||||
if ( strlen((*it).GetModules()) != 2 )
|
||||
continue;
|
||||
if ( peers->FindPeer((*it).GetCallsign(), PROTOCOL_DEXTRA) == nullptr )
|
||||
{
|
||||
// resolve again peer's IP in case it's a dynamic IP
|
||||
(*it).ResolveIp();
|
||||
// send connect packet to re-initiate peer link
|
||||
EncodeConnectPacket(&buffer, (*it).GetModules());
|
||||
Send(buffer, (*it).GetIp(), DEXTRA_PORT);
|
||||
std::cout << "Sending connect packet to XRF peer " << (*it).GetCallsign() << " @ " << (*it).GetIp() << " for module " << (*it).GetModules()[1] << " (module " << (*it).GetModules()[0] << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// done
|
||||
g_Reflector.ReleasePeers();
|
||||
g_GateKeeper.ReleasePeerList();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// streams helpers
|
||||
|
||||
void CDextraProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, const CIp &Ip)
|
||||
{
|
||||
// find the stream
|
||||
CPacketStream *stream = GetStream(Header->GetStreamId());
|
||||
if ( stream )
|
||||
{
|
||||
// stream already open
|
||||
// skip packet, but tickle the stream
|
||||
stream->Tickle();
|
||||
}
|
||||
else
|
||||
{
|
||||
// no stream open yet, open a new one
|
||||
CCallsign my(Header->GetMyCallsign());
|
||||
CCallsign rpt1(Header->GetRpt1Callsign());
|
||||
CCallsign rpt2(Header->GetRpt2Callsign());
|
||||
|
||||
// find this client
|
||||
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, PROTOCOL_DEXTRA);
|
||||
if ( client )
|
||||
{
|
||||
// get client callsign
|
||||
rpt1 = client->GetCallsign();
|
||||
// apply protocol revision details
|
||||
if ( client->GetProtocolRevision() == 2 )
|
||||
{
|
||||
// update Header RPT2 module letter with
|
||||
// the module the client is linked to
|
||||
auto m = client->GetReflectorModule();
|
||||
Header->SetRpt2Module(m);
|
||||
rpt2.SetModule(m);
|
||||
}
|
||||
// and try to open the stream
|
||||
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
|
||||
{
|
||||
// keep the handle
|
||||
m_Streams.push_back(stream);
|
||||
}
|
||||
}
|
||||
// release
|
||||
g_Reflector.ReleaseClients();
|
||||
|
||||
// update last heard
|
||||
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
|
||||
g_Reflector.ReleaseUsers();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// packet decoding helpers
|
||||
|
||||
bool CDextraProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *callsign, char *reflectormodule, int *revision)
|
||||
{
|
||||
bool valid = false;
|
||||
if ((Buffer.size() == 11) && (Buffer.data()[9] != ' '))
|
||||
{
|
||||
callsign->SetCallsign(Buffer.data(), 8);
|
||||
callsign->SetModule(Buffer.data()[8]);
|
||||
*reflectormodule = Buffer.data()[9];
|
||||
*revision = (Buffer.data()[10] == 11) ? 1 : 0;
|
||||
valid = (callsign->IsValid() && IsLetter(*reflectormodule));
|
||||
// detect revision
|
||||
if ( (Buffer.data()[10] == 11) )
|
||||
{
|
||||
*revision = 1;
|
||||
}
|
||||
else if ( callsign->HasSameCallsignWithWildcard(CCallsign("XRF*")) )
|
||||
{
|
||||
*revision = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*revision = 0;
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool CDextraProtocol::IsValidDisconnectPacket(const CBuffer &Buffer, CCallsign *callsign)
|
||||
{
|
||||
bool valid = false;
|
||||
if ((Buffer.size() == 11) && (Buffer.data()[9] == ' '))
|
||||
{
|
||||
callsign->SetCallsign(Buffer.data(), 8);
|
||||
callsign->SetModule(Buffer.data()[8]);
|
||||
valid = callsign->IsValid();
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool CDextraProtocol::IsValidKeepAlivePacket(const CBuffer &Buffer, CCallsign *callsign)
|
||||
{
|
||||
bool valid = false;
|
||||
if (Buffer.size() == 9)
|
||||
{
|
||||
callsign->SetCallsign(Buffer.data(), 8);
|
||||
valid = callsign->IsValid();
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool CDextraProtocol::IsValidDvHeaderPacket(const CBuffer &Buffer, std::unique_ptr<CDvHeaderPacket> &header)
|
||||
{
|
||||
if ( 56==Buffer.size() && 0==Buffer.Compare((uint8 *)"DSVT", 4) && 0x10U==Buffer.data()[4] && 0x20U==Buffer.data()[8] )
|
||||
{
|
||||
// create packet
|
||||
header = std::unique_ptr<CDvHeaderPacket>(new CDvHeaderPacket((struct dstar_header *)&(Buffer.data()[15]), *((uint16 *)&(Buffer.data()[12])), 0x80));
|
||||
// check validity of packet
|
||||
if ( header && header->IsValid() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDextraProtocol::IsValidDvFramePacket(const CBuffer &Buffer, std::unique_ptr<CDvFramePacket> &dvframe)
|
||||
{
|
||||
if ( 27==Buffer.size() && 0==Buffer.Compare((uint8 *)"DSVT", 4) && 0x20U==Buffer.data()[4] && 0x20U==Buffer.data()[8] && 0U==(Buffer.data()[14] & 0x40U) )
|
||||
{
|
||||
// create packet
|
||||
dvframe = std::unique_ptr<CDvFramePacket>(new CDvFramePacket((struct dstar_dvframe *)&(Buffer.data()[15]), *((uint16 *)&(Buffer.data()[12])), Buffer.data()[14]));
|
||||
// check validity of packet
|
||||
if ( dvframe && dvframe->IsValid() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDextraProtocol::IsValidDvLastFramePacket(const CBuffer &Buffer, std::unique_ptr<CDvLastFramePacket> &dvframe)
|
||||
{
|
||||
if ( 27==Buffer.size() && 0==Buffer.Compare((uint8 *)"DSVT", 4) && 0x20U==Buffer.data()[4] && 0x20U==Buffer.data()[8] && (Buffer.data()[14] & 0x40) )
|
||||
{
|
||||
// create packet
|
||||
dvframe = std::unique_ptr<CDvLastFramePacket>(new CDvLastFramePacket((struct dstar_dvframe *)&(Buffer.data()[15]), *((uint16 *)&(Buffer.data()[12])), Buffer.data()[14]));
|
||||
// check validity of packet
|
||||
if ( dvframe && dvframe->IsValid() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// packet encoding helpers
|
||||
|
||||
void CDextraProtocol::EncodeKeepAlivePacket(CBuffer *Buffer)
|
||||
{
|
||||
Buffer->Set(GetReflectorCallsign());
|
||||
}
|
||||
|
||||
void CDextraProtocol::EncodeConnectPacket(CBuffer *Buffer, const char *Modules)
|
||||
{
|
||||
uint8 lm = (uint8)Modules[0];
|
||||
uint8 rm = (uint8)Modules[1];
|
||||
Buffer->Set((uint8 *)(const char *)GetReflectorCallsign(), CALLSIGN_LEN);
|
||||
Buffer->Append(lm);
|
||||
Buffer->Append(rm);
|
||||
Buffer->Append((uint8)0);
|
||||
}
|
||||
|
||||
void CDextraProtocol::EncodeConnectAckPacket(CBuffer *Buffer, int ProtRev)
|
||||
{
|
||||
// is it for a XRF or repeater
|
||||
if ( ProtRev == 2 )
|
||||
{
|
||||
// XRFxxx
|
||||
uint8 rm = (Buffer->data())[8];
|
||||
uint8 lm = (Buffer->data())[9];
|
||||
Buffer->clear();
|
||||
Buffer->Set((uint8 *)(const char *)GetReflectorCallsign(), CALLSIGN_LEN);
|
||||
Buffer->Append(lm);
|
||||
Buffer->Append(rm);
|
||||
Buffer->Append((uint8)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// regular repeater
|
||||
uint8 tag[] = { 'A','C','K',0 };
|
||||
Buffer->resize(Buffer->size()-1);
|
||||
Buffer->Append(tag, sizeof(tag));
|
||||
}
|
||||
}
|
||||
|
||||
void CDextraProtocol::EncodeConnectNackPacket(CBuffer *Buffer)
|
||||
{
|
||||
uint8 tag[] = { 'N','A','K',0 };
|
||||
Buffer->resize(Buffer->size()-1);
|
||||
Buffer->Append(tag, sizeof(tag));
|
||||
}
|
||||
|
||||
void CDextraProtocol::EncodeDisconnectPacket(CBuffer *Buffer, char Module)
|
||||
{
|
||||
uint8 tag[] = { ' ',0 };
|
||||
Buffer->Set((uint8 *)(const char *)GetReflectorCallsign(), CALLSIGN_LEN);
|
||||
Buffer->Append((uint8)Module);
|
||||
Buffer->Append(tag, sizeof(tag));
|
||||
}
|
||||
|
||||
void CDextraProtocol::EncodeDisconnectedPacket(CBuffer *Buffer)
|
||||
{
|
||||
uint8 tag[] = { 'D','I','S','C','O','N','N','E','C','T','E','D' };
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
}
|
||||
|
||||
bool CDextraProtocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Packet, CBuffer *Buffer) const
|
||||
{
|
||||
uint8 tag[] = { 'D','S','V','T',0x10,0x00,0x00,0x00,0x20,0x00,0x01,0x02 };
|
||||
struct dstar_header DstarHeader;
|
||||
|
||||
Packet.ConvertToDstarStruct(&DstarHeader);
|
||||
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
Buffer->Append(Packet.GetStreamId());
|
||||
Buffer->Append((uint8)0x80);
|
||||
Buffer->Append((uint8 *)&DstarHeader, sizeof(struct dstar_header));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDextraProtocol::EncodeDvFramePacket(const CDvFramePacket &Packet, CBuffer *Buffer) const
|
||||
{
|
||||
uint8 tag[] = { 'D','S','V','T',0x20,0x00,0x00,0x00,0x20,0x00,0x01,0x02 };
|
||||
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
Buffer->Append(Packet.GetStreamId());
|
||||
Buffer->Append((uint8)(Packet.GetPacketId() % 21));
|
||||
Buffer->Append((uint8 *)Packet.GetAmbe(), AMBE_SIZE);
|
||||
Buffer->Append((uint8 *)Packet.GetDvData(), DVDATA_SIZE);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool CDextraProtocol::EncodeDvLastFramePacket(const CDvLastFramePacket &Packet, CBuffer *Buffer) const
|
||||
{
|
||||
uint8 tag1[] = { 'D','S','V','T',0x20,0x00,0x00,0x00,0x20,0x00,0x01,0x02 };
|
||||
uint8 tag2[] = { 0x55,0xC8,0x7A,0x00,0x00,0x00,0x00,0x00,0x00,0x25,0x1A,0xC6 };
|
||||
|
||||
Buffer->Set(tag1, sizeof(tag1));
|
||||
Buffer->Append(Packet.GetStreamId());
|
||||
Buffer->Append((uint8)((Packet.GetPacketId() % 21) | 0x40));
|
||||
Buffer->Append(tag2, sizeof(tag2));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -0,0 +1,104 @@
|
||||
//
|
||||
// DExtraProtocol.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 01/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdextraprotocol_h
|
||||
#define cdextraprotocol_h
|
||||
|
||||
#include "Timer.h"
|
||||
#include "DCSProtocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
#include "DVFramePacket.h"
|
||||
#include "DVLastFramePacket.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// note on protocol revisions:
|
||||
//
|
||||
// rev 0:
|
||||
// this is standard protocol implementation
|
||||
//
|
||||
// rev 1:
|
||||
// this is specific UP4DAR umplementation
|
||||
// the protocol is detected using byte(10) of connect packet (value is 11)
|
||||
// the protocol require a specific non-standard disconnect acqknowleding packet
|
||||
//
|
||||
// rev 2:
|
||||
// this is specific to KI4KLF dxrfd reflector
|
||||
// the protocol is detected by looking at "XRF" in connect packet callsign
|
||||
// the protocol require a specific connect ack packet
|
||||
// the protocol also implement a workaround for detecting stream's module
|
||||
// as dxrfd soes not set DV header RPT2 properly.
|
||||
// the protocol assumes that a dxrfd can only be linked to one module at a time
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDextraProtocol : public CProtocol
|
||||
{
|
||||
public:
|
||||
// initialization
|
||||
bool Initialize(const char *type, const int ptype, const uint16 port, const bool has_ipv4, const bool has_ipv6);
|
||||
|
||||
// task
|
||||
void Task(void);
|
||||
|
||||
protected:
|
||||
// queue helper
|
||||
void HandleQueue(void);
|
||||
|
||||
// keepalive helpers
|
||||
void HandlePeerLinks(void);
|
||||
void HandleKeepalives(void);
|
||||
|
||||
// stream helpers
|
||||
void OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &, const CIp &);
|
||||
|
||||
// packet decoding helpers
|
||||
bool IsValidConnectPacket( const CBuffer &, CCallsign *, char *, int *);
|
||||
bool IsValidDisconnectPacket( const CBuffer &, CCallsign *);
|
||||
bool IsValidKeepAlivePacket( const CBuffer &, CCallsign *);
|
||||
bool IsValidDvHeaderPacket( const CBuffer &, std::unique_ptr<CDvHeaderPacket> &);
|
||||
bool IsValidDvFramePacket( const CBuffer &, std::unique_ptr<CDvFramePacket> &);
|
||||
bool IsValidDvLastFramePacket(const CBuffer &, std::unique_ptr<CDvLastFramePacket> &);
|
||||
|
||||
// packet encoding helpers
|
||||
void EncodeKeepAlivePacket(CBuffer *);
|
||||
void EncodeConnectPacket(CBuffer *, const char *);
|
||||
void EncodeConnectAckPacket(CBuffer *, int);
|
||||
void EncodeConnectNackPacket(CBuffer *);
|
||||
void EncodeDisconnectPacket(CBuffer *, char);
|
||||
void EncodeDisconnectedPacket(CBuffer *);
|
||||
bool EncodeDvHeaderPacket(const CDvHeaderPacket &, CBuffer *) const;
|
||||
bool EncodeDvFramePacket(const CDvFramePacket &, CBuffer *) const;
|
||||
bool EncodeDvLastFramePacket(const CDvLastFramePacket &, CBuffer *) const;
|
||||
|
||||
protected:
|
||||
// time
|
||||
CTimePoint m_LastKeepaliveTime;
|
||||
CTimePoint m_LastPeersLinkTime;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cdextraprotocol_h */
|
||||
@ -0,0 +1,151 @@
|
||||
//
|
||||
// cdmriddir.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 08/10/2016.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <string.h>
|
||||
#include "Main.h"
|
||||
#include "Reflector.h"
|
||||
#include "DMRIdDir.h"
|
||||
#include "cdmriddirfile.h"
|
||||
#include "DMRIdDirHttp.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor & destructor
|
||||
|
||||
CDmridDir::CDmridDir()
|
||||
{
|
||||
keep_running = true;
|
||||
}
|
||||
|
||||
CDmridDir::~CDmridDir()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// init & close
|
||||
|
||||
bool CDmridDir::Init(void)
|
||||
{
|
||||
// load content
|
||||
Reload();
|
||||
|
||||
// reset run flag
|
||||
keep_running = true;
|
||||
|
||||
// start thread;
|
||||
m_Future = std::async(std::launch::async, &CDmridDir::Thread, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDmridDir::Close(void)
|
||||
{
|
||||
keep_running = false;
|
||||
if ( m_Future.valid() )
|
||||
{
|
||||
m_Future.get();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// thread
|
||||
|
||||
void CDmridDir::Thread()
|
||||
{
|
||||
while (keep_running)
|
||||
{
|
||||
// Wait DMRIDDB_REFRESH_RATE minutes
|
||||
for (int i=0; i<30*DMRIDDB_REFRESH_RATE && keep_running; i++)
|
||||
CTimePoint::TaskSleepFor(2000);
|
||||
|
||||
// have lists files changed ?
|
||||
if ( NeedReload() )
|
||||
{
|
||||
Reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Reload
|
||||
|
||||
bool CDmridDir::Reload(void)
|
||||
{
|
||||
CBuffer buffer;
|
||||
bool ok = false;
|
||||
|
||||
if ( LoadContent(&buffer) )
|
||||
{
|
||||
Lock();
|
||||
{
|
||||
ok = RefreshContent(buffer);
|
||||
}
|
||||
Unlock();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// find
|
||||
|
||||
const CCallsign *CDmridDir::FindCallsign(uint32 dmrid)
|
||||
{
|
||||
auto found = m_CallsignMap.find(dmrid);
|
||||
if ( found != m_CallsignMap.end() )
|
||||
{
|
||||
return &(found->second);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32 CDmridDir::FindDmrid(const CCallsign &callsign)
|
||||
{
|
||||
auto found = m_DmridMap.find(callsign);
|
||||
if ( found != m_DmridMap.end() )
|
||||
{
|
||||
return (found->second);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// syntax helpers
|
||||
|
||||
bool CDmridDir::IsValidDmrid(const char *sz)
|
||||
{
|
||||
bool ok = false;
|
||||
size_t n = ::strlen(sz);
|
||||
if ( (n > 0) && (n <= 8) )
|
||||
{
|
||||
ok = true;
|
||||
for ( size_t i = 0; (i < n) && ok; i++ )
|
||||
{
|
||||
ok &= ::isdigit(sz[i]);
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
//
|
||||
// DMRIdDir.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 08/10/2016.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdmriddir_h
|
||||
#define cdmriddir_h
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include "Buffer.h"
|
||||
#include "Callsign.h"
|
||||
|
||||
// compare function for std::map::find
|
||||
|
||||
struct CDmridDirCallsignCompare
|
||||
{
|
||||
bool operator() (const CCallsign &cs1, const CCallsign &cs2) const
|
||||
{ return cs1.HasLowerCallsign(cs2);}
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CDmridDir
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CDmridDir();
|
||||
|
||||
// destructor
|
||||
~CDmridDir();
|
||||
|
||||
// init & close
|
||||
virtual bool Init(void);
|
||||
virtual void Close(void);
|
||||
|
||||
// locks
|
||||
void Lock(void) { m_Mutex.lock(); }
|
||||
void Unlock(void) { m_Mutex.unlock(); }
|
||||
|
||||
// refresh
|
||||
virtual bool LoadContent(CBuffer *) { return false; }
|
||||
virtual bool RefreshContent(const CBuffer &) { return false; }
|
||||
|
||||
// find
|
||||
const CCallsign *FindCallsign(uint32);
|
||||
uint32 FindDmrid(const CCallsign &);
|
||||
|
||||
protected:
|
||||
// thread
|
||||
void Thread();
|
||||
|
||||
// reload helpers
|
||||
bool Reload(void);
|
||||
virtual bool NeedReload(void) { return false; }
|
||||
bool IsValidDmrid(const char *);
|
||||
|
||||
protected:
|
||||
// data
|
||||
std::map <uint32, CCallsign> m_CallsignMap;
|
||||
std::map <CCallsign, uint32, CDmridDirCallsignCompare> m_DmridMap;
|
||||
|
||||
// Lock()
|
||||
std::mutex m_Mutex;
|
||||
|
||||
// thread
|
||||
std::atomic<bool> keep_running;
|
||||
std::future<void> m_Future;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cdmriddir_h */
|
||||
@ -0,0 +1,182 @@
|
||||
//
|
||||
// cdmriddirhttp.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 29/12/2017.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <string.h>
|
||||
#include "Main.h"
|
||||
#include "Reflector.h"
|
||||
#include "DMRIdDirHttp.h"
|
||||
|
||||
#if (DMRIDDB_USE_RLX_SERVER == 1)
|
||||
CDmridDirHttp g_DmridDir;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// refresh
|
||||
|
||||
bool CDmridDirHttp::LoadContent(CBuffer *buffer)
|
||||
{
|
||||
// get file from xlxapi server
|
||||
return HttpGet("xlxapi.rlx.lu", "api/exportdmr.php", 80, buffer);
|
||||
}
|
||||
|
||||
bool CDmridDirHttp::RefreshContent(const CBuffer &buffer)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
// clear directory
|
||||
m_CallsignMap.clear();
|
||||
m_DmridMap.clear();
|
||||
|
||||
// scan file
|
||||
if ( buffer.size() > 0 )
|
||||
{
|
||||
char *ptr1 = (char *)buffer.data();
|
||||
char *ptr2;
|
||||
// get next line
|
||||
while ( (ptr2 = ::strchr(ptr1, '\n')) != nullptr )
|
||||
{
|
||||
*ptr2 = 0;
|
||||
// get items
|
||||
char *dmrid;
|
||||
char *callsign;
|
||||
if ( ((dmrid = ::strtok(ptr1, ";")) != nullptr) && IsValidDmrid(dmrid) )
|
||||
{
|
||||
if ( ((callsign = ::strtok(nullptr, ";")) != nullptr) )
|
||||
{
|
||||
// new entry
|
||||
uint32 ui = atoi(dmrid);
|
||||
CCallsign cs(callsign, ui);
|
||||
if ( cs.IsValid() )
|
||||
{
|
||||
m_CallsignMap.insert(std::pair<uint32,CCallsign>(ui, cs));
|
||||
m_DmridMap.insert(std::pair<CCallsign,uint32>(cs,ui));
|
||||
}
|
||||
}
|
||||
}
|
||||
// next line
|
||||
ptr1 = ptr2+1;
|
||||
}
|
||||
// done
|
||||
ok = true;
|
||||
}
|
||||
|
||||
// report
|
||||
std::cout << "Read " << m_DmridMap.size() << " DMR ids from xlxapi.rlx.lu database " << std::endl;
|
||||
|
||||
// done
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// httpd helpers
|
||||
|
||||
#define DMRID_HTTPGET_SIZEMAX (256)
|
||||
|
||||
bool CDmridDirHttp::HttpGet(const char *hostname, const char *filename, int port, CBuffer *buffer)
|
||||
{
|
||||
bool ok = false;
|
||||
int sock_id;
|
||||
|
||||
// open socket
|
||||
if ( (sock_id = ::socket(AF_INET, SOCK_STREAM, 0)) >= 0 )
|
||||
{
|
||||
// get hostname address
|
||||
struct sockaddr_in servaddr;
|
||||
struct hostent *hp;
|
||||
::memset(&servaddr,0,sizeof(servaddr));
|
||||
if( (hp = gethostbyname(hostname)) != nullptr )
|
||||
{
|
||||
// dns resolved
|
||||
::memcpy((char *)&servaddr.sin_addr.s_addr, (char *)hp->h_addr, hp->h_length);
|
||||
servaddr.sin_port = htons(port);
|
||||
servaddr.sin_family = AF_INET;
|
||||
|
||||
// connect
|
||||
if ( ::connect(sock_id, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0)
|
||||
{
|
||||
// send the GET request
|
||||
char request[DMRID_HTTPGET_SIZEMAX];
|
||||
::sprintf(request, "GET /%s HTTP/1.0\r\nFrom: %s\r\nUser-Agent: xlxd\r\n\r\n",
|
||||
filename, (const char *)g_Reflector.GetCallsign());
|
||||
::write(sock_id, request, strlen(request));
|
||||
|
||||
// config receive timeouts
|
||||
fd_set read_set;
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 5;
|
||||
timeout.tv_usec = 0;
|
||||
FD_ZERO(&read_set);
|
||||
FD_SET(sock_id, &read_set);
|
||||
|
||||
// get the reply back
|
||||
buffer->clear();
|
||||
bool done = false;
|
||||
do
|
||||
{
|
||||
char buf[1440];
|
||||
ssize_t len = 0;
|
||||
select(sock_id+1, &read_set, nullptr, nullptr, &timeout);
|
||||
//if ( (ret > 0) || ((ret < 0) && (errno == EINPROGRESS)) )
|
||||
//if ( ret >= 0 )
|
||||
//{
|
||||
usleep(5000);
|
||||
len = read(sock_id, buf, 1440);
|
||||
if ( len > 0 )
|
||||
{
|
||||
buffer->Append((uint8 *)buf, (int)len);
|
||||
ok = true;
|
||||
}
|
||||
//}
|
||||
done = (len <= 0);
|
||||
|
||||
}
|
||||
while (!done);
|
||||
buffer->Append((uint8)0);
|
||||
|
||||
// and disconnect
|
||||
close(sock_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Cannot establish connection with host " << hostname << std::endl;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Host " << hostname << " not found" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Failed to open wget socket" << std::endl;
|
||||
}
|
||||
|
||||
// done
|
||||
return ok;
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
//
|
||||
// DMRIdDirHttp.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 29/12/2017.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdmriddirhttp_h
|
||||
#define cdmriddirhttp_h
|
||||
|
||||
#include "DMRIdDir.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class CDmridDirHttp : public CDmridDir
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CDmridDirHttp() {}
|
||||
|
||||
// destructor
|
||||
~CDmridDirHttp() {}
|
||||
|
||||
// refresh
|
||||
bool LoadContent(CBuffer *);
|
||||
bool RefreshContent(const CBuffer &);
|
||||
|
||||
protected:
|
||||
// reload helpers
|
||||
bool NeedReload(void) { return true; }
|
||||
bool HttpGet(const char *, const char *, int, CBuffer *);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cdmriddirhttp_h */
|
||||
@ -0,0 +1,52 @@
|
||||
//
|
||||
// cdmrmmdvmclient.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 04/03/2017.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "DMMMDVMClient.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructors
|
||||
|
||||
CDmrmmdvmClient::CDmrmmdvmClient()
|
||||
{
|
||||
}
|
||||
|
||||
CDmrmmdvmClient::CDmrmmdvmClient(const CCallsign &callsign, const CIp &ip, char reflectorModule)
|
||||
: CClient(callsign, ip, reflectorModule)
|
||||
{
|
||||
}
|
||||
|
||||
CDmrmmdvmClient::CDmrmmdvmClient(const CDmrmmdvmClient &client)
|
||||
: CClient(client)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// status
|
||||
|
||||
bool CDmrmmdvmClient::IsAlive(void) const
|
||||
{
|
||||
return (m_LastKeepaliveTime.DurationSinceNow() < DMRMMDVM_KEEPALIVE_TIMEOUT);
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
//
|
||||
// DMMMDVMClient.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 04/03/2017.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdmrmmdvmclient_h
|
||||
#define cdmrmmdvmclient_h
|
||||
|
||||
#include "Client.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDmrmmdvmClient : public CClient
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CDmrmmdvmClient();
|
||||
CDmrmmdvmClient(const CCallsign &, const CIp &, char = ' ');
|
||||
CDmrmmdvmClient(const CDmrmmdvmClient &);
|
||||
|
||||
// destructor
|
||||
virtual ~CDmrmmdvmClient() {};
|
||||
|
||||
// identity
|
||||
int GetProtocol(void) const { return PROTOCOL_DMRMMDVM; }
|
||||
const char *GetProtocolName(void) const { return "DMRMmdvm"; }
|
||||
int GetCodec(void) const { return CODEC_AMBE2PLUS; }
|
||||
bool IsNode(void) const { return true; }
|
||||
|
||||
// status
|
||||
bool IsAlive(void) const;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif /* cdmrmmdvmclient_h */
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,136 @@
|
||||
//
|
||||
// DMMMDVMProtocol.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 04/03/2017.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdmrmmdvmprotocol_h
|
||||
#define cdmrmmdvmprotocol_h
|
||||
|
||||
#include "Timer.h"
|
||||
#include "DCSProtocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
#include "DVFramePacket.h"
|
||||
#include "DVLastFramePacket.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
// frame type
|
||||
#define DMRMMDVM_FRAMETYPE_VOICE 0
|
||||
#define DMRMMDVM_FRAMETYPE_VOICESYNC 1
|
||||
#define DMRMMDVM_FRAMETYPE_DATASYNC 2
|
||||
|
||||
// slot type
|
||||
#define MMDVM_SLOTTYPE_HEADER 1
|
||||
#define MMDVM_SLOTTYPE_TERMINATOR 2
|
||||
|
||||
// DMRMMDVM Module ID
|
||||
#define MMDVM_MODULE_ID 'B'
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDmrmmdvmStreamCacheItem
|
||||
{
|
||||
public:
|
||||
CDmrmmdvmStreamCacheItem() {}
|
||||
~CDmrmmdvmStreamCacheItem() {}
|
||||
|
||||
CDvHeaderPacket m_dvHeader;
|
||||
CDvFramePacket m_dvFrame0;
|
||||
CDvFramePacket m_dvFrame1;
|
||||
|
||||
uint8 m_uiSeqId;
|
||||
};
|
||||
|
||||
|
||||
class CDmrmmdvmProtocol : public CProtocol
|
||||
{
|
||||
public:
|
||||
// initialization
|
||||
bool Initialize(const char *type, const int ptype, const uint16 port, const bool has_ipv4, const bool has_ipv6);
|
||||
|
||||
// task
|
||||
void Task(void);
|
||||
|
||||
protected:
|
||||
// queue helper
|
||||
void HandleQueue(void);
|
||||
|
||||
// keepalive helpers
|
||||
void HandleKeepalives(void);
|
||||
|
||||
// stream helpers
|
||||
void OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &, const CIp &, uint8, uint8);
|
||||
|
||||
// packet decoding helpers
|
||||
bool IsValidConnectPacket(const CBuffer &, CCallsign *, const CIp &);
|
||||
bool IsValidAuthenticationPacket(const CBuffer &, CCallsign *, const CIp &);
|
||||
bool IsValidDisconnectPacket(const CBuffer &, CCallsign *);
|
||||
bool IsValidConfigPacket(const CBuffer &, CCallsign *, const CIp &);
|
||||
bool IsValidOptionPacket(const CBuffer &, CCallsign *);
|
||||
bool IsValidKeepAlivePacket(const CBuffer &, CCallsign *);
|
||||
bool IsValidRssiPacket(const CBuffer &, CCallsign *, int *);
|
||||
bool IsValidDvHeaderPacket(const CBuffer &, std::unique_ptr<CDvHeaderPacket> &, uint8 *, uint8 *);
|
||||
bool IsValidDvFramePacket(const CBuffer &, std::array<std::unique_ptr<CDvFramePacket>, 3> &);
|
||||
bool IsValidDvLastFramePacket(const CBuffer &, std::unique_ptr<CDvLastFramePacket> &);
|
||||
|
||||
// packet encoding helpers
|
||||
void EncodeKeepAlivePacket(CBuffer *, std::shared_ptr<CClient>);
|
||||
void EncodeAckPacket(CBuffer *, const CCallsign &);
|
||||
void EncodeConnectAckPacket(CBuffer *, const CCallsign &, uint32);
|
||||
void EncodeNackPacket(CBuffer *, const CCallsign &);
|
||||
void EncodeClosePacket(CBuffer *, std::shared_ptr<CClient>);
|
||||
bool EncodeDvHeaderPacket(const CDvHeaderPacket &, uint8, CBuffer *) const;
|
||||
void EncodeDvPacket(const CDvHeaderPacket &, const CDvFramePacket &, const CDvFramePacket &, const CDvFramePacket &, uint8, CBuffer *) const;
|
||||
void EncodeDvLastPacket(const CDvHeaderPacket &, uint8, CBuffer *) const;
|
||||
|
||||
// dmr DstId to Module helper
|
||||
char DmrDstIdToModule(uint32) const;
|
||||
uint32 ModuleToDmrDestId(char) const;
|
||||
|
||||
// Buffer & LC helpers
|
||||
void AppendVoiceLCToBuffer(CBuffer *, uint32) const;
|
||||
void AppendTerminatorLCToBuffer(CBuffer *, uint32) const;
|
||||
void ReplaceEMBInBuffer(CBuffer *, uint8) const;
|
||||
void AppendDmrIdToBuffer(CBuffer *, uint32) const;
|
||||
void AppendDmrRptrIdToBuffer(CBuffer *, uint32) const;
|
||||
|
||||
|
||||
protected:
|
||||
// for keep alive
|
||||
CTimePoint m_LastKeepaliveTime;
|
||||
|
||||
// for stream id
|
||||
uint16 m_uiStreamId;
|
||||
|
||||
// for queue header caches
|
||||
std::array<CDmrmmdvmStreamCacheItem, NB_OF_MODULES> m_StreamsCache;
|
||||
|
||||
// for authentication
|
||||
uint32 m_uiAuthSeed;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif /* cdmrmmdvmprotocol_h */
|
||||
@ -0,0 +1,52 @@
|
||||
//
|
||||
// cdmrplusclient.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL on 10/01/2016.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "cdmrplusclient.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructors
|
||||
|
||||
CDmrplusClient::CDmrplusClient()
|
||||
{
|
||||
}
|
||||
|
||||
CDmrplusClient::CDmrplusClient(const CCallsign &callsign, const CIp &ip, char reflectorModule)
|
||||
: CClient(callsign, ip, reflectorModule)
|
||||
{
|
||||
}
|
||||
|
||||
CDmrplusClient::CDmrplusClient(const CDmrplusClient &client)
|
||||
: CClient(client)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// status
|
||||
|
||||
bool CDmrplusClient::IsAlive(void) const
|
||||
{
|
||||
return (m_LastKeepaliveTime.DurationSinceNow() < DMRPLUS_KEEPALIVE_TIMEOUT);
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
//
|
||||
// cdmrplusclient.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 10/01/2016.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdmrplusclient_h
|
||||
#define cdmrplusclient_h
|
||||
|
||||
#include "Client.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDmrplusClient : public CClient
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CDmrplusClient();
|
||||
CDmrplusClient(const CCallsign &, const CIp &, char = ' ');
|
||||
CDmrplusClient(const CDmrplusClient &);
|
||||
|
||||
// destructor
|
||||
virtual ~CDmrplusClient() {};
|
||||
|
||||
// identity
|
||||
int GetProtocol(void) const { return PROTOCOL_DMRPLUS; }
|
||||
const char *GetProtocolName(void) const { return "DMRplus"; }
|
||||
int GetCodec(void) const { return CODEC_AMBE2PLUS; }
|
||||
bool IsNode(void) const { return true; }
|
||||
|
||||
// status
|
||||
bool IsAlive(void) const;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cdmrplusclient_h */
|
||||
@ -0,0 +1,788 @@
|
||||
//
|
||||
// cdmrplusprotocol.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 10/01/2016.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include "cdmrplusclient.h"
|
||||
#include "DMRPlusProtocol.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
#include "DMRIdDir.h"
|
||||
#include "CBPT19696.h"
|
||||
#include "RS129.h"
|
||||
#include "Golay2087.h"
|
||||
#include "QR1676.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constants
|
||||
|
||||
static uint8 g_DmrSyncBSVoice[] = { 0x07,0x55,0xFD,0x7D,0xF7,0x5F,0x70 };
|
||||
static uint8 g_DmrSyncBSData[] = { 0x0D,0xFF,0x57,0xD7,0x5D,0xF5,0xD0 };
|
||||
static uint8 g_DmrSyncMSVoice[] = { 0x07,0xF7,0xD5,0xDD,0x57,0xDF,0xD0 };
|
||||
static uint8 g_DmrSyncMSData[] = { 0x0D,0x5D,0x7F,0x77,0xFD,0x75,0x70 };
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operation
|
||||
|
||||
bool CDmrplusProtocol::Initialize(const char *type, const int ptype, const uint16 port, const bool has_ipv4, const bool has_ipv6)
|
||||
{
|
||||
// base class
|
||||
if (! CProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6))
|
||||
return false;
|
||||
|
||||
// update time
|
||||
m_LastKeepaliveTime.Now();
|
||||
|
||||
// random number generator
|
||||
time_t t;
|
||||
::srand((unsigned) time(&t));
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// task
|
||||
|
||||
void CDmrplusProtocol::Task(void)
|
||||
{
|
||||
CBuffer Buffer;
|
||||
CIp Ip;
|
||||
CCallsign Callsign;
|
||||
char ToLinkModule;
|
||||
std::unique_ptr<CDvHeaderPacket> Header;
|
||||
std::array<std::unique_ptr<CDvFramePacket>, 3> Frames;
|
||||
|
||||
// handle incoming packets
|
||||
#if DMR_IPV6==true
|
||||
#if DMR_IPV4==true
|
||||
if ( ReceiveDS(Buffer, Ip, 20) )
|
||||
#else
|
||||
if ( Receive6(Buffer, Ip, 20) )
|
||||
#endif
|
||||
#else
|
||||
if ( Receive4(Buffer, Ip, 20) )
|
||||
#endif
|
||||
{
|
||||
// crack the packet
|
||||
if ( IsValidDvFramePacket(Ip, Buffer, Frames) )
|
||||
{
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
OnDvFramePacketIn(Frames[i], &Ip);
|
||||
}
|
||||
}
|
||||
else if ( IsValidDvHeaderPacket(Ip, Buffer, Header) )
|
||||
{
|
||||
// callsign muted?
|
||||
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, PROTOCOL_DMRPLUS) )
|
||||
{
|
||||
// handle it
|
||||
OnDvHeaderPacketIn(Header, Ip);
|
||||
}
|
||||
}
|
||||
else if ( IsValidConnectPacket(Buffer, &Callsign, &ToLinkModule, Ip) )
|
||||
{
|
||||
//std::cout << "DMRplus keepalive/connect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
|
||||
|
||||
// callsign authorized?
|
||||
if ( g_GateKeeper.MayLink(Callsign, Ip, PROTOCOL_DMRPLUS) )
|
||||
{
|
||||
// acknowledge the request
|
||||
EncodeConnectAckPacket(&Buffer);
|
||||
Send(Buffer, Ip);
|
||||
|
||||
// add client if needed
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
std::shared_ptr<CClient>client = clients->FindClient(Callsign, Ip, PROTOCOL_DMRPLUS);
|
||||
// client already connected ?
|
||||
if ( client == nullptr )
|
||||
{
|
||||
std::cout << "DMRplus connect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
|
||||
|
||||
// create the client and append
|
||||
clients->AddClient(std::make_shared<CDmrplusClient>(Callsign, Ip, ToLinkModule));
|
||||
}
|
||||
else
|
||||
{
|
||||
client->Alive();
|
||||
}
|
||||
// and done
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
else
|
||||
{
|
||||
// deny the request
|
||||
EncodeConnectNackPacket(&Buffer);
|
||||
Send(Buffer, Ip);
|
||||
}
|
||||
|
||||
}
|
||||
else if ( IsValidDisconnectPacket(Buffer, &Callsign, &ToLinkModule) )
|
||||
{
|
||||
std::cout << "DMRplus disconnect packet for module " << ToLinkModule << " from " << Callsign << " at " << Ip << std::endl;
|
||||
|
||||
// find client & remove it
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
std::shared_ptr<CClient>client = clients->FindClient(Ip, PROTOCOL_DMRPLUS);
|
||||
if ( client != nullptr )
|
||||
{
|
||||
clients->RemoveClient(client);
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string title("Unknown DMR+ packet from ");
|
||||
title += Ip.GetAddress();
|
||||
Buffer.Dump(title);
|
||||
}
|
||||
}
|
||||
|
||||
// handle end of streaming timeout
|
||||
CheckStreamsTimeout();
|
||||
|
||||
// handle queue from reflector
|
||||
HandleQueue();
|
||||
|
||||
|
||||
// keep client alive
|
||||
if ( m_LastKeepaliveTime.DurationSinceNow() > DMRPLUS_KEEPALIVE_PERIOD )
|
||||
{
|
||||
//
|
||||
HandleKeepalives();
|
||||
|
||||
// update time
|
||||
m_LastKeepaliveTime.Now();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// streams helpers
|
||||
|
||||
void CDmrplusProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, const CIp &Ip)
|
||||
{
|
||||
// find the stream
|
||||
CPacketStream *stream = GetStream(Header->GetStreamId());
|
||||
if ( stream )
|
||||
{
|
||||
// stream already open
|
||||
// skip packet, but tickle the stream
|
||||
stream->Tickle();
|
||||
}
|
||||
else
|
||||
{
|
||||
CCallsign my(Header->GetMyCallsign());
|
||||
CCallsign rpt1(Header->GetRpt1Callsign());
|
||||
CCallsign rpt2(Header->GetRpt2Callsign());
|
||||
|
||||
// no stream open yet, open a new one
|
||||
// find this client
|
||||
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, PROTOCOL_DMRPLUS);
|
||||
if ( client )
|
||||
{
|
||||
// and try to open the stream
|
||||
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
|
||||
{
|
||||
// keep the handle
|
||||
m_Streams.push_back(stream);
|
||||
}
|
||||
}
|
||||
// release
|
||||
g_Reflector.ReleaseClients();
|
||||
// update last heard
|
||||
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
|
||||
g_Reflector.ReleaseUsers();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// queue helper
|
||||
|
||||
void CDmrplusProtocol::HandleQueue(void)
|
||||
{
|
||||
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
{
|
||||
// get the packet
|
||||
auto packet = m_Queue.front();
|
||||
m_Queue.pop();
|
||||
|
||||
// get our sender's id
|
||||
int iModId = g_Reflector.GetModuleIndex(packet->GetModuleId());
|
||||
|
||||
// encode
|
||||
CBuffer buffer;
|
||||
|
||||
// check if it's header
|
||||
if ( packet->IsDvHeader() )
|
||||
{
|
||||
// update local stream cache
|
||||
// this relies on queue feeder setting valid module id
|
||||
m_StreamsCache[iModId].m_dvHeader = CDvHeaderPacket((const CDvHeaderPacket &)*packet);
|
||||
m_StreamsCache[iModId].m_uiSeqId = 4;
|
||||
|
||||
// encode it
|
||||
EncodeDvHeaderPacket((const CDvHeaderPacket &)*packet, &buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
// update local stream cache or send triplet when needed
|
||||
switch ( packet->GetDmrPacketSubid() )
|
||||
{
|
||||
case 1:
|
||||
m_StreamsCache[iModId].m_dvFrame0 = CDvFramePacket((const CDvFramePacket &)*packet);
|
||||
break;
|
||||
case 2:
|
||||
m_StreamsCache[iModId].m_dvFrame1 = CDvFramePacket((const CDvFramePacket &)*packet);
|
||||
break;
|
||||
case 3:
|
||||
EncodeDvPacket(
|
||||
m_StreamsCache[iModId].m_dvHeader,
|
||||
m_StreamsCache[iModId].m_dvFrame0,
|
||||
m_StreamsCache[iModId].m_dvFrame1,
|
||||
(const CDvFramePacket &)*packet,
|
||||
m_StreamsCache[iModId].m_uiSeqId,
|
||||
&buffer);
|
||||
m_StreamsCache[iModId].m_uiSeqId = GetNextSeqId(m_StreamsCache[iModId].m_uiSeqId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// send it
|
||||
if ( buffer.size() > 0 )
|
||||
{
|
||||
// and push it to all our clients linked to the module and who are not streaming in
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_DMRPLUS, it)) != nullptr )
|
||||
{
|
||||
// is this client busy ?
|
||||
if ( !client->IsAMaster() && (client->GetReflectorModule() == packet->GetModuleId()) )
|
||||
{
|
||||
// no, send the packet
|
||||
Send(buffer, client->GetIp());
|
||||
}
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
|
||||
// debug
|
||||
//buffer.DebugDump(g_Reflector.m_DebugFile);
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
void CDmrplusProtocol::SendBufferToClients(const CBuffer &buffer, uint8 module)
|
||||
{
|
||||
if ( buffer.size() > 0 )
|
||||
{
|
||||
// and push it to all our clients linked to the module and who are not streaming in
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_DMRPLUS, it)) != nullptr )
|
||||
{
|
||||
// is this client busy ?
|
||||
if ( !client->IsAMaster() && (client->GetReflectorModule() == module) )
|
||||
{
|
||||
// no, send the packet
|
||||
Send(buffer, client->GetIp());
|
||||
}
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
|
||||
// debug
|
||||
//buffer.DebugDump(g_Reflector.m_DebugFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// keepalive helpers
|
||||
|
||||
void CDmrplusProtocol::HandleKeepalives(void)
|
||||
{
|
||||
// DMRplus protocol keepalive request is client tasks
|
||||
// here, just check that all clients are still alive
|
||||
// and disconnect them if not
|
||||
|
||||
// iterate on clients
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_DMRPLUS, it)) != nullptr )
|
||||
{
|
||||
// is this client busy ?
|
||||
if ( client->IsAMaster() )
|
||||
{
|
||||
// yes, just tickle it
|
||||
client->Alive();
|
||||
}
|
||||
// check it's still with us
|
||||
else if ( !client->IsAlive() )
|
||||
{
|
||||
// no, disconnect
|
||||
//CBuffer disconnect;
|
||||
//EncodeDisconnectPacket(&disconnect, client);
|
||||
//Send(disconnect, client->GetIp());
|
||||
|
||||
// remove it
|
||||
std::cout << "DMRplus client " << client->GetCallsign() << " keepalive timeout" << std::endl;
|
||||
clients->RemoveClient(client);
|
||||
}
|
||||
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// packet decoding helpers
|
||||
|
||||
bool CDmrplusProtocol::IsValidConnectPacket(const CBuffer &Buffer, CCallsign *callsign, char *reflectormodule, const CIp &Ip)
|
||||
{
|
||||
bool valid = false;
|
||||
if ( Buffer.size() == 31 )
|
||||
{
|
||||
char sz[9];
|
||||
::memcpy(sz, Buffer.data(), 8);
|
||||
sz[8] = 0;
|
||||
uint32 dmrid = atoi(sz);
|
||||
callsign->SetDmrid(dmrid, true);
|
||||
callsign->SetModule(DMRPLUS_MODULE_ID);
|
||||
::memcpy(sz, &Buffer.data()[8], 4);
|
||||
sz[4] = 0;
|
||||
*reflectormodule = DmrDstIdToModule(atoi(sz));
|
||||
valid = (callsign->IsValid() && (std::isupper(*reflectormodule) || (*reflectormodule == ' ')) );
|
||||
if ( !valid)
|
||||
{
|
||||
std::cout << "Invalid callsign in DMR+ connect packet from IP: " << Ip << " CS:" << *callsign << " DMRID:" << callsign->GetDmrid() << " ReflectorModule:" << *reflectormodule << std::endl;
|
||||
}
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool CDmrplusProtocol::IsValidDisconnectPacket(const CBuffer &Buffer, CCallsign *callsign, char *reflectormodule)
|
||||
{
|
||||
bool valid = false;
|
||||
if ( Buffer.size() == 32 )
|
||||
{
|
||||
char sz[9];
|
||||
::memcpy(sz, Buffer.data(), 8);
|
||||
sz[8] = 0;
|
||||
uint32 dmrid = atoi(sz);
|
||||
callsign->SetDmrid(dmrid, true);
|
||||
callsign->SetModule(DMRPLUS_MODULE_ID);
|
||||
*reflectormodule = Buffer.data()[11] - '0' + 'A';
|
||||
valid = (callsign->IsValid() && std::isupper(*reflectormodule));
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool CDmrplusProtocol::IsValidDvHeaderPacket(const CIp &Ip, const CBuffer &Buffer, std::unique_ptr<CDvHeaderPacket> &Header)
|
||||
{
|
||||
uint8 uiPacketType = Buffer.data()[8];
|
||||
if ( (Buffer.size() == 72) && ( uiPacketType == 2 ) )
|
||||
{
|
||||
// frame details
|
||||
uint8 uiSlot = (Buffer.data()[16] == 0x22) ? DMR_SLOT2 : DMR_SLOT1;
|
||||
uint8 uiCallType = (Buffer.data()[62] == 1) ? DMR_GROUP_CALL : DMR_PRIVATE_CALL;
|
||||
uint8 uiColourCode = Buffer.data()[20] & 0x0F;
|
||||
if ( (uiSlot == DMRPLUS_REFLECTOR_SLOT) && (uiCallType == DMR_GROUP_CALL) && (uiColourCode == DMRPLUS_REFLECTOR_COLOUR) )
|
||||
{
|
||||
// more frames details
|
||||
//uint8 uiSeqId = Buffer.data()[4];
|
||||
//uint8 uiVoiceSeq = (Buffer.data()[18] & 0x0F) - 7; // aka slot type
|
||||
uint32 uiDstId = *(uint32 *)(&Buffer.data()[64]) & 0x00FFFFFF;
|
||||
uint32 uiSrcId = *(uint32 *)(&Buffer.data()[68]) & 0x00FFFFFF;
|
||||
|
||||
// build DVHeader
|
||||
CCallsign csMY = CCallsign("", uiSrcId);
|
||||
CCallsign rpt1 = CCallsign("", uiSrcId);
|
||||
rpt1.SetModule(DMRPLUS_MODULE_ID);
|
||||
CCallsign rpt2 = m_ReflectorCallsign;
|
||||
rpt2.SetModule(DmrDstIdToModule(uiDstId));
|
||||
uint32 uiStreamId = IpToStreamId(Ip);
|
||||
|
||||
// and packet
|
||||
Header = std::unique_ptr<CDvHeaderPacket>(new CDvHeaderPacket(uiSrcId, CCallsign("CQCQCQ"), rpt1, rpt2, uiStreamId, 0, 0));
|
||||
if (Header && Header->IsValid())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDmrplusProtocol::IsValidDvFramePacket(const CIp &Ip, const CBuffer &Buffer, std::array<std::unique_ptr<CDvFramePacket>, 3> &frames)
|
||||
{
|
||||
uint8 uiPacketType = Buffer.data()[8];
|
||||
if ( (Buffer.size() == 72) && ((uiPacketType == 1) || (uiPacketType == 3)) )
|
||||
{
|
||||
// frame details
|
||||
uint8 uiSlot = (Buffer.data()[16] == 0x22) ? DMR_SLOT2 : DMR_SLOT1;
|
||||
uint8 uiCallType = (Buffer.data()[62] == 1) ? DMR_GROUP_CALL : DMR_PRIVATE_CALL;
|
||||
uint8 uiColourCode = Buffer.data()[20] & 0x0F;
|
||||
if ( (uiSlot == DMRPLUS_REFLECTOR_SLOT) && (uiCallType == DMR_GROUP_CALL) && (uiColourCode == DMRPLUS_REFLECTOR_COLOUR) )
|
||||
{
|
||||
// more frames details
|
||||
//uint8 uiSeqId = Buffer.data()[4];
|
||||
uint8 uiVoiceSeq = (Buffer.data()[18] & 0x0F) - 7; // aka slot type
|
||||
//uint32 uiDstId = *(uint32 *)(&Buffer.data()[64]) & 0x00FFFFFF;
|
||||
//uint32 uiSrcId = *(uint32 *)(&Buffer.data()[68]) & 0x00FFFFFF;
|
||||
|
||||
// crack payload
|
||||
uint8 dmrframe[33];
|
||||
uint8 dmr3ambe[27];
|
||||
uint8 dmrambe[9];
|
||||
uint8 dmrsync[7];
|
||||
// get the 33 bytes ambe
|
||||
memcpy(dmrframe, &(Buffer.data()[26]), 33);
|
||||
// handle endianess
|
||||
SwapEndianess(dmrframe, sizeof(dmrframe));
|
||||
// extract the 3 ambe frames
|
||||
memcpy(dmr3ambe, dmrframe, 14);
|
||||
dmr3ambe[13] &= 0xF0;
|
||||
dmr3ambe[13] |= (dmrframe[19] & 0x0F);
|
||||
memcpy(&dmr3ambe[14], &dmrframe[20], 13);
|
||||
// extract sync
|
||||
dmrsync[0] = dmrframe[13] & 0x0F;
|
||||
::memcpy(&dmrsync[1], &dmrframe[14], 5);
|
||||
dmrsync[6] = dmrframe[19] & 0xF0;
|
||||
|
||||
// and create 3 dv frames
|
||||
uint32 uiStreamId = IpToStreamId(Ip);
|
||||
// frame1
|
||||
memcpy(dmrambe, &dmr3ambe[0], 9);
|
||||
frames[0] = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(dmrambe, dmrsync, uiStreamId, uiVoiceSeq, 1));
|
||||
|
||||
// frame2
|
||||
memcpy(dmrambe, &dmr3ambe[9], 9);
|
||||
frames[1] = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(dmrambe, dmrsync, uiStreamId, uiVoiceSeq, 2));
|
||||
|
||||
// frame3
|
||||
memcpy(dmrambe, &dmr3ambe[18], 9);
|
||||
if ( uiPacketType == 3 )
|
||||
{
|
||||
frames[2] = std::unique_ptr<CDvFramePacket>(new CDvLastFramePacket(dmrambe, dmrsync, uiStreamId, uiVoiceSeq, 3));
|
||||
}
|
||||
else
|
||||
{
|
||||
frames[2] = std::unique_ptr<CDvFramePacket>(new CDvFramePacket(dmrambe, dmrsync, uiStreamId, uiVoiceSeq, 3));
|
||||
}
|
||||
|
||||
// check
|
||||
if (frames[0] && frames[1] && frames[2])
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// packet encoding helpers
|
||||
|
||||
void CDmrplusProtocol::EncodeConnectAckPacket(CBuffer *Buffer)
|
||||
{
|
||||
uint8 tag[] = { 'A','C','K',' ','O','K',0x0A,0x00 };
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
}
|
||||
|
||||
void CDmrplusProtocol::EncodeConnectNackPacket(CBuffer *Buffer)
|
||||
{
|
||||
uint8 tag[] = { 'N','A','K',' ','O','K',0x0A,0x00 };
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
}
|
||||
|
||||
bool CDmrplusProtocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Packet, CBuffer *Buffer) const
|
||||
{
|
||||
uint8 tag[] = { 0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x02,
|
||||
0x00,0x05,0x01,0x02,0x00,0x00,0x00
|
||||
} ;
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
|
||||
// uiSeqId
|
||||
//Buffer->ReplaceAt(4, 2);
|
||||
// uiPktType
|
||||
//Buffer->ReplaceAt(8, 2);
|
||||
// uiSlot
|
||||
Buffer->Append((uint16)((DMRPLUS_REFLECTOR_SLOT == DMR_SLOT1) ? 0x1111 : 0x2222));
|
||||
// uiSlotType
|
||||
Buffer->Append((uint16)0xEEEE);
|
||||
// uiColourCode
|
||||
uint8 uiColourCode = DMRPLUS_REFLECTOR_COLOUR | (DMRPLUS_REFLECTOR_COLOUR << 4);
|
||||
Buffer->Append((uint8)uiColourCode);
|
||||
Buffer->Append((uint8)uiColourCode);
|
||||
// uiFrameType
|
||||
Buffer->Append((uint16)0x1111);
|
||||
// reserved
|
||||
Buffer->Append((uint16)0x0000);
|
||||
// payload
|
||||
uint32 uiSrcId = Packet.GetMyCallsign().GetDmrid() & 0x00FFFFFF;
|
||||
uint32 uiDstId = ModuleToDmrDestId(Packet.GetRpt2Module()) & 0x00FFFFFF;
|
||||
Buffer->Append((uint8)0x00, 34);
|
||||
Buffer->ReplaceAt(36, HIBYTE(HIWORD(uiSrcId)));
|
||||
Buffer->ReplaceAt(38, LOBYTE(HIWORD(uiSrcId)));
|
||||
Buffer->ReplaceAt(40, HIBYTE(LOWORD(uiSrcId)));
|
||||
Buffer->ReplaceAt(42, LOBYTE(LOWORD(uiSrcId)));
|
||||
|
||||
// reserved
|
||||
Buffer->Append((uint16)0x0000);
|
||||
// uiCallType
|
||||
Buffer->Append((uint8)0x01);
|
||||
// reserved
|
||||
Buffer->Append((uint8)0x00);
|
||||
// uiDstId
|
||||
Buffer->Append(uiDstId);
|
||||
// uiSrcId
|
||||
Buffer->Append(uiSrcId);
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDmrplusProtocol::EncodeDvPacket
|
||||
(const CDvHeaderPacket &Header,
|
||||
const CDvFramePacket &DvFrame0, const CDvFramePacket &DvFrame1, const CDvFramePacket &DvFrame2,
|
||||
uint8 seqid, CBuffer *Buffer) const
|
||||
{
|
||||
|
||||
uint8 tag[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
|
||||
0x00,0x05,0x01,0x02,0x00,0x00,0x00
|
||||
} ;
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
|
||||
// uiSeqId
|
||||
Buffer->ReplaceAt(4, seqid);
|
||||
// uiPktType
|
||||
//Buffer->ReplaceAt(8, 1);
|
||||
// uiSlot
|
||||
Buffer->Append((uint16)((DMRPLUS_REFLECTOR_SLOT == DMR_SLOT1) ? 0x1111 : 0x2222));
|
||||
// uiVoiceSeq
|
||||
uint8 uiVoiceSeq = (DvFrame0.GetDmrPacketId() + 7) | ((DvFrame0.GetDmrPacketId() + 7) << 4);
|
||||
Buffer->Append((uint8)uiVoiceSeq);
|
||||
Buffer->Append((uint8)uiVoiceSeq);
|
||||
// uiColourCode
|
||||
uint8 uiColourCode = DMRPLUS_REFLECTOR_COLOUR | (DMRPLUS_REFLECTOR_COLOUR << 4);
|
||||
Buffer->Append((uint8)uiColourCode);
|
||||
Buffer->Append((uint8)uiColourCode);
|
||||
// uiFrameType
|
||||
Buffer->Append((uint16)0x1111);
|
||||
// reserved
|
||||
Buffer->Append((uint16)0x0000);
|
||||
|
||||
// payload
|
||||
uint32 uiSrcId = Header.GetMyCallsign().GetDmrid() & 0x00FFFFFF;
|
||||
uint32 uiDstId = ModuleToDmrDestId(Header.GetRpt2Module()) & 0x00FFFFFF;
|
||||
// frame0
|
||||
Buffer->ReplaceAt(26, DvFrame0.GetAmbePlus(), 9);
|
||||
// 1/2 frame1
|
||||
Buffer->ReplaceAt(35, DvFrame1.GetAmbePlus(), 5);
|
||||
Buffer->ReplaceAt(39, (uint8)(Buffer->at(39) & 0xF0));
|
||||
// 1/2 frame1
|
||||
Buffer->ReplaceAt(45, DvFrame1.GetAmbePlus()+4, 5);
|
||||
Buffer->ReplaceAt(45, (uint8)(Buffer->at(45) & 0x0F));
|
||||
// frame2
|
||||
Buffer->ReplaceAt(50, DvFrame2.GetAmbePlus(), 9);
|
||||
|
||||
// sync or embedded signaling
|
||||
ReplaceEMBInBuffer(Buffer, DvFrame0.GetDmrPacketId());
|
||||
|
||||
// reserved
|
||||
Buffer->Append((uint16)0x0000);
|
||||
Buffer->Append((uint8)0x00);
|
||||
// uiCallType
|
||||
Buffer->Append((uint8)0x01);
|
||||
// reserved
|
||||
Buffer->Append((uint8)0x00);
|
||||
// uiDstId
|
||||
Buffer->Append(uiDstId);
|
||||
// uiSrcId
|
||||
Buffer->Append(uiSrcId);
|
||||
|
||||
// handle indianess
|
||||
SwapEndianess(&(Buffer->data()[26]), 34);
|
||||
}
|
||||
|
||||
void CDmrplusProtocol::SwapEndianess(uint8 *buffer, int len) const
|
||||
{
|
||||
for ( int i = 0; i < len; i += 2 )
|
||||
{
|
||||
uint8 t = buffer[i];
|
||||
buffer[i] = buffer[i+1];
|
||||
buffer[i+1] = t;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SeqId helper
|
||||
|
||||
uint8 CDmrplusProtocol::GetNextSeqId(uint8 uiSeqId) const
|
||||
{
|
||||
return (uiSeqId + 1) & 0xFF;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DestId to Module helper
|
||||
|
||||
char CDmrplusProtocol::DmrDstIdToModule(uint32 tg) const
|
||||
{
|
||||
// is it a 4xxx ?
|
||||
if ( (tg >= 4001) && (tg <= (4000 + NB_OF_MODULES)) )
|
||||
{
|
||||
return ((char)(tg - 4001) + 'A');
|
||||
}
|
||||
return ' ';
|
||||
}
|
||||
|
||||
uint32 CDmrplusProtocol::ModuleToDmrDestId(char m) const
|
||||
{
|
||||
return (uint32)(m - 'A')+4001;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Buffer & LC helpers
|
||||
|
||||
void CDmrplusProtocol::AppendVoiceLCToBuffer(CBuffer *buffer, uint32 uiSrcId) const
|
||||
{
|
||||
uint8 payload[34];
|
||||
|
||||
// fill payload
|
||||
CBPTC19696 bptc;
|
||||
::memset(payload, 0, sizeof(payload));
|
||||
// LC data
|
||||
uint8 lc[12];
|
||||
{
|
||||
::memset(lc, 0, sizeof(lc));
|
||||
// uiDstId = TG9
|
||||
lc[5] = 9;
|
||||
// uiSrcId
|
||||
lc[6] = (uint8)LOBYTE(HIWORD(uiSrcId));
|
||||
lc[7] = (uint8)HIBYTE(LOWORD(uiSrcId));
|
||||
lc[8] = (uint8)LOBYTE(LOWORD(uiSrcId));
|
||||
// parity
|
||||
uint8 parity[4];
|
||||
CRS129::encode(lc, 9, parity);
|
||||
lc[9] = parity[2] ^ DMR_VOICE_LC_HEADER_CRC_MASK;
|
||||
lc[10] = parity[1] ^ DMR_VOICE_LC_HEADER_CRC_MASK;
|
||||
lc[11] = parity[0] ^ DMR_VOICE_LC_HEADER_CRC_MASK;
|
||||
}
|
||||
// sync
|
||||
::memcpy(payload+13, g_DmrSyncBSData, sizeof(g_DmrSyncBSData));
|
||||
// slot type
|
||||
{
|
||||
// slot type
|
||||
uint8 slottype[3];
|
||||
::memset(slottype, 0, sizeof(slottype));
|
||||
slottype[0] = (DMRPLUS_REFLECTOR_COLOUR << 4) & 0xF0;
|
||||
slottype[0] |= (DMR_DT_VOICE_LC_HEADER << 0) & 0x0FU;
|
||||
CGolay2087::encode(slottype);
|
||||
payload[12U] = (payload[12U] & 0xC0U) | ((slottype[0U] >> 2) & 0x3FU);
|
||||
payload[13U] = (payload[13U] & 0x0FU) | ((slottype[0U] << 6) & 0xC0U) | ((slottype[1U] >> 2) & 0x30U);
|
||||
payload[19U] = (payload[19U] & 0xF0U) | ((slottype[1U] >> 2) & 0x0FU);
|
||||
payload[20U] = (payload[20U] & 0x03U) | ((slottype[1U] << 6) & 0xC0U) | ((slottype[2U] >> 2) & 0x3CU);
|
||||
|
||||
}
|
||||
// and encode
|
||||
bptc.encode(lc, payload);
|
||||
|
||||
// and append
|
||||
buffer->Append(payload, sizeof(payload));
|
||||
}
|
||||
|
||||
void CDmrplusProtocol::ReplaceEMBInBuffer(CBuffer *buffer, uint8 uiDmrPacketId) const
|
||||
{
|
||||
// voice packet A ?
|
||||
if ( uiDmrPacketId == 0 )
|
||||
{
|
||||
// sync
|
||||
buffer->ReplaceAt(39, (uint8)(buffer->at(39) | (g_DmrSyncBSVoice[0] & 0x0F)));
|
||||
buffer->ReplaceAt(40, g_DmrSyncBSVoice+1, 5);
|
||||
buffer->ReplaceAt(45, (uint8)(buffer->at(45) | (g_DmrSyncBSVoice[6] & 0xF0)));
|
||||
}
|
||||
// voice packet B,C,D,E ?
|
||||
else if ( (uiDmrPacketId >= 1) && (uiDmrPacketId <= 4 ) )
|
||||
{
|
||||
// EMB LC
|
||||
uint8 emb[2];
|
||||
emb[0] = (DMRMMDVM_REFLECTOR_COLOUR << 4) & 0xF0;
|
||||
//emb[0] |= PI ? 0x08U : 0x00;
|
||||
//emb[0] |= (LCSS << 1) & 0x06;
|
||||
emb[1] = 0x00;
|
||||
// encode
|
||||
CQR1676::encode(emb);
|
||||
// and append
|
||||
buffer->ReplaceAt(39, (uint8)((buffer->at(39) & 0xF0) | ((emb[0U] >> 4) & 0x0F)));
|
||||
buffer->ReplaceAt(40, (uint8)((buffer->at(40) & 0x0F) | ((emb[0U] << 4) & 0xF0)));
|
||||
buffer->ReplaceAt(40, (uint8)(buffer->at(40) & 0xF0));
|
||||
buffer->ReplaceAt(41, (uint8)0);
|
||||
buffer->ReplaceAt(42, (uint8)0);
|
||||
buffer->ReplaceAt(43, (uint8)0);
|
||||
buffer->ReplaceAt(44, (uint8)(buffer->at(44) & 0x0F));
|
||||
buffer->ReplaceAt(44, (uint8)((buffer->at(44) & 0xF0) | ((emb[1U] >> 4) & 0x0F)));
|
||||
buffer->ReplaceAt(45, (uint8)((buffer->at(45) & 0x0F) | ((emb[1U] << 4) & 0xF0)));
|
||||
}
|
||||
// voice packet F
|
||||
else
|
||||
{
|
||||
// nullptr
|
||||
uint8 emb[2];
|
||||
emb[0] = (DMRMMDVM_REFLECTOR_COLOUR << 4) & 0xF0;
|
||||
//emb[0] |= PI ? 0x08U : 0x00;
|
||||
//emb[0] |= (LCSS << 1) & 0x06;
|
||||
emb[1] = 0x00;
|
||||
// encode
|
||||
CQR1676::encode(emb);
|
||||
// and append
|
||||
buffer->ReplaceAt(39, (uint8)((buffer->at(39) & 0xF0) | ((emb[0U] >> 4) & 0x0F)));
|
||||
buffer->ReplaceAt(40, (uint8)((buffer->at(40) & 0x0F) | ((emb[0U] << 4) & 0xF0)));
|
||||
buffer->ReplaceAt(40, (uint8)(buffer->at(40) & 0xF0));
|
||||
buffer->ReplaceAt(41, (uint8)0);
|
||||
buffer->ReplaceAt(42, (uint8)0);
|
||||
buffer->ReplaceAt(43, (uint8)0);
|
||||
buffer->ReplaceAt(44, (uint8)(buffer->at(44) & 0x0F));
|
||||
buffer->ReplaceAt(44, (uint8)((buffer->at(44) & 0xF0) | ((emb[1U] >> 4) & 0x0F)));
|
||||
buffer->ReplaceAt(45, (uint8)((buffer->at(45) & 0x0F) | ((emb[1U] << 4) & 0xF0)));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// uiStreamId helpers
|
||||
|
||||
|
||||
// uiStreamId helpers
|
||||
uint32 CDmrplusProtocol::IpToStreamId(const CIp &ip) const
|
||||
{
|
||||
return ip.GetAddr() ^ (uint32)(MAKEDWORD(ip.GetPort(), ip.GetPort()));
|
||||
}
|
||||
@ -0,0 +1,116 @@
|
||||
//
|
||||
// DMRPlusProtocol.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 10/01/2016.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdmrplusprotocol_h
|
||||
#define cdmrplusprotocol_h
|
||||
|
||||
#include "Timer.h"
|
||||
#include "DCSProtocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
#include "DVFramePacket.h"
|
||||
#include "DVLastFramePacket.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
// DMR Plus Module ID
|
||||
#define DMRPLUS_MODULE_ID 'B'
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDmrplusStreamCacheItem
|
||||
{
|
||||
public:
|
||||
CDmrplusStreamCacheItem() { m_uiSeqId = 0x77; }
|
||||
|
||||
CDvHeaderPacket m_dvHeader;
|
||||
CDvFramePacket m_dvFrame0;
|
||||
CDvFramePacket m_dvFrame1;
|
||||
|
||||
uint8 m_uiSeqId;
|
||||
};
|
||||
|
||||
|
||||
class CDmrplusProtocol : public CProtocol
|
||||
{
|
||||
public:
|
||||
// initialization
|
||||
bool Initialize(const char *type, const int pytpe, const uint16 port, const bool has_ipv4, const bool has_ipv6);
|
||||
|
||||
// task
|
||||
void Task(void);
|
||||
|
||||
protected:
|
||||
// queue helper
|
||||
void HandleQueue(void);
|
||||
void SendBufferToClients(const CBuffer &, uint8);
|
||||
|
||||
// keepalive helpers
|
||||
void HandleKeepalives(void);
|
||||
|
||||
// stream helpers
|
||||
void OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &, const CIp &);
|
||||
|
||||
// packet decoding helpers
|
||||
bool IsValidConnectPacket(const CBuffer &, CCallsign *, char *, const CIp &);
|
||||
bool IsValidDisconnectPacket(const CBuffer &, CCallsign *, char *);
|
||||
bool IsValidDvHeaderPacket(const CIp &, const CBuffer &, std::unique_ptr<CDvHeaderPacket> &);
|
||||
bool IsValidDvFramePacket(const CIp &, const CBuffer &, std::array<std::unique_ptr<CDvFramePacket>, 3> &);
|
||||
|
||||
// packet encoding helpers
|
||||
void EncodeConnectAckPacket(CBuffer *);
|
||||
void EncodeConnectNackPacket(CBuffer *);
|
||||
bool EncodeDvHeaderPacket(const CDvHeaderPacket &, CBuffer *) const;
|
||||
void EncodeDvPacket(const CDvHeaderPacket &, const CDvFramePacket &, const CDvFramePacket &, const CDvFramePacket &, uint8, CBuffer *) const;
|
||||
void SwapEndianess(uint8 *, int) const;
|
||||
|
||||
// dmr SeqId helper
|
||||
uint8 GetNextSeqId(uint8) const;
|
||||
|
||||
// dmr DstId to Module helper
|
||||
char DmrDstIdToModule(uint32) const;
|
||||
uint32 ModuleToDmrDestId(char) const;
|
||||
|
||||
// uiStreamId helpers
|
||||
uint32 IpToStreamId(const CIp &) const;
|
||||
|
||||
// Buffer & LC helpers
|
||||
void AppendVoiceLCToBuffer(CBuffer *, uint32) const;
|
||||
void AppendTerminatorLCToBuffer(CBuffer *, uint32) const;
|
||||
void ReplaceEMBInBuffer(CBuffer *, uint8) const;
|
||||
|
||||
|
||||
protected:
|
||||
// for keep alive
|
||||
CTimePoint m_LastKeepaliveTime;
|
||||
|
||||
// for queue header caches
|
||||
std::array<CDmrplusStreamCacheItem, NB_OF_MODULES> m_StreamsCache;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#endif /* cdmrplusprotocol_h */
|
||||
@ -0,0 +1,61 @@
|
||||
//
|
||||
// cdplusclient.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "DPlusClient.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructors
|
||||
|
||||
CDplusClient::CDplusClient()
|
||||
{
|
||||
m_bDextraDongle = false;
|
||||
}
|
||||
|
||||
CDplusClient::CDplusClient(const CCallsign &callsign, const CIp &ip, char reflectorModule)
|
||||
: CClient(callsign, ip, reflectorModule)
|
||||
{
|
||||
m_bDextraDongle = false;
|
||||
}
|
||||
|
||||
CDplusClient::CDplusClient(const CDplusClient &client)
|
||||
: CClient(client)
|
||||
{
|
||||
m_bDextraDongle = client.m_bDextraDongle;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// status
|
||||
|
||||
bool CDplusClient::IsAlive(void) const
|
||||
{
|
||||
return (m_LastKeepaliveTime.DurationSinceNow() < DPLUS_KEEPALIVE_TIMEOUT);
|
||||
}
|
||||
|
||||
void CDplusClient::SetMasterOfModule(char c)
|
||||
{
|
||||
CClient::SetMasterOfModule(c);
|
||||
SetReflectorModule(c);
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
//
|
||||
// DPlusClient.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdplusclient_h
|
||||
#define cdplusclient_h
|
||||
|
||||
#include "cclient.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDplusClient : public CClient
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CDplusClient();
|
||||
CDplusClient(const CCallsign &, const CIp &, char = ' ');
|
||||
CDplusClient(const CDplusClient &);
|
||||
|
||||
// destructor
|
||||
virtual ~CDplusClient() {};
|
||||
|
||||
// identity
|
||||
int GetProtocol(void) const { return PROTOCOL_DPLUS; }
|
||||
const char *GetProtocolName(void) const { return "DPlus"; }
|
||||
int GetCodec(void) const { return CODEC_AMBEPLUS; }
|
||||
bool IsNode(void) const { return true; }
|
||||
bool IsDextraDongle(void) const { return m_bDextraDongle; }
|
||||
void SetDextraDongle(void) { m_bDextraDongle = true; }
|
||||
|
||||
// status
|
||||
bool IsAlive(void) const;
|
||||
void SetMasterOfModule(char);
|
||||
|
||||
protected:
|
||||
// data
|
||||
bool m_bDextraDongle;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cdplusclient_h */
|
||||
@ -0,0 +1,532 @@
|
||||
//
|
||||
// cdplusprotocol.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 01/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include "DPlusClient.h"
|
||||
#include "DPlusProtocol.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operation
|
||||
|
||||
bool CDplusProtocol::Initialize(const char *type, const int ptype, const uint16 port, const bool has_ipv4, const bool has_ipv6)
|
||||
{
|
||||
// base class
|
||||
if (! CProtocol::Initialize(type, ptype, port, has_ipv4, has_ipv6))
|
||||
return false;
|
||||
|
||||
// update time
|
||||
m_LastKeepaliveTime.Now();
|
||||
|
||||
// done
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// task
|
||||
|
||||
void CDplusProtocol::Task(void)
|
||||
{
|
||||
CBuffer Buffer;
|
||||
CIp Ip;
|
||||
CCallsign Callsign;
|
||||
std::unique_ptr<CDvHeaderPacket> Header;
|
||||
std::unique_ptr<CDvFramePacket> Frame;
|
||||
std::unique_ptr<CDvLastFramePacket> LastFrame;
|
||||
|
||||
// handle incoming packets
|
||||
#if DSTAR_IPV6==true
|
||||
#if DSTAR_IPV4==true
|
||||
if ( ReceiveDS(Buffer, Ip, 20) )
|
||||
#else
|
||||
if ( Receive6(Buffer, Ip, 20) )
|
||||
#endif
|
||||
#else
|
||||
if ( Receive4(Buffer, Ip, 20) )
|
||||
#endif
|
||||
{
|
||||
// crack the packet
|
||||
if ( IsValidDvFramePacket(Buffer, Frame) )
|
||||
{
|
||||
OnDvFramePacketIn(Frame, &Ip);
|
||||
}
|
||||
else if ( IsValidDvHeaderPacket(Buffer, Header) )
|
||||
{
|
||||
// is muted?
|
||||
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, PROTOCOL_DPLUS, Header->GetRpt2Module()) )
|
||||
{
|
||||
// handle it
|
||||
OnDvHeaderPacketIn(Header, Ip);
|
||||
}
|
||||
}
|
||||
else if ( IsValidDvLastFramePacket(Buffer, LastFrame) )
|
||||
{
|
||||
OnDvLastFramePacketIn(LastFrame, &Ip);
|
||||
}
|
||||
else if ( IsValidConnectPacket(Buffer) )
|
||||
{
|
||||
std::cout << "DPlus connect request packet from " << Ip << std::endl;
|
||||
|
||||
// acknowledge the request
|
||||
Send(Buffer, Ip);
|
||||
}
|
||||
else if ( IsValidLoginPacket(Buffer, &Callsign) )
|
||||
{
|
||||
std::cout << "DPlus login packet from " << Callsign << " at " << Ip << std::endl;
|
||||
|
||||
// callsign authorized?
|
||||
if ( g_GateKeeper.MayLink(Callsign, Ip, PROTOCOL_DPLUS) )
|
||||
{
|
||||
// acknowledge the request
|
||||
EncodeLoginAckPacket(&Buffer);
|
||||
Send(Buffer, Ip);
|
||||
|
||||
// create the client and append
|
||||
g_Reflector.GetClients()->AddClient(std::make_shared<CDplusClient>(Callsign, Ip));
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
else
|
||||
{
|
||||
// deny the request
|
||||
EncodeLoginNackPacket(&Buffer);
|
||||
Send(Buffer, Ip);
|
||||
}
|
||||
|
||||
}
|
||||
else if ( IsValidDisconnectPacket(Buffer) )
|
||||
{
|
||||
std::cout << "DPlus disconnect packet from " << Ip << std::endl;
|
||||
|
||||
// find client
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
std::shared_ptr<CClient>client = clients->FindClient(Ip, PROTOCOL_DPLUS);
|
||||
if ( client != nullptr )
|
||||
{
|
||||
// remove it
|
||||
clients->RemoveClient(client);
|
||||
// and acknowledge the disconnect
|
||||
EncodeDisconnectPacket(&Buffer);
|
||||
Send(Buffer, Ip);
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
else if ( IsValidKeepAlivePacket(Buffer) )
|
||||
{
|
||||
//std::cout << "DPlus keepalive packet from " << Ip << std::endl;
|
||||
|
||||
// find all clients with that callsign & ip and keep them alive
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(Ip, PROTOCOL_DPLUS, it)) != nullptr )
|
||||
{
|
||||
client->Alive();
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string title("Unknown DPlus packet from ");
|
||||
title += Ip.GetAddress();
|
||||
Buffer.Dump(title);
|
||||
}
|
||||
}
|
||||
|
||||
// handle end of streaming timeout
|
||||
CheckStreamsTimeout();
|
||||
|
||||
// handle queue from reflector
|
||||
HandleQueue();
|
||||
|
||||
// keep client alive
|
||||
if ( m_LastKeepaliveTime.DurationSinceNow() > DPLUS_KEEPALIVE_PERIOD )
|
||||
{
|
||||
//
|
||||
HandleKeepalives();
|
||||
|
||||
// update time
|
||||
m_LastKeepaliveTime.Now();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// streams helpers
|
||||
|
||||
void CDplusProtocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, const CIp &Ip)
|
||||
{
|
||||
// find the stream
|
||||
CPacketStream *stream = GetStream(Header->GetStreamId());
|
||||
if ( stream )
|
||||
{
|
||||
// stream already open
|
||||
// skip packet, but tickle the stream
|
||||
stream->Tickle();
|
||||
}
|
||||
else
|
||||
{
|
||||
// no stream open yet, open a new one
|
||||
CCallsign my(Header->GetMyCallsign());
|
||||
CCallsign rpt1(Header->GetRpt1Callsign());
|
||||
CCallsign rpt2(Header->GetRpt2Callsign());
|
||||
|
||||
// first, check module is valid
|
||||
if ( g_Reflector.IsValidModule(rpt2.GetModule()) )
|
||||
{
|
||||
// find this client
|
||||
std::shared_ptr<CClient>client = g_Reflector.GetClients()->FindClient(Ip, PROTOCOL_DPLUS);
|
||||
if ( client )
|
||||
{
|
||||
// now we know if it's a dextra dongle or a genuine dplus node
|
||||
if ( Header->GetRpt2Callsign().HasSameCallsignWithWildcard(CCallsign("XRF*")) )
|
||||
{
|
||||
client->SetDextraDongle();
|
||||
}
|
||||
// now we know its module, let's update it
|
||||
if ( !client->HasModule() )
|
||||
{
|
||||
client->SetModule(rpt1.GetModule());
|
||||
}
|
||||
// get client callsign
|
||||
rpt1 = client->GetCallsign();
|
||||
// and try to open the stream
|
||||
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
|
||||
{
|
||||
// keep the handle
|
||||
m_Streams.push_back(stream);
|
||||
}
|
||||
}
|
||||
// release
|
||||
g_Reflector.ReleaseClients();
|
||||
|
||||
// update last heard
|
||||
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
|
||||
g_Reflector.ReleaseUsers();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "DPlus node " << rpt1 << " link attempt on non-existing module" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// queue helper
|
||||
|
||||
void CDplusProtocol::HandleQueue(void)
|
||||
{
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
{
|
||||
// get the packet
|
||||
auto packet = m_Queue.front();
|
||||
m_Queue.pop();
|
||||
|
||||
// get our sender's id
|
||||
int iModId = g_Reflector.GetModuleIndex(packet->GetModuleId());
|
||||
|
||||
// check if it's header and update cache
|
||||
if ( packet->IsDvHeader() )
|
||||
{
|
||||
// this relies on queue feeder setting valid module id
|
||||
m_StreamsCache[iModId].m_dvHeader = CDvHeaderPacket((const CDvHeaderPacket &)*packet);
|
||||
m_StreamsCache[iModId].m_iSeqCounter = 0;
|
||||
}
|
||||
|
||||
// encode it
|
||||
CBuffer buffer;
|
||||
if ( EncodeDvPacket(*packet, &buffer) )
|
||||
{
|
||||
// and push it to all our clients who are not streaming in
|
||||
// note that for dplus protocol, all stream of all modules are push to all clients
|
||||
// it's client who decide which stream he's interrrested in
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_DPLUS, it)) != nullptr )
|
||||
{
|
||||
// is this client busy ?
|
||||
if ( !client->IsAMaster() )
|
||||
{
|
||||
// check if client is a dextra dongle
|
||||
// then replace RPT2 with XRF instead of REF
|
||||
// if the client type is not yet known, send bothheaders
|
||||
if ( packet->IsDvHeader() )
|
||||
{
|
||||
// sending header in Dplus is client specific
|
||||
SendDvHeader((CDvHeaderPacket *)packet.get(), (CDplusClient *)client.get());
|
||||
}
|
||||
else if ( packet->IsDvFrame() )
|
||||
{
|
||||
// and send the DV frame
|
||||
Send(buffer, client->GetIp());
|
||||
|
||||
// is it time to insert a DVheader copy ?
|
||||
if ( (m_StreamsCache[iModId].m_iSeqCounter++ % 21) == 20 )
|
||||
{
|
||||
// yes, clone it
|
||||
CDvHeaderPacket packet2(m_StreamsCache[iModId].m_dvHeader);
|
||||
// and send it
|
||||
SendDvHeader(&packet2, (CDplusClient *)client.get());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, send the original packet
|
||||
Send(buffer, client->GetIp());
|
||||
}
|
||||
}
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
void CDplusProtocol::SendDvHeader(CDvHeaderPacket *packet, CDplusClient *client)
|
||||
{
|
||||
// encode it
|
||||
CBuffer buffer;
|
||||
if ( EncodeDvPacket(*packet, &buffer) )
|
||||
{
|
||||
if ( (client->IsDextraDongle() || !client->HasModule()) )
|
||||
{
|
||||
// clone the packet and patch it
|
||||
CDvHeaderPacket packet2(*((CDvHeaderPacket *)packet));
|
||||
CCallsign rpt2 = packet2.GetRpt2Callsign();
|
||||
rpt2.PatchCallsign(0, (const uint8 *)"XRF", 3);
|
||||
packet2.SetRpt2Callsign(rpt2);
|
||||
|
||||
// encode it
|
||||
CBuffer buffer2;
|
||||
if ( EncodeDvPacket(packet2, &buffer2) )
|
||||
{
|
||||
// and send it
|
||||
Send(buffer2, client->GetIp());
|
||||
}
|
||||
|
||||
// client type known ?
|
||||
if ( !client->HasModule() )
|
||||
{
|
||||
// no, send also the genuine packet
|
||||
Send(buffer, client->GetIp());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, send the original packet
|
||||
Send(buffer, client->GetIp());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// keepalive helpers
|
||||
|
||||
void CDplusProtocol::HandleKeepalives(void)
|
||||
{
|
||||
// send keepalives
|
||||
CBuffer keepalive;
|
||||
EncodeKeepAlivePacket(&keepalive);
|
||||
|
||||
// iterate on clients
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_DPLUS, it)) != nullptr )
|
||||
{
|
||||
// send keepalive
|
||||
//std::cout << "Sending DPlus packet @ " << client->GetIp() << std::endl;
|
||||
Send(keepalive, client->GetIp());
|
||||
|
||||
// is this client busy ?
|
||||
if ( client->IsAMaster() )
|
||||
{
|
||||
// yes, just tickle it
|
||||
client->Alive();
|
||||
}
|
||||
// check it's still with us
|
||||
else if ( !client->IsAlive() )
|
||||
{
|
||||
// no, disconnect
|
||||
CBuffer disconnect;
|
||||
EncodeDisconnectPacket(&disconnect);
|
||||
Send(disconnect, client->GetIp());
|
||||
|
||||
// and remove it
|
||||
std::cout << "DPlus client " << client->GetCallsign() << " keepalive timeout" << std::endl;
|
||||
clients->RemoveClient(client);
|
||||
}
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// packet decoding helpers
|
||||
|
||||
bool CDplusProtocol::IsValidConnectPacket(const CBuffer &Buffer)
|
||||
{
|
||||
uint8 tag[] = { 0x05,0x00,0x18,0x00,0x01 };
|
||||
return (Buffer == CBuffer(tag, sizeof(tag)));
|
||||
}
|
||||
|
||||
bool CDplusProtocol::IsValidLoginPacket(const CBuffer &Buffer, CCallsign *Callsign)
|
||||
{
|
||||
uint8 Tag[] = { 0x1C,0xC0,0x04,0x00 };
|
||||
bool valid = false;
|
||||
|
||||
if ( (Buffer.size() == 28) &&(::memcmp(Buffer.data(), Tag, sizeof(Tag)) == 0) )
|
||||
{
|
||||
Callsign->SetCallsign(&(Buffer.data()[4]), 8);
|
||||
valid = Callsign->IsValid();
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool CDplusProtocol::IsValidDisconnectPacket(const CBuffer &Buffer)
|
||||
{
|
||||
uint8 tag[] = { 0x05,0x00,0x18,0x00,0x00 };
|
||||
return (Buffer == CBuffer(tag, sizeof(tag)));
|
||||
}
|
||||
|
||||
bool CDplusProtocol::IsValidKeepAlivePacket(const CBuffer &Buffer)
|
||||
{
|
||||
uint8 tag[] = { 0x03,0x60,0x00 };
|
||||
return (Buffer == CBuffer(tag, sizeof(tag)));
|
||||
}
|
||||
|
||||
bool CDplusProtocol::IsValidDvHeaderPacket(const CBuffer &Buffer, std::unique_ptr<CDvHeaderPacket> &header)
|
||||
{
|
||||
if ( 58==Buffer.size() && 0x3AU==Buffer.data()[0] && 0x80U==Buffer.data()[1] && 0==Buffer.Compare((uint8 *)"DSVT", 2, 4) && 0x10U==Buffer.data()[6] && 0x20U==Buffer.data()[10] )
|
||||
{
|
||||
// create packet
|
||||
header = std::unique_ptr<CDvHeaderPacket>(new CDvHeaderPacket((struct dstar_header *)&(Buffer.data()[17]), *((uint16 *)&(Buffer.data()[14])), 0x80));
|
||||
// check validity of packet
|
||||
if ( header && header->IsValid() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDplusProtocol::IsValidDvFramePacket(const CBuffer &Buffer, std::unique_ptr<CDvFramePacket> &dvframe)
|
||||
{
|
||||
if ( 29==Buffer.size() && 0x1DU==Buffer.data()[0] && 0x80U==Buffer.data()[1] && 0==Buffer.Compare((uint8 *)"DSVT", 2, 4) && 0x20U==Buffer.data()[6] && 0x20U==Buffer.data()[10] )
|
||||
{
|
||||
// create packet
|
||||
dvframe = std::unique_ptr<CDvFramePacket>(new CDvFramePacket((struct dstar_dvframe *)&(Buffer.data()[17]), *((uint16 *)&(Buffer.data()[14])), Buffer.data()[16]));
|
||||
// check validity of packet
|
||||
if ( dvframe && dvframe->IsValid() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CDplusProtocol::IsValidDvLastFramePacket(const CBuffer &Buffer, std::unique_ptr<CDvLastFramePacket> &dvframe)
|
||||
{
|
||||
if ( 32==Buffer.size() && 0==Buffer.Compare((uint8 *)"DSVT", 2, 4) && 0x20U==Buffer.data()[0] && 0x80U==Buffer.data()[1] && 0x20U==Buffer.data()[6] && 0x20U==Buffer.data()[10] )
|
||||
{
|
||||
// create packet
|
||||
dvframe = std::unique_ptr<CDvLastFramePacket>(new CDvLastFramePacket((struct dstar_dvframe *)&(Buffer.data()[17]), *((uint16 *)&(Buffer.data()[14])), Buffer.data()[16]));
|
||||
// check validity of packet
|
||||
if ( dvframe && dvframe->IsValid() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// packet encoding helpers
|
||||
|
||||
void CDplusProtocol::EncodeKeepAlivePacket(CBuffer *Buffer)
|
||||
{
|
||||
uint8 tag[] = { 0x03,0x60,0x00 };
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
}
|
||||
|
||||
void CDplusProtocol::EncodeLoginAckPacket(CBuffer *Buffer)
|
||||
{
|
||||
uint8 tag[] = { 0x08,0xC0,0x04,0x00,'O','K','R','W' };
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
}
|
||||
|
||||
void CDplusProtocol::EncodeLoginNackPacket(CBuffer *Buffer)
|
||||
{
|
||||
uint8 tag[] = { 0x08,0xC0,0x04,0x00,'B','U','S','Y' };
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
}
|
||||
|
||||
void CDplusProtocol::EncodeDisconnectPacket(CBuffer *Buffer)
|
||||
{
|
||||
uint8 tag[] = { 0x05,0x00,0x18,0x00,0x00 };
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
}
|
||||
|
||||
|
||||
bool CDplusProtocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Packet, CBuffer *Buffer) const
|
||||
{
|
||||
uint8 tag[] = { 0x3A,0x80,0x44,0x53,0x56,0x54,0x10,0x00,0x00,0x00,0x20,0x00,0x01,0x02 };
|
||||
struct dstar_header DstarHeader;
|
||||
|
||||
Packet.ConvertToDstarStruct(&DstarHeader);
|
||||
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
Buffer->Append(Packet.GetStreamId());
|
||||
Buffer->Append((uint8)0x80);
|
||||
Buffer->Append((uint8 *)&DstarHeader, sizeof(struct dstar_header));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CDplusProtocol::EncodeDvFramePacket(const CDvFramePacket &Packet, CBuffer *Buffer) const
|
||||
{
|
||||
uint8 tag[] = { 0x1D,0x80,0x44,0x53,0x56,0x54,0x20,0x00,0x00,0x00,0x20,0x00,0x01,0x02 };
|
||||
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
Buffer->Append(Packet.GetStreamId());
|
||||
Buffer->Append((uint8)(Packet.GetPacketId() % 21));
|
||||
Buffer->Append((uint8 *)Packet.GetAmbe(), AMBE_SIZE);
|
||||
Buffer->Append((uint8 *)Packet.GetDvData(), DVDATA_SIZE);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool CDplusProtocol::EncodeDvLastFramePacket(const CDvLastFramePacket &Packet, CBuffer *Buffer) const
|
||||
{
|
||||
uint8 tag1[] = { 0x20,0x80,0x44,0x53,0x56,0x54,0x20,0x00,0x81,0x00,0x20,0x00,0x01,0x02 };
|
||||
uint8 tag2[] = { 0x55,0xC8,0x7A,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x25,0x1A,0xC6 };
|
||||
|
||||
Buffer->Set(tag1, sizeof(tag1));
|
||||
Buffer->Append(Packet.GetStreamId());
|
||||
Buffer->Append((uint8)((Packet.GetPacketId() % 21) | 0x40));
|
||||
Buffer->Append(tag2, sizeof(tag2));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
//
|
||||
// DPlusProtocol.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 01/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdplusprotocol_h
|
||||
#define cdplusprotocol_h
|
||||
|
||||
#include "Timer.h"
|
||||
#include "Protocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
#include "DVFramePacket.h"
|
||||
#include "DVLastFramePacket.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDplusClient;
|
||||
|
||||
class CDPlusStreamCacheItem
|
||||
{
|
||||
public:
|
||||
CDPlusStreamCacheItem() { m_iSeqCounter = 0; }
|
||||
|
||||
CDvHeaderPacket m_dvHeader;
|
||||
uint8 m_iSeqCounter;
|
||||
};
|
||||
|
||||
class CDplusProtocol : public CProtocol
|
||||
{
|
||||
public:
|
||||
// initialization
|
||||
bool Initialize(const char *type, const int ptype, const uint16 port, const bool has_ipv4, const bool has_ipv6);
|
||||
|
||||
// task
|
||||
void Task(void);
|
||||
|
||||
protected:
|
||||
// queue helper
|
||||
void HandleQueue(void);
|
||||
void SendDvHeader(CDvHeaderPacket *, CDplusClient *);
|
||||
|
||||
// keepalive helpers
|
||||
void HandleKeepalives(void);
|
||||
|
||||
// stream helpers
|
||||
void OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &, const CIp &);
|
||||
|
||||
// packet decoding helpers
|
||||
bool IsValidConnectPacket(const CBuffer &);
|
||||
bool IsValidLoginPacket(const CBuffer &, CCallsign *);
|
||||
bool IsValidDisconnectPacket(const CBuffer &);
|
||||
bool IsValidKeepAlivePacket(const CBuffer &);
|
||||
bool IsValidDvHeaderPacket(const CBuffer &, std::unique_ptr<CDvHeaderPacket> &);
|
||||
bool IsValidDvFramePacket(const CBuffer &, std::unique_ptr<CDvFramePacket> &);
|
||||
bool IsValidDvLastFramePacket(const CBuffer &, std::unique_ptr<CDvLastFramePacket> &);
|
||||
|
||||
// packet encoding helpers
|
||||
void EncodeKeepAlivePacket(CBuffer *);
|
||||
void EncodeLoginAckPacket(CBuffer *);
|
||||
void EncodeLoginNackPacket(CBuffer *);
|
||||
void EncodeDisconnectPacket(CBuffer *);
|
||||
bool EncodeDvHeaderPacket(const CDvHeaderPacket &, CBuffer *) const;
|
||||
bool EncodeDvFramePacket(const CDvFramePacket &, CBuffer *) const;
|
||||
bool EncodeDvLastFramePacket(const CDvLastFramePacket &, CBuffer *) const;
|
||||
|
||||
|
||||
protected:
|
||||
// for keep alive
|
||||
CTimePoint m_LastKeepaliveTime;
|
||||
|
||||
// for queue header caches
|
||||
std::array<CDPlusStreamCacheItem, NB_OF_MODULES> m_StreamsCache;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cdplusprotocol_h */
|
||||
@ -0,0 +1,157 @@
|
||||
//
|
||||
// cdvframepacket.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 01/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include "DVFramePacket.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CDvFramePacket::CDvFramePacket()
|
||||
{
|
||||
::memset(m_uiAmbe, 0, sizeof(m_uiAmbe));
|
||||
::memset(m_uiDvData, 0, sizeof(m_uiDvData));
|
||||
#ifndef NO_XLX
|
||||
::memset(m_uiAmbePlus, 0, sizeof(m_uiAmbePlus));
|
||||
::memset(m_uiDvSync, 0, sizeof(m_uiDvSync));
|
||||
#endif
|
||||
};
|
||||
|
||||
// dstar constructor
|
||||
|
||||
CDvFramePacket::CDvFramePacket(const struct dstar_dvframe *dvframe, uint16 sid, uint8 pid)
|
||||
: CPacket(sid, pid)
|
||||
{
|
||||
::memcpy(m_uiAmbe, dvframe->AMBE, sizeof(m_uiAmbe));
|
||||
::memcpy(m_uiDvData, dvframe->DVDATA, sizeof(m_uiDvData));
|
||||
#ifndef NO_XLX
|
||||
::memset(m_uiAmbePlus, 0, sizeof(m_uiAmbePlus));
|
||||
::memset(m_uiDvSync, 0, sizeof(m_uiDvSync));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef NO_XLX
|
||||
// dmr constructor
|
||||
|
||||
CDvFramePacket::CDvFramePacket(const uint8 *ambe, const uint8 *sync, uint16 sid, uint8 pid, uint8 spid)
|
||||
: CPacket(sid, pid, spid)
|
||||
{
|
||||
::memcpy(m_uiAmbePlus, ambe, sizeof(m_uiAmbePlus));
|
||||
::memcpy(m_uiDvSync, sync, sizeof(m_uiDvSync));
|
||||
::memset(m_uiAmbe, 0, sizeof(m_uiAmbe));
|
||||
::memset(m_uiDvData, 0, sizeof(m_uiDvData));
|
||||
}
|
||||
|
||||
// ysf constructor
|
||||
|
||||
CDvFramePacket::CDvFramePacket(const uint8 *ambe, uint16 sid, uint8 pid, uint8 spid, uint8 fid)
|
||||
: CPacket(sid, pid, spid, fid)
|
||||
{
|
||||
::memcpy(m_uiAmbePlus, ambe, sizeof(m_uiAmbePlus));
|
||||
::memset(m_uiDvSync, 0, sizeof(m_uiDvSync));
|
||||
::memset(m_uiAmbe, 0, sizeof(m_uiAmbe));
|
||||
::memset(m_uiDvData, 0, sizeof(m_uiDvData));
|
||||
}
|
||||
|
||||
// xlx constructor
|
||||
|
||||
CDvFramePacket::CDvFramePacket
|
||||
(uint16 sid,
|
||||
uint8 dstarpid, const uint8 *dstarambe, const uint8 *dstardvdata,
|
||||
uint8 dmrpid, uint8 dprspid, const uint8 *dmrambe, const uint8 *dmrsync)
|
||||
: CPacket(sid, dstarpid, dmrpid, dprspid, 0xFF, 0xFF, 0xFF)
|
||||
{
|
||||
::memcpy(m_uiAmbe, dstarambe, sizeof(m_uiAmbe));
|
||||
::memcpy(m_uiDvData, dstardvdata, sizeof(m_uiDvData));
|
||||
::memcpy(m_uiAmbePlus, dmrambe, sizeof(m_uiAmbePlus));
|
||||
::memcpy(m_uiDvSync, dmrsync, sizeof(m_uiDvSync));
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// virtual duplication
|
||||
|
||||
std::unique_ptr<CPacket> CDvFramePacket::Duplicate(void) const
|
||||
{
|
||||
return std::unique_ptr<CPacket>(new CDvFramePacket(*this));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// get
|
||||
|
||||
const uint8 *CDvFramePacket::GetAmbe(uint8 uiCodec) const
|
||||
{
|
||||
switch (uiCodec)
|
||||
{
|
||||
case CODEC_AMBEPLUS:
|
||||
return m_uiAmbe;
|
||||
#ifndef NO_XLX
|
||||
case CODEC_AMBE2PLUS:
|
||||
return m_uiAmbePlus;
|
||||
#endif
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// set
|
||||
|
||||
void CDvFramePacket::SetDvData(uint8 *DvData)
|
||||
{
|
||||
::memcpy(m_uiDvData, DvData, sizeof(m_uiDvData));
|
||||
}
|
||||
|
||||
void CDvFramePacket::SetAmbe(uint8 uiCodec, uint8 *Ambe)
|
||||
{
|
||||
switch (uiCodec)
|
||||
{
|
||||
case CODEC_AMBEPLUS:
|
||||
::memcpy(m_uiAmbe, Ambe, sizeof(m_uiAmbe));
|
||||
break;
|
||||
#ifndef NO_XLX
|
||||
case CODEC_AMBE2PLUS:
|
||||
::memcpy(m_uiAmbePlus, Ambe, sizeof(m_uiAmbe));
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operators
|
||||
|
||||
bool CDvFramePacket::operator ==(const CDvFramePacket &DvFrame) const
|
||||
{
|
||||
return ( (::memcmp(m_uiAmbe, DvFrame.m_uiAmbe, sizeof(m_uiAmbe)) == 0)
|
||||
&& (::memcmp(m_uiDvData, DvFrame.m_uiDvData, sizeof(m_uiDvData)) == 0)
|
||||
#ifndef NO_XLX
|
||||
&& (::memcmp(m_uiAmbePlus, DvFrame.m_uiAmbePlus, sizeof(m_uiAmbePlus)) == 0)
|
||||
&& (::memcmp(m_uiDvSync, DvFrame.m_uiDvSync, sizeof(m_uiDvSync)) == 0)
|
||||
#endif
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,108 @@
|
||||
//
|
||||
// DVFramePacket.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 01/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdvframepacket_h
|
||||
#define cdvframepacket_h
|
||||
|
||||
#include "Packet.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// defines
|
||||
|
||||
#define AMBE_SIZE 9
|
||||
#define DVDATA_SIZE 3
|
||||
|
||||
#define AMBEPLUS_SIZE 9
|
||||
#define DVSYNC_SIZE 7
|
||||
|
||||
// typedef & structures
|
||||
|
||||
struct __attribute__ ((__packed__))dstar_dvframe
|
||||
{
|
||||
uint8 AMBE[AMBE_SIZE];
|
||||
uint8 DVDATA[DVDATA_SIZE];
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDvFramePacket : public CPacket
|
||||
{
|
||||
//friend class CCodecStream;
|
||||
public:
|
||||
// constructor
|
||||
CDvFramePacket();
|
||||
CDvFramePacket(const struct dstar_dvframe *, uint16, uint8);
|
||||
#ifndef NO_XLX
|
||||
CDvFramePacket(const uint8 *, const uint8 *, uint16, uint8, uint8);
|
||||
CDvFramePacket(const uint8 *, uint16, uint8, uint8, uint8);
|
||||
CDvFramePacket(uint16, uint8, const uint8 *, const uint8 *, uint8, uint8, const uint8 *, const uint8 *);
|
||||
#endif
|
||||
|
||||
// virtual duplication
|
||||
std::unique_ptr<CPacket> Duplicate(void) const;
|
||||
|
||||
// identity
|
||||
bool IsDvFrame(void) const { return true; }
|
||||
#ifndef NO_XLX
|
||||
bool HasTranscodableAmbe(void) const { return true; }
|
||||
#endif
|
||||
|
||||
// get
|
||||
const uint8 *GetAmbe(uint8) const;
|
||||
const uint8 *GetAmbe(void) const { return m_uiAmbe; }
|
||||
#ifndef NO_XLX
|
||||
const uint8 *GetAmbePlus(void) const { return m_uiAmbePlus; }
|
||||
const uint8 *GetDvSync(void) const { return m_uiDvSync; }
|
||||
#endif
|
||||
const uint8 *GetDvData(void) const { return m_uiDvData; }
|
||||
|
||||
// set
|
||||
void SetDvData(uint8 *);
|
||||
void SetAmbe(uint8, uint8 *);
|
||||
|
||||
// operators
|
||||
bool operator ==(const CDvFramePacket &) const;
|
||||
|
||||
protected:
|
||||
// get
|
||||
uint8 *GetAmbeData(void) { return m_uiAmbe; }
|
||||
#ifndef NO_XLX
|
||||
uint8 *GetAmbePlusData(void) { return m_uiAmbePlus; }
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// data (dstar)
|
||||
uint8 m_uiAmbe[AMBE_SIZE];
|
||||
uint8 m_uiDvData[DVDATA_SIZE];
|
||||
#ifndef NO_XLX
|
||||
// data (dmr)
|
||||
uint8 m_uiAmbePlus[AMBEPLUS_SIZE];
|
||||
uint8 m_uiDvSync[DVSYNC_SIZE];
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cdvframepacket_h */
|
||||
@ -0,0 +1,159 @@
|
||||
//
|
||||
// cdvheaderpacket.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 01/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include <cstdio>
|
||||
#include "DMRIdDir.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CDvHeaderPacket::CDvHeaderPacket()
|
||||
{
|
||||
m_uiFlag1 = 0;
|
||||
m_uiFlag2 = 0;
|
||||
m_uiFlag3 = 0;
|
||||
m_uiCrc = 0;
|
||||
}
|
||||
|
||||
// dstar constructor
|
||||
|
||||
CDvHeaderPacket::CDvHeaderPacket(const struct dstar_header *buffer, uint16 sid, uint8 pid)
|
||||
: CPacket(sid, pid)
|
||||
{
|
||||
m_uiFlag1 = buffer->Flag1;
|
||||
m_uiFlag2 = buffer->Flag2;
|
||||
m_uiFlag3 = buffer->Flag3;
|
||||
m_csUR.SetCallsign(buffer->UR, CALLSIGN_LEN);
|
||||
m_csRPT1.SetCallsign(buffer->RPT1, CALLSIGN_LEN);
|
||||
m_csRPT2.SetCallsign(buffer->RPT2, CALLSIGN_LEN);
|
||||
m_csMY.SetCallsign(buffer->MY, CALLSIGN_LEN);
|
||||
m_csMY.SetSuffix(buffer->SUFFIX, CALLSUFFIX_LEN);
|
||||
m_uiCrc = buffer->Crc;
|
||||
}
|
||||
|
||||
#ifndef NO_XLX
|
||||
// dmr constructor
|
||||
|
||||
CDvHeaderPacket::CDvHeaderPacket(uint32 my, const CCallsign &ur, const CCallsign &rpt1, const CCallsign &rpt2, uint16 sid, uint8 pid, uint8 spid)
|
||||
: CPacket(sid, pid, spid)
|
||||
{
|
||||
m_uiFlag1 = 0;
|
||||
m_uiFlag2 = 0;
|
||||
m_uiFlag3 = 0;
|
||||
m_uiCrc = 0;
|
||||
m_csUR = ur;
|
||||
m_csRPT1 = rpt1;
|
||||
m_csRPT2 = rpt2;
|
||||
m_csMY = CCallsign("", my);
|
||||
}
|
||||
|
||||
// YSF constructor
|
||||
|
||||
CDvHeaderPacket::CDvHeaderPacket(const CCallsign &my, const CCallsign &ur, const CCallsign &rpt1, const CCallsign &rpt2, uint16 sid, uint8 pid)
|
||||
: CPacket(sid, pid, 0, 0)
|
||||
{
|
||||
m_uiFlag1 = 0;
|
||||
m_uiFlag2 = 0;
|
||||
m_uiFlag3 = 0;
|
||||
m_uiCrc = 0;
|
||||
m_csUR = ur;
|
||||
m_csRPT1 = rpt1;
|
||||
m_csRPT2 = rpt2;
|
||||
m_csMY = my;
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// virtual duplication
|
||||
|
||||
std::unique_ptr<CPacket> CDvHeaderPacket::Duplicate(void) const
|
||||
{
|
||||
return std::unique_ptr<CPacket>(new CDvHeaderPacket(*this));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// conversion
|
||||
|
||||
void CDvHeaderPacket::ConvertToDstarStruct(struct dstar_header *buffer) const
|
||||
{
|
||||
::memset(buffer, 0, sizeof(struct dstar_header));
|
||||
buffer->Flag1 = m_uiFlag1;
|
||||
buffer->Flag2 = m_uiFlag2;
|
||||
buffer->Flag3 = m_uiFlag3;
|
||||
m_csUR.GetCallsign(buffer->UR);
|
||||
m_csRPT1.GetCallsign(buffer->RPT1);
|
||||
m_csRPT2.GetCallsign(buffer->RPT2);
|
||||
m_csMY.GetCallsign(buffer->MY);
|
||||
m_csMY.GetSuffix(buffer->SUFFIX);
|
||||
buffer->Crc = m_uiCrc;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// get valid
|
||||
|
||||
bool CDvHeaderPacket::IsValid(void) const
|
||||
{
|
||||
bool valid = CPacket::IsValid();
|
||||
|
||||
valid &= m_csRPT1.IsValid();
|
||||
valid &= m_csRPT2.IsValid();
|
||||
valid &= m_csMY.IsValid();
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operators
|
||||
|
||||
bool CDvHeaderPacket::operator ==(const CDvHeaderPacket &Header) const
|
||||
{
|
||||
return ( (m_uiFlag1 == Header.m_uiFlag1) &&
|
||||
(m_uiFlag2 == Header.m_uiFlag2) &&
|
||||
(m_uiFlag3 == Header.m_uiFlag3) &&
|
||||
(m_csUR == Header.m_csUR) &&
|
||||
(m_csRPT1 == Header.m_csRPT1) &&
|
||||
(m_csRPT2 == Header.m_csRPT2) &&
|
||||
(m_csMY == Header.m_csMY) );
|
||||
}
|
||||
|
||||
#ifdef IMPLEMENT_CDVHEADERPACKET_CONST_CHAR_OPERATOR
|
||||
CDvHeaderPacket::operator const char *() const
|
||||
{
|
||||
char *sz = (char *)(const char *)m_sz;
|
||||
|
||||
std::sprintf(sz, "%02X %02X %02X\n%s\n%s\n%s\n%s",
|
||||
m_uiFlag1, m_uiFlag2, m_uiFlag3,
|
||||
(const char *)m_csUR,
|
||||
(const char *)m_csRPT1,
|
||||
(const char *)m_csRPT2,
|
||||
(const char *)m_csMY);
|
||||
|
||||
return m_sz;
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,121 @@
|
||||
//
|
||||
// DVHeaderPacket.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 01/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdvheaderpacket_h
|
||||
#define cdvheaderpacket_h
|
||||
|
||||
#include "Callsign.h"
|
||||
#include "Packet.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// implementation details
|
||||
|
||||
//#define IMPLEMENT_CDVHEADERPACKET_CONST_CHAR_OPERATOR
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// typedef & structures
|
||||
|
||||
struct __attribute__ ((__packed__))dstar_header
|
||||
{
|
||||
// flags
|
||||
uint8 Flag1;
|
||||
uint8 Flag2;
|
||||
uint8 Flag3;
|
||||
// callsigns
|
||||
uint8 RPT2[CALLSIGN_LEN];
|
||||
uint8 RPT1[CALLSIGN_LEN];
|
||||
uint8 UR[CALLSIGN_LEN];
|
||||
uint8 MY[CALLSIGN_LEN];
|
||||
uint8 SUFFIX[CALLSUFFIX_LEN];
|
||||
// crc
|
||||
uint16 Crc;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDvHeaderPacket : public CPacket
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CDvHeaderPacket();
|
||||
CDvHeaderPacket(const struct dstar_header *, uint16, uint8);
|
||||
#ifndef NO_XLX
|
||||
CDvHeaderPacket(uint32, const CCallsign &, const CCallsign &, const CCallsign &, uint16, uint8, uint8);
|
||||
CDvHeaderPacket(const CCallsign &, const CCallsign &, const CCallsign &, const CCallsign &, uint16, uint8);
|
||||
#endif
|
||||
|
||||
// virtual duplication
|
||||
std::unique_ptr<CPacket> Duplicate(void) const;
|
||||
|
||||
// identity
|
||||
bool IsDvHeader(void) const { return true; }
|
||||
|
||||
// conversion
|
||||
void ConvertToDstarStruct(struct dstar_header *) const;
|
||||
|
||||
// get valid
|
||||
bool IsValid(void) const;
|
||||
|
||||
// get callsigns
|
||||
const CCallsign &GetUrCallsign(void) const { return m_csUR; }
|
||||
const CCallsign &GetRpt1Callsign(void) const { return m_csRPT1; }
|
||||
const CCallsign &GetRpt2Callsign(void) const { return m_csRPT2; }
|
||||
const CCallsign &GetMyCallsign(void) const { return m_csMY; }
|
||||
|
||||
// get modules
|
||||
char GetUrModule(void) const { return m_csUR.GetModule(); }
|
||||
char GetRpt1Module(void) const { return m_csRPT1.GetModule(); }
|
||||
char GetRpt2Module(void) const { return m_csRPT2.GetModule(); }
|
||||
char GetMyModule(void) const { return m_csMY.GetModule(); }
|
||||
|
||||
// set callsigns
|
||||
void SetRpt2Callsign(const CCallsign &cs) { m_csRPT2 = cs; }
|
||||
void SetRpt2Module(char c) { m_csRPT2.SetModule(c); }
|
||||
|
||||
// operators
|
||||
bool operator ==(const CDvHeaderPacket &) const;
|
||||
#ifdef IMPLEMENT_CDVHEADERPACKET_CONST_CHAR_OPERATOR
|
||||
operator const char *() const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// data
|
||||
uint8 m_uiFlag1;
|
||||
uint8 m_uiFlag2;
|
||||
uint8 m_uiFlag3;
|
||||
CCallsign m_csUR;
|
||||
CCallsign m_csRPT1;
|
||||
CCallsign m_csRPT2;
|
||||
CCallsign m_csMY;
|
||||
uint16 m_uiCrc;
|
||||
#ifdef IMPLEMENT_CDVHEADERPACKET_CONST_CHAR_OPERATOR
|
||||
// buffer
|
||||
char m_sz[256];
|
||||
#endif
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cdvheaderpacket_h */
|
||||
@ -0,0 +1,83 @@
|
||||
//
|
||||
// cdvlastframepacket.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 03/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "DVLastFramePacket.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CDvLastFramePacket::CDvLastFramePacket()
|
||||
{
|
||||
}
|
||||
|
||||
// dstar constructor
|
||||
|
||||
CDvLastFramePacket::CDvLastFramePacket(const struct dstar_dvframe *DvFrame, uint16 sid, uint8 pid)
|
||||
: CDvFramePacket(DvFrame, sid, pid)
|
||||
{
|
||||
}
|
||||
|
||||
#ifndef NO_XLX
|
||||
// dmr constructor
|
||||
|
||||
CDvLastFramePacket::CDvLastFramePacket(const uint8 *ambe, const uint8 *sync, uint16 sid, uint8 pid, uint8 spid)
|
||||
: CDvFramePacket(ambe, sync, sid, pid, spid)
|
||||
{
|
||||
}
|
||||
|
||||
// dstar + dmr constructor
|
||||
|
||||
CDvLastFramePacket::CDvLastFramePacket
|
||||
(uint16 sid,
|
||||
uint8 dstarpid, const uint8 *dstarambe, const uint8 *dstardvdata,
|
||||
uint8 dmrpid, uint8 dprspid, const uint8 *dmrambe, const uint8 *dmrsync)
|
||||
: CDvFramePacket(sid, dstarpid, dstarambe, dstardvdata, dmrpid, dprspid, dmrambe, dmrsync)
|
||||
{
|
||||
}
|
||||
|
||||
// ysf constructor
|
||||
|
||||
CDvLastFramePacket::CDvLastFramePacket(const uint8 *ambe, uint16 sid, uint8 pid, uint8 spid, uint8 fid)
|
||||
: CDvFramePacket(ambe, sid, pid, spid, fid)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// copy constructor
|
||||
|
||||
CDvLastFramePacket::CDvLastFramePacket(const CDvLastFramePacket &DvFrame)
|
||||
: CDvFramePacket(DvFrame)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// virtual duplication
|
||||
|
||||
std::unique_ptr<CPacket> CDvLastFramePacket::Duplicate(void) const
|
||||
{
|
||||
return std::unique_ptr<CPacket>(new CDvLastFramePacket(*this));
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
//
|
||||
// DVLastFramePacket.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 03/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cdvlastframepacket_h
|
||||
#define cdvlastframepacket_h
|
||||
|
||||
|
||||
#include "DVFramePacket.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// defines
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CDvLastFramePacket : public CDvFramePacket
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CDvLastFramePacket();
|
||||
CDvLastFramePacket(const struct dstar_dvframe *, uint16, uint8);
|
||||
#ifndef NO_XLX
|
||||
CDvLastFramePacket(const uint8 *, const uint8 *, uint16, uint8, uint8);
|
||||
CDvLastFramePacket(const uint8 *, uint16, uint8, uint8, uint8);
|
||||
CDvLastFramePacket(uint16, uint8, const uint8 *, const uint8 *, uint8, uint8, const uint8 *, const uint8 *);
|
||||
#endif
|
||||
CDvLastFramePacket(const CDvLastFramePacket &);
|
||||
|
||||
// virtual duplication
|
||||
std::unique_ptr<CPacket> Duplicate(void) const;
|
||||
|
||||
// identity
|
||||
bool IsLastPacket(void) const { return true; }
|
||||
bool HasTranscodableAmbe(void) const { return false; }
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cdvlastframepacket_h */
|
||||
@ -0,0 +1,53 @@
|
||||
//
|
||||
// cg3client.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Marius Petrescu (YO2LOJ) on 03/06/2019.
|
||||
// Copyright © 2019 Marius Petrescu (YO2LOJ). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "G3Client.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructors
|
||||
|
||||
CG3Client::CG3Client()
|
||||
{
|
||||
}
|
||||
|
||||
CG3Client::CG3Client(const CCallsign &callsign, const CIp &ip, char reflectorModule)
|
||||
: CClient(callsign, ip, reflectorModule)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CG3Client::CG3Client(const CG3Client &client)
|
||||
: CClient(client)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// status
|
||||
|
||||
bool CG3Client::IsAlive(void) const
|
||||
{
|
||||
return (m_LastKeepaliveTime.DurationSinceNow() < G3_KEEPALIVE_TIMEOUT);
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
//
|
||||
// G3Client.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Marius Petrescu (YO2LOJ) on 03/06/2019.
|
||||
// Copyright © 2019 Marius Petrescu (YO2LOJ). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cg3client_h
|
||||
#define cg3client_h
|
||||
|
||||
#include "Client.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CG3Client : public CClient
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CG3Client();
|
||||
CG3Client(const CCallsign &, const CIp &, char = ' ');
|
||||
CG3Client(const CG3Client &);
|
||||
|
||||
// destructor
|
||||
virtual ~CG3Client() {};
|
||||
|
||||
// identity
|
||||
int GetProtocol(void) const { return PROTOCOL_G3; }
|
||||
const char *GetProtocolName(void) const { return "Terminal/AP"; }
|
||||
int GetCodec(void) const { return CODEC_AMBEPLUS; }
|
||||
bool IsNode(void) const { return true; }
|
||||
|
||||
// status
|
||||
bool IsAlive(void) const;
|
||||
|
||||
protected:
|
||||
// data
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cg3client_h */
|
||||
@ -0,0 +1,785 @@
|
||||
//
|
||||
// cg3protocol.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Marius Petrescu (YO2LOJ) on 03/06/2019.
|
||||
// Copyright © 2019 Marius Petrescu (YO2LOJ). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include "G3Client.h"
|
||||
#include "G3Protocol.h"
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operation
|
||||
|
||||
bool CG3Protocol::Initialize(const char */*type*/, const int /*type*/, const uint16 /*port*/, const bool /*has_ipv4*/, const bool /*has_ipv6*/)
|
||||
// everything is hard coded until ICOM gets their act together and start supporting IPv6
|
||||
{
|
||||
ReadOptions();
|
||||
|
||||
// init reflector apparent callsign
|
||||
m_ReflectorCallsign = g_Reflector.GetCallsign();
|
||||
|
||||
// reset stop flag
|
||||
keep_running = true;
|
||||
|
||||
// update the reflector callsign
|
||||
//m_ReflectorCallsign.PatchCallsign(0, (const uint8 *)"XLX", 3);
|
||||
|
||||
// create our sockets
|
||||
auto s = g_Reflector.m_Address.GetV4Address(PROTOCOL_G3);
|
||||
CIp ip(AF_INET, G3_DV_PORT, s.c_str());
|
||||
if ( ip.IsSet() )
|
||||
{
|
||||
if (! m_Socket4.Open(ip))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
std::cout << "Listening on " << ip << std::endl;
|
||||
|
||||
//create helper socket
|
||||
ip.SetPort(G3_PRESENCE_PORT);
|
||||
if (! m_PresenceSocket.Open(ip))
|
||||
{
|
||||
std::cerr << "Error opening socket on port UDP" << G3_PRESENCE_PORT << " on ip " << ip << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
ip.SetPort(G3_CONFIG_PORT);
|
||||
if (! m_ConfigSocket.Open(ip))
|
||||
{
|
||||
std::cerr << "Error opening G3 config socket on port UDP" << G3_CONFIG_PORT << " on ip " << ip << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! m_IcmpRawSocket.Open(IPPROTO_ICMP))
|
||||
{
|
||||
std::cerr << "Error opening raw socket for ICMP" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// start helper threads
|
||||
m_Future = std::async(std::launch::async, &CG3Protocol::Thread, this);
|
||||
m_PresenceFuture = std::async(std::launch::async, &CG3Protocol::PresenceThread, this);
|
||||
m_ConfigFuture = std::async(std::launch::async, &CG3Protocol::ConfigThread, this);
|
||||
m_IcmpFuture = std::async(std::launch::async, &CG3Protocol::IcmpThread, this);
|
||||
|
||||
// update time
|
||||
m_LastKeepaliveTime.Now();
|
||||
|
||||
std::cout << "Initialized G3 Protocol, all threads started" << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
void CG3Protocol::Close(void)
|
||||
{
|
||||
if (m_PresenceFuture.valid())
|
||||
{
|
||||
m_PresenceFuture.get();
|
||||
}
|
||||
|
||||
if (m_ConfigFuture.valid())
|
||||
{
|
||||
m_ConfigFuture.get();
|
||||
}
|
||||
|
||||
if (m_IcmpFuture.valid())
|
||||
{
|
||||
m_IcmpFuture.get();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// private threads
|
||||
|
||||
void CG3Protocol::PresenceThread()
|
||||
{
|
||||
while (keep_running)
|
||||
{
|
||||
PresenceTask();
|
||||
}
|
||||
}
|
||||
|
||||
void CG3Protocol::ConfigThread()
|
||||
{
|
||||
while (keep_running)
|
||||
{
|
||||
ConfigTask();
|
||||
}
|
||||
}
|
||||
|
||||
void CG3Protocol::IcmpThread()
|
||||
{
|
||||
while (keep_running)
|
||||
{
|
||||
IcmpTask();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// presence task
|
||||
|
||||
void CG3Protocol::PresenceTask(void)
|
||||
{
|
||||
CBuffer Buffer;
|
||||
CIp ReqIp;
|
||||
CCallsign Callsign;
|
||||
CCallsign Owner;
|
||||
CCallsign Terminal;
|
||||
|
||||
|
||||
if ( m_PresenceSocket.Receive(Buffer, ReqIp, 20) )
|
||||
{
|
||||
|
||||
CIp Ip(ReqIp);
|
||||
Ip.SetPort(G3_DV_PORT);
|
||||
|
||||
if (Buffer.size() == 32)
|
||||
{
|
||||
Callsign.SetCallsign(&Buffer.data()[8], 8);
|
||||
Owner.SetCallsign(&Buffer.data()[16], 8);
|
||||
Terminal.SetCallsign(&Buffer.data()[24], 8);
|
||||
|
||||
std::cout << "Presence from owner " << Owner << " on " << Ip << " as " << Callsign << " on terminal " << Terminal << std::endl;
|
||||
|
||||
// accept
|
||||
Buffer.data()[2] = 0x80; // response
|
||||
Buffer.data()[3] = 0x00; // ok
|
||||
|
||||
if (m_GwAddress == 0)
|
||||
{
|
||||
Buffer.Append(*(uint32 *)m_ConfigSocket.GetLocalAddr());
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.Append(m_GwAddress);
|
||||
}
|
||||
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>extant = nullptr;
|
||||
while ( (extant = clients->FindNextClient(PROTOCOL_G3, it)) != nullptr )
|
||||
{
|
||||
CIp ClIp = extant->GetIp();
|
||||
if (ClIp.GetAddr() == Ip.GetAddr())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (extant == nullptr)
|
||||
{
|
||||
it = clients->begin();
|
||||
|
||||
// do we already have a client with the same call (IP changed)?
|
||||
while ( (extant = clients->FindNextClient(PROTOCOL_G3, it)) != nullptr )
|
||||
{
|
||||
if (extant->GetCallsign().HasSameCallsign(Terminal))
|
||||
{
|
||||
//delete old client
|
||||
clients->RemoveClient(extant);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// create new client and append
|
||||
clients->AddClient(std::make_shared<CG3Client>(Terminal, Ip));
|
||||
}
|
||||
else
|
||||
{
|
||||
// client changed callsign
|
||||
if (!extant->GetCallsign().HasSameCallsign(Terminal))
|
||||
{
|
||||
//delete old client
|
||||
clients->RemoveClient(extant);
|
||||
|
||||
// create new client and append
|
||||
clients->AddClient(std::make_shared<CG3Client>(Terminal, Ip));
|
||||
}
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
|
||||
m_PresenceSocket.Send(Buffer, ReqIp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// configuration task
|
||||
|
||||
void CG3Protocol::ConfigTask(void)
|
||||
{
|
||||
CBuffer Buffer;
|
||||
CIp Ip;
|
||||
CCallsign Call;
|
||||
bool isRepeaterCall;
|
||||
|
||||
if ( m_ConfigSocket.Receive(&Buffer, &Ip, 20) != -1 )
|
||||
{
|
||||
if (Buffer.size() == 16)
|
||||
{
|
||||
if (memcmp(&Buffer.data()[8], " ", 8) == 0)
|
||||
{
|
||||
Call.SetCallsign(GetReflectorCallsign(), 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
Call.SetCallsign(&Buffer.data()[8], 8);
|
||||
}
|
||||
|
||||
isRepeaterCall = ((Buffer.data()[2] & 0x10) == 0x10);
|
||||
|
||||
std::cout << "Config request from " << Ip << " for " << Call << " (" << ((char *)(isRepeaterCall)?"repeater":"routed") << ")" << std::endl;
|
||||
|
||||
//std::cout << "Local address: " << inet_ntoa(*m_ConfigSocket.GetLocalAddr()) << std::endl;
|
||||
|
||||
Buffer.data()[2] |= 0x80; // response
|
||||
|
||||
if (isRepeaterCall)
|
||||
{
|
||||
if ((Call.HasSameCallsign(GetReflectorCallsign())) && (g_Reflector.IsValidModule(Call.GetModule())))
|
||||
{
|
||||
Buffer.data()[3] = 0x00; // ok
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Module " << Call << " invalid" << std::endl;
|
||||
Buffer.data()[3] = 0x01; // reject
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// reject routed calls for now
|
||||
Buffer.data()[3] = 0x01; // reject
|
||||
}
|
||||
|
||||
char module = Call.GetModule();
|
||||
|
||||
if (!strchr(m_Modules.c_str(), module) && !strchr(m_Modules.c_str(), '*'))
|
||||
{
|
||||
// restricted
|
||||
std::cout << "Module " << Call << " restricted by configuration" << std::endl;
|
||||
Buffer.data()[3] = 0x01; // reject
|
||||
}
|
||||
|
||||
// UR
|
||||
Buffer.resize(8);
|
||||
Buffer.Append((uint8 *)(const char *)Call, CALLSIGN_LEN - 1);
|
||||
Buffer.Append((uint8)module);
|
||||
|
||||
// RPT1
|
||||
Buffer.Append((uint8 *)(const char *)GetReflectorCallsign(), CALLSIGN_LEN - 1);
|
||||
Buffer.Append((uint8)'G');
|
||||
|
||||
// RPT2
|
||||
Buffer.Append((uint8 *)(const char *)GetReflectorCallsign(), CALLSIGN_LEN - 1);
|
||||
|
||||
if (isRepeaterCall)
|
||||
{
|
||||
Buffer.Append((uint8)Call.GetModule());
|
||||
}
|
||||
else
|
||||
{
|
||||
// routed - no module for now
|
||||
Buffer.Append((uint8)' ');
|
||||
}
|
||||
|
||||
if (Buffer.data()[3] == 0x00)
|
||||
{
|
||||
std::cout << "External G3 gateway address " << inet_ntoa(*(in_addr *)&m_GwAddress) << std::endl;
|
||||
|
||||
if (m_GwAddress == 0)
|
||||
{
|
||||
Buffer.Append(*(uint32 *)m_ConfigSocket.GetLocalAddr());
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.Append(m_GwAddress);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.Append(0u);
|
||||
}
|
||||
|
||||
m_ConfigSocket.Send(Buffer, Ip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// icmp task
|
||||
|
||||
void CG3Protocol::IcmpTask(void)
|
||||
{
|
||||
uint8_t Buffer[RAW_BUFFER_LENMAX];
|
||||
CIp Ip;
|
||||
int iIcmpType;
|
||||
|
||||
if ((iIcmpType = m_IcmpRawSocket.IcmpReceive(Buffer, &Ip, 20)) != -1)
|
||||
{
|
||||
if (iIcmpType == ICMP_DEST_UNREACH)
|
||||
{
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_G3, it)) != nullptr )
|
||||
{
|
||||
CIp ClientIp = client->GetIp();
|
||||
if (ClientIp.GetAddr() == Ip.GetAddr())
|
||||
{
|
||||
clients->RemoveClient(client);
|
||||
}
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DV task
|
||||
|
||||
void CG3Protocol::Task(void)
|
||||
{
|
||||
CBuffer Buffer;
|
||||
CIp Ip;
|
||||
CCallsign Callsign;
|
||||
char ToLinkModule;
|
||||
int ProtRev;
|
||||
std::unique_ptr<CDvHeaderPacket> Header;
|
||||
std::unique_ptr<CDvFramePacket> Frame;
|
||||
std::unique_ptr<CDvLastFramePacket> LastFrame;
|
||||
|
||||
// any incoming packet ?
|
||||
if ( m_Socket4.Receive(Buffer, Ip, 20) )
|
||||
{
|
||||
CIp ClIp;
|
||||
CIp *BaseIp = nullptr;
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_G3, it)) != nullptr )
|
||||
{
|
||||
ClIp = client->GetIp();
|
||||
if (ClIp.GetAddr() == Ip.GetAddr())
|
||||
{
|
||||
BaseIp = &ClIp;
|
||||
client->Alive();
|
||||
// supress host checks - no ping needed to trigger potential ICMPs
|
||||
// the regular data flow will do it
|
||||
m_LastKeepaliveTime.Now();
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
|
||||
if (BaseIp != nullptr)
|
||||
{
|
||||
// crack the packet
|
||||
if ( IsValidDvFramePacket(Buffer, Frame) )
|
||||
{
|
||||
OnDvFramePacketIn(Frame, BaseIp);
|
||||
}
|
||||
else if ( IsValidDvHeaderPacket(Buffer, Header) )
|
||||
{
|
||||
// callsign muted?
|
||||
if ( g_GateKeeper.MayTransmit(Header->GetMyCallsign(), Ip, PROTOCOL_G3, Header->GetRpt2Module()) )
|
||||
{
|
||||
// handle it
|
||||
OnDvHeaderPacketIn(Header, *BaseIp);
|
||||
}
|
||||
}
|
||||
else if ( IsValidDvLastFramePacket(Buffer, LastFrame) )
|
||||
{
|
||||
OnDvLastFramePacketIn(LastFrame, BaseIp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle end of streaming timeout
|
||||
CheckStreamsTimeout();
|
||||
|
||||
// handle queue from reflector
|
||||
HandleQueue();
|
||||
|
||||
// keep alive during idle if needed
|
||||
if ( m_LastKeepaliveTime.DurationSinceNow() > G3_KEEPALIVE_PERIOD )
|
||||
{
|
||||
// handle keep alives
|
||||
HandleKeepalives();
|
||||
|
||||
// update time
|
||||
m_LastKeepaliveTime.Now();
|
||||
|
||||
// reload option if needed - called once every G3_KEEPALIVE_PERIOD
|
||||
NeedReload();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// queue helper
|
||||
|
||||
void CG3Protocol::HandleQueue(void)
|
||||
{
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
{
|
||||
// supress host checks
|
||||
m_LastKeepaliveTime.Now();
|
||||
|
||||
// get the packet
|
||||
auto packet = m_Queue.front();
|
||||
m_Queue.pop();
|
||||
|
||||
// encode it
|
||||
CBuffer buffer;
|
||||
if ( EncodeDvPacket(*packet, &buffer) )
|
||||
{
|
||||
// and push it to all our clients linked to the module and who are not streaming in
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_G3, it)) != nullptr )
|
||||
{
|
||||
// is this client busy ?
|
||||
if ( !client->IsAMaster() && (client->GetReflectorModule() == packet->GetModuleId()) )
|
||||
{
|
||||
// not busy, send the packet
|
||||
int n = packet->IsDvHeader() ? 5 : 1;
|
||||
for ( int i = 0; i < n; i++ )
|
||||
{
|
||||
Send(buffer, client->GetIp());
|
||||
}
|
||||
}
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// keepalive helpers
|
||||
|
||||
void CG3Protocol::HandleKeepalives(void)
|
||||
{
|
||||
// G3 Terminal mode does not support keepalive
|
||||
// We will send some short packed and expect
|
||||
// A ICMP unreachable on failure
|
||||
CBuffer keepalive((uint8 *)"PING", 4);
|
||||
|
||||
// iterate on clients
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_G3, it)) != nullptr )
|
||||
{
|
||||
if (!client->IsAlive())
|
||||
{
|
||||
clients->RemoveClient(client);
|
||||
}
|
||||
else
|
||||
{
|
||||
// send keepalive packet
|
||||
Send(keepalive, client->GetIp());
|
||||
}
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// streams helpers
|
||||
|
||||
void CG3Protocol::OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &Header, const CIp &Ip)
|
||||
{
|
||||
// find the stream
|
||||
CPacketStream *stream = GetStream(Header->GetStreamId(), &Ip);
|
||||
|
||||
if ( stream )
|
||||
{
|
||||
// stream already open
|
||||
// skip packet, but tickle the stream
|
||||
stream->Tickle();
|
||||
}
|
||||
else
|
||||
{
|
||||
// no stream open yet, open a new one
|
||||
CCallsign my(Header->GetMyCallsign());
|
||||
CCallsign rpt1(Header->GetRpt1Callsign());
|
||||
CCallsign rpt2(Header->GetRpt2Callsign());
|
||||
|
||||
// find this client
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_G3, it)) != nullptr )
|
||||
{
|
||||
CIp ClIp = client->GetIp();
|
||||
if (ClIp.GetAddr() == Ip.GetAddr())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( client )
|
||||
{
|
||||
|
||||
// move it to the proper module
|
||||
if (m_ReflectorCallsign.HasSameCallsign(rpt2))
|
||||
{
|
||||
if (client->GetReflectorModule() != rpt2.GetModule())
|
||||
{
|
||||
auto new_module = rpt2.GetModule();
|
||||
if (strchr(m_Modules.c_str(), '*') || strchr(m_Modules.c_str(), new_module))
|
||||
{
|
||||
client->SetReflectorModule(new_module);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_Reflector.ReleaseClients();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// get client callsign
|
||||
rpt1 = client->GetCallsign();
|
||||
|
||||
// and try to open the stream
|
||||
if ( (stream = g_Reflector.OpenStream(Header, client)) != nullptr )
|
||||
{
|
||||
// keep the handle
|
||||
m_Streams.push_back(stream);
|
||||
}
|
||||
|
||||
// update last heard
|
||||
g_Reflector.GetUsers()->Hearing(my, rpt1, rpt2);
|
||||
g_Reflector.ReleaseUsers();
|
||||
}
|
||||
}
|
||||
// release
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// packet decoding helpers
|
||||
|
||||
bool CG3Protocol::IsValidDvHeaderPacket(const CBuffer &Buffer, std::unique_ptr<CDvHeaderPacket> &header)
|
||||
{
|
||||
if ( 56==Buffer.size() && 0==Buffer.Compare((uint8 *)"DSVT", 4) && 0x10U==Buffer.data()[4] && 0x20U==Buffer.data()[8] )
|
||||
{
|
||||
// create packet
|
||||
header = std::unique_ptr<CDvHeaderPacket>(new CDvHeaderPacket((struct dstar_header *)&(Buffer.data()[15]), *((uint16 *)&(Buffer.data()[12])), 0x80));
|
||||
// check validity of packet
|
||||
if ( header && header->IsValid() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CG3Protocol::IsValidDvFramePacket(const CBuffer &Buffer, std::unique_ptr<CDvFramePacket> &dvframe)
|
||||
{
|
||||
if ( 27==Buffer.size() && 0==Buffer.Compare((uint8 *)"DSVT", 4) && 0x20U==Buffer.data()[4] && 0x20U==Buffer.data()[8] && 0U==(Buffer.data()[14] & 0x40U) )
|
||||
{
|
||||
// create packet
|
||||
dvframe = std::unique_ptr<CDvFramePacket>(new CDvFramePacket((struct dstar_dvframe *)&(Buffer.data()[15]), *((uint16 *)&(Buffer.data()[12])), Buffer.data()[14]));
|
||||
// check validity of packet
|
||||
if ( dvframe && dvframe->IsValid() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CG3Protocol::IsValidDvLastFramePacket(const CBuffer &Buffer, std::unique_ptr<CDvLastFramePacket> &dvframe)
|
||||
{
|
||||
if ( 27==Buffer.size() && 0==Buffer.Compare((uint8 *)"DSVT", 4) && 0x20U==Buffer.data()[4] && 0x20U==Buffer.data()[8] && (Buffer.data()[14] & 0x40U) )
|
||||
{
|
||||
// create packet
|
||||
dvframe = std::unique_ptr<CDvLastFramePacket>(new CDvLastFramePacket((struct dstar_dvframe *)&(Buffer.data()[15]), *((uint16 *)&(Buffer.data()[12])), Buffer.data()[14]));
|
||||
// check validity of packet
|
||||
if ( dvframe && dvframe->IsValid() )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// packet encoding helpers
|
||||
|
||||
bool CG3Protocol::EncodeDvHeaderPacket(const CDvHeaderPacket &Packet, CBuffer *Buffer) const
|
||||
{
|
||||
uint8 tag[] = { 'D','S','V','T',0x10,0x00,0x00,0x00,0x20,0x00,0x01,0x02 };
|
||||
struct dstar_header DstarHeader;
|
||||
|
||||
Packet.ConvertToDstarStruct(&DstarHeader);
|
||||
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
Buffer->Append(Packet.GetStreamId());
|
||||
Buffer->Append((uint8)0x80);
|
||||
Buffer->Append((uint8 *)&DstarHeader, sizeof(struct dstar_header));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CG3Protocol::EncodeDvFramePacket(const CDvFramePacket &Packet, CBuffer *Buffer) const
|
||||
{
|
||||
uint8 tag[] = { 'D','S','V','T',0x20,0x00,0x00,0x00,0x20,0x00,0x01,0x02 };
|
||||
|
||||
Buffer->Set(tag, sizeof(tag));
|
||||
Buffer->Append(Packet.GetStreamId());
|
||||
Buffer->Append((uint8)(Packet.GetPacketId() % 21));
|
||||
Buffer->Append((uint8 *)Packet.GetAmbe(), AMBE_SIZE);
|
||||
Buffer->Append((uint8 *)Packet.GetDvData(), DVDATA_SIZE);
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool CG3Protocol::EncodeDvLastFramePacket(const CDvLastFramePacket &Packet, CBuffer *Buffer) const
|
||||
{
|
||||
uint8 tag1[] = { 'D','S','V','T',0x20,0x00,0x00,0x00,0x20,0x00,0x01,0x02 };
|
||||
uint8 tag2[] = { 0x55,0xC8,0x7A,0x00,0x00,0x00,0x00,0x00,0x00,0x25,0x1A,0xC6 };
|
||||
|
||||
Buffer->Set(tag1, sizeof(tag1));
|
||||
Buffer->Append(Packet.GetStreamId());
|
||||
Buffer->Append((uint8)((Packet.GetPacketId() % 21) | 0x40));
|
||||
Buffer->Append(tag2, sizeof(tag2));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// option helpers
|
||||
|
||||
char *CG3Protocol::TrimWhiteSpaces(char *str)
|
||||
{
|
||||
char *end;
|
||||
while ((*str == ' ') || (*str == '\t')) str++;
|
||||
if (*str == 0)
|
||||
return str;
|
||||
end = str + strlen(str) - 1;
|
||||
while ((end > str) && ((*end == ' ') || (*end == '\t') || (*end == '\r')))
|
||||
end--;
|
||||
*(end + 1) = 0;
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
void CG3Protocol::NeedReload(void)
|
||||
{
|
||||
struct stat fileStat;
|
||||
|
||||
if (::stat(TERMINALOPTIONS_PATH, &fileStat) != -1)
|
||||
{
|
||||
if (m_LastModTime != fileStat.st_mtime)
|
||||
{
|
||||
ReadOptions();
|
||||
|
||||
// we have new options - iterate on clients for potential removal
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
auto it = clients->begin();
|
||||
std::shared_ptr<CClient>client = nullptr;
|
||||
while ( (client = clients->FindNextClient(PROTOCOL_G3, it)) != nullptr )
|
||||
{
|
||||
char module = client->GetReflectorModule();
|
||||
if (!strchr(m_Modules.c_str(), module) && !strchr(m_Modules.c_str(), '*'))
|
||||
{
|
||||
clients->RemoveClient(client);
|
||||
}
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CG3Protocol::ReadOptions(void)
|
||||
{
|
||||
char sz[256];
|
||||
int opts = 0;
|
||||
|
||||
|
||||
std::ifstream file(TERMINALOPTIONS_PATH);
|
||||
if (file.is_open())
|
||||
{
|
||||
m_GwAddress = 0u;
|
||||
m_Modules = "*";
|
||||
|
||||
while (file.getline(sz, sizeof(sz)).good())
|
||||
{
|
||||
char *szt = TrimWhiteSpaces(sz);
|
||||
char *szval;
|
||||
|
||||
if ((::strlen(szt) > 0) && szt[0] != '#')
|
||||
{
|
||||
if ((szt = ::strtok(szt, " ,\t")) != nullptr)
|
||||
{
|
||||
if ((szval = ::strtok(nullptr, " ,\t")) != nullptr)
|
||||
{
|
||||
if (::strncmp(szt, "address", 7) == 0)
|
||||
{
|
||||
in_addr addr = { .s_addr = inet_addr(szval) };
|
||||
if (addr.s_addr)
|
||||
{
|
||||
std::cout << "G3 handler address set to " << inet_ntoa(addr) << std::endl;
|
||||
m_GwAddress = addr.s_addr;
|
||||
opts++;
|
||||
}
|
||||
}
|
||||
else if (strncmp(szt, "modules", 7) == 0)
|
||||
{
|
||||
std::cout << "G3 handler module list set to " << szval << std::endl;
|
||||
m_Modules = szval;
|
||||
opts++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unknown option - ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "G3 handler loaded " << opts << " options from file " << TERMINALOPTIONS_PATH << std::endl;
|
||||
file.close();
|
||||
|
||||
struct stat fileStat;
|
||||
|
||||
if (::stat(TERMINALOPTIONS_PATH, &fileStat) != -1)
|
||||
{
|
||||
m_LastModTime = fileStat.st_mtime;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,133 @@
|
||||
//
|
||||
// G3Protocol.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Marius Petrescu (YO2LOJ) on 03/06/2019.
|
||||
// Copyright © 2019 Marius Petrescu (YO2LOJ). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cg3protocol_h
|
||||
#define cg3protocol_h
|
||||
|
||||
#include <string>
|
||||
#include "Timer.h"
|
||||
#include "DCSProtocol.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
#include "DVFramePacket.h"
|
||||
#include "DVLastFramePacket.h"
|
||||
#include "RawSocket.h"
|
||||
#include "UDPMsgSocket.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// note on the G3 terminal/AP protocol:
|
||||
//
|
||||
// There are 3 steps in handling an incoming connection
|
||||
//
|
||||
// 1 - Notification of terminal call on port UDP 12346, Presence port, a CUdpSocket.
|
||||
// - Call will be rejected if in blacklisted
|
||||
//
|
||||
// 2 - Destination request on port UDP 12345, Config port, a CUdpMsgSocket.
|
||||
// - Calls to specific callsigns will be accepted for a default module
|
||||
// - Repeater calls will be accepted for local modules
|
||||
// - All other calls are rejected
|
||||
//
|
||||
// 3 - Actual D-star flow like in Dextra to/from port 40000
|
||||
// 2 distinct sockets where used in the initial protocol
|
||||
// later firmwares implement a single bidirectional socket
|
||||
//
|
||||
// Alive monitoring is done via a "PING" to remote port 40000. We will get an
|
||||
// ICMP unreachable on terminal mode close or on station shut down if routing is done
|
||||
// correctly. Otherwise a long timeout is used (e.g. 1h)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CG3Protocol : public CProtocol
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CG3Protocol() : m_GwAddress(0u), m_Modules("*"), m_LastModTime(0) {}
|
||||
|
||||
// initialization
|
||||
bool Initialize(const char *type, const int ptype, const uint16 port, const bool has_ipv4, const bool has_ipv6);
|
||||
|
||||
// close
|
||||
void Close(void);
|
||||
|
||||
// task
|
||||
void Task(void);
|
||||
|
||||
protected:
|
||||
// threads
|
||||
void PresenceThread(void);
|
||||
void ConfigThread(void);
|
||||
void IcmpThread(void);
|
||||
|
||||
// helper tasks
|
||||
void PresenceTask(void);
|
||||
void ConfigTask(void);
|
||||
void IcmpTask(void);
|
||||
|
||||
// config
|
||||
void ReadOptions(void);
|
||||
|
||||
// helper
|
||||
char *TrimWhiteSpaces(char *);
|
||||
void NeedReload(void);
|
||||
|
||||
// queue helper
|
||||
void HandleQueue(void);
|
||||
|
||||
// keepalive helpers
|
||||
void HandleKeepalives(void);
|
||||
|
||||
// stream helpers
|
||||
void OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &, const CIp &);
|
||||
|
||||
// packet decoding helpers
|
||||
bool IsValidDvHeaderPacket(const CBuffer &, std::unique_ptr<CDvHeaderPacket> &);
|
||||
bool IsValidDvFramePacket(const CBuffer &, std::unique_ptr<CDvFramePacket> &);
|
||||
bool IsValidDvLastFramePacket(const CBuffer &, std::unique_ptr<CDvLastFramePacket> &);
|
||||
|
||||
// packet encoding helpers
|
||||
bool EncodeDvHeaderPacket(const CDvHeaderPacket &, CBuffer *) const;
|
||||
bool EncodeDvFramePacket(const CDvFramePacket &, CBuffer *) const;
|
||||
bool EncodeDvLastFramePacket(const CDvLastFramePacket &, CBuffer *) const;
|
||||
|
||||
protected:
|
||||
std::future<void> m_PresenceFuture, m_ConfigFuture, m_IcmpFuture;
|
||||
|
||||
// time
|
||||
CTimePoint m_LastKeepaliveTime;
|
||||
|
||||
// sockets
|
||||
CUdpSocket m_PresenceSocket;
|
||||
CUdpMsgSocket m_ConfigSocket;
|
||||
CRawSocket m_IcmpRawSocket;
|
||||
|
||||
// optional params
|
||||
uint32 m_GwAddress;
|
||||
std::string m_Modules;
|
||||
time_t m_LastModTime;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cg3protocol_h */
|
||||
@ -0,0 +1,80 @@
|
||||
//
|
||||
// GateKeeper.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 07/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cgatekeeper_h
|
||||
#define cgatekeeper_h
|
||||
|
||||
#include "Main.h"
|
||||
#include "Callsign.h"
|
||||
#include "IP.h"
|
||||
#include "CallsignList.h"
|
||||
#include "PeerCallsignList.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CGateKeeper
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CGateKeeper();
|
||||
|
||||
// destructor
|
||||
virtual ~CGateKeeper();
|
||||
|
||||
// init & clode
|
||||
bool Init(void);
|
||||
void Close(void);
|
||||
|
||||
// authorizations
|
||||
bool MayLink(const CCallsign &, const CIp &, int, char * = nullptr) const;
|
||||
bool MayTransmit(const CCallsign &, const CIp &, int = PROTOCOL_ANY, char = ' ') const;
|
||||
|
||||
// peer list handeling
|
||||
CPeerCallsignList *GetPeerList(void) { m_PeerList.Lock(); return &m_PeerList; }
|
||||
void ReleasePeerList(void) { m_PeerList.Unlock(); }
|
||||
|
||||
protected:
|
||||
// thread
|
||||
void Thread();
|
||||
|
||||
// operation helpers
|
||||
bool IsNodeListedOk(const CCallsign &, const CIp &, char = ' ') const;
|
||||
bool IsPeerListedOk(const CCallsign &, const CIp &, char) const;
|
||||
bool IsPeerListedOk(const CCallsign &, const CIp &, char *) const;
|
||||
|
||||
protected:
|
||||
// data
|
||||
CCallsignList m_NodeWhiteList;
|
||||
CCallsignList m_NodeBlackList;
|
||||
CPeerCallsignList m_PeerList;
|
||||
|
||||
// thread
|
||||
std::atomic<bool> keep_running;
|
||||
std::future<void> m_Future;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cgatekeeper_h */
|
||||
@ -0,0 +1,268 @@
|
||||
/*
|
||||
* 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 "Golay2087.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
const unsigned int ENCODING_TABLE_2087[] =
|
||||
{
|
||||
0x0000U, 0xB08EU, 0xE093U, 0x501DU, 0x70A9U, 0xC027U, 0x903AU, 0x20B4U, 0x60DCU, 0xD052U, 0x804FU, 0x30C1U,
|
||||
0x1075U, 0xA0FBU, 0xF0E6U, 0x4068U, 0x7036U, 0xC0B8U, 0x90A5U, 0x202BU, 0x009FU, 0xB011U, 0xE00CU, 0x5082U,
|
||||
0x10EAU, 0xA064U, 0xF079U, 0x40F7U, 0x6043U, 0xD0CDU, 0x80D0U, 0x305EU, 0xD06CU, 0x60E2U, 0x30FFU, 0x8071U,
|
||||
0xA0C5U, 0x104BU, 0x4056U, 0xF0D8U, 0xB0B0U, 0x003EU, 0x5023U, 0xE0ADU, 0xC019U, 0x7097U, 0x208AU, 0x9004U,
|
||||
0xA05AU, 0x10D4U, 0x40C9U, 0xF047U, 0xD0F3U, 0x607DU, 0x3060U, 0x80EEU, 0xC086U, 0x7008U, 0x2015U, 0x909BU,
|
||||
0xB02FU, 0x00A1U, 0x50BCU, 0xE032U, 0x90D9U, 0x2057U, 0x704AU, 0xC0C4U, 0xE070U, 0x50FEU, 0x00E3U, 0xB06DU,
|
||||
0xF005U, 0x408BU, 0x1096U, 0xA018U, 0x80ACU, 0x3022U, 0x603FU, 0xD0B1U, 0xE0EFU, 0x5061U, 0x007CU, 0xB0F2U,
|
||||
0x9046U, 0x20C8U, 0x70D5U, 0xC05BU, 0x8033U, 0x30BDU, 0x60A0U, 0xD02EU, 0xF09AU, 0x4014U, 0x1009U, 0xA087U,
|
||||
0x40B5U, 0xF03BU, 0xA026U, 0x10A8U, 0x301CU, 0x8092U, 0xD08FU, 0x6001U, 0x2069U, 0x90E7U, 0xC0FAU, 0x7074U,
|
||||
0x50C0U, 0xE04EU, 0xB053U, 0x00DDU, 0x3083U, 0x800DU, 0xD010U, 0x609EU, 0x402AU, 0xF0A4U, 0xA0B9U, 0x1037U,
|
||||
0x505FU, 0xE0D1U, 0xB0CCU, 0x0042U, 0x20F6U, 0x9078U, 0xC065U, 0x70EBU, 0xA03DU, 0x10B3U, 0x40AEU, 0xF020U,
|
||||
0xD094U, 0x601AU, 0x3007U, 0x8089U, 0xC0E1U, 0x706FU, 0x2072U, 0x90FCU, 0xB048U, 0x00C6U, 0x50DBU, 0xE055U,
|
||||
0xD00BU, 0x6085U, 0x3098U, 0x8016U, 0xA0A2U, 0x102CU, 0x4031U, 0xF0BFU, 0xB0D7U, 0x0059U, 0x5044U, 0xE0CAU,
|
||||
0xC07EU, 0x70F0U, 0x20EDU, 0x9063U, 0x7051U, 0xC0DFU, 0x90C2U, 0x204CU, 0x00F8U, 0xB076U, 0xE06BU, 0x50E5U,
|
||||
0x108DU, 0xA003U, 0xF01EU, 0x4090U, 0x6024U, 0xD0AAU, 0x80B7U, 0x3039U, 0x0067U, 0xB0E9U, 0xE0F4U, 0x507AU,
|
||||
0x70CEU, 0xC040U, 0x905DU, 0x20D3U, 0x60BBU, 0xD035U, 0x8028U, 0x30A6U, 0x1012U, 0xA09CU, 0xF081U, 0x400FU,
|
||||
0x30E4U, 0x806AU, 0xD077U, 0x60F9U, 0x404DU, 0xF0C3U, 0xA0DEU, 0x1050U, 0x5038U, 0xE0B6U, 0xB0ABU, 0x0025U,
|
||||
0x2091U, 0x901FU, 0xC002U, 0x708CU, 0x40D2U, 0xF05CU, 0xA041U, 0x10CFU, 0x307BU, 0x80F5U, 0xD0E8U, 0x6066U,
|
||||
0x200EU, 0x9080U, 0xC09DU, 0x7013U, 0x50A7U, 0xE029U, 0xB034U, 0x00BAU, 0xE088U, 0x5006U, 0x001BU, 0xB095U,
|
||||
0x9021U, 0x20AFU, 0x70B2U, 0xC03CU, 0x8054U, 0x30DAU, 0x60C7U, 0xD049U, 0xF0FDU, 0x4073U, 0x106EU, 0xA0E0U,
|
||||
0x90BEU, 0x2030U, 0x702DU, 0xC0A3U, 0xE017U, 0x5099U, 0x0084U, 0xB00AU, 0xF062U, 0x40ECU, 0x10F1U, 0xA07FU,
|
||||
0x80CBU, 0x3045U, 0x6058U, 0xD0D6U
|
||||
};
|
||||
|
||||
const unsigned int DECODING_TABLE_1987[] =
|
||||
{
|
||||
0x00000U, 0x00001U, 0x00002U, 0x00003U, 0x00004U, 0x00005U, 0x00006U, 0x00007U, 0x00008U, 0x00009U, 0x0000AU, 0x0000BU, 0x0000CU,
|
||||
0x0000DU, 0x0000EU, 0x24020U, 0x00010U, 0x00011U, 0x00012U, 0x00013U, 0x00014U, 0x00015U, 0x00016U, 0x00017U, 0x00018U, 0x00019U,
|
||||
0x0001AU, 0x0001BU, 0x0001CU, 0x0001DU, 0x48040U, 0x01480U, 0x00020U, 0x00021U, 0x00022U, 0x00023U, 0x00024U, 0x00025U, 0x00026U,
|
||||
0x24008U, 0x00028U, 0x00029U, 0x0002AU, 0x24004U, 0x0002CU, 0x24002U, 0x24001U, 0x24000U, 0x00030U, 0x00031U, 0x00032U, 0x08180U,
|
||||
0x00034U, 0x00C40U, 0x00036U, 0x00C42U, 0x00038U, 0x43000U, 0x0003AU, 0x43002U, 0x02902U, 0x24012U, 0x02900U, 0x24010U, 0x00040U,
|
||||
0x00041U, 0x00042U, 0x00043U, 0x00044U, 0x00045U, 0x00046U, 0x00047U, 0x00048U, 0x00049U, 0x0004AU, 0x02500U, 0x0004CU, 0x0004DU,
|
||||
0x48010U, 0x48011U, 0x00050U, 0x00051U, 0x00052U, 0x21200U, 0x00054U, 0x00C20U, 0x48008U, 0x48009U, 0x00058U, 0x00059U, 0x48004U,
|
||||
0x48005U, 0x48002U, 0x48003U, 0x48000U, 0x48001U, 0x00060U, 0x00061U, 0x00062U, 0x00063U, 0x00064U, 0x00C10U, 0x10300U, 0x0B000U,
|
||||
0x00068U, 0x00069U, 0x01880U, 0x01881U, 0x40181U, 0x40180U, 0x24041U, 0x24040U, 0x00070U, 0x00C04U, 0x00072U, 0x00C06U, 0x00C01U,
|
||||
0x00C00U, 0x00C03U, 0x00C02U, 0x05204U, 0x00C0CU, 0x48024U, 0x48025U, 0x05200U, 0x00C08U, 0x48020U, 0x48021U, 0x00080U, 0x00081U,
|
||||
0x00082U, 0x00083U, 0x00084U, 0x00085U, 0x00086U, 0x00087U, 0x00088U, 0x00089U, 0x0008AU, 0x50200U, 0x0008CU, 0x0A800U, 0x01411U,
|
||||
0x01410U, 0x00090U, 0x00091U, 0x00092U, 0x08120U, 0x00094U, 0x00095U, 0x04A00U, 0x01408U, 0x00098U, 0x00099U, 0x01405U, 0x01404U,
|
||||
0x01403U, 0x01402U, 0x01401U, 0x01400U, 0x000A0U, 0x000A1U, 0x000A2U, 0x08110U, 0x000A4U, 0x000A5U, 0x42400U, 0x42401U, 0x000A8U,
|
||||
0x000A9U, 0x01840U, 0x01841U, 0x40141U, 0x40140U, 0x24081U, 0x24080U, 0x000B0U, 0x08102U, 0x08101U, 0x08100U, 0x000B4U, 0x08106U,
|
||||
0x08105U, 0x08104U, 0x20A01U, 0x20A00U, 0x08109U, 0x08108U, 0x01423U, 0x01422U, 0x01421U, 0x01420U, 0x000C0U, 0x000C1U, 0x000C2U,
|
||||
0x000C3U, 0x000C4U, 0x000C5U, 0x000C6U, 0x000C7U, 0x000C8U, 0x000C9U, 0x01820U, 0x01821U, 0x20600U, 0x40120U, 0x16000U, 0x16001U,
|
||||
0x000D0U, 0x000D1U, 0x42801U, 0x42800U, 0x03100U, 0x18200U, 0x03102U, 0x18202U, 0x000D8U, 0x000D9U, 0x48084U, 0x01444U, 0x48082U,
|
||||
0x01442U, 0x48080U, 0x01440U, 0x000E0U, 0x32000U, 0x01808U, 0x04600U, 0x40109U, 0x40108U, 0x0180CU, 0x4010AU, 0x01802U, 0x40104U,
|
||||
0x01800U, 0x01801U, 0x40101U, 0x40100U, 0x01804U, 0x40102U, 0x0A408U, 0x08142U, 0x08141U, 0x08140U, 0x00C81U, 0x00C80U, 0x00C83U,
|
||||
0x00C82U, 0x0A400U, 0x0A401U, 0x01810U, 0x01811U, 0x40111U, 0x40110U, 0x01814U, 0x40112U, 0x00100U, 0x00101U, 0x00102U, 0x00103U,
|
||||
0x00104U, 0x00105U, 0x00106U, 0x41800U, 0x00108U, 0x00109U, 0x0010AU, 0x02440U, 0x0010CU, 0x0010DU, 0x0010EU, 0x02444U, 0x00110U,
|
||||
0x00111U, 0x00112U, 0x080A0U, 0x00114U, 0x00115U, 0x00116U, 0x080A4U, 0x00118U, 0x00119U, 0x15000U, 0x15001U, 0x02822U, 0x02823U,
|
||||
0x02820U, 0x02821U, 0x00120U, 0x00121U, 0x00122U, 0x08090U, 0x00124U, 0x00125U, 0x10240U, 0x10241U, 0x00128U, 0x00129U, 0x0012AU,
|
||||
0x24104U, 0x09400U, 0x400C0U, 0x02810U, 0x24100U, 0x00130U, 0x08082U, 0x08081U, 0x08080U, 0x31001U, 0x31000U, 0x02808U, 0x08084U,
|
||||
0x02806U, 0x0808AU, 0x02804U, 0x08088U, 0x02802U, 0x02803U, 0x02800U, 0x02801U, 0x00140U, 0x00141U, 0x00142U, 0x02408U, 0x00144U,
|
||||
0x00145U, 0x10220U, 0x10221U, 0x00148U, 0x02402U, 0x02401U, 0x02400U, 0x400A1U, 0x400A0U, 0x02405U, 0x02404U, 0x00150U, 0x00151U,
|
||||
0x00152U, 0x02418U, 0x03080U, 0x03081U, 0x03082U, 0x03083U, 0x09801U, 0x09800U, 0x02411U, 0x02410U, 0x48102U, 0x09804U, 0x48100U,
|
||||
0x48101U, 0x00160U, 0x00161U, 0x10204U, 0x10205U, 0x10202U, 0x40088U, 0x10200U, 0x10201U, 0x40085U, 0x40084U, 0x02421U, 0x02420U,
|
||||
0x40081U, 0x40080U, 0x10208U, 0x40082U, 0x41402U, 0x080C2U, 0x41400U, 0x080C0U, 0x00D01U, 0x00D00U, 0x10210U, 0x10211U, 0x40095U,
|
||||
0x40094U, 0x02844U, 0x080C8U, 0x40091U, 0x40090U, 0x02840U, 0x02841U, 0x00180U, 0x00181U, 0x00182U, 0x08030U, 0x00184U, 0x14400U,
|
||||
0x22201U, 0x22200U, 0x00188U, 0x00189U, 0x0018AU, 0x08038U, 0x40061U, 0x40060U, 0x40063U, 0x40062U, 0x00190U, 0x08022U, 0x08021U,
|
||||
0x08020U, 0x03040U, 0x03041U, 0x08025U, 0x08024U, 0x40C00U, 0x40C01U, 0x08029U, 0x08028U, 0x2C000U, 0x2C001U, 0x01501U, 0x01500U,
|
||||
0x001A0U, 0x08012U, 0x08011U, 0x08010U, 0x40049U, 0x40048U, 0x08015U, 0x08014U, 0x06200U, 0x40044U, 0x30400U, 0x08018U, 0x40041U,
|
||||
0x40040U, 0x40043U, 0x40042U, 0x08003U, 0x08002U, 0x08001U, 0x08000U, 0x08007U, 0x08006U, 0x08005U, 0x08004U, 0x0800BU, 0x0800AU,
|
||||
0x08009U, 0x08008U, 0x40051U, 0x40050U, 0x02880U, 0x0800CU, 0x001C0U, 0x001C1U, 0x64000U, 0x64001U, 0x03010U, 0x40028U, 0x08C00U,
|
||||
0x08C01U, 0x40025U, 0x40024U, 0x02481U, 0x02480U, 0x40021U, 0x40020U, 0x40023U, 0x40022U, 0x03004U, 0x03005U, 0x08061U, 0x08060U,
|
||||
0x03000U, 0x03001U, 0x03002U, 0x03003U, 0x0300CU, 0x40034U, 0x30805U, 0x30804U, 0x03008U, 0x40030U, 0x30801U, 0x30800U, 0x4000DU,
|
||||
0x4000CU, 0x08051U, 0x08050U, 0x40009U, 0x40008U, 0x10280U, 0x4000AU, 0x40005U, 0x40004U, 0x01900U, 0x40006U, 0x40001U, 0x40000U,
|
||||
0x40003U, 0x40002U, 0x14800U, 0x08042U, 0x08041U, 0x08040U, 0x03020U, 0x40018U, 0x08045U, 0x08044U, 0x40015U, 0x40014U, 0x08049U,
|
||||
0x08048U, 0x40011U, 0x40010U, 0x40013U, 0x40012U, 0x00200U, 0x00201U, 0x00202U, 0x00203U, 0x00204U, 0x00205U, 0x00206U, 0x00207U,
|
||||
0x00208U, 0x00209U, 0x0020AU, 0x50080U, 0x0020CU, 0x0020DU, 0x0020EU, 0x50084U, 0x00210U, 0x00211U, 0x00212U, 0x21040U, 0x00214U,
|
||||
0x00215U, 0x04880U, 0x04881U, 0x00218U, 0x00219U, 0x0E001U, 0x0E000U, 0x0021CU, 0x0021DU, 0x04888U, 0x0E004U, 0x00220U, 0x00221U,
|
||||
0x00222U, 0x00223U, 0x00224U, 0x00225U, 0x10140U, 0x10141U, 0x00228U, 0x00229U, 0x0022AU, 0x24204U, 0x12401U, 0x12400U, 0x24201U,
|
||||
0x24200U, 0x00230U, 0x00231U, 0x00232U, 0x21060U, 0x2A000U, 0x2A001U, 0x2A002U, 0x2A003U, 0x20881U, 0x20880U, 0x20883U, 0x20882U,
|
||||
0x05040U, 0x05041U, 0x05042U, 0x24210U, 0x00240U, 0x00241U, 0x00242U, 0x21010U, 0x00244U, 0x46000U, 0x10120U, 0x10121U, 0x00248U,
|
||||
0x00249U, 0x0024AU, 0x21018U, 0x20480U, 0x20481U, 0x20482U, 0x20483U, 0x00250U, 0x21002U, 0x21001U, 0x21000U, 0x18081U, 0x18080U,
|
||||
0x21005U, 0x21004U, 0x12800U, 0x12801U, 0x21009U, 0x21008U, 0x05020U, 0x05021U, 0x48200U, 0x48201U, 0x00260U, 0x00261U, 0x10104U,
|
||||
0x04480U, 0x10102U, 0x10103U, 0x10100U, 0x10101U, 0x62002U, 0x62003U, 0x62000U, 0x62001U, 0x05010U, 0x05011U, 0x10108U, 0x10109U,
|
||||
0x0500CU, 0x21022U, 0x21021U, 0x21020U, 0x05008U, 0x00E00U, 0x10110U, 0x10111U, 0x05004U, 0x05005U, 0x05006U, 0x21028U, 0x05000U,
|
||||
0x05001U, 0x05002U, 0x05003U, 0x00280U, 0x00281U, 0x00282U, 0x50008U, 0x00284U, 0x00285U, 0x04810U, 0x22100U, 0x00288U, 0x50002U,
|
||||
0x50001U, 0x50000U, 0x20440U, 0x20441U, 0x50005U, 0x50004U, 0x00290U, 0x00291U, 0x04804U, 0x04805U, 0x04802U, 0x18040U, 0x04800U,
|
||||
0x04801U, 0x20821U, 0x20820U, 0x50011U, 0x50010U, 0x0480AU, 0x01602U, 0x04808U, 0x01600U, 0x002A0U, 0x002A1U, 0x04441U, 0x04440U,
|
||||
0x002A4U, 0x002A5U, 0x04830U, 0x04444U, 0x06100U, 0x20810U, 0x50021U, 0x50020U, 0x06104U, 0x20814U, 0x50025U, 0x50024U, 0x20809U,
|
||||
0x20808U, 0x13000U, 0x08300U, 0x04822U, 0x2080CU, 0x04820U, 0x04821U, 0x20801U, 0x20800U, 0x20803U, 0x20802U, 0x20805U, 0x20804U,
|
||||
0x04828U, 0x20806U, 0x002C0U, 0x002C1U, 0x04421U, 0x04420U, 0x20408U, 0x18010U, 0x2040AU, 0x18012U, 0x20404U, 0x20405U, 0x50041U,
|
||||
0x50040U, 0x20400U, 0x20401U, 0x20402U, 0x20403U, 0x18005U, 0x18004U, 0x21081U, 0x21080U, 0x18001U, 0x18000U, 0x04840U, 0x18002U,
|
||||
0x20414U, 0x1800CU, 0x21089U, 0x21088U, 0x20410U, 0x18008U, 0x20412U, 0x1800AU, 0x04403U, 0x04402U, 0x04401U, 0x04400U, 0x10182U,
|
||||
0x04406U, 0x10180U, 0x04404U, 0x01A02U, 0x0440AU, 0x01A00U, 0x04408U, 0x20420U, 0x40300U, 0x20422U, 0x40302U, 0x04413U, 0x04412U,
|
||||
0x04411U, 0x04410U, 0x18021U, 0x18020U, 0x10190U, 0x18022U, 0x20841U, 0x20840U, 0x01A10U, 0x20842U, 0x05080U, 0x05081U, 0x05082U,
|
||||
0x05083U, 0x00300U, 0x00301U, 0x00302U, 0x00303U, 0x00304U, 0x00305U, 0x10060U, 0x22080U, 0x00308U, 0x00309U, 0x28800U, 0x28801U,
|
||||
0x44402U, 0x44403U, 0x44400U, 0x44401U, 0x00310U, 0x00311U, 0x10C01U, 0x10C00U, 0x00314U, 0x00315U, 0x10070U, 0x10C04U, 0x00318U,
|
||||
0x00319U, 0x28810U, 0x10C08U, 0x44412U, 0x00000U, 0x44410U, 0x44411U, 0x00320U, 0x60400U, 0x10044U, 0x10045U, 0x10042U, 0x0C800U,
|
||||
0x10040U, 0x10041U, 0x06080U, 0x06081U, 0x06082U, 0x06083U, 0x1004AU, 0x0C808U, 0x10048U, 0x10049U, 0x58008U, 0x08282U, 0x08281U,
|
||||
0x08280U, 0x10052U, 0x0C810U, 0x10050U, 0x10051U, 0x58000U, 0x58001U, 0x58002U, 0x08288U, 0x02A02U, 0x02A03U, 0x02A00U, 0x02A01U,
|
||||
0x00340U, 0x00341U, 0x10024U, 0x10025U, 0x10022U, 0x10023U, 0x10020U, 0x10021U, 0x34001U, 0x34000U, 0x02601U, 0x02600U, 0x1002AU,
|
||||
0x34004U, 0x10028U, 0x10029U, 0x0C400U, 0x0C401U, 0x21101U, 0x21100U, 0x60800U, 0x60801U, 0x10030U, 0x10031U, 0x0C408U, 0x34010U,
|
||||
0x21109U, 0x21108U, 0x60808U, 0x60809U, 0x10038U, 0x28420U, 0x10006U, 0x10007U, 0x10004U, 0x10005U, 0x10002U, 0x10003U, 0x10000U,
|
||||
0x10001U, 0x1000EU, 0x40284U, 0x1000CU, 0x1000DU, 0x1000AU, 0x40280U, 0x10008U, 0x10009U, 0x10016U, 0x10017U, 0x10014U, 0x10015U,
|
||||
0x10012U, 0x10013U, 0x10010U, 0x10011U, 0x05104U, 0x44802U, 0x44801U, 0x44800U, 0x05100U, 0x05101U, 0x10018U, 0x28400U, 0x00380U,
|
||||
0x00381U, 0x22005U, 0x22004U, 0x22003U, 0x22002U, 0x22001U, 0x22000U, 0x06020U, 0x06021U, 0x50101U, 0x50100U, 0x11800U, 0x11801U,
|
||||
0x22009U, 0x22008U, 0x45001U, 0x45000U, 0x08221U, 0x08220U, 0x04902U, 0x22012U, 0x04900U, 0x22010U, 0x06030U, 0x45008U, 0x08229U,
|
||||
0x08228U, 0x11810U, 0x11811U, 0x04908U, 0x22018U, 0x06008U, 0x06009U, 0x08211U, 0x08210U, 0x100C2U, 0x22022U, 0x100C0U, 0x22020U,
|
||||
0x06000U, 0x06001U, 0x06002U, 0x06003U, 0x06004U, 0x40240U, 0x06006U, 0x40242U, 0x08203U, 0x08202U, 0x08201U, 0x08200U, 0x08207U,
|
||||
0x08206U, 0x08205U, 0x08204U, 0x06010U, 0x20900U, 0x08209U, 0x08208U, 0x61002U, 0x20904U, 0x61000U, 0x61001U, 0x29020U, 0x29021U,
|
||||
0x100A4U, 0x22044U, 0x100A2U, 0x22042U, 0x100A0U, 0x22040U, 0x20504U, 0x40224U, 0x0D005U, 0x0D004U, 0x20500U, 0x40220U, 0x0D001U,
|
||||
0x0D000U, 0x03204U, 0x18104U, 0x08261U, 0x08260U, 0x03200U, 0x18100U, 0x03202U, 0x18102U, 0x11421U, 0x11420U, 0x00000U, 0x11422U,
|
||||
0x03208U, 0x18108U, 0x0D011U, 0x0D010U, 0x29000U, 0x29001U, 0x10084U, 0x04500U, 0x10082U, 0x40208U, 0x10080U, 0x10081U, 0x06040U,
|
||||
0x40204U, 0x06042U, 0x40206U, 0x40201U, 0x40200U, 0x10088U, 0x40202U, 0x29010U, 0x08242U, 0x08241U, 0x08240U, 0x10092U, 0x40218U,
|
||||
0x10090U, 0x10091U, 0x11401U, 0x11400U, 0x11403U, 0x11402U, 0x40211U, 0x40210U, 0x10098U, 0x40212U, 0x00400U, 0x00401U, 0x00402U,
|
||||
0x00403U, 0x00404U, 0x00405U, 0x00406U, 0x00407U, 0x00408U, 0x00409U, 0x0040AU, 0x02140U, 0x0040CU, 0x0040DU, 0x01091U, 0x01090U,
|
||||
0x00410U, 0x00411U, 0x00412U, 0x00413U, 0x00414U, 0x00860U, 0x01089U, 0x01088U, 0x00418U, 0x38000U, 0x01085U, 0x01084U, 0x01083U,
|
||||
0x01082U, 0x01081U, 0x01080U, 0x00420U, 0x00421U, 0x00422U, 0x00423U, 0x00424U, 0x00850U, 0x42080U, 0x42081U, 0x00428U, 0x00429U,
|
||||
0x48801U, 0x48800U, 0x09100U, 0x12200U, 0x24401U, 0x24400U, 0x00430U, 0x00844U, 0x00432U, 0x00846U, 0x00841U, 0x00840U, 0x1C000U,
|
||||
0x00842U, 0x00438U, 0x0084CU, 0x010A5U, 0x010A4U, 0x00849U, 0x00848U, 0x010A1U, 0x010A0U, 0x00440U, 0x00441U, 0x00442U, 0x02108U,
|
||||
0x00444U, 0x00830U, 0x70001U, 0x70000U, 0x00448U, 0x02102U, 0x02101U, 0x02100U, 0x20280U, 0x20281U, 0x02105U, 0x02104U, 0x00450U,
|
||||
0x00824U, 0x00452U, 0x00826U, 0x00821U, 0x00820U, 0x00823U, 0x00822U, 0x24802U, 0x02112U, 0x24800U, 0x02110U, 0x00829U, 0x00828U,
|
||||
0x48400U, 0x010C0U, 0x00460U, 0x00814U, 0x04281U, 0x04280U, 0x00811U, 0x00810U, 0x00813U, 0x00812U, 0x54000U, 0x54001U, 0x02121U,
|
||||
0x02120U, 0x00819U, 0x00818U, 0x0081BU, 0x0081AU, 0x00805U, 0x00804U, 0x41100U, 0x00806U, 0x00801U, 0x00800U, 0x00803U, 0x00802U,
|
||||
0x0A080U, 0x0080CU, 0x0A082U, 0x0080EU, 0x00809U, 0x00808U, 0x0080BU, 0x0080AU, 0x00480U, 0x00481U, 0x00482U, 0x00483U, 0x00484U,
|
||||
0x14100U, 0x42020U, 0x01018U, 0x00488U, 0x00489U, 0x01015U, 0x01014U, 0x20240U, 0x01012U, 0x01011U, 0x01010U, 0x00490U, 0x00491U,
|
||||
0x0100DU, 0x0100CU, 0x0100BU, 0x0100AU, 0x01009U, 0x01008U, 0x40900U, 0x01006U, 0x01005U, 0x01004U, 0x01003U, 0x01002U, 0x01001U,
|
||||
0x01000U, 0x004A0U, 0x004A1U, 0x42004U, 0x04240U, 0x42002U, 0x42003U, 0x42000U, 0x42001U, 0x30102U, 0x30103U, 0x30100U, 0x30101U,
|
||||
0x4200AU, 0x01032U, 0x42008U, 0x01030U, 0x25000U, 0x25001U, 0x08501U, 0x08500U, 0x008C1U, 0x008C0U, 0x42010U, 0x01028U, 0x0A040U,
|
||||
0x0A041U, 0x01025U, 0x01024U, 0x01023U, 0x01022U, 0x01021U, 0x01020U, 0x004C0U, 0x49000U, 0x04221U, 0x04220U, 0x20208U, 0x20209U,
|
||||
0x08900U, 0x08901U, 0x20204U, 0x20205U, 0x02181U, 0x02180U, 0x20200U, 0x20201U, 0x20202U, 0x01050U, 0x0A028U, 0x008A4U, 0x0104DU,
|
||||
0x0104CU, 0x008A1U, 0x008A0U, 0x01049U, 0x01048U, 0x0A020U, 0x0A021U, 0x01045U, 0x01044U, 0x20210U, 0x01042U, 0x01041U, 0x01040U,
|
||||
0x04203U, 0x04202U, 0x04201U, 0x04200U, 0x00891U, 0x00890U, 0x42040U, 0x04204U, 0x0A010U, 0x0A011U, 0x01C00U, 0x04208U, 0x20220U,
|
||||
0x40500U, 0x20222U, 0x40502U, 0x0A008U, 0x00884U, 0x04211U, 0x04210U, 0x00881U, 0x00880U, 0x00883U, 0x00882U, 0x0A000U, 0x0A001U,
|
||||
0x0A002U, 0x0A003U, 0x0A004U, 0x00888U, 0x01061U, 0x01060U, 0x00500U, 0x00501U, 0x00502U, 0x02048U, 0x00504U, 0x14080U, 0x00506U,
|
||||
0x14082U, 0x00508U, 0x02042U, 0x02041U, 0x02040U, 0x09020U, 0x09021U, 0x44200U, 0x02044U, 0x00510U, 0x00511U, 0x10A01U, 0x10A00U,
|
||||
0x4A001U, 0x4A000U, 0x4A003U, 0x4A002U, 0x40880U, 0x40881U, 0x02051U, 0x02050U, 0x40884U, 0x01182U, 0x01181U, 0x01180U, 0x00520U,
|
||||
0x60200U, 0x00522U, 0x60202U, 0x09008U, 0x09009U, 0x0900AU, 0x0900BU, 0x09004U, 0x09005U, 0x30080U, 0x02060U, 0x09000U, 0x09001U,
|
||||
0x09002U, 0x09003U, 0x41042U, 0x08482U, 0x41040U, 0x08480U, 0x00941U, 0x00940U, 0x41044U, 0x00942U, 0x09014U, 0x09015U, 0x02C04U,
|
||||
0x08488U, 0x09010U, 0x09011U, 0x02C00U, 0x02C01U, 0x00540U, 0x0200AU, 0x02009U, 0x02008U, 0x08882U, 0x0200EU, 0x08880U, 0x0200CU,
|
||||
0x02003U, 0x02002U, 0x02001U, 0x02000U, 0x02007U, 0x02006U, 0x02005U, 0x02004U, 0x0C200U, 0x0C201U, 0x41020U, 0x02018U, 0x00921U,
|
||||
0x00920U, 0x41024U, 0x00922U, 0x02013U, 0x02012U, 0x02011U, 0x02010U, 0x02017U, 0x02016U, 0x02015U, 0x02014U, 0x41012U, 0x0202AU,
|
||||
0x41010U, 0x02028U, 0x26000U, 0x00910U, 0x10600U, 0x10601U, 0x02023U, 0x02022U, 0x02021U, 0x02020U, 0x09040U, 0x40480U, 0x02025U,
|
||||
0x02024U, 0x41002U, 0x00904U, 0x41000U, 0x41001U, 0x00901U, 0x00900U, 0x41004U, 0x00902U, 0x4100AU, 0x02032U, 0x41008U, 0x02030U,
|
||||
0x00909U, 0x00908U, 0x28201U, 0x28200U, 0x00580U, 0x14004U, 0x00582U, 0x14006U, 0x14001U, 0x14000U, 0x08840U, 0x14002U, 0x40810U,
|
||||
0x40811U, 0x30020U, 0x020C0U, 0x14009U, 0x14008U, 0x01111U, 0x01110U, 0x40808U, 0x40809U, 0x08421U, 0x08420U, 0x14011U, 0x14010U,
|
||||
0x01109U, 0x01108U, 0x40800U, 0x40801U, 0x40802U, 0x01104U, 0x40804U, 0x01102U, 0x01101U, 0x01100U, 0x03801U, 0x03800U, 0x30008U,
|
||||
0x08410U, 0x14021U, 0x14020U, 0x42100U, 0x42101U, 0x30002U, 0x30003U, 0x30000U, 0x30001U, 0x09080U, 0x40440U, 0x30004U, 0x30005U,
|
||||
0x08403U, 0x08402U, 0x08401U, 0x08400U, 0x08407U, 0x08406U, 0x08405U, 0x08404U, 0x40820U, 0x40821U, 0x30010U, 0x08408U, 0x40824U,
|
||||
0x01122U, 0x01121U, 0x01120U, 0x08806U, 0x0208AU, 0x08804U, 0x02088U, 0x08802U, 0x14040U, 0x08800U, 0x08801U, 0x02083U, 0x02082U,
|
||||
0x02081U, 0x02080U, 0x20300U, 0x40420U, 0x08808U, 0x02084U, 0x03404U, 0x03405U, 0x08814U, 0x02098U, 0x03400U, 0x03401U, 0x08810U,
|
||||
0x08811U, 0x40840U, 0x40841U, 0x02091U, 0x02090U, 0x40844U, 0x01142U, 0x01141U, 0x01140U, 0x04303U, 0x04302U, 0x04301U, 0x04300U,
|
||||
0x40409U, 0x40408U, 0x08820U, 0x08821U, 0x40405U, 0x40404U, 0x30040U, 0x020A0U, 0x40401U, 0x40400U, 0x40403U, 0x40402U, 0x41082U,
|
||||
0x08442U, 0x41080U, 0x08440U, 0x00981U, 0x00980U, 0x41084U, 0x00982U, 0x0A100U, 0x11200U, 0x0A102U, 0x11202U, 0x40411U, 0x40410U,
|
||||
0x40413U, 0x40412U, 0x00600U, 0x00601U, 0x00602U, 0x00603U, 0x00604U, 0x00605U, 0x00606U, 0x00607U, 0x00608U, 0x05800U, 0x0060AU,
|
||||
0x05802U, 0x200C0U, 0x12020U, 0x44100U, 0x44101U, 0x00610U, 0x00611U, 0x10901U, 0x10900U, 0x51000U, 0x51001U, 0x51002U, 0x10904U,
|
||||
0x00618U, 0x05810U, 0x01285U, 0x01284U, 0x51008U, 0x01282U, 0x01281U, 0x01280U, 0x00620U, 0x60100U, 0x040C1U, 0x040C0U, 0x12009U,
|
||||
0x12008U, 0x21800U, 0x21801U, 0x12005U, 0x12004U, 0x12007U, 0x12006U, 0x12001U, 0x12000U, 0x12003U, 0x12002U, 0x00630U, 0x00A44U,
|
||||
0x040D1U, 0x040D0U, 0x00A41U, 0x00A40U, 0x21810U, 0x00A42U, 0x12015U, 0x12014U, 0x00000U, 0x12016U, 0x12011U, 0x12010U, 0x12013U,
|
||||
0x12012U, 0x00640U, 0x00641U, 0x040A1U, 0x040A0U, 0x20088U, 0x20089U, 0x2008AU, 0x040A4U, 0x20084U, 0x20085U, 0x19000U, 0x02300U,
|
||||
0x20080U, 0x20081U, 0x20082U, 0x20083U, 0x0C100U, 0x0C101U, 0x21401U, 0x21400U, 0x00A21U, 0x00A20U, 0x00A23U, 0x00A22U, 0x20094U,
|
||||
0x20095U, 0x19010U, 0x21408U, 0x20090U, 0x20091U, 0x20092U, 0x28120U, 0x04083U, 0x04082U, 0x04081U, 0x04080U, 0x00A11U, 0x00A10U,
|
||||
0x10500U, 0x04084U, 0x200A4U, 0x0408AU, 0x04089U, 0x04088U, 0x200A0U, 0x12040U, 0x200A2U, 0x12042U, 0x00A05U, 0x00A04U, 0x04091U,
|
||||
0x04090U, 0x00A01U, 0x00A00U, 0x00A03U, 0x00A02U, 0x05404U, 0x00A0CU, 0x28105U, 0x28104U, 0x05400U, 0x00A08U, 0x28101U, 0x28100U,
|
||||
0x00680U, 0x00681U, 0x04061U, 0x04060U, 0x20048U, 0x20049U, 0x2004AU, 0x04064U, 0x20044U, 0x20045U, 0x50401U, 0x50400U, 0x20040U,
|
||||
0x20041U, 0x20042U, 0x01210U, 0x68002U, 0x68003U, 0x68000U, 0x68001U, 0x04C02U, 0x0120AU, 0x04C00U, 0x01208U, 0x20054U, 0x01206U,
|
||||
0x01205U, 0x01204U, 0x20050U, 0x01202U, 0x01201U, 0x01200U, 0x18800U, 0x04042U, 0x04041U, 0x04040U, 0x42202U, 0x04046U, 0x42200U,
|
||||
0x04044U, 0x20064U, 0x0404AU, 0x04049U, 0x04048U, 0x20060U, 0x12080U, 0x20062U, 0x12082U, 0x18810U, 0x04052U, 0x04051U, 0x04050U,
|
||||
0x4C009U, 0x4C008U, 0x42210U, 0x04054U, 0x20C01U, 0x20C00U, 0x20C03U, 0x20C02U, 0x4C001U, 0x4C000U, 0x01221U, 0x01220U, 0x2000CU,
|
||||
0x04022U, 0x04021U, 0x04020U, 0x20008U, 0x20009U, 0x2000AU, 0x04024U, 0x20004U, 0x20005U, 0x20006U, 0x04028U, 0x20000U, 0x20001U,
|
||||
0x20002U, 0x20003U, 0x2001CU, 0x04032U, 0x04031U, 0x04030U, 0x20018U, 0x18400U, 0x2001AU, 0x18402U, 0x20014U, 0x20015U, 0x20016U,
|
||||
0x01244U, 0x20010U, 0x20011U, 0x20012U, 0x01240U, 0x04003U, 0x04002U, 0x04001U, 0x04000U, 0x20028U, 0x04006U, 0x04005U, 0x04004U,
|
||||
0x20024U, 0x0400AU, 0x04009U, 0x04008U, 0x20020U, 0x20021U, 0x20022U, 0x0400CU, 0x04013U, 0x04012U, 0x04011U, 0x04010U, 0x00A81U,
|
||||
0x00A80U, 0x04015U, 0x04014U, 0x0A200U, 0x11100U, 0x04019U, 0x04018U, 0x20030U, 0x20031U, 0x50800U, 0x50801U, 0x00700U, 0x60020U,
|
||||
0x10811U, 0x10810U, 0x4400AU, 0x60024U, 0x44008U, 0x44009U, 0x44006U, 0x02242U, 0x44004U, 0x02240U, 0x44002U, 0x44003U, 0x44000U,
|
||||
0x44001U, 0x0C040U, 0x10802U, 0x10801U, 0x10800U, 0x0C044U, 0x10806U, 0x10805U, 0x10804U, 0x23000U, 0x23001U, 0x10809U, 0x10808U,
|
||||
0x44012U, 0x44013U, 0x44010U, 0x44011U, 0x60001U, 0x60000U, 0x60003U, 0x60002U, 0x60005U, 0x60004U, 0x10440U, 0x10441U, 0x60009U,
|
||||
0x60008U, 0x44024U, 0x6000AU, 0x09200U, 0x12100U, 0x44020U, 0x44021U, 0x60011U, 0x60010U, 0x10821U, 0x10820U, 0x07003U, 0x07002U,
|
||||
0x07001U, 0x07000U, 0x23020U, 0x60018U, 0x28045U, 0x28044U, 0x09210U, 0x28042U, 0x28041U, 0x28040U, 0x0C010U, 0x0C011U, 0x02209U,
|
||||
0x02208U, 0x10422U, 0x10423U, 0x10420U, 0x10421U, 0x02203U, 0x02202U, 0x02201U, 0x02200U, 0x20180U, 0x20181U, 0x44040U, 0x02204U,
|
||||
0x0C000U, 0x0C001U, 0x0C002U, 0x10840U, 0x0C004U, 0x0C005U, 0x0C006U, 0x10844U, 0x0C008U, 0x0C009U, 0x02211U, 0x02210U, 0x0C00CU,
|
||||
0x28022U, 0x28021U, 0x28020U, 0x60041U, 0x60040U, 0x10404U, 0x04180U, 0x10402U, 0x10403U, 0x10400U, 0x10401U, 0x02223U, 0x02222U,
|
||||
0x02221U, 0x02220U, 0x1040AU, 0x28012U, 0x10408U, 0x28010U, 0x0C020U, 0x0C021U, 0x41200U, 0x41201U, 0x00B01U, 0x00B00U, 0x10410U,
|
||||
0x28008U, 0x11081U, 0x11080U, 0x28005U, 0x28004U, 0x28003U, 0x28002U, 0x28001U, 0x28000U, 0x52040U, 0x14204U, 0x22405U, 0x22404U,
|
||||
0x14201U, 0x14200U, 0x22401U, 0x22400U, 0x20144U, 0x20145U, 0x44084U, 0x022C0U, 0x20140U, 0x20141U, 0x44080U, 0x44081U, 0x40A08U,
|
||||
0x10882U, 0x10881U, 0x10880U, 0x14211U, 0x14210U, 0x1A008U, 0x10884U, 0x40A00U, 0x40A01U, 0x40A02U, 0x01304U, 0x1A002U, 0x01302U,
|
||||
0x1A000U, 0x01300U, 0x60081U, 0x60080U, 0x04141U, 0x04140U, 0x60085U, 0x60084U, 0x104C0U, 0x04144U, 0x06400U, 0x06401U, 0x30200U,
|
||||
0x30201U, 0x06404U, 0x40640U, 0x30204U, 0x30205U, 0x08603U, 0x08602U, 0x08601U, 0x08600U, 0x00000U, 0x08606U, 0x08605U, 0x08604U,
|
||||
0x11041U, 0x11040U, 0x30210U, 0x11042U, 0x11045U, 0x11044U, 0x1A020U, 0x01320U, 0x52000U, 0x52001U, 0x04121U, 0x04120U, 0x20108U,
|
||||
0x20109U, 0x08A00U, 0x08A01U, 0x20104U, 0x20105U, 0x02281U, 0x02280U, 0x20100U, 0x20101U, 0x20102U, 0x20103U, 0x0C080U, 0x0C081U,
|
||||
0x0C082U, 0x04130U, 0x0C084U, 0x06808U, 0x08A10U, 0x08A11U, 0x11021U, 0x11020U, 0x11023U, 0x11022U, 0x20110U, 0x06800U, 0x20112U,
|
||||
0x06802U, 0x04103U, 0x04102U, 0x04101U, 0x04100U, 0x10482U, 0x04106U, 0x10480U, 0x04104U, 0x11011U, 0x11010U, 0x04109U, 0x04108U,
|
||||
0x20120U, 0x40600U, 0x20122U, 0x40602U, 0x11009U, 0x11008U, 0x22800U, 0x04110U, 0x1100DU, 0x1100CU, 0x22804U, 0x04114U, 0x11001U,
|
||||
0x11000U, 0x11003U, 0x11002U, 0x11005U, 0x11004U, 0x28081U, 0x28080U
|
||||
};
|
||||
|
||||
#define X18 0x00040000 /* vector representation of X^{18} */
|
||||
#define X11 0x00000800 /* vector representation of X^{11} */
|
||||
#define MASK8 0xfffff800 /* auxiliary vector for testing */
|
||||
#define GENPOL 0x00000c75 /* generator polinomial, g(x) */
|
||||
|
||||
unsigned int CGolay2087::getSyndrome1987(unsigned int pattern)
|
||||
/*
|
||||
* Compute the syndrome corresponding to the given pattern, i.e., the
|
||||
* remainder after dividing the pattern (when considering it as the vector
|
||||
* representation of a polynomial) by the generator polynomial, GENPOL.
|
||||
* In the program this pattern has several meanings: (1) pattern = infomation
|
||||
* bits, when constructing the encoding table; (2) pattern = error pattern,
|
||||
* when constructing the decoding table; and (3) pattern = received vector, to
|
||||
* obtain its syndrome in decoding.
|
||||
*/
|
||||
{
|
||||
unsigned int aux = X18;
|
||||
|
||||
if (pattern >= X11)
|
||||
{
|
||||
while (pattern & MASK8)
|
||||
{
|
||||
while (!(aux & pattern))
|
||||
aux = aux >> 1;
|
||||
|
||||
pattern ^= (aux / X11) * GENPOL;
|
||||
}
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
unsigned char CGolay2087::decode(const unsigned char* data)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
|
||||
unsigned int code = (data[0U] << 11) + (data[1U] << 3) + (data[2U] >> 5);
|
||||
unsigned int syndrome = getSyndrome1987(code);
|
||||
unsigned int error_pattern = DECODING_TABLE_1987[syndrome];
|
||||
|
||||
if (error_pattern != 0x00U)
|
||||
code ^= error_pattern;
|
||||
|
||||
return code >> 11;
|
||||
}
|
||||
|
||||
void CGolay2087::encode(unsigned char* data)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
|
||||
unsigned int value = data[0U];
|
||||
|
||||
unsigned int cksum = ENCODING_TABLE_2087[value];
|
||||
|
||||
data[1U] = cksum & 0xFFU;
|
||||
data[2U] = cksum >> 8;
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
#ifndef Golay2087_H
|
||||
#define Golay2087_H
|
||||
|
||||
class CGolay2087
|
||||
{
|
||||
public:
|
||||
static void encode(unsigned char* data);
|
||||
|
||||
static unsigned char decode(const unsigned char* data);
|
||||
|
||||
private:
|
||||
static unsigned int getSyndrome1987(unsigned int pattern);
|
||||
};
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 2010,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 Golay24128_H
|
||||
#define Golay24128_H
|
||||
|
||||
class CGolay24128
|
||||
{
|
||||
public:
|
||||
static unsigned int encode23127(unsigned int data);
|
||||
static unsigned int encode24128(unsigned int data);
|
||||
|
||||
static unsigned int decode23127(unsigned int code);
|
||||
static unsigned int decode24128(unsigned int code);
|
||||
static unsigned int decode24128(unsigned char* bytes);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,534 @@
|
||||
/*
|
||||
* 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 "Hamming.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
// Hamming (15,11,3) check a boolean data array
|
||||
bool CHamming::decode15113_1(bool* d)
|
||||
{
|
||||
assert(d != nullptr);
|
||||
|
||||
// Calculate the parity it should have
|
||||
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6];
|
||||
bool c1 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9];
|
||||
bool c2 = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[8] ^ d[10];
|
||||
bool c3 = d[0] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[9] ^ d[10];
|
||||
|
||||
unsigned char n = 0U;
|
||||
n |= (c0 != d[11]) ? 0x01U : 0x00U;
|
||||
n |= (c1 != d[12]) ? 0x02U : 0x00U;
|
||||
n |= (c2 != d[13]) ? 0x04U : 0x00U;
|
||||
n |= (c3 != d[14]) ? 0x08U : 0x00U;
|
||||
|
||||
switch (n)
|
||||
{
|
||||
// Parity bit errors
|
||||
case 0x01U:
|
||||
d[11] = !d[11];
|
||||
return true;
|
||||
case 0x02U:
|
||||
d[12] = !d[12];
|
||||
return true;
|
||||
case 0x04U:
|
||||
d[13] = !d[13];
|
||||
return true;
|
||||
case 0x08U:
|
||||
d[14] = !d[14];
|
||||
return true;
|
||||
|
||||
// Data bit errors
|
||||
case 0x0FU:
|
||||
d[0] = !d[0];
|
||||
return true;
|
||||
case 0x07U:
|
||||
d[1] = !d[1];
|
||||
return true;
|
||||
case 0x0BU:
|
||||
d[2] = !d[2];
|
||||
return true;
|
||||
case 0x03U:
|
||||
d[3] = !d[3];
|
||||
return true;
|
||||
case 0x0DU:
|
||||
d[4] = !d[4];
|
||||
return true;
|
||||
case 0x05U:
|
||||
d[5] = !d[5];
|
||||
return true;
|
||||
case 0x09U:
|
||||
d[6] = !d[6];
|
||||
return true;
|
||||
case 0x0EU:
|
||||
d[7] = !d[7];
|
||||
return true;
|
||||
case 0x06U:
|
||||
d[8] = !d[8];
|
||||
return true;
|
||||
case 0x0AU:
|
||||
d[9] = !d[9];
|
||||
return true;
|
||||
case 0x0CU:
|
||||
d[10] = !d[10];
|
||||
return true;
|
||||
|
||||
// No bit errors
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CHamming::encode15113_1(bool* d)
|
||||
{
|
||||
assert(d != nullptr);
|
||||
|
||||
// Calculate the checksum this row should have
|
||||
d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6];
|
||||
d[12] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9];
|
||||
d[13] = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[8] ^ d[10];
|
||||
d[14] = d[0] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[9] ^ d[10];
|
||||
}
|
||||
|
||||
// Hamming (15,11,3) check a boolean data array
|
||||
bool CHamming::decode15113_2(bool* d)
|
||||
{
|
||||
assert(d != nullptr);
|
||||
|
||||
// Calculate the checksum this row should have
|
||||
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
|
||||
bool c1 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9];
|
||||
bool c2 = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10];
|
||||
bool c3 = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10];
|
||||
|
||||
unsigned char n = 0x00U;
|
||||
n |= (c0 != d[11]) ? 0x01U : 0x00U;
|
||||
n |= (c1 != d[12]) ? 0x02U : 0x00U;
|
||||
n |= (c2 != d[13]) ? 0x04U : 0x00U;
|
||||
n |= (c3 != d[14]) ? 0x08U : 0x00U;
|
||||
|
||||
switch (n)
|
||||
{
|
||||
// Parity bit errors
|
||||
case 0x01U:
|
||||
d[11] = !d[11];
|
||||
return true;
|
||||
case 0x02U:
|
||||
d[12] = !d[12];
|
||||
return true;
|
||||
case 0x04U:
|
||||
d[13] = !d[13];
|
||||
return true;
|
||||
case 0x08U:
|
||||
d[14] = !d[14];
|
||||
return true;
|
||||
|
||||
// Data bit errors
|
||||
case 0x09U:
|
||||
d[0] = !d[0];
|
||||
return true;
|
||||
case 0x0BU:
|
||||
d[1] = !d[1];
|
||||
return true;
|
||||
case 0x0FU:
|
||||
d[2] = !d[2];
|
||||
return true;
|
||||
case 0x07U:
|
||||
d[3] = !d[3];
|
||||
return true;
|
||||
case 0x0EU:
|
||||
d[4] = !d[4];
|
||||
return true;
|
||||
case 0x05U:
|
||||
d[5] = !d[5];
|
||||
return true;
|
||||
case 0x0AU:
|
||||
d[6] = !d[6];
|
||||
return true;
|
||||
case 0x0DU:
|
||||
d[7] = !d[7];
|
||||
return true;
|
||||
case 0x03U:
|
||||
d[8] = !d[8];
|
||||
return true;
|
||||
case 0x06U:
|
||||
d[9] = !d[9];
|
||||
return true;
|
||||
case 0x0CU:
|
||||
d[10] = !d[10];
|
||||
return true;
|
||||
|
||||
// No bit errors
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CHamming::encode15113_2(bool* d)
|
||||
{
|
||||
assert(d != nullptr);
|
||||
|
||||
// Calculate the checksum this row should have
|
||||
d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
|
||||
d[12] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9];
|
||||
d[13] = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10];
|
||||
d[14] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10];
|
||||
}
|
||||
|
||||
// Hamming (13,9,3) check a boolean data array
|
||||
bool CHamming::decode1393(bool* d)
|
||||
{
|
||||
assert(d != nullptr);
|
||||
|
||||
// Calculate the checksum this column should have
|
||||
bool c0 = d[0] ^ d[1] ^ d[3] ^ d[5] ^ d[6];
|
||||
bool c1 = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7];
|
||||
bool c2 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
|
||||
bool c3 = d[0] ^ d[2] ^ d[4] ^ d[5] ^ d[8];
|
||||
|
||||
unsigned char n = 0x00U;
|
||||
n |= (c0 != d[9]) ? 0x01U : 0x00U;
|
||||
n |= (c1 != d[10]) ? 0x02U : 0x00U;
|
||||
n |= (c2 != d[11]) ? 0x04U : 0x00U;
|
||||
n |= (c3 != d[12]) ? 0x08U : 0x00U;
|
||||
|
||||
switch (n)
|
||||
{
|
||||
// Parity bit errors
|
||||
case 0x01U:
|
||||
d[9] = !d[9];
|
||||
return true;
|
||||
case 0x02U:
|
||||
d[10] = !d[10];
|
||||
return true;
|
||||
case 0x04U:
|
||||
d[11] = !d[11];
|
||||
return true;
|
||||
case 0x08U:
|
||||
d[12] = !d[12];
|
||||
return true;
|
||||
|
||||
// Data bit erros
|
||||
case 0x0FU:
|
||||
d[0] = !d[0];
|
||||
return true;
|
||||
case 0x07U:
|
||||
d[1] = !d[1];
|
||||
return true;
|
||||
case 0x0EU:
|
||||
d[2] = !d[2];
|
||||
return true;
|
||||
case 0x05U:
|
||||
d[3] = !d[3];
|
||||
return true;
|
||||
case 0x0AU:
|
||||
d[4] = !d[4];
|
||||
return true;
|
||||
case 0x0DU:
|
||||
d[5] = !d[5];
|
||||
return true;
|
||||
case 0x03U:
|
||||
d[6] = !d[6];
|
||||
return true;
|
||||
case 0x06U:
|
||||
d[7] = !d[7];
|
||||
return true;
|
||||
case 0x0CU:
|
||||
d[8] = !d[8];
|
||||
return true;
|
||||
|
||||
// No bit errors
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CHamming::encode1393(bool* d)
|
||||
{
|
||||
assert(d != nullptr);
|
||||
|
||||
// Calculate the checksum this column should have
|
||||
d[9] = d[0] ^ d[1] ^ d[3] ^ d[5] ^ d[6];
|
||||
d[10] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7];
|
||||
d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
|
||||
d[12] = d[0] ^ d[2] ^ d[4] ^ d[5] ^ d[8];
|
||||
}
|
||||
|
||||
// Hamming (10,6,3) check a boolean data array
|
||||
bool CHamming::decode1063(bool* d)
|
||||
{
|
||||
assert(d != nullptr);
|
||||
|
||||
// Calculate the checksum this column should have
|
||||
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[5];
|
||||
bool c1 = d[0] ^ d[1] ^ d[3] ^ d[5];
|
||||
bool c2 = d[0] ^ d[2] ^ d[3] ^ d[4];
|
||||
bool c3 = d[1] ^ d[2] ^ d[3] ^ d[4];
|
||||
|
||||
unsigned char n = 0x00U;
|
||||
n |= (c0 != d[6]) ? 0x01U : 0x00U;
|
||||
n |= (c1 != d[7]) ? 0x02U : 0x00U;
|
||||
n |= (c2 != d[8]) ? 0x04U : 0x00U;
|
||||
n |= (c3 != d[9]) ? 0x08U : 0x00U;
|
||||
|
||||
switch (n)
|
||||
{
|
||||
// Parity bit errors
|
||||
case 0x01U:
|
||||
d[6] = !d[6];
|
||||
return true;
|
||||
case 0x02U:
|
||||
d[7] = !d[7];
|
||||
return true;
|
||||
case 0x04U:
|
||||
d[8] = !d[8];
|
||||
return true;
|
||||
case 0x08U:
|
||||
d[9] = !d[9];
|
||||
return true;
|
||||
|
||||
// Data bit erros
|
||||
case 0x07U:
|
||||
d[0] = !d[0];
|
||||
return true;
|
||||
case 0x0BU:
|
||||
d[1] = !d[1];
|
||||
return true;
|
||||
case 0x0DU:
|
||||
d[2] = !d[2];
|
||||
return true;
|
||||
case 0x0EU:
|
||||
d[3] = !d[3];
|
||||
return true;
|
||||
case 0x0CU:
|
||||
d[4] = !d[4];
|
||||
return true;
|
||||
case 0x03U:
|
||||
d[5] = !d[5];
|
||||
return true;
|
||||
|
||||
// No bit errors
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CHamming::encode1063(bool* d)
|
||||
{
|
||||
assert(d != nullptr);
|
||||
|
||||
// Calculate the checksum this column should have
|
||||
d[6] = d[0] ^ d[1] ^ d[2] ^ d[5];
|
||||
d[7] = d[0] ^ d[1] ^ d[3] ^ d[5];
|
||||
d[8] = d[0] ^ d[2] ^ d[3] ^ d[4];
|
||||
d[9] = d[1] ^ d[2] ^ d[3] ^ d[4];
|
||||
}
|
||||
|
||||
// A Hamming (16,11,4) Check
|
||||
bool CHamming::decode16114(bool* d)
|
||||
{
|
||||
assert(d != nullptr);
|
||||
|
||||
// Calculate the checksum this column should have
|
||||
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
|
||||
bool c1 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9];
|
||||
bool c2 = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10];
|
||||
bool c3 = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10];
|
||||
bool c4 = d[0] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[9] ^ d[10];
|
||||
|
||||
// Compare these with the actual bits
|
||||
unsigned char n = 0x00U;
|
||||
n |= (c0 != d[11]) ? 0x01U : 0x00U;
|
||||
n |= (c1 != d[12]) ? 0x02U : 0x00U;
|
||||
n |= (c2 != d[13]) ? 0x04U : 0x00U;
|
||||
n |= (c3 != d[14]) ? 0x08U : 0x00U;
|
||||
n |= (c4 != d[15]) ? 0x10U : 0x00U;
|
||||
|
||||
switch (n)
|
||||
{
|
||||
// Parity bit errors
|
||||
case 0x01U:
|
||||
d[11] = !d[11];
|
||||
return true;
|
||||
case 0x02U:
|
||||
d[12] = !d[12];
|
||||
return true;
|
||||
case 0x04U:
|
||||
d[13] = !d[13];
|
||||
return true;
|
||||
case 0x08U:
|
||||
d[14] = !d[14];
|
||||
return true;
|
||||
case 0x10U:
|
||||
d[15] = !d[15];
|
||||
return true;
|
||||
|
||||
// Data bit errors
|
||||
case 0x19U:
|
||||
d[0] = !d[0];
|
||||
return true;
|
||||
case 0x0BU:
|
||||
d[1] = !d[1];
|
||||
return true;
|
||||
case 0x1FU:
|
||||
d[2] = !d[2];
|
||||
return true;
|
||||
case 0x07U:
|
||||
d[3] = !d[3];
|
||||
return true;
|
||||
case 0x0EU:
|
||||
d[4] = !d[4];
|
||||
return true;
|
||||
case 0x15U:
|
||||
d[5] = !d[5];
|
||||
return true;
|
||||
case 0x1AU:
|
||||
d[6] = !d[6];
|
||||
return true;
|
||||
case 0x0DU:
|
||||
d[7] = !d[7];
|
||||
return true;
|
||||
case 0x13U:
|
||||
d[8] = !d[8];
|
||||
return true;
|
||||
case 0x16U:
|
||||
d[9] = !d[9];
|
||||
return true;
|
||||
case 0x1CU:
|
||||
d[10] = !d[10];
|
||||
return true;
|
||||
|
||||
// No bit errors
|
||||
case 0x00U:
|
||||
return true;
|
||||
|
||||
// Unrecoverable errors
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CHamming::encode16114(bool* d)
|
||||
{
|
||||
assert(d != nullptr);
|
||||
|
||||
d[11] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[5] ^ d[7] ^ d[8];
|
||||
d[12] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[9];
|
||||
d[13] = d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[7] ^ d[9] ^ d[10];
|
||||
d[14] = d[0] ^ d[1] ^ d[2] ^ d[4] ^ d[6] ^ d[7] ^ d[10];
|
||||
d[15] = d[0] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[9] ^ d[10];
|
||||
}
|
||||
|
||||
// A Hamming (17,12,3) Check
|
||||
bool CHamming::decode17123(bool* d)
|
||||
{
|
||||
assert(d != nullptr);
|
||||
|
||||
// Calculate the checksum this column should have
|
||||
bool c0 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[6] ^ d[7] ^ d[9];
|
||||
bool c1 = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[7] ^ d[8] ^ d[10];
|
||||
bool c2 = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[8] ^ d[9] ^ d[11];
|
||||
bool c3 = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[10];
|
||||
bool c4 = d[0] ^ d[1] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[11];
|
||||
|
||||
// Compare these with the actual bits
|
||||
unsigned char n = 0x00U;
|
||||
n |= (c0 != d[12]) ? 0x01U : 0x00U;
|
||||
n |= (c1 != d[13]) ? 0x02U : 0x00U;
|
||||
n |= (c2 != d[14]) ? 0x04U : 0x00U;
|
||||
n |= (c3 != d[15]) ? 0x08U : 0x00U;
|
||||
n |= (c4 != d[16]) ? 0x10U : 0x00U;
|
||||
|
||||
switch (n)
|
||||
{
|
||||
// Parity bit errors
|
||||
case 0x01U:
|
||||
d[12] = !d[12];
|
||||
return true;
|
||||
case 0x02U:
|
||||
d[13] = !d[13];
|
||||
return true;
|
||||
case 0x04U:
|
||||
d[14] = !d[14];
|
||||
return true;
|
||||
case 0x08U:
|
||||
d[15] = !d[15];
|
||||
return true;
|
||||
case 0x10U:
|
||||
d[16] = !d[16];
|
||||
return true;
|
||||
|
||||
// Data bit errors
|
||||
case 0x1BU:
|
||||
d[0] = !d[0];
|
||||
return true;
|
||||
case 0x1FU:
|
||||
d[1] = !d[1];
|
||||
return true;
|
||||
case 0x17U:
|
||||
d[2] = !d[2];
|
||||
return true;
|
||||
case 0x07U:
|
||||
d[3] = !d[3];
|
||||
return true;
|
||||
case 0x0EU:
|
||||
d[4] = !d[4];
|
||||
return true;
|
||||
case 0x1CU:
|
||||
d[5] = !d[5];
|
||||
return true;
|
||||
case 0x11U:
|
||||
d[6] = !d[6];
|
||||
return true;
|
||||
case 0x0BU:
|
||||
d[7] = !d[7];
|
||||
return true;
|
||||
case 0x16U:
|
||||
d[8] = !d[8];
|
||||
return true;
|
||||
case 0x05U:
|
||||
d[9] = !d[9];
|
||||
return true;
|
||||
case 0x0AU:
|
||||
d[10] = !d[10];
|
||||
return true;
|
||||
case 0x14U:
|
||||
d[11] = !d[11];
|
||||
return true;
|
||||
|
||||
// No bit errors
|
||||
case 0x00U:
|
||||
return true;
|
||||
|
||||
// Unrecoverable errors
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void CHamming::encode17123(bool* d)
|
||||
{
|
||||
assert(d != nullptr);
|
||||
|
||||
d[12] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[6] ^ d[7] ^ d[9];
|
||||
d[13] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[7] ^ d[8] ^ d[10];
|
||||
d[14] = d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[8] ^ d[9] ^ d[11];
|
||||
d[15] = d[0] ^ d[1] ^ d[4] ^ d[5] ^ d[7] ^ d[10];
|
||||
d[16] = d[0] ^ d[1] ^ d[2] ^ d[5] ^ d[6] ^ d[8] ^ d[11];
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef Hamming_H
|
||||
#define Hamming_H
|
||||
|
||||
class CHamming
|
||||
{
|
||||
public:
|
||||
static void encode15113_1(bool* d);
|
||||
static bool decode15113_1(bool* d);
|
||||
|
||||
static void encode15113_2(bool* d);
|
||||
static bool decode15113_2(bool* d);
|
||||
|
||||
static void encode1393(bool* d);
|
||||
static bool decode1393(bool* d);
|
||||
|
||||
static void encode1063(bool* d);
|
||||
static bool decode1063(bool* d);
|
||||
|
||||
static void encode16114(bool* d);
|
||||
static bool decode16114(bool* d);
|
||||
|
||||
static void encode17123(bool* d);
|
||||
static bool decode17123(bool* d);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,309 @@
|
||||
/*
|
||||
* Copyright (C) 2020 by Thomas Early N7TAE
|
||||
*
|
||||
* 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 <cstdint>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include "cip.h"
|
||||
|
||||
CIp::CIp() : is_set(false)
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
CIp::CIp(const char *address, int family, int type, uint16_t port) : is_set(true)
|
||||
{
|
||||
Clear();
|
||||
if (0 == strncasecmp(address, "none", 4))
|
||||
{
|
||||
is_set = false;
|
||||
return;
|
||||
}
|
||||
struct addrinfo hints, *result;
|
||||
bzero(&hints, sizeof(struct addrinfo));
|
||||
hints.ai_family = family;
|
||||
hints.ai_socktype = type;
|
||||
if (0 == getaddrinfo(address, (port ? std::to_string(port).c_str() : nullptr), &hints, &result))
|
||||
{
|
||||
memcpy(&addr, result->ai_addr, result->ai_addrlen);
|
||||
addr.ss_family = result->ai_family;
|
||||
freeaddrinfo(result);
|
||||
}
|
||||
SetPort(port);
|
||||
}
|
||||
CIp::CIp(const int family, const uint16_t port, const char *address) : is_set(true)
|
||||
{
|
||||
Initialize(family, port, address);
|
||||
}
|
||||
|
||||
void CIp::Initialize(const int family, const uint16_t port, const char *address)
|
||||
{
|
||||
Clear();
|
||||
if (0 == strncasecmp(address, "none", 4))
|
||||
{
|
||||
is_set = false;
|
||||
return;
|
||||
}
|
||||
is_set = true;
|
||||
addr.ss_family = family;
|
||||
if (AF_INET == family)
|
||||
{
|
||||
auto addr4 = (struct sockaddr_in *)&addr;
|
||||
addr4->sin_port = htons(port);
|
||||
if (address)
|
||||
{
|
||||
if (0 == strncasecmp(address, "loc", 3))
|
||||
inet_pton(AF_INET, "127.0.0.1", &(addr4->sin_addr));
|
||||
else if (0 == strncasecmp(address, "any", 3))
|
||||
inet_pton(AF_INET, "0.0.0.0", &(addr4->sin_addr));
|
||||
else
|
||||
{
|
||||
if (1 > inet_pton(AF_INET, address, &(addr4->sin_addr)))
|
||||
{
|
||||
std::cerr << "Address Initialization Error: '" << address << "' is not a valdid IPV4 address!" << std::endl;
|
||||
is_set = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (AF_INET6 == family)
|
||||
{
|
||||
auto addr6 = (struct sockaddr_in6 *)&addr;
|
||||
addr6->sin6_port = htons(port);
|
||||
if (address)
|
||||
{
|
||||
if (0 == strncasecmp(address, "loc", 3))
|
||||
inet_pton(AF_INET6, "::1", &(addr6->sin6_addr));
|
||||
else if (0 == strncasecmp(address, "any", 3))
|
||||
inet_pton(AF_INET6, "::", &(addr6->sin6_addr));
|
||||
else
|
||||
{
|
||||
if (1 > inet_pton(AF_INET6, address, &(addr6->sin6_addr)))
|
||||
{
|
||||
std::cerr << "Address Initialization Error: '" << address << "' is not a valid IPV6 address!" << std::endl;
|
||||
is_set = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "Error: Wrong address family type:" << family << " for [" << (address ? address : "NULL") << "]:" << port << std::endl;
|
||||
is_set = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CIp::operator==(const CIp &rhs) const // compares ports, addresses and families
|
||||
{
|
||||
// if anything is not equal, then we are done
|
||||
if (addr.ss_family != rhs.addr.ss_family)
|
||||
return false;
|
||||
if (AF_INET == addr.ss_family)
|
||||
{
|
||||
auto l = (struct sockaddr_in *)&addr;
|
||||
auto r = (struct sockaddr_in *)&rhs.addr;
|
||||
if (l->sin_addr.s_addr == r->sin_addr.s_addr)
|
||||
return l->sin_port == r->sin_port;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else if (AF_INET6 == addr.ss_family)
|
||||
{
|
||||
auto l = (struct sockaddr_in6 *)&addr;
|
||||
auto r = (struct sockaddr_in6 *)&rhs.addr;
|
||||
if (0 == memcmp(&(l->sin6_addr), &(r->sin6_addr), sizeof(struct in6_addr)))
|
||||
return l->sin6_port == r->sin6_port;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CIp::operator!=(const CIp &rhs) const // compares ports, addresses and families
|
||||
{
|
||||
// if anything is not equal, then we are done
|
||||
if (addr.ss_family != rhs.addr.ss_family)
|
||||
return true;
|
||||
if (AF_INET == addr.ss_family)
|
||||
{
|
||||
auto l = (struct sockaddr_in *)&addr;
|
||||
auto r = (struct sockaddr_in *)&rhs.addr;
|
||||
if (l->sin_addr.s_addr != r->sin_addr.s_addr)
|
||||
return true;
|
||||
else
|
||||
return l->sin_port != r->sin_port;
|
||||
}
|
||||
else if (AF_INET6 == addr.ss_family)
|
||||
{
|
||||
auto l = (struct sockaddr_in6 *)&addr;
|
||||
auto r = (struct sockaddr_in6 *)&rhs.addr;
|
||||
if (0 != memcmp(&(l->sin6_addr), &(r->sin6_addr), sizeof(struct in6_addr)))
|
||||
return true;
|
||||
else
|
||||
return l->sin6_port != r->sin6_port;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CIp::AddressIsZero() const
|
||||
{
|
||||
if (AF_INET == addr.ss_family)
|
||||
{
|
||||
auto addr4 = (struct sockaddr_in *)&addr;
|
||||
return (addr4->sin_addr.s_addr == 0U);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto addr6 = (struct sockaddr_in6 *)&addr;
|
||||
for (unsigned int i=0; i<16; i++)
|
||||
{
|
||||
if (addr6->sin6_addr.s6_addr[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void CIp::ClearAddress()
|
||||
{
|
||||
if (AF_INET == addr.ss_family)
|
||||
{
|
||||
auto addr4 = (struct sockaddr_in *)&addr;
|
||||
addr4->sin_addr.s_addr = 0U;
|
||||
strcpy(straddr, "0.0.0.0");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto addr6 = (struct sockaddr_in6 *)&addr;
|
||||
memset(&(addr6->sin6_addr.s6_addr), 0, 16);
|
||||
strcpy(straddr, "::");
|
||||
}
|
||||
}
|
||||
|
||||
const char *CIp::GetAddress() const
|
||||
{
|
||||
if (straddr[0])
|
||||
return straddr;
|
||||
|
||||
if (AF_INET == addr.ss_family)
|
||||
{
|
||||
auto addr4 = (struct sockaddr_in *)&addr;
|
||||
inet_ntop(AF_INET, &(addr4->sin_addr), straddr, INET6_ADDRSTRLEN);
|
||||
}
|
||||
else if (AF_INET6 == addr.ss_family)
|
||||
{
|
||||
auto addr6 = (struct sockaddr_in6 *)&addr;
|
||||
inet_ntop(AF_INET6, &(addr6->sin6_addr), straddr, INET6_ADDRSTRLEN);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "CIp::GetAddress: unknown socket family=" << addr.ss_family << std::endl;
|
||||
}
|
||||
return straddr;
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &stream, const CIp &Ip)
|
||||
{
|
||||
const char *sz = Ip;
|
||||
if (AF_INET6 == Ip.GetFamily())
|
||||
stream << "[" << sz << "]";
|
||||
else
|
||||
stream << sz;
|
||||
const uint16_t port = Ip.GetPort();
|
||||
if (port)
|
||||
stream << ":" << port;
|
||||
return stream;
|
||||
}
|
||||
|
||||
uint32_t CIp::GetAddr() const
|
||||
{
|
||||
if (AF_INET6 == addr.ss_family)
|
||||
{
|
||||
auto addr6 = (struct sockaddr_in6 *)&addr;
|
||||
// hash the results
|
||||
auto *a = (const uint32_t *)&(addr6->sin6_addr.s6_addr);
|
||||
return a[0] ^ a[1] ^ a[2] ^ a[3];
|
||||
}
|
||||
else
|
||||
{
|
||||
auto addr4 = (struct sockaddr_in *)&addr;
|
||||
return addr4->sin_addr.s_addr;
|
||||
}
|
||||
}
|
||||
|
||||
int CIp::GetFamily() const
|
||||
{
|
||||
return addr.ss_family;
|
||||
}
|
||||
|
||||
uint16_t CIp::GetPort() const
|
||||
{
|
||||
if (AF_INET == addr.ss_family)
|
||||
{
|
||||
auto addr4 = (struct sockaddr_in *)&addr;
|
||||
return ntohs(addr4->sin_port);
|
||||
}
|
||||
else if (AF_INET6 == addr.ss_family)
|
||||
{
|
||||
auto addr6 = (struct sockaddr_in6 *)&addr;
|
||||
return ntohs(addr6->sin6_port);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CIp::SetPort(const uint16_t newport)
|
||||
{
|
||||
if (AF_INET == addr.ss_family)
|
||||
{
|
||||
auto addr4 = (struct sockaddr_in *)&addr;
|
||||
addr4->sin_port = htons(newport);
|
||||
}
|
||||
else if (AF_INET6 == addr.ss_family)
|
||||
{
|
||||
auto addr6 = (struct sockaddr_in6 *)&addr;
|
||||
addr6->sin6_port = htons(newport);
|
||||
}
|
||||
}
|
||||
|
||||
struct sockaddr *CIp::GetPointer()
|
||||
{
|
||||
memset(straddr, 0, INET6_ADDRSTRLEN); // things might change
|
||||
return (struct sockaddr *)&addr;
|
||||
}
|
||||
|
||||
const struct sockaddr *CIp::GetCPointer() const
|
||||
{
|
||||
return (const struct sockaddr *)&addr;
|
||||
}
|
||||
|
||||
size_t CIp::GetSize() const
|
||||
{
|
||||
if (AF_INET == addr.ss_family)
|
||||
return sizeof(struct sockaddr_in);
|
||||
else
|
||||
return sizeof(struct sockaddr_in6);
|
||||
}
|
||||
|
||||
void CIp::Clear()
|
||||
{
|
||||
memset(&addr, 0, sizeof(struct sockaddr_storage));
|
||||
memset(straddr, 0, INET6_ADDRSTRLEN);
|
||||
is_set = false;
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* Copyright (C) 2020 by Thomas Early N7TAE
|
||||
*
|
||||
* 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 <iostream>
|
||||
#include <cstring>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <strings.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
class CIp
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CIp();
|
||||
CIp(const char *address, int family = AF_UNSPEC, int type = SOCK_DGRAM, uint16_t port = 0U);
|
||||
CIp(const int family, const uint16_t port = 0U, const char *address = nullptr);
|
||||
|
||||
// initializer for empty constructor
|
||||
void Initialize(const int family, const uint16_t port = 0U, const char *address = nullptr);
|
||||
|
||||
// comparison operators
|
||||
bool operator==(const CIp &rhs) const;
|
||||
bool operator!=(const CIp &rhs) const;
|
||||
|
||||
// state methods
|
||||
bool IsSet() const { return is_set; }
|
||||
bool AddressIsZero() const;
|
||||
void ClearAddress();
|
||||
const char *GetAddress() const;
|
||||
operator const char *() const { return GetAddress(); }
|
||||
friend std::ostream &operator<<(std::ostream &stream, const CIp &Ip);
|
||||
int GetFamily() const;
|
||||
uint16_t GetPort() const;
|
||||
size_t GetSize() const;
|
||||
uint32_t GetAddr() const;
|
||||
|
||||
// modifiers
|
||||
void SetPort(const uint16_t newport);
|
||||
|
||||
// for i/o
|
||||
struct sockaddr *GetPointer();
|
||||
const struct sockaddr *GetCPointer() const;
|
||||
|
||||
void Clear();
|
||||
|
||||
private:
|
||||
struct sockaddr_storage addr;
|
||||
mutable char straddr[INET6_ADDRSTRLEN];
|
||||
bool is_set;
|
||||
};
|
||||
|
||||
std::ostream &operator<<(std::ostream &stream, const CIp &Ip);
|
||||
@ -0,0 +1,85 @@
|
||||
//
|
||||
// main.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "Reflector.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// global objects
|
||||
|
||||
CReflector g_Reflector;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// function declaration
|
||||
|
||||
#include "Users.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
const std::string cs(CALLSIGN);
|
||||
if ((cs.size() != 6) || (cs.compare(0, 3, "XLX") && cs.compare(0, 3, "XRF")))
|
||||
{
|
||||
std::cerr << "Malformed reflector callsign: '" << cs << "', aborting!" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// remove pidfile
|
||||
remove(PIDFILE_PATH);
|
||||
|
||||
// splash
|
||||
std::cout << "Starting " << cs << " " << VERSION_MAJOR << "." << VERSION_MINOR << "." << VERSION_REVISION << std::endl << std::endl;
|
||||
|
||||
// initialize reflector
|
||||
g_Reflector.SetCallsign(cs.c_str());
|
||||
|
||||
#ifdef TRANSCODER_IP
|
||||
g_Reflector.SetTranscoderIp(TRANSCODER_IP, INET6_ADDRSTRLEN);
|
||||
#endif
|
||||
|
||||
|
||||
// and let it run
|
||||
if ( !g_Reflector.Start() )
|
||||
{
|
||||
std::cout << "Error starting reflector" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
std::cout << "Reflector " << g_Reflector.GetCallsign() << "started and listening" << std::endl;
|
||||
|
||||
// write new pid file
|
||||
std::ofstream ofs(PIDFILE_PATH, std::ofstream::out);
|
||||
ofs << getpid() << std::endl;
|
||||
ofs.close();
|
||||
|
||||
pause(); // wait for any signal
|
||||
|
||||
g_Reflector.Stop();
|
||||
std::cout << "Reflector stopped" << std::endl;
|
||||
|
||||
// done
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@ -0,0 +1,265 @@
|
||||
//
|
||||
// Main.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Eary, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef main_h
|
||||
#define main_h
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <chrono>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <ctime>
|
||||
#include <cctype>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <fstream>
|
||||
#include <algorithm>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "configure.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// defines
|
||||
|
||||
//// Module configuration
|
||||
#define DSTAR_IPV4 true
|
||||
#define DMR_IPV4 true
|
||||
#define YSF_IPV4 true
|
||||
#define XLX_IPV4 true
|
||||
|
||||
#define DSTAR_IPV6 true
|
||||
#define DMR_IPV6 false
|
||||
#define YSF_IPV6 false
|
||||
#define XLX_IPV6 false
|
||||
|
||||
// version -----------------------------------------------------
|
||||
|
||||
#define VERSION_MAJOR 2
|
||||
#define VERSION_MINOR 4
|
||||
#define VERSION_REVISION 31
|
||||
|
||||
// global ------------------------------------------------------
|
||||
|
||||
//#define JSON_MONITOR
|
||||
|
||||
// debug -------------------------------------------------------
|
||||
|
||||
//#define DEBUG_NO_ERROR_ON_XML_OPEN_FAIL
|
||||
//#define DEBUG_DUMPFILE
|
||||
|
||||
// protocols ---------------------------------------------------
|
||||
|
||||
#define PROTOCOL_ANY -1
|
||||
#define PROTOCOL_NONE 0
|
||||
#define PROTOCOL_DEXTRA 1
|
||||
#define PROTOCOL_DPLUS 2
|
||||
#define PROTOCOL_DCS 3
|
||||
#ifndef NO_XLX
|
||||
#define PROTOCOL_XLX 4
|
||||
#define PROTOCOL_DMRPLUS 5
|
||||
#define PROTOCOL_DMRMMDVM 6
|
||||
#define PROTOCOL_YSF 7
|
||||
#endif
|
||||
#ifndef NO_G3
|
||||
#define PROTOCOL_G3 8
|
||||
#endif
|
||||
|
||||
// DExtra
|
||||
#define DEXTRA_PORT 30001 // UDP port
|
||||
#define DEXTRA_KEEPALIVE_PERIOD 3 // in seconds
|
||||
#define DEXTRA_KEEPALIVE_TIMEOUT (DEXTRA_KEEPALIVE_PERIOD*10) // in seconds
|
||||
#define DEXTRA_RECONNECT_PERIOD 5 // in seconds
|
||||
|
||||
// DPlus
|
||||
#define DPLUS_PORT 20001 // UDP port
|
||||
#define DPLUS_KEEPALIVE_PERIOD 1 // in seconds
|
||||
#define DPLUS_KEEPALIVE_TIMEOUT (DPLUS_KEEPALIVE_PERIOD*10) // in seconds
|
||||
|
||||
// DCS
|
||||
#define DCS_PORT 30051 // UDP port
|
||||
#define DCS_KEEPALIVE_PERIOD 1 // in seconds
|
||||
#define DCS_KEEPALIVE_TIMEOUT (DCS_KEEPALIVE_PERIOD*30) // in seconds
|
||||
|
||||
#ifndef NO_XLX
|
||||
// XLX
|
||||
#define XLX_PORT 10002 // UDP port
|
||||
#define XLX_KEEPALIVE_PERIOD 1 // in seconds
|
||||
#define XLX_KEEPALIVE_TIMEOUT (XLX_KEEPALIVE_PERIOD*30) // in seconds
|
||||
#define XLX_RECONNECT_PERIOD 5 // in seconds
|
||||
|
||||
// DMRPlus (dongle)
|
||||
#define DMRPLUS_PORT 8880 // UDP port
|
||||
#define DMRPLUS_KEEPALIVE_PERIOD 1 // in seconds
|
||||
#define DMRPLUS_KEEPALIVE_TIMEOUT (DMRPLUS_KEEPALIVE_PERIOD*10) // in seconds
|
||||
#define DMRPLUS_REFLECTOR_SLOT DMR_SLOT2
|
||||
#define DMRPLUS_REFLECTOR_COLOUR 1
|
||||
|
||||
// DMRMmdvm
|
||||
#define DMRMMDVM_PORT 62030 // UDP port
|
||||
#define DMRMMDVM_KEEPALIVE_PERIOD 10 // in seconds
|
||||
#define DMRMMDVM_KEEPALIVE_TIMEOUT (DMRMMDVM_KEEPALIVE_PERIOD*10) // in seconds
|
||||
#define DMRMMDVM_REFLECTOR_SLOT DMR_SLOT2
|
||||
#define DMRMMDVM_REFLECTOR_COLOUR 1
|
||||
|
||||
// YSF
|
||||
#define YSF_PORT 42000 // UDP port
|
||||
#define YSF_KEEPALIVE_PERIOD 3 // in seconds
|
||||
#define YSF_KEEPALIVE_TIMEOUT (YSF_KEEPALIVE_PERIOD*10) // in seconds
|
||||
#define YSF_DEFAULT_NODE_TX_FREQ 445500000 // in Hz
|
||||
#define YSF_DEFAULT_NODE_RX_FREQ 445500000 // in Hz
|
||||
// the following two defines are now in configure.h
|
||||
// #define YSF_AUTOLINK_ENABLE 0 // 1 = enable, 0 = disable auto-link
|
||||
// #define YSF_AUTOLINK_MODULE 'B' // module for client to auto-link to
|
||||
#endif
|
||||
|
||||
#ifndef NO_G3
|
||||
// G3 Terminal
|
||||
#define G3_PRESENCE_PORT 12346 // UDP port
|
||||
#define G3_CONFIG_PORT 12345 // UDP port
|
||||
#define G3_DV_PORT 40000 // UDP port
|
||||
#define G3_KEEPALIVE_PERIOD 10 // in seconds
|
||||
#define G3_KEEPALIVE_TIMEOUT 3600 // in seconds, 1 hour
|
||||
#endif
|
||||
|
||||
#ifdef TRANSCODER_IP
|
||||
// Transcoder server --------------------------------------------
|
||||
|
||||
#define TRANSCODER_PORT 10100 // UDP port
|
||||
#define TRANSCODER_KEEPALIVE_PERIOD 5 // in seconds
|
||||
#define TRANSCODER_KEEPALIVE_TIMEOUT 30 // in seconds
|
||||
#define TRANSCODER_AMBEPACKET_TIMEOUT 400 // in ms
|
||||
#endif
|
||||
|
||||
// codec --------------------------------------------------------
|
||||
|
||||
#define CODEC_NONE 0
|
||||
#define CODEC_AMBEPLUS 1 // DStar
|
||||
#ifndef NO_XLX
|
||||
#define CODEC_AMBE2PLUS 2 // DMR
|
||||
|
||||
|
||||
// DMRid database -----------------------------------------------
|
||||
|
||||
#define DMRIDDB_USE_RLX_SERVER 1 // 1 = use http, 0 = use local file
|
||||
#define DMRIDDB_PATH "/usr/local/etc/dmrid.dat" // local file path
|
||||
#define DMRIDDB_REFRESH_RATE 180 // in minutes
|
||||
|
||||
// Wires-X node database ----------------------------------------
|
||||
|
||||
#define YSFNODEDB_USE_RLX_SERVER 1 // 1 = use http, 0 = use local file
|
||||
#define YSFNODEDB_PATH "/usr/local/etc/ysfnode.dat" // local file path
|
||||
#define YSFNODEDB_REFRESH_RATE 180 // in minutes
|
||||
#endif
|
||||
|
||||
// xml & json reporting -----------------------------------------
|
||||
|
||||
#define LASTHEARD_USERS_MAX_SIZE 100
|
||||
#define XML_UPDATE_PERIOD 10 // in seconds
|
||||
#ifdef JSON_MONITOR
|
||||
#define JSON_UPDATE_PERIOD 10 // in seconds
|
||||
#define JSON_PORT 10001
|
||||
#endif
|
||||
|
||||
// system paths -------------------------------------------------
|
||||
#ifdef NO_XLX
|
||||
#define XML_PATH "/var/log/xrfd.xml"
|
||||
#define WHITELIST_PATH "/usr/local/etc/xrfd.whitelist"
|
||||
#define BLACKLIST_PATH "/usr/local/etc/xrfd.blacklist"
|
||||
#define INTERLINKLIST_PATH "/usr/local/etc/xrfd.interlink"
|
||||
#define TERMINALOPTIONS_PATH "/usr/local/etc/xrfd.terminal"
|
||||
#define DEBUGDUMP_PATH "/var/log/xrfd.debug"
|
||||
#define PIDFILE_PATH "/var/run/xrfd.pid"
|
||||
#else
|
||||
#define XML_PATH "/var/log/xlxd.xml"
|
||||
#define WHITELIST_PATH "/usr/local/etc/xlxd.whitelist"
|
||||
#define BLACKLIST_PATH "/usr/local/etc/xlxd.blacklist"
|
||||
#define INTERLINKLIST_PATH "/usr/local/etc/xlxd.interlink"
|
||||
#define TERMINALOPTIONS_PATH "/usr/local/etc/xlxd.terminal"
|
||||
#define DEBUGDUMP_PATH "/var/log/xlxd.debug"
|
||||
#define PIDFILE_PATH "/var/run/xlxd.pid"
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// typedefs
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short uint16;
|
||||
typedef unsigned int uint32;
|
||||
typedef unsigned int uint;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// macros
|
||||
|
||||
#define MIN(a,b) ((a)<(b))?(a):(b)
|
||||
#define MAX(a,b) ((a)>(b))?(a):(b)
|
||||
#define MAKEWORD(low, high) ((uint16)(((uint8)(low)) | (((uint16)((uint8)(high))) << 8)))
|
||||
#define MAKEDWORD(low, high) ((uint32)(((uint16)(low)) | (((uint32)((uint16)(high))) << 16)))
|
||||
#define LOBYTE(w) ((uint8)(uint16)(w & 0x00FF))
|
||||
#define HIBYTE(w) ((uint8)((((uint16)(w)) >> 8) & 0xFF))
|
||||
#define LOWORD(dw) ((uint16)(uint32)(dw & 0x0000FFFF))
|
||||
#define HIWORD(dw) ((uint16)((((uint32)(dw)) >> 16) & 0xFFFF))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// global objects
|
||||
|
||||
class CReflector;
|
||||
extern CReflector g_Reflector;
|
||||
|
||||
class CGateKeeper;
|
||||
extern CGateKeeper g_GateKeeper;
|
||||
|
||||
#ifndef NO_XLX
|
||||
#if (DMRIDDB_USE_RLX_SERVER == 1)
|
||||
class CDmridDirHttp;
|
||||
extern CDmridDirHttp g_DmridDir;
|
||||
#else
|
||||
class CDmridDirFile;
|
||||
extern CDmridDirFile g_DmridDir;
|
||||
#endif
|
||||
|
||||
#if (YSFNODEDB_USE_RLX_SERVER == 1)
|
||||
class CYsfNodeDirHttp;
|
||||
extern CYsfNodeDirHttp g_YsfNodeDir;
|
||||
#else
|
||||
class CYsfNodeDirFile;
|
||||
extern CYsfNodeDirFile g_YsfNodeDir;
|
||||
#endif
|
||||
|
||||
class CTranscoder;
|
||||
extern CTranscoder g_Transcoder;
|
||||
#endif
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* main_h */
|
||||
@ -0,0 +1,46 @@
|
||||
//
|
||||
// cnotification.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc on 05/12/2015.
|
||||
// Copyright © 2015 Jean-Luc. All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "cnotification.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CNotification::CNotification()
|
||||
{
|
||||
// init variables
|
||||
m_iId = NOTIFICATION_NONE;
|
||||
}
|
||||
|
||||
CNotification::CNotification(int iId)
|
||||
{
|
||||
m_iId = iId;
|
||||
}
|
||||
|
||||
CNotification::CNotification(int iId, const CCallsign &Callsign)
|
||||
{
|
||||
m_iId = iId;
|
||||
m_Callsign = Callsign;
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
//
|
||||
// cnotification.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc on 05/12/2015.
|
||||
// Copyright © 2015 Jean-Luc. All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef cnotification_h
|
||||
#define cnotification_h
|
||||
|
||||
#include "Callsign.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Id
|
||||
#define NOTIFICATION_NONE 0
|
||||
#define NOTIFICATION_CLIENTS 1
|
||||
#define NOTIFICATION_USERS 2
|
||||
#define NOTIFICATION_STREAM_OPEN 3
|
||||
#define NOTIFICATION_STREAM_CLOSE 4
|
||||
#define NOTIFICATION_PEERS 5
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CNotification
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CNotification();
|
||||
CNotification(int);
|
||||
CNotification(int, const CCallsign &);
|
||||
|
||||
// get
|
||||
int GetId(void) const { return m_iId; }
|
||||
const CCallsign &GetCallsign(void) const { return m_Callsign; }
|
||||
|
||||
protected:
|
||||
// data
|
||||
int m_iId;
|
||||
CCallsign m_Callsign;
|
||||
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cnotification_h */
|
||||
@ -0,0 +1,134 @@
|
||||
//
|
||||
// cpacket.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 04/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "Packet.h"
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CPacket::CPacket()
|
||||
{
|
||||
m_uiStreamId = 0;
|
||||
m_uiDstarPacketId = 0;
|
||||
m_uiDmrPacketId = 0;
|
||||
m_uiDmrPacketSubid = 0;
|
||||
m_uiYsfPacketId = 0;
|
||||
m_uiYsfPacketSubId = 0;
|
||||
m_uiYsfPacketFrameId = 0;
|
||||
m_uiModuleId = ' ';
|
||||
m_uiOriginId = ORIGIN_LOCAL;
|
||||
};
|
||||
|
||||
// dstar contrsuctor
|
||||
|
||||
CPacket::CPacket(uint16 sid, uint8 dstarpid)
|
||||
{
|
||||
m_uiStreamId = sid;
|
||||
m_uiDstarPacketId = dstarpid;
|
||||
m_uiDmrPacketId = 0xFF;
|
||||
m_uiDmrPacketSubid = 0xFF;
|
||||
m_uiYsfPacketId = 0xFF;
|
||||
m_uiYsfPacketSubId = 0xFF;
|
||||
m_uiYsfPacketFrameId = 0xFF;
|
||||
m_uiModuleId = ' ';
|
||||
m_uiOriginId = ORIGIN_LOCAL;
|
||||
};
|
||||
|
||||
// dmr constructor
|
||||
|
||||
CPacket::CPacket(uint16 sid, uint8 dmrpid, uint8 dmrspid)
|
||||
{
|
||||
m_uiStreamId = sid;
|
||||
m_uiDmrPacketId = dmrpid;
|
||||
m_uiDmrPacketSubid = dmrspid;
|
||||
m_uiDstarPacketId = 0xFF;
|
||||
m_uiYsfPacketId = 0xFF;
|
||||
m_uiYsfPacketSubId = 0xFF;
|
||||
m_uiYsfPacketFrameId = 0xFF;
|
||||
m_uiModuleId = ' ';
|
||||
m_uiOriginId = ORIGIN_LOCAL;
|
||||
};
|
||||
|
||||
// ysf constructor
|
||||
|
||||
CPacket::CPacket(uint16 sid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysffrid)
|
||||
{
|
||||
m_uiStreamId = sid;
|
||||
m_uiYsfPacketId = ysfpid;
|
||||
m_uiYsfPacketSubId = ysfsubpid;
|
||||
m_uiYsfPacketFrameId = ysffrid;
|
||||
m_uiDstarPacketId = 0xFF;
|
||||
m_uiDmrPacketId = 0xFF;
|
||||
m_uiDmrPacketSubid = 0xFF;
|
||||
m_uiModuleId = ' ';
|
||||
m_uiOriginId = ORIGIN_LOCAL;
|
||||
}
|
||||
|
||||
// xlx constructor
|
||||
|
||||
CPacket::CPacket(uint16 sid, uint8 dstarpid, uint8 dmrpid, uint8 dmrsubpid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysffrid)
|
||||
{
|
||||
m_uiStreamId = sid;
|
||||
m_uiDstarPacketId = dstarpid;
|
||||
m_uiDmrPacketId = dmrpid;
|
||||
m_uiDmrPacketSubid = dmrsubpid;
|
||||
m_uiYsfPacketId = ysfpid;
|
||||
m_uiYsfPacketSubId = ysfsubpid;
|
||||
m_uiYsfPacketFrameId = ysffrid;
|
||||
m_uiModuleId = ' ';
|
||||
m_uiOriginId = ORIGIN_LOCAL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// pid conversion
|
||||
|
||||
void CPacket::UpdatePids(uint32 pid)
|
||||
{
|
||||
// called while phusing this packet in a stream queue
|
||||
// so now packet sequence number is known and undefined pids can be updated
|
||||
// this is needed as dtsar & dmt pids are different and cannot be
|
||||
// derived from each other
|
||||
|
||||
// dstar pid needs update ?
|
||||
if ( m_uiDstarPacketId == 0xFF )
|
||||
{
|
||||
m_uiDstarPacketId = (pid % 21);
|
||||
}
|
||||
// dmr pids need update ?
|
||||
if ( m_uiDmrPacketId == 0xFF )
|
||||
{
|
||||
m_uiDmrPacketId = ((pid / 3) % 6);
|
||||
m_uiDmrPacketSubid = ((pid % 3) + 1);
|
||||
}
|
||||
// ysf pids need update ?
|
||||
if ( m_uiYsfPacketId == 0xFF )
|
||||
{
|
||||
m_uiYsfPacketId = ((pid / 5) % 8);
|
||||
m_uiYsfPacketSubId = pid % 5;
|
||||
m_uiYsfPacketFrameId = ((pid / 5) & 0x7FU) << 1;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
//
|
||||
// Packet.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 01/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cpacket_h
|
||||
#define cpacket_h
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Origin Id
|
||||
|
||||
#define ORIGIN_LOCAL 0
|
||||
#define ORIGIN_PEER 1
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CPacket
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CPacket();
|
||||
CPacket(uint16 sid, uint8 dstarpid);
|
||||
CPacket(uint16 sid, uint8 dmrpid, uint8 dmrsubpid);
|
||||
CPacket(uint16 sid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysfsubpidmax);
|
||||
CPacket(uint16 sid, uint8 dstarpid, uint8 dmrpid, uint8 dmrsubpid, uint8 ysfpid, uint8 ysfsubpid, uint8 ysfsubpidmax);
|
||||
|
||||
// destructor
|
||||
virtual ~CPacket() {}
|
||||
|
||||
// virtual duplication
|
||||
virtual std::unique_ptr<CPacket> Duplicate(void) const = 0;
|
||||
|
||||
// identity
|
||||
virtual bool IsDvHeader(void) const { return false; }
|
||||
virtual bool IsDvFrame(void) const { return false; }
|
||||
virtual bool IsLastPacket(void) const { return false; }
|
||||
virtual bool HasTranscodableAmbe(void) const { return false; }
|
||||
|
||||
// get
|
||||
virtual bool IsValid(void) const { return true; }
|
||||
uint16 GetStreamId(void) const { return m_uiStreamId; }
|
||||
uint8 GetPacketId(void) const { return m_uiDstarPacketId; }
|
||||
uint8 GetDstarPacketId(void) const { return m_uiDstarPacketId; }
|
||||
uint8 GetDmrPacketId(void) const { return m_uiDmrPacketId; }
|
||||
uint8 GetDmrPacketSubid(void) const { return m_uiDmrPacketSubid; }
|
||||
uint8 GetYsfPacketId(void) const { return m_uiYsfPacketId; }
|
||||
uint8 GetYsfPacketSubId(void) const { return m_uiYsfPacketSubId; }
|
||||
uint8 GetYsfPacketFrameId(void) const { return m_uiYsfPacketFrameId; }
|
||||
uint8 GetModuleId(void) const { return m_uiModuleId; }
|
||||
bool IsLocalOrigin(void) const { return (m_uiOriginId == ORIGIN_LOCAL); }
|
||||
|
||||
// set
|
||||
void UpdatePids(uint32);
|
||||
void SetModuleId(uint8 uiId) { m_uiModuleId = uiId; }
|
||||
void SetLocalOrigin(void) { m_uiOriginId = ORIGIN_LOCAL; }
|
||||
void SetRemotePeerOrigin(void) { m_uiOriginId = ORIGIN_PEER; }
|
||||
|
||||
protected:
|
||||
// data
|
||||
uint16 m_uiStreamId;
|
||||
uint8 m_uiDstarPacketId;
|
||||
uint8 m_uiDmrPacketId;
|
||||
uint8 m_uiDmrPacketSubid;
|
||||
uint8 m_uiYsfPacketId;
|
||||
uint8 m_uiYsfPacketSubId;
|
||||
uint8 m_uiYsfPacketFrameId;
|
||||
uint8 m_uiModuleId;
|
||||
uint8 m_uiOriginId;
|
||||
};
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cpacket_h */
|
||||
@ -0,0 +1,67 @@
|
||||
//
|
||||
// PacketQueue.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 02/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cpacketqueue_h
|
||||
#define cpacketqueue_h
|
||||
|
||||
#include "Packet.h"
|
||||
#include "Client.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CPacketQueue
|
||||
|
||||
class CClient;
|
||||
|
||||
class CPacketQueue
|
||||
{
|
||||
public:
|
||||
// destructor
|
||||
virtual ~CPacketQueue() {}
|
||||
|
||||
// lock
|
||||
void Lock() { m_Mutex.lock(); }
|
||||
void Unlock() { m_Mutex.unlock(); }
|
||||
|
||||
// pass thru
|
||||
void pop() { queue.pop(); }
|
||||
bool empty() const { return queue.empty(); }
|
||||
std::unique_ptr<CPacket> front() { return std::move(queue.front()); }
|
||||
void push(std::unique_ptr<CPacket> &packet) { queue.push(std::move(packet)); }
|
||||
|
||||
protected:
|
||||
// status
|
||||
bool m_bOpen;
|
||||
uint16 m_uiStreamId;
|
||||
std::mutex m_Mutex;
|
||||
|
||||
// owner
|
||||
CClient *m_Client;
|
||||
std::queue<std::unique_ptr<CPacket>> queue;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cpacketqueue_h */
|
||||
@ -0,0 +1,148 @@
|
||||
//
|
||||
// cpacketstream.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 06/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "PacketStream.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CPacketStream::CPacketStream()
|
||||
{
|
||||
m_bOpen = false;
|
||||
m_uiStreamId = 0;
|
||||
m_uiPacketCntr = 0;
|
||||
m_OwnerClient = nullptr;
|
||||
#ifdef TRANSCODER_IP
|
||||
m_CodecStream = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// open / close
|
||||
|
||||
bool CPacketStream::OpenPacketStream(const CDvHeaderPacket &DvHeader, std::shared_ptr<CClient>client)
|
||||
{
|
||||
bool ok = false;
|
||||
|
||||
// not already open?
|
||||
if ( !m_bOpen )
|
||||
{
|
||||
// update status
|
||||
m_bOpen = true;
|
||||
m_uiStreamId = DvHeader.GetStreamId();
|
||||
m_uiPacketCntr = 0;
|
||||
m_DvHeader = DvHeader;
|
||||
m_OwnerClient = client;
|
||||
m_LastPacketTime.Now();
|
||||
#ifdef TRANSCODER_IP
|
||||
if (std::string::npos != std::string(TRANSCODED_MODULES).find(DvHeader.GetRpt2Module()))
|
||||
m_CodecStream = g_Transcoder.GetCodecStream(this, client->GetCodec());
|
||||
else
|
||||
m_CodecStream = g_Transcoder.GetCodecStream(this, CODEC_NONE);
|
||||
#endif
|
||||
ok = true;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
void CPacketStream::ClosePacketStream(void)
|
||||
{
|
||||
// update status
|
||||
m_bOpen = false;
|
||||
m_uiStreamId = 0;
|
||||
m_OwnerClient = nullptr;
|
||||
#ifdef TRANSCODER_IP
|
||||
g_Transcoder.ReleaseStream(m_CodecStream);
|
||||
m_CodecStream = nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// push & pop
|
||||
|
||||
void CPacketStream::Push(std::unique_ptr<CPacket> Packet)
|
||||
{
|
||||
// update stream dependent packet data
|
||||
m_LastPacketTime.Now();
|
||||
Packet->UpdatePids(m_uiPacketCntr++);
|
||||
// transcoder avaliable ?
|
||||
#ifdef TRANSCODER_IP
|
||||
if ( m_CodecStream != nullptr )
|
||||
{
|
||||
// todo: verify no possibilty of double lock here
|
||||
m_CodecStream->Lock();
|
||||
{
|
||||
// transcoder ready & frame need transcoding ?
|
||||
if ( m_CodecStream->IsConnected() && Packet->HasTranscodableAmbe() )
|
||||
{
|
||||
// yes, push packet to trancoder queue
|
||||
// trancoder will push it after transcoding
|
||||
// is completed
|
||||
m_CodecStream->push(Packet);
|
||||
}
|
||||
else
|
||||
{
|
||||
// no, just bypass tarnscoder
|
||||
push(Packet);
|
||||
}
|
||||
}
|
||||
m_CodecStream->Unlock();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// otherwise, push direct push
|
||||
push(Packet);
|
||||
}
|
||||
}
|
||||
|
||||
bool CPacketStream::IsEmpty(void) const
|
||||
{
|
||||
#ifdef TRANSCODER_IP
|
||||
bool bEmpty = empty();
|
||||
// also check no packets still in Codec stream's queue
|
||||
if ( bEmpty && (m_CodecStream != nullptr) )
|
||||
{
|
||||
bEmpty = m_CodecStream->IsEmpty();
|
||||
}
|
||||
|
||||
// done
|
||||
return bEmpty;
|
||||
#else
|
||||
return empty();
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// get
|
||||
|
||||
const CIp *CPacketStream::GetOwnerIp(void)
|
||||
{
|
||||
if ( m_OwnerClient != nullptr )
|
||||
{
|
||||
return &(m_OwnerClient->GetIp());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
//
|
||||
// PacketStream.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 06/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cpacketstream_h
|
||||
#define cpacketstream_h
|
||||
|
||||
#include "PacketQueue.h"
|
||||
#include "Timer.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
#include "Transcoder.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//#define STREAM_TIMEOUT (0.600)
|
||||
#define STREAM_TIMEOUT (1.600)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CPacketStream : public CPacketQueue
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CPacketStream();
|
||||
|
||||
// open / close
|
||||
bool OpenPacketStream(const CDvHeaderPacket &, std::shared_ptr<CClient>);
|
||||
void ClosePacketStream(void);
|
||||
|
||||
// push & pop
|
||||
void Push(std::unique_ptr<CPacket> packet);
|
||||
void Tickle(void) { m_LastPacketTime.Now(); }
|
||||
bool IsEmpty(void) const;
|
||||
|
||||
// get
|
||||
std::shared_ptr<CClient> GetOwnerClient(void) { return m_OwnerClient; }
|
||||
const CIp *GetOwnerIp(void);
|
||||
bool IsExpired(void) const { return (m_LastPacketTime.DurationSinceNow() > STREAM_TIMEOUT); }
|
||||
bool IsOpen(void) const { return m_bOpen; }
|
||||
uint16 GetStreamId(void) const { return m_uiStreamId; }
|
||||
const CCallsign &GetUserCallsign(void) const { return m_DvHeader.GetMyCallsign(); }
|
||||
|
||||
protected:
|
||||
// data
|
||||
bool m_bOpen;
|
||||
uint16 m_uiStreamId;
|
||||
uint32 m_uiPacketCntr;
|
||||
CTimePoint m_LastPacketTime;
|
||||
CDvHeaderPacket m_DvHeader;
|
||||
std::shared_ptr<CClient> m_OwnerClient;
|
||||
#ifdef TRANSCODER_IP
|
||||
std::shared_ptr<CCodecStream> m_CodecStream;
|
||||
#endif
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cpacketstream_h */
|
||||
@ -0,0 +1,151 @@
|
||||
//
|
||||
// cpeer.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 10/12/2016.
|
||||
// Copyright © 2016 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include "Reflector.h"
|
||||
#include "Peer.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
|
||||
CPeer::CPeer()
|
||||
{
|
||||
::memset(m_ReflectorModules, 0, sizeof(m_ReflectorModules));
|
||||
m_ConnectTime = std::time(nullptr);
|
||||
m_LastHeardTime = std::time(nullptr);
|
||||
}
|
||||
|
||||
CPeer::CPeer(const CCallsign &callsign, const CIp &ip, const char *modules, const CVersion &version)
|
||||
{
|
||||
m_Callsign = callsign;
|
||||
m_Ip = ip;
|
||||
::memset(m_ReflectorModules, 0, sizeof(m_ReflectorModules));
|
||||
::strncpy(m_ReflectorModules, modules, sizeof(m_ReflectorModules)-1);
|
||||
m_Version = version;
|
||||
m_LastKeepaliveTime.Now();
|
||||
m_ConnectTime = std::time(nullptr);
|
||||
m_LastHeardTime = std::time(nullptr);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// destructors
|
||||
|
||||
CPeer::~CPeer()
|
||||
{
|
||||
m_Clients.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operators
|
||||
|
||||
bool CPeer::operator ==(const CPeer &peer) const
|
||||
{
|
||||
if (peer.m_Callsign != m_Callsign)
|
||||
return false;
|
||||
if (peer.m_Ip != m_Ip)
|
||||
return false;
|
||||
if (! (peer.m_Version == m_Version))
|
||||
return false;
|
||||
auto it1 = cbegin();
|
||||
auto it2 = peer.cbegin();
|
||||
while (true)
|
||||
{
|
||||
if (it1==cend() && it2==peer.cend())
|
||||
break;
|
||||
if (it1==cend() || it2==peer.cend())
|
||||
return false;
|
||||
if (*it1 != *it2)
|
||||
return false;
|
||||
it1++;
|
||||
it2++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// status
|
||||
|
||||
bool CPeer::IsAMaster(void) const
|
||||
{
|
||||
for ( auto it=cbegin(); it!=cend(); it++ )
|
||||
{
|
||||
if ((*it)->IsAMaster())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CPeer::Alive(void)
|
||||
{
|
||||
m_LastKeepaliveTime.Now();
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
(*it)->Alive();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// reporting
|
||||
|
||||
void CPeer::WriteXml(std::ofstream &xmlFile)
|
||||
{
|
||||
xmlFile << "<PEER>" << std::endl;
|
||||
xmlFile << "\t<Callsign>" << m_Callsign << "</Callsign>" << std::endl;
|
||||
xmlFile << "\t<IP>" << m_Ip.GetAddress() << "</IP>" << std::endl;
|
||||
xmlFile << "\t<LinkedModule>" << m_ReflectorModules << "</LinkedModule>" << std::endl;
|
||||
xmlFile << "\t<Protocol>" << GetProtocolName() << "</Protocol>" << std::endl;
|
||||
char mbstr[100];
|
||||
if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_ConnectTime)))
|
||||
{
|
||||
xmlFile << "\t<ConnectTime>" << mbstr << "</ConnectTime>" << std::endl;
|
||||
}
|
||||
if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_LastHeardTime)))
|
||||
{
|
||||
xmlFile << "\t<LastHeardTime>" << mbstr << "</LastHeardTime>" << std::endl;
|
||||
}
|
||||
xmlFile << "</PEER>" << std::endl;
|
||||
}
|
||||
|
||||
void CPeer::GetJsonObject(char *Buffer)
|
||||
{
|
||||
char sz[512];
|
||||
char mbstr[100];
|
||||
char cs[16];
|
||||
|
||||
if (std::strftime(mbstr, sizeof(mbstr), "%A %c", std::localtime(&m_LastHeardTime)))
|
||||
{
|
||||
m_Callsign.GetCallsignString(cs);
|
||||
|
||||
::sprintf(sz, "{\"callsign\":\"%s\",\"linkedto\":\"%s\",\"time\":\"%s\"}",
|
||||
cs,
|
||||
m_ReflectorModules,
|
||||
mbstr);
|
||||
::strcat(Buffer, sz);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
//
|
||||
// Peer.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 10/12/2016.
|
||||
// Copyright © 2016 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cpeer_h
|
||||
#define cpeer_h
|
||||
|
||||
#include "Version.h"
|
||||
#include "Timer.h"
|
||||
#include "IP.h"
|
||||
#include "Callsign.h"
|
||||
#include "Client.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CPeer
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CPeer();
|
||||
CPeer(const CCallsign &, const CIp &, const char *, const CVersion &);
|
||||
CPeer(const CPeer &) = delete;
|
||||
|
||||
// destructor
|
||||
virtual ~CPeer();
|
||||
|
||||
// operators
|
||||
bool operator ==(const CPeer &) const;
|
||||
|
||||
// get
|
||||
const CCallsign &GetCallsign(void) const { return m_Callsign; }
|
||||
const CIp &GetIp(void) const { return m_Ip; }
|
||||
char *GetReflectorModules(void) { return m_ReflectorModules; }
|
||||
|
||||
// set
|
||||
|
||||
// identity
|
||||
virtual int GetProtocol(void) const { return PROTOCOL_NONE; }
|
||||
virtual int GetProtocolRevision(void) const { return 0; }
|
||||
virtual const char *GetProtocolName(void) const { return "none"; }
|
||||
|
||||
// status
|
||||
virtual bool IsAMaster(void) const;
|
||||
virtual void Alive(void);
|
||||
virtual bool IsAlive(void) const { return false; }
|
||||
virtual void Heard(void) { m_LastHeardTime = std::time(nullptr); }
|
||||
|
||||
// clients access
|
||||
int GetNbClients(void) const { return (int)m_Clients.size(); }
|
||||
void ClearClients(void) { m_Clients.clear(); }
|
||||
|
||||
// pass-thru
|
||||
std::list<std::shared_ptr<CClient>>::iterator begin() { return m_Clients.begin(); }
|
||||
std::list<std::shared_ptr<CClient>>::iterator end() { return m_Clients.end(); }
|
||||
std::list<std::shared_ptr<CClient>>::const_iterator cbegin() const { return m_Clients.cbegin(); }
|
||||
std::list<std::shared_ptr<CClient>>::const_iterator cend() const { return m_Clients.cend(); }
|
||||
|
||||
// reporting
|
||||
virtual void WriteXml(std::ofstream &);
|
||||
virtual void GetJsonObject(char *);
|
||||
|
||||
protected:
|
||||
// data
|
||||
CCallsign m_Callsign;
|
||||
CIp m_Ip;
|
||||
char m_ReflectorModules[27];
|
||||
CVersion m_Version;
|
||||
std::list<std::shared_ptr<CClient>> m_Clients;
|
||||
|
||||
// status
|
||||
CTimePoint m_LastKeepaliveTime;
|
||||
std::time_t m_ConnectTime;
|
||||
std::time_t m_LastHeardTime;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cpeer_h */
|
||||
@ -0,0 +1,93 @@
|
||||
//
|
||||
// cxlxcallsignlist.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/01/2016.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <string.h>
|
||||
#include "Main.h"
|
||||
#include "PeerCallsignList.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// file io
|
||||
|
||||
bool CPeerCallsignList::LoadFromFile(const char *filename)
|
||||
{
|
||||
bool ok = false;
|
||||
char sz[256];
|
||||
|
||||
// and load
|
||||
std::ifstream file (filename);
|
||||
if ( file.is_open() )
|
||||
{
|
||||
Lock();
|
||||
|
||||
// empty list
|
||||
m_Callsigns.clear();
|
||||
// fill with file content
|
||||
while ( file.getline(sz, sizeof(sz)).good() )
|
||||
{
|
||||
// remove leading & trailing spaces
|
||||
char *szt = TrimWhiteSpaces(sz);
|
||||
|
||||
// crack it
|
||||
if ( (::strlen(szt) > 0) && (szt[0] != '#') )
|
||||
{
|
||||
// 1st token is callsign
|
||||
if ( (szt = ::strtok(szt, " ,\t")) != nullptr )
|
||||
{
|
||||
CCallsign callsign(szt);
|
||||
// 2nd token is ip
|
||||
char *szip;
|
||||
if ( (szip = ::strtok(nullptr, " ,\t")) != nullptr )
|
||||
{
|
||||
// 3rd token is modules list
|
||||
if ( (szt = ::strtok(nullptr, " ,\t")) != nullptr )
|
||||
{
|
||||
// and load
|
||||
m_Callsigns.push_back(CCallsignListItem(callsign, szip, szt));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// close file
|
||||
file.close();
|
||||
|
||||
// keep file path
|
||||
m_Filename = filename;
|
||||
|
||||
// update time
|
||||
GetLastModTime(&m_LastModTime);
|
||||
|
||||
// and done
|
||||
Unlock();
|
||||
ok = true;
|
||||
std::cout << "Gatekeeper loaded " << m_Callsigns.size() << " lines from " << filename << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Gatekeeper cannot find " << filename << std::endl;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
//
|
||||
// PeerCallsignList.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/01/2016.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef cpeercallsignlist_h
|
||||
#define cpeercallsignlist_h
|
||||
|
||||
|
||||
#include "Main.h"
|
||||
#include "CallsignList.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CPeerCallsignList : public CCallsignList
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CPeerCallsignList() {}
|
||||
|
||||
// destructor
|
||||
virtual ~CPeerCallsignList() {}
|
||||
|
||||
// file io
|
||||
bool LoadFromFile(const char *);
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cpeercallsignlist_h */
|
||||
@ -0,0 +1,171 @@
|
||||
//
|
||||
// cpeers.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 10/12/2016.
|
||||
// Copyright © 2016 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "Reflector.h"
|
||||
#include "Peers.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
|
||||
CPeers::CPeers() {}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// destructors
|
||||
|
||||
CPeers::~CPeers()
|
||||
{
|
||||
m_Mutex.lock();
|
||||
m_Peers.clear();
|
||||
m_Mutex.unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// manage peers
|
||||
|
||||
void CPeers::AddPeer(std::shared_ptr<CPeer> peer)
|
||||
{
|
||||
// first check if peer already exists
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
if (*peer == *(*it))
|
||||
// if found, just do nothing
|
||||
// so *peer keep pointing on a valid object
|
||||
// on function return
|
||||
{
|
||||
// delete new one
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if not, append to the vector
|
||||
m_Peers.push_back(peer);
|
||||
std::cout << "New peer " << peer->GetCallsign() << " at " << peer->GetIp() << " added with protocol " << peer->GetProtocolName() << std::endl;
|
||||
// and append all peer's client to reflector client list
|
||||
// it is double lock safe to lock Clients list after Peers list
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
for ( auto cit=peer->cbegin(); cit!=peer->cend(); cit++ )
|
||||
{
|
||||
clients->AddClient(*cit);
|
||||
}
|
||||
g_Reflector.ReleaseClients();
|
||||
|
||||
// notify
|
||||
g_Reflector.OnPeersChanged();
|
||||
}
|
||||
|
||||
void CPeers::RemovePeer(std::shared_ptr<CPeer> peer)
|
||||
{
|
||||
// look for the client
|
||||
for ( auto pit=begin(); pit!=end(); /*increment done in body */ )
|
||||
{
|
||||
// compare object pointers
|
||||
if (( *pit == peer ) && ( !(*pit)->IsAMaster() ))
|
||||
{
|
||||
// remove all clients from reflector client list
|
||||
// it is double lock safe to lock Clients list after Peers list
|
||||
CClients *clients = g_Reflector.GetClients();
|
||||
for ( auto cit=peer->begin(); cit!=peer->end(); cit++ )
|
||||
{
|
||||
// this also delete the client object
|
||||
clients->RemoveClient(*cit);
|
||||
}
|
||||
// so clear it then
|
||||
(*pit)->ClearClients();
|
||||
g_Reflector.ReleaseClients();
|
||||
|
||||
// remove it
|
||||
std::cout << "Peer " << (*pit)->GetCallsign() << " at " << (*pit)->GetIp() << " removed" << std::endl;
|
||||
pit = m_Peers.erase(pit);
|
||||
// notify
|
||||
g_Reflector.OnPeersChanged();
|
||||
}
|
||||
else
|
||||
{
|
||||
pit++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// find peers
|
||||
|
||||
std::shared_ptr<CPeer> CPeers::FindPeer(const CIp &Ip, int Protocol)
|
||||
{
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
if ( ((*it)->GetIp() == Ip) && ((*it)->GetProtocol() == Protocol))
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<CPeer> CPeers::FindPeer(const CCallsign &Callsign, const CIp &Ip, int Protocol)
|
||||
{
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
if ( (*it)->GetCallsign().HasSameCallsign(Callsign) && ((*it)->GetIp() == Ip) && ((*it)->GetProtocol() == Protocol) )
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<CPeer> CPeers::FindPeer(const CCallsign &Callsign, int Protocol)
|
||||
{
|
||||
for ( auto it=begin(); it!=end(); it++ )
|
||||
{
|
||||
if ( ((*it)->GetProtocol() == Protocol) && (*it)->GetCallsign().HasSameCallsign(Callsign) )
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// iterate on peers
|
||||
|
||||
std::shared_ptr<CPeer> CPeers::FindNextPeer(int Protocol, std::list<std::shared_ptr<CPeer>>::iterator &it)
|
||||
{
|
||||
while ( it!=end() )
|
||||
{
|
||||
if ( (*it)->GetProtocol() == Protocol )
|
||||
{
|
||||
return *it++;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
//
|
||||
// Peers.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 10/12/2016.
|
||||
// Copyright © 2016 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cpeers_h
|
||||
#define cpeers_h
|
||||
|
||||
#include "Peer.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CPeers
|
||||
{
|
||||
public:
|
||||
// constructors
|
||||
CPeers();
|
||||
|
||||
// destructors
|
||||
virtual ~CPeers();
|
||||
|
||||
// locks
|
||||
void Lock(void) { m_Mutex.lock(); }
|
||||
void Unlock(void) { m_Mutex.unlock(); }
|
||||
|
||||
// manage peers
|
||||
int GetSize(void) const { return (int)m_Peers.size(); }
|
||||
void AddPeer(std::shared_ptr<CPeer>);
|
||||
void RemovePeer(std::shared_ptr<CPeer>);
|
||||
|
||||
// pass-thru
|
||||
std::list<std::shared_ptr<CPeer>>::iterator begin() { return m_Peers.begin(); }
|
||||
std::list<std::shared_ptr<CPeer>>::iterator end() { return m_Peers.end(); }
|
||||
std::list<std::shared_ptr<CPeer>>::const_iterator cbegin() const { return m_Peers.cbegin(); }
|
||||
std::list<std::shared_ptr<CPeer>>::const_iterator cend() const { return m_Peers.cend(); }
|
||||
|
||||
// find peers
|
||||
std::shared_ptr<CPeer> FindPeer(const CIp &, int);
|
||||
std::shared_ptr<CPeer> FindPeer(const CCallsign &, const CIp &, int);
|
||||
std::shared_ptr<CPeer> FindPeer(const CCallsign &, int);
|
||||
|
||||
// iterate on peers
|
||||
std::shared_ptr<CPeer> FindNextPeer(int, std::list<std::shared_ptr<CPeer>>::iterator &);
|
||||
|
||||
protected:
|
||||
// data
|
||||
std::mutex m_Mutex;
|
||||
std::list<std::shared_ptr<CPeer>> m_Peers;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cpeers_h */
|
||||
@ -0,0 +1,100 @@
|
||||
//
|
||||
// Copyright © 2020 Thomas A. Eary, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "ProtoAddress.h"
|
||||
|
||||
CProtoAddress::CProtoAddress()
|
||||
{
|
||||
#ifdef LISTEN_IPV4
|
||||
v4address[PROTOCOL_ANY] = LISTEN_IPV4;
|
||||
#endif
|
||||
#ifdef LISTEN_V4_DPLUS
|
||||
v4address[PROTOCOL_DPLUS] = LISTEN_V4_DPLUS;
|
||||
#endif
|
||||
#ifdef LISTEN_V4_DCS
|
||||
v4address[PROTOCOL_DCS] = LISTEN_V4_DCS;
|
||||
#endif
|
||||
#ifdef LISTEN_V4_DEXTRA
|
||||
v4address[PROTOCOL_DEXTRA] = LISTEN_V4_DEXTRA;
|
||||
#endif
|
||||
#ifdef LISTEN_V4_DMRMMDVM
|
||||
v4address[PROTOCOL_DMRMMDVM] = LISTEN_V4_DMRMMDVM;
|
||||
#endif
|
||||
#ifdef LISTEN_V4_DMRPLUS
|
||||
v4address[PROTOCOL_DMRPLUS] = LISTEN_V4_DMRPLUS;
|
||||
#endif
|
||||
#ifdef LISTEN_V4_YSF
|
||||
v4address[PROTOCOL_YSF] = LISTEN_V4_YSF;
|
||||
#endif
|
||||
#ifdef LISTEN_V4_XLX
|
||||
v4address[PROTOCOL_XLX] = LISTEN_V4_XLX;
|
||||
#endif
|
||||
#ifdef LISTEN_V4_G3
|
||||
v4address[PROTOCOL_G3] = LISTEN_V4_G3;
|
||||
#endif
|
||||
|
||||
#ifdef LISTEN_IPV6
|
||||
v6address[PROTOCOL_ANY] = LISTEN_IPV6;
|
||||
#endif
|
||||
#ifdef LISTEN_V6_DPLUS
|
||||
v6address[PROTOCOL_DPLUS] = LISTEN_V6_DPLUS;
|
||||
#endif
|
||||
#ifdef LISTEN_V6_DCS
|
||||
v6address[PROTOCOL_DCS] = LISTEN_V6_DCS;
|
||||
#endif
|
||||
#ifdef LISTEN_V6_DEXTRA
|
||||
v6address[PROTOCOL_DEXTRA] = LISTEN_V6_DEXTRA;
|
||||
#endif
|
||||
#ifdef LISTEN_V6_DMRMMDVM
|
||||
v6address[PROTOCOL_DMRMMDVM] = LISTEN_V6_DMRMMDVM;
|
||||
#endif
|
||||
#ifdef LISTEN_V6_DMRPLUS
|
||||
v6address[PROTOCOL_DMRPLUS] = LISTEN_V6_DMRPLUS;
|
||||
#endif
|
||||
#ifdef LISTEN_V6_YSF
|
||||
v6address[PROTOCOL_YSF] = LISTEN_V6_YSF;
|
||||
#endif
|
||||
#ifdef LISTEN_V6_XLX
|
||||
v6address[PROTOCOL_XLX] = LISTEN_V6_XLX;
|
||||
#endif
|
||||
#ifdef LISTEN_V6_G3
|
||||
v6address[PROTOCOL_G3] = LISTEN_V6_G3;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef LISTEN_IPV4
|
||||
std::string CProtoAddress::GetV4Address(int protocol)
|
||||
{
|
||||
if (v4address.end() == v4address.find(protocol))
|
||||
return v4address[PROTOCOL_ANY];
|
||||
else
|
||||
return v4address[protocol];
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LISTEN_IPV6
|
||||
std::string CProtoAddress::GetV6Address(int protocol)
|
||||
{
|
||||
if (v6address.end() == v6address.find(protocol))
|
||||
return v6address[PROTOCOL_ANY];
|
||||
else
|
||||
return v6address[protocol];
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// Copyright © 2020 Thomas A. Eary, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
#include "Main.h"
|
||||
|
||||
class CProtoAddress
|
||||
{
|
||||
public:
|
||||
CProtoAddress();
|
||||
#ifdef LISTEN_IPV4
|
||||
std::string GetV4Address(int protocol);
|
||||
#endif
|
||||
#ifdef LISTEN_IPV6
|
||||
std::string GetV6Address(int protocol);
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef LISTEN_IPV4
|
||||
std::unordered_map<int, std::string> v4address;
|
||||
#endif
|
||||
#ifdef LISTEN_IPV6
|
||||
std::unordered_map<int, std::string> v6address;
|
||||
#endif
|
||||
};
|
||||
@ -0,0 +1,389 @@
|
||||
//
|
||||
// cprotocol.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 01/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include "DCSProtocol.h"
|
||||
#include "Clients.h"
|
||||
#include "Reflector.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
|
||||
CProtocol::CProtocol() : keep_running(true) {}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// destructor
|
||||
|
||||
CProtocol::~CProtocol()
|
||||
{
|
||||
// kill threads
|
||||
Close();
|
||||
|
||||
// empty queue
|
||||
m_Queue.Lock();
|
||||
while ( !m_Queue.empty() )
|
||||
{
|
||||
m_Queue.pop();
|
||||
}
|
||||
m_Queue.Unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// initialization
|
||||
|
||||
bool CProtocol::Initialize(const char *type, int ptype, const uint16 port, const bool has_ipv4, const bool has_ipv6)
|
||||
{
|
||||
// init reflector apparent callsign
|
||||
m_ReflectorCallsign = g_Reflector.GetCallsign();
|
||||
|
||||
// reset stop flag
|
||||
keep_running = true;
|
||||
|
||||
// update the reflector callsign
|
||||
if (type)
|
||||
m_ReflectorCallsign.PatchCallsign(0, (const uint8 *)type, 3);
|
||||
|
||||
// create our sockets
|
||||
#ifdef LISTEN_IPV4
|
||||
if (has_ipv4)
|
||||
{
|
||||
const auto s = g_Reflector.m_Address.GetV4Address(ptype);
|
||||
CIp ip4(AF_INET, port, s.c_str());
|
||||
if ( ip4.IsSet() )
|
||||
{
|
||||
if (! m_Socket4.Open(ip4))
|
||||
return false;
|
||||
}
|
||||
std::cout << "Listening on " << ip4 << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LISTEN_IPV6
|
||||
if (has_ipv6)
|
||||
{
|
||||
CIp ip6(AF_INET6, port, g_Reflector.m_Address.GetV6Address(ptype).c_str());
|
||||
if ( ip6.IsSet() )
|
||||
{
|
||||
if (! m_Socket6.Open(ip6))
|
||||
{
|
||||
m_Socket4.Close();
|
||||
return false;
|
||||
}
|
||||
std::cout << "Listening on " << ip6 << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
try {
|
||||
m_Future = std::async(std::launch::async, &CProtocol::Thread, this);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Could not start protocol on port " << port << ": " << e.what() << std::endl;
|
||||
m_Socket4.Close();
|
||||
m_Socket6.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CProtocol::Thread()
|
||||
{
|
||||
while (keep_running)
|
||||
{
|
||||
Task();
|
||||
}
|
||||
}
|
||||
|
||||
void CProtocol::Close(void)
|
||||
{
|
||||
keep_running = false;
|
||||
if ( m_Future.valid() )
|
||||
{
|
||||
m_Future.get();
|
||||
}
|
||||
m_Socket4.Close();
|
||||
m_Socket6.Close();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// packet encoding helpers
|
||||
|
||||
bool CProtocol::EncodeDvPacket(const CPacket &packet, CBuffer *buffer) const
|
||||
{
|
||||
if ( packet.IsDvFrame() )
|
||||
{
|
||||
if ( packet.IsLastPacket() )
|
||||
return EncodeDvLastFramePacket((CDvLastFramePacket &)packet, buffer);
|
||||
else
|
||||
return EncodeDvFramePacket((CDvFramePacket &)packet, buffer);
|
||||
}
|
||||
if ( packet.IsDvHeader() )
|
||||
return EncodeDvHeaderPacket((CDvHeaderPacket &)packet, buffer);
|
||||
|
||||
std::cerr << "Can't encode an unknown packet type!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// streams helpers
|
||||
|
||||
void CProtocol::OnDvFramePacketIn(std::unique_ptr<CDvFramePacket> &Frame, const CIp *Ip)
|
||||
{
|
||||
// find the stream
|
||||
CPacketStream *stream = GetStream(Frame->GetStreamId(), Ip);
|
||||
if ( stream )
|
||||
{
|
||||
//std::cout << "DV frame" << "from " << *Ip << std::endl;
|
||||
// and push
|
||||
stream->Lock();
|
||||
stream->Push(std::move(Frame));
|
||||
stream->Unlock();
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// std::cout << "Orphaned Frame with ID " << Frame->GetStreamId() << " on " << *Ip << std::endl;
|
||||
// }
|
||||
}
|
||||
|
||||
void CProtocol::OnDvLastFramePacketIn(std::unique_ptr<CDvLastFramePacket> &Frame, const CIp *Ip)
|
||||
{
|
||||
// find the stream
|
||||
CPacketStream *stream = GetStream(Frame->GetStreamId(), Ip);
|
||||
if ( stream )
|
||||
{
|
||||
// push
|
||||
stream->Lock();
|
||||
stream->Push(std::move(Frame));
|
||||
stream->Unlock();
|
||||
|
||||
// Don't close yet, this stops the last packet relfection bug that was fixed in upstream by the same change.
|
||||
// Don't close the stream yet but rely on CheckStreamsTimeout
|
||||
// mechanism, so the stream will be closed after the queues have
|
||||
// been sinked out. This avoid last packets to be send back
|
||||
// to transmitting client (master)
|
||||
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// std::cout << "Orphaned Last Frame with ID " << Frame->GetStreamId() << " on " << *Ip << std::endl;
|
||||
// }
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// stream handle helpers
|
||||
|
||||
CPacketStream *CProtocol::GetStream(uint16 uiStreamId, const CIp *Ip)
|
||||
{
|
||||
for ( auto it=m_Streams.begin(); it!=m_Streams.end(); it++ )
|
||||
{
|
||||
if ( (*it)->GetStreamId() == uiStreamId )
|
||||
{
|
||||
// if Ip not nullptr, also check if IP match
|
||||
if ( (Ip != nullptr) && ((*it)->GetOwnerIp() != nullptr) )
|
||||
{
|
||||
if ( *Ip == *((*it)->GetOwnerIp()) )
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// done
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CProtocol::CheckStreamsTimeout(void)
|
||||
{
|
||||
for ( auto it=m_Streams.begin(); it!=m_Streams.end(); )
|
||||
{
|
||||
// time out ?
|
||||
(*it)->Lock();
|
||||
if ( (*it)->IsExpired() )
|
||||
{
|
||||
// yes, close it
|
||||
(*it)->Unlock();
|
||||
g_Reflector.CloseStream(*it);
|
||||
// and remove it
|
||||
it = m_Streams.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
(*it++)->Unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// syntax helper
|
||||
|
||||
bool CProtocol::IsNumber(char c) const
|
||||
{
|
||||
return ((c >= '0') && (c <= '9'));
|
||||
}
|
||||
|
||||
bool CProtocol::IsLetter(char c) const
|
||||
{
|
||||
return ((c >= 'A') && (c <= 'Z'));
|
||||
}
|
||||
|
||||
bool CProtocol::IsSpace(char c) const
|
||||
{
|
||||
return (c == ' ');
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// DestId to Module helper
|
||||
|
||||
char CProtocol::DmrDstIdToModule(uint32 tg) const
|
||||
{
|
||||
return ((char)((tg % 26)-1) + 'A');
|
||||
}
|
||||
|
||||
uint32 CProtocol::ModuleToDmrDestId(char m) const
|
||||
{
|
||||
return (uint32)(m - 'A')+1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Receivers
|
||||
|
||||
bool CProtocol::Receive6(CBuffer &buf, CIp &ip, int time_ms)
|
||||
{
|
||||
return m_Socket6.Receive(buf, ip, time_ms);
|
||||
}
|
||||
|
||||
bool CProtocol::Receive4(CBuffer &buf, CIp &ip, int time_ms)
|
||||
{
|
||||
return m_Socket4.Receive(buf, ip, time_ms);
|
||||
}
|
||||
|
||||
bool CProtocol::ReceiveDS(CBuffer &buf, CIp &ip, int time_ms)
|
||||
{
|
||||
auto fd4 = m_Socket4.GetSocket();
|
||||
auto fd6 = m_Socket6.GetSocket();
|
||||
|
||||
if (fd4 < 0)
|
||||
{
|
||||
if (fd6 < 0)
|
||||
return false;
|
||||
return m_Socket6.Receive(buf, ip, time_ms);
|
||||
}
|
||||
else if (fd6 < 0)
|
||||
return m_Socket4.Receive(buf, ip, time_ms);
|
||||
|
||||
fd_set fset;
|
||||
FD_ZERO(&fset);
|
||||
FD_SET(fd4, &fset);
|
||||
FD_SET(fd6, &fset);
|
||||
int max = (fd4 > fd6) ? fd4 : fd6;
|
||||
struct timeval tv;
|
||||
tv.tv_sec = time_ms / 1000;
|
||||
tv.tv_usec = (time_ms % 1000) * 1000;
|
||||
|
||||
auto rval = select(max+1, &fset, 0, 0, &tv);
|
||||
if (rval <= 0)
|
||||
{
|
||||
if (rval < 0)
|
||||
std::cerr << "ReceiveDS select error: " << strerror(errno) << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FD_ISSET(fd4, &fset))
|
||||
return m_Socket4.ReceiveFrom(buf, ip);
|
||||
else
|
||||
return m_Socket6.ReceiveFrom(buf, ip);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// dual stack senders
|
||||
|
||||
void CProtocol::Send(const CBuffer &buf, const CIp &Ip) const
|
||||
{
|
||||
switch (Ip.GetFamily())
|
||||
{
|
||||
case AF_INET:
|
||||
m_Socket4.Send(buf, Ip);
|
||||
break;
|
||||
case AF_INET6:
|
||||
m_Socket6.Send(buf, Ip);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Wrong family: " << Ip.GetFamily() << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CProtocol::Send(const char *buf, const CIp &Ip) const
|
||||
{
|
||||
switch (Ip.GetFamily())
|
||||
{
|
||||
case AF_INET:
|
||||
m_Socket4.Send(buf, Ip);
|
||||
break;
|
||||
case AF_INET6:
|
||||
m_Socket6.Send(buf, Ip);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "ERROR: wrong family: " << Ip.GetFamily() << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CProtocol::Send(const CBuffer &buf, const CIp &Ip, uint16_t port) const
|
||||
{
|
||||
switch (Ip.GetFamily())
|
||||
{
|
||||
case AF_INET:
|
||||
m_Socket4.Send(buf, Ip, port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
m_Socket6.Send(buf, Ip, port);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Wrong family: " << Ip.GetFamily() << " on port " << port << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void CProtocol::Send(const char *buf, const CIp &Ip, uint16_t port) const
|
||||
{
|
||||
switch (Ip.GetFamily())
|
||||
{
|
||||
case AF_INET:
|
||||
m_Socket4.Send(buf, Ip, port);
|
||||
break;
|
||||
case AF_INET6:
|
||||
m_Socket6.Send(buf, Ip, port);
|
||||
break;
|
||||
default:
|
||||
std::cerr << "Wrong family: " << Ip.GetFamily() << " on port " << port << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,156 @@
|
||||
//
|
||||
// DCSProtocol.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 01/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cprotocol_h
|
||||
#define cprotocol_h
|
||||
|
||||
#include "UDPSocket.h"
|
||||
#include "PacketStream.h"
|
||||
#include "DVHeaderPacket.h"
|
||||
#include "DVFramePacket.h"
|
||||
#include "DVLastFramePacket.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// DMR defines
|
||||
// slot n'
|
||||
#define DMR_SLOT1 1
|
||||
#define DMR_SLOT2 2
|
||||
// call type
|
||||
#define DMR_GROUP_CALL 0
|
||||
#define DMR_PRIVATE_CALL 1
|
||||
// frame type
|
||||
#define DMR_FRAMETYPE_VOICE 0
|
||||
#define DMR_FRAMETYPE_VOICESYNC 1
|
||||
#define DMR_FRAMETYPE_DATA 2
|
||||
#define DMR_FRAMETYPE_DATASYNC 3
|
||||
// data type
|
||||
#define DMR_DT_VOICE_PI_HEADER 0
|
||||
#define DMR_DT_VOICE_LC_HEADER 1
|
||||
#define DMR_DT_TERMINATOR_WITH_LC 2
|
||||
#define DMR_DT_CSBK 3
|
||||
#define DMR_DT_DATA_HEADER 6
|
||||
#define DMR_DT_RATE_12_DATA 7
|
||||
#define DMR_DT_RATE_34_DATA 8
|
||||
#define DMR_DT_IDLE 9
|
||||
#define DMR_DT_RATE_1_DATA 10
|
||||
// CRC masks
|
||||
#define DMR_VOICE_LC_HEADER_CRC_MASK 0x96
|
||||
#define DMR_TERMINATOR_WITH_LC_CRC_MASK 0x99
|
||||
#define DMR_PI_HEADER_CRC_MASK 0x69
|
||||
#define DMR_DATA_HEADER_CRC_MASK 0xCC
|
||||
#define DMR_CSBK_CRC_MASK 0xA5
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CProtocol
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CProtocol();
|
||||
|
||||
// destructor
|
||||
virtual ~CProtocol();
|
||||
|
||||
// initialization
|
||||
virtual bool Initialize(const char *type, const int ptype, const uint16 port, const bool has_ipv4, const bool has_ipv6);
|
||||
virtual void Close(void);
|
||||
|
||||
// queue
|
||||
CPacketQueue *GetQueue(void) { m_Queue.Lock(); return &m_Queue; }
|
||||
void ReleaseQueue(void) { m_Queue.Unlock(); }
|
||||
|
||||
// get
|
||||
const CCallsign &GetReflectorCallsign(void)const { return m_ReflectorCallsign; }
|
||||
|
||||
// task
|
||||
void Thread(void);
|
||||
virtual void Task(void) = 0;
|
||||
|
||||
protected:
|
||||
// packet encoding helpers
|
||||
virtual bool EncodeDvPacket(const CPacket &, CBuffer *) const;
|
||||
virtual bool EncodeDvHeaderPacket(const CDvHeaderPacket &, CBuffer *) const { return false; }
|
||||
virtual bool EncodeDvFramePacket(const CDvFramePacket &, CBuffer *) const { return false; }
|
||||
virtual bool EncodeDvLastFramePacket(const CDvLastFramePacket &, CBuffer *) const { return false; }
|
||||
|
||||
// stream helpers
|
||||
virtual void OnDvHeaderPacketIn(std::unique_ptr<CDvHeaderPacket> &, const CIp &) {}
|
||||
virtual void OnDvFramePacketIn(std::unique_ptr<CDvFramePacket> &, const CIp * = nullptr);
|
||||
virtual void OnDvLastFramePacketIn(std::unique_ptr<CDvLastFramePacket> &, const CIp * = nullptr);
|
||||
|
||||
// stream handle helpers
|
||||
CPacketStream *GetStream(uint16, const CIp * = nullptr);
|
||||
void CheckStreamsTimeout(void);
|
||||
|
||||
// queue helper
|
||||
virtual void HandleQueue(void) = 0;
|
||||
|
||||
// keepalive helpers
|
||||
virtual void HandleKeepalives(void) = 0;
|
||||
|
||||
// syntax helper
|
||||
bool IsNumber(char) const;
|
||||
bool IsLetter(char) const;
|
||||
bool IsSpace(char) const;
|
||||
|
||||
// dmr DstId to Module helper
|
||||
virtual char DmrDstIdToModule(uint32) const;
|
||||
virtual uint32 ModuleToDmrDestId(char) const;
|
||||
|
||||
bool Receive6(CBuffer &buf, CIp &Ip, int time_ms);
|
||||
bool Receive4(CBuffer &buf, CIp &Ip, int time_ms);
|
||||
bool ReceiveDS(CBuffer &buf, CIp &Ip, int time_ms);
|
||||
|
||||
void Send(const CBuffer &buf, const CIp &Ip) const;
|
||||
void Send(const char *buf, const CIp &Ip) const;
|
||||
void Send(const CBuffer &buf, const CIp &Ip, uint16 port) const;
|
||||
void Send(const char *buf, const CIp &Ip, uint16 port) const;
|
||||
|
||||
// socket
|
||||
CUdpSocket m_Socket4;
|
||||
CUdpSocket m_Socket6;
|
||||
|
||||
// streams
|
||||
std::list<CPacketStream *> m_Streams;
|
||||
|
||||
// queue
|
||||
CPacketQueue m_Queue;
|
||||
|
||||
// thread
|
||||
std::atomic<bool> keep_running;
|
||||
std::future<void> m_Future;
|
||||
|
||||
// identity
|
||||
CCallsign m_ReflectorCallsign;
|
||||
|
||||
// debug
|
||||
CTimePoint m_DebugTimer;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* cprotocol_h */
|
||||
@ -0,0 +1,63 @@
|
||||
//
|
||||
// Protocols.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 01/11/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef cprotocols_h
|
||||
#define cprotocols_h
|
||||
|
||||
#include "DCSProtocol.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CProtocols
|
||||
{
|
||||
public:
|
||||
// destructors
|
||||
~CProtocols();
|
||||
|
||||
// initialization
|
||||
bool Init(void);
|
||||
void Close(void);
|
||||
void Lock(void) { m_Mutex.lock(); }
|
||||
void Unlock(void) { m_Mutex.unlock(); }
|
||||
|
||||
// pass-thru
|
||||
std::list<std::unique_ptr<CProtocol>>::iterator begin() { return m_Protocols.begin(); }
|
||||
std::list<std::unique_ptr<CProtocol>>::iterator end() { return m_Protocols.end(); }
|
||||
|
||||
protected:
|
||||
// data
|
||||
std::mutex m_Mutex;
|
||||
std::list<std::unique_ptr<CProtocol>> m_Protocols;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif /* cprotocols_h */
|
||||
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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 "QR1676.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
|
||||
const unsigned int ENCODING_TABLE_1676[] =
|
||||
{
|
||||
0x0000U, 0x0273U, 0x04E5U, 0x0696U, 0x09C9U, 0x0BBAU, 0x0D2CU, 0x0F5FU, 0x11E2U, 0x1391U, 0x1507U, 0x1774U,
|
||||
0x182BU, 0x1A58U, 0x1CCEU, 0x1EBDU, 0x21B7U, 0x23C4U, 0x2552U, 0x2721U, 0x287EU, 0x2A0DU, 0x2C9BU, 0x2EE8U,
|
||||
0x3055U, 0x3226U, 0x34B0U, 0x36C3U, 0x399CU, 0x3BEFU, 0x3D79U, 0x3F0AU, 0x411EU, 0x436DU, 0x45FBU, 0x4788U,
|
||||
0x48D7U, 0x4AA4U, 0x4C32U, 0x4E41U, 0x50FCU, 0x528FU, 0x5419U, 0x566AU, 0x5935U, 0x5B46U, 0x5DD0U, 0x5FA3U,
|
||||
0x60A9U, 0x62DAU, 0x644CU, 0x663FU, 0x6960U, 0x6B13U, 0x6D85U, 0x6FF6U, 0x714BU, 0x7338U, 0x75AEU, 0x77DDU,
|
||||
0x7882U, 0x7AF1U, 0x7C67U, 0x7E14U, 0x804FU, 0x823CU, 0x84AAU, 0x86D9U, 0x8986U, 0x8BF5U, 0x8D63U, 0x8F10U,
|
||||
0x91ADU, 0x93DEU, 0x9548U, 0x973BU, 0x9864U, 0x9A17U, 0x9C81U, 0x9EF2U, 0xA1F8U, 0xA38BU, 0xA51DU, 0xA76EU,
|
||||
0xA831U, 0xAA42U, 0xACD4U, 0xAEA7U, 0xB01AU, 0xB269U, 0xB4FFU, 0xB68CU, 0xB9D3U, 0xBBA0U, 0xBD36U, 0xBF45U,
|
||||
0xC151U, 0xC322U, 0xC5B4U, 0xC7C7U, 0xC898U, 0xCAEBU, 0xCC7DU, 0xCE0EU, 0xD0B3U, 0xD2C0U, 0xD456U, 0xD625U,
|
||||
0xD97AU, 0xDB09U, 0xDD9FU, 0xDFECU, 0xE0E6U, 0xE295U, 0xE403U, 0xE670U, 0xE92FU, 0xEB5CU, 0xEDCAU, 0xEFB9U,
|
||||
0xF104U, 0xF377U, 0xF5E1U, 0xF792U, 0xF8CDU, 0xFABEU, 0xFC28U, 0xFE5BU
|
||||
};
|
||||
|
||||
const unsigned int DECODING_TABLE_1576[] =
|
||||
{
|
||||
0x0000U, 0x0001U, 0x0002U, 0x0003U, 0x0004U, 0x0005U, 0x0006U, 0x4020U, 0x0008U, 0x0009U, 0x000AU, 0x000BU,
|
||||
0x000CU, 0x000DU, 0x2081U, 0x2080U, 0x0010U, 0x0011U, 0x0012U, 0x0013U, 0x0014U, 0x0C00U, 0x0016U, 0x0C02U,
|
||||
0x0018U, 0x0120U, 0x001AU, 0x0122U, 0x4102U, 0x0124U, 0x4100U, 0x4101U, 0x0020U, 0x0021U, 0x0022U, 0x4004U,
|
||||
0x0024U, 0x4002U, 0x4001U, 0x4000U, 0x0028U, 0x0110U, 0x1800U, 0x1801U, 0x002CU, 0x400AU, 0x4009U, 0x4008U,
|
||||
0x0030U, 0x0108U, 0x0240U, 0x0241U, 0x0034U, 0x4012U, 0x4011U, 0x4010U, 0x0101U, 0x0100U, 0x0103U, 0x0102U,
|
||||
0x0105U, 0x0104U, 0x1401U, 0x1400U, 0x0040U, 0x0041U, 0x0042U, 0x0043U, 0x0044U, 0x0045U, 0x0046U, 0x4060U,
|
||||
0x0048U, 0x0049U, 0x0301U, 0x0300U, 0x004CU, 0x1600U, 0x0305U, 0x0304U, 0x0050U, 0x0051U, 0x0220U, 0x0221U,
|
||||
0x3000U, 0x4200U, 0x3002U, 0x4202U, 0x0058U, 0x1082U, 0x1081U, 0x1080U, 0x3008U, 0x4208U, 0x2820U, 0x1084U,
|
||||
0x0060U, 0x0061U, 0x0210U, 0x0211U, 0x0480U, 0x0481U, 0x4041U, 0x4040U, 0x0068U, 0x2402U, 0x2401U, 0x2400U,
|
||||
0x0488U, 0x3100U, 0x2810U, 0x2404U, 0x0202U, 0x0880U, 0x0200U, 0x0201U, 0x0206U, 0x0884U, 0x0204U, 0x0205U,
|
||||
0x0141U, 0x0140U, 0x0208U, 0x0209U, 0x2802U, 0x0144U, 0x2800U, 0x2801U, 0x0080U, 0x0081U, 0x0082U, 0x0A00U,
|
||||
0x0084U, 0x0085U, 0x2009U, 0x2008U, 0x0088U, 0x0089U, 0x2005U, 0x2004U, 0x2003U, 0x2002U, 0x2001U, 0x2000U,
|
||||
0x0090U, 0x0091U, 0x0092U, 0x1048U, 0x0602U, 0x0C80U, 0x0600U, 0x0601U, 0x0098U, 0x1042U, 0x1041U, 0x1040U,
|
||||
0x2013U, 0x2012U, 0x2011U, 0x2010U, 0x00A0U, 0x00A1U, 0x00A2U, 0x4084U, 0x0440U, 0x0441U, 0x4081U, 0x4080U,
|
||||
0x6000U, 0x1200U, 0x6002U, 0x1202U, 0x6004U, 0x2022U, 0x2021U, 0x2020U, 0x0841U, 0x0840U, 0x2104U, 0x0842U,
|
||||
0x2102U, 0x0844U, 0x2100U, 0x2101U, 0x0181U, 0x0180U, 0x0B00U, 0x0182U, 0x5040U, 0x0184U, 0x2108U, 0x2030U,
|
||||
0x00C0U, 0x00C1U, 0x4401U, 0x4400U, 0x0420U, 0x0421U, 0x0422U, 0x4404U, 0x0900U, 0x0901U, 0x1011U, 0x1010U,
|
||||
0x0904U, 0x2042U, 0x2041U, 0x2040U, 0x0821U, 0x0820U, 0x1009U, 0x1008U, 0x4802U, 0x0824U, 0x4800U, 0x4801U,
|
||||
0x1003U, 0x1002U, 0x1001U, 0x1000U, 0x0501U, 0x0500U, 0x1005U, 0x1004U, 0x0404U, 0x0810U, 0x1100U, 0x1101U,
|
||||
0x0400U, 0x0401U, 0x0402U, 0x0403U, 0x040CU, 0x0818U, 0x1108U, 0x1030U, 0x0408U, 0x0409U, 0x040AU, 0x2060U,
|
||||
0x0801U, 0x0800U, 0x0280U, 0x0802U, 0x0410U, 0x0804U, 0x0412U, 0x0806U, 0x0809U, 0x0808U, 0x1021U, 0x1020U,
|
||||
0x5000U, 0x2200U, 0x5002U, 0x2202U
|
||||
};
|
||||
|
||||
#define X14 0x00004000 /* vector representation of X^{14} */
|
||||
#define X8 0x00000100 /* vector representation of X^{8} */
|
||||
#define MASK7 0xffffff00 /* auxiliary vector for testing */
|
||||
#define GENPOL 0x00000139 /* generator polinomial, g(x) */
|
||||
|
||||
unsigned int CQR1676::getSyndrome1576(unsigned int pattern)
|
||||
/*
|
||||
* Compute the syndrome corresponding to the given pattern, i.e., the
|
||||
* remainder after dividing the pattern (when considering it as the vector
|
||||
* representation of a polynomial) by the generator polynomial, GENPOL.
|
||||
* In the program this pattern has several meanings: (1) pattern = infomation
|
||||
* bits, when constructing the encoding table; (2) pattern = error pattern,
|
||||
* when constructing the decoding table; and (3) pattern = received vector, to
|
||||
* obtain its syndrome in decoding.
|
||||
*/
|
||||
{
|
||||
unsigned int aux = X14;
|
||||
|
||||
if (pattern >= X8)
|
||||
{
|
||||
while (pattern & MASK7)
|
||||
{
|
||||
while (!(aux & pattern))
|
||||
aux = aux >> 1;
|
||||
|
||||
pattern ^= (aux / X8) * GENPOL;
|
||||
}
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
// Compute the EMB against a precomputed list of correct words
|
||||
void CQR1676::encode(unsigned char* data)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
|
||||
unsigned int value = (data[0U] >> 1) & 0x7FU;
|
||||
unsigned int cksum = ENCODING_TABLE_1676[value];
|
||||
|
||||
data[0U] = cksum >> 8;
|
||||
data[1U] = cksum & 0xFFU;
|
||||
}
|
||||
|
||||
unsigned char CQR1676::decode(const unsigned char* data)
|
||||
{
|
||||
assert(data != nullptr);
|
||||
|
||||
unsigned int code = (data[0U] << 7) + (data[1U] >> 1);
|
||||
unsigned int syndrome = getSyndrome1576(code);
|
||||
unsigned int error_pattern = DECODING_TABLE_1576[syndrome];
|
||||
|
||||
code ^= error_pattern;
|
||||
|
||||
return code >> 7;
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
#ifndef QR1676_H
|
||||
#define QR1676_H
|
||||
|
||||
class CQR1676
|
||||
{
|
||||
public:
|
||||
static void encode(unsigned char* data);
|
||||
|
||||
static unsigned char decode(const unsigned char* data);
|
||||
|
||||
private:
|
||||
static unsigned int getSyndrome1576(unsigned int pattern);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 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 "RS129.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
const unsigned int NPAR = 3U;
|
||||
|
||||
/* Maximum degree of various polynomials. */
|
||||
//const unsigned int MAXDEG = NPAR * 2U;
|
||||
|
||||
/* Generator Polynomial */
|
||||
const unsigned char POLY[] = {64U, 56U, 14U, 1U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U};
|
||||
|
||||
const unsigned char EXP_TABLE[] =
|
||||
{
|
||||
0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U, 0x1DU, 0x3AU, 0x74U, 0xE8U, 0xCDU, 0x87U, 0x13U, 0x26U,
|
||||
0x4CU, 0x98U, 0x2DU, 0x5AU, 0xB4U, 0x75U, 0xEAU, 0xC9U, 0x8FU, 0x03U, 0x06U, 0x0CU, 0x18U, 0x30U, 0x60U, 0xC0U,
|
||||
0x9DU, 0x27U, 0x4EU, 0x9CU, 0x25U, 0x4AU, 0x94U, 0x35U, 0x6AU, 0xD4U, 0xB5U, 0x77U, 0xEEU, 0xC1U, 0x9FU, 0x23U,
|
||||
0x46U, 0x8CU, 0x05U, 0x0AU, 0x14U, 0x28U, 0x50U, 0xA0U, 0x5DU, 0xBAU, 0x69U, 0xD2U, 0xB9U, 0x6FU, 0xDEU, 0xA1U,
|
||||
0x5FU, 0xBEU, 0x61U, 0xC2U, 0x99U, 0x2FU, 0x5EU, 0xBCU, 0x65U, 0xCAU, 0x89U, 0x0FU, 0x1EU, 0x3CU, 0x78U, 0xF0U,
|
||||
0xFDU, 0xE7U, 0xD3U, 0xBBU, 0x6BU, 0xD6U, 0xB1U, 0x7FU, 0xFEU, 0xE1U, 0xDFU, 0xA3U, 0x5BU, 0xB6U, 0x71U, 0xE2U,
|
||||
0xD9U, 0xAFU, 0x43U, 0x86U, 0x11U, 0x22U, 0x44U, 0x88U, 0x0DU, 0x1AU, 0x34U, 0x68U, 0xD0U, 0xBDU, 0x67U, 0xCEU,
|
||||
0x81U, 0x1FU, 0x3EU, 0x7CU, 0xF8U, 0xEDU, 0xC7U, 0x93U, 0x3BU, 0x76U, 0xECU, 0xC5U, 0x97U, 0x33U, 0x66U, 0xCCU,
|
||||
0x85U, 0x17U, 0x2EU, 0x5CU, 0xB8U, 0x6DU, 0xDAU, 0xA9U, 0x4FU, 0x9EU, 0x21U, 0x42U, 0x84U, 0x15U, 0x2AU, 0x54U,
|
||||
0xA8U, 0x4DU, 0x9AU, 0x29U, 0x52U, 0xA4U, 0x55U, 0xAAU, 0x49U, 0x92U, 0x39U, 0x72U, 0xE4U, 0xD5U, 0xB7U, 0x73U,
|
||||
0xE6U, 0xD1U, 0xBFU, 0x63U, 0xC6U, 0x91U, 0x3FU, 0x7EU, 0xFCU, 0xE5U, 0xD7U, 0xB3U, 0x7BU, 0xF6U, 0xF1U, 0xFFU,
|
||||
0xE3U, 0xDBU, 0xABU, 0x4BU, 0x96U, 0x31U, 0x62U, 0xC4U, 0x95U, 0x37U, 0x6EU, 0xDCU, 0xA5U, 0x57U, 0xAEU, 0x41U,
|
||||
0x82U, 0x19U, 0x32U, 0x64U, 0xC8U, 0x8DU, 0x07U, 0x0EU, 0x1CU, 0x38U, 0x70U, 0xE0U, 0xDDU, 0xA7U, 0x53U, 0xA6U,
|
||||
0x51U, 0xA2U, 0x59U, 0xB2U, 0x79U, 0xF2U, 0xF9U, 0xEFU, 0xC3U, 0x9BU, 0x2BU, 0x56U, 0xACU, 0x45U, 0x8AU, 0x09U,
|
||||
0x12U, 0x24U, 0x48U, 0x90U, 0x3DU, 0x7AU, 0xF4U, 0xF5U, 0xF7U, 0xF3U, 0xFBU, 0xEBU, 0xCBU, 0x8BU, 0x0BU, 0x16U,
|
||||
0x2CU, 0x58U, 0xB0U, 0x7DU, 0xFAU, 0xE9U, 0xCFU, 0x83U, 0x1BU, 0x36U, 0x6CU, 0xD8U, 0xADU, 0x47U, 0x8EU, 0x01U,
|
||||
0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U, 0x1DU, 0x3AU, 0x74U, 0xE8U, 0xCDU, 0x87U, 0x13U, 0x26U, 0x4CU,
|
||||
0x98U, 0x2DU, 0x5AU, 0xB4U, 0x75U, 0xEAU, 0xC9U, 0x8FU, 0x03U, 0x06U, 0x0CU, 0x18U, 0x30U, 0x60U, 0xC0U, 0x9DU,
|
||||
0x27U, 0x4EU, 0x9CU, 0x25U, 0x4AU, 0x94U, 0x35U, 0x6AU, 0xD4U, 0xB5U, 0x77U, 0xEEU, 0xC1U, 0x9FU, 0x23U, 0x46U,
|
||||
0x8CU, 0x05U, 0x0AU, 0x14U, 0x28U, 0x50U, 0xA0U, 0x5DU, 0xBAU, 0x69U, 0xD2U, 0xB9U, 0x6FU, 0xDEU, 0xA1U, 0x5FU,
|
||||
0xBEU, 0x61U, 0xC2U, 0x99U, 0x2FU, 0x5EU, 0xBCU, 0x65U, 0xCAU, 0x89U, 0x0FU, 0x1EU, 0x3CU, 0x78U, 0xF0U, 0xFDU,
|
||||
0xE7U, 0xD3U, 0xBBU, 0x6BU, 0xD6U, 0xB1U, 0x7FU, 0xFEU, 0xE1U, 0xDFU, 0xA3U, 0x5BU, 0xB6U, 0x71U, 0xE2U, 0xD9U,
|
||||
0xAFU, 0x43U, 0x86U, 0x11U, 0x22U, 0x44U, 0x88U, 0x0DU, 0x1AU, 0x34U, 0x68U, 0xD0U, 0xBDU, 0x67U, 0xCEU, 0x81U,
|
||||
0x1FU, 0x3EU, 0x7CU, 0xF8U, 0xEDU, 0xC7U, 0x93U, 0x3BU, 0x76U, 0xECU, 0xC5U, 0x97U, 0x33U, 0x66U, 0xCCU, 0x85U,
|
||||
0x17U, 0x2EU, 0x5CU, 0xB8U, 0x6DU, 0xDAU, 0xA9U, 0x4FU, 0x9EU, 0x21U, 0x42U, 0x84U, 0x15U, 0x2AU, 0x54U, 0xA8U,
|
||||
0x4DU, 0x9AU, 0x29U, 0x52U, 0xA4U, 0x55U, 0xAAU, 0x49U, 0x92U, 0x39U, 0x72U, 0xE4U, 0xD5U, 0xB7U, 0x73U, 0xE6U,
|
||||
0xD1U, 0xBFU, 0x63U, 0xC6U, 0x91U, 0x3FU, 0x7EU, 0xFCU, 0xE5U, 0xD7U, 0xB3U, 0x7BU, 0xF6U, 0xF1U, 0xFFU, 0xE3U,
|
||||
0xDBU, 0xABU, 0x4BU, 0x96U, 0x31U, 0x62U, 0xC4U, 0x95U, 0x37U, 0x6EU, 0xDCU, 0xA5U, 0x57U, 0xAEU, 0x41U, 0x82U,
|
||||
0x19U, 0x32U, 0x64U, 0xC8U, 0x8DU, 0x07U, 0x0EU, 0x1CU, 0x38U, 0x70U, 0xE0U, 0xDDU, 0xA7U, 0x53U, 0xA6U, 0x51U,
|
||||
0xA2U, 0x59U, 0xB2U, 0x79U, 0xF2U, 0xF9U, 0xEFU, 0xC3U, 0x9BU, 0x2BU, 0x56U, 0xACU, 0x45U, 0x8AU, 0x09U, 0x12U,
|
||||
0x24U, 0x48U, 0x90U, 0x3DU, 0x7AU, 0xF4U, 0xF5U, 0xF7U, 0xF3U, 0xFBU, 0xEBU, 0xCBU, 0x8BU, 0x0BU, 0x16U, 0x2CU,
|
||||
0x58U, 0xB0U, 0x7DU, 0xFAU, 0xE9U, 0xCFU, 0x83U, 0x1BU, 0x36U, 0x6CU, 0xD8U, 0xADU, 0x47U, 0x8EU, 0x01U, 0x00U
|
||||
};
|
||||
|
||||
const unsigned char LOG_TABLE[] =
|
||||
{
|
||||
0x00U, 0x00U, 0x01U, 0x19U, 0x02U, 0x32U, 0x1AU, 0xC6U, 0x03U, 0xDFU, 0x33U, 0xEEU, 0x1BU, 0x68U, 0xC7U, 0x4BU,
|
||||
0x04U, 0x64U, 0xE0U, 0x0EU, 0x34U, 0x8DU, 0xEFU, 0x81U, 0x1CU, 0xC1U, 0x69U, 0xF8U, 0xC8U, 0x08U, 0x4CU, 0x71U,
|
||||
0x05U, 0x8AU, 0x65U, 0x2FU, 0xE1U, 0x24U, 0x0FU, 0x21U, 0x35U, 0x93U, 0x8EU, 0xDAU, 0xF0U, 0x12U, 0x82U, 0x45U,
|
||||
0x1DU, 0xB5U, 0xC2U, 0x7DU, 0x6AU, 0x27U, 0xF9U, 0xB9U, 0xC9U, 0x9AU, 0x09U, 0x78U, 0x4DU, 0xE4U, 0x72U, 0xA6U,
|
||||
0x06U, 0xBFU, 0x8BU, 0x62U, 0x66U, 0xDDU, 0x30U, 0xFDU, 0xE2U, 0x98U, 0x25U, 0xB3U, 0x10U, 0x91U, 0x22U, 0x88U,
|
||||
0x36U, 0xD0U, 0x94U, 0xCEU, 0x8FU, 0x96U, 0xDBU, 0xBDU, 0xF1U, 0xD2U, 0x13U, 0x5CU, 0x83U, 0x38U, 0x46U, 0x40U,
|
||||
0x1EU, 0x42U, 0xB6U, 0xA3U, 0xC3U, 0x48U, 0x7EU, 0x6EU, 0x6BU, 0x3AU, 0x28U, 0x54U, 0xFAU, 0x85U, 0xBAU, 0x3DU,
|
||||
0xCAU, 0x5EU, 0x9BU, 0x9FU, 0x0AU, 0x15U, 0x79U, 0x2BU, 0x4EU, 0xD4U, 0xE5U, 0xACU, 0x73U, 0xF3U, 0xA7U, 0x57U,
|
||||
0x07U, 0x70U, 0xC0U, 0xF7U, 0x8CU, 0x80U, 0x63U, 0x0DU, 0x67U, 0x4AU, 0xDEU, 0xEDU, 0x31U, 0xC5U, 0xFEU, 0x18U,
|
||||
0xE3U, 0xA5U, 0x99U, 0x77U, 0x26U, 0xB8U, 0xB4U, 0x7CU, 0x11U, 0x44U, 0x92U, 0xD9U, 0x23U, 0x20U, 0x89U, 0x2EU,
|
||||
0x37U, 0x3FU, 0xD1U, 0x5BU, 0x95U, 0xBCU, 0xCFU, 0xCDU, 0x90U, 0x87U, 0x97U, 0xB2U, 0xDCU, 0xFCU, 0xBEU, 0x61U,
|
||||
0xF2U, 0x56U, 0xD3U, 0xABU, 0x14U, 0x2AU, 0x5DU, 0x9EU, 0x84U, 0x3CU, 0x39U, 0x53U, 0x47U, 0x6DU, 0x41U, 0xA2U,
|
||||
0x1FU, 0x2DU, 0x43U, 0xD8U, 0xB7U, 0x7BU, 0xA4U, 0x76U, 0xC4U, 0x17U, 0x49U, 0xECU, 0x7FU, 0x0CU, 0x6FU, 0xF6U,
|
||||
0x6CU, 0xA1U, 0x3BU, 0x52U, 0x29U, 0x9DU, 0x55U, 0xAAU, 0xFBU, 0x60U, 0x86U, 0xB1U, 0xBBU, 0xCCU, 0x3EU, 0x5AU,
|
||||
0xCBU, 0x59U, 0x5FU, 0xB0U, 0x9CU, 0xA9U, 0xA0U, 0x51U, 0x0BU, 0xF5U, 0x16U, 0xEBU, 0x7AU, 0x75U, 0x2CU, 0xD7U,
|
||||
0x4FU, 0xAEU, 0xD5U, 0xE9U, 0xE6U, 0xE7U, 0xADU, 0xE8U, 0x74U, 0xD6U, 0xF4U, 0xEAU, 0xA8U, 0x50U, 0x58U, 0xAFU
|
||||
};
|
||||
|
||||
/* multiplication using logarithms */
|
||||
static unsigned char gmult(unsigned char a, unsigned char b)
|
||||
{
|
||||
if (a == 0U || b == 0U)
|
||||
return 0U;
|
||||
|
||||
unsigned int i = LOG_TABLE[a];
|
||||
unsigned int j = LOG_TABLE[b];
|
||||
|
||||
return EXP_TABLE[i + j];
|
||||
}
|
||||
|
||||
/* Simulate a LFSR with generator polynomial for n byte RS code.
|
||||
* Pass in a pointer to the data array, and amount of data.
|
||||
*
|
||||
* The parity bytes are deposited into parity.
|
||||
*/
|
||||
void CRS129::encode(const unsigned char* msg, unsigned int nbytes, unsigned char* parity)
|
||||
{
|
||||
assert(msg != nullptr);
|
||||
assert(parity != nullptr);
|
||||
|
||||
for (unsigned int i = 0U; i < NPAR + 1U; i++)
|
||||
parity[i] = 0x00U;
|
||||
|
||||
for (unsigned int i = 0U; i < nbytes; i++)
|
||||
{
|
||||
unsigned char dbyte = msg[i] ^ parity[NPAR - 1U];
|
||||
|
||||
for (int j = NPAR - 1; j > 0; j--)
|
||||
parity[j] = parity[j - 1] ^ ::gmult(POLY[j], dbyte);
|
||||
|
||||
parity[0] = ::gmult(POLY[0], dbyte);
|
||||
}
|
||||
}
|
||||
|
||||
// Reed-Solomon (12,9) check
|
||||
bool CRS129::check(const unsigned char* in)
|
||||
{
|
||||
assert(in != nullptr);
|
||||
|
||||
unsigned char parity[4U];
|
||||
encode(in, 9U, parity);
|
||||
|
||||
return in[9U] == parity[2U] && in[10U] == parity[1U] && in[11U] == parity[0U];
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 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.
|
||||
*/
|
||||
|
||||
#if !defined(RS129_H)
|
||||
#define RS129_H
|
||||
|
||||
class CRS129
|
||||
{
|
||||
public:
|
||||
static bool check(const unsigned char* in);
|
||||
|
||||
static void encode(const unsigned char* msg, unsigned int nbytes, unsigned char* parity);
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,148 @@
|
||||
//
|
||||
// crawsocket.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Marius Petrescu (YO2LOJ) on 22/02/2020.
|
||||
// Copyright © 2020 Marius Petrescu (YO2LOJ). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include "Reflector.h"
|
||||
#include "RawSocket.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CRawSocket::CRawSocket()
|
||||
{
|
||||
m_Socket = -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// destructor
|
||||
|
||||
CRawSocket::~CRawSocket()
|
||||
{
|
||||
if ( m_Socket != -1 )
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// open & close
|
||||
|
||||
bool CRawSocket::Open(uint16 uiProto)
|
||||
{
|
||||
bool open = false;
|
||||
int on = 1;
|
||||
|
||||
// create socket
|
||||
m_Socket = socket(AF_INET, SOCK_RAW, uiProto);
|
||||
if ( m_Socket != -1 )
|
||||
{
|
||||
fcntl(m_Socket, F_SETFL, O_NONBLOCK);
|
||||
open = true;
|
||||
m_Proto = uiProto;
|
||||
}
|
||||
|
||||
// done
|
||||
return open;
|
||||
}
|
||||
|
||||
void CRawSocket::Close(void)
|
||||
{
|
||||
if ( m_Socket != -1 )
|
||||
{
|
||||
close(m_Socket);
|
||||
m_Socket = -1;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// read
|
||||
|
||||
int CRawSocket::Receive(uint8_t *Buffer, CIp *Ip, int timeout)
|
||||
{
|
||||
struct sockaddr_in Sin;
|
||||
fd_set FdSet;
|
||||
unsigned int uiFromLen = sizeof(struct sockaddr_in);
|
||||
int iRecvLen = -1;
|
||||
struct timeval tv;
|
||||
|
||||
// socket valid ?
|
||||
if ( m_Socket != -1 )
|
||||
{
|
||||
// control socket
|
||||
FD_ZERO(&FdSet);
|
||||
FD_SET(m_Socket, &FdSet);
|
||||
tv.tv_sec = timeout / 1000;
|
||||
tv.tv_usec = (timeout % 1000) * 1000;
|
||||
select(m_Socket + 1, &FdSet, 0, 0, &tv);
|
||||
|
||||
// read
|
||||
iRecvLen = (int)recvfrom(m_Socket, Buffer, RAW_BUFFER_LENMAX, 0, (struct sockaddr *)&Sin, &uiFromLen);
|
||||
|
||||
// handle
|
||||
if ( iRecvLen != -1 )
|
||||
{
|
||||
// get IP
|
||||
memcpy(Ip->GetPointer(), &Sin, sizeof(struct sockaddr_in));
|
||||
}
|
||||
}
|
||||
|
||||
// done
|
||||
return iRecvLen;
|
||||
}
|
||||
|
||||
// protocol specific
|
||||
|
||||
// ICMP
|
||||
|
||||
int CRawSocket::IcmpReceive(uint8_t *Buffer, CIp *Ip, int timeout)
|
||||
{
|
||||
int iIcmpType = -1;
|
||||
int iRecv;
|
||||
|
||||
if (m_Proto == IPPROTO_ICMP)
|
||||
{
|
||||
iRecv = Receive(Buffer, Ip, timeout);
|
||||
|
||||
if (iRecv >= (int)(sizeof(struct ip) + sizeof(struct icmp)))
|
||||
{
|
||||
struct ip *iph = (struct ip *)Buffer;
|
||||
int iphdrlen = iph->ip_hl * 4;
|
||||
struct icmp *icmph = (struct icmp *)((unsigned char *)iph + iphdrlen);
|
||||
struct ip *remote_iph = (struct ip *)((unsigned char *)icmph + 8);
|
||||
|
||||
iIcmpType = icmph->icmp_type;
|
||||
|
||||
struct sockaddr_in Sin;
|
||||
bzero(&Sin, sizeof(Sin));
|
||||
Sin.sin_family = AF_INET;
|
||||
Sin.sin_addr.s_addr = remote_iph->ip_dst.s_addr;
|
||||
|
||||
memcpy(Ip->GetPointer(), &Sin, sizeof(struct sockaddr_in));
|
||||
|
||||
}
|
||||
}
|
||||
return iIcmpType;
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
//
|
||||
// RawSocket.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Marius Petrescu (YO2LOJ) on 22/02/2020.
|
||||
// Copyright © 2020 Marius Petrescu (YO2LOJ). All rights reserved.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Description:
|
||||
// Raw socket access class with protocol specific
|
||||
|
||||
|
||||
#ifndef crawsocket_h
|
||||
#define crawsocket_h
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_icmp.h>
|
||||
#include "IP.h"
|
||||
#include "Buffer.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
#define RAW_BUFFER_LENMAX 65536
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CRawSocket
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CRawSocket();
|
||||
|
||||
// destructor
|
||||
~CRawSocket();
|
||||
|
||||
// open & close
|
||||
bool Open(uint16);
|
||||
void Close(void);
|
||||
int GetSocket(void) { return m_Socket; }
|
||||
|
||||
// read
|
||||
|
||||
// if ETH_P_ALL is used, the received data buffer will hold
|
||||
// the ethernet header (struct ethhdr) followed by the IP header (struct iphdr),
|
||||
// the protocol header (e.g tcp, udp, icmp) and the data.
|
||||
// For specific protocols, the data content may vary depending on the protocol
|
||||
// Returns the number of received bytes in buffer
|
||||
|
||||
protected:
|
||||
int Receive(uint8_t *, CIp *, int);
|
||||
|
||||
// ICMP receive helper
|
||||
// parameters:
|
||||
// buffer - packet receive buffer (starting with ip header)
|
||||
// ip - remote address (filled in on receive)
|
||||
// timeout - receive timeout in msec
|
||||
// return value:
|
||||
// ICMP type, -1 if nothing was received
|
||||
|
||||
public:
|
||||
int IcmpReceive(uint8_t *, CIp *, int);
|
||||
|
||||
// write
|
||||
// no write support - complexity makes it out of scope for now
|
||||
// to be added if needed
|
||||
|
||||
protected:
|
||||
// data
|
||||
int m_Socket;
|
||||
int m_Proto;
|
||||
struct sockaddr_in m_SocketAddr;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* crawsocket_h */
|
||||
@ -0,0 +1,729 @@
|
||||
//
|
||||
// creflector.cpp
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#include "Main.h"
|
||||
#include <string.h>
|
||||
#include "Reflector.h"
|
||||
#include "GateKeeper.h"
|
||||
#include "cdmriddirfile.h"
|
||||
#include "DMRIdDirHttp.h"
|
||||
#include "Transcoder.h"
|
||||
#include "YSFNodeDirFile.h"
|
||||
#include "YSFNodeDirhttp.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constructor
|
||||
|
||||
CReflector::CReflector()
|
||||
{
|
||||
keep_running = true;
|
||||
#ifdef DEBUG_DUMPFILE
|
||||
m_DebugFile.open("/Users/jeanluc/Desktop/xlxdebug.txt");
|
||||
#endif
|
||||
}
|
||||
|
||||
CReflector::CReflector(const CCallsign &callsign)
|
||||
{
|
||||
#ifdef DEBUG_DUMPFILE
|
||||
m_DebugFile.close();
|
||||
#endif
|
||||
keep_running = true;
|
||||
m_Callsign = callsign;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// destructor
|
||||
|
||||
CReflector::~CReflector()
|
||||
{
|
||||
keep_running = false;
|
||||
if ( m_XmlReportFuture.valid() )
|
||||
{
|
||||
m_XmlReportFuture.get();
|
||||
}
|
||||
#ifdef JSON_MONITOR
|
||||
if ( m_JsonReportFuture.valid() )
|
||||
{
|
||||
m_JsonReportFuture.get();
|
||||
}
|
||||
#endif
|
||||
for ( int i = 0; i < NB_OF_MODULES; i++ )
|
||||
{
|
||||
if ( m_RouterFuture[i].valid() )
|
||||
{
|
||||
m_RouterFuture[i].get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// operation
|
||||
|
||||
bool CReflector::Start(void)
|
||||
{
|
||||
// let's go!
|
||||
keep_running = true;
|
||||
|
||||
// init gate keeper. It can only return true!
|
||||
g_GateKeeper.Init();
|
||||
|
||||
#ifndef NO_XLX
|
||||
// init dmrid directory. No need to check the return value.
|
||||
g_DmridDir.Init();
|
||||
|
||||
// init wiresx node directory. Likewise with the return vale.
|
||||
g_YsfNodeDir.Init();
|
||||
|
||||
#ifdef TRANSCODER_IP
|
||||
// init the transcoder
|
||||
if (! g_Transcoder.Init())
|
||||
return false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// create protocols
|
||||
if (! m_Protocols.Init())
|
||||
{
|
||||
m_Protocols.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// start one thread per reflector module
|
||||
for ( int i = 0; i < NB_OF_MODULES; i++ )
|
||||
{
|
||||
m_RouterFuture[i] = std::async(std::launch::async, &CReflector::RouterThread, this, &(m_Stream[i]));
|
||||
}
|
||||
|
||||
// start the reporting threads
|
||||
m_XmlReportFuture = std::async(std::launch::async, &CReflector::XmlReportThread, this);
|
||||
#ifdef JSON_MONITOR
|
||||
m_JsonReportFuture = std::async(std::launch::async, &CReflector::JsonReportThread, this);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CReflector::Stop(void)
|
||||
{
|
||||
// stop & delete all threads
|
||||
keep_running = false;
|
||||
|
||||
// stop & delete report threads
|
||||
if ( m_XmlReportFuture.valid() )
|
||||
{
|
||||
m_XmlReportFuture.get();
|
||||
}
|
||||
#ifdef JSON_MONITOR
|
||||
if ( m_JsonReportFuture.valid() )
|
||||
{
|
||||
m_JsonReportFuture.get();
|
||||
}
|
||||
#endif
|
||||
|
||||
// stop & delete all router thread
|
||||
for ( int i = 0; i < NB_OF_MODULES; i++ )
|
||||
{
|
||||
if ( m_RouterFuture[i].valid() )
|
||||
{
|
||||
m_RouterFuture[i].get();
|
||||
}
|
||||
}
|
||||
|
||||
// close protocols
|
||||
m_Protocols.Close();
|
||||
|
||||
// close gatekeeper
|
||||
g_GateKeeper.Close();
|
||||
|
||||
#ifdef TRANSCODER_IP
|
||||
// close transcoder
|
||||
g_Transcoder.Close();
|
||||
#endif
|
||||
|
||||
#ifndef NO_XLX
|
||||
// close databases
|
||||
g_DmridDir.Close();
|
||||
g_YsfNodeDir.Close();
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// stream opening & closing
|
||||
|
||||
bool CReflector::IsStreaming(char module)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// clients MUST have bee locked by the caller so we can freely access it within the fuction
|
||||
CPacketStream *CReflector::OpenStream(std::unique_ptr<CDvHeaderPacket> &DvHeader, std::shared_ptr<CClient>client)
|
||||
{
|
||||
// check sid is not zero
|
||||
if ( 0U == DvHeader->GetStreamId() )
|
||||
return nullptr;
|
||||
|
||||
// check if client is valid candidate
|
||||
if ( ! m_Clients.IsClient(client) || client->IsAMaster() )
|
||||
return nullptr;
|
||||
|
||||
// check if no stream with same streamid already open
|
||||
// to prevent loops
|
||||
if ( IsStreamOpen(DvHeader) )
|
||||
{
|
||||
std::cerr << "Detected stream loop on module " << DvHeader->GetRpt2Module() << " for client " << client->GetCallsign() << " with sid " << DvHeader->GetStreamId() << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// get the module's queue
|
||||
char module = DvHeader->GetRpt2Module();
|
||||
CPacketStream *stream = GetStream(module);
|
||||
if ( stream == nullptr )
|
||||
return nullptr;
|
||||
|
||||
stream->Lock();
|
||||
// is it available ?
|
||||
if ( stream->OpenPacketStream(*DvHeader, client) )
|
||||
{
|
||||
// stream open, mark client as master
|
||||
// so that it can't be deleted
|
||||
client->SetMasterOfModule(module);
|
||||
|
||||
// update last heard time
|
||||
client->Heard();
|
||||
|
||||
// report
|
||||
std::cout << "Opening stream on module " << module << " for client " << client->GetCallsign() << " with sid " << DvHeader->GetStreamId() << " by user " << DvHeader->GetMyCallsign() << std::endl;
|
||||
|
||||
// and push header packet
|
||||
stream->Push(std::move(DvHeader));
|
||||
|
||||
// notify
|
||||
g_Reflector.OnStreamOpen(stream->GetUserCallsign());
|
||||
|
||||
}
|
||||
stream->Unlock();
|
||||
return stream;
|
||||
}
|
||||
|
||||
void CReflector::CloseStream(CPacketStream *stream)
|
||||
{
|
||||
if ( stream != nullptr )
|
||||
{
|
||||
// wait queue is empty. this waits forever
|
||||
bool bEmpty = false;
|
||||
do
|
||||
{
|
||||
stream->Lock();
|
||||
// do not use stream->IsEmpty() has this "may" never succeed
|
||||
// and anyway, the DvLastFramPacket short-circuit the transcoder
|
||||
// loop queues
|
||||
bEmpty = stream->empty();
|
||||
stream->Unlock();
|
||||
if ( !bEmpty )
|
||||
CTimePoint::TaskSleepFor(10);
|
||||
}
|
||||
while (!bEmpty);
|
||||
|
||||
GetClients(); // lock clients
|
||||
stream->Lock(); // lock stream
|
||||
|
||||
// get and check the master
|
||||
std::shared_ptr<CClient>client = stream->GetOwnerClient();
|
||||
if ( client != nullptr )
|
||||
{
|
||||
// client no longer a master
|
||||
client->NotAMaster();
|
||||
|
||||
// notify
|
||||
OnStreamClose(stream->GetUserCallsign());
|
||||
|
||||
std::cout << "Closing stream of module " << GetStreamModule(stream) << std::endl;
|
||||
}
|
||||
|
||||
// release clients
|
||||
ReleaseClients();
|
||||
|
||||
// unlock before closing
|
||||
// to avoid double lock in assiociated
|
||||
// codecstream close/thread-join
|
||||
stream->Unlock();
|
||||
|
||||
// and stop the queue
|
||||
stream->ClosePacketStream();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// router threads
|
||||
|
||||
void CReflector::RouterThread(CPacketStream *streamIn)
|
||||
{
|
||||
// get our module
|
||||
uint8 uiModuleId = GetStreamModule(streamIn);
|
||||
|
||||
// get on input queue
|
||||
std::unique_ptr<CPacket> packet;
|
||||
|
||||
while (keep_running)
|
||||
{
|
||||
// any packet in our input queue ?
|
||||
streamIn->Lock();
|
||||
if ( !streamIn->empty() )
|
||||
{
|
||||
// get the packet
|
||||
packet = streamIn->front();
|
||||
streamIn->pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
packet = nullptr;
|
||||
}
|
||||
streamIn->Unlock();
|
||||
|
||||
// route it
|
||||
if ( packet != nullptr )
|
||||
{
|
||||
// set origin
|
||||
packet->SetModuleId(uiModuleId);
|
||||
|
||||
// iterate on all protocols
|
||||
m_Protocols.Lock();
|
||||
for ( auto it=m_Protocols.begin(); it!=m_Protocols.end(); it++ )
|
||||
{
|
||||
// duplicate packet
|
||||
auto packetClone = packet->Duplicate();
|
||||
|
||||
// if packet is header, update RPT2 according to protocol
|
||||
if ( packetClone->IsDvHeader() )
|
||||
{
|
||||
// get our callsign
|
||||
CCallsign csRPT = (*it)->GetReflectorCallsign();
|
||||
csRPT.SetModule(GetStreamModule(streamIn));
|
||||
(dynamic_cast<CDvHeaderPacket *>(packetClone.get()))->SetRpt2Callsign(csRPT);
|
||||
}
|
||||
|
||||
// and push it
|
||||
CPacketQueue *queue = (*it)->GetQueue();
|
||||
queue->push(packetClone);
|
||||
(*it)->ReleaseQueue();
|
||||
}
|
||||
m_Protocols.Unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
CTimePoint::TaskSleepFor(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// report threads
|
||||
|
||||
void CReflector::XmlReportThread()
|
||||
{
|
||||
while (keep_running)
|
||||
{
|
||||
// report to xml file
|
||||
std::ofstream xmlFile;
|
||||
xmlFile.open(XML_PATH, std::ios::out | std::ios::trunc);
|
||||
if ( xmlFile.is_open() )
|
||||
{
|
||||
// write xml file
|
||||
WriteXmlFile(xmlFile);
|
||||
|
||||
// and close file
|
||||
xmlFile.close();
|
||||
}
|
||||
#ifndef DEBUG_NO_ERROR_ON_XML_OPEN_FAIL
|
||||
else
|
||||
{
|
||||
std::cout << "Failed to open " << XML_PATH << std::endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
// and wait a bit
|
||||
for (int i=0; i< XML_UPDATE_PERIOD && keep_running; i++)
|
||||
CTimePoint::TaskSleepFor(1000);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef JSON_MONITOR
|
||||
void CReflector::JsonReportThread()
|
||||
{
|
||||
CUdpSocket Socket;
|
||||
CBuffer Buffer;
|
||||
CIp Ip;
|
||||
bool bOn;
|
||||
|
||||
// init variable
|
||||
bOn = false;
|
||||
|
||||
// create listening socket
|
||||
if ( Socket.Open(JSON_PORT) )
|
||||
{
|
||||
// and loop
|
||||
while (keep_running)
|
||||
{
|
||||
// any command ?
|
||||
if ( Socket.Receive(Buffer, Ip, 50) )
|
||||
{
|
||||
// check verb
|
||||
if ( Buffer.Compare((uint8 *)"hello", 5) == 0 )
|
||||
{
|
||||
std::cout << "Monitor socket connected with " << Ip << std::endl;
|
||||
|
||||
// connected
|
||||
bOn = true;
|
||||
|
||||
// announce ourselves
|
||||
SendJsonReflectorObject(Socket, Ip);
|
||||
|
||||
// dump tables
|
||||
SendJsonNodesObject(Socket, Ip);
|
||||
SendJsonStationsObject(Socket, Ip);
|
||||
}
|
||||
else if ( Buffer.Compare((uint8 *)"bye", 3) == 0 )
|
||||
{
|
||||
std::cout << "Monitor socket disconnected" << std::endl;
|
||||
|
||||
// diconnected
|
||||
bOn = false;
|
||||
}
|
||||
}
|
||||
|
||||
// any notifications ?
|
||||
CNotification notification;
|
||||
m_Notifications.Lock();
|
||||
if ( !m_Notifications.empty() )
|
||||
{
|
||||
// get the packet
|
||||
notification = m_Notifications.front();
|
||||
m_Notifications.pop();
|
||||
}
|
||||
m_Notifications.Unlock();
|
||||
|
||||
// handle it
|
||||
if ( bOn )
|
||||
{
|
||||
switch ( notification.GetId() )
|
||||
{
|
||||
case NOTIFICATION_CLIENTS:
|
||||
case NOTIFICATION_PEERS:
|
||||
//std::cout << "Monitor updating nodes table" << std::endl;
|
||||
SendJsonNodesObject(Socket, Ip);
|
||||
break;
|
||||
case NOTIFICATION_USERS:
|
||||
//std::cout << "Monitor updating stations table" << std::endl;
|
||||
SendJsonStationsObject(Socket, Ip);
|
||||
break;
|
||||
case NOTIFICATION_STREAM_OPEN:
|
||||
//std::cout << "Monitor notify station " << notification.GetCallsign() << "going ON air" << std::endl;
|
||||
SendJsonStationsObject(Socket, Ip);
|
||||
SendJsonOnairObject(Socket, Ip, notification.GetCallsign());
|
||||
break;
|
||||
case NOTIFICATION_STREAM_CLOSE:
|
||||
//std::cout << "Monitor notify station " << notification.GetCallsign() << "going OFF air" << std::endl;
|
||||
SendJsonOffairObject(Socket, Ip, notification.GetCallsign());
|
||||
break;
|
||||
case NOTIFICATION_NONE:
|
||||
default:
|
||||
// nothing to do, just sleep a bit
|
||||
CTimePoint::TaskSleepFor(250);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "Error creating monitor socket" << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// notifications
|
||||
|
||||
void CReflector::OnPeersChanged(void)
|
||||
{
|
||||
CNotification notification(NOTIFICATION_PEERS);
|
||||
|
||||
m_Notifications.Lock();
|
||||
m_Notifications.push(notification);
|
||||
m_Notifications.Unlock();
|
||||
}
|
||||
|
||||
void CReflector::OnClientsChanged(void)
|
||||
{
|
||||
CNotification notification(NOTIFICATION_CLIENTS);
|
||||
|
||||
m_Notifications.Lock();
|
||||
m_Notifications.push(notification);
|
||||
m_Notifications.Unlock();
|
||||
}
|
||||
|
||||
void CReflector::OnUsersChanged(void)
|
||||
{
|
||||
CNotification notification(NOTIFICATION_USERS);
|
||||
|
||||
m_Notifications.Lock();
|
||||
m_Notifications.push(notification);
|
||||
m_Notifications.Unlock();
|
||||
}
|
||||
|
||||
void CReflector::OnStreamOpen(const CCallsign &callsign)
|
||||
{
|
||||
CNotification notification(NOTIFICATION_STREAM_OPEN, callsign);
|
||||
|
||||
m_Notifications.Lock();
|
||||
m_Notifications.push(notification);
|
||||
m_Notifications.Unlock();
|
||||
}
|
||||
|
||||
void CReflector::OnStreamClose(const CCallsign &callsign)
|
||||
{
|
||||
CNotification notification(NOTIFICATION_STREAM_CLOSE, callsign);
|
||||
|
||||
m_Notifications.Lock();
|
||||
m_Notifications.push(notification);
|
||||
m_Notifications.Unlock();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// modules & queues
|
||||
|
||||
int CReflector::GetModuleIndex(char module) const
|
||||
{
|
||||
int i = (int)module - (int)'A';
|
||||
if ( (i < 0) || (i >= NB_OF_MODULES) )
|
||||
{
|
||||
i = -1;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
CPacketStream *CReflector::GetStream(char module)
|
||||
{
|
||||
int i = GetModuleIndex(module);
|
||||
if ( i >= 0 )
|
||||
{
|
||||
return &(m_Stream[i]);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CReflector::IsStreamOpen(const std::unique_ptr<CDvHeaderPacket> &DvHeader)
|
||||
{
|
||||
for ( unsigned i = 0; i < m_Stream.size(); i++ )
|
||||
{
|
||||
if ( (m_Stream[i].GetStreamId() == DvHeader->GetStreamId()) && (m_Stream[i].IsOpen()) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char CReflector::GetStreamModule(CPacketStream *stream)
|
||||
{
|
||||
for ( unsigned i = 0; i < m_Stream.size(); i++ )
|
||||
{
|
||||
if ( &(m_Stream[i]) == stream )
|
||||
return GetModuleLetter(i);
|
||||
}
|
||||
return ' ';
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// xml helpers
|
||||
|
||||
void CReflector::WriteXmlFile(std::ofstream &xmlFile)
|
||||
{
|
||||
// write header
|
||||
xmlFile << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
|
||||
|
||||
// software version
|
||||
char sz[64];
|
||||
::sprintf(sz, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, VERSION_REVISION);
|
||||
xmlFile << "<Version>" << sz << "</Version>" << std::endl;
|
||||
|
||||
// linked peers
|
||||
xmlFile << "<" << m_Callsign << "linked peers>" << std::endl;
|
||||
// lock
|
||||
CPeers *peers = GetPeers();
|
||||
// iterate on peers
|
||||
for ( auto pit=peers->cbegin(); pit!=peers->cend(); pit++ )
|
||||
{
|
||||
(*pit)->WriteXml(xmlFile);
|
||||
}
|
||||
// unlock
|
||||
ReleasePeers();
|
||||
xmlFile << "</" << m_Callsign << "linked peers>" << std::endl;
|
||||
|
||||
// linked nodes
|
||||
xmlFile << "<" << m_Callsign << "linked nodes>" << std::endl;
|
||||
// lock
|
||||
CClients *clients = GetClients();
|
||||
// iterate on clients
|
||||
for ( auto cit=clients->cbegin(); cit!=clients->cend(); cit++ )
|
||||
{
|
||||
if ( (*cit)->IsNode() )
|
||||
{
|
||||
(*cit)->WriteXml(xmlFile);
|
||||
}
|
||||
}
|
||||
// unlock
|
||||
ReleaseClients();
|
||||
xmlFile << "</" << m_Callsign << "linked nodes>" << std::endl;
|
||||
|
||||
// last heard users
|
||||
xmlFile << "<" << m_Callsign << "heard users>" << std::endl;
|
||||
// lock
|
||||
CUsers *users = GetUsers();
|
||||
// iterate on users
|
||||
for ( auto it=users->begin(); it!=users->end(); it++ )
|
||||
{
|
||||
(*it).WriteXml(xmlFile);
|
||||
}
|
||||
// unlock
|
||||
ReleaseUsers();
|
||||
xmlFile << "</" << m_Callsign << "heard users>" << std::endl;
|
||||
}
|
||||
|
||||
|
||||
#ifdef JSON_MONITOR
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// json helpers
|
||||
|
||||
void CReflector::SendJsonReflectorObject(CUdpSocket &Socket, CIp &Ip)
|
||||
{
|
||||
char Buffer[1024];
|
||||
char cs[CALLSIGN_LEN+1];
|
||||
char mod[8] = "\"A\"";
|
||||
|
||||
// get reflector callsign
|
||||
m_Callsign.GetCallsign((uint8 *)cs);
|
||||
cs[CALLSIGN_LEN] = 0;
|
||||
|
||||
// build string
|
||||
::sprintf(Buffer, "{\"reflector\":\"%s\",\"modules\":[", cs);
|
||||
for ( int i = 0; i < NB_OF_MODULES; i++ )
|
||||
{
|
||||
::strcat(Buffer, mod);
|
||||
mod[1]++;
|
||||
if ( i < NB_OF_MODULES-1 )
|
||||
{
|
||||
::strcat(Buffer, ",");
|
||||
}
|
||||
}
|
||||
::strcat(Buffer, "]}");
|
||||
|
||||
// and send
|
||||
Socket.Send(Buffer, Ip);
|
||||
}
|
||||
|
||||
#define JSON_NBMAX_NODES 250
|
||||
|
||||
void CReflector::SendJsonNodesObject(CUdpSocket &Socket, CIp &Ip)
|
||||
{
|
||||
char Buffer[12+(JSON_NBMAX_NODES*94)];
|
||||
|
||||
// nodes object table
|
||||
::sprintf(Buffer, "{\"nodes\":[");
|
||||
// lock
|
||||
CClients *clients = GetClients();
|
||||
// iterate on clients
|
||||
for ( auto it=clients->cbegin(); it!=clients->cend(); )
|
||||
{
|
||||
(*it++)->GetJsonObject(Buffer);
|
||||
if ( it != clients->cend() )
|
||||
{
|
||||
::strcat(Buffer, ",");
|
||||
}
|
||||
}
|
||||
// unlock
|
||||
ReleaseClients();
|
||||
::strcat(Buffer, "]}");
|
||||
|
||||
// and send
|
||||
//std::cout << Buffer << std::endl;
|
||||
Socket.Send(Buffer, Ip);
|
||||
}
|
||||
|
||||
void CReflector::SendJsonStationsObject(CUdpSocket &Socket, CIp &Ip)
|
||||
{
|
||||
char Buffer[15+(LASTHEARD_USERS_MAX_SIZE*94)];
|
||||
|
||||
// stations object table
|
||||
::sprintf(Buffer, "{\"stations\":[");
|
||||
|
||||
// lock
|
||||
CUsers *users = GetUsers();
|
||||
// iterate on users
|
||||
for ( auto it=users->begin(); it!=users->end(); )
|
||||
{
|
||||
(*it++).GetJsonObject(Buffer);
|
||||
if ( it != users->end() )
|
||||
{
|
||||
::strcat(Buffer, ",");
|
||||
}
|
||||
}
|
||||
// unlock
|
||||
ReleaseUsers();
|
||||
|
||||
::strcat(Buffer, "]}");
|
||||
|
||||
// and send
|
||||
//std::cout << Buffer << std::endl;
|
||||
Socket.Send(Buffer, Ip);
|
||||
}
|
||||
|
||||
void CReflector::SendJsonOnairObject(CUdpSocket &Socket, CIp &Ip, const CCallsign &Callsign)
|
||||
{
|
||||
char Buffer[128];
|
||||
char sz[CALLSIGN_LEN+1];
|
||||
|
||||
// onair object
|
||||
Callsign.GetCallsignString(sz);
|
||||
::sprintf(Buffer, "{\"onair\":\"%s\"}", sz);
|
||||
|
||||
// and send
|
||||
//std::cout << Buffer << std::endl;
|
||||
Socket.Send(Buffer, Ip);
|
||||
}
|
||||
|
||||
void CReflector::SendJsonOffairObject(CUdpSocket &Socket, CIp &Ip, const CCallsign &Callsign)
|
||||
{
|
||||
char Buffer[128];
|
||||
char sz[CALLSIGN_LEN+1];
|
||||
|
||||
// offair object
|
||||
Callsign.GetCallsignString(sz);
|
||||
::sprintf(Buffer, "{\"offair\":\"%s\"}", sz);
|
||||
|
||||
// and send
|
||||
//std::cout << Buffer << std::endl;
|
||||
Socket.Send(Buffer, Ip);
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,160 @@
|
||||
//
|
||||
// Reflector.h
|
||||
// xlxd
|
||||
//
|
||||
// Created by Jean-Luc Deltombe (LX3JL) on 31/10/2015.
|
||||
// Copyright © 2015 Jean-Luc Deltombe (LX3JL). All rights reserved.
|
||||
// Copyright © 2020 Thomas A. Early, N7TAE
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// This file is part of xlxd.
|
||||
//
|
||||
// xlxd 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 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// xlxd 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 Foobar. If not, see <http://www.gnu.org/licenses/>.
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#ifndef creflector_h
|
||||
#define creflector_h
|
||||
|
||||
#include "ProtoAddress.h"
|
||||
#include "Users.h"
|
||||
#include "Clients.h"
|
||||
#include "Peers.h"
|
||||
#include "Protocols.h"
|
||||
#include "PacketStream.h"
|
||||
#include "NotificationQueue.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// define
|
||||
|
||||
// event defines
|
||||
#define EVENT_NONE 0
|
||||
#define EVENT_CLIENTS 1
|
||||
#define EVENT_USERS 2
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
// class
|
||||
|
||||
class CReflector
|
||||
{
|
||||
public:
|
||||
// constructor
|
||||
CReflector();
|
||||
CReflector(const CCallsign &);
|
||||
|
||||
// destructor
|
||||
virtual ~CReflector();
|
||||
|
||||
// settings
|
||||
void SetCallsign(const CCallsign &callsign) { m_Callsign = callsign; }
|
||||
const CCallsign &GetCallsign(void) const { return m_Callsign; }
|
||||
|
||||
#ifdef TRANSCODER_IP
|
||||
void SetTranscoderIp(const char *a, const int n) { memset(m_AmbedIp, 0, n); strncpy(m_AmbedIp, a, n-1); }
|
||||
const char *GetTranscoderIp(void) const { return m_AmbedIp; }
|
||||
#endif
|
||||
|
||||
// operation
|
||||
bool Start(void);
|
||||
void Stop(void);
|
||||
|
||||
// clients
|
||||
CClients *GetClients(void) { m_Clients.Lock(); return &m_Clients; }
|
||||
void ReleaseClients(void) { m_Clients.Unlock(); }
|
||||
|
||||
// peers
|
||||
CPeers *GetPeers(void) { m_Peers.Lock(); return &m_Peers; }
|
||||
void ReleasePeers(void) { m_Peers.Unlock(); }
|
||||
|
||||
// stream opening & closing
|
||||
CPacketStream *OpenStream(std::unique_ptr<CDvHeaderPacket> &, std::shared_ptr<CClient>);
|
||||
bool IsStreaming(char);
|
||||
void CloseStream(CPacketStream *);
|
||||
|
||||
// users
|
||||
CUsers *GetUsers(void) { m_Users.Lock(); return &m_Users; }
|
||||
void ReleaseUsers(void) { m_Users.Unlock(); }
|
||||
|
||||
// IP Addresses
|
||||
CProtoAddress m_Address;
|
||||
|
||||
// get
|
||||
bool IsValidModule(char c) const { return (GetModuleIndex(c) >= 0); }
|
||||
int GetModuleIndex(char) const;
|
||||
char GetModuleLetter(int i) const { return 'A' + (char)i; }
|
||||
|
||||
// notifications
|
||||
void OnPeersChanged(void);
|
||||
void OnClientsChanged(void);
|
||||
void OnUsersChanged(void);
|
||||
void OnStreamOpen(const CCallsign &);
|
||||
void OnStreamClose(const CCallsign &);
|
||||
|
||||
protected:
|
||||
// threads
|
||||
void RouterThread(CPacketStream *);
|
||||
void XmlReportThread(void);
|
||||
#ifdef JSON_MONITOR
|
||||
void JsonReportThread(void);
|
||||
#endif
|
||||
|
||||
// streams
|
||||
CPacketStream *GetStream(char);
|
||||
bool IsStreamOpen(const std::unique_ptr<CDvHeaderPacket> &);
|
||||
char GetStreamModule(CPacketStream *);
|
||||
|
||||
// xml helpers
|
||||
void WriteXmlFile(std::ofstream &);
|
||||
|
||||
#ifdef JSON_MONITOR
|
||||
// json helpers
|
||||
void SendJsonReflectorObject(CUdpSocket &, CIp &);
|
||||
void SendJsonNodesObject(CUdpSocket &, CIp &);
|
||||
void SendJsonStationsObject(CUdpSocket &, CIp &);
|
||||
void SendJsonOnairObject(CUdpSocket &, CIp &, const CCallsign &);
|
||||
void SendJsonOffairObject(CUdpSocket &, CIp &, const CCallsign &);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
// identity
|
||||
CCallsign m_Callsign;
|
||||
#ifdef TRANSCODER_IP
|
||||
char m_AmbedIp[INET6_ADDRSTRLEN];
|
||||
#endif
|
||||
|
||||
// objects
|
||||
CUsers m_Users; // sorted list of lastheard stations
|
||||
CClients m_Clients; // list of linked repeaters/nodes/peers's modules
|
||||
CPeers m_Peers; // list of linked peers
|
||||
CProtocols m_Protocols; // list of supported protocol handlers
|
||||
|
||||
// queues
|
||||
std::array<CPacketStream, NB_OF_MODULES> m_Stream;
|
||||
|
||||
// threads
|
||||
std::atomic<bool> keep_running;
|
||||
std::array<std::future<void>, NB_OF_MODULES> m_RouterFuture;
|
||||
std::future<void> m_XmlReportFuture, m_JsonReportFuture;
|
||||
|
||||
// notifications
|
||||
CNotificationQueue m_Notifications;
|
||||
|
||||
public:
|
||||
#ifdef DEBUG_DUMPFILE
|
||||
std::ofstream m_DebugFile;
|
||||
#endif
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif /* creflector_h */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue