2015-12-29 17:45:47 -05:00
|
|
|
//
|
|
|
|
// cprotocol.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
|
2020-07-02 13:38:10 -04:00
|
|
|
// along with Foobar. If not, see <http://www.gnu.org/licenses/>.
|
2015-12-29 17:45:47 -05:00
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#include "main.h"
|
|
|
|
#include "cprotocol.h"
|
|
|
|
#include "cclients.h"
|
|
|
|
#include "creflector.h"
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// constructor
|
|
|
|
|
|
|
|
|
|
|
|
CProtocol::CProtocol()
|
|
|
|
{
|
|
|
|
m_bStopThread = false;
|
|
|
|
m_pThread = NULL;
|
|
|
|
m_Streams.reserve(NB_OF_MODULES);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// destructor
|
|
|
|
|
|
|
|
CProtocol::~CProtocol()
|
|
|
|
{
|
|
|
|
// kill threads
|
|
|
|
m_bStopThread = true;
|
|
|
|
if ( m_pThread != NULL )
|
|
|
|
{
|
|
|
|
m_pThread->join();
|
|
|
|
delete m_pThread;
|
|
|
|
}
|
2020-07-02 13:38:10 -04:00
|
|
|
|
2015-12-29 17:45:47 -05:00
|
|
|
// empty queue
|
|
|
|
m_Queue.Lock();
|
|
|
|
while ( !m_Queue.empty() )
|
|
|
|
{
|
|
|
|
m_Queue.pop();
|
|
|
|
}
|
|
|
|
m_Queue.Unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// initialization
|
|
|
|
|
|
|
|
bool CProtocol::Init(void)
|
|
|
|
{
|
|
|
|
// init reflector apparent callsign
|
|
|
|
m_ReflectorCallsign = g_Reflector.GetCallsign();
|
2020-07-02 13:38:10 -04:00
|
|
|
|
2015-12-29 17:45:47 -05:00
|
|
|
// reset stop flag
|
|
|
|
m_bStopThread = false;
|
|
|
|
|
|
|
|
// start thread;
|
|
|
|
m_pThread = new std::thread(CProtocol::Thread, this);
|
2020-07-02 13:38:10 -04:00
|
|
|
|
2015-12-29 17:45:47 -05:00
|
|
|
// done
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CProtocol::Close(void)
|
|
|
|
{
|
|
|
|
m_bStopThread = true;
|
|
|
|
if ( m_pThread != NULL )
|
|
|
|
{
|
|
|
|
m_pThread->join();
|
|
|
|
delete m_pThread;
|
|
|
|
m_pThread = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// thread
|
|
|
|
|
|
|
|
void CProtocol::Thread(CProtocol *This)
|
|
|
|
{
|
|
|
|
while ( !This->m_bStopThread )
|
|
|
|
{
|
|
|
|
This->Task();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// packet encoding helpers
|
|
|
|
|
|
|
|
bool CProtocol::EncodeDvPacket(const CPacket &packet, CBuffer *buffer) const
|
|
|
|
{
|
|
|
|
bool ok = false;
|
|
|
|
if ( packet.IsDvFrame() )
|
|
|
|
{
|
|
|
|
if ( packet.IsLastPacket() )
|
|
|
|
{
|
|
|
|
ok = EncodeDvLastFramePacket((const CDvLastFramePacket &)packet, buffer);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ok = EncodeDvFramePacket((const CDvFramePacket &)packet, buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( packet.IsDvHeader() )
|
|
|
|
{
|
|
|
|
ok = EncodeDvHeaderPacket((const CDvHeaderPacket &)packet, buffer);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
buffer->clear();
|
|
|
|
}
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// streams helpers
|
|
|
|
|
2017-02-02 10:37:38 -05:00
|
|
|
void CProtocol::OnDvFramePacketIn(CDvFramePacket *Frame, const CIp *Ip)
|
2015-12-29 17:45:47 -05:00
|
|
|
{
|
|
|
|
// find the stream
|
2017-02-02 10:37:38 -05:00
|
|
|
CPacketStream *stream = GetStream(Frame->GetStreamId(), Ip);
|
2020-07-02 13:38:10 -04:00
|
|
|
if ( stream == NULL )
|
|
|
|
{
|
2021-01-05 04:36:36 -05:00
|
|
|
// std::cout << "Deleting oprhaned Last Frame Packet with StreamId " << Frame->GetStreamId() << " from " << *Ip << std::endl;
|
2020-07-02 13:38:10 -04:00
|
|
|
delete Frame;
|
|
|
|
}
|
|
|
|
else
|
2015-12-29 17:45:47 -05:00
|
|
|
{
|
2017-08-22 14:23:57 -04:00
|
|
|
//std::cout << "DV frame" << "from " << *Ip << std::endl;
|
2015-12-29 17:45:47 -05:00
|
|
|
// and push
|
|
|
|
stream->Lock();
|
|
|
|
stream->Push(Frame);
|
|
|
|
stream->Unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-16 10:57:24 -04:00
|
|
|
void CProtocol::OnDvLastFramePacketIn(CDvLastFramePacket *Frame, const CIp *Ip)
|
|
|
|
{
|
|
|
|
// find the stream
|
|
|
|
CPacketStream *stream = GetStream(Frame->GetStreamId(), Ip);
|
2020-07-02 13:38:10 -04:00
|
|
|
if ( stream == NULL )
|
|
|
|
{
|
2021-01-05 04:36:36 -05:00
|
|
|
// std::cout << "Deleting oprhaned Last Frame Packet with StreamId " << Frame->GetStreamId() << " from " << *Ip << std::endl;
|
2020-07-02 13:38:10 -04:00
|
|
|
delete Frame;
|
|
|
|
}
|
|
|
|
else
|
2019-03-16 10:57:24 -04:00
|
|
|
{
|
|
|
|
// push
|
|
|
|
stream->Lock();
|
|
|
|
stream->Push(Frame);
|
|
|
|
stream->Unlock();
|
2021-01-05 04:36:36 -05:00
|
|
|
|
|
|
|
// and 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)
|
|
|
|
// g_Reflector.CloseStream(stream);
|
2019-03-16 10:57:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-29 17:45:47 -05:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// stream handle helpers
|
|
|
|
|
2017-02-02 10:37:38 -05:00
|
|
|
CPacketStream *CProtocol::GetStream(uint16 uiStreamId, const CIp *Ip)
|
2015-12-29 17:45:47 -05:00
|
|
|
{
|
|
|
|
CPacketStream *stream = NULL;
|
2020-07-02 13:38:10 -04:00
|
|
|
|
2017-02-02 10:37:38 -05:00
|
|
|
// find if we have a stream with same streamid in our cache
|
2015-12-29 17:45:47 -05:00
|
|
|
for ( int i = 0; (i < m_Streams.size()) && (stream == NULL); i++ )
|
|
|
|
{
|
|
|
|
if ( m_Streams[i]->GetStreamId() == uiStreamId )
|
|
|
|
{
|
2017-02-02 10:37:38 -05:00
|
|
|
// if Ip not NULL, also check if IP match
|
2019-12-01 07:57:12 -05:00
|
|
|
if ( (Ip != NULL) && (m_Streams[i]->GetOwnerIp() != NULL) )
|
2017-02-02 10:37:38 -05:00
|
|
|
{
|
2019-12-01 07:57:12 -05:00
|
|
|
if ( *Ip == *(m_Streams[i]->GetOwnerIp()) )
|
|
|
|
{
|
|
|
|
stream = m_Streams[i];
|
|
|
|
}
|
2017-02-02 10:37:38 -05:00
|
|
|
}
|
2015-12-29 17:45:47 -05:00
|
|
|
}
|
|
|
|
}
|
2017-02-02 10:37:38 -05:00
|
|
|
// done
|
2015-12-29 17:45:47 -05:00
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CProtocol::CheckStreamsTimeout(void)
|
|
|
|
{
|
|
|
|
for ( int i = 0; i < m_Streams.size(); i++ )
|
|
|
|
{
|
|
|
|
// time out ?
|
|
|
|
m_Streams[i]->Lock();
|
|
|
|
if ( m_Streams[i]->IsExpired() )
|
|
|
|
{
|
|
|
|
// yes, close it
|
|
|
|
m_Streams[i]->Unlock();
|
|
|
|
g_Reflector.CloseStream(m_Streams[i]);
|
|
|
|
// and remove it
|
|
|
|
m_Streams.erase(m_Streams.begin()+i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_Streams[i]->Unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// queue helper
|
|
|
|
|
|
|
|
void CProtocol::HandleQueue(void)
|
|
|
|
{
|
|
|
|
// the default protocol just keep queue empty
|
|
|
|
m_Queue.Lock();
|
|
|
|
while ( !m_Queue.empty() )
|
|
|
|
{
|
|
|
|
delete m_Queue.front();
|
|
|
|
m_Queue.pop();
|
|
|
|
}
|
|
|
|
m_Queue.Unlock();
|
|
|
|
}
|
|
|
|
|
2016-02-11 12:51:12 -05:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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 == ' ');
|
|
|
|
}
|
2015-12-29 17:45:47 -05:00
|
|
|
|
2017-08-22 14:23:57 -04:00
|
|
|
////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// 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;
|
|
|
|
}
|
2021-01-05 04:36:36 -05:00
|
|
|
|