Use APRS Gateway for APRS-IS access.

This commit is contained in:
Jonathan Naylor 2020-06-01 11:35:02 +01:00
parent fc08cf95f3
commit 166f40b078
15 changed files with 71 additions and 744 deletions

View File

@ -23,8 +23,7 @@
#include <cstring>
#include <cmath>
CAPRSWriter::CAPRSWriter(const std::string& callsign, const std::string& suffix, const std::string& password, const std::string& address, unsigned int port) :
m_thread(NULL),
CAPRSWriter::CAPRSWriter(const std::string& callsign, const std::string& suffix, const std::string& address, unsigned int port) :
m_enabled(false),
m_idTimer(1000U),
m_callsign(callsign),
@ -34,12 +33,14 @@ m_latitude(0.0F),
m_longitude(0.0F),
m_height(0),
m_desc(),
m_aprsAddress(),
m_aprsPort(port),
m_aprsSocket(),
m_mobileGPSAddress(),
m_mobileGPSPort(0U),
m_socket(NULL)
m_mobileSocket(NULL)
{
assert(!callsign.empty());
assert(!password.empty());
assert(!address.empty());
assert(port > 0U);
@ -48,7 +49,7 @@ m_socket(NULL)
m_callsign.append(suffix.substr(0U, 1U));
}
m_thread = new CAPRSWriterThread(m_callsign, password, address, port);
m_aprsAddress = CUDPSocket::lookup(address);
}
CAPRSWriter::~CAPRSWriter()
@ -77,16 +78,16 @@ void CAPRSWriter::setMobileLocation(const std::string& address, unsigned int por
m_mobileGPSAddress = CUDPSocket::lookup(address);
m_mobileGPSPort = port;
m_socket = new CUDPSocket;
m_mobileSocket = new CUDPSocket;
}
bool CAPRSWriter::open()
{
if (m_socket != NULL) {
bool ret = m_socket->open();
if (m_mobileSocket != NULL) {
bool ret = m_mobileSocket->open();
if (!ret) {
delete m_socket;
m_socket = NULL;
delete m_mobileSocket;
m_mobileSocket = NULL;
return false;
}
@ -98,23 +99,21 @@ bool CAPRSWriter::open()
m_idTimer.start();
return m_thread->start();
return m_aprsSocket.open();
}
void CAPRSWriter::write(const char* data)
{
assert(data != NULL);
m_thread->write(data);
m_aprsSocket.write((unsigned char*)data, (unsigned int)::strlen(data), m_aprsAddress, m_aprsPort);
}
void CAPRSWriter::clock(unsigned int ms)
{
m_idTimer.clock(ms);
m_thread->clock(ms);
if (m_socket != NULL) {
if (m_mobileSocket != NULL) {
if (m_idTimer.hasExpired()) {
pollGPS();
m_idTimer.start();
@ -131,26 +130,23 @@ void CAPRSWriter::clock(unsigned int ms)
void CAPRSWriter::close()
{
if (m_socket != NULL) {
m_socket->close();
delete m_socket;
}
m_aprsSocket.close();
m_thread->stop();
if (m_mobileSocket != NULL) {
m_mobileSocket->close();
delete m_mobileSocket;
}
}
bool CAPRSWriter::pollGPS()
{
assert(m_socket != NULL);
assert(m_mobileSocket != NULL);
return m_socket->write((unsigned char*)"NXDNGateway", 11U, m_mobileGPSAddress, m_mobileGPSPort);
return m_mobileSocket->write((unsigned char*)"NXDNGateway", 11U, m_mobileGPSAddress, m_mobileGPSPort);
}
void CAPRSWriter::sendIdFrameFixed()
{
if (!m_thread->isConnected())
return;
// Default values aren't passed on
if (m_latitude == 0.0F && m_longitude == 0.0F)
return;
@ -201,13 +197,13 @@ void CAPRSWriter::sendIdFrameFixed()
server.append("S");
char output[500U];
::sprintf(output, "%s>APDG04,TCPIP*,qAC,%s:!%s%cD%s%c&/A=%06.0f%s %s",
::sprintf(output, "%s>APDG04,TCPIP*,qAC,%s:!%s%cD%s%c&/A=%06.0f%s %s\r\n",
m_callsign.c_str(), server.c_str(),
lat, (m_latitude < 0.0F) ? 'S' : 'N',
lon, (m_longitude < 0.0F) ? 'W' : 'E',
float(m_height) * 3.28F, band, desc);
m_thread->write(output);
write(output);
}
void CAPRSWriter::sendIdFrameMobile()
@ -216,13 +212,10 @@ void CAPRSWriter::sendIdFrameMobile()
unsigned char buffer[200U];
in_addr address;
unsigned int port;
int ret = m_socket->read(buffer, 200U, address, port);
int ret = m_mobileSocket->read(buffer, 200U, address, port);
if (ret <= 0)
return;
if (!m_thread->isConnected())
return;
buffer[ret] = '\0';
// Parse the GPS data
@ -297,8 +290,7 @@ void CAPRSWriter::sendIdFrameMobile()
::sprintf(output + ::strlen(output), "%03.0f/%03.0f", rawBearing, rawVelocity * 0.539957F);
}
::sprintf(output + ::strlen(output), "/A=%06.0f%s %s", float(rawAltitude) * 3.28F, band, desc);
::sprintf(output + ::strlen(output), "/A=%06.0f%s %s\r\n", float(rawAltitude) * 3.28F, band, desc);
m_thread->write(output);
write(output);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2010,2011,2012,2016,2017,2018 by Jonathan Naylor G4KLX
* Copyright (C) 2010,2011,2012,2016,2017,2018,2020 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
@ -19,7 +19,6 @@
#ifndef APRSWriter_H
#define APRSWriter_H
#include "APRSWriterThread.h"
#include "UDPSocket.h"
#include "Timer.h"
@ -40,7 +39,7 @@
class CAPRSWriter {
public:
CAPRSWriter(const std::string& callsign, const std::string& suffix, const std::string& password, const std::string& address, unsigned int port);
CAPRSWriter(const std::string& callsign, const std::string& suffix, const std::string& address, unsigned int port);
~CAPRSWriter();
bool open();
@ -58,19 +57,21 @@ public:
void close();
private:
CAPRSWriterThread* m_thread;
bool m_enabled;
CTimer m_idTimer;
std::string m_callsign;
unsigned int m_txFrequency;
unsigned int m_rxFrequency;
float m_latitude;
float m_longitude;
int m_height;
std::string m_desc;
in_addr m_mobileGPSAddress;
unsigned int m_mobileGPSPort;
CUDPSocket* m_socket;
bool m_enabled;
CTimer m_idTimer;
std::string m_callsign;
unsigned int m_txFrequency;
unsigned int m_rxFrequency;
float m_latitude;
float m_longitude;
int m_height;
std::string m_desc;
in_addr m_aprsAddress;
unsigned int m_aprsPort;
CUDPSocket m_aprsSocket;
in_addr m_mobileGPSAddress;
unsigned int m_mobileGPSPort;
CUDPSocket* m_mobileSocket;
bool pollGPS();
void sendIdFrameFixed();

View File

@ -1,279 +0,0 @@
/*
* Copyright (C) 2010-2014,2016,2020 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 "APRSWriterThread.h"
#include "Utils.h"
#include "Log.h"
#include <algorithm>
#include <functional>
#include <cctype>
#include <cstdint>
#include <cstdio>
#include <cassert>
// #define DUMP_TX
const unsigned int CALLSIGN_LENGTH = 8U;
const unsigned int APRS_TIMEOUT = 10U;
CAPRSWriterThread::CAPRSWriterThread(const std::string& callsign, const std::string& password, const std::string& address, unsigned int port) :
CThread(),
m_username(callsign),
m_password(password),
m_socket(address, port),
m_queue(20U, "APRS Queue"),
m_exit(false),
m_connected(false),
m_reconnectTimer(1000U),
m_tries(1U),
m_APRSReadCallback(NULL),
m_filter(),
m_clientName("YSFGateway")
{
assert(!callsign.empty());
assert(!password.empty());
assert(!address.empty());
assert(port > 0U);
m_username.resize(CALLSIGN_LENGTH, ' ');
m_username.erase(std::find_if(m_username.rbegin(), m_username.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), m_username.end());
std::transform(m_username.begin(), m_username.end(), m_username.begin(), ::toupper);
}
CAPRSWriterThread::CAPRSWriterThread(const std::string& callsign, const std::string& password, const std::string& address, unsigned int port, const std::string& filter, const std::string& clientName) :
CThread(),
m_username(callsign),
m_password(password),
m_socket(address, port),
m_queue(20U, "APRS Queue"),
m_exit(false),
m_connected(false),
m_reconnectTimer(1000U),
m_tries(1U),
m_APRSReadCallback(NULL),
m_filter(filter),
m_clientName(clientName)
{
assert(!callsign.empty());
assert(!password.empty());
assert(!address.empty());
assert(port > 0U);
m_username.resize(CALLSIGN_LENGTH, ' ');
m_username.erase(std::find_if(m_username.rbegin(), m_username.rend(), std::not1(std::ptr_fun<int, int>(std::isspace))).base(), m_username.end());
std::transform(m_username.begin(), m_username.end(), m_username.begin(), ::toupper);
}
CAPRSWriterThread::~CAPRSWriterThread()
{
m_username.clear();
}
bool CAPRSWriterThread::start()
{
run();
return true;
}
void CAPRSWriterThread::entry()
{
LogMessage("Starting the APRS Writer thread");
m_connected = connect();
if (!m_connected) {
LogError("Connect attempt to the APRS server has failed");
startReconnectionTimer();
}
try {
while (!m_exit) {
if (!m_connected) {
if (m_reconnectTimer.isRunning() && m_reconnectTimer.hasExpired()) {
m_reconnectTimer.stop();
m_connected = connect();
if (!m_connected) {
LogError("Reconnect attempt to the APRS server has failed");
startReconnectionTimer();
}
}
}
if (m_connected) {
m_tries = 0U;
if (!m_queue.isEmpty()){
char* p = NULL;
m_queue.getData(&p, 1U);
LogMessage("APRS ==> %s", p);
::strcat(p, "\r\n");
bool ret = m_socket.write((unsigned char*)p, (unsigned int)::strlen(p));
if (!ret) {
m_connected = false;
m_socket.close();
LogError("Connection to the APRS thread has failed");
startReconnectionTimer();
}
delete[] p;
}
{
std::string line;
int length = m_socket.readLine(line, APRS_TIMEOUT);
if (length < 0) {
m_connected = false;
m_socket.close();
LogError("Error when reading from the APRS server");
startReconnectionTimer();
}
if(length > 0 && line.at(0U) != '#'//check if we have something and if that something is an APRS frame
&& m_APRSReadCallback != NULL)//do we have someone wanting an APRS Frame?
{
//wxLogMessage(wxT("Received APRS Frame : ") + line);
m_APRSReadCallback(std::string(line));
}
}
}
}
if (m_connected)
m_socket.close();
while (!m_queue.isEmpty()) {
char* p = NULL;
m_queue.getData(&p, 1U);
delete[] p;
}
}
catch (std::exception& e) {
LogError("Exception raised in the APRS Writer thread - \"%s\"", e.what());
}
catch (...) {
LogError("Unknown exception raised in the APRS Writer thread");
}
LogMessage("Stopping the APRS Writer thread");
}
void CAPRSWriterThread::setReadAPRSCallback(ReadAPRSFrameCallback cb)
{
m_APRSReadCallback = cb;
}
void CAPRSWriterThread::write(const char* data)
{
assert(data != NULL);
if (!m_connected)
return;
unsigned int len = (unsigned int)::strlen(data);
char* p = new char[len + 5U];
::strcpy(p, data);
m_queue.addData(&p, 1U);
}
bool CAPRSWriterThread::isConnected() const
{
return m_connected;
}
void CAPRSWriterThread::stop()
{
m_exit = true;
wait();
}
void CAPRSWriterThread::clock(unsigned int ms)
{
m_reconnectTimer.clock(ms);
}
bool CAPRSWriterThread::connect()
{
bool ret = m_socket.open();
if (!ret)
return false;
//wait for lgin banner
int length;
std::string serverResponse;
length = m_socket.readLine(serverResponse, APRS_TIMEOUT);
if (length == 0) {
LogError("No reply from the APRS server after %u seconds", APRS_TIMEOUT);
m_socket.close();
return false;
}
LogMessage("Received login banner : %s", serverResponse.c_str());
std::string filter(m_filter);
if (filter.length() > 0)
filter.insert(0U, " filter ");
char connectString[200U];
::sprintf(connectString, "user %s pass %s vers %s%s\n", m_username.c_str(), m_password.c_str(), (m_clientName.length() ? m_clientName : "YSFGateway").c_str(), filter.c_str());
ret = m_socket.writeLine(std::string(connectString));
if (!ret) {
m_socket.close();
return false;
}
length = m_socket.readLine(serverResponse, APRS_TIMEOUT);
if (length == 0) {
LogError("No reply from the APRS server after %u seconds", APRS_TIMEOUT);
m_socket.close();
return false;
}
if (length < 0) {
LogError("Error when reading from the APRS server");
m_socket.close();
return false;
}
LogMessage("Response from APRS server: %s", serverResponse.c_str());
LogMessage("Connected to the APRS server");
return true;
}
void CAPRSWriterThread::startReconnectionTimer()
{
// Clamp at a ten minutes reconnect time
m_tries++;
if (m_tries > 10U)
m_tries = 10U;
m_reconnectTimer.setTimeout(m_tries * 60U);
m_reconnectTimer.start();
}

View File

@ -1,68 +0,0 @@
/*
* Copyright (C) 2010,2011,2012,2016,2020 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 APRSWriterThread_H
#define APRSWriterThread_H
#include "TCPSocket.h"
#include "RingBuffer.h"
#include "Timer.h"
#include "Thread.h"
#include <string>
typedef void (*ReadAPRSFrameCallback)(const std::string&);
class CAPRSWriterThread : public CThread {
public:
CAPRSWriterThread(const std::string& callsign, const std::string& password, const std::string& address, unsigned int port);
CAPRSWriterThread(const std::string& callsign, const std::string& password, const std::string& address, unsigned int port, const std::string& filter, const std::string& clientName);
virtual ~CAPRSWriterThread();
virtual bool start();
virtual bool isConnected() const;
virtual void write(const char* data);
virtual void entry();
virtual void stop();
void setReadAPRSCallback(ReadAPRSFrameCallback cb);
void clock(unsigned int ms);
private:
std::string m_username;
std::string m_password;
CTCPSocket m_socket;
CRingBuffer<char*> m_queue;
bool m_exit;
bool m_connected;
CTimer m_reconnectTimer;
unsigned int m_tries;
ReadAPRSFrameCallback m_APRSReadCallback;
std::string m_filter;
std::string m_clientName;
bool connect();
void startReconnectionTimer();
};
#endif

View File

@ -33,7 +33,7 @@ enum SECTION {
SECTION_ID_LOOKUP,
SECTION_VOICE,
SECTION_LOG,
SECTION_APRS_FI,
SECTION_APRS,
SECTION_NETWORK,
SECTION_MOBILE_GPS,
SECTION_REMOTE_COMMANDS
@ -65,9 +65,8 @@ m_voiceDirectory(),
m_logFilePath(),
m_logFileRoot(),
m_aprsEnabled(false),
m_aprsServer(),
m_aprsPort(0U),
m_aprsPassword(),
m_aprsAddress("127.0.0.1"),
m_aprsPort(8673U),
m_aprsSuffix(),
m_aprsDescription(),
m_networkPort(0U),
@ -119,8 +118,8 @@ bool CConf::read()
section = SECTION_VOICE;
else if (::strncmp(buffer, "[Log]", 5U) == 0)
section = SECTION_LOG;
else if (::strncmp(buffer, "[aprs.fi]", 9U) == 0)
section = SECTION_APRS_FI;
else if (::strncmp(buffer, "[APRS]", 6U) == 0)
section = SECTION_APRS;
else if (::strncmp(buffer, "[Network]", 9U) == 0)
section = SECTION_NETWORK;
else if (::strncmp(buffer, "[Mobile GPS]", 12U) == 0)
@ -195,15 +194,13 @@ bool CConf::read()
m_logFilePath = value;
else if (::strcmp(key, "FileRoot") == 0)
m_logFileRoot = value;
} else if (section == SECTION_APRS_FI) {
} else if (section == SECTION_APRS) {
if (::strcmp(key, "Enable") == 0)
m_aprsEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Server") == 0)
m_aprsServer = value;
else if (::strcmp(key, "Address") == 0)
m_aprsAddress = value;
else if (::strcmp(key, "Port") == 0)
m_aprsPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "Password") == 0)
m_aprsPassword = value;
else if (::strcmp(key, "Suffix") == 0)
m_aprsSuffix = value;
else if (::strcmp(key, "Description") == 0)
@ -366,9 +363,9 @@ bool CConf::getAPRSEnabled() const
return m_aprsEnabled;
}
std::string CConf::getAPRSServer() const
std::string CConf::getAPRSAddress() const
{
return m_aprsServer;
return m_aprsAddress;
}
unsigned int CConf::getAPRSPort() const
@ -376,11 +373,6 @@ unsigned int CConf::getAPRSPort() const
return m_aprsPort;
}
std::string CConf::getAPRSPassword() const
{
return m_aprsPassword;
}
std::string CConf::getAPRSSuffix() const
{
return m_aprsSuffix;

View File

@ -59,11 +59,10 @@ public:
std::string getVoiceLanguage() const;
std::string getVoiceDirectory() const;
// The aprs.fi section
// The APRS section
bool getAPRSEnabled() const;
std::string getAPRSServer() const;
std::string getAPRSAddress() const;
unsigned int getAPRSPort() const;
std::string getAPRSPassword() const;
std::string getAPRSSuffix() const;
std::string getAPRSDescription() const;
@ -124,9 +123,8 @@ private:
std::string m_logFileRoot;
bool m_aprsEnabled;
std::string m_aprsServer;
std::string m_aprsAddress;
unsigned int m_aprsPort;
std::string m_aprsPassword;
std::string m_aprsSuffix;
std::string m_aprsDescription;

View File

@ -140,10 +140,10 @@ bool CGPSHandler::processIcom()
int bearing = ::atoi(pRMC[8U]);
int speed = ::atoi(pRMC[7U]);
::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07.2lf%s/%08.2lf%sr%03d/%03d Icom IDAS via MMDVM",
::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07.2lf%s/%08.2lf%sr%03d/%03d Icom IDAS via MMDVM\r\n",
source.c_str(), m_callsign.c_str(), latitude, pRMC[4U], longitude, pRMC[6U], bearing, speed);
} else {
::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07.2lf%s/%08.2lf%sr Icom IDAS via MMDVM",
::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%07.2lf%s/%08.2lf%sr Icom IDAS via MMDVM\r\n",
source.c_str(), m_callsign.c_str(), latitude, pRMC[4U], longitude, pRMC[6U]);
}
@ -239,10 +239,10 @@ bool CGPSHandler::processKenwood()
char output[300U];
if (course != 0xFFFFU && speedBefore != 0x3FFU && speedAfter != 0x0FU) {
::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%04u.%02u%c/%05u.%02u%cr%03d/%03d Kenwood NEXEDGE via MMDVM",
::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%04u.%02u%c/%05u.%02u%cr%03d/%03d Kenwood NEXEDGE via MMDVM\r\n",
source.c_str(), m_callsign.c_str(), latBefore, latAfter / 100U, north, lonBefore, lonAfter / 100U, east, course / 10U, speedBefore);
} else {
::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%04u.%02u%c/%05u.%02u%cr Kenwood NEXEDGE via MMDVM",
::sprintf(output, "%s>APDPRS,NXDN*,qAR,%s:!%04u.%02u%c/%05u.%02u%cr Kenwood NEXEDGE via MMDVM\r\n",
source.c_str(), m_callsign.c_str(), latBefore, latAfter / 100U, north, lonBefore, lonAfter / 100U, east);
}

View File

@ -4,8 +4,8 @@ CFLAGS = -g -O3 -Wall -std=c++0x -pthread
LIBS = -lpthread
LDFLAGS = -g
OBJECTS = APRSWriter.o APRSWriterThread.o Conf.o GPSHandler.o IcomNetwork.o KenwoodNetwork.o Log.o Mutex.o NXDNCRC.o NXDNGateway.o NXDNLookup.o NXDNNetwork.o \
Reflectors.o RptNetwork.o StopWatch.o TCPSocket.o Thread.o Timer.o UDPSocket.o Utils.o Voice.o
OBJECTS = APRSWriter.o Conf.o GPSHandler.o IcomNetwork.o KenwoodNetwork.o Log.o Mutex.o NXDNCRC.o NXDNGateway.o NXDNLookup.o NXDNNetwork.o \
Reflectors.o RptNetwork.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o Voice.o
all: NXDNGateway
@ -17,4 +17,4 @@ NXDNGateway: $(OBJECTS)
clean:
$(RM) NXDNGateway *.o *.d *.bak *~

View File

@ -591,12 +591,11 @@ void CNXDNGateway::createGPS()
std::string callsign = m_conf.getCallsign();
std::string rptSuffix = m_conf.getSuffix();
std::string hostname = m_conf.getAPRSServer();
std::string address = m_conf.getAPRSAddress();
unsigned int port = m_conf.getAPRSPort();
std::string password = m_conf.getAPRSPassword();
std::string suffix = m_conf.getAPRSSuffix();
m_writer = new CAPRSWriter(callsign, rptSuffix, password, hostname, port);
m_writer = new CAPRSWriter(callsign, rptSuffix, address, port);
unsigned int txFrequency = m_conf.getTxFrequency();
unsigned int rxFrequency = m_conf.getRxFrequency();

View File

@ -16,7 +16,7 @@ RptProtocol=Icom
RptAddress=127.0.0.1
RptPort=14021
LocalPort=14020
Debug=0
Debug=1
Daemon=1
[Info]
@ -34,14 +34,12 @@ Enabled=1
Language=en_GB
Directory=./Audio
[aprs.fi]
[APRS]
Enable=0
# Server=noam.aprs2.net
Server=euro.aprs2.net
Port=14580
Password=9999
Description=APRS Description
Address=127.0.0.1
Port=8673
Suffix=N
Description=APRS Description
[Id Lookup]
Name=NXDN.csv

View File

@ -147,7 +147,6 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="APRSWriter.h" />
<ClInclude Include="APRSWriterThread.h" />
<ClInclude Include="Conf.h" />
<ClInclude Include="GPSHandler.h" />
<ClInclude Include="IcomNetwork.h" />
@ -162,7 +161,6 @@
<ClInclude Include="RingBuffer.h" />
<ClInclude Include="RptNetwork.h" />
<ClInclude Include="StopWatch.h" />
<ClInclude Include="TCPSocket.h" />
<ClInclude Include="Thread.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="UDPSocket.h" />
@ -172,7 +170,6 @@
</ItemGroup>
<ItemGroup>
<ClCompile Include="APRSWriter.cpp" />
<ClCompile Include="APRSWriterThread.cpp" />
<ClCompile Include="Conf.cpp" />
<ClCompile Include="GPSHandler.cpp" />
<ClCompile Include="IcomNetwork.cpp" />
@ -186,7 +183,6 @@
<ClCompile Include="Reflectors.cpp" />
<ClCompile Include="RptNetwork.cpp" />
<ClCompile Include="StopWatch.cpp" />
<ClCompile Include="TCPSocket.cpp" />
<ClCompile Include="Thread.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="UDPSocket.cpp" />

View File

@ -62,12 +62,6 @@
<ClInclude Include="APRSWriter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="APRSWriterThread.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="TCPSocket.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="RingBuffer.h">
<Filter>Header Files</Filter>
</ClInclude>
@ -130,12 +124,6 @@
<ClCompile Include="APRSWriter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="APRSWriterThread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="TCPSocket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GPSHandler.cpp">
<Filter>Source Files</Filter>
</ClCompile>

View File

@ -1,232 +0,0 @@
/*
* Copyright (C) 2010-2013,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 "TCPSocket.h"
#include "UDPSocket.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
#if defined(_WIN32) || defined(_WIN64)
typedef int ssize_t;
#else
#include <cerrno>
#endif
CTCPSocket::CTCPSocket(const std::string& address, unsigned int port) :
m_address(address),
m_port(port),
m_fd(-1)
{
assert(!address.empty());
assert(port > 0U);
#if defined(_WIN32) || defined(_WIN64)
WSAData data;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
if (wsaRet != 0)
LogError("Error from WSAStartup");
#endif
}
CTCPSocket::~CTCPSocket()
{
#if defined(_WIN32) || defined(_WIN64)
::WSACleanup();
#endif
}
bool CTCPSocket::open()
{
if (m_fd != -1)
return true;
if (m_address.empty() || m_port == 0U)
return false;
m_fd = ::socket(PF_INET, SOCK_STREAM, 0);
if (m_fd < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot create the TCP client socket, err=%d", ::GetLastError());
#else
LogError("Cannot create the TCP client socket, err=%d", errno);
#endif
return false;
}
struct sockaddr_in addr;
::memset(&addr, 0x00, sizeof(struct sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(m_port);
addr.sin_addr = CUDPSocket::lookup(m_address);
if (addr.sin_addr.s_addr == INADDR_NONE) {
close();
return false;
}
if (::connect(m_fd, (sockaddr*)&addr, sizeof(struct sockaddr_in)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot connect the TCP client socket, err=%d", ::GetLastError());
#else
LogError("Cannot connect the TCP client socket, err=%d", errno);
#endif
close();
return false;
}
int noDelay = 1;
if (::setsockopt(m_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&noDelay, sizeof(noDelay)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot set the TCP client socket option, err=%d", ::GetLastError());
#else
LogError("Cannot set the TCP client socket option, err=%d", errno);
#endif
close();
return false;
}
return true;
}
int CTCPSocket::read(unsigned char* buffer, unsigned int length, unsigned int secs, unsigned int msecs)
{
assert(buffer != NULL);
assert(length > 0U);
assert(m_fd != -1);
// Check that the recv() won't block
fd_set readFds;
FD_ZERO(&readFds);
#if defined(_WIN32) || defined(_WIN64)
FD_SET((unsigned int)m_fd, &readFds);
#else
FD_SET(m_fd, &readFds);
#endif
// Return after timeout
timeval tv;
tv.tv_sec = secs;
tv.tv_usec = msecs * 1000;
int ret = ::select(m_fd + 1, &readFds, NULL, NULL, &tv);
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from TCP client select, err=%d", ::GetLastError());
#else
LogError("Error returned from TCP client select, err=%d", errno);
#endif
return -1;
}
#if defined(_WIN32) || defined(_WIN64)
if (!FD_ISSET((unsigned int)m_fd, &readFds))
return 0;
#else
if (!FD_ISSET(m_fd, &readFds))
return 0;
#endif
ssize_t len = ::recv(m_fd, (char*)buffer, length, 0);
if (len == 0) {
return -2;
} else if (len < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from recv, err=%d", ::GetLastError());
#else
LogError("Error returned from recv, err=%d", errno);
#endif
return -1;
}
return len;
}
int CTCPSocket::readLine(std::string& line, unsigned int secs)
{
// Maybe there is a better way to do this like reading blocks, pushing them for later calls
// Nevermind, we'll read one char at a time for the time being.
int resultCode;
int len = 0;
line.clear();
char c[2U];
c[1U] = 0x00U;
do
{
resultCode = read((unsigned char*)c, 1U, secs);
if (resultCode == 1){
line.append(c);
len++;
}
} while (c[0U] != '\n' && resultCode == 1);
return resultCode <= 0 ? resultCode : len;
}
bool CTCPSocket::write(const unsigned char* buffer, unsigned int length)
{
assert(buffer != NULL);
assert(length > 0U);
assert(m_fd != -1);
ssize_t ret = ::send(m_fd, (char *)buffer, length, 0);
if (ret != ssize_t(length)) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from send, err=%d", ::GetLastError());
#else
LogError("Error returned from send, err=%d", errno);
#endif
return false;
}
return true;
}
bool CTCPSocket::writeLine(const std::string& line)
{
std::string lineCopy(line);
if (lineCopy.length() > 0 && lineCopy.at(lineCopy.length() - 1) != '\n')
lineCopy.append("\n");
//stupidly write one char after the other
size_t len = lineCopy.length();
bool result = true;
for (size_t i = 0U; i < len && result; i++){
unsigned char c = lineCopy.at(i);
result = write(&c , 1);
}
return result;
}
void CTCPSocket::close()
{
if (m_fd != -1) {
#if defined(_WIN32) || defined(_WIN64)
::closesocket(m_fd);
#else
::close(m_fd);
#endif
m_fd = -1;
}
}

View File

@ -1,58 +0,0 @@
/*
* Copyright (C) 2010,2011,2012,2013,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 TCPSocket_H
#define TCPSocket_H
#if !defined(_WIN32) && !defined(_WIN64)
#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>
#else
#include <winsock.h>
#endif
#include <string>
class CTCPSocket {
public:
CTCPSocket(const std::string& address, unsigned int port);
~CTCPSocket();
bool open();
int read(unsigned char* buffer, unsigned int length, unsigned int secs, unsigned int msecs = 0U);
int readLine(std::string& line, unsigned int secs);
bool write(const unsigned char* buffer, unsigned int length);
bool writeLine(const std::string& line);
void close();
private:
std::string m_address;
unsigned short m_port;
int m_fd;
};
#endif

View File

@ -19,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20200519";
const char* VERSION = "20200601";
#endif