#24 Port DRats
parent
c11065855e
commit
0ddbe62b18
@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright (C) 2011 by Jonathan Naylor G4KLX
|
||||
* Copyright (c) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "TCPReaderWriterServer.h"
|
||||
#include "Log.h"
|
||||
#include "NetUtils.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
CTCPReaderWriterServer::CTCPReaderWriterServer(const std::string& address, unsigned int port) :
|
||||
CThread("TCP server"),
|
||||
m_address(address),
|
||||
m_port(port),
|
||||
m_fd(-1),
|
||||
m_client(NULL),
|
||||
m_stopped(false)
|
||||
{
|
||||
assert(port > 0U);
|
||||
}
|
||||
|
||||
CTCPReaderWriterServer::~CTCPReaderWriterServer()
|
||||
{
|
||||
}
|
||||
|
||||
bool CTCPReaderWriterServer::start()
|
||||
{
|
||||
bool ret = open();
|
||||
if (!ret) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
Create();
|
||||
Run();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CTCPReaderWriterServer::read(unsigned char* buffer, unsigned int length, unsigned int secs)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
if (m_client != NULL) {
|
||||
int ret = m_client->read(buffer, length, secs);
|
||||
if (ret < 0) {
|
||||
CLog::logInfo("Lost TCP connection to port %u", m_port);
|
||||
|
||||
m_client->close();
|
||||
delete m_client;
|
||||
m_client = NULL;
|
||||
|
||||
open();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CTCPReaderWriterServer::write(const unsigned char* buffer, unsigned int length)
|
||||
{
|
||||
assert(buffer != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
if (m_client != NULL) {
|
||||
bool ret = m_client->write(buffer, length);
|
||||
if (!ret) {
|
||||
CLog::logInfo("Lost TCP connection to port %u", m_port);
|
||||
|
||||
m_client->close();
|
||||
delete m_client;
|
||||
m_client = NULL;
|
||||
|
||||
open();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void* CTCPReaderWriterServer::Entry()
|
||||
{
|
||||
#ifndef DEBUG_DSTARGW
|
||||
try {
|
||||
#endif
|
||||
while (!m_stopped) {
|
||||
int ret = accept();
|
||||
switch (ret) {
|
||||
case -2:
|
||||
break;
|
||||
case -1:
|
||||
break;
|
||||
default:
|
||||
CLog::logInfo("Incoming TCP connection to port %u", m_port);
|
||||
m_client = new CTCPReaderWriterClient(ret);
|
||||
close();
|
||||
break;
|
||||
}
|
||||
|
||||
Sleep(1000UL);
|
||||
}
|
||||
|
||||
if (m_client != NULL) {
|
||||
m_client->close();
|
||||
delete m_client;
|
||||
}
|
||||
|
||||
close();
|
||||
|
||||
#ifndef DEBUG_DSTARGW
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
std::string message(e.what());
|
||||
CLog::logError("Exception raised in the TCP Reader-Writer Server thread - \"%s\"", message.c_str());
|
||||
}
|
||||
catch (...) {
|
||||
CLog::logError("Unknown exception raised in the TCP Reader-Writer Server thread");
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CTCPReaderWriterServer::stop()
|
||||
{
|
||||
m_stopped = true;
|
||||
|
||||
Wait();
|
||||
}
|
||||
|
||||
bool CTCPReaderWriterServer::open()
|
||||
{
|
||||
m_fd = ::socket(PF_INET, SOCK_STREAM, 0);
|
||||
if (m_fd < 0) {
|
||||
CLog::logError("Cannot create the TCP server socket, err=%d", errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_in addr;
|
||||
::memset(&addr, 0x00, sizeof(struct sockaddr_in));
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(m_port);
|
||||
if (m_address.empty())
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
else
|
||||
addr.sin_addr = lookup(m_address);
|
||||
|
||||
if (addr.sin_addr.s_addr == INADDR_NONE) {
|
||||
CLog::logError("The address is invalid - %s", m_address.c_str());
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
int reuse = 1;
|
||||
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
|
||||
CLog::logError("Cannot set the TCP server socket option, err=%d", errno);
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::bind(m_fd, (sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1) {
|
||||
CLog::logError("Cannot bind the TCP server address, err=%d", errno);
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
::listen(m_fd, 5);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int CTCPReaderWriterServer::accept()
|
||||
{
|
||||
if (m_fd == -1)
|
||||
return -1;
|
||||
|
||||
// Check that the accept() won't block
|
||||
fd_set readFds;
|
||||
FD_ZERO(&readFds);
|
||||
#if defined(__WINDOWS__)
|
||||
FD_SET((unsigned int)m_fd, &readFds);
|
||||
#else
|
||||
FD_SET(m_fd, &readFds);
|
||||
#endif
|
||||
|
||||
// Return after timeout
|
||||
timeval tv;
|
||||
tv.tv_sec = 0L;
|
||||
tv.tv_usec = 0L;
|
||||
|
||||
int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv);
|
||||
if (ret < 0) {
|
||||
CLog::logError("Error returned from TCP server select, err=%d", errno);
|
||||
return -2;
|
||||
}
|
||||
|
||||
#if defined(__WINDOWS__)
|
||||
if (!FD_ISSET((unsigned int)m_fd, &readFds))
|
||||
return -1;
|
||||
#else
|
||||
if (!FD_ISSET(m_fd, &readFds))
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
struct sockaddr_in addr;
|
||||
#if defined(__WINDOWS__)
|
||||
int len = sizeof(struct sockaddr_in);
|
||||
#else
|
||||
socklen_t len = sizeof(struct sockaddr_in);
|
||||
#endif
|
||||
|
||||
ret = ::accept(m_fd, (sockaddr*)&addr, &len);
|
||||
if (ret < 0) {
|
||||
CLog::logError("Error returned from TCP server accept, err=%d", errno);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CTCPReaderWriterServer::close()
|
||||
{
|
||||
if (m_fd != -1) {
|
||||
::close(m_fd);
|
||||
m_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
in_addr CTCPReaderWriterServer::lookup(const std::string& hostname) const
|
||||
{
|
||||
in_addr addrv4;
|
||||
addrv4.s_addr = INADDR_NONE;
|
||||
|
||||
sockaddr_storage addr;
|
||||
auto res = CNetUtils::lookupV4(hostname, addr);
|
||||
|
||||
if(res) {
|
||||
addrv4 = TOIPV4(addr)->sin_addr;
|
||||
}
|
||||
|
||||
return addrv4;
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2011 by Jonathan Naylor G4KLX
|
||||
* Copyright (c) 2021-2022 by Geoffrey Merck F4FXL / KC3FRA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "TCPReaderWriterClient.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#include <netdb.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <string>
|
||||
|
||||
class CTCPReaderWriterServer : public CThread {
|
||||
public:
|
||||
CTCPReaderWriterServer(const std::string& address, unsigned int port);
|
||||
virtual ~CTCPReaderWriterServer();
|
||||
|
||||
virtual bool start();
|
||||
|
||||
virtual bool write(const unsigned char* buffer, unsigned int length);
|
||||
virtual int read(unsigned char* buffer, unsigned int length, unsigned int secs);
|
||||
|
||||
virtual void stop();
|
||||
|
||||
virtual void* Entry();
|
||||
|
||||
private:
|
||||
std::string m_address;
|
||||
unsigned short m_port;
|
||||
int m_fd;
|
||||
CTCPReaderWriterClient* m_client;
|
||||
bool m_stopped;
|
||||
|
||||
bool open();
|
||||
int accept();
|
||||
void close();
|
||||
in_addr lookup(const std::string& hostname) const;
|
||||
};
|
||||
@ -0,0 +1,384 @@
|
||||
/*
|
||||
* Copyright (C) 2011-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 "DStarDefines.h"
|
||||
#include "DRATSServer.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <string.h>
|
||||
#include <chrono>
|
||||
|
||||
// #define LOOPBACK
|
||||
|
||||
const unsigned int BUFFER_LENGTH = 30000U;
|
||||
|
||||
CDRATSServer::CDRATSServer(const std::string& address, unsigned int port, const std::string& callsign, IRepeaterCallback* handler) :
|
||||
CThread("DRats"),
|
||||
m_address(address),
|
||||
m_port(port),
|
||||
m_callsign(callsign),
|
||||
m_handler(handler),
|
||||
m_socket(NULL),
|
||||
m_stopped(false),
|
||||
m_readState(SS_FIRST),
|
||||
m_readBuffer(NULL),
|
||||
m_readLength(0U),
|
||||
m_readPos(0U),
|
||||
m_readEnd(false),
|
||||
m_writeText(NULL),
|
||||
m_writeState(SS_FIRST),
|
||||
m_writeBuffer(NULL),
|
||||
m_writeLength(0U)
|
||||
{
|
||||
assert(handler != NULL);
|
||||
assert(port > 0U);
|
||||
|
||||
m_readBuffer = new unsigned char[BUFFER_LENGTH];
|
||||
m_writeBuffer = new unsigned char[BUFFER_LENGTH];
|
||||
m_writeText = new unsigned char[6U];
|
||||
}
|
||||
|
||||
CDRATSServer::~CDRATSServer()
|
||||
{
|
||||
delete[] m_readBuffer;
|
||||
delete[] m_writeBuffer;
|
||||
delete[] m_writeText;
|
||||
}
|
||||
|
||||
bool CDRATSServer::open()
|
||||
{
|
||||
m_socket = new CTCPReaderWriterServer(m_address, m_port);
|
||||
bool ret = m_socket->start();
|
||||
if (!ret) {
|
||||
delete m_socket;
|
||||
m_socket = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
Create();
|
||||
Run();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CDRATSServer::writeHeader(const CHeaderData&)
|
||||
{
|
||||
m_writeState = SS_FIRST;
|
||||
|
||||
if (m_writeLength > 0U && m_socket != NULL) {
|
||||
CUtils::dump("From RF", m_writeBuffer, m_writeLength);
|
||||
m_socket->write(m_writeBuffer, m_writeLength);
|
||||
}
|
||||
|
||||
m_writeLength = 0U;
|
||||
}
|
||||
|
||||
void CDRATSServer::writeData(const CAMBEData& data)
|
||||
{
|
||||
// Sync data isn't sent on
|
||||
if (data.isSync()) {
|
||||
m_writeState = SS_FIRST;
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.isEnd()) {
|
||||
if (m_writeLength > 0U && m_socket != NULL) {
|
||||
CUtils::dump("From RF", m_writeBuffer, m_writeLength);
|
||||
m_socket->write(m_writeBuffer, m_writeLength);
|
||||
}
|
||||
|
||||
m_writeLength = 0U;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char buffer[DV_FRAME_MAX_LENGTH_BYTES];
|
||||
unsigned int length = data.getData(buffer, DV_FRAME_MAX_LENGTH_BYTES);
|
||||
|
||||
if (length != DV_FRAME_LENGTH_BYTES)
|
||||
return;
|
||||
|
||||
unsigned char byte1 = buffer[VOICE_FRAME_LENGTH_BYTES + 0U] ^ SCRAMBLER_BYTE1;
|
||||
unsigned char byte2 = buffer[VOICE_FRAME_LENGTH_BYTES + 1U] ^ SCRAMBLER_BYTE2;
|
||||
unsigned char byte3 = buffer[VOICE_FRAME_LENGTH_BYTES + 2U] ^ SCRAMBLER_BYTE3;
|
||||
|
||||
switch (m_writeState) {
|
||||
case SS_FIRST:
|
||||
m_writeText[0U] = byte1;
|
||||
m_writeText[1U] = byte2;
|
||||
m_writeText[2U] = byte3;
|
||||
m_writeState = SS_SECOND;
|
||||
return;
|
||||
|
||||
case SS_SECOND:
|
||||
m_writeText[3U] = byte1;
|
||||
m_writeText[4U] = byte2;
|
||||
m_writeText[5U] = byte3;
|
||||
m_writeState = SS_FIRST;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((m_writeText[0U] & SLOW_DATA_TYPE_MASK) != SLOW_DATA_TYPE_GPS)
|
||||
return;
|
||||
|
||||
length = m_writeText[0U] & 0x07; // Maximum value of 5
|
||||
if (length > 5U)
|
||||
length = 5U;
|
||||
|
||||
for (unsigned int i = 0U; i < length; i++) {
|
||||
m_writeBuffer[m_writeLength++] = m_writeText[i + 1U];
|
||||
|
||||
// Check for [EOB] in the buffer to signal the end of the D-RATS data.
|
||||
// To allow strstr() to run correctly
|
||||
m_writeBuffer[m_writeLength] = 0x00U;
|
||||
|
||||
if (::strstr((char*)m_writeBuffer, "[EOB]") != NULL) {
|
||||
if (m_socket != NULL) {
|
||||
CUtils::dump("From RF", m_writeBuffer, m_writeLength);
|
||||
m_socket->write(m_writeBuffer, m_writeLength);
|
||||
}
|
||||
|
||||
m_writeLength = 0U;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CDRATSServer::writeEnd()
|
||||
{
|
||||
if (m_writeLength > 0U && m_socket != NULL) {
|
||||
CUtils::dump("From RF", m_writeBuffer, m_writeLength);
|
||||
m_socket->write(m_writeBuffer, m_writeLength);
|
||||
}
|
||||
|
||||
m_writeLength = 0U;
|
||||
}
|
||||
|
||||
void* CDRATSServer::Entry()
|
||||
{
|
||||
CLog::logInfo("Starting the D-RATS Server thread for %s", m_callsign.c_str());
|
||||
|
||||
bool sending = false;
|
||||
unsigned int id = 0U;
|
||||
|
||||
unsigned char seqNo = 0U;
|
||||
unsigned int sent = 0U;
|
||||
|
||||
std::chrono::high_resolution_clock::time_point time;
|
||||
|
||||
#ifndef DEBUG_DSTARGW
|
||||
try {
|
||||
#endif
|
||||
while (!m_stopped) {
|
||||
serviceSocket();
|
||||
|
||||
if (m_readEnd && !sending) {
|
||||
id = CHeaderData::createId();
|
||||
|
||||
// Write header
|
||||
CHeaderData header;
|
||||
header.setMyCall1(m_callsign);
|
||||
header.setMyCall2("DATA");
|
||||
header.setYourCall("CQCQCQ ");
|
||||
header.setId(id);
|
||||
|
||||
#if defined(LOOPBACK)
|
||||
writeHeader(header);
|
||||
#else
|
||||
m_handler->process(header, DIR_INCOMING, AS_DRATS);
|
||||
#endif
|
||||
|
||||
m_readState = SS_FIRST;
|
||||
m_readPos = 0U;
|
||||
sending = true;
|
||||
seqNo = 0U;
|
||||
sent = 0U;
|
||||
|
||||
time = std::chrono::high_resolution_clock::now();
|
||||
}
|
||||
|
||||
if (m_readEnd && sending) {
|
||||
unsigned int needed = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - time).count() / DSTAR_FRAME_TIME_MS;
|
||||
|
||||
while (sent < needed && sending) {
|
||||
// Write AMBE data
|
||||
CAMBEData data;
|
||||
data.setId(id);
|
||||
|
||||
unsigned char buffer[DV_FRAME_LENGTH_BYTES];
|
||||
::memcpy(buffer + 0U, NULL_AMBE_DATA_BYTES, VOICE_FRAME_LENGTH_BYTES);
|
||||
|
||||
// Insert sync bytes when the sequence number is zero, slow data otherwise
|
||||
if (seqNo == 0U) {
|
||||
::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES);
|
||||
m_readState = SS_FIRST;
|
||||
} else {
|
||||
if (m_readState == SS_FIRST) {
|
||||
unsigned char readText[3U];
|
||||
::memset(readText, 'f', 3U);
|
||||
|
||||
unsigned int length = m_readLength - m_readPos;
|
||||
unsigned char bytes = 5U;
|
||||
if (length < 5U)
|
||||
bytes = length;
|
||||
|
||||
readText[0U] = SLOW_DATA_TYPE_GPS | bytes;
|
||||
|
||||
for (unsigned int i = 0U; i < 2U && m_readPos < m_readLength; i++)
|
||||
readText[i + 1U] = m_readBuffer[m_readPos++];
|
||||
|
||||
readText[0U] ^= SCRAMBLER_BYTE1;
|
||||
readText[1U] ^= SCRAMBLER_BYTE2;
|
||||
readText[2U] ^= SCRAMBLER_BYTE3;
|
||||
|
||||
::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, readText, DATA_FRAME_LENGTH_BYTES);
|
||||
|
||||
m_readState = SS_SECOND;
|
||||
} else {
|
||||
unsigned char readText[3U];
|
||||
::memset(readText, 'f', 3U);
|
||||
|
||||
for (unsigned int i = 0U; i < 3U && m_readPos < m_readLength; i++)
|
||||
readText[i] = m_readBuffer[m_readPos++];
|
||||
|
||||
readText[0U] ^= SCRAMBLER_BYTE1;
|
||||
readText[1U] ^= SCRAMBLER_BYTE2;
|
||||
readText[2U] ^= SCRAMBLER_BYTE3;
|
||||
|
||||
::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, readText, DATA_FRAME_LENGTH_BYTES);
|
||||
|
||||
m_readState = SS_FIRST;
|
||||
}
|
||||
}
|
||||
|
||||
data.setSeq(seqNo);
|
||||
data.setData(buffer, DV_FRAME_LENGTH_BYTES);
|
||||
sent++;
|
||||
|
||||
#if defined(LOOPBACK)
|
||||
writeData(data);
|
||||
#else
|
||||
m_handler->process(data, DIR_INCOMING, AS_DRATS);
|
||||
#endif
|
||||
if (m_readPos == m_readLength) {
|
||||
if (m_readState == SS_SECOND) {
|
||||
seqNo++;
|
||||
if (seqNo == 21U)
|
||||
seqNo = 0U;
|
||||
|
||||
unsigned char readText[3U];
|
||||
readText[0U] = 'f' ^ SCRAMBLER_BYTE1;
|
||||
readText[1U] = 'f' ^ SCRAMBLER_BYTE2;
|
||||
readText[2U] = 'f' ^ SCRAMBLER_BYTE3;
|
||||
|
||||
::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, readText, DATA_FRAME_LENGTH_BYTES);
|
||||
|
||||
data.setSeq(seqNo);
|
||||
data.setData(buffer, DV_FRAME_LENGTH_BYTES);
|
||||
sent++;
|
||||
#if defined(LOOPBACK)
|
||||
writeData(data);
|
||||
#else
|
||||
m_handler->process(data, DIR_INCOMING, AS_DRATS);
|
||||
#endif
|
||||
}
|
||||
|
||||
seqNo++;
|
||||
if (seqNo == 21U)
|
||||
seqNo = 0U;
|
||||
|
||||
if (seqNo == 0U)
|
||||
::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, DATA_SYNC_BYTES, DATA_FRAME_LENGTH_BYTES);
|
||||
else
|
||||
::memcpy(buffer + VOICE_FRAME_LENGTH_BYTES, NULL_SLOW_DATA_BYTES, DATA_FRAME_LENGTH_BYTES);
|
||||
|
||||
data.setData(buffer, DV_FRAME_LENGTH_BYTES);
|
||||
data.setSeq(seqNo);
|
||||
data.setEnd(true);
|
||||
sent++;
|
||||
#if defined(LOOPBACK)
|
||||
writeData(data);
|
||||
#else
|
||||
m_handler->process(data, DIR_INCOMING, AS_DRATS);
|
||||
#endif
|
||||
m_readLength = 0U;
|
||||
m_readPos = 0U;
|
||||
m_readEnd = false;
|
||||
sending = false;
|
||||
sent = 0U;
|
||||
}
|
||||
|
||||
seqNo++;
|
||||
if (seqNo == 21U)
|
||||
seqNo = 0U;
|
||||
}
|
||||
}
|
||||
|
||||
// 50ms
|
||||
Sleep(50UL);
|
||||
}
|
||||
|
||||
if (m_socket != NULL)
|
||||
m_socket->stop();
|
||||
#ifndef DEBUG_DSTARGW
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
std::string message(e.what());
|
||||
CLog::logError("Exception raised in the D-RATS Server thread - \"%s\""), message.c_str();
|
||||
}
|
||||
catch (...) {
|
||||
CLog::logError("Unknown exception raised in the D-RATS Server thread");
|
||||
}
|
||||
#endif
|
||||
|
||||
CLog::logInfo("Stopping the D-RATS Server thread for %s", m_callsign.c_str());
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CDRATSServer::close()
|
||||
{
|
||||
m_stopped = true;
|
||||
|
||||
Wait();
|
||||
}
|
||||
|
||||
void CDRATSServer::serviceSocket()
|
||||
{
|
||||
if (m_socket == NULL) {
|
||||
m_readLength = 0U;
|
||||
m_readPos = 0U;
|
||||
m_readEnd = false;
|
||||
return;
|
||||
}
|
||||
|
||||
int len = m_socket->read(m_readBuffer + m_readLength, BUFFER_LENGTH - m_readLength, 0U);
|
||||
if (len > 0) {
|
||||
m_readLength += len;
|
||||
|
||||
if (!m_readEnd) {
|
||||
// To allow strstr() to run correctly
|
||||
m_readBuffer[m_readLength] = 0x00U;
|
||||
|
||||
if (::strstr((char*)m_readBuffer, "[EOB]") != NULL) {
|
||||
CUtils::dump("To RF", m_readBuffer, m_readLength);
|
||||
m_readEnd = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2011,2012 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 DRATSServer_H
|
||||
#define DRATSServer_H
|
||||
|
||||
#include "TCPReaderWriterServer.h"
|
||||
#include "RepeaterCallback.h"
|
||||
#include "HeaderData.h"
|
||||
#include "AMBEData.h"
|
||||
#include "Defs.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class CDRATSServer : public CThread {
|
||||
public:
|
||||
CDRATSServer(const std::string& address, unsigned int port, const std::string& callsign, IRepeaterCallback* handler);
|
||||
virtual ~CDRATSServer();
|
||||
|
||||
virtual bool open();
|
||||
|
||||
virtual void writeHeader(const CHeaderData& header);
|
||||
virtual void writeData(const CAMBEData& data);
|
||||
virtual void writeEnd();
|
||||
|
||||
virtual void close();
|
||||
|
||||
virtual void* Entry();
|
||||
|
||||
private:
|
||||
std::string m_address;
|
||||
unsigned int m_port;
|
||||
std::string m_callsign;
|
||||
IRepeaterCallback* m_handler;
|
||||
CTCPReaderWriterServer* m_socket;
|
||||
bool m_stopped;
|
||||
SLOWDATA_STATE m_readState;
|
||||
unsigned char* m_readBuffer;
|
||||
unsigned int m_readLength;
|
||||
unsigned int m_readPos;
|
||||
bool m_readEnd;
|
||||
unsigned char* m_writeText;
|
||||
SLOWDATA_STATE m_writeState;
|
||||
unsigned char* m_writeBuffer;
|
||||
unsigned int m_writeLength;
|
||||
|
||||
void serviceSocket();
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Reference in new issue