1
0
Fork 0

Compare commits

...

82 commits

Author SHA1 Message Date
Jonathan Naylor
aecc34ee64 Allow YSFClients to compile under Windows. 2024-04-22 13:15:25 +01:00
Jonathan Naylor
dfe50c4245 Simplify the UDP socket handling. 2024-01-29 15:44:33 +00:00
Jonathan Naylor
f7f94b3ca1
Merge pull request from W0CHP/master
Reverses PR , which broke FCS Remote/Dynamic linking
2023-10-04 17:45:18 +01:00
Chipster
bf6577e2ca Reverses PR , which broke FCS Remote/Dynamic linking 2023-10-04 11:12:45 -05:00
Jonathan Naylor
7cbac3bdab
Merge pull request from iu5jae/master
Update YSFGateway.cpp
2023-07-28 16:50:30 +01:00
Antonio Matraia
95d83fd9ce Requested changes
Changed indentation from space to tab, used false instead of 0 for boolean variables.
2023-07-26 22:02:47 +02:00
Antonio Matraia
2530199d54 Possibility of inserting startup reflector as ID 2023-07-23 20:50:05 +02:00
Antonio Matraia
351e6c2d59 added YSFDirect
Added management of the YSFBMGateway gateway using the id 00006
2023-07-21 00:41:19 +02:00
Antonio Matraia
2e303e55e6 updated YSFGateway
Remote control management compatible with pistar uk.

If the requested room does not exist, the gw remains on the previously set one
2023-07-08 20:57:03 +02:00
Antonio Matraia
daef16c145 Update YSFGateway.cpp
fixed the "segmentation fault" error in case a non-existent room is requested
2023-06-30 22:09:20 +02:00
Jonathan Naylor
3409e45d83
Merge pull request from f1rmb/f1rmb_gpsd_fix_status_check_api_version_2
Take care of GPSd API version about fix.
2023-05-21 12:56:57 +01:00
Daniel Caujolle-Bert
f637ff564f Take care of GPSd API version about fix. 2023-05-21 06:50:10 +02:00
Jonathan Naylor
c027bed0aa
Merge pull request from W0CHP/master
Update sample INI with quoted `Symbol=` value.
2023-05-19 16:20:35 +01:00
Chipster
fd84400bfc Update sample INI with quoted Symbol= value. 2023-05-19 09:57:48 -05:00
Jonathan Naylor
9eb6d3967f Remove the YSF Reflector. 2023-02-23 19:31:28 +00:00
Jonathan Naylor
3731800162
Merge pull request from W0CHP/master 2023-02-17 18:04:17 +00:00
Chipster
098c4fc6b4 Add mode type to APRS string. Make APRS band/offset string a bit more consistent. 2023-02-17 06:20:09 -06:00
Jonathan Naylor
9efe097f0b Update to gpsd 3.2.1 API. 2023-02-13 17:56:44 +00:00
Jonathan Naylor
20096333dd
Merge pull request from W0CHP/master 2023-02-13 15:57:00 +00:00
Chipster
2d92907b96
Merge branch 'g4klx:master' into master 2023-02-13 09:33:29 -06:00
Chipster
b743f1a6e8 For DGId and YSF Gatweays, add missing symbol func. in offset/no-offset cconditions 2023-02-13 09:28:41 -06:00
Jonathan Naylor
b0f3f70f77
Merge pull request from W0CHP/master 2023-02-13 15:09:55 +00:00
Chipster
e3dd9f5321 Add APRS Symbol option (based on my PR https://github.com/g4klx/DMRGateway/pull/122) 2023-02-13 06:59:27 -06:00
Chipster
471d031a08 Add APRS Symbol option (based on my PR https://github.com/g4klx/DMRGateway/pull/122) 2023-02-13 06:43:30 -06:00
Jonathan Naylor
22a0b9ae28
Merge pull request from dg9ffm/patch-33
Update FCSRooms.txt
2023-02-06 20:16:23 +00:00
dg9ffm
df5b0346f2
Update FCSRooms.txt
Update FCSRooms.txt
2023-02-05 22:32:47 +01:00
Jonathan Naylor
1fab3dbd61
Merge pull request from jcid2023/patch-1 2023-01-19 20:36:12 +00:00
jcid2023
d58edef727
Update YSFHosts.txt
Host update and addition.

Thanks.
2023-01-19 14:29:42 -05:00
Jonathan Naylor
ec16283b5c
Merge pull request from DO1OLI/master
Show FCS receive debug only when debug is active
2022-11-16 19:22:30 +00:00
DO1OLI
9bccf4c2b6 added .vscode to .gitignore 2022-11-05 11:09:09 +01:00
Oliver
cdfc8c9fad Show FCS receive debug only when debug is active 2022-07-16 11:02:52 +02:00
Jonathan Naylor
1015f3d55f Once linked, pass all traffic to the room/reflector, regardless of the
DG-Id.
2022-06-03 17:06:07 +01:00
Jonathan Naylor
1344f545e9
Merge pull request from f1rmb/network_status
Add new remote command:
2022-01-24 07:10:37 +00:00
Daniel Caujolle-Bert
227b3a9b2f Add new remote command:
- status: displays network connection status (n/a, conn, disc), just like DMRGateway/MMDVMHost.
 - host: display connected host, or NONE if disconnected (surrounded with double quotes).
2022-01-24 02:21:34 +00:00
Jonathan Naylor
267b8e0809
Merge pull request from f1rmb/fix_remote_commands 2022-01-20 12:22:20 +00:00
Daniel Caujolle-Bert
3af8708977
Expect a space between LinkYSF/LinkFCS and its argument. 2022-01-20 13:16:20 +01:00
Jonathan Naylor
15247d0c47
Merge pull request from W0CHP/master 2022-01-07 15:40:22 +00:00
Chipster
e792cab308 Added git version string to VERSION, etc. (GitVersion.h); consistent with other clients.
Added '--version|-v' to YSFParrot, as well as GitVersion.h facility
Added GitVersion.h to gitignore
2022-01-07 09:14:33 -06:00
Chipster
c05a7f0205 * Added git version string to VERSION, etc. (GitVersion.h); consistent with other clients.
* Added '--version|-v' to YSFParrot, as well as GitVersion.h facility
2022-01-07 08:35:27 -06:00
Jonathan Naylor
d3ee33ab0f
Merge pull request from f1rmb/fix_remote_commands 2022-01-05 09:26:00 +00:00
Daniel Caujolle-Bert
0e48d79162 Apply left trim to remote command argument (otherwise string compare are failing); 2022-01-05 08:54:06 +00:00
Jonathan Naylor
7c517f8476 Update the README 2021-12-13 10:38:16 +00:00
Jonathan Naylor
c5d76be1cc
Merge pull request from dg9ffm/patch-32
Update FCSRooms.txt
2021-12-12 20:01:23 +00:00
dg9ffm
9634817ddf
Update FCSRooms.txt
Update FCSRooms.txt
2021-12-05 11:23:58 +01:00
Jonathan Naylor
6cea7a63bc
Merge pull request from narspt/patch-5
fix undesired connect packet passthrough
2021-12-03 07:36:12 +00:00
narspt
90233f50e2
fix undesired connect packet passthrough 2021-12-03 01:23:51 +00:00
Jonathan Naylor
1147745c48
Merge pull request from narspt/patch-4 2021-11-29 06:34:26 +00:00
narspt
301e030b4d
update processWiresX return type definition 2021-11-29 01:47:21 +00:00
narspt
54ae27d63b
fix wiresx cmd passthrough happening even disabled 2021-11-29 01:43:34 +00:00
Jonathan Naylor
1456810fa9 Make FCS rooms numbering dynamic. 2021-11-08 20:16:31 +00:00
Jonathan Naylor
f0868dd4ba Update YSFHosts.txt 2021-10-25 18:49:01 +01:00
Jonathan Naylor
d152dd1074 Fix compiler warnings 2021-10-25 18:03:19 +01:00
Jonathan Naylor
e68f88e8dc
Merge pull request from dg9ffm/patch-31
Update FCSRooms.txt
2021-09-29 23:32:54 +01:00
dg9ffm
08bb6c2734
Update FCSRooms.txt
Add new FCS284 (YCS284) for Bulgaria
Add new FCS505 (YCS505) for Australia
2021-09-29 23:37:16 +02:00
Jonathan Naylor
20488044b1
Merge pull request from dg9ffm/patch-30
Update FCSRooms.txt
2021-09-27 21:37:58 +01:00
dg9ffm
3b7ac383db
Update FCSRooms.txt
Add new FCS202 (YCS202) for Greece
2021-09-26 16:49:38 +02:00
Jonathan Naylor
c848b32cce Add FT-5D GPS support for the DGIdGateway. 2021-09-22 21:57:38 +01:00
Jonathan Naylor
04d4c91f7c
Merge pull request from f1rmb/add_yeasu_ft5d_and_missing_transceivers
Add FT-5R to the list of supported radios + icon
2021-09-22 21:53:35 +01:00
Daniel Caujolle-Bert
dee62db7cd Add FT-5R to the list of supported radios + icon
Add non-default APRS icon for the FTM-300D and DR-2X.
2021-09-22 19:59:30 +01:00
Jonathan Naylor
3a99410248 Fix the IP display bug. 2021-08-24 18:56:59 +01:00
Jonathan Naylor
8167158f87 Fix a memory corruption. 2021-08-24 18:47:32 +01:00
Jonathan Naylor
94fbd66cc3 Update the YSF hosts file. 2021-07-19 21:55:04 +01:00
Jonathan Naylor
264129e57a
Merge pull request from dg9ffm/patch-29
Update FCSRooms.txt
2021-06-27 22:17:32 +01:00
dg9ffm
480601b954
Update FCSRooms.txt
Update FCSRooms.txt
2021-06-26 19:56:04 +02:00
Jonathan Naylor
2d4ffac048
Merge pull request from f1rmb/f1rmb_network_port_datatype
Fix network ports datatype (unsigned int -> unsigned short). UDPSocket: fix old bug using m_port instead of m_port[x].
2021-04-25 09:37:25 +01:00
Daniel Caujolle-Bert
fc76b0f4ab
Fix network ports datatype (unsigned int -> unsigned short). UDPSocket: fix old bug using m_port instead of m_port[x]. 2021-04-25 07:51:51 +02:00
Jonathan Naylor
014cddadd5
Merge pull request from f1rmb/f1rmb_fix_UDPSocket_close
Fix nasty bug in UDPSocket::close().
2021-04-08 18:15:07 +01:00
Daniel Caujolle-Bert
d6ac3b2be5
Fix nasty bug in UDPSocket::close(). 2021-03-31 13:41:35 +02:00
Jonathan Naylor
c9660478c5 Bring the DGId Gateway FCS Rooms file up to date. 2021-03-28 15:31:01 +01:00
Jonathan Naylor
b582905728
Merge pull request from dg9ffm/patch-28 2021-03-13 16:37:16 +00:00
dg9ffm
ca1e857aa6
Update FCSRooms.txt
Add new FCS450 (YCS450) C4FM System Fusion II Multiprotocol Server for Korea
2021-03-13 16:54:18 +01:00
Jonathan Naylor
10dcdbf56f Truncate FCS reflector names to six characters. 2021-02-28 14:18:21 +00:00
Jonathan Naylor
0c02bec9d2 Remove duplicate log messages. 2021-02-15 07:22:50 +00:00
Jonathan Naylor
6c3af73383 Fix bugs and simplify the blocking code. 2021-02-14 19:06:28 +00:00
Jonathan Naylor
d0602d9aa6 Efficiency improvements for the block list checking. 2021-02-14 13:30:06 +00:00
Jonathan Naylor
51fc88f6e4 Use struct sockaddr_storage instead of sockaddr_storage. 2021-02-13 15:35:44 +00:00
Jonathan Naylor
05c627c7d5 Fix the missing IP addresses. 2021-02-13 14:43:54 +00:00
Jonathan Naylor
39f2dc9a0d Actually stop the data if blocked. 2021-02-13 14:07:45 +00:00
Jonathan Naylor
1a81c4a003 Linux cleanup. 2021-02-13 13:29:46 +00:00
Jonathan Naylor
c159461f30 Add a rudimentary block list. 2021-02-13 13:24:27 +00:00
Jonathan Naylor
1d428e921d
Merge pull request from dg9ffm/patch-27
Update FCSRooms.txt
2021-02-06 14:06:05 +00:00
dg9ffm
44cf900ec2
Update FCSRooms.txt
Adding new FCS311 US (YCS311)
2021-02-04 22:11:40 +01:00
91 changed files with 4292 additions and 6140 deletions

2
.gitignore vendored
View file

@ -17,3 +17,5 @@ DGIdGateway/DGIdGateway
YSFGateway/YSFGateway
YSFParrot/YSFParrot
YSFReflector/YSFReflector
GitVersion.h
.vscode

3
DGIdGateway/.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,3 @@
{
"makefile.extensionOutputFolder": "./.vscode"
}

View file

@ -25,7 +25,7 @@
#include <cstring>
#include <cmath>
CAPRSWriter::CAPRSWriter(const std::string& callsign, const std::string& rptSuffix, const std::string& address, unsigned int port, const std::string& suffix, bool debug) :
CAPRSWriter::CAPRSWriter(const std::string& callsign, const std::string& rptSuffix, const std::string& address, unsigned short port, const std::string& suffix, bool debug) :
m_idTimer(1000U),
m_callsign(callsign),
m_debug(debug),
@ -35,6 +35,7 @@ m_latitude(0.0F),
m_longitude(0.0F),
m_height(0),
m_desc(),
m_symbol(),
m_suffix(suffix),
m_aprsAddr(),
m_aprsAddrLen(0U),
@ -63,11 +64,12 @@ CAPRSWriter::~CAPRSWriter()
{
}
void CAPRSWriter::setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc)
void CAPRSWriter::setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc, const std::string& symbol)
{
m_txFrequency = txFrequency;
m_rxFrequency = rxFrequency;
m_desc = desc;
m_symbol = symbol;
}
void CAPRSWriter::setStaticLocation(float latitude, float longitude, int height)
@ -158,12 +160,15 @@ void CAPRSWriter::write(const unsigned char* source, const char* type, unsigned
case 0x24U:
case 0x28U:
case 0x30U:
case 0x33U:
symbol = '[';
break;
case 0x25U:
case 0x29U:
case 0x31U:
symbol = '>';
break;
case 0x20U:
case 0x26U:
symbol = 'r';
break;
@ -229,19 +234,19 @@ void CAPRSWriter::sendIdFrameFixed()
char desc[200U];
if (m_txFrequency != 0U) {
float offset = float(int(m_rxFrequency) - int(m_txFrequency)) / 1000000.0F;
::sprintf(desc, "MMDVM Voice %.5LfMHz %c%.4lfMHz%s%s",
::sprintf(desc, "MMDVM Voice (C4FM) %.5LfMHz %c%.4lfMHz%s%s",
(long double)(m_txFrequency) / 1000000.0F,
offset < 0.0F ? '-' : '+',
::fabs(offset), m_desc.empty() ? "" : ", ", m_desc.c_str());
} else {
::sprintf(desc, "MMDVM Voice%s%s", m_desc.empty() ? "" : ", ", m_desc.c_str());
::sprintf(desc, "MMDVM Voice (C4FM)%s%s", m_desc.empty() ? "" : ", ", m_desc.c_str());
}
const char* band = "4m";
if (m_txFrequency >= 1200000000U)
band = "1.2";
band = "23cm/1.2GHz";
else if (m_txFrequency >= 420000000U)
band = "440";
band = "70cm`";
else if (m_txFrequency >= 144000000U)
band = "2m";
else if (m_txFrequency >= 50000000U)
@ -265,17 +270,21 @@ void CAPRSWriter::sendIdFrameFixed()
::sprintf(lon, "%08.2lf", longitude);
std::string server = m_callsign;
std::string symbol = m_symbol;
size_t pos = server.find_first_of('-');
if (pos == std::string::npos)
server.append("-S");
else
server.append("S");
if (symbol.empty())
symbol.append("D&");
char output[500U];
::sprintf(output, "%s>APDG03,TCPIP*,qAC,%s:!%s%cD%s%c&/A=%06.0f%s %s\r\n",
::sprintf(output, "%s>APDG03,TCPIP*,qAC,%s:!%s%c%c%s%c%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',
lat, (m_latitude < 0.0F) ? 'S' : 'N', symbol[0],
lon, (m_longitude < 0.0F) ? 'W' : 'E', symbol[1],
float(m_height) * 3.28F, band, desc);
if (m_debug)
@ -299,7 +308,11 @@ void CAPRSWriter::sendIdFrameMobile()
#endif
#if GPSD_API_MAJOR_VERSION >= 10
if (m_gpsdData.fix.status != STATUS_FIX)
#else
if (m_gpsdData.status != STATUS_FIX)
#endif
return;
bool latlonSet = (m_gpsdData.set & LATLON_SET) == LATLON_SET;
@ -323,19 +336,19 @@ void CAPRSWriter::sendIdFrameMobile()
char desc[200U];
if (m_txFrequency != 0U) {
float offset = float(int(m_rxFrequency) - int(m_txFrequency)) / 1000000.0F;
::sprintf(desc, "MMDVM Voice %.5LfMHz %c%.4lfMHz%s%s",
::sprintf(desc, "MMDVM Voice (C4FM) %.5LfMHz %c%.4lfMHz%s%s",
(long double)(m_txFrequency) / 1000000.0F,
offset < 0.0F ? '-' : '+',
::fabs(offset), m_desc.empty() ? "" : ", ", m_desc.c_str());
} else {
::sprintf(desc, "MMDVM Voice%s%s", m_desc.empty() ? "" : ", ", m_desc.c_str());
::sprintf(desc, "MMDVM Voice (C4FM)%s%s", m_desc.empty() ? "" : ", ", m_desc.c_str());
}
const char* band = "4m";
if (m_txFrequency >= 1200000000U)
band = "1.2";
band = "23cm/1.2GHz";
else if (m_txFrequency >= 420000000U)
band = "440";
band = "70cm";
else if (m_txFrequency >= 144000000U)
band = "2m";
else if (m_txFrequency >= 50000000U)
@ -359,17 +372,21 @@ void CAPRSWriter::sendIdFrameMobile()
::sprintf(lon, "%08.2lf", longitude);
std::string server = m_callsign;
std::string symbol = m_symbol;
size_t pos = server.find_first_of('-');
if (pos == std::string::npos)
server.append("-S");
else
server.append("S");
if (symbol.empty())
symbol.append("D&");
char output[500U];
::sprintf(output, "%s>APDG03,TCPIP*,qAC,%s:!%s%cD%s%c&",
::sprintf(output, "%s>APDG03,TCPIP*,qAC,%s:!%s%c%c%s%c%c",
m_callsign.c_str(), server.c_str(),
lat, (rawLatitude < 0.0F) ? 'S' : 'N',
lon, (rawLongitude < 0.0F) ? 'W' : 'E');
lat, (rawLatitude < 0.0F) ? 'S' : 'N', symbol[0],
lon, (rawLongitude < 0.0F) ? 'W' : 'E', symbol[1]);
if (bearingSet && velocitySet)
::sprintf(output + ::strlen(output), "%03.0f/%03.0f", rawBearing, rawVelocity * 0.539957F);

View file

@ -42,12 +42,12 @@
class CAPRSWriter {
public:
CAPRSWriter(const std::string& callsign, const std::string& rptSuffix, const std::string& address, unsigned int port, const std::string& suffix, bool debug);
CAPRSWriter(const std::string& callsign, const std::string& rptSuffix, const std::string& address, unsigned short port, const std::string& suffix, bool debug);
~CAPRSWriter();
bool open();
void setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc);
void setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc, const std::string& symbol);
void setStaticLocation(float latitude, float longitude, int height);
@ -69,6 +69,7 @@ private:
float m_longitude;
int m_height;
std::string m_desc;
std::string m_symbol;
std::string m_suffix;
sockaddr_storage m_aprsAddr;
unsigned int m_aprsAddrLen;

View file

@ -71,6 +71,7 @@ m_aprsAddress(),
m_aprsPort(0U),
m_aprsSuffix(),
m_aprsDescription(),
m_aprsSymbol("/r"),
m_ysfNetHosts(),
m_ysfRFHangTime(60U),
m_ysfNetHangTime(60U),
@ -178,11 +179,11 @@ bool CConf::read()
else if (::strcmp(key, "RptAddress") == 0)
m_rptAddress = value;
else if (::strcmp(key, "RptPort") == 0)
m_rptPort = (unsigned int)::atoi(value);
m_rptPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "LocalAddress") == 0)
m_myAddress = value;
else if (::strcmp(key, "LocalPort") == 0)
m_myPort = (unsigned int)::atoi(value);
m_myPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "RFHangTime") == 0)
m_ysfRFHangTime = m_fcsRFHangTime = m_rfHangTime = (unsigned int)::atoi(value);
else if (::strcmp(key, "NetHangTime") == 0)
@ -225,11 +226,13 @@ bool CConf::read()
else if (::strcmp(key, "Address") == 0)
m_aprsAddress = value;
else if (::strcmp(key, "Port") == 0)
m_aprsPort = (unsigned int)::atoi(value);
m_aprsPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "Suffix") == 0)
m_aprsSuffix = value;
else if (::strcmp(key, "Description") == 0)
m_aprsDescription = value;
else if (::strcmp(key, "Symbol") == 0)
m_aprsSymbol = value;
} else if (section == SECTION_YSF_NETWORK) {
if (::strcmp(key, "Hosts") == 0)
m_ysfNetHosts = value;
@ -286,7 +289,7 @@ bool CConf::read()
else if (::strcmp(key, "Name") == 0)
dgIdData->m_name = value;
else if (::strcmp(key, "Port") == 0)
dgIdData->m_port = (unsigned int)::atoi(value);
dgIdData->m_port = (unsigned short)::atoi(value);
else if (::strcmp(key, "Local") == 0)
dgIdData->m_local = (unsigned int)::atoi(value);
else if (::strcmp(key, "DGId") == 0)
@ -335,7 +338,7 @@ std::string CConf::getRptAddress() const
return m_rptAddress;
}
unsigned int CConf::getRptPort() const
unsigned short CConf::getRptPort() const
{
return m_rptPort;
}
@ -345,7 +348,7 @@ std::string CConf::getMyAddress() const
return m_myAddress;
}
unsigned int CConf::getMyPort() const
unsigned short CConf::getMyPort() const
{
return m_myPort;
}
@ -435,7 +438,7 @@ std::string CConf::getAPRSAddress() const
return m_aprsAddress;
}
unsigned int CConf::getAPRSPort() const
unsigned short CConf::getAPRSPort() const
{
return m_aprsPort;
}
@ -450,6 +453,11 @@ std::string CConf::getAPRSDescription() const
return m_aprsDescription;
}
std::string CConf::getAPRSSymbol() const
{
return m_aprsSymbol;
}
std::string CConf::getYSFNetHosts() const
{
return m_ysfNetHosts;

View file

@ -33,8 +33,8 @@ struct DGIdData {
bool m_static;
std::string m_name;
std::string m_address;
unsigned int m_port;
unsigned int m_local;
unsigned short m_port;
unsigned short m_local;
unsigned int m_netDGId;
std::vector<IMRSDestination*> m_destinations;
unsigned int m_rfHangTime;
@ -55,9 +55,9 @@ public:
std::string getSuffix() const;
unsigned int getId() const;
std::string getRptAddress() const;
unsigned int getRptPort() const;
unsigned short getRptPort() const;
std::string getMyAddress() const;
unsigned int getMyPort() const;
unsigned short getMyPort() const;
bool getBleep() const;
bool getDebug() const;
bool getDaemon() const;
@ -81,9 +81,10 @@ public:
// The APRS section
bool getAPRSEnabled() const;
std::string getAPRSAddress() const;
unsigned int getAPRSPort() const;
unsigned short getAPRSPort() const;
std::string getAPRSSuffix() const;
std::string getAPRSDescription() const;
std::string getAPRSSymbol() const;
// The YSF Network section
std::string getYSFNetHosts() const;
@ -102,9 +103,9 @@ private:
std::string m_suffix;
unsigned int m_id;
std::string m_rptAddress;
unsigned int m_rptPort;
unsigned short m_rptPort;
std::string m_myAddress;
unsigned int m_myPort;
unsigned short m_myPort;
unsigned int m_rfHangTime;
unsigned int m_netHangTime;
bool m_bleep;
@ -127,9 +128,10 @@ private:
bool m_aprsEnabled;
std::string m_aprsAddress;
unsigned int m_aprsPort;
unsigned short m_aprsPort;
std::string m_aprsSuffix;
std::string m_aprsDescription;
std::string m_aprsSymbol;
std::string m_ysfNetHosts;
unsigned int m_ysfRFHangTime;

View file

@ -30,6 +30,7 @@
#include "Timer.h"
#include "Utils.h"
#include "Log.h"
#include "GitVersion.h"
#if defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
@ -69,7 +70,7 @@ int main(int argc, char** argv)
for (int currentArg = 1; currentArg < argc; ++currentArg) {
std::string arg = argv[currentArg];
if ((arg == "-v") || (arg == "--version")) {
::fprintf(stdout, "DGIdGateway version %s\n", VERSION);
::fprintf(stdout, "DGIdGateway version %s git #%.7s\n", VERSION, gitversion);
return 0;
} else if (arg.substr(0, 1) == "-") {
::fprintf(stderr, "Usage: DGIdGateway [-v|--version] [filename]\n");
@ -199,7 +200,7 @@ int CDGIdGateway::run()
bool debug = m_conf.getDebug();
std::string myAddress = m_conf.getMyAddress();
unsigned int myPort = m_conf.getMyPort();
unsigned short myPort = m_conf.getMyPort();
CYSFNetwork rptNetwork(myAddress, myPort, "MMDVM", rptAddr, rptAddrLen, m_callsign, debug);
ret = rptNetwork.open();
@ -243,7 +244,7 @@ int CDGIdGateway::run()
if (type == "FCS") {
std::string name = (*it)->m_name;
unsigned int local = (*it)->m_local;
unsigned short local = (*it)->m_local;
unsigned int txFrequency = m_conf.getTxFrequency();
unsigned int rxFrequency = m_conf.getRxFrequency();
std::string locator = calculateLocator();
@ -303,7 +304,7 @@ int CDGIdGateway::run()
LogMessage("Added IMRS:%s to DG-ID %u%s", name.c_str(), dgid, statc ? " (Static)" : "");
}
} else if (type == "Gateway") {
unsigned int local = (*it)->m_local;
unsigned short local = (*it)->m_local;
sockaddr_storage addr;
unsigned int addrLen;
@ -319,7 +320,7 @@ int CDGIdGateway::run()
LogWarning("Unable to resolve the address for the YSF Gateway");
}
} else if (type == "Parrot") {
unsigned int local = (*it)->m_local;
unsigned short local = (*it)->m_local;
sockaddr_storage addr;
unsigned int addrLen;
@ -335,7 +336,7 @@ int CDGIdGateway::run()
LogWarning("Unable to resolve the address for the YSF Parrot");
}
} else if (type == "YSF2DMR") {
unsigned int local = (*it)->m_local;
unsigned short local = (*it)->m_local;
sockaddr_storage addr;
unsigned int addrLen;
@ -351,7 +352,7 @@ int CDGIdGateway::run()
LogWarning("Unable to resolve the address for YSF2DMR");
}
} else if (type == "YSF2NXDN") {
unsigned int local = (*it)->m_local;
unsigned short local = (*it)->m_local;
sockaddr_storage addr;
unsigned int addrLen;
@ -367,7 +368,7 @@ int CDGIdGateway::run()
LogWarning("Unable to resolve the address for YSF2NXDN");
}
} else if (type == "YSF2P25") {
unsigned int local = (*it)->m_local;
unsigned short local = (*it)->m_local;
sockaddr_storage addr;
unsigned int addrLen;
@ -407,7 +408,8 @@ int CDGIdGateway::run()
CStopWatch stopWatch;
stopWatch.start();
LogMessage("Starting DGIdGateway-%s", VERSION);
LogMessage("DGIdGateway-%s is starting", VERSION);
LogMessage("Built %s %s (GitID #%.7s)", __TIME__, __DATE__, gitversion);
DGID_STATUS state = DS_NOTLINKED;
unsigned int nPips = 0U;
@ -425,13 +427,7 @@ int CDGIdGateway::run()
if (dgId == WIRESX_DGID)
dgId = 0U;
if (dgId != currentDGId) {
if (currentDGId != UNSET_DGID && dgIdNetwork[currentDGId] != NULL && !dgIdNetwork[currentDGId]->m_static) {
dgIdNetwork[currentDGId]->unlink();
dgIdNetwork[currentDGId]->unlink();
dgIdNetwork[currentDGId]->unlink();
}
if (currentDGId == UNSET_DGID) {
if (dgIdNetwork[dgId] != NULL && !dgIdNetwork[dgId]->m_static) {
dgIdNetwork[dgId]->link();
dgIdNetwork[dgId]->link();
@ -441,13 +437,13 @@ int CDGIdGateway::run()
if (dgIdNetwork[dgId] != NULL) {
std::string desc = dgIdNetwork[dgId]->getDesc(dgId);
LogMessage("DG-ID set to %u (%s) via RF", dgId, desc.c_str());
currentDGId = dgId;
state = DS_NOTLINKED;
} else {
LogMessage("DG-ID set to %u (None) via RF", dgId);
state = DS_NOTOPEN;
}
currentDGId = dgId;
fromRF = true;
}
@ -609,7 +605,7 @@ void CDGIdGateway::createGPS()
return;
std::string address = m_conf.getAPRSAddress();
unsigned int port = m_conf.getAPRSPort();
unsigned short port = m_conf.getAPRSPort();
std::string suffix = m_conf.getAPRSSuffix();
bool debug = m_conf.getDebug();
@ -618,8 +614,9 @@ void CDGIdGateway::createGPS()
unsigned int txFrequency = m_conf.getTxFrequency();
unsigned int rxFrequency = m_conf.getRxFrequency();
std::string desc = m_conf.getAPRSDescription();
std::string symbol = m_conf.getAPRSSymbol();
m_writer->setInfo(txFrequency, rxFrequency, desc);
m_writer->setInfo(txFrequency, rxFrequency, desc, symbol);
bool enabled = m_conf.getGPSDEnabled();
if (enabled) {

View file

@ -36,6 +36,7 @@ Address=127.0.0.1
Port=8673
Description=APRS Description
Suffix=Y
# Symbol="/r"
[YSF Network]
Hosts=./YSFHosts.txt

View file

@ -94,6 +94,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
@ -111,6 +114,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@ -124,6 +130,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@ -141,6 +150,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="APRSWriter.cpp" />

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2014,2016,2017,2018,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2014,2016,2017,2018,2020,2021 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
@ -29,7 +29,7 @@ const char* FCS_VERSION = "MMDVM";
const unsigned int BUFFER_LENGTH = 200U;
CFCSNetwork::CFCSNetwork(const std::string& reflector, unsigned int port, const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, const std::string& locator, unsigned int id, bool statc, bool debug) :
CFCSNetwork::CFCSNetwork(const std::string& reflector, unsigned short port, const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, const std::string& locator, unsigned int id, bool statc, bool debug) :
m_socket(port),
m_debug(debug),
m_addr(),
@ -60,7 +60,7 @@ m_state(DS_NOTOPEN)
m_print = reflector.substr(0U, 6U) + "-" + reflector.substr(6U);
char url[50U];
::sprintf(url, "%s.xreflector.net", reflector.c_str());
::sprintf(url, "%.6s.xreflector.net", reflector.c_str());
if (CUDPSocket::lookup(std::string(url), FCS_PORT, m_addr, m_addrLen) != 0)
m_addrLen = 0U;
}
@ -191,7 +191,8 @@ void CFCSNetwork::clock(unsigned int ms)
if (length <= 0)
return;
CUtils::dump(1U, "FCS Network Data Received", buffer, length);
if (m_debug)
CUtils::dump(1U, "FCS Network Data Received", buffer, length);
if (m_state == DS_NOTLINKED)
return;

View file

@ -30,7 +30,7 @@
class CFCSNetwork : public CDGIdNetwork {
public:
CFCSNetwork(const std::string& reflector, unsigned int port, const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, const std::string& locator, unsigned int id, bool statc, bool debug);
CFCSNetwork(const std::string& reflector, unsigned short port, const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, const std::string& locator, unsigned int id, bool statc, bool debug);
virtual ~CFCSNetwork();
virtual std::string getDesc(unsigned int dgId);

View file

@ -1,5 +1,5 @@
# xreflector.net - FCS_Hosts.txt
# Last Update: 10.12.2020 06:50 UTC
# Last Update: 13.03.2021 15:50 UTC
#
FCS00100;Repeater;FCS001 - Repeater;;;
FCS00101;Deutschland;FCS001 - Deutschland;;;
@ -457,7 +457,7 @@ FCS00552;nn;FCS005 - nn;;;
FCS00553;nn;FCS005 - nn;;;
FCS00554;nn;FCS005 - nn;;;
FCS00555;nn;FCS005 - nn;;;
FCS00556;nn;FCS005 - nn;;;
FCS00556;ARFCOM;FCS005 - ARFCOM;;;
FCS00557;nn;FCS005 - nn;;;
FCS00558;nn;FCS005 - nn;;;
FCS00559;nn;FCS005 - nn;;;
@ -604,38 +604,38 @@ FCS20699;Test-9;FCS206 - Test-9;;;
FCS20700;nn;FCS207 - nn;;;
FCS20701;DR-2X;FCS207 - DR-2X;;;
FCS20702;Europe;FCS207 - Europe;;;
FCS20703;North-America;FCS207 - North-America;;;
FCS20704;Asia;FCS207 - Asia;;;
FCS20705;Oceania;FCS207 - Oceania;;;
FCS20706;Africa;FCS207 - Africa;;;
FCS20707;South-America;FCS207 - South-America;;;
FCS20703;nn;FCS207 - nn;;;
FCS20704;nn;FCS207 - nn;;;
FCS20705;nn;FCS207 - nn;;;
FCS20706;nn;FCS207 - nn;;;
FCS20707;nn;FCS207 - nn;;;
FCS20708;nn;FCS207 - nn;;;
FCS20709;nn;FCS207 - nn;;;
FCS20710;WW-german;FCS207 - WW-german;;;
FCS20711;WW-french;FCS207 - WW-french;;;
FCS20710;nn;FCS207 - nn;;;
FCS20711;nn;FCS207 - nn;;;
FCS20712;WW-dutch/flemish;FCS207 - WW-dutch/flemish;;;
FCS20713;WW-english;FCS207 - WW-english;;;
FCS20714;WW-spanish;FCS207 - WW-spanish;;;
FCS20715;WW-portuguese;FCS207 - WW-portuguese;;;
FCS20716;WW-italian;FCS207 - WW-italian;;;
FCS20713;nn;FCS207 - nn;;;
FCS20714;nn;FCS207 - nn;;;
FCS20715;nn;FCS207 - nn;;;
FCS20716;nn;FCS207 - nn;;;
FCS20717;Netherlands;FCS207 - Netherlands;;;
FCS20718;Belgium;FCS207 - Belgium;;;
FCS20718;nn;FCS207 - nn;;;
FCS20719;nn;FCS207 - nn;;;
FCS20720;DACH;FCS207 - DACH;;;
FCS20721;World-Wide;FCS207 - World-Wide;;;
FCS20722;Italy;FCS207 - Italy;;;
FCS20723;France;FCS207 - France;;;
FCS20724;Spain;FCS207 - Spain;;;
FCS20720;nn;FCS207 - nn;;;
FCS20721;nn;FCS207 - nn;;;
FCS20722;nn;FCS207 - nn;;;
FCS20723;nn;FCS207 - nn;;;
FCS20724;nn;FCS207 - nn;;;
FCS20725;UK-2;FCS207 - UK-2;;;
FCS20726;Romania;FCS207 - Romania;;;
FCS20727;Portugal;FCS207 - Portugal;;;
FCS20728;Switzerland;FCS207 - Switzerland;;;
FCS20726;nn;FCS207 - nn;;;
FCS20727;nn;FCS207 - nn;;;
FCS20728;nn;FCS207 - nn;;;
FCS20729;nn;FCS207 - nn;;;
FCS20730;nn;FCS207 - nn;;;
FCS20731;North-America;FCS207 - North-America;;;
FCS20732;Austria;FCS207 - Austria;;;
FCS20731;nn;FCS207 - nn;;;
FCS20732;nn;FCS207 - nn;;;
FCS20733;nn;FCS207 - nn;;;
FCS20734;Mexico;FCS207 - Mexico;;;
FCS20734;nn;FCS207 - nn;;;
FCS20735;United Kingdom;FCS207 - United Kingdom;;;
FCS20736;nn;FCS207 - nn;;;
FCS20737;nn;FCS207 - nn;;;
@ -660,10 +660,10 @@ FCS20755;nn;FCS207 - nn;;;
FCS20756;nn;FCS207 - nn;;;
FCS20757;nn;FCS207 - nn;;;
FCS20758;nn;FCS207 - nn;;;
FCS20759;Moldova;FCS207 - Moldova;;;
FCS20760;Poland;FCS207 - Poland;;;
FCS20759;nn;FCS207 - nn;;;
FCS20760;nn;FCS207 - nn;;;
FCS20761;nn;FCS207 - nn;;;
FCS20762;Germany;FCS207 - Germany;;;
FCS20762;nn;FCS207 - nn;;;
FCS20763;nn;FCS207 - nn;;;
FCS20764;nn;FCS207 - nn;;;
FCS20765;nn;FCS207 - nn;;;
@ -671,9 +671,9 @@ FCS20766;nn;FCS207 - nn;;;
FCS20767;nn;FCS207 - nn;;;
FCS20768;nn;FCS207 - nn;;;
FCS20769;nn;FCS207 - nn;;;
FCS20770;nn;FCS207 - nn;;;
FCS20771;nn;FCS207 - nn;;;
FCS20772;Brazil;FCS207 - Brazil;;;
FCS20770;Theekransje;FCS207 - Theekransje;;;
FCS20771;Rookkamer;FCS207 - Rookkamer;;;
FCS20772;Techniek;FCS207 - Techniek;;;
FCS20773;nn;FCS207 - nn;;;
FCS20774;nn;FCS207 - nn;;;
FCS20775;nn;FCS207 - nn;;;
@ -681,26 +681,26 @@ FCS20776;nn;FCS207 - nn;;;
FCS20777;nn;FCS207 - nn;;;
FCS20778;nn;FCS207 - nn;;;
FCS20779;nn;FCS207 - nn;;;
FCS20780;REG0;FCS207 - REG0;;;
FCS20781;REG1;FCS207 - REG1;;;
FCS20782;REG2;FCS207 - REG2;;;
FCS20783;REG3;FCS207 - REG3;;;
FCS20784;REG4;FCS207 - REG4;;;
FCS20785;REG5;FCS207 - REG5;;;
FCS20786;REG6;FCS207 - REG6;;;
FCS20787;REG7;FCS207 - REG7;;;
FCS20788;REG8;FCS207 - REG8;;;
FCS20789;REG9;FCS207 - REG9;;;
FCS20780;Groepsgesprekken;FCS207 - Groepsgesprekken;;;
FCS20781;nn;FCS207 - nn;;;
FCS20782;Groepsgesprekken;FCS207 - Groepsgesprekken;;;
FCS20783;nn;FCS207 - nn;;;
FCS20784;nn;FCS207 - nn;;;
FCS20785;nn;FCS207 - nn;;;
FCS20786;nn;FCS207 - nn;;;
FCS20787;nn;FCS207 - nn;;;
FCS20788;nn;FCS207 - nn;;;
FCS20789;nn;FCS207 - nn;;;
FCS20790;CLEAR DG-ID;FCS207 - CLEAR DG-ID;;;
FCS20791;Test-1;FCS207 - Test-1;;;
FCS20792;Test-2;FCS207 - Test-2;;;
FCS20793;Test-3;FCS207 - Test-3;;;
FCS20794;Test-4;FCS207 - Test-4;;;
FCS20795;Test-5;FCS207 - Test-5;;;
FCS20796;Test-6;FCS207 - Test-6;;;
FCS20797;Test-7;FCS207 - Test-7;;;
FCS20798;Test-8;FCS207 - Test-8;;;
FCS20799;Test-9;FCS207 - Test-9;;;
FCS20791;nn;FCS207 - nn;;;
FCS20792;nn;FCS207 - nn;;;
FCS20793;nn;FCS207 - nn;;;
FCS20794;nn;FCS207 - nn;;;
FCS20795;nn;FCS207 - nn;;;
FCS20796;nn;FCS207 - nn;;;
FCS20797;nn;FCS207 - nn;;;
FCS20798;nn;FCS207 - nn;;;
FCS20799;Testomgeving;FCS207 - Testomgeving;;;
FCS20800;nn;FCS208 - nn;;;
FCS20801;DR-2X;FCS208 - DR-2X;;;
FCS20802;Europe;FCS208 - Europe;;;
@ -728,7 +728,7 @@ FCS20823;France;FCS208 - France;;;
FCS20824;Spain;FCS208 - Spain;;;
FCS20825;nn;FCS208 - nn;;;
FCS20826;Romania;FCS208 - Romania;;;
FCS20827;Portugal;FCS208 - Portugal;;;
FCS20827;nn;FCS208 - nn;;;
FCS20828;Switzerland;FCS208 - Switzerland;;;
FCS20829;nn;FCS208 - nn;;;
FCS20830;nn;FCS208 - nn;;;
@ -760,8 +760,8 @@ FCS20855;nn;FCS208 - nn;;;
FCS20856;nn;FCS208 - nn;;;
FCS20857;nn;FCS208 - nn;;;
FCS20858;nn;FCS208 - nn;;;
FCS20859;Moldova;FCS208 - Moldova;;;
FCS20860;Poland;FCS208 - Poland;;;
FCS20859;nn;FCS208 - nn;;;
FCS20860;nn;FCS208 - nn;;;
FCS20861;nn;FCS208 - nn;;;
FCS20862;Germany;FCS208 - Germany;;;
FCS20863;nn;FCS208 - nn;;;
@ -795,12 +795,12 @@ FCS20890;CLEAR DG-ID;FCS208 - CLEAR DG-ID;;;
FCS20891;Alsace;FCS208 - Alsace;;;
FCS20892;Bourgogne-Franche-Comte;FCS208 - Bourgogne-Franche-Comte;;;
FCS20893;Loire-Atlantique;FCS208 - Loire-Atlantique;;;
FCS20894;Test-4;FCS208 - Test-4;;;
FCS20895;Test-5;FCS208 - Test-5;;;
FCS20896;Test-6;FCS208 - Test-6;;;
FCS20897;Test-7;FCS208 - Test-7;;;
FCS20898;Test-8;FCS208 - Test-8;;;
FCS20899;Test-9;FCS208 - Test-9;;;
FCS20894;YSF-France;FCS208 - YSF-France;;;
FCS20895;Urgence France;FCS208 - Urgence France;;;
FCS20896;Mayenne-France;FCS208 - Mayenne-France;;;
FCS20897;nn;FCS208 - nn;;;
FCS20898;Belgique Francophone;FCS208 - Belgique Francophone;;;
FCS20899;nn;FCS208 - nn;;;
FCS22200;nn;FCS222 - nn;;;
FCS22201;nn;FCS222 - nn;;;
FCS22202;nn;FCS222 - nn;;;
@ -817,32 +817,32 @@ FCS22212;nn;FCS222 - nn;;;
FCS22213;nn;FCS222 - nn;;;
FCS22214;nn;FCS222 - nn;;;
FCS22215;nn;FCS222 - nn;;;
FCS22216;nn;FCS222 - nn;;;
FCS22216;IT-WW;FCS222 - IT-WW;;;
FCS22217;Netherlands;FCS222 - Netherlands;;;
FCS22218;Belgium;FCS222 - Belgium;;;
FCS22218;nn;FCS222 - nn;;;
FCS22219;nn;FCS222 - nn;;;
FCS22220;D-A-CH;FCS222 - D-A-CH;;;
FCS22221;World-Wide;FCS222 - World-Wide;;;
FCS22222;Italy-MultiIP;FCS222 - Italy-MultiIP;;;
FCS22223;France;FCS222 - France;;;
FCS22223;nn;FCS222 - nn;;;
FCS22224;Spain;FCS222 - Spain;;;
FCS22225;nn;FCS222 - nn;;;
FCS22226;Romania;FCS222 - Romania;;;
FCS22227;Portugal;FCS222 - Portugal;;;
FCS22227;nn;FCS222 - nn;;;
FCS22228;Switzerland;FCS222 - Switzerland;;;
FCS22229;nn;FCS222 - nn;;;
FCS22230;LAZIO;FCS222 - LAZIO;;;
FCS22231;nn;FCS222 - nn;;;
FCS22230;MP-LAZIO;FCS222 - MP-LAZIO;;;
FCS22231;MP-Sardegna;FCS222 - MP-Sardegna;;;
FCS22232;Austria;FCS222 - Austria;;;
FCS22233;nn;FCS222 - nn;;;
FCS22234;Mexico;FCS222 - Mexico;;;
FCS22235;United Kingdom;FCS222 - United Kingdom;;;
FCS22234;nn;FCS222 - nn;;;
FCS22235;nn;FCS222 - nn;;;
FCS22236;nn;FCS222 - nn;;;
FCS22237;nn;FCS222 - nn;;;
FCS22238;nn;FCS222 - nn;;;
FCS22239;nn;FCS222 - nn;;;
FCS22240;nn;FCS222 - nn;;;
FCS22241;MULTIP-TOS;FCS222 - MULTIP-TOS;;;
FCS22240;MP-Romagna;FCS222 - MP-Romagna;;;
FCS22241;MP-Toscana;FCS222 - MP-Toscana;;;
FCS22242;nn;FCS222 - nn;;;
FCS22243;nn;FCS222 - nn;;;
FCS22244;nn;FCS222 - nn;;;
@ -889,7 +889,7 @@ FCS22284;Test-4;FCS222 - Test-4;;;
FCS22285;Test-5;FCS222 - Test-5;;;
FCS22286;Test-6;FCS222 - Test-6;;;
FCS22287;Test-7;FCS222 - Test-7;;;
FCS22288;Cluster-GRF;FCS222 - Cluster-GRF;;;
FCS22288;Test-8;FCS222 - Test-8;;;
FCS22289;Test-9;FCS222 - Test-9;;;
FCS22290;CLEAR DG-ID;FCS222 - CLEAR DG-ID;;;
FCS22291;nn;FCS222 - nn;;;
@ -910,7 +910,7 @@ FCS22405;Oceania;FCS224 - Oceania;;;
FCS22406;Africa;FCS224 - Africa;;;
FCS22407;South-America;FCS224 - South-America;;;
FCS22408;nn;FCS224 - nn;;;
FCS22409;nn;FCS224 - nn;;;
FCS22409;C4FM-Link;FCS224 - C4FM-Link;;;
FCS22410;WW-german;FCS224 - WW-german;;;
FCS22411;WW-french;FCS224 - WW-french;;;
FCS22412;WW-dutch/flemish;FCS224 - WW-dutch/flemish;;;
@ -918,7 +918,7 @@ FCS22413;WW-english;FCS224 - WW-english;;;
FCS22414;WW-spanish;FCS224 - WW-spanish;;;
FCS22415;WW-portuguese;FCS224 - WW-portuguese;;;
FCS22416;WW-italian;FCS224 - WW-italian;;;
FCS22417;Netherlands;FCS224 - Netherlands;;;
FCS22417;nn;FCS224 - nn;;;
FCS22418;RC-VELETA;FCS224 - RC-VELETA;;;
FCS22419;nn;FCS224 - nn;;;
FCS22420;D-A-CH;FCS224 - D-A-CH;;;
@ -928,7 +928,7 @@ FCS22423;France;FCS224 - France;;;
FCS22424;C4FM-Link;FCS224 - C4FM-Link;;;
FCS22425;CQ-UK-2;FCS224 - CQ-UK-2;;;
FCS22426;Romania;FCS224 - Romania;;;
FCS22427;Portugal;FCS224 - Portugal;;;
FCS22427;nn;FCS224 - nn;;;
FCS22428;Switzerland;FCS224 - Switzerland;;;
FCS22429;nn;FCS224 - nn;;;
FCS22430;SKYNET;FCS224 - SKYNET;;;
@ -951,7 +951,7 @@ FCS22446;nn;FCS224 - nn;;;
FCS22447;nn;FCS224 - nn;;;
FCS22448;URG-LINK;FCS224 - URG-LINK;;;
FCS22449;nn;FCS224 - nn;;;
FCS22450;nn;FCS224 - nn;;;
FCS22450;Andalucia;FCS224 - Andalucia;;;
FCS22451;nn;FCS224 - nn;;;
FCS22452;Miami;FCS224 - Miami;;;
FCS22453;nn;FCS224 - nn;;;
@ -973,7 +973,7 @@ FCS22468;CANARIAS;FCS224 - CANARIAS;;;
FCS22469;nn;FCS224 - nn;;;
FCS22470;DR2X-DMR;FCS224 - DR2X-DMR;;;
FCS22471;EA-Distrito-1;FCS224 - EA-Distrito-1;;;
FCS22472;EA-Distrito-2;FCS224 - EA-Distrito-2;;;
FCS22472;Brazil;FCS224 - Brazil;;;
FCS22473;EA-Distrito-3;FCS224 - EA-Distrito-3;;;
FCS22474;EA-Distrito-4;FCS224 - EA-Distrito-4;;;
FCS22475;EA-Distrito-5;FCS224 - EA-Distrito-5;;;
@ -995,7 +995,7 @@ FCS22490;Clear-DG-ID;FCS224 - Clear-DG-ID;;;
FCS22491;nn;FCS224 - nn;;;
FCS22492;nn;FCS224 - nn;;;
FCS22493;nn;FCS224 - nn;;;
FCS22494;nn;FCS224 - nn;;;
FCS22494;RC-Zaria;FCS224 - RC-Zaria;;;
FCS22495;LATINOS;FCS224 - LATINOS;;;
FCS22496;EA7URF;FCS224 - EA7URF;;;
FCS22497;Emergencias;FCS224 - Emergencias;;;
@ -1019,16 +1019,16 @@ FCS22614;WW-spanish;FCS226 - WW-spanish;;;
FCS22615;WW-portuguese;FCS226 - WW-portuguese;;;
FCS22616;WW-italian;FCS226 - WW-italian;;;
FCS22617;Netherlands;FCS226 - Netherlands;;;
FCS22618;Belgium;FCS226 - Belgium;;;
FCS22618;nn;FCS226 - nn;;;
FCS22619;nn;FCS226 - nn;;;
FCS22620;DACH;FCS226 - DACH;;;
FCS22621;World-Wide;FCS226 - World-Wide;;;
FCS22622;Italy;FCS226 - Italy;;;
FCS22623;France;FCS226 - France;;;
FCS22623;nn;FCS226 - nn;;;
FCS22624;Spain;FCS226 - Spain;;;
FCS22625;nn;FCS226 - nn;;;
FCS22626;Romania;FCS226 - Romania;;;
FCS22627;Portugal;FCS226 - Portugal;;;
FCS22627;nn;FCS226 - nn;;;
FCS22628;Switzerland;FCS226 - Switzerland;;;
FCS22629;nn;FCS226 - nn;;;
FCS22630;nn;FCS226 - nn;;;
@ -1036,7 +1036,7 @@ FCS22631;North-America;FCS226 - North-America;;;
FCS22632;Austria;FCS226 - Austria;;;
FCS22633;nn;FCS226 - nn;;;
FCS22634;Mexico;FCS226 - Mexico;;;
FCS22635;United Kingdom;FCS226 - United Kingdom;;;
FCS22635;nn;FCS226 - nn;;;
FCS22636;nn;FCS226 - nn;;;
FCS22637;nn;FCS226 - nn;;;
FCS22638;nn;FCS226 - nn;;;
@ -1071,26 +1071,26 @@ FCS22666;nn;FCS226 - nn;;;
FCS22667;nn;FCS226 - nn;;;
FCS22668;nn;FCS226 - nn;;;
FCS22669;nn;FCS226 - nn;;;
FCS22670;Romania;FCS226 - Romania;;;
FCS22671;Romania;FCS226 - Romania;;;
FCS22672;Romania;FCS226 - Romania;;;
FCS22673;Romania;FCS226 - Romania;;;
FCS22674;Romania;FCS226 - Romania;;;
FCS22675;Romania;FCS226 - Romania;;;
FCS22676;Romania;FCS226 - Romania;;;
FCS22677;Romania;FCS226 - Romania;;;
FCS22678;Romania;FCS226 - Romania;;;
FCS22679;Romania;FCS226 - Romania;;;
FCS22680;Romania;FCS226 - Romania;;;
FCS22681;Romania;FCS226 - Romania;;;
FCS22682;Romania;FCS226 - Romania;;;
FCS22683;Romania;FCS226 - Romania;;;
FCS22684;Romania;FCS226 - Romania;;;
FCS22685;Romania;FCS226 - Romania;;;
FCS22686;Romania;FCS226 - Romania;;;
FCS22687;Romania;FCS226 - Romania;;;
FCS22688;Romania;FCS226 - Romania;;;
FCS22689;Romania;FCS226 - Romania;;;
FCS22670;all-local;FCS226 - all-local;;;
FCS22671;RVSU;FCS226 - RVSU;;;
FCS22672;Banat;FCS226 - Banat;;;
FCS22673;Bucovina;FCS226 - Bucovina;;;
FCS22674;Crisana;FCS226 - Crisana;;;
FCS22675;Dobrogea;FCS226 - Dobrogea;;;
FCS22676;Maramures;FCS226 - Maramures;;;
FCS22677;Moldova;FCS226 - Moldova;;;
FCS22678;Muntenia;FCS226 - Muntenia;;;
FCS22679;Transilvania;FCS226 - Transilvania;;;
FCS22680;nn;FCS226 - nn;;;
FCS22681;Test;FCS226 - Test;;;
FCS22682;YO2;FCS226 - YO2;;;
FCS22683;YO3;FCS226 - YO3;;;
FCS22684;YO4;FCS226 - YO4;;;
FCS22685;YO5;FCS226 - YO5;;;
FCS22686;YO6;FCS226 - YO6;;;
FCS22687;YO7;FCS226 - YO7;;;
FCS22688;YO8;FCS226 - YO8;;;
FCS22689;Test;FCS226 - Test;;;
FCS22690;CLEAR-DG-ID;FCS226 - CLEAR-DG-ID;;;
FCS22691;Test-1;FCS226 - Test-1;;;
FCS22692;Test-2;FCS226 - Test-2;;;
@ -1319,16 +1319,16 @@ FCS25914;WW-spanish;FCS259 - WW-spanish;;;
FCS25915;WW-portuguese;FCS259 - WW-portuguese;;;
FCS25916;WW-italian;FCS259 - WW-italian;;;
FCS25917;Netherlands;FCS259 - Netherlands;;;
FCS25918;Belgium;FCS259 - Belgium;;;
FCS25918;nn;FCS259 - nn;;;
FCS25919;nn;FCS259 - nn;;;
FCS25920;DACH;FCS259 - DACH;;;
FCS25921;World-Wide;FCS259 - World-Wide;;;
FCS25922;Italy;FCS259 - Italy;;;
FCS25923;France;FCS259 - France;;;
FCS25923;nn;FCS259 - nn;;;
FCS25924;Spain;FCS259 - Spain;;;
FCS25925;nn;FCS259 - nn;;;
FCS25926;Romania;FCS259 - Romania;;;
FCS25927;Portugal;FCS259 - Portugal;;;
FCS25927;nn;FCS259 - nn;;;
FCS25928;Switzerland;FCS259 - Switzerland;;;
FCS25929;nn;FCS259 - nn;;;
FCS25930;nn;FCS259 - nn;;;
@ -1336,7 +1336,7 @@ FCS25931;North-America;FCS259 - North-America;;;
FCS25932;Austria;FCS259 - Austria;;;
FCS25933;nn;FCS259 - nn;;;
FCS25934;Mexico;FCS259 - Mexico;;;
FCS25935;United Kingdom;FCS259 - United Kingdom;;;
FCS25935;nn;FCS259 - nn;;;
FCS25936;nn;FCS259 - nn;;;
FCS25937;nn;FCS259 - nn;;;
FCS25938;nn;FCS259 - nn;;;
@ -1381,16 +1381,16 @@ FCS25976;nn;FCS259 - nn;;;
FCS25977;nn;FCS259 - nn;;;
FCS25978;nn;FCS259 - nn;;;
FCS25979;nn;FCS259 - nn;;;
FCS25980;REG0;FCS259 - REG0;;;
FCS25981;REG1;FCS259 - REG1;;;
FCS25982;REG2;FCS259 - REG2;;;
FCS25983;REG3;FCS259 - REG3;;;
FCS25984;REG4;FCS259 - REG4;;;
FCS25985;REG5;FCS259 - REG5;;;
FCS25986;REG6;FCS259 - REG6;;;
FCS25987;REG7;FCS259 - REG7;;;
FCS25988;REG8;FCS259 - REG8;;;
FCS25989;REG9;FCS259 - REG9;;;
FCS25980;nn;FCS259 - nn;;;
FCS25981;ER1;FCS259 - ER1;;;
FCS25982;ER2;FCS259 - ER2;;;
FCS25983;ER3;FCS259 - ER3;;;
FCS25984;ER4;FCS259 - ER4;;;
FCS25985;ER5;FCS259 - ER5;;;
FCS25986;nn;FCS259 - nn;;;
FCS25987;nn;FCS259 - nn;;;
FCS25988;nn;FCS259 - nn;;;
FCS25989;nn;FCS259 - nn;;;
FCS25990;CLEAR DG-ID;FCS259 - CLEAR DG-ID;;;
FCS25991;Test-1;FCS259 - Test-1;;;
FCS25992;Test-2;FCS259 - Test-2;;;
@ -1401,7 +1401,7 @@ FCS25996;Test-6;FCS259 - Test-6;;;
FCS25997;Test-7;FCS259 - Test-7;;;
FCS25998;Test-8;FCS259 - Test-8;;;
FCS25999;Test-9;FCS259 - Test-9;;;
FCS26000;Polska;FCS260 - Polska;;;
FCS26000;nn;FCS260 - nn;;;
FCS26001;DR-2X;FCS260 - DR-2X;;;
FCS26002;Europe;FCS260 - Europe;;;
FCS26003;North-America;FCS260 - North-America;;;
@ -1411,14 +1411,14 @@ FCS26006;Africa;FCS260 - Africa;;;
FCS26007;South-America;FCS260 - South-America;;;
FCS26008;nn;FCS260 - nn;;;
FCS26009;nn;FCS260 - nn;;;
FCS26010;WW-german;FCS260 - WW-german;;;
FCS26011;WW-french;FCS260 - WW-french;;;
FCS26012;WW-dutch/flemish;FCS260 - WW-dutch/flemish;;;
FCS26013;WW-english;FCS260 - WW-english;;;
FCS26014;WW-spanish;FCS260 - WW-spanish;;;
FCS26015;WW-portuguese;FCS260 - WW-portuguese;;;
FCS26016;WW-italian;FCS260 - WW-italian;;;
FCS26017;Netherlands;FCS260 - Netherlands;;;
FCS26010;nn;FCS260 - nn;;;
FCS26011;nn;FCS260 - nn;;;
FCS26012;nn;FCS260 - nn;;;
FCS26013;nn;FCS260 - nn;;;
FCS26014;nn;FCS260 - nn;;;
FCS26015;nn;FCS260 - nn;;;
FCS26016;nn;FCS260 - nn;;;
FCS26017;nn;FCS260 - nn;;;
FCS26018;Belgium;FCS260 - Belgium;;;
FCS26019;nn;FCS260 - nn;;;
FCS26020;DACH;FCS260 - DACH;;;
@ -1428,14 +1428,14 @@ FCS26023;France;FCS260 - France;;;
FCS26024;Spain;FCS260 - Spain;;;
FCS26025;UK-2;FCS260 - UK-2;;;
FCS26026;Romania;FCS260 - Romania;;;
FCS26027;Portugal;FCS260 - Portugal;;;
FCS26027;nn;FCS260 - nn;;;
FCS26028;Switzerland;FCS260 - Switzerland;;;
FCS26029;nn;FCS260 - nn;;;
FCS26030;nn;FCS260 - nn;;;
FCS26031;North-America;FCS260 - North-America;;;
FCS26032;Austria;FCS260 - Austria;;;
FCS26033;nn;FCS260 - nn;;;
FCS26034;Mexico;FCS260 - Mexico;;;
FCS26034;nn;FCS260 - nn;;;
FCS26035;UK-1;FCS260 - UK-1;;;
FCS26036;nn;FCS260 - nn;;;
FCS26037;nn;FCS260 - nn;;;
@ -1460,7 +1460,7 @@ FCS26055;nn;FCS260 - nn;;;
FCS26056;nn;FCS260 - nn;;;
FCS26057;nn;FCS260 - nn;;;
FCS26058;nn;FCS260 - nn;;;
FCS26059;Moldova;FCS260 - Moldova;;;
FCS26059;nn;FCS260 - nn;;;
FCS26060;Poland;FCS260 - Poland;;;
FCS26061;nn;FCS260 - nn;;;
FCS26062;Germany;FCS260 - Germany;;;
@ -1481,7 +1481,7 @@ FCS26076;nn;FCS260 - nn;;;
FCS26077;nn;FCS260 - nn;;;
FCS26078;nn;FCS260 - nn;;;
FCS26079;nn;FCS260 - nn;;;
FCS26080;nn;FCS260 - nn;;;
FCS26080;DMR+ Poland;FCS260 - DMR+ Poland;;;
FCS26081;SP1;FCS260 - SP1;;;
FCS26082;SP2;FCS260 - SP2;;;
FCS26083;SP3;FCS260 - SP3;;;
@ -1546,7 +1546,7 @@ FCS26241;nn;FCS262 - nn;;;
FCS26242;nn;FCS262 - nn;;;
FCS26243;nn;FCS262 - nn;;;
FCS26244;nn;FCS262 - nn;;;
FCS26245;nn;FCS262 - nn;;;
FCS26245;Korea;FCS262 - Korea;;;
FCS26246;nn;FCS262 - nn;;;
FCS26247;nn;FCS262 - nn;;;
FCS26248;nn;FCS262 - nn;;;
@ -1611,29 +1611,29 @@ FCS26806;Africa;FCS268 - Africa;;;
FCS26807;South-America;FCS268 - South-America;;;
FCS26808;nn;FCS268 - nn;;;
FCS26809;nn;FCS268 - nn;;;
FCS26810;WW-german;FCS268 - WW-german;;;
FCS26810;nn;FCS268 - nn;;;
FCS26811;WW-french;FCS268 - WW-french;;;
FCS26812;WW-dutch/flemish;FCS268 - WW-dutch/flemish;;;
FCS26813;WW-english;FCS268 - WW-english;;;
FCS26814;WW-spanish;FCS268 - WW-spanish;;;
FCS26815;WW-portuguese;FCS268 - WW-portuguese;;;
FCS26816;WW-italian;FCS268 - WW-italian;;;
FCS26817;Netherlands;FCS268 - Netherlands;;;
FCS26818;Belgium;FCS268 - Belgium;;;
FCS26816;nn;FCS268 - nn;;;
FCS26817;nn;FCS268 - nn;;;
FCS26818;nn;FCS268 - nn;;;
FCS26819;nn;FCS268 - nn;;;
FCS26820;DACH;FCS268 - DACH;;;
FCS26820;nn;FCS268 - nn;;;
FCS26821;World-Wide;FCS268 - World-Wide;;;
FCS26822;Italy;FCS268 - Italy;;;
FCS26823;France;FCS268 - France;;;
FCS26824;Spain;FCS268 - Spain;;;
FCS26825;nn;FCS268 - nn;;;
FCS26826;Romania;FCS268 - Romania;;;
FCS26826;nn;FCS268 - nn;;;
FCS26827;Portugal;FCS268 - Portugal;;;
FCS26828;Switzerland;FCS268 - Switzerland;;;
FCS26828;nn;FCS268 - nn;;;
FCS26829;nn;FCS268 - nn;;;
FCS26830;nn;FCS268 - nn;;;
FCS26830;Skynet;FCS268 - Skynet;;;
FCS26831;North-America;FCS268 - North-America;;;
FCS26832;Austria;FCS268 - Austria;;;
FCS26832;nn;FCS268 - nn;;;
FCS26833;nn;FCS268 - nn;;;
FCS26834;Mexico;FCS268 - Mexico;;;
FCS26835;United Kingdom;FCS268 - United Kingdom;;;
@ -1660,10 +1660,10 @@ FCS26855;nn;FCS268 - nn;;;
FCS26856;nn;FCS268 - nn;;;
FCS26857;nn;FCS268 - nn;;;
FCS26858;nn;FCS268 - nn;;;
FCS26859;Moldova;FCS268 - Moldova;;;
FCS26860;Poland;FCS268 - Poland;;;
FCS26859;nn;FCS268 - nn;;;
FCS26860;nn;FCS268 - nn;;;
FCS26861;nn;FCS268 - nn;;;
FCS26862;Germany;FCS268 - Germany;;;
FCS26862;nn;FCS268 - nn;;;
FCS26863;nn;FCS268 - nn;;;
FCS26864;nn;FCS268 - nn;;;
FCS26865;nn;FCS268 - nn;;;
@ -1692,14 +1692,14 @@ FCS26887;REG7;FCS268 - REG7;;;
FCS26888;REG8;FCS268 - REG8;;;
FCS26889;REG9;FCS268 - REG9;;;
FCS26890;CLEAR DG-ID;FCS268 - CLEAR DG-ID;;;
FCS26891;Test-1;FCS268 - Test-1;;;
FCS26892;Test-2;FCS268 - Test-2;;;
FCS26893;Test-3;FCS268 - Test-3;;;
FCS26894;Test-4;FCS268 - Test-4;;;
FCS26895;Test-5;FCS268 - Test-5;;;
FCS26896;Test-6;FCS268 - Test-6;;;
FCS26897;Test-7;FCS268 - Test-7;;;
FCS26898;Test-8;FCS268 - Test-8;;;
FCS26891;YSF903;FCS268 - YSF903;;;
FCS26892;YSF012;FCS268 - YSF012;;;
FCS26893;YSF009;FCS268 - YSF009;;;
FCS26894;YSF915;FCS268 - YSF915;;;
FCS26895;YSF268;FCS268 - YSF268;;;
FCS26896;nn;FCS268 - nn;;;
FCS26897;nn;FCS268 - nn;;;
FCS26898;Brasil-AMRASE;FCS268 - Brasil-AMRASE;;;
FCS26899;Test-9;FCS268 - Test-9;;;
FCS31000;nn;FCS310 - nn;;;
FCS31001;DR-2X;FCS310 - DR-2X;;;
@ -1737,11 +1737,11 @@ FCS31032;nn;FCS310 - nn;;;
FCS31033;East-Hub USA;FCS310 - East-Hub USA;;;
FCS31034;West-Hub USA;FCS310 - West-Hub USA;;;
FCS31035;WM-Connect;FCS310 - WM-Connect;;;
FCS31036;nn;FCS310 - nn;;;
FCS31037;nn;FCS310 - nn;;;
FCS31038;nn;FCS310 - nn;;;
FCS31039;nn;FCS310 - nn;;;
FCS31040;nn;FCS310 - nn;;;
FCS31036;SE-Link;FCS310 - SE-Link;;;
FCS31037;America-Link-USA;FCS310 - America-Link-USA;;;
FCS31038;RocketCity-AL;FCS310 - RocketCity-AL;;;
FCS31039;Alabama-Link;FCS310 - Alabama-Link;;;
FCS31040;FusionNet369;FCS310 - FusionNet369;;;
FCS31041;nn;FCS310 - nn;;;
FCS31042;nn;FCS310 - nn;;;
FCS31043;nn;FCS310 - nn;;;
@ -1801,6 +1801,106 @@ FCS31096;nn;FCS310 - nn;;;
FCS31097;nn;FCS310 - nn;;;
FCS31098;nn;FCS310 - nn;;;
FCS31099;ECHO;FCS310 - ECHO;;;
FCS31100;nn;FCS311 - nn;;;
FCS31101;DR-2X;FCS311 - DR-2X;;;
FCS31102;Europe;FCS311 - Europe;;;
FCS31103;North-America;FCS311 - North-America;;;
FCS31104;Asia;FCS311 - Asia;;;
FCS31105;Oceania;FCS311 - Oceania;;;
FCS31106;Africa;FCS311 - Africa;;;
FCS31107;South-America;FCS311 - South-America;;;
FCS31108;nn;FCS311 - nn;;;
FCS31109;nn;FCS311 - nn;;;
FCS31110;nn;FCS311 - nn;;;
FCS31111;nn;FCS311 - nn;;;
FCS31112;nn;FCS311 - nn;;;
FCS31113;WW-english;FCS311 - WW-english;;;
FCS31114;nn;FCS311 - nn;;;
FCS31115;nn;FCS311 - nn;;;
FCS31116;nn;FCS311 - nn;;;
FCS31117;nn;FCS311 - nn;;;
FCS31118;nn;FCS311 - nn;;;
FCS31119;nn;FCS311 - nn;;;
FCS31120;nn;FCS311 - nn;;;
FCS31121;nn;FCS311 - nn;;;
FCS31122;nn;FCS311 - nn;;;
FCS31123;nn;FCS311 - nn;;;
FCS31124;nn;FCS311 - nn;;;
FCS31125;UK-2;FCS311 - UK-2;;;
FCS31126;nn;FCS311 - nn;;;
FCS31127;nn;FCS311 - nn;;;
FCS31128;nn;FCS311 - nn;;;
FCS31129;nn;FCS311 - nn;;;
FCS31130;nn;FCS311 - nn;;;
FCS31131;North-America;FCS311 - North-America;;;
FCS31132;nn;FCS311 - nn;;;
FCS31133;nn;FCS311 - nn;;;
FCS31134;nn;FCS311 - nn;;;
FCS31135;WM-Connect;FCS311 - WM-Connect;;;
FCS31136;nn;FCS311 - nn;;;
FCS31137;America-Link-USA;FCS311 - America-Link-USA;;;
FCS31138;RocketCity-Link;FCS311 - RocketCity-Link;;;
FCS31139;Alabama-Link;FCS311 - Alabama-Link;;;
FCS31140;nn;FCS311 - nn;;;
FCS31141;nn;FCS311 - nn;;;
FCS31142;US-Georgia;FCS311 - US-Georgia;;;
FCS31143;nn;FCS311 - nn;;;
FCS31144;nn;FCS311 - nn;;;
FCS31145;nn;FCS311 - nn;;;
FCS31146;nn;FCS311 - nn;;;
FCS31147;nn;FCS311 - nn;;;
FCS31148;nn;FCS311 - nn;;;
FCS31149;nn;FCS311 - nn;;;
FCS31150;nn;FCS311 - nn;;;
FCS31151;nn;FCS311 - nn;;;
FCS31152;nn;FCS311 - nn;;;
FCS31153;nn;FCS311 - nn;;;
FCS31154;nn;FCS311 - nn;;;
FCS31155;nn;FCS311 - nn;;;
FCS31156;nn;FCS311 - nn;;;
FCS31157;nn;FCS311 - nn;;;
FCS31158;nn;FCS311 - nn;;;
FCS31159;nn;FCS311 - nn;;;
FCS31160;nn;FCS311 - nn;;;
FCS31161;nn;FCS311 - nn;;;
FCS31162;nn;FCS311 - nn;;;
FCS31163;nn;FCS311 - nn;;;
FCS31164;nn;FCS311 - nn;;;
FCS31165;nn;FCS311 - nn;;;
FCS31166;nn;FCS311 - nn;;;
FCS31167;nn;FCS311 - nn;;;
FCS31168;nn;FCS311 - nn;;;
FCS31169;nn;FCS311 - nn;;;
FCS31170;MNTRBO-TEST;FCS311 - MNTRBO-TEST;;;
FCS31171;America-RagChew;FCS311 - America-RagChew;;;
FCS31172;Amsat;FCS311 - Amsat;;;
FCS31173;HUBNET;FCS311 - HUBNET;;;
FCS31174;nn;FCS311 - nn;;;
FCS31175;USA;FCS311 - USA;;;
FCS31176;nn;FCS311 - nn;;;
FCS31177;nn;FCS311 - nn;;;
FCS31178;nn;FCS311 - nn;;;
FCS31179;nn;FCS311 - nn;;;
FCS31180;Rural-Minnesota;FCS311 - Rural-Minnesota;;;
FCS31181;SARA-QRX-FCMG;FCS311 - SARA-QRX-FCMG;;;
FCS31182;nn;FCS311 - nn;;;
FCS31183;nn;FCS311 - nn;;;
FCS31184;nn;FCS311 - nn;;;
FCS31185;nn;FCS311 - nn;;;
FCS31186;nn;FCS311 - nn;;;
FCS31187;nn;FCS311 - nn;;;
FCS31188;nn;FCS311 - nn;;;
FCS31189;nn;FCS311 - nn;;;
FCS31190;CLEAR DG-ID;FCS311 - CLEAR DG-ID;;;
FCS31191;Test-1;FCS311 - Test-1;;;
FCS31192;Test-2;FCS311 - Test-2;;;
FCS31193;Test-3;FCS311 - Test-3;;;
FCS31194;Test-4;FCS311 - Test-4;;;
FCS31195;Test-5;FCS311 - Test-5;;;
FCS31196;Test-6;FCS311 - Test-6;;;
FCS31197;Test-7;FCS311 - Test-7;;;
FCS31198;Test-8;FCS311 - Test-8;;;
FCS31199;Test-9;FCS311 - Test-9;;;
FCS33400;nn;FCS334 - nn;;;
FCS33401;DR-2X;FCS334 - DR-2X;;;
FCS33402;Europe;FCS334 - Europe;;;
@ -1819,24 +1919,24 @@ FCS33414;WW-spanish;FCS334 - WW-spanish;;;
FCS33415;WW-portuguese;FCS334 - WW-portuguese;;;
FCS33416;WW-italian;FCS334 - WW-italian;;;
FCS33417;Netherlands;FCS334 - Netherlands;;;
FCS33418;Belgium;FCS334 - Belgium;;;
FCS33418;nn;FCS334 - nn;;;
FCS33419;nn;FCS334 - nn;;;
FCS33420;DACH;FCS334 - DACH;;;
FCS33421;World-Wide;FCS334 - World-Wide;;;
FCS33422;Italy;FCS334 - Italy;;;
FCS33423;France;FCS334 - France;;;
FCS33423;nn;FCS334 - nn;;;
FCS33424;Spain;FCS334 - Spain;;;
FCS33425;nn;FCS334 - nn;;;
FCS33426;Romania;FCS334 - Romania;;;
FCS33427;Portugal;FCS334 - Portugal;;;
FCS33427;nn;FCS334 - nn;;;
FCS33428;Switzerland;FCS334 - Switzerland;;;
FCS33429;nn;FCS334 - nn;;;
FCS33430;nn;FCS334 - nn;;;
FCS33430;Skynet;FCS334 - Skynet;;;
FCS33431;North-America;FCS334 - North-America;;;
FCS33432;Austria;FCS334 - Austria;;;
FCS33433;nn;FCS334 - nn;;;
FCS33434;Mexico;FCS334 - Mexico;;;
FCS33435;United Kingdom;FCS334 - United Kingdom;;;
FCS33435;CQ-UK;FCS334 - CQ-UK;;;
FCS33436;nn;FCS334 - nn;;;
FCS33437;nn;FCS334 - nn;;;
FCS33438;nn;FCS334 - nn;;;
@ -1860,8 +1960,8 @@ FCS33455;nn;FCS334 - nn;;;
FCS33456;nn;FCS334 - nn;;;
FCS33457;nn;FCS334 - nn;;;
FCS33458;nn;FCS334 - nn;;;
FCS33459;Moldova;FCS334 - Moldova;;;
FCS33460;Poland;FCS334 - Poland;;;
FCS33459;nn;FCS334 - nn;;;
FCS33460;nn;FCS334 - nn;;;
FCS33461;nn;FCS334 - nn;;;
FCS33462;Germany;FCS334 - Germany;;;
FCS33463;nn;FCS334 - nn;;;
@ -1871,8 +1971,8 @@ FCS33466;nn;FCS334 - nn;;;
FCS33467;nn;FCS334 - nn;;;
FCS33468;nn;FCS334 - nn;;;
FCS33469;nn;FCS334 - nn;;;
FCS33470;nn;FCS334 - nn;;;
FCS33471;nn;FCS334 - nn;;;
FCS33470;Chih-Mexico;FCS334 - Chih-Mexico;;;
FCS33471;Mexico;FCS334 - Mexico;;;
FCS33472;nn;FCS334 - nn;;;
FCS33473;nn;FCS334 - nn;;;
FCS33474;nn;FCS334 - nn;;;
@ -1901,6 +2001,106 @@ FCS33496;Test-6;FCS334 - Test-6;;;
FCS33497;Test-7;FCS334 - Test-7;;;
FCS33498;Test-8;FCS334 - Test-8;;;
FCS33499;Test-9;FCS334 - Test-9;;;
FCS45000;nn;FCS450 - nn;;;
FCS45001;DR-2X;FCS450 - DR-2X;;;
FCS45002;Europe;FCS450 - Europe;;;
FCS45003;North-America;FCS450 - North-America;;;
FCS45004;Asia;FCS450 - Asia;;;
FCS45005;Oceania;FCS450 - Oceania;;;
FCS45006;Africa;FCS450 - Africa;;;
FCS45007;South-America;FCS450 - South-America;;;
FCS45008;nn;FCS450 - nn;;;
FCS45009;nn;FCS450 - nn;;;
FCS45010;WW-german;FCS450 - WW-german;;;
FCS45011;WW-french;FCS450 - WW-french;;;
FCS45012;WW-dutch/flemish;FCS450 - WW-dutch/flemish;;;
FCS45013;WW-english;FCS450 - WW-english;;;
FCS45014;WW-spanish;FCS450 - WW-spanish;;;
FCS45015;WW-portuguese;FCS450 - WW-portuguese;;;
FCS45016;WW-italian;FCS450 - WW-italian;;;
FCS45017;Netherlands;FCS450 - Netherlands;;;
FCS45018;Belgium;FCS450 - Belgium;;;
FCS45019;nn;FCS450 - nn;;;
FCS45020;DACH;FCS450 - DACH;;;
FCS45021;World-Wide;FCS450 - World-Wide;;;
FCS45022;Italy;FCS450 - Italy;;;
FCS45023;nn;FCS450 - nn;;;
FCS45024;Spain;FCS450 - Spain;;;
FCS45025;nn;FCS450 - nn;;;
FCS45026;nn;FCS450 - nn;;;
FCS45027;nn;FCS450 - nn;;;
FCS45028;Switzerland;FCS450 - Switzerland;;;
FCS45029;nn;FCS450 - nn;;;
FCS45030;nn;FCS450 - nn;;;
FCS45031;North-America;FCS450 - North-America;;;
FCS45032;Austria;FCS450 - Austria;;;
FCS45033;nn;FCS450 - nn;;;
FCS45034;Mexico;FCS450 - Mexico;;;
FCS45035;United Kingdom;FCS450 - United Kingdom;;;
FCS45036;nn;FCS450 - nn;;;
FCS45037;America-Link-USA;FCS450 - America-Link-USA;;;
FCS45038;nn;FCS450 - nn;;;
FCS45039;nn;FCS450 - nn;;;
FCS45040;nn;FCS450 - nn;;;
FCS45041;nn;FCS450 - nn;;;
FCS45042;nn;FCS450 - nn;;;
FCS45043;nn;FCS450 - nn;;;
FCS45044;nn;FCS450 - nn;;;
FCS45045;Korea;FCS450 - Korea;;;
FCS45046;nn;FCS450 - nn;;;
FCS45047;nn;FCS450 - nn;;;
FCS45048;nn;FCS450 - nn;;;
FCS45049;nn;FCS450 - nn;;;
FCS45050;nn;FCS450 - nn;;;
FCS45051;nn;FCS450 - nn;;;
FCS45052;nn;FCS450 - nn;;;
FCS45053;nn;FCS450 - nn;;;
FCS45054;nn;FCS450 - nn;;;
FCS45055;nn;FCS450 - nn;;;
FCS45056;nn;FCS450 - nn;;;
FCS45057;nn;FCS450 - nn;;;
FCS45058;nn;FCS450 - nn;;;
FCS45059;nn;FCS450 - nn;;;
FCS45060;nn;FCS450 - nn;;;
FCS45061;nn;FCS450 - nn;;;
FCS45062;Germany;FCS450 - Germany;;;
FCS45063;nn;FCS450 - nn;;;
FCS45064;nn;FCS450 - nn;;;
FCS45065;nn;FCS450 - nn;;;
FCS45066;nn;FCS450 - nn;;;
FCS45067;nn;FCS450 - nn;;;
FCS45068;nn;FCS450 - nn;;;
FCS45069;nn;FCS450 - nn;;;
FCS45070;nn;FCS450 - nn;;;
FCS45071;nn;FCS450 - nn;;;
FCS45072;nn;FCS450 - nn;;;
FCS45073;nn;FCS450 - nn;;;
FCS45074;nn;FCS450 - nn;;;
FCS45075;nn;FCS450 - nn;;;
FCS45076;nn;FCS450 - nn;;;
FCS45077;nn;FCS450 - nn;;;
FCS45078;Alabama-Link;FCS450 - Alabama-Link;;;
FCS45079;nn;FCS450 - nn;;;
FCS45080;REG0;FCS450 - REG0;;;
FCS45081;REG1;FCS450 - REG1;;;
FCS45082;REG2;FCS450 - REG2;;;
FCS45083;REG3;FCS450 - REG3;;;
FCS45084;REG4;FCS450 - REG4;;;
FCS45085;REG5;FCS450 - REG5;;;
FCS45086;REG6;FCS450 - REG6;;;
FCS45087;REG7;FCS450 - REG7;;;
FCS45088;REG8;FCS450 - REG8;;;
FCS45089;REG9;FCS450 - REG9;;;
FCS45090;CLEAR DG-ID;FCS450 - CLEAR DG-ID;;;
FCS45091;Test-1;FCS450 - Test-1;;;
FCS45092;Test-2;FCS450 - Test-2;;;
FCS45093;Test-3;FCS450 - Test-3;;;
FCS45094;Test-4;FCS450 - Test-4;;;
FCS45095;Test-5;FCS450 - Test-5;;;
FCS45096;Test-6;FCS450 - Test-6;;;
FCS45097;Test-7;FCS450 - Test-7;;;
FCS45098;Test-8;FCS450 - Test-8;;;
FCS45099;Test-9;FCS450 - Test-9;;;
FCS53000;nn;FCS530 - nn;;;
FCS53001;DR-2X;FCS530 - DR-2X;;;
FCS53002;Europe;FCS530 - Europe;;;
@ -1919,16 +2119,16 @@ FCS53014;WW-spanish;FCS530 - WW-spanish;;;
FCS53015;WW-portuguese;FCS530 - WW-portuguese;;;
FCS53016;WW-italian;FCS530 - WW-italian;;;
FCS53017;Netherlands;FCS530 - Netherlands;;;
FCS53018;Belgium;FCS530 - Belgium;;;
FCS53018;nn;FCS530 - nn;;;
FCS53019;nn;FCS530 - nn;;;
FCS53020;DACH;FCS530 - DACH;;;
FCS53021;World-Wide;FCS530 - World-Wide;;;
FCS53022;Italy;FCS530 - Italy;;;
FCS53023;France;FCS530 - France;;;
FCS53023;nn;FCS530 - nn;;;
FCS53024;Spain;FCS530 - Spain;;;
FCS53025;UK-2;FCS530 - UK-2;;;
FCS53026;Romania;FCS530 - Romania;;;
FCS53027;Portugal;FCS530 - Portugal;;;
FCS53027;nn;FCS530 - nn;;;
FCS53028;Switzerland;FCS530 - Switzerland;;;
FCS53029;nn;FCS530 - nn;;;
FCS53030;nn;FCS530 - nn;;;
@ -1936,9 +2136,9 @@ FCS53031;North-America;FCS530 - North-America;;;
FCS53032;Austria;FCS530 - Austria;;;
FCS53033;nn;FCS530 - nn;;;
FCS53034;Mexico;FCS530 - Mexico;;;
FCS53035;United Kingdom;FCS530 - United Kingdom;;;
FCS53035;United-Kingdom-1;FCS530 - United-Kingdom-1;;;
FCS53036;nn;FCS530 - nn;;;
FCS53037;nn;FCS530 - nn;;;
FCS53037;US-America-Link;FCS530 - US-America-Link;;;
FCS53038;nn;FCS530 - nn;;;
FCS53039;nn;FCS530 - nn;;;
FCS53040;nn;FCS530 - nn;;;
@ -1960,8 +2160,8 @@ FCS53055;nn;FCS530 - nn;;;
FCS53056;nn;FCS530 - nn;;;
FCS53057;nn;FCS530 - nn;;;
FCS53058;nn;FCS530 - nn;;;
FCS53059;Moldova;FCS530 - Moldova;;;
FCS53060;Poland;FCS530 - Poland;;;
FCS53059;nn;FCS530 - nn;;;
FCS53060;nn;FCS530 - nn;;;
FCS53061;nn;FCS530 - nn;;;
FCS53062;Germany;FCS530 - Germany;;;
FCS53063;nn;FCS530 - nn;;;
@ -1973,24 +2173,24 @@ FCS53068;nn;FCS530 - nn;;;
FCS53069;nn;FCS530 - nn;;;
FCS53070;nn;FCS530 - nn;;;
FCS53071;nn;FCS530 - nn;;;
FCS53072;Brazil;FCS530 - Brazil;;;
FCS53072;nn;FCS530 - nn;;;
FCS53073;nn;FCS530 - nn;;;
FCS53074;nn;FCS530 - nn;;;
FCS53075;nn;FCS530 - nn;;;
FCS53076;nn;FCS530 - nn;;;
FCS53075;Bridge-UK-TG235;FCS530 - Bridge-UK-TG235;;;
FCS53076;America-RC;FCS530 - America-RC;;;
FCS53077;nn;FCS530 - nn;;;
FCS53078;nn;FCS530 - nn;;;
FCS53079;nn;FCS530 - nn;;;
FCS53080;REG0;FCS530 - REG0;;;
FCS53081;REG1;FCS530 - REG1;;;
FCS53082;REG2;FCS530 - REG2;;;
FCS53083;REG3;FCS530 - REG3;;;
FCS53084;REG4;FCS530 - REG4;;;
FCS53085;REG5;FCS530 - REG5;;;
FCS53086;REG6;FCS530 - REG6;;;
FCS53087;REG7;FCS530 - REG7;;;
FCS53088;REG8;FCS530 - REG8;;;
FCS53089;REG9;FCS530 - REG9;;;
FCS53078;Alabama-Link;FCS530 - Alabama-Link;;;
FCS53079;QuadNet-Array;FCS530 - QuadNet-Array;;;
FCS53080;NZ-Canterbury-NZ;FCS530 - NZ-Canterbury-NZ;;;
FCS53081;ZL-1;FCS530 - ZL-1;;;
FCS53082;ZL-2;FCS530 - ZL-2;;;
FCS53083;ZL-3;FCS530 - ZL-3;;;
FCS53084;ZL-4;FCS530 - ZL-4;;;
FCS53085;nn;FCS530 - nn;;;
FCS53086;nn;FCS530 - nn;;;
FCS53087;nn;FCS530 - nn;;;
FCS53088;nn;FCS530 - nn;;;
FCS53089;IPSC2 ZL;FCS530 - IPSC2 ZL;;;
FCS53090;CLEAR DG-ID;FCS530 - CLEAR DG-ID;;;
FCS53091;Test-1;FCS530 - Test-1;;;
FCS53092;Test-2;FCS530 - Test-2;;;
@ -2097,7 +2297,7 @@ FCS72492;Test-2;FCS724 - Test-2;;;
FCS72493;Test-3;FCS724 - Test-3;;;
FCS72494;Test-4;FCS724 - Test-4;;;
FCS72495;Test-5;FCS724 - Test-5;;;
FCS72496;Test-6;FCS724 - Test-6;;;
FCS72496;Brazil;FCS724 - Brazil;;;
FCS72497;Test-7;FCS724 - Test-7;;;
FCS72498;Test-8;FCS724 - Test-8;;;
FCS72499;Test-9;FCS724 - Test-9;;;

View file

@ -270,6 +270,9 @@ void CGPS::transmitGPS(const unsigned char* source)
case 0x30U:
::strcpy(radio, "FT-3D");
break;
case 0x33U:
::strcpy(radio, "FT-5D");
break;
default:
::sprintf(radio, "0x%02X", m_buffer[4U]);
break;

View file

@ -161,7 +161,7 @@ void Log(unsigned int level, const char* fmt, ...)
struct tm* tm = ::gmtime(&now.tv_sec);
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03ld ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000L);
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03lld ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000LL);
#endif
va_list vl;

View file

@ -23,9 +23,22 @@ DGIdGateway: $(OBJECTS)
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
DGIdGateway.o: GitVersion.h FORCE
.PHONY: GitVersion.h
FORCE:
install:
install -m 755 DGIdGateway /usr/local/bin/
clean:
$(RM) DGIdGateway *.o *.d *.bak *~
$(RM) DGIdGateway *.o *.d *.bak *~ GitVersion.h
GitVersion.h:
ifneq ("$(wildcard ../.git/index)","")
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
else
echo "const char *gitversion = \"0000000000000000000000000000000000000000\";" > $@
endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2006-2016,2020,2024 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
@ -28,34 +28,25 @@
#if defined(HAVE_LOG_H)
#include "Log.h"
#else
#define LogMessage(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__)
#define LogError(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__)
#define LogInfo(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__)
#endif
CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) :
m_address_save(address),
m_port_save(port),
m_counter(0U)
CUDPSocket::CUDPSocket(const std::string& address, unsigned short port) :
m_localAddress(address),
m_localPort(port),
m_fd(-1),
m_af(AF_UNSPEC)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::CUDPSocket(unsigned int port) :
m_address_save(),
m_port_save(port),
m_counter(0U)
CUDPSocket::CUDPSocket(unsigned short port) :
m_localAddress(),
m_localPort(port),
m_fd(-1),
m_af(AF_UNSPEC)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::~CUDPSocket()
@ -79,7 +70,7 @@ void CUDPSocket::shutdown()
#endif
}
int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& address_length)
int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockaddr_storage& addr, unsigned int& address_length)
{
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
@ -87,15 +78,15 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_
return lookup(hostname, port, addr, address_length, hints);
}
int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& address_length, struct addrinfo& hints)
int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockaddr_storage& addr, unsigned int& address_length, struct addrinfo& hints)
{
std::string portstr = std::to_string(port);
struct addrinfo *res;
/* port is always digits, no needs to lookup service */
/* Port is always digits, no needs to lookup service */
hints.ai_flags |= AI_NUMERICSERV;
int err = getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
int err = ::getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
if (err != 0) {
sockaddr_in* paddr = (sockaddr_in*)&addr;
::memset(paddr, 0x00U, address_length = sizeof(sockaddr_in));
@ -108,7 +99,7 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_
::memcpy(&addr, res->ai_addr, address_length = res->ai_addrlen);
freeaddrinfo(res);
::freeaddrinfo(res);
return 0;
}
@ -120,33 +111,33 @@ bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& ad
if (type == IMT_ADDRESS_AND_PORT) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
}
} else if (type == IMT_ADDRESS_ONLY) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
}
} else {
return false;
@ -162,33 +153,34 @@ bool CUDPSocket::isNone(const sockaddr_storage& addr)
bool CUDPSocket::open(const sockaddr_storage& address)
{
return open(address.ss_family);
m_af = address.ss_family;
return open();
}
bool CUDPSocket::open(unsigned int af)
bool CUDPSocket::open()
{
return open(0, af, m_address_save, m_port_save);
}
assert(m_fd == -1);
bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port)
{
sockaddr_storage addr;
unsigned int addrlen;
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = af;
hints.ai_family = m_af;
/* to determine protocol family, call lookup() first. */
int err = lookup(address, port, addr, addrlen, hints);
// To determine protocol family, call lookup() on the local address first.
int err = lookup(m_localAddress, m_localPort, addr, addrlen, hints);
if (err != 0) {
LogError("The local address is invalid - %s", address.c_str());
LogError("The local address is invalid - %s", m_localAddress.c_str());
return false;
}
int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0);
if (fd < 0) {
m_af = addr.ss_family;
m_fd = ::socket(m_af, SOCK_DGRAM, 0);
if (m_fd < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
#else
@ -197,62 +189,51 @@ bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std
return false;
}
m_address[index] = address;
m_port[index] = port;
m_af[index] = addr.ss_family;
m_fd[index] = fd;
if (port > 0U) {
if (m_localPort > 0U) {
int reuse = 1;
if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError());
#else
LogError("Cannot set the UDP socket option, err: %d", errno);
#endif
close();
return false;
}
if (::bind(fd, (sockaddr*)&addr, addrlen) == -1) {
if (::bind(m_fd, (sockaddr*)&addr, addrlen) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
#else
LogError("Cannot bind the UDP address, err: %d", errno);
#endif
close();
return false;
}
LogInfo("Opening UDP port on %u", port);
LogInfo("Opening UDP port on %hu", m_localPort);
}
return true;
}
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length)
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &addressLength)
{
assert(buffer != NULL);
assert(length > 0U);
assert(m_fd >= 0);
// Check that the readfrom() won't block
int i, n;
struct pollfd pfd[UDP_SOCKET_MAX];
for (i = n = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] >= 0) {
pfd[n].fd = m_fd[i];
pfd[n].events = POLLIN;
n++;
}
}
// no socket descriptor to receive
if (n == 0)
return 0;
struct pollfd pfd;
pfd.fd = m_fd;
pfd.events = POLLIN;
pfd.revents = 0;
// Return immediately
#if defined(_WIN32) || defined(_WIN64)
int ret = WSAPoll(pfd, n, 0);
int ret = WSAPoll(&pfd, 1, 0);
#else
int ret = ::poll(pfd, n, 0);
int ret = ::poll(&pfd, 1, 0);
#endif
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
@ -263,14 +244,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
return -1;
}
int index;
for (i = 0; i < n; i++) {
// round robin
index = (i + m_counter) % n;
if (pfd[index].revents & POLLIN)
break;
}
if (i == n)
if ((pfd.revents & POLLIN) == 0)
return 0;
#if defined(_WIN32) || defined(_WIN64)
@ -280,9 +254,9 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
#endif
#if defined(_WIN32) || defined(_WIN64)
int len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#else
ssize_t len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#endif
if (len <= 0) {
#if defined(_WIN32) || defined(_WIN64)
@ -291,7 +265,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
LogError("Error returned from recvfrom, err: %d", errno);
if (len == -1 && errno == ENOTSOCK) {
LogMessage("Re-opening UDP port on %u", m_port);
LogMessage("Re-opening UDP port on %hu", m_localPort);
close();
open();
}
@ -299,43 +273,39 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
return -1;
}
m_counter++;
address_length = size;
addressLength = size;
return len;
}
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length)
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addressLength)
{
assert(buffer != NULL);
assert(length > 0U);
assert(m_fd >= 0);
bool result = false;
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] < 0 || m_af[i] != address.ss_family)
continue;
#if defined(_WIN32) || defined(_WIN64)
int ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, addressLength);
#else
ssize_t ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, addressLength);
#endif
if (ret < 0) {
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from sendto, err: %lu", ::GetLastError());
LogError("Error returned from sendto, err: %lu", ::GetLastError());
#else
LogError("Error returned from sendto, err: %d", errno);
LogError("Error returned from sendto, err: %d", errno);
#endif
} else {
} else {
#if defined(_WIN32) || defined(_WIN64)
if (ret == int(length))
result = true;
if (ret == int(length))
result = true;
#else
if (ret == ssize_t(length))
result = true;
if (ret == ssize_t(length))
result = true;
#endif
}
}
return result;
@ -343,18 +313,13 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const s
void CUDPSocket::close()
{
for (int i = 0; i < UDP_SOCKET_MAX; i++)
close(m_fd[i]);
}
void CUDPSocket::close(const unsigned int index)
{
if (m_fd[index] >= 0) {
if (m_fd >= 0) {
#if defined(_WIN32) || defined(_WIN64)
::closesocket(m_fd[index]);
::closesocket(m_fd);
#else
::close(m_fd[index]);
::close(m_fd);
#endif
m_fd[index] = -1;
m_fd = -1;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2011,2013,2015,2016,2020,2024 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
@ -35,10 +35,6 @@
#include <ws2tcpip.h>
#endif
#if !defined(UDP_SOCKET_MAX)
#define UDP_SOCKET_MAX 1
#endif
enum IPMATCHTYPE {
IMT_ADDRESS_AND_PORT,
IMT_ADDRESS_ONLY
@ -46,38 +42,38 @@ enum IPMATCHTYPE {
class CUDPSocket {
public:
CUDPSocket(const std::string& address, unsigned int port = 0U);
CUDPSocket(unsigned int port = 0U);
CUDPSocket(const std::string& address, unsigned short port = 0U);
CUDPSocket(unsigned short port = 0U);
~CUDPSocket();
bool open(unsigned int af = AF_UNSPEC);
bool open();
bool open(const sockaddr_storage& address);
bool open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port);
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length);
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length);
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &addressLength);
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addressLength);
void close();
void close(const unsigned int index);
static void startup();
static void shutdown();
static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length);
static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length, struct addrinfo& hints);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& addressLength);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& addressLength, struct addrinfo& hints);
static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IMT_ADDRESS_AND_PORT);
static bool isNone(const sockaddr_storage& addr);
private:
std::string m_address_save;
unsigned short m_port_save;
std::string m_address[UDP_SOCKET_MAX];
unsigned short m_port[UDP_SOCKET_MAX];
unsigned int m_af[UDP_SOCKET_MAX];
int m_fd[UDP_SOCKET_MAX];
unsigned int m_counter;
std::string m_localAddress;
unsigned short m_localPort;
#if defined(_WIN32) || defined(_WIN64)
SOCKET m_fd;
int m_af;
#else
int m_fd;
sa_family_t m_af;
#endif
};
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015-2021,2023,2024 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,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20201108";
const char* VERSION = "20240129";
#endif

View file

@ -47,8 +47,8 @@ const unsigned char YSF_CM_INDIVIDUAL = 0x03U;
const unsigned char YSF_MR_NOT_BUSY = 0x01U;
const unsigned char YSF_MR_BUSY = 0x02U;
const unsigned int FCS_PORT = 62500U;
const unsigned short FCS_PORT = 62500U;
const unsigned int IMRS_PORT = 21110U;
const unsigned short IMRS_PORT = 21110U;
#endif

File diff suppressed because it is too large Load diff

View file

@ -27,7 +27,7 @@
const unsigned int BUFFER_LENGTH = 200U;
CYSFNetwork::CYSFNetwork(const std::string& localAddress, unsigned int localPort, const std::string& name, const sockaddr_storage& addr, unsigned int addrLen, const std::string& callsign, bool debug) :
CYSFNetwork::CYSFNetwork(const std::string& localAddress, unsigned short localPort, const std::string& name, const sockaddr_storage& addr, unsigned int addrLen, const std::string& callsign, bool debug) :
m_socket(localAddress, localPort),
m_debug(debug),
m_addr(addr),
@ -56,7 +56,7 @@ m_state(DS_NOTOPEN)
}
}
CYSFNetwork::CYSFNetwork(unsigned int localPort, const std::string& name, const sockaddr_storage& addr, unsigned int addrLen, const std::string& callsign, bool statc, bool debug) :
CYSFNetwork::CYSFNetwork(unsigned short localPort, const std::string& name, const sockaddr_storage& addr, unsigned int addrLen, const std::string& callsign, bool statc, bool debug) :
m_socket(localPort),
m_debug(debug),
m_addr(addr),

View file

@ -30,8 +30,8 @@
class CYSFNetwork : public CDGIdNetwork {
public:
CYSFNetwork(const std::string& localAddress, unsigned int localPort, const std::string& name, const sockaddr_storage& addr, unsigned int addrLen, const std::string& callsign, bool debug);
CYSFNetwork(unsigned int localPort, const std::string& name, const sockaddr_storage& addr, unsigned int addrLen, const std::string& callsign, bool statc, bool debug);
CYSFNetwork(const std::string& localAddress, unsigned short localPort, const std::string& name, const sockaddr_storage& addr, unsigned int addrLen, const std::string& callsign, bool debug);
CYSFNetwork(unsigned short localPort, const std::string& name, const sockaddr_storage& addr, unsigned int addrLen, const std::string& callsign, bool statc, bool debug);
virtual ~CYSFNetwork();
virtual std::string getDesc(unsigned int dgId);

View file

@ -58,7 +58,7 @@ bool CYSFReflectors::load()
if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL && p6 != NULL) {
std::string host = std::string(p4);
unsigned int port = (unsigned int)::atoi(p5);
unsigned short port = (unsigned short)::atoi(p5);
if (::strstr(p1, "YCS") == NULL && ::strstr(p2, "YCS") == NULL) {
sockaddr_storage addr;

38
DGIdGateway/prebuild.cmd Normal file
View file

@ -0,0 +1,38 @@
@echo off
REM This pre-build file is for MSVS VC++. It parses the git master hash and
REM converts it into GitVersion.h for compiling into builds. [George M1GEO]
cd %1
setlocal enabledelayedexpansion
set HEADFILE=..\.git\HEAD
set HASHFILE=0
if exist %HEADFILE% (
for /F "tokens=4 delims=/:" %%a in ('type %HEADFILE%') do set HEADBRANCH=%%a
set HASHFILE=.git\refs\heads\!HEADBRANCH!
echo Found Git HEAD file: %HEADFILE%
echo Git HEAD branch: !HEADBRANCH!
echo Git HASH file: !HASHFILE!
call :USEHASH
) else (
echo No head file :(
call :USENULL
)
goto :EOF
:USENULL
set GITHASH=0000000000000000000000000000000000000000
goto :WRITEGITVERSIONHEADER
:USEHASH
for /f %%i in ('type !HASHFILE!') do set GITHASH=%%i
goto :WRITEGITVERSIONHEADER
:WRITEGITVERSIONHEADER
echo // File contains Git commit ID SHA1 present at buildtime (prebuild.cmd) > GitVersion.h
echo const char *gitversion = "%GITHASH%"; >> GitVersion.h
echo Current Git HASH: %GITHASH%
goto :FINISHED
:FINISHED
echo GitVersion.h written...

View file

@ -1,4 +1,4 @@
SUBDIRS = DGIdGateway YSFGateway YSFParrot YSFReflector
SUBDIRS = DGIdGateway YSFGateway YSFParrot
CLEANDIRS = $(SUBDIRS:%=clean-%)
INSTALLDIRS = $(SUBDIRS:%=install-%)

View file

@ -6,12 +6,10 @@ The YSF Gateway allows for use of Yaesu Wires-X commands from the radio to contr
The DG-ID Gateway allows the use of the DG-ID setting on the radio to control access to the different System Fusion network systems. It optionally sends System Fusion GPS information to aprs.fi.
The Reflector retransmits any received System Fusion data to other MMDVM Hosts or Gateways logged into the reflector at the time. It also provides status information to potential clients.
The Gateways and the Reflector have ini files that contain the parameters for running the software. The filename of the ini file is passed as a parameter on the command line. The Parrot takes the UDP port number to listen on as an argument.
The Gateways have ini files that contain the parameters for running the software. The filename of the ini file is passed as a parameter on the command line. The Parrot takes the UDP port number to listen on as an argument.
The MMDVM .ini file should have the IP address and port number of the client in the [System Fusion Network] settings.
They build on 32-bit and 64-bit Linux as well as on Windows using Visual Studio 2019 on x86 and x64.
This software is licenced under the GPL v2 and is intended for amateur and educational use only. Use of this software for commercial purposes is strictly forbidden.
This software is licenced under the GPL v2 and is primarily intended for amateur and educational use.

View file

@ -5,8 +5,6 @@ VisualStudioVersion = 16.0.30406.217
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "YSFParrot", "YSFParrot\YSFParrot.vcxproj", "{D3BBE5EC-91F7-457B-B782-B616B918708F}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "YSFReflector", "YSFReflector\YSFReflector.vcxproj", "{317D87F1-3485-4739-9F94-A07738B8E19D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "YSFGateway", "YSFGateway\YSFGateway.vcxproj", "{4F82857B-D2CC-48DC-91A8-6275BDD3081B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DGIdGateway", "DGIdGateway\DGIdGateway.vcxproj", "{1A4724B0-257E-45E9-943D-EABC56A1027E}"
@ -27,14 +25,6 @@ Global
{D3BBE5EC-91F7-457B-B782-B616B918708F}.Release|x64.Build.0 = Release|x64
{D3BBE5EC-91F7-457B-B782-B616B918708F}.Release|x86.ActiveCfg = Release|Win32
{D3BBE5EC-91F7-457B-B782-B616B918708F}.Release|x86.Build.0 = Release|Win32
{317D87F1-3485-4739-9F94-A07738B8E19D}.Debug|x64.ActiveCfg = Debug|x64
{317D87F1-3485-4739-9F94-A07738B8E19D}.Debug|x64.Build.0 = Debug|x64
{317D87F1-3485-4739-9F94-A07738B8E19D}.Debug|x86.ActiveCfg = Debug|Win32
{317D87F1-3485-4739-9F94-A07738B8E19D}.Debug|x86.Build.0 = Debug|Win32
{317D87F1-3485-4739-9F94-A07738B8E19D}.Release|x64.ActiveCfg = Release|x64
{317D87F1-3485-4739-9F94-A07738B8E19D}.Release|x64.Build.0 = Release|x64
{317D87F1-3485-4739-9F94-A07738B8E19D}.Release|x86.ActiveCfg = Release|Win32
{317D87F1-3485-4739-9F94-A07738B8E19D}.Release|x86.Build.0 = Release|Win32
{4F82857B-D2CC-48DC-91A8-6275BDD3081B}.Debug|x64.ActiveCfg = Debug|x64
{4F82857B-D2CC-48DC-91A8-6275BDD3081B}.Debug|x64.Build.0 = Debug|x64
{4F82857B-D2CC-48DC-91A8-6275BDD3081B}.Debug|x86.ActiveCfg = Debug|Win32

View file

@ -25,7 +25,7 @@
#include <cstring>
#include <cmath>
CAPRSWriter::CAPRSWriter(const std::string& callsign, const std::string& rptSuffix, const std::string& address, unsigned int port, const std::string& suffix, bool debug) :
CAPRSWriter::CAPRSWriter(const std::string& callsign, const std::string& rptSuffix, const std::string& address, unsigned short port, const std::string& suffix, bool debug) :
m_idTimer(1000U),
m_callsign(callsign),
m_debug(debug),
@ -35,6 +35,7 @@ m_latitude(0.0F),
m_longitude(0.0F),
m_height(0),
m_desc(),
m_symbol(),
m_suffix(suffix),
m_aprsAddr(),
m_aprsAddrLen(0U),
@ -63,11 +64,12 @@ CAPRSWriter::~CAPRSWriter()
{
}
void CAPRSWriter::setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc)
void CAPRSWriter::setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc, const std::string& symbol)
{
m_txFrequency = txFrequency;
m_rxFrequency = rxFrequency;
m_desc = desc;
m_symbol = symbol;
}
void CAPRSWriter::setStaticLocation(float latitude, float longitude, int height)
@ -158,12 +160,15 @@ void CAPRSWriter::write(const unsigned char* source, const char* type, unsigned
case 0x24U:
case 0x28U:
case 0x30U:
case 0x33U:
symbol = '[';
break;
case 0x25U:
case 0x29U:
case 0x31U:
symbol = '>';
break;
case 0x20U:
case 0x26U:
symbol = 'r';
break;
@ -229,19 +234,19 @@ void CAPRSWriter::sendIdFrameFixed()
char desc[200U];
if (m_txFrequency != 0U) {
float offset = float(int(m_rxFrequency) - int(m_txFrequency)) / 1000000.0F;
::sprintf(desc, "MMDVM Voice %.5LfMHz %c%.4lfMHz%s%s",
::sprintf(desc, "MMDVM Voice (C4FM) %.5LfMHz %c%.4lfMHz%s%s",
(long double)(m_txFrequency) / 1000000.0F,
offset < 0.0F ? '-' : '+',
::fabs(offset), m_desc.empty() ? "" : ", ", m_desc.c_str());
} else {
::sprintf(desc, "MMDVM Voice%s%s", m_desc.empty() ? "" : ", ", m_desc.c_str());
::sprintf(desc, "MMDVM Voice (C4FM)%s%s", m_desc.empty() ? "" : ", ", m_desc.c_str());
}
const char* band = "4m";
if (m_txFrequency >= 1200000000U)
band = "1.2";
band = "23cm/1.2GHz";
else if (m_txFrequency >= 420000000U)
band = "440";
band = "70cm";
else if (m_txFrequency >= 144000000U)
band = "2m";
else if (m_txFrequency >= 50000000U)
@ -265,17 +270,21 @@ void CAPRSWriter::sendIdFrameFixed()
::sprintf(lon, "%08.2lf", longitude);
std::string server = m_callsign;
std::string symbol = m_symbol;
size_t pos = server.find_first_of('-');
if (pos == std::string::npos)
server.append("-S");
else
server.append("S");
if (symbol.empty())
symbol.append("D&");
char output[500U];
::sprintf(output, "%s>APDG03,TCPIP*,qAC,%s:!%s%cD%s%c&/A=%06.0f%s %s\r\n",
::sprintf(output, "%s>APDG03,TCPIP*,qAC,%s:!%s%c%c%s%c%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',
lat, (m_latitude < 0.0F) ? 'S' : 'N', symbol[0],
lon, (m_longitude < 0.0F) ? 'W' : 'E', symbol[1],
float(m_height) * 3.28F, band, desc);
if (m_debug)
@ -298,8 +307,11 @@ void CAPRSWriter::sendIdFrameMobile()
return;
#endif
#if GPSD_API_MAJOR_VERSION >= 10
if (m_gpsdData.fix.status != STATUS_FIX)
#else
if (m_gpsdData.status != STATUS_FIX)
#endif
return;
bool latlonSet = (m_gpsdData.set & LATLON_SET) == LATLON_SET;
@ -323,19 +335,19 @@ void CAPRSWriter::sendIdFrameMobile()
char desc[200U];
if (m_txFrequency != 0U) {
float offset = float(int(m_rxFrequency) - int(m_txFrequency)) / 1000000.0F;
::sprintf(desc, "MMDVM Voice %.5LfMHz %c%.4lfMHz%s%s",
::sprintf(desc, "MMDVM Voice (C4FM) %.5LfMHz %c%.4lfMHz%s%s",
(long double)(m_txFrequency) / 1000000.0F,
offset < 0.0F ? '-' : '+',
::fabs(offset), m_desc.empty() ? "" : ", ", m_desc.c_str());
} else {
::sprintf(desc, "MMDVM Voice%s%s", m_desc.empty() ? "" : ", ", m_desc.c_str());
::sprintf(desc, "MMDVM Voice (C4FM)%s%s", m_desc.empty() ? "" : ", ", m_desc.c_str());
}
const char* band = "4m";
if (m_txFrequency >= 1200000000U)
band = "1.2";
band = "23cm/1.2GHz";
else if (m_txFrequency >= 420000000U)
band = "440";
band = "70cm";
else if (m_txFrequency >= 144000000U)
band = "2m";
else if (m_txFrequency >= 50000000U)
@ -359,17 +371,21 @@ void CAPRSWriter::sendIdFrameMobile()
::sprintf(lon, "%08.2lf", longitude);
std::string server = m_callsign;
size_t pos = server.find_first_of('-');
if (pos == std::string::npos)
server.append("-S");
else
server.append("S");
std::string symbol = m_symbol;
size_t pos = server.find_first_of('-');
if (pos == std::string::npos)
server.append("-S");
else
server.append("S");
if (symbol.empty())
symbol.append("D&");
char output[500U];
::sprintf(output, "%s>APDG03,TCPIP*,qAC,%s:!%s%cD%s%c&",
::sprintf(output, "%s>APDG03,TCPIP*,qAC,%s:!%s%c%c%s%c%c",
m_callsign.c_str(), server.c_str(),
lat, (rawLatitude < 0.0F) ? 'S' : 'N',
lon, (rawLongitude < 0.0F) ? 'W' : 'E');
lat, (rawLatitude < 0.0F) ? 'S' : 'N', symbol[0],
lon, (rawLongitude < 0.0F) ? 'W' : 'E', symbol[1]);
if (bearingSet && velocitySet)
::sprintf(output + ::strlen(output), "%03.0f/%03.0f", rawBearing, rawVelocity * 0.539957F);

View file

@ -42,12 +42,12 @@
class CAPRSWriter {
public:
CAPRSWriter(const std::string& callsign, const std::string& rptSuffix, const std::string& address, unsigned int port, const std::string& suffix, bool debug);
CAPRSWriter(const std::string& callsign, const std::string& rptSuffix, const std::string& address, unsigned short port, const std::string& suffix, bool debug);
~CAPRSWriter();
bool open();
void setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc);
void setInfo(unsigned int txFrequency, unsigned int rxFrequency, const std::string& desc, const std::string& symbol);
void setStaticLocation(float latitude, float longitude, int height);
@ -69,6 +69,7 @@ private:
float m_longitude;
int m_height;
std::string m_desc;
std::string m_symbol;
std::string m_suffix;
sockaddr_storage m_aprsAddr;
unsigned int m_aprsAddrLen;

View file

@ -70,6 +70,7 @@ m_aprsAddress(),
m_aprsPort(0U),
m_aprsSuffix(),
m_aprsDescription(),
m_aprsSymbol("/r"),
m_networkStartup(),
m_networkOptions(),
m_networkInactivityTimeout(0U),
@ -183,11 +184,11 @@ bool CConf::read()
else if (::strcmp(key, "RptAddress") == 0)
m_rptAddress = value;
else if (::strcmp(key, "RptPort") == 0)
m_rptPort = (unsigned int)::atoi(value);
m_rptPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "LocalAddress") == 0)
m_myAddress = value;
else if (::strcmp(key, "LocalPort") == 0)
m_myPort = (unsigned int)::atoi(value);
m_myPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "WiresXMakeUpper") == 0)
m_wiresXMakeUpper = ::atoi(value) == 1;
else if (::strcmp(key, "WiresXCommandPassthrough") == 0)
@ -230,11 +231,13 @@ bool CConf::read()
else if (::strcmp(key, "Address") == 0)
m_aprsAddress = value;
else if (::strcmp(key, "Port") == 0)
m_aprsPort = (unsigned int)::atoi(value);
m_aprsPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "Suffix") == 0)
m_aprsSuffix = value;
else if (::strcmp(key, "Description") == 0)
m_aprsDescription = value;
else if (::strcmp(key, "Symbol") == 0)
m_aprsSymbol = value;
} else if (section == SECTION_NETWORK) {
if (::strcmp(key, "Startup") == 0)
m_networkStartup = value;
@ -250,7 +253,7 @@ bool CConf::read()
if (::strcmp(key, "Enable") == 0)
m_ysfNetworkEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Port") == 0)
m_ysfNetworkPort = (unsigned int)::atoi(value);
m_ysfNetworkPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "Hosts") == 0)
m_ysfNetworkHosts = value;
else if (::strcmp(key, "ReloadTime") == 0)
@ -258,26 +261,26 @@ bool CConf::read()
else if (::strcmp(key, "ParrotAddress") == 0)
m_ysfNetworkParrotAddress = value;
else if (::strcmp(key, "ParrotPort") == 0)
m_ysfNetworkParrotPort = (unsigned int)::atoi(value);
m_ysfNetworkParrotPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "YSF2DMRAddress") == 0)
m_ysfNetworkYSF2DMRAddress = value;
else if (::strcmp(key, "YSF2DMRPort") == 0)
m_ysfNetworkYSF2DMRPort = (unsigned int)::atoi(value);
m_ysfNetworkYSF2DMRPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "YSF2NXDNAddress") == 0)
m_ysfNetworkYSF2NXDNAddress = value;
else if (::strcmp(key, "YSF2NXDNPort") == 0)
m_ysfNetworkYSF2NXDNPort = (unsigned int)::atoi(value);
m_ysfNetworkYSF2NXDNPort = (unsigned short)::atoi(value);
else if (::strcmp(key, "YSF2P25Address") == 0)
m_ysfNetworkYSF2P25Address = value;
else if (::strcmp(key, "YSF2P25Port") == 0)
m_ysfNetworkYSF2P25Port = (unsigned int)::atoi(value);
m_ysfNetworkYSF2P25Port = (unsigned short)::atoi(value);
} else if (section == SECTION_FCS_NETWORK) {
if (::strcmp(key, "Enable") == 0)
m_fcsNetworkEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Rooms") == 0)
m_fcsNetworkFile = value;
else if (::strcmp(key, "Port") == 0)
m_fcsNetworkPort = (unsigned int)::atoi(value);
m_fcsNetworkPort = (unsigned short)::atoi(value);
} else if (section == SECTION_GPSD) {
if (::strcmp(key, "Enable") == 0)
m_gpsdEnabled = ::atoi(value) == 1;
@ -289,7 +292,7 @@ bool CConf::read()
if (::strcmp(key, "Enable") == 0)
m_remoteCommandsEnabled = ::atoi(value) == 1;
else if (::strcmp(key, "Port") == 0)
m_remoteCommandsPort = (unsigned int)::atoi(value);
m_remoteCommandsPort = (unsigned short)::atoi(value);
}
}
@ -318,7 +321,7 @@ std::string CConf::getRptAddress() const
return m_rptAddress;
}
unsigned int CConf::getRptPort() const
unsigned short CConf::getRptPort() const
{
return m_rptPort;
}
@ -328,7 +331,7 @@ std::string CConf::getMyAddress() const
return m_myAddress;
}
unsigned int CConf::getMyPort() const
unsigned short CConf::getMyPort() const
{
return m_myPort;
}
@ -428,7 +431,7 @@ std::string CConf::getAPRSAddress() const
return m_aprsAddress;
}
unsigned int CConf::getAPRSPort() const
unsigned short CConf::getAPRSPort() const
{
return m_aprsPort;
}
@ -443,6 +446,11 @@ std::string CConf::getAPRSDescription() const
return m_aprsDescription;
}
std::string CConf::getAPRSSymbol() const
{
return m_aprsSymbol;
}
std::string CConf::getNetworkStartup() const
{
return m_networkStartup;
@ -473,7 +481,7 @@ bool CConf::getYSFNetworkEnabled() const
return m_ysfNetworkEnabled;
}
unsigned int CConf::getYSFNetworkPort() const
unsigned short CConf::getYSFNetworkPort() const
{
return m_ysfNetworkPort;
}
@ -493,7 +501,7 @@ std::string CConf::getYSFNetworkParrotAddress() const
return m_ysfNetworkParrotAddress;
}
unsigned int CConf::getYSFNetworkParrotPort() const
unsigned short CConf::getYSFNetworkParrotPort() const
{
return m_ysfNetworkParrotPort;
}
@ -503,7 +511,7 @@ std::string CConf::getYSFNetworkYSF2DMRAddress() const
return m_ysfNetworkYSF2DMRAddress;
}
unsigned int CConf::getYSFNetworkYSF2DMRPort() const
unsigned short CConf::getYSFNetworkYSF2DMRPort() const
{
return m_ysfNetworkYSF2DMRPort;
}
@ -513,7 +521,7 @@ std::string CConf::getYSFNetworkYSF2NXDNAddress() const
return m_ysfNetworkYSF2NXDNAddress;
}
unsigned int CConf::getYSFNetworkYSF2NXDNPort() const
unsigned short CConf::getYSFNetworkYSF2NXDNPort() const
{
return m_ysfNetworkYSF2NXDNPort;
}
@ -523,7 +531,7 @@ std::string CConf::getYSFNetworkYSF2P25Address() const
return m_ysfNetworkYSF2P25Address;
}
unsigned int CConf::getYSFNetworkYSF2P25Port() const
unsigned short CConf::getYSFNetworkYSF2P25Port() const
{
return m_ysfNetworkYSF2P25Port;
}
@ -539,7 +547,7 @@ std::string CConf::getFCSNetworkFile() const
return m_fcsNetworkFile;
}
unsigned int CConf::getFCSNetworkPort() const
unsigned short CConf::getFCSNetworkPort() const
{
return m_fcsNetworkPort;
}
@ -564,7 +572,7 @@ bool CConf::getRemoteCommandsEnabled() const
return m_remoteCommandsEnabled;
}
unsigned int CConf::getRemoteCommandsPort() const
unsigned short CConf::getRemoteCommandsPort() const
{
return m_remoteCommandsPort;
}

View file

@ -34,9 +34,9 @@ public:
std::string getSuffix() const;
unsigned int getId() const;
std::string getRptAddress() const;
unsigned int getRptPort() const;
unsigned short getRptPort() const;
std::string getMyAddress() const;
unsigned int getMyPort() const;
unsigned short getMyPort() const;
bool getWiresXMakeUpper() const;
bool getWiresXCommandPassthrough() const;
bool getDebug() const;
@ -62,9 +62,10 @@ public:
// The APRS section
bool getAPRSEnabled() const;
std::string getAPRSAddress() const;
unsigned int getAPRSPort() const;
unsigned short getAPRSPort() const;
std::string getAPRSSuffix() const;
std::string getAPRSDescription() const;
std::string getAPRSSymbol() const;
// The Network section
std::string getNetworkStartup() const;
@ -75,22 +76,22 @@ public:
// The YSF Network section
bool getYSFNetworkEnabled() const;
unsigned int getYSFNetworkPort() const;
unsigned short getYSFNetworkPort() const;
std::string getYSFNetworkHosts() const;
unsigned int getYSFNetworkReloadTime() const;
std::string getYSFNetworkParrotAddress() const;
unsigned int getYSFNetworkParrotPort() const;
unsigned short getYSFNetworkParrotPort() const;
std::string getYSFNetworkYSF2DMRAddress() const;
unsigned int getYSFNetworkYSF2DMRPort() const;
unsigned short getYSFNetworkYSF2DMRPort() const;
std::string getYSFNetworkYSF2NXDNAddress() const;
unsigned int getYSFNetworkYSF2NXDNPort() const;
unsigned short getYSFNetworkYSF2NXDNPort() const;
std::string getYSFNetworkYSF2P25Address() const;
unsigned int getYSFNetworkYSF2P25Port() const;
unsigned short getYSFNetworkYSF2P25Port() const;
// The FCS Network section
bool getFCSNetworkEnabled() const;
std::string getFCSNetworkFile() const;
unsigned int getFCSNetworkPort() const;
unsigned short getFCSNetworkPort() const;
// The GPSD section
bool getGPSDEnabled() const;
@ -99,7 +100,7 @@ public:
// The Remote Commands section
bool getRemoteCommandsEnabled() const;
unsigned int getRemoteCommandsPort() const;
unsigned short getRemoteCommandsPort() const;
private:
std::string m_file;
@ -107,9 +108,9 @@ private:
std::string m_suffix;
unsigned int m_id;
std::string m_rptAddress;
unsigned int m_rptPort;
unsigned short m_rptPort;
std::string m_myAddress;
unsigned int m_myPort;
unsigned short m_myPort;
bool m_wiresXMakeUpper;
bool m_wiresXCommandPassthrough;
bool m_debug;
@ -132,9 +133,10 @@ private:
bool m_aprsEnabled;
std::string m_aprsAddress;
unsigned int m_aprsPort;
unsigned short m_aprsPort;
std::string m_aprsSuffix;
std::string m_aprsDescription;
std::string m_aprsSymbol;
std::string m_networkStartup;
std::string m_networkOptions;
@ -143,28 +145,28 @@ private:
bool m_networkDebug;
bool m_ysfNetworkEnabled;
unsigned int m_ysfNetworkPort;
unsigned short m_ysfNetworkPort;
std::string m_ysfNetworkHosts;
unsigned int m_ysfNetworkReloadTime;
std::string m_ysfNetworkParrotAddress;
unsigned int m_ysfNetworkParrotPort;
unsigned short m_ysfNetworkParrotPort;
std::string m_ysfNetworkYSF2DMRAddress;
unsigned int m_ysfNetworkYSF2DMRPort;
unsigned short m_ysfNetworkYSF2DMRPort;
std::string m_ysfNetworkYSF2NXDNAddress;
unsigned int m_ysfNetworkYSF2NXDNPort;
unsigned short m_ysfNetworkYSF2NXDNPort;
std::string m_ysfNetworkYSF2P25Address;
unsigned int m_ysfNetworkYSF2P25Port;
unsigned short m_ysfNetworkYSF2P25Port;
bool m_fcsNetworkEnabled;
std::string m_fcsNetworkFile;
unsigned int m_fcsNetworkPort;
unsigned short m_fcsNetworkPort;
bool m_gpsdEnabled;
std::string m_gpsdAddress;
std::string m_gpsdPort;
bool m_remoteCommandsEnabled;
unsigned int m_remoteCommandsPort;
unsigned short m_remoteCommandsPort;
};
#endif

View file

@ -29,7 +29,7 @@ const char* FCS_VERSION = "MMDVM";
const unsigned int BUFFER_LENGTH = 200U;
CFCSNetwork::CFCSNetwork(unsigned int port, const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, const std::string& locator, unsigned int id, bool debug) :
CFCSNetwork::CFCSNetwork(unsigned short port, const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, const std::string& locator, unsigned int id, bool debug) :
m_socket(port),
m_debug(debug),
m_addr(),

View file

@ -36,7 +36,7 @@ enum FCS_STATE {
class CFCSNetwork {
public:
CFCSNetwork(unsigned int port, const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, const std::string& locator, unsigned int id, bool debug);
CFCSNetwork(unsigned short port, const std::string& callsign, unsigned int rxFrequency, unsigned int txFrequency, const std::string& locator, unsigned int id, bool debug);
~CFCSNetwork();
bool open();

File diff suppressed because it is too large Load diff

View file

@ -270,6 +270,9 @@ void CGPS::transmitGPS(const unsigned char* source)
case 0x30U:
::strcpy(radio, "FT-3D");
break;
case 0x33U:
::strcpy(radio, "FT-5D");
break;
default:
::sprintf(radio, "0x%02X", m_buffer[4U]);
break;

View file

@ -161,7 +161,7 @@ void Log(unsigned int level, const char* fmt, ...)
struct tm* tm = ::gmtime(&now.tv_sec);
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03ld ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000L);
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03lld ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000LL);
#endif
va_list vl;

View file

@ -22,9 +22,22 @@ YSFGateway: $(OBJECTS)
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
YSFGateway.o: GitVersion.h FORCE
.PHONY: GitVersion.h
FORCE:
install:
install -m 755 YSFGateway /usr/local/bin/
clean:
$(RM) YSFGateway *.o *.d *.bak *~
$(RM) YSFGateway *.o *.d *.bak *~ GitVersion.h
# Export the current git version if the index file exists, else 000...
GitVersion.h:
ifneq ("$(wildcard ../.git/index)","")
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
else
echo "const char *gitversion = \"0000000000000000000000000000000000000000\";" > $@
endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2006-2016,2020,2024 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
@ -28,34 +28,25 @@
#if defined(HAVE_LOG_H)
#include "Log.h"
#else
#define LogMessage(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__)
#define LogError(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__)
#define LogInfo(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__)
#endif
CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) :
m_address_save(address),
m_port_save(port),
m_counter(0U)
CUDPSocket::CUDPSocket(const std::string& address, unsigned short port) :
m_localAddress(address),
m_localPort(port),
m_fd(-1),
m_af(AF_UNSPEC)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::CUDPSocket(unsigned int port) :
m_address_save(),
m_port_save(port),
m_counter(0U)
CUDPSocket::CUDPSocket(unsigned short port) :
m_localAddress(),
m_localPort(port),
m_fd(-1),
m_af(AF_UNSPEC)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::~CUDPSocket()
@ -79,7 +70,7 @@ void CUDPSocket::shutdown()
#endif
}
int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& address_length)
int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockaddr_storage& addr, unsigned int& address_length)
{
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
@ -87,15 +78,15 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_
return lookup(hostname, port, addr, address_length, hints);
}
int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& address_length, struct addrinfo& hints)
int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockaddr_storage& addr, unsigned int& address_length, struct addrinfo& hints)
{
std::string portstr = std::to_string(port);
struct addrinfo *res;
/* port is always digits, no needs to lookup service */
/* Port is always digits, no needs to lookup service */
hints.ai_flags |= AI_NUMERICSERV;
int err = getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
int err = ::getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
if (err != 0) {
sockaddr_in* paddr = (sockaddr_in*)&addr;
::memset(paddr, 0x00U, address_length = sizeof(sockaddr_in));
@ -108,7 +99,7 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_
::memcpy(&addr, res->ai_addr, address_length = res->ai_addrlen);
freeaddrinfo(res);
::freeaddrinfo(res);
return 0;
}
@ -120,33 +111,33 @@ bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& ad
if (type == IMT_ADDRESS_AND_PORT) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
}
} else if (type == IMT_ADDRESS_ONLY) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
}
} else {
return false;
@ -162,33 +153,34 @@ bool CUDPSocket::isNone(const sockaddr_storage& addr)
bool CUDPSocket::open(const sockaddr_storage& address)
{
return open(address.ss_family);
m_af = address.ss_family;
return open();
}
bool CUDPSocket::open(unsigned int af)
bool CUDPSocket::open()
{
return open(0, af, m_address_save, m_port_save);
}
assert(m_fd == -1);
bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port)
{
sockaddr_storage addr;
unsigned int addrlen;
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = af;
hints.ai_family = m_af;
/* to determine protocol family, call lookup() first. */
int err = lookup(address, port, addr, addrlen, hints);
// To determine protocol family, call lookup() on the local address first.
int err = lookup(m_localAddress, m_localPort, addr, addrlen, hints);
if (err != 0) {
LogError("The local address is invalid - %s", address.c_str());
LogError("The local address is invalid - %s", m_localAddress.c_str());
return false;
}
int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0);
if (fd < 0) {
m_af = addr.ss_family;
m_fd = ::socket(m_af, SOCK_DGRAM, 0);
if (m_fd < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
#else
@ -197,62 +189,51 @@ bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std
return false;
}
m_address[index] = address;
m_port[index] = port;
m_af[index] = addr.ss_family;
m_fd[index] = fd;
if (port > 0U) {
if (m_localPort > 0U) {
int reuse = 1;
if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError());
#else
LogError("Cannot set the UDP socket option, err: %d", errno);
#endif
close();
return false;
}
if (::bind(fd, (sockaddr*)&addr, addrlen) == -1) {
if (::bind(m_fd, (sockaddr*)&addr, addrlen) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
#else
LogError("Cannot bind the UDP address, err: %d", errno);
#endif
close();
return false;
}
LogInfo("Opening UDP port on %u", port);
LogInfo("Opening UDP port on %hu", m_localPort);
}
return true;
}
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length)
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &addressLength)
{
assert(buffer != NULL);
assert(length > 0U);
assert(m_fd >= 0);
// Check that the readfrom() won't block
int i, n;
struct pollfd pfd[UDP_SOCKET_MAX];
for (i = n = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] >= 0) {
pfd[n].fd = m_fd[i];
pfd[n].events = POLLIN;
n++;
}
}
// no socket descriptor to receive
if (n == 0)
return 0;
struct pollfd pfd;
pfd.fd = m_fd;
pfd.events = POLLIN;
pfd.revents = 0;
// Return immediately
#if defined(_WIN32) || defined(_WIN64)
int ret = WSAPoll(pfd, n, 0);
int ret = WSAPoll(&pfd, 1, 0);
#else
int ret = ::poll(pfd, n, 0);
int ret = ::poll(&pfd, 1, 0);
#endif
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
@ -263,14 +244,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
return -1;
}
int index;
for (i = 0; i < n; i++) {
// round robin
index = (i + m_counter) % n;
if (pfd[index].revents & POLLIN)
break;
}
if (i == n)
if ((pfd.revents & POLLIN) == 0)
return 0;
#if defined(_WIN32) || defined(_WIN64)
@ -280,9 +254,9 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
#endif
#if defined(_WIN32) || defined(_WIN64)
int len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#else
ssize_t len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#endif
if (len <= 0) {
#if defined(_WIN32) || defined(_WIN64)
@ -291,7 +265,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
LogError("Error returned from recvfrom, err: %d", errno);
if (len == -1 && errno == ENOTSOCK) {
LogMessage("Re-opening UDP port on %u", m_port);
LogMessage("Re-opening UDP port on %hu", m_localPort);
close();
open();
}
@ -299,43 +273,39 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
return -1;
}
m_counter++;
address_length = size;
addressLength = size;
return len;
}
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length)
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addressLength)
{
assert(buffer != NULL);
assert(length > 0U);
assert(m_fd >= 0);
bool result = false;
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] < 0 || m_af[i] != address.ss_family)
continue;
#if defined(_WIN32) || defined(_WIN64)
int ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, addressLength);
#else
ssize_t ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, addressLength);
#endif
if (ret < 0) {
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from sendto, err: %lu", ::GetLastError());
LogError("Error returned from sendto, err: %lu", ::GetLastError());
#else
LogError("Error returned from sendto, err: %d", errno);
LogError("Error returned from sendto, err: %d", errno);
#endif
} else {
} else {
#if defined(_WIN32) || defined(_WIN64)
if (ret == int(length))
result = true;
if (ret == int(length))
result = true;
#else
if (ret == ssize_t(length))
result = true;
if (ret == ssize_t(length))
result = true;
#endif
}
}
return result;
@ -343,18 +313,13 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const s
void CUDPSocket::close()
{
for (int i = 0; i < UDP_SOCKET_MAX; i++)
close(m_fd[i]);
}
void CUDPSocket::close(const unsigned int index)
{
if (m_fd[index] >= 0) {
if (m_fd >= 0) {
#if defined(_WIN32) || defined(_WIN64)
::closesocket(m_fd[index]);
::closesocket(m_fd);
#else
::close(m_fd[index]);
::close(m_fd);
#endif
m_fd[index] = -1;
m_fd = -1;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2011,2013,2015,2016,2020,2024 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
@ -35,10 +35,6 @@
#include <ws2tcpip.h>
#endif
#if !defined(UDP_SOCKET_MAX)
#define UDP_SOCKET_MAX 1
#endif
enum IPMATCHTYPE {
IMT_ADDRESS_AND_PORT,
IMT_ADDRESS_ONLY
@ -46,38 +42,38 @@ enum IPMATCHTYPE {
class CUDPSocket {
public:
CUDPSocket(const std::string& address, unsigned int port = 0U);
CUDPSocket(unsigned int port = 0U);
CUDPSocket(const std::string& address, unsigned short port = 0U);
CUDPSocket(unsigned short port = 0U);
~CUDPSocket();
bool open(unsigned int af = AF_UNSPEC);
bool open();
bool open(const sockaddr_storage& address);
bool open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port);
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length);
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length);
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &addressLength);
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addressLength);
void close();
void close(const unsigned int index);
static void startup();
static void shutdown();
static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length);
static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length, struct addrinfo& hints);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& addressLength);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& addressLength, struct addrinfo& hints);
static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IMT_ADDRESS_AND_PORT);
static bool isNone(const sockaddr_storage& addr);
private:
std::string m_address_save;
unsigned short m_port_save;
std::string m_address[UDP_SOCKET_MAX];
unsigned short m_port[UDP_SOCKET_MAX];
unsigned int m_af[UDP_SOCKET_MAX];
int m_fd[UDP_SOCKET_MAX];
unsigned int m_counter;
std::string m_localAddress;
unsigned short m_localPort;
#if defined(_WIN32) || defined(_WIN64)
SOCKET m_fd;
int m_af;
#else
int m_fd;
sa_family_t m_af;
#endif
};
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015-2021,2023,2024 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,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20201108";
const char* VERSION = "20240129";
#endif

View file

@ -153,22 +153,22 @@ void CWiresX::setInfo(const std::string& name, unsigned int txFrequency, unsigne
m_header[i + 14U] = m_node.at(i);
}
void CWiresX::setParrot(const std::string& address, unsigned int port)
void CWiresX::setParrot(const std::string& address, unsigned short port)
{
m_reflectors.setParrot(address, port);
}
void CWiresX::setYSF2DMR(const std::string& address, unsigned int port)
void CWiresX::setYSF2DMR(const std::string& address, unsigned short port)
{
m_reflectors.setYSF2DMR(address, port);
}
void CWiresX::setYSF2NXDN(const std::string& address, unsigned int port)
void CWiresX::setYSF2NXDN(const std::string& address, unsigned short port)
{
m_reflectors.setYSF2NXDN(address, port);
}
void CWiresX::setYSF2P25(const std::string& address, unsigned int port)
void CWiresX::setYSF2P25(const std::string& address, unsigned short port)
{
m_reflectors.setYSF2P25(address, port);
}

View file

@ -51,10 +51,10 @@ public:
~CWiresX();
void setInfo(const std::string& name, unsigned int txFrequency, unsigned int rxFrequency);
void setParrot(const std::string& address, unsigned int port);
void setYSF2DMR(const std::string& address, unsigned int port);
void setYSF2NXDN(const std::string& address, unsigned int port);
void setYSF2P25(const std::string& address, unsigned int port);
void setParrot(const std::string& address, unsigned short port);
void setYSF2DMR(const std::string& address, unsigned short port);
void setYSF2NXDN(const std::string& address, unsigned short port);
void setYSF2P25(const std::string& address, unsigned short port);
void addFCSRoom(const std::string& id, const std::string& name);
bool start();

View file

@ -47,6 +47,6 @@ const unsigned char YSF_CM_INDIVIDUAL = 0x03U;
const unsigned char YSF_MR_NOT_BUSY = 0x01U;
const unsigned char YSF_MR_BUSY = 0x02U;
const unsigned int FCS_PORT = 62500U;
const unsigned short FCS_PORT = 62500U;
#endif

View file

@ -25,6 +25,7 @@
#include "Timer.h"
#include "Utils.h"
#include "Log.h"
#include "GitVersion.h"
#if defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
@ -47,6 +48,7 @@ const char* DEFAULT_INI_FILE = "/etc/YSFGateway.ini";
#include <cstring>
#include <clocale>
#include <cmath>
#include <algorithm>
int main(int argc, char** argv)
{
@ -55,7 +57,7 @@ int main(int argc, char** argv)
for (int currentArg = 1; currentArg < argc; ++currentArg) {
std::string arg = argv[currentArg];
if ((arg == "-v") || (arg == "--version")) {
::fprintf(stdout, "YSFGateway version %s\n", VERSION);
::fprintf(stdout, "YSFGateway version %s git #%.7s\n", VERSION, gitversion);
return 0;
} else if (arg.substr(0, 1) == "-") {
::fprintf(stderr, "Usage: YSFGateway [-v|--version] [filename]\n");
@ -199,7 +201,7 @@ int CYSFGateway::run()
}
std::string myAddress = m_conf.getMyAddress();
unsigned int myPort = m_conf.getMyPort();
unsigned short myPort = m_conf.getMyPort();
CYSFNetwork rptNetwork(myAddress, myPort, m_callsign, debug);
ret = rptNetwork.setDestination("MMDVM", rptAddr, rptAddrLen);
@ -211,7 +213,7 @@ int CYSFGateway::run()
bool ysfNetworkEnabled = m_conf.getYSFNetworkEnabled();
if (ysfNetworkEnabled) {
unsigned int ysfPort = m_conf.getYSFNetworkPort();
unsigned short ysfPort = m_conf.getYSFNetworkPort();
m_ysfNetwork = new CYSFNetwork(ysfPort, m_callsign, debug);
}
@ -222,7 +224,7 @@ int CYSFGateway::run()
std::string locator = calculateLocator();
unsigned int id = m_conf.getId();
unsigned int fcsPort = m_conf.getFCSNetworkPort();
unsigned short fcsPort = m_conf.getFCSNetworkPort();
m_fcsNetwork = new CFCSNetwork(fcsPort, m_callsign, rxFrequency, txFrequency, locator, id, debug);
ret = m_fcsNetwork->open();
@ -265,7 +267,8 @@ int CYSFGateway::run()
CStopWatch stopWatch;
stopWatch.start();
LogMessage("Starting YSFGateway-%s", VERSION);
LogMessage("YSFGateway-%s is starting", VERSION);
LogMessage("Built %s %s (GitID #%.7s)", __TIME__, __DATE__, gitversion);
for (;;) {
unsigned char buffer[200U];
@ -281,10 +284,13 @@ int CYSFGateway::run()
CYSFReflector* reflector = m_wiresX->getReflector();
if (m_ysfNetwork != NULL && m_linkType == LINK_YSF && wiresXCommandPassthrough && reflector->m_wiresX) {
processDTMF(buffer, dt);
m_exclude = processWiresX(buffer, fich, true, wiresXCommandPassthrough);
processWiresX(buffer, fich, true, wiresXCommandPassthrough);
} else {
processDTMF(buffer, dt);
m_exclude = processWiresX(buffer, fich, false, wiresXCommandPassthrough);
processWiresX(buffer, fich, false, wiresXCommandPassthrough);
reflector = m_wiresX->getReflector(); //reflector may have changed
if (m_ysfNetwork != NULL && m_linkType == LINK_YSF && reflector->m_wiresX)
m_exclude = (dt == YSF_DT_DATA_FR_MODE);
}
if (m_gps != NULL)
@ -454,7 +460,7 @@ void CYSFGateway::createGPS()
return;
std::string address = m_conf.getAPRSAddress();
unsigned int port = m_conf.getAPRSPort();
unsigned short port = m_conf.getAPRSPort();
std::string suffix = m_conf.getAPRSSuffix();
bool debug = m_conf.getDebug();
@ -463,8 +469,10 @@ void CYSFGateway::createGPS()
unsigned int txFrequency = m_conf.getTxFrequency();
unsigned int rxFrequency = m_conf.getRxFrequency();
std::string desc = m_conf.getAPRSDescription();
std::string symbol = m_conf.getAPRSSymbol();
m_writer->setInfo(txFrequency, rxFrequency, desc, symbol);
m_writer->setInfo(txFrequency, rxFrequency, desc);
bool enabled = m_conf.getGPSDEnabled();
if (enabled) {
@ -503,7 +511,7 @@ void CYSFGateway::createWiresX(CYSFNetwork* rptNetwork)
m_wiresX->setInfo(name, txFrequency, rxFrequency);
std::string address = m_conf.getYSFNetworkParrotAddress();
unsigned int port = m_conf.getYSFNetworkParrotPort();
unsigned short port = m_conf.getYSFNetworkParrotPort();
if (port > 0U)
m_wiresX->setParrot(address, port);
@ -530,10 +538,8 @@ void CYSFGateway::createWiresX(CYSFNetwork* rptNetwork)
m_wiresX->start();
}
bool CYSFGateway::processWiresX(const unsigned char* buffer, const CYSFFICH& fich, bool dontProcessWiresXLocal, bool wiresXCommandPassthrough)
void CYSFGateway::processWiresX(const unsigned char* buffer, const CYSFFICH& fich, bool dontProcessWiresXLocal, bool wiresXCommandPassthrough)
{
bool ret=true;
assert(buffer != NULL);
WX_STATUS status = m_wiresX->process(buffer + 35U, buffer + 14U, fich, dontProcessWiresXLocal);
@ -624,10 +630,8 @@ bool CYSFGateway::processWiresX(const unsigned char* buffer, const CYSFFICH& fic
}
break;
default:
ret = false;
break;
}
return ret;
}
void CYSFGateway::processDTMF(unsigned char* buffer, unsigned char dt)
@ -879,8 +883,10 @@ void CYSFGateway::processRemoteCommands()
int res = m_remoteSocket->read(buffer, 200U, addr, addrLen);
if (res > 0) {
buffer[res] = '\0';
if (::memcmp(buffer + 0U, "LinkYSF", 7U) == 0) {
std::string id = std::string((char*)(buffer + 7U));
if ((::memcmp(buffer + 0U, "LinkYSF", 7U) == 0) && (strlen((char*)buffer + 0U) > 8)) {
std::string id = std::string((char*)(buffer + 8U));
// Left trim
id.erase(id.begin(), std::find_if(id.begin(), id.end(), [](unsigned char ch) { return !std::isspace(ch); }));
CYSFReflector* reflector = m_reflectors->findById(id);
if (reflector == NULL)
reflector = m_reflectors->findByName(id);
@ -908,8 +914,10 @@ void CYSFGateway::processRemoteCommands()
LogWarning("Invalid YSF reflector id/name - \"%s\"", id.c_str());
return;
}
} else if (::memcmp(buffer + 0U, "LinkFCS", 7U) == 0) {
std::string raw = std::string((char*)(buffer + 7U));
} else if ((::memcmp(buffer + 0U, "LinkFCS", 7U) == 0) && (strlen((char*)buffer + 0U) > 8)) {
std::string raw = std::string((char*)(buffer + 8U));
// Left trim
raw.erase(raw.begin(), std::find_if(raw.begin(), raw.end(), [](unsigned char ch) { return !std::isspace(ch); }));
std::string id = "FCS00";
std::string idShort = "FCS";
if (raw.length() == 3U) {
@ -971,6 +979,13 @@ void CYSFGateway::processRemoteCommands()
m_lostTimer.stop();
m_linkType = LINK_NONE;
}
} else if (::memcmp(buffer + 0U, "status", 6U) == 0) {
std::string state = std::string("ysf:") + (((m_ysfNetwork == NULL) && (m_fcsNetwork == NULL)) ? "n/a" : ((m_linkType != LINK_NONE) ? "conn" : "disc"));
m_remoteSocket->write((unsigned char*)state.c_str(), (unsigned int)state.length(), addr, addrLen);
} else if (::memcmp(buffer + 0U, "host", 4U) == 0) {
std::string ref = ((((m_ysfNetwork == NULL) && (m_fcsNetwork == NULL)) || (m_linkType == LINK_NONE)) ? "NONE" : m_current);
std::string host = std::string("ysf:\"") + ref + "\"";
m_remoteSocket->write((unsigned char*)host.c_str(), (unsigned int)host.length(), addr, addrLen);
} else {
CUtils::dump("Invalid remote command received", buffer, res);
}

View file

@ -69,7 +69,7 @@ private:
void startupLinking();
std::string calculateLocator();
bool processWiresX(const unsigned char* buffer, const CYSFFICH& fich, bool dontProcessWiresXLocal, bool wiresXCommandPassthrough);
void processWiresX(const unsigned char* buffer, const CYSFFICH& fich, bool dontProcessWiresXLocal, bool wiresXCommandPassthrough);
void processDTMF(unsigned char* buffer, unsigned char dt);
void createWiresX(CYSFNetwork* rptNetwork);
void createGPS();

View file

@ -36,6 +36,7 @@ Address=127.0.0.1
Port=8673
Description=APRS Description
Suffix=Y
# Symbol="/r"
[Network]
# Startup=FCS00120

View file

@ -94,6 +94,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@ -108,6 +111,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
@ -126,6 +132,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@ -144,6 +153,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="APRSWriter.h" />

File diff suppressed because it is too large Load diff

View file

@ -27,7 +27,7 @@
const unsigned int BUFFER_LENGTH = 200U;
CYSFNetwork::CYSFNetwork(const std::string& address, unsigned int port, const std::string& callsign, bool debug) :
CYSFNetwork::CYSFNetwork(const std::string& address, unsigned short port, const std::string& callsign, bool debug) :
m_socket(address, port),
m_debug(debug),
m_addr(),
@ -60,7 +60,7 @@ m_linked(false)
}
}
CYSFNetwork::CYSFNetwork(unsigned int port, const std::string& callsign, bool debug) :
CYSFNetwork::CYSFNetwork(unsigned short port, const std::string& callsign, bool debug) :
m_socket(port),
m_debug(debug),
m_addr(),

View file

@ -29,8 +29,8 @@
class CYSFNetwork {
public:
CYSFNetwork(const std::string& address, unsigned int port, const std::string& callsign, bool debug);
CYSFNetwork(unsigned int port, const std::string& callsign, bool debug);
CYSFNetwork(const std::string& address, unsigned short port, const std::string& callsign, bool debug);
CYSFNetwork(unsigned short port, const std::string& callsign, bool debug);
~CYSFNetwork();
bool setDestination(const std::string& name, const sockaddr_storage& addr, unsigned int addrLen);

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016-2021 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
@ -76,25 +76,25 @@ static bool refComparison(const CYSFReflector* r1, const CYSFReflector* r2)
return false;
}
void CYSFReflectors::setParrot(const std::string& address, unsigned int port)
void CYSFReflectors::setParrot(const std::string& address, unsigned short port)
{
m_parrotAddress = address;
m_parrotPort = port;
}
void CYSFReflectors::setYSF2DMR(const std::string& address, unsigned int port)
void CYSFReflectors::setYSF2DMR(const std::string& address, unsigned short port)
{
m_YSF2DMRAddress = address;
m_YSF2DMRPort = port;
}
void CYSFReflectors::setYSF2NXDN(const std::string& address, unsigned int port)
void CYSFReflectors::setYSF2NXDN(const std::string& address, unsigned short port)
{
m_YSF2NXDNAddress = address;
m_YSF2NXDNPort = port;
}
void CYSFReflectors::setYSF2P25(const std::string& address, unsigned int port)
void CYSFReflectors::setYSF2P25(const std::string& address, unsigned short port)
{
m_YSF2P25Address = address;
m_YSF2P25Port = port;
@ -128,7 +128,7 @@ bool CYSFReflectors::load()
if (p1 != NULL && p2 != NULL && p3 != NULL && p4 != NULL && p5 != NULL && p6 != NULL) {
std::string host = std::string(p4);
unsigned int port = (unsigned int)::atoi(p5);
unsigned short port = (unsigned short)::atoi(p5);
sockaddr_storage addr;
unsigned int addrLen;
@ -252,13 +252,19 @@ bool CYSFReflectors::load()
}
}
unsigned int id = 10U;
for (std::vector<std::pair<std::string, std::string>>::const_iterator it = m_fcsRooms.cbegin(); it != m_fcsRooms.cend(); ++it, id++) {
unsigned int id = 9U;
for (std::vector<std::pair<std::string, std::string>>::const_iterator it1 = m_fcsRooms.cbegin(); it1 != m_fcsRooms.cend(); ++it1) {
bool used;
do {
id++;
used = findById(id);
} while (used);
char text[10U];
::sprintf(text, "%05u", id);
std::string name = it->first;
std::string desc = it->second;
std::string name = it1->first;
std::string desc = it1->second;
CYSFReflector* refl = new CYSFReflector;
refl->m_id = text;
@ -303,6 +309,19 @@ CYSFReflector* CYSFReflectors::findById(const std::string& id)
return NULL;
}
bool CYSFReflectors::findById(unsigned int id) const
{
char text[10U];
::sprintf(text, "%05u", id);
for (std::vector<CYSFReflector*>::const_iterator it = m_newReflectors.cbegin(); it != m_newReflectors.cend(); ++it) {
if (text == (*it)->m_id)
return true;
}
return false;
}
CYSFReflector* CYSFReflectors::findByName(const std::string& name)
{
std::string fullName = name;

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2016-2020 by Jonathan Naylor G4KLX
* Copyright (C) 2016-2021 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
@ -59,10 +59,10 @@ public:
CYSFReflectors(const std::string& hostsFile, unsigned int reloadTime, bool makeUpper);
~CYSFReflectors();
void setParrot(const std::string& address, unsigned int port);
void setYSF2DMR(const std::string& address, unsigned int port);
void setYSF2NXDN(const std::string& address, unsigned int port);
void setYSF2P25(const std::string& address, unsigned int port);
void setParrot(const std::string& address, unsigned short port);
void setYSF2DMR(const std::string& address, unsigned short port);
void setYSF2NXDN(const std::string& address, unsigned short port);
void setYSF2P25(const std::string& address, unsigned short port);
void addFCSRoom(const std::string& id, const std::string& name);
bool load();
@ -81,19 +81,21 @@ public:
private:
std::string m_hostsFile;
std::string m_parrotAddress;
unsigned int m_parrotPort;
unsigned short m_parrotPort;
std::string m_YSF2DMRAddress;
unsigned int m_YSF2DMRPort;
unsigned short m_YSF2DMRPort;
std::string m_YSF2NXDNAddress;
unsigned int m_YSF2NXDNPort;
unsigned short m_YSF2NXDNPort;
std::string m_YSF2P25Address;
unsigned int m_YSF2P25Port;
unsigned short m_YSF2P25Port;
std::vector<std::pair<std::string, std::string>> m_fcsRooms;
std::vector<CYSFReflector*> m_newReflectors;
std::vector<CYSFReflector*> m_currReflectors;
std::vector<CYSFReflector*> m_search;
bool m_makeUpper;
CTimer m_timer;
bool findById(unsigned int id) const;
};
#endif

38
YSFGateway/prebuild.cmd Normal file
View file

@ -0,0 +1,38 @@
@echo off
REM This pre-build file is for MSVS VC++. It parses the git master hash and
REM converts it into GitVersion.h for compiling into builds. [George M1GEO]
cd %1
setlocal enabledelayedexpansion
set HEADFILE=..\.git\HEAD
set HASHFILE=0
if exist %HEADFILE% (
for /F "tokens=4 delims=/:" %%a in ('type %HEADFILE%') do set HEADBRANCH=%%a
set HASHFILE=.git\refs\heads\!HEADBRANCH!
echo Found Git HEAD file: %HEADFILE%
echo Git HEAD branch: !HEADBRANCH!
echo Git HASH file: !HASHFILE!
call :USEHASH
) else (
echo No head file :(
call :USENULL
)
goto :EOF
:USENULL
set GITHASH=0000000000000000000000000000000000000000
goto :WRITEGITVERSIONHEADER
:USEHASH
for /f %%i in ('type !HASHFILE!') do set GITHASH=%%i
goto :WRITEGITVERSIONHEADER
:WRITEGITVERSIONHEADER
echo // File contains Git commit ID SHA1 present at buildtime (prebuild.cmd) > GitVersion.h
echo const char *gitversion = "%GITHASH%"; >> GitVersion.h
echo Current Git HASH: %GITHASH%
goto :FINISHED
:FINISHED
echo GitVersion.h written...

View file

@ -14,9 +14,21 @@ YSFParrot: $(OBJECTS)
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
YSFParrot.o: GitVersion.h FORCE
.PHONY: GitVersion.h
FORCE:
install:
install -m 755 YSFParrot /usr/local/bin/
clean:
$(RM) YSFParrot *.o *.d *.bak *~
$(RM) YSFParrot *.o *.d *.bak *~ GitVersion.h
GitVersion.h:
ifneq ("$(wildcard ../.git/index)","")
echo "const char *gitversion = \"$(shell git rev-parse HEAD)\";" > $@
else
echo "const char *gitversion = \"0000000000000000000000000000000000000000\";" > $@
endif

View file

@ -24,7 +24,7 @@
const unsigned int BUFFER_LENGTH = 200U;
CNetwork::CNetwork(unsigned int port) :
CNetwork::CNetwork(unsigned short port) :
m_socket(port),
m_addr(),
m_addrLen(0U)

View file

@ -26,7 +26,7 @@
class CNetwork {
public:
CNetwork(unsigned int port);
CNetwork(unsigned short port);
~CNetwork();
bool open();

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2006-2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2006-2016,2020,2024 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
@ -33,30 +33,20 @@
#define LogInfo(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__)
#endif
CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) :
m_address_save(address),
m_port_save(port),
m_counter(0U)
CUDPSocket::CUDPSocket(const std::string& address, unsigned short port) :
m_localAddress(address),
m_localPort(port),
m_fd(-1),
m_af(AF_UNSPEC)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::CUDPSocket(unsigned int port) :
m_address_save(),
m_port_save(port),
m_counter(0U)
CUDPSocket::CUDPSocket(unsigned short port) :
m_localAddress(),
m_localPort(port),
m_fd(-1),
m_af(AF_UNSPEC)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::~CUDPSocket()
@ -80,7 +70,7 @@ void CUDPSocket::shutdown()
#endif
}
int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& address_length)
int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockaddr_storage& addr, unsigned int& address_length)
{
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
@ -88,15 +78,15 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_
return lookup(hostname, port, addr, address_length, hints);
}
int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& address_length, struct addrinfo& hints)
int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockaddr_storage& addr, unsigned int& address_length, struct addrinfo& hints)
{
std::string portstr = std::to_string(port);
struct addrinfo *res;
/* port is always digits, no needs to lookup service */
/* Port is always digits, no needs to lookup service */
hints.ai_flags |= AI_NUMERICSERV;
int err = getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
int err = ::getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
if (err != 0) {
sockaddr_in* paddr = (sockaddr_in*)&addr;
::memset(paddr, 0x00U, address_length = sizeof(sockaddr_in));
@ -109,7 +99,7 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_
::memcpy(&addr, res->ai_addr, address_length = res->ai_addrlen);
freeaddrinfo(res);
::freeaddrinfo(res);
return 0;
}
@ -121,33 +111,33 @@ bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& ad
if (type == IMT_ADDRESS_AND_PORT) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
}
} else if (type == IMT_ADDRESS_ONLY) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
}
} else {
return false;
@ -163,33 +153,34 @@ bool CUDPSocket::isNone(const sockaddr_storage& addr)
bool CUDPSocket::open(const sockaddr_storage& address)
{
return open(address.ss_family);
m_af = address.ss_family;
return open();
}
bool CUDPSocket::open(unsigned int af)
bool CUDPSocket::open()
{
return open(0, af, m_address_save, m_port_save);
}
assert(m_fd == -1);
bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port)
{
sockaddr_storage addr;
unsigned int addrlen;
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = af;
hints.ai_family = m_af;
/* to determine protocol family, call lookup() first. */
int err = lookup(address, port, addr, addrlen, hints);
// To determine protocol family, call lookup() on the local address first.
int err = lookup(m_localAddress, m_localPort, addr, addrlen, hints);
if (err != 0) {
LogError("The local address is invalid - %s", address.c_str());
LogError("The local address is invalid - %s", m_localAddress.c_str());
return false;
}
int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0);
if (fd < 0) {
m_af = addr.ss_family;
m_fd = ::socket(m_af, SOCK_DGRAM, 0);
if (m_fd < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
#else
@ -198,62 +189,51 @@ bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std
return false;
}
m_address[index] = address;
m_port[index] = port;
m_af[index] = addr.ss_family;
m_fd[index] = fd;
if (port > 0U) {
if (m_localPort > 0U) {
int reuse = 1;
if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
if (::setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError());
#else
LogError("Cannot set the UDP socket option, err: %d", errno);
#endif
close();
return false;
}
if (::bind(fd, (sockaddr*)&addr, addrlen) == -1) {
if (::bind(m_fd, (sockaddr*)&addr, addrlen) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
#else
LogError("Cannot bind the UDP address, err: %d", errno);
#endif
close();
return false;
}
LogInfo("Opening UDP port on %u", port);
LogInfo("Opening UDP port on %hu", m_localPort);
}
return true;
}
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length)
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &addressLength)
{
assert(buffer != NULL);
assert(length > 0U);
assert(m_fd >= 0);
// Check that the readfrom() won't block
int i, n;
struct pollfd pfd[UDP_SOCKET_MAX];
for (i = n = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] >= 0) {
pfd[n].fd = m_fd[i];
pfd[n].events = POLLIN;
n++;
}
}
// no socket descriptor to receive
if (n == 0)
return 0;
struct pollfd pfd;
pfd.fd = m_fd;
pfd.events = POLLIN;
pfd.revents = 0;
// Return immediately
#if defined(_WIN32) || defined(_WIN64)
int ret = WSAPoll(pfd, n, 0);
int ret = WSAPoll(&pfd, 1, 0);
#else
int ret = ::poll(pfd, n, 0);
int ret = ::poll(&pfd, 1, 0);
#endif
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
@ -264,14 +244,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
return -1;
}
int index;
for (i = 0; i < n; i++) {
// round robin
index = (i + m_counter) % n;
if (pfd[index].revents & POLLIN)
break;
}
if (i == n)
if ((pfd.revents & POLLIN) == 0)
return 0;
#if defined(_WIN32) || defined(_WIN64)
@ -281,9 +254,9 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
#endif
#if defined(_WIN32) || defined(_WIN64)
int len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
int len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#else
ssize_t len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
ssize_t len = ::recvfrom(m_fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#endif
if (len <= 0) {
#if defined(_WIN32) || defined(_WIN64)
@ -292,7 +265,7 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
LogError("Error returned from recvfrom, err: %d", errno);
if (len == -1 && errno == ENOTSOCK) {
LogMessage("Re-opening UDP port on %u", m_port);
LogMessage("Re-opening UDP port on %hu", m_localPort);
close();
open();
}
@ -300,43 +273,39 @@ int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storag
return -1;
}
m_counter++;
address_length = size;
addressLength = size;
return len;
}
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length)
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addressLength)
{
assert(buffer != NULL);
assert(length > 0U);
assert(m_fd >= 0);
bool result = false;
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] < 0 || m_af[i] != address.ss_family)
continue;
#if defined(_WIN32) || defined(_WIN64)
int ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
int ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, addressLength);
#else
ssize_t ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
ssize_t ret = ::sendto(m_fd, (char *)buffer, length, 0, (sockaddr *)&address, addressLength);
#endif
if (ret < 0) {
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from sendto, err: %lu", ::GetLastError());
LogError("Error returned from sendto, err: %lu", ::GetLastError());
#else
LogError("Error returned from sendto, err: %d", errno);
LogError("Error returned from sendto, err: %d", errno);
#endif
} else {
} else {
#if defined(_WIN32) || defined(_WIN64)
if (ret == int(length))
result = true;
if (ret == int(length))
result = true;
#else
if (ret == ssize_t(length))
result = true;
if (ret == ssize_t(length))
result = true;
#endif
}
}
return result;
@ -344,18 +313,13 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const s
void CUDPSocket::close()
{
for (int i = 0; i < UDP_SOCKET_MAX; i++)
close(m_fd[i]);
}
void CUDPSocket::close(const unsigned int index)
{
if (m_fd[index] >= 0) {
if (m_fd >= 0) {
#if defined(_WIN32) || defined(_WIN64)
::closesocket(m_fd[index]);
::closesocket(m_fd);
#else
::close(m_fd[index]);
::close(m_fd);
#endif
m_fd[index] = -1;
m_fd = -1;
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2009-2011,2013,2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2009-2011,2013,2015,2016,2020,2024 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
@ -35,10 +35,6 @@
#include <ws2tcpip.h>
#endif
#if !defined(UDP_SOCKET_MAX)
#define UDP_SOCKET_MAX 1
#endif
enum IPMATCHTYPE {
IMT_ADDRESS_AND_PORT,
IMT_ADDRESS_ONLY
@ -46,38 +42,38 @@ enum IPMATCHTYPE {
class CUDPSocket {
public:
CUDPSocket(const std::string& address, unsigned int port = 0U);
CUDPSocket(unsigned int port = 0U);
CUDPSocket(const std::string& address, unsigned short port = 0U);
CUDPSocket(unsigned short port = 0U);
~CUDPSocket();
bool open(unsigned int af = AF_UNSPEC);
bool open();
bool open(const sockaddr_storage& address);
bool open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port);
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length);
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length);
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &addressLength);
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int addressLength);
void close();
void close(const unsigned int index);
static void startup();
static void shutdown();
static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length);
static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length, struct addrinfo& hints);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& addressLength);
static int lookup(const std::string& hostName, unsigned short port, sockaddr_storage& address, unsigned int& addressLength, struct addrinfo& hints);
static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IMT_ADDRESS_AND_PORT);
static bool isNone(const sockaddr_storage& addr);
private:
std::string m_address_save;
unsigned short m_port_save;
std::string m_address[UDP_SOCKET_MAX];
unsigned short m_port[UDP_SOCKET_MAX];
unsigned int m_af[UDP_SOCKET_MAX];
int m_fd[UDP_SOCKET_MAX];
unsigned int m_counter;
std::string m_localAddress;
unsigned short m_localPort;
#if defined(_WIN32) || defined(_WIN64)
SOCKET m_fd;
int m_af;
#else
int m_fd;
sa_family_t m_af;
#endif
};
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
* Copyright (C) 2015,2016,2020,2024 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,6 +19,6 @@
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20201101";
const char* VERSION = "20240129";
#endif

View file

@ -23,6 +23,7 @@
#include "Version.h"
#include "Thread.h"
#include "Timer.h"
#include "GitVersion.h"
#include <cstdio>
#include <cstdlib>
@ -30,24 +31,32 @@
int main(int argc, char** argv)
{
if (argc == 1) {
::fprintf(stderr, "Usage: YSFParrot [-d|--debug] <port>\n");
return 1;
if (argc > 1) {
for (int currentArg = 1; currentArg < argc; ++currentArg) {
std::string arg = argv[currentArg];
if ((arg == "-v") || (arg == "--version")) {
::fprintf(stdout, "YSFParrot version %s git #%.7s\n", VERSION, gitversion);
return 0;
} else if (arg.substr(0, 1) == "-") {
::fprintf(stderr, "Usage: YSFParrot [-v|--version] [-d|--debug] <port>\n");
return 1;
} else {
unsigned short port = (unsigned short)::atoi(argv[1U]);
if (port == 0U) {
::fprintf(stderr, "YSFParrot: invalid port number - %s\n", argv[1U]);
return 1;
}
CYSFParrot parrot(port);
parrot.run();
return 0;
}
}
}
unsigned int port = ::atoi(argv[1U]);
if (port == 0U) {
::fprintf(stderr, "YSFParrot: invalid port number - %s\n", argv[1U]);
return 1;
}
CYSFParrot parrot(port);
parrot.run();
return 0;
}
CYSFParrot::CYSFParrot(unsigned int port) :
CYSFParrot::CYSFParrot(unsigned short port) :
m_port(port)
{
CUDPSocket::startup();
@ -77,7 +86,8 @@ void CYSFParrot::run()
unsigned int count = 0U;
bool playing = false;
::fprintf(stdout, "Starting YSFParrot-%s\n", VERSION);
::fprintf(stdout, "YSFParrot-%s is starting", VERSION);
::fprintf(stdout, "Built %s %s (GitID #%.7s)", __TIME__, __DATE__, gitversion);
for (;;) {
unsigned char buffer[200U];

View file

@ -22,13 +22,13 @@
class CYSFParrot
{
public:
CYSFParrot(unsigned int port);
CYSFParrot(unsigned short port);
~CYSFParrot();
void run();
private:
unsigned int m_port;
unsigned short m_port;
};
#endif

View file

@ -94,6 +94,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@ -108,6 +111,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
@ -126,6 +132,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@ -144,6 +153,9 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<PreBuildEvent>
<Command>prebuild.cmd</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="StopWatch.h" />

38
YSFParrot/prebuild.cmd Normal file
View file

@ -0,0 +1,38 @@
@echo off
REM This pre-build file is for MSVS VC++. It parses the git master hash and
REM converts it into GitVersion.h for compiling into builds. [George M1GEO]
cd %1
setlocal enabledelayedexpansion
set HEADFILE=..\.git\HEAD
set HASHFILE=0
if exist %HEADFILE% (
for /F "tokens=4 delims=/:" %%a in ('type %HEADFILE%') do set HEADBRANCH=%%a
set HASHFILE=.git\refs\heads\!HEADBRANCH!
echo Found Git HEAD file: %HEADFILE%
echo Git HEAD branch: !HEADBRANCH!
echo Git HASH file: !HASHFILE!
call :USEHASH
) else (
echo No head file :(
call :USENULL
)
goto :EOF
:USENULL
set GITHASH=0000000000000000000000000000000000000000
goto :WRITEGITVERSIONHEADER
:USEHASH
for /f %%i in ('type !HASHFILE!') do set GITHASH=%%i
goto :WRITEGITVERSIONHEADER
:WRITEGITVERSIONHEADER
echo // File contains Git commit ID SHA1 present at buildtime (prebuild.cmd) > GitVersion.h
echo const char *gitversion = "%GITHASH%"; >> GitVersion.h
echo Current Git HASH: %GITHASH%
goto :FINISHED
:FINISHED
echo GitVersion.h written...

View file

@ -1,200 +0,0 @@
/*
* Copyright (C) 2015,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 "Conf.h"
#include "Log.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
const int BUFFER_SIZE = 500;
enum SECTION {
SECTION_NONE,
SECTION_GENERAL,
SECTION_INFO,
SECTION_LOG,
SECTION_NETWORK
};
CConf::CConf(const std::string& file) :
m_file(file),
m_daemon(false),
m_id(0U),
m_name(),
m_description(),
m_logDisplayLevel(0U),
m_logFileLevel(0U),
m_logFilePath(),
m_logFileRoot(),
m_logFileRotate(true),
m_networkPort(0U),
m_networkDebug(false)
{
}
CConf::~CConf()
{
}
bool CConf::read()
{
FILE* fp = ::fopen(m_file.c_str(), "rt");
if (fp == NULL) {
::fprintf(stderr, "Couldn't open the .ini file - %s\n", m_file.c_str());
return false;
}
SECTION section = SECTION_NONE;
char buffer[BUFFER_SIZE];
while (::fgets(buffer, BUFFER_SIZE, fp) != NULL) {
if (buffer[0U] == '#')
continue;
if (buffer[0U] == '[') {
if (::strncmp(buffer, "[General]", 9U) == 0)
section = SECTION_GENERAL;
else if (::strncmp(buffer, "[Info]", 6U) == 0)
section = SECTION_INFO;
else if (::strncmp(buffer, "[Log]", 5U) == 0)
section = SECTION_LOG;
else if (::strncmp(buffer, "[Network]", 9U) == 0)
section = SECTION_NETWORK;
else
section = SECTION_NONE;
continue;
}
char* key = ::strtok(buffer, " \t=\r\n");
if (key == NULL)
continue;
char* value = ::strtok(NULL, "\r\n");
if (value == NULL)
continue;
// Remove quotes from the value
size_t len = ::strlen(value);
if (len > 1U && *value == '"' && value[len - 1U] == '"') {
value[len - 1U] = '\0';
value++;
} else {
char *p;
// if value is not quoted, remove after # (to make comment)
if ((p = strchr(value, '#')) != NULL)
*p = '\0';
// remove trailing tab/space
for (p = value + strlen(value) - 1U; p >= value && (*p == '\t' || *p == ' '); p--)
*p = '\0';
}
if (section == SECTION_GENERAL) {
if (::strcmp(key, "Daemon") == 0)
m_daemon = ::atoi(value) == 1;
} else if (section == SECTION_INFO) {
if (::strcmp(key, "Id") == 0)
m_id = (unsigned int)::atoi(value);
else if (::strcmp(key, "Name") == 0)
m_name = value;
else if (::strcmp(key, "Description") == 0)
m_description = value;
} else if (section == SECTION_LOG) {
if (::strcmp(key, "FilePath") == 0)
m_logFilePath = value;
else if (::strcmp(key, "FileRoot") == 0)
m_logFileRoot = value;
else if (::strcmp(key, "FileLevel") == 0)
m_logFileLevel = (unsigned int)::atoi(value);
else if (::strcmp(key, "DisplayLevel") == 0)
m_logDisplayLevel = (unsigned int)::atoi(value);
else if (::strcmp(key, "FileRotate") == 0)
m_logFileRotate = ::atoi(value) == 1;
} else if (section == SECTION_NETWORK) {
if (::strcmp(key, "Port") == 0)
m_networkPort = (unsigned int)::atoi(value);
else if (::strcmp(key, "Debug") == 0)
m_networkDebug = ::atoi(value) == 1;
}
}
::fclose(fp);
return true;
}
bool CConf::getDaemon() const
{
return m_daemon;
}
unsigned int CConf::getId() const
{
return m_id;
}
std::string CConf::getName() const
{
return m_name;
}
std::string CConf::getDescription() const
{
return m_description;
}
unsigned int CConf::getLogDisplayLevel() const
{
return m_logDisplayLevel;
}
unsigned int CConf::getLogFileLevel() const
{
return m_logFileLevel;
}
std::string CConf::getLogFilePath() const
{
return m_logFilePath;
}
std::string CConf::getLogFileRoot() const
{
return m_logFileRoot;
}
bool CConf::getLogFileRotate() const
{
return m_logFileRotate;
}
unsigned int CConf::getNetworkPort() const
{
return m_networkPort;
}
bool CConf::getNetworkDebug() const
{
return m_networkDebug;
}

View file

@ -1,70 +0,0 @@
/*
* Copyright (C) 2015,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.
*/
#if !defined(CONF_H)
#define CONF_H
#include <string>
#include <vector>
class CConf
{
public:
CConf(const std::string& file);
~CConf();
bool read();
// The General section
bool getDaemon() const;
// The Info section
unsigned int getId() const;
std::string getName() const;
std::string getDescription() const;
// The Log section
unsigned int getLogDisplayLevel() const;
unsigned int getLogFileLevel() const;
std::string getLogFilePath() const;
std::string getLogFileRoot() const;
bool getLogFileRotate() const;
// The Network section
unsigned int getNetworkPort() const;
bool getNetworkDebug() const;
private:
std::string m_file;
bool m_daemon;
unsigned int m_id;
std::string m_name;
std::string m_description;
unsigned int m_logDisplayLevel;
unsigned int m_logFileLevel;
std::string m_logFilePath;
std::string m_logFileRoot;
bool m_logFileRotate;
unsigned int m_networkPort;
bool m_networkDebug;
};
#endif

View file

@ -1,192 +0,0 @@
/*
* Copyright (C) 2015,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 "Log.h"
#if defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
#else
#include <sys/time.h>
#include <unistd.h>
#endif
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <ctime>
#include <cassert>
#include <cstring>
static unsigned int m_fileLevel = 2U;
static std::string m_filePath;
static std::string m_fileRoot;
static bool m_fileRotate = true;
static FILE* m_fpLog = NULL;
static bool m_daemon = false;
static unsigned int m_displayLevel = 2U;
static struct tm m_tm;
static char LEVELS[] = " DMIWEF";
static bool logOpenRotate()
{
bool status = false;
if (m_fileLevel == 0U)
return true;
time_t now;
::time(&now);
struct tm* tm = ::gmtime(&now);
if (tm->tm_mday == m_tm.tm_mday && tm->tm_mon == m_tm.tm_mon && tm->tm_year == m_tm.tm_year) {
if (m_fpLog != NULL)
return true;
} else {
if (m_fpLog != NULL)
::fclose(m_fpLog);
}
char filename[200U];
#if defined(_WIN32) || defined(_WIN64)
::sprintf(filename, "%s\\%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#else
::sprintf(filename, "%s/%s-%04d-%02d-%02d.log", m_filePath.c_str(), m_fileRoot.c_str(), tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
#endif
if ((m_fpLog = ::fopen(filename, "a+t")) != NULL) {
status = true;
#if !defined(_WIN32) && !defined(_WIN64)
if (m_daemon)
dup2(fileno(m_fpLog), fileno(stderr));
#endif
}
m_tm = *tm;
return status;
}
static bool logOpenNoRotate()
{
bool status = false;
if (m_fileLevel == 0U)
return true;
if (m_fpLog != NULL)
return true;
char filename[200U];
#if defined(_WIN32) || defined(_WIN64)
::sprintf(filename, "%s\\%s.log", m_filePath.c_str(), m_fileRoot.c_str());
#else
::sprintf(filename, "%s/%s.log", m_filePath.c_str(), m_fileRoot.c_str());
#endif
if ((m_fpLog = ::fopen(filename, "a+t")) != NULL) {
status = true;
#if !defined(_WIN32) && !defined(_WIN64)
if (m_daemon)
dup2(fileno(m_fpLog), fileno(stderr));
#endif
}
return status;
}
bool LogOpen()
{
if (m_fileRotate)
return logOpenRotate();
else
return logOpenNoRotate();
}
bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel, bool rotate)
{
m_filePath = filePath;
m_fileRoot = fileRoot;
m_fileLevel = fileLevel;
m_displayLevel = displayLevel;
m_daemon = daemon;
m_fileRotate = rotate;
if (m_daemon)
m_displayLevel = 0U;
return ::LogOpen();
}
void LogFinalise()
{
if (m_fpLog != NULL)
::fclose(m_fpLog);
}
void Log(unsigned int level, const char* fmt, ...)
{
assert(fmt != NULL);
char buffer[501U];
#if defined(_WIN32) || defined(_WIN64)
SYSTEMTIME st;
::GetSystemTime(&st);
::sprintf(buffer, "%c: %04u-%02u-%02u %02u:%02u:%02u.%03u ", LEVELS[level], st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
#else
struct timeval now;
::gettimeofday(&now, NULL);
struct tm* tm = ::gmtime(&now.tv_sec);
::sprintf(buffer, "%c: %04d-%02d-%02d %02d:%02d:%02d.%03ld ", LEVELS[level], tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, now.tv_usec / 1000L);
#endif
va_list vl;
va_start(vl, fmt);
::vsnprintf(buffer + ::strlen(buffer), 500, fmt, vl);
va_end(vl);
if (level >= m_fileLevel && m_fileLevel != 0U) {
bool ret = ::LogOpen();
if (!ret)
return;
::fprintf(m_fpLog, "%s\n", buffer);
::fflush(m_fpLog);
}
if (level >= m_displayLevel && m_displayLevel != 0U) {
::fprintf(stdout, "%s\n", buffer);
::fflush(stdout);
}
if (level == 6U) { // Fatal
::fclose(m_fpLog);
exit(1);
}
}

View file

@ -1,36 +0,0 @@
/*
* Copyright (C) 2015,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.
*/
#if !defined(LOG_H)
#define LOG_H
#include <string>
#define LogDebug(fmt, ...) Log(1U, fmt, ##__VA_ARGS__)
#define LogMessage(fmt, ...) Log(2U, fmt, ##__VA_ARGS__)
#define LogInfo(fmt, ...) Log(3U, fmt, ##__VA_ARGS__)
#define LogWarning(fmt, ...) Log(4U, fmt, ##__VA_ARGS__)
#define LogError(fmt, ...) Log(5U, fmt, ##__VA_ARGS__)
#define LogFatal(fmt, ...) Log(6U, fmt, ##__VA_ARGS__)
extern void Log(unsigned int level, const char* fmt, ...);
extern bool LogInitialise(bool daemon, const std::string& filePath, const std::string& fileRoot, unsigned int fileLevel, unsigned int displayLevel, bool rotate);
extern void LogFinalise();
#endif

View file

@ -1,22 +0,0 @@
CC = cc
CXX = c++
CFLAGS = -g -O3 -Wall -std=c++0x -pthread -DHAVE_LOG_H -DUDP_SOCKET_MAX=2
LIBS = -lpthread
LDFLAGS = -g
OBJECTS = Conf.o Log.o Network.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o YSFReflector.o
all: YSFReflector
YSFReflector: $(OBJECTS)
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o YSFReflector
%.o: %.cpp
$(CXX) $(CFLAGS) -c -o $@ $<
install:
install -m 755 YSFReflector /usr/local/bin/
clean:
$(RM) YSFReflector *.o *.d *.bak *~

View file

@ -1,155 +0,0 @@
/*
* Copyright (C) 2009-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 "YSFDefines.h"
#include "Network.h"
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
#include <cstring>
CNetwork::CNetwork(unsigned int port, unsigned int id, const std::string& name, const std::string& description, bool debug) :
m_socket(),
m_port(port),
m_id(id),
m_name(name),
m_description(description),
m_callsign(),
m_debug(debug),
m_status(NULL)
{
m_name.resize(16U, ' ');
m_description.resize(14U, ' ');
m_status = new unsigned char[50U];
}
CNetwork::~CNetwork()
{
delete[] m_status;
}
bool CNetwork::open()
{
LogInfo("Opening YSF network connection");
bool status = false;
unsigned int af[] = {AF_INET, AF_INET6};
for (unsigned int i = 0U; i < UDP_SOCKET_MAX && i < (sizeof(af) / sizeof(unsigned int)); i++)
status |= m_socket.open(i, af[i], "", m_port);
return status;
}
bool CNetwork::writeData(const unsigned char* data, const sockaddr_storage& addr, unsigned int addrLen)
{
assert(data != NULL);
if (m_debug)
CUtils::dump(1U, "YSF Network Data Sent", data, 155U);
return m_socket.write(data, 155U, addr, addrLen);
}
bool CNetwork::writePoll(const sockaddr_storage& addr, unsigned int addrLen)
{
unsigned char buffer[20U];
buffer[0] = 'Y';
buffer[1] = 'S';
buffer[2] = 'F';
buffer[3] = 'P';
buffer[4U] = 'R';
buffer[5U] = 'E';
buffer[6U] = 'F';
buffer[7U] = 'L';
buffer[8U] = 'E';
buffer[9U] = 'C';
buffer[10U] = 'T';
buffer[11U] = 'O';
buffer[12U] = 'R';
buffer[13U] = ' ';
if (m_debug)
CUtils::dump(1U, "YSF Network Poll Sent", buffer, 14U);
return m_socket.write(buffer, 14U, addr, addrLen);
}
unsigned int CNetwork::readData(unsigned char* data, unsigned int length, sockaddr_storage& addr, unsigned int& addrLen)
{
assert(data != NULL);
assert(length > 0U);
int len = m_socket.read(data, length, addr, addrLen);
if (len <= 0)
return 0U;
if (m_debug)
CUtils::dump(1U, "YSF Network Data Received", data, len);
// Throw away any options messages
if (::memcmp(data, "YSFO", 4U) == 0)
return 0U;
// Throw away any info messages
if (::memcmp(data, "YSFI", 4U) == 0)
return 0U;
// Handle incoming status requests
if (::memcmp(data, "YSFS", 4U) == 0) {
m_socket.write(m_status, 42U, addr, addrLen);
return 0U;
}
return len;
}
void CNetwork::setCount(unsigned int count)
{
if (count > 999U)
count = 999U;
unsigned int hash = m_id;
if (hash == 0U) {
for (unsigned int i = 0U; i < m_name.size(); i++) {
hash += m_name.at(i);
hash += (hash << 10);
hash ^= (hash >> 6);
}
// Final avalanche
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
}
::sprintf((char*)m_status, "YSFS%05u%16.16s%14.14s%03u", hash % 100000U, m_name.c_str(), m_description.c_str(), count);
}
void CNetwork::close()
{
m_socket.close();
LogInfo("Closing YSF network connection");
}

View file

@ -1,57 +0,0 @@
/*
* Copyright (C) 2009-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.
*/
#ifndef Network_H
#define Network_H
#include "YSFDefines.h"
#include "UDPSocket.h"
#include "Timer.h"
#include <cstdint>
#include <string>
class CNetwork {
public:
CNetwork(unsigned int port, unsigned int id, const std::string& name, const std::string& description, bool debug);
~CNetwork();
bool open();
bool writeData(const unsigned char* data, const sockaddr_storage& addr, unsigned int addrLen);
bool writePoll(const sockaddr_storage& addr, unsigned int addrLen);
unsigned int readData(unsigned char* data, unsigned int length, sockaddr_storage& addr, unsigned int& addrLen);
void close();
void setCount(unsigned int count);
private:
CUDPSocket m_socket;
unsigned short m_port;
unsigned int m_id;
std::string m_name;
std::string m_description;
std::string m_callsign;
bool m_debug;
unsigned char* m_status;
};
#endif

View file

@ -1,105 +0,0 @@
/*
* Copyright (C) 2015,2016,2018 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 "StopWatch.h"
#if defined(_WIN32) || defined(_WIN64)
CStopWatch::CStopWatch() :
m_frequencyS(),
m_frequencyMS(),
m_start()
{
::QueryPerformanceFrequency(&m_frequencyS);
m_frequencyMS.QuadPart = m_frequencyS.QuadPart / 1000ULL;
}
CStopWatch::~CStopWatch()
{
}
unsigned long long CStopWatch::time() const
{
LARGE_INTEGER now;
::QueryPerformanceCounter(&now);
return (unsigned long long)(now.QuadPart / m_frequencyMS.QuadPart);
}
unsigned long long CStopWatch::start()
{
::QueryPerformanceCounter(&m_start);
return (unsigned long long)(m_start.QuadPart / m_frequencyS.QuadPart);
}
unsigned int CStopWatch::elapsed()
{
LARGE_INTEGER now;
::QueryPerformanceCounter(&now);
LARGE_INTEGER temp;
temp.QuadPart = (now.QuadPart - m_start.QuadPart) * 1000;
return (unsigned int)(temp.QuadPart / m_frequencyS.QuadPart);
}
#else
#include <cstdio>
#include <ctime>
CStopWatch::CStopWatch() :
m_startMS(0ULL)
{
}
CStopWatch::~CStopWatch()
{
}
unsigned long long CStopWatch::time() const
{
struct timeval now;
::gettimeofday(&now, NULL);
return now.tv_sec * 1000ULL + now.tv_usec / 1000ULL;
}
unsigned long long CStopWatch::start()
{
struct timespec now;
::clock_gettime(CLOCK_MONOTONIC, &now);
m_startMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL;
return m_startMS;
}
unsigned int CStopWatch::elapsed()
{
struct timespec now;
::clock_gettime(CLOCK_MONOTONIC, &now);
unsigned long long nowMS = now.tv_sec * 1000ULL + now.tv_nsec / 1000000ULL;
return nowMS - m_startMS;
}
#endif

View file

@ -1,50 +0,0 @@
/*
* Copyright (C) 2015,2016,2018 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(STOPWATCH_H)
#define STOPWATCH_H
#if defined(_WIN32) || defined(_WIN64)
#include <WS2tcpip.h>
#include <windows.h>
#else
#include <sys/time.h>
#endif
class CStopWatch
{
public:
CStopWatch();
~CStopWatch();
unsigned long long time() const;
unsigned long long start();
unsigned int elapsed();
private:
#if defined(_WIN32) || defined(_WIN64)
LARGE_INTEGER m_frequencyS;
LARGE_INTEGER m_frequencyMS;
LARGE_INTEGER m_start;
#else
unsigned long long m_startMS;
#endif
};
#endif

View file

@ -1,107 +0,0 @@
/*
* Copyright (C) 2015,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 "Thread.h"
#if defined(_WIN32) || defined(_WIN64)
CThread::CThread() :
m_handle()
{
}
CThread::~CThread()
{
}
bool CThread::run()
{
m_handle = ::CreateThread(NULL, 0, &helper, this, 0, NULL);
return m_handle != NULL;
}
void CThread::wait()
{
::WaitForSingleObject(m_handle, INFINITE);
::CloseHandle(m_handle);
}
DWORD CThread::helper(LPVOID arg)
{
CThread* p = (CThread*)arg;
p->entry();
return 0UL;
}
void CThread::sleep(unsigned int ms)
{
::Sleep(ms);
}
#else
#include <unistd.h>
CThread::CThread() :
m_thread()
{
}
CThread::~CThread()
{
}
bool CThread::run()
{
return ::pthread_create(&m_thread, NULL, helper, this) == 0;
}
void CThread::wait()
{
::pthread_join(m_thread, NULL);
}
void* CThread::helper(void* arg)
{
CThread* p = (CThread*)arg;
p->entry();
return NULL;
}
void CThread::sleep(unsigned int ms)
{
struct timespec ts;
ts.tv_sec = ms / 1000U;
ts.tv_nsec = (ms % 1000U) * 1000000U;
::nanosleep(&ts, NULL);
}
#endif

View file

@ -1,56 +0,0 @@
/*
* 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(THREAD_H)
#define THREAD_H
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#else
#include <pthread.h>
#endif
class CThread
{
public:
CThread();
virtual ~CThread();
virtual bool run();
virtual void entry() = 0;
virtual void wait();
static void sleep(unsigned int ms);
private:
#if defined(_WIN32) || defined(_WIN64)
HANDLE m_handle;
#else
pthread_t m_thread;
#endif
#if defined(_WIN32) || defined(_WIN64)
static DWORD __stdcall helper(LPVOID arg);
#else
static void* helper(void* arg);
#endif
};
#endif

View file

@ -1,68 +0,0 @@
/*
* Copyright (C) 2009,2010,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 "Timer.h"
#include <cstdio>
#include <cassert>
CTimer::CTimer(unsigned int ticksPerSec, unsigned int secs, unsigned int msecs) :
m_ticksPerSec(ticksPerSec),
m_timeout(0U),
m_timer(0U)
{
assert(ticksPerSec > 0U);
if (secs > 0U || msecs > 0U) {
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
}
}
CTimer::~CTimer()
{
}
void CTimer::setTimeout(unsigned int secs, unsigned int msecs)
{
if (secs > 0U || msecs > 0U) {
// m_timeout = ((secs * 1000U + msecs) * m_ticksPerSec) / 1000U + 1U;
unsigned long long temp = (secs * 1000ULL + msecs) * m_ticksPerSec;
m_timeout = (unsigned int)(temp / 1000ULL + 1ULL);
} else {
m_timeout = 0U;
m_timer = 0U;
}
}
unsigned int CTimer::getTimeout() const
{
if (m_timeout == 0U)
return 0U;
return (m_timeout - 1U) / m_ticksPerSec;
}
unsigned int CTimer::getTimer() const
{
if (m_timer == 0U)
return 0U;
return (m_timer - 1U) / m_ticksPerSec;
}

View file

@ -1,89 +0,0 @@
/*
* Copyright (C) 2009,2010,2011,2014 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 Timer_H
#define Timer_H
class CTimer {
public:
CTimer(unsigned int ticksPerSec, unsigned int secs = 0U, unsigned int msecs = 0U);
~CTimer();
void setTimeout(unsigned int secs, unsigned int msecs = 0U);
unsigned int getTimeout() const;
unsigned int getTimer() const;
unsigned int getRemaining()
{
if (m_timeout == 0U || m_timer == 0U)
return 0U;
if (m_timer >= m_timeout)
return 0U;
return (m_timeout - m_timer) / m_ticksPerSec;
}
bool isRunning()
{
return m_timer > 0U;
}
void start(unsigned int secs, unsigned int msecs = 0U)
{
setTimeout(secs, msecs);
start();
}
void start()
{
if (m_timeout > 0U)
m_timer = 1U;
}
void stop()
{
m_timer = 0U;
}
bool hasExpired()
{
if (m_timeout == 0U || m_timer == 0U)
return false;
if (m_timer >= m_timeout)
return true;
return false;
}
void clock(unsigned int ticks = 1U)
{
if (m_timer > 0U && m_timeout > 0U)
m_timer += ticks;
}
private:
unsigned int m_ticksPerSec;
unsigned int m_timeout;
unsigned int m_timer;
};
#endif

View file

@ -1,388 +0,0 @@
/*
* Copyright (C) 2006-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 "UDPSocket.h"
#include <cassert>
#if !defined(_WIN32) && !defined(_WIN64)
#include <cerrno>
#include <cstring>
#endif
#if defined(HAVE_LOG_H)
#include "Log.h"
#else
#define LogError(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__)
#define LogInfo(fmt, ...) ::fprintf(stderr, fmt "\n", ## __VA_ARGS__)
#endif
CUDPSocket::CUDPSocket(const std::string& address, unsigned int port) :
m_address_save(address),
m_port_save(port),
m_counter(0U)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::CUDPSocket(unsigned int port) :
m_address_save(),
m_port_save(port),
m_counter(0U)
{
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
m_address[i] = "";
m_port[i] = 0U;
m_af[i] = 0U;
m_fd[i] = -1;
}
}
CUDPSocket::~CUDPSocket()
{
}
void CUDPSocket::startup()
{
#if defined(_WIN32) || defined(_WIN64)
WSAData data;
int wsaRet = ::WSAStartup(MAKEWORD(2, 2), &data);
if (wsaRet != 0)
LogError("Error from WSAStartup");
#endif
}
void CUDPSocket::shutdown()
{
#if defined(_WIN32) || defined(_WIN64)
::WSACleanup();
#endif
}
int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& address_length)
{
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
return lookup(hostname, port, addr, address_length, hints);
}
int CUDPSocket::lookup(const std::string& hostname, unsigned int port, sockaddr_storage& addr, unsigned int& address_length, struct addrinfo& hints)
{
std::string portstr = std::to_string(port);
struct addrinfo *res;
/* port is always digits, no needs to lookup service */
hints.ai_flags |= AI_NUMERICSERV;
int err = getaddrinfo(hostname.empty() ? NULL : hostname.c_str(), portstr.c_str(), &hints, &res);
if (err != 0) {
sockaddr_in* paddr = (sockaddr_in*)&addr;
::memset(paddr, 0x00U, address_length = sizeof(sockaddr_in));
paddr->sin_family = AF_INET;
paddr->sin_port = htons(port);
paddr->sin_addr.s_addr = htonl(INADDR_NONE);
LogError("Cannot find address for host %s", hostname.c_str());
return err;
}
::memcpy(&addr, res->ai_addr, address_length = res->ai_addrlen);
freeaddrinfo(res);
return 0;
}
bool CUDPSocket::match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type)
{
if (addr1.ss_family != addr2.ss_family)
return false;
if (type == IMT_ADDRESS_AND_PORT) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return (in_1->sin_addr.s_addr == in_2->sin_addr.s_addr) && (in_1->sin_port == in_2->sin_port);
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr) && (in6_1->sin6_port == in6_2->sin6_port);
default:
return false;
}
} else if (type == IMT_ADDRESS_ONLY) {
switch (addr1.ss_family) {
case AF_INET:
struct sockaddr_in *in_1, *in_2;
in_1 = (struct sockaddr_in*)&addr1;
in_2 = (struct sockaddr_in*)&addr2;
return in_1->sin_addr.s_addr == in_2->sin_addr.s_addr;
case AF_INET6:
struct sockaddr_in6 *in6_1, *in6_2;
in6_1 = (struct sockaddr_in6*)&addr1;
in6_2 = (struct sockaddr_in6*)&addr2;
return IN6_ARE_ADDR_EQUAL(&in6_1->sin6_addr, &in6_2->sin6_addr);
default:
return false;
}
} else {
return false;
}
}
bool CUDPSocket::isNone(const sockaddr_storage& addr)
{
struct sockaddr_in *in = (struct sockaddr_in *)&addr;
return ((addr.ss_family == AF_INET) && (in->sin_addr.s_addr == htonl(INADDR_NONE)));
}
char* CUDPSocket::display(const sockaddr_storage& addr, char* buffer, unsigned int length)
{
assert(buffer != NULL);
assert(length > INET6_ADDRSTRLEN);
switch (addr.ss_family) {
case AF_INET: {
struct sockaddr_in* in4 = (struct sockaddr_in*)&addr;
::inet_ntop(AF_INET, &in4, buffer, length);
::sprintf(buffer + ::strlen(buffer), ":%u", in4->sin_port);
}
break;
case AF_INET6: {
struct sockaddr_in6* in6 = (struct sockaddr_in6*)&addr;
::inet_ntop(AF_INET6, &in6, buffer, length);
::sprintf(buffer + ::strlen(buffer), ":%u", in6->sin6_port);
}
break;
default:
::strcpy(buffer, "Unknown");
break;
}
return buffer;
}
bool CUDPSocket::open(const sockaddr_storage& address)
{
return open(address.ss_family);
}
bool CUDPSocket::open(unsigned int af)
{
return open(0, af, m_address_save, m_port_save);
}
bool CUDPSocket::open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port)
{
sockaddr_storage addr;
unsigned int addrlen;
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = af;
/* to determine protocol family, call lookup() first. */
int err = lookup(address, port, addr, addrlen, hints);
if (err != 0) {
LogError("The local address is invalid - %s", address.c_str());
return false;
}
int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0);
if (fd < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot create the UDP socket, err: %lu", ::GetLastError());
#else
LogError("Cannot create the UDP socket, err: %d", errno);
#endif
return false;
}
m_address[index] = address;
m_port[index] = port;
m_af[index] = addr.ss_family;
m_fd[index] = fd;
if (port > 0U) {
int reuse = 1;
if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot set the UDP socket option, err: %lu", ::GetLastError());
#else
LogError("Cannot set the UDP socket option, err: %d", errno);
#endif
return false;
}
if (::bind(fd, (sockaddr*)&addr, addrlen) == -1) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Cannot bind the UDP address, err: %lu", ::GetLastError());
#else
LogError("Cannot bind the UDP address, err: %d", errno);
#endif
return false;
}
LogInfo("Opening UDP port on %u", port);
}
return true;
}
int CUDPSocket::read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length)
{
assert(buffer != NULL);
assert(length > 0U);
// Check that the readfrom() won't block
int i, n;
struct pollfd pfd[UDP_SOCKET_MAX];
for (i = n = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] >= 0) {
pfd[n].fd = m_fd[i];
pfd[n].events = POLLIN;
n++;
}
}
// no socket descriptor to receive
if (n == 0)
return 0;
// Return immediately
#if defined(_WIN32) || defined(_WIN64)
int ret = WSAPoll(pfd, n, 0);
#else
int ret = ::poll(pfd, n, 0);
#endif
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from UDP poll, err: %lu", ::GetLastError());
#else
LogError("Error returned from UDP poll, err: %d", errno);
#endif
return -1;
}
int index;
for (i = 0; i < n; i++) {
// round robin
index = (i + m_counter) % n;
if (pfd[index].revents & POLLIN)
break;
}
if (i == n)
return 0;
#if defined(_WIN32) || defined(_WIN64)
int size = sizeof(sockaddr_storage);
#else
socklen_t size = sizeof(sockaddr_storage);
#endif
#if defined(_WIN32) || defined(_WIN64)
int len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#else
ssize_t len = ::recvfrom(pfd[index].fd, (char*)buffer, length, 0, (sockaddr *)&address, &size);
#endif
if (len <= 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from recvfrom, err: %lu", ::GetLastError());
#else
LogError("Error returned from recvfrom, err: %d", errno);
if (len == -1 && errno == ENOTSOCK) {
LogMessage("Re-opening UDP port on %u", m_port);
close();
open();
}
#endif
return -1;
}
m_counter++;
address_length = size;
return len;
}
bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length)
{
assert(buffer != NULL);
assert(length > 0U);
bool result = false;
for (int i = 0; i < UDP_SOCKET_MAX; i++) {
if (m_fd[i] < 0 || m_af[i] != address.ss_family)
continue;
#if defined(_WIN32) || defined(_WIN64)
int ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
#else
ssize_t ret = ::sendto(m_fd[i], (char *)buffer, length, 0, (sockaddr *)&address, address_length);
#endif
if (ret < 0) {
#if defined(_WIN32) || defined(_WIN64)
LogError("Error returned from sendto, err: %lu", ::GetLastError());
#else
LogError("Error returned from sendto, err: %d", errno);
#endif
} else {
#if defined(_WIN32) || defined(_WIN64)
if (ret == int(length))
result = true;
#else
if (ret == ssize_t(length))
result = true;
#endif
}
}
return result;
}
void CUDPSocket::close()
{
for (int i = 0; i < UDP_SOCKET_MAX; i++)
close(m_fd[i]);
}
void CUDPSocket::close(const unsigned int index)
{
if (m_fd[index] >= 0) {
#if defined(_WIN32) || defined(_WIN64)
::closesocket(m_fd[index]);
#else
::close(m_fd[index]);
#endif
m_fd[index] = -1;
}
}

View file

@ -1,85 +0,0 @@
/*
* Copyright (C) 2009-2011,2013,2015,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 UDPSocket_H
#define UDPSocket_H
#include <string>
#if !defined(_WIN32) && !defined(_WIN64)
#include <netdb.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <poll.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#else
#include <ws2tcpip.h>
#endif
#if !defined(UDP_SOCKET_MAX)
#define UDP_SOCKET_MAX 1
#endif
enum IPMATCHTYPE {
IMT_ADDRESS_AND_PORT,
IMT_ADDRESS_ONLY
};
class CUDPSocket {
public:
CUDPSocket(const std::string& address, unsigned int port = 0U);
CUDPSocket(unsigned int port = 0U);
~CUDPSocket();
bool open(unsigned int af = AF_UNSPEC);
bool open(const sockaddr_storage& address);
bool open(const unsigned int index, const unsigned int af, const std::string& address, const unsigned int port);
int read(unsigned char* buffer, unsigned int length, sockaddr_storage& address, unsigned int &address_length);
bool write(const unsigned char* buffer, unsigned int length, const sockaddr_storage& address, unsigned int address_length);
void close();
void close(const unsigned int index);
static void startup();
static void shutdown();
static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length);
static int lookup(const std::string& hostName, unsigned int port, sockaddr_storage& address, unsigned int& address_length, struct addrinfo& hints);
static bool match(const sockaddr_storage& addr1, const sockaddr_storage& addr2, IPMATCHTYPE type = IMT_ADDRESS_AND_PORT);
static bool isNone(const sockaddr_storage& addr);
static char* display(const sockaddr_storage& address, char* buffer, unsigned int length);
private:
std::string m_address_save;
unsigned short m_port_save;
std::string m_address[UDP_SOCKET_MAX];
unsigned short m_port[UDP_SOCKET_MAX];
unsigned int m_af[UDP_SOCKET_MAX];
int m_fd[UDP_SOCKET_MAX];
unsigned int m_counter;
};
#endif

View file

@ -1,146 +0,0 @@
/*
* Copyright (C) 2009,2014,2015,2016 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; version 2 of the License.
*
* 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.
*/
#include "Utils.h"
#include "Log.h"
#include <cstdio>
#include <cassert>
void CUtils::dump(const std::string& title, const unsigned char* data, unsigned int length)
{
assert(data != NULL);
dump(2U, title, data, length);
}
void CUtils::dump(int level, const std::string& title, const unsigned char* data, unsigned int length)
{
assert(data != NULL);
::Log(level, "%s", title.c_str());
unsigned int offset = 0U;
while (length > 0U) {
std::string output;
unsigned int bytes = (length > 16U) ? 16U : length;
for (unsigned i = 0U; i < bytes; i++) {
char temp[10U];
::sprintf(temp, "%02X ", 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 = data[offset + i];
if (::isprint(c))
output += c;
else
output += '.';
}
output += '*';
::Log(level, "%04X: %s", offset, output.c_str());
offset += 16U;
if (length >= 16U)
length -= 16U;
else
length = 0U;
}
}
void CUtils::dump(const std::string& title, const bool* bits, unsigned int length)
{
assert(bits != NULL);
dump(2U, title, bits, length);
}
void CUtils::dump(int level, const std::string& title, const bool* bits, unsigned int length)
{
assert(bits != NULL);
unsigned char bytes[100U];
unsigned int nBytes = 0U;
for (unsigned int n = 0U; n < length; n += 8U, nBytes++)
bitsToByteBE(bits + n, bytes[nBytes]);
dump(level, title, bytes, nBytes);
}
void CUtils::byteToBitsBE(unsigned char byte, bool* bits)
{
assert(bits != NULL);
bits[0U] = (byte & 0x80U) == 0x80U;
bits[1U] = (byte & 0x40U) == 0x40U;
bits[2U] = (byte & 0x20U) == 0x20U;
bits[3U] = (byte & 0x10U) == 0x10U;
bits[4U] = (byte & 0x08U) == 0x08U;
bits[5U] = (byte & 0x04U) == 0x04U;
bits[6U] = (byte & 0x02U) == 0x02U;
bits[7U] = (byte & 0x01U) == 0x01U;
}
void CUtils::byteToBitsLE(unsigned char byte, bool* bits)
{
assert(bits != NULL);
bits[0U] = (byte & 0x01U) == 0x01U;
bits[1U] = (byte & 0x02U) == 0x02U;
bits[2U] = (byte & 0x04U) == 0x04U;
bits[3U] = (byte & 0x08U) == 0x08U;
bits[4U] = (byte & 0x10U) == 0x10U;
bits[5U] = (byte & 0x20U) == 0x20U;
bits[6U] = (byte & 0x40U) == 0x40U;
bits[7U] = (byte & 0x80U) == 0x80U;
}
void CUtils::bitsToByteBE(const bool* bits, unsigned char& byte)
{
assert(bits != NULL);
byte = bits[0U] ? 0x80U : 0x00U;
byte |= bits[1U] ? 0x40U : 0x00U;
byte |= bits[2U] ? 0x20U : 0x00U;
byte |= bits[3U] ? 0x10U : 0x00U;
byte |= bits[4U] ? 0x08U : 0x00U;
byte |= bits[5U] ? 0x04U : 0x00U;
byte |= bits[6U] ? 0x02U : 0x00U;
byte |= bits[7U] ? 0x01U : 0x00U;
}
void CUtils::bitsToByteLE(const bool* bits, unsigned char& byte)
{
assert(bits != NULL);
byte = bits[0U] ? 0x01U : 0x00U;
byte |= bits[1U] ? 0x02U : 0x00U;
byte |= bits[2U] ? 0x04U : 0x00U;
byte |= bits[3U] ? 0x08U : 0x00U;
byte |= bits[4U] ? 0x10U : 0x00U;
byte |= bits[5U] ? 0x20U : 0x00U;
byte |= bits[6U] ? 0x40U : 0x00U;
byte |= bits[7U] ? 0x80U : 0x00U;
}

View file

@ -1,36 +0,0 @@
/*
* Copyright (C) 2009,2014,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; version 2 of the License.
*
* 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.
*/
#ifndef Utils_H
#define Utils_H
#include <string>
class CUtils {
public:
static void dump(const std::string& title, const unsigned char* data, unsigned int length);
static void dump(int level, const std::string& title, const unsigned char* data, unsigned int length);
static void dump(const std::string& title, const bool* bits, unsigned int length);
static void dump(int level, const std::string& title, const bool* bits, unsigned int length);
static void byteToBitsBE(unsigned char byte, bool* bits);
static void byteToBitsLE(unsigned char byte, bool* bits);
static void bitsToByteBE(const bool* bits, unsigned char& byte);
static void bitsToByteLE(const bool* bits, unsigned char& byte);
private:
};
#endif

View file

@ -1,24 +0,0 @@
/*
* Copyright (C) 2015,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.
*/
#if !defined(VERSION_H)
#define VERSION_H
const char* VERSION = "20201124";
#endif

View file

@ -1,49 +0,0 @@
/*
* 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(YSFDefines_H)
#define YSFDefines_H
const unsigned int YSF_FRAME_LENGTH_BYTES = 120U;
const unsigned char YSF_SYNC_BYTES[] = {0xD4U, 0x71U, 0xC9U, 0x63U, 0x4DU};
const unsigned int YSF_SYNC_LENGTH_BYTES = 5U;
const unsigned int YSF_FICH_LENGTH_BYTES = 25U;
const unsigned char YSF_SYNC_OK = 0x01U;
const unsigned int YSF_CALLSIGN_LENGTH = 10U;
const unsigned char YSF_FI_HEADER = 0x00U;
const unsigned char YSF_FI_COMMUNICATIONS = 0x01U;
const unsigned char YSF_FI_TERMINATOR = 0x02U;
const unsigned char YSF_FI_TEST = 0x03U;
const unsigned char YSF_DT_VD_MODE1 = 0x00U;
const unsigned char YSF_DT_DATA_FR_MODE = 0x01U;
const unsigned char YSF_DT_VD_MODE2 = 0x02U;
const unsigned char YSF_DT_VOICE_FR_MODE = 0x03U;
const unsigned char YSF_CM_GROUP = 0x00U;
const unsigned char YSF_CM_INDIVIDUAL = 0x03U;
const unsigned char YSF_MR_NOT_BUSY = 0x01U;
const unsigned char YSF_MR_BUSY = 0x02U;
#endif

View file

@ -1,357 +0,0 @@
/*
* Copyright (C) 2016,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
* 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 "YSFReflector.h"
#include "StopWatch.h"
#include "Network.h"
#include "Version.h"
#include "Thread.h"
#include "Log.h"
#if defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <pwd.h>
#endif
#if defined(_WIN32) || defined(_WIN64)
const char* DEFAULT_INI_FILE = "YSFReflector.ini";
#else
const char* DEFAULT_INI_FILE = "/etc/YSFReflector.ini";
#endif
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <ctime>
#include <cstring>
int main(int argc, char** argv)
{
const char* iniFile = DEFAULT_INI_FILE;
if (argc > 1) {
for (int currentArg = 1; currentArg < argc; ++currentArg) {
std::string arg = argv[currentArg];
if ((arg == "-v") || (arg == "--version")) {
::fprintf(stdout, "YSFReflector version %s\n", VERSION);
return 0;
} else if (arg.substr(0, 1) == "-") {
::fprintf(stderr, "Usage: YSFReflector [-v|--version] [filename]\n");
return 1;
} else {
iniFile = argv[currentArg];
}
}
}
CYSFReflector* reflector = new CYSFReflector(std::string(iniFile));
reflector->run();
delete reflector;
return 0;
}
CYSFReflector::CYSFReflector(const std::string& file) :
m_conf(file),
m_repeaters()
{
CUDPSocket::startup();
}
CYSFReflector::~CYSFReflector()
{
CUDPSocket::shutdown();
}
void CYSFReflector::run()
{
bool ret = m_conf.read();
if (!ret) {
::fprintf(stderr, "YSFReflector: cannot read the .ini file\n");
return;
}
#if !defined(_WIN32) && !defined(_WIN64)
bool m_daemon = m_conf.getDaemon();
if (m_daemon) {
// Create new process
pid_t pid = ::fork();
if (pid == -1) {
::fprintf(stderr, "Couldn't fork() , exiting\n");
return;
} else if (pid != 0) {
exit(EXIT_SUCCESS);
}
// Create new session and process group
if (::setsid() == -1) {
::fprintf(stderr, "Couldn't setsid(), exiting\n");
return;
}
// Set the working directory to the root directory
if (::chdir("/") == -1) {
::fprintf(stderr, "Couldn't cd /, exiting\n");
return;
}
// If we are currently root...
if (getuid() == 0) {
struct passwd* user = ::getpwnam("mmdvm");
if (user == NULL) {
::fprintf(stderr, "Could not get the mmdvm user, exiting\n");
return;
}
uid_t mmdvm_uid = user->pw_uid;
gid_t mmdvm_gid = user->pw_gid;
// Set user and group ID's to mmdvm:mmdvm
if (setgid(mmdvm_gid) != 0) {
::fprintf(stderr, "Could not set mmdvm GID, exiting\n");
return;
}
if (setuid(mmdvm_uid) != 0) {
::fprintf(stderr, "Could not set mmdvm UID, exiting\n");
return;
}
// Double check it worked (AKA Paranoia)
if (setuid(0) != -1) {
::fprintf(stderr, "It's possible to regain root - something is wrong!, exiting\n");
return;
}
}
}
#endif
#if !defined(_WIN32) && !defined(_WIN64)
ret = ::LogInitialise(m_daemon, m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel(), m_conf.getLogFileRotate());
#else
ret = ::LogInitialise(false, m_conf.getLogFilePath(), m_conf.getLogFileRoot(), m_conf.getLogFileLevel(), m_conf.getLogDisplayLevel(), m_conf.getLogFileRotate());
#endif
if (!ret) {
::fprintf(stderr, "YSFReflector: unable to open the log file\n");
return;
}
#if !defined(_WIN32) && !defined(_WIN64)
if (m_daemon) {
::close(STDIN_FILENO);
::close(STDOUT_FILENO);
::close(STDERR_FILENO);
}
#endif
CNetwork network(m_conf.getNetworkPort(), m_conf.getId(), m_conf.getName(), m_conf.getDescription(), m_conf.getNetworkDebug());
ret = network.open();
if (!ret) {
::LogFinalise();
return;
}
network.setCount(0);
CStopWatch stopWatch;
stopWatch.start();
CTimer dumpTimer(1000U, 120U);
dumpTimer.start();
CTimer pollTimer(1000U, 5U);
pollTimer.start();
LogMessage("Starting YSFReflector-%s", VERSION);
CTimer watchdogTimer(1000U, 0U, 1500U);
unsigned char tag[YSF_CALLSIGN_LENGTH];
unsigned char src[YSF_CALLSIGN_LENGTH];
unsigned char dst[YSF_CALLSIGN_LENGTH];
for (;;) {
unsigned char buffer[200U];
sockaddr_storage addr;
unsigned int addrLen;
unsigned int len = network.readData(buffer, 200U, addr, addrLen);
if (len > 0U) {
CYSFRepeater* rpt = findRepeater(addr);
if (::memcmp(buffer, "YSFP", 4U) == 0) {
if (rpt == NULL) {
rpt = new CYSFRepeater;
rpt->m_callsign = std::string((char*)(buffer + 4U), 10U);
rpt->m_addr = addr;
rpt->m_addrLen = addrLen;
m_repeaters.push_back(rpt);
network.setCount(m_repeaters.size());
char buff[80U];
LogMessage("Adding %s (%s)", rpt->m_callsign.c_str(), CUDPSocket::display(addr, buff, 80U));
}
rpt->m_timer.start();
network.writePoll(addr, addrLen);
} else if (::memcmp(buffer + 0U, "YSFU", 4U) == 0 && rpt != NULL) {
char buff[80U];
LogMessage("Removing %s (%s) unlinked", rpt->m_callsign.c_str(), CUDPSocket::display(addr, buff, 80U));
for (std::vector<CYSFRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
CYSFRepeater* itRpt = *it;
if (CUDPSocket::match(itRpt->m_addr, rpt->m_addr)) {
m_repeaters.erase(it);
delete itRpt;
break;
}
}
network.setCount(m_repeaters.size());
} else if (::memcmp(buffer + 0U, "YSFD", 4U) == 0 && rpt != NULL) {
if (!watchdogTimer.isRunning()) {
::memcpy(tag, buffer + 4U, YSF_CALLSIGN_LENGTH);
if (::memcmp(buffer + 14U, " ", YSF_CALLSIGN_LENGTH) != 0)
::memcpy(src, buffer + 14U, YSF_CALLSIGN_LENGTH);
else
::memcpy(src, "??????????", YSF_CALLSIGN_LENGTH);
if (::memcmp(buffer + 24U, " ", YSF_CALLSIGN_LENGTH) != 0)
::memcpy(dst, buffer + 24U, YSF_CALLSIGN_LENGTH);
else
::memcpy(dst, "??????????", YSF_CALLSIGN_LENGTH);
LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U);
} else {
if (::memcmp(tag, buffer + 4U, YSF_CALLSIGN_LENGTH) == 0) {
bool changed = false;
if (::memcmp(buffer + 14U, " ", YSF_CALLSIGN_LENGTH) != 0 && ::memcmp(src, "??????????", YSF_CALLSIGN_LENGTH) == 0) {
::memcpy(src, buffer + 14U, YSF_CALLSIGN_LENGTH);
changed = true;
}
if (::memcmp(buffer + 24U, " ", YSF_CALLSIGN_LENGTH) != 0 && ::memcmp(dst, "??????????", YSF_CALLSIGN_LENGTH) == 0) {
::memcpy(dst, buffer + 24U, YSF_CALLSIGN_LENGTH);
changed = true;
}
if (changed)
LogMessage("Received data from %10.10s to %10.10s at %10.10s", src, dst, buffer + 4U);
}
}
watchdogTimer.start();
for (std::vector<CYSFRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
if (!CUDPSocket::match((*it)->m_addr, addr))
network.writeData(buffer, (*it)->m_addr, (*it)->m_addrLen);
}
if ((buffer[34U] & 0x01U) == 0x01U) {
LogMessage("Received end of transmission");
watchdogTimer.stop();
}
}
}
unsigned int ms = stopWatch.elapsed();
stopWatch.start();
pollTimer.clock(ms);
if (pollTimer.hasExpired()) {
for (std::vector<CYSFRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it)
network.writePoll((*it)->m_addr, (*it)->m_addrLen);
pollTimer.start();
}
// Remove any repeaters that haven't reported for a while
for (std::vector<CYSFRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it)
(*it)->m_timer.clock(ms);
for (std::vector<CYSFRepeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
CYSFRepeater* itRpt = *it;
if (itRpt->m_timer.hasExpired()) {
char buff[80U];
LogMessage("Removing %s (%s) disappeared", itRpt->m_callsign.c_str(), CUDPSocket::display(itRpt->m_addr, buff, 80U));
m_repeaters.erase(it);
delete itRpt;
network.setCount(m_repeaters.size());
break;
}
}
watchdogTimer.clock(ms);
if (watchdogTimer.isRunning() && watchdogTimer.hasExpired()) {
LogMessage("Network watchdog has expired");
watchdogTimer.stop();
}
dumpTimer.clock(ms);
if (dumpTimer.hasExpired()) {
dumpRepeaters();
dumpTimer.start();
}
if (ms < 5U)
CThread::sleep(5U);
}
network.close();
::LogFinalise();
}
CYSFRepeater* CYSFReflector::findRepeater(const sockaddr_storage& addr) const
{
for (std::vector<CYSFRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
if (CUDPSocket::match(addr, (*it)->m_addr))
return *it;
}
return NULL;
}
void CYSFReflector::dumpRepeaters() const
{
if (m_repeaters.size() == 0U) {
LogMessage("No repeaters/gateways linked");
return;
}
LogMessage("Currently linked repeaters/gateways:");
for (std::vector<CYSFRepeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
std::string callsign = (*it)->m_callsign;
sockaddr_storage addr = (*it)->m_addr;
unsigned int timer = (*it)->m_timer.getTimer();
unsigned int timeout = (*it)->m_timer.getTimeout();
char buffer[80U];
LogMessage(" %s: %s %u/%u", callsign.c_str(), CUDPSocket::display(addr, buffer, 80U), timer, timeout);
}
}

View file

@ -1,73 +0,0 @@
/*
* Copyright (C) 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.
*/
#if !defined(YSFReflector_H)
#define YSFReflector_H
#include "Timer.h"
#include "Conf.h"
#include <cstdio>
#include <string>
#include <vector>
#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 <arpa/inet.h>
#else
#include <WS2tcpip.h>
#endif
class CYSFRepeater {
public:
CYSFRepeater() :
m_callsign(),
m_addr(),
m_addrLen(0U),
m_timer(1000U, 60U)
{
}
std::string m_callsign;
sockaddr_storage m_addr;
unsigned int m_addrLen;
CTimer m_timer;
};
class CYSFReflector
{
public:
CYSFReflector(const std::string& file);
~CYSFReflector();
void run();
private:
CConf m_conf;
std::vector<CYSFRepeater*> m_repeaters;
CYSFRepeater* findRepeater(const sockaddr_storage& addr) const;
void dumpRepeaters() const;
};
#endif

View file

@ -1,22 +0,0 @@
[General]
Daemon=1
[Info]
# Remember to register your YSFReflector at:
# https://register.ysfreflector.de
# Id=5 digits only
Name=16 characters max
Description=14 characters max
[Log]
# Logging levels, 0=No logging
DisplayLevel=1
FileLevel=1
FilePath=.
FileRoot=YSFReflector
FileRotate=1
[Network]
Port=42000
Debug=0

View file

@ -1,76 +0,0 @@
#!/bin/bash
### BEGIN INIT INFO
#
# Provides: YSFReflector
# Required-Start: $all
# Required-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Example startscript YSFReflector
#
### END INIT INFO
## Fill in name of program here.
PROG="YSFReflector"
PROG_PATH="/usr/local/bin/"
PROG_ARGS="/etc/YSFReflector.ini"
PIDFILE="/var/run/YSFReflector.pid"
USER="root"
start() {
if [ -e $PIDFILE ]; then
## Program is running, exit with error.
echo "Error! $PROG is currently running!" 1>&2
exit 1
else
cd $PROG_PATH
./$PROG $PROG_ARGS
echo "$PROG started"
touch $PIDFILE
fi
}
stop() {
if [ -e $PIDFILE ]; then
## Program is running, so stop it
echo "$PROG is running"
rm -f $PIDFILE
killall $PROG
echo "$PROG stopped"
else
## Program is not running, exit with error.
echo "Error! $PROG not started!" 1>&2
exit 1
fi
}
## Check to see if we are running as root first.
## Found at
## http://www.cyberciti.biz/tips/shell-root-user-check-script.html
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" 1>&2
exit 1
fi
case "$1" in
start)
start
exit 0
;;
stop)
stop
exit 0
;;
reload|restart|force-reload)
stop
sleep 5
start
exit 0
;;
**)
echo "Usage: $0 {start|stop|reload}" 1>&2
exit 1
;;
esac
exit 0
### END

View file

@ -1,175 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{317D87F1-3485-4739-9F94-A07738B8E19D}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>YSFReflector</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;HAVE_LOG_H;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;HAVE_LOG_H;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;HAVE_LOG_H;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;HAVE_LOG_H;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClInclude Include="Conf.h" />
<ClInclude Include="Log.h" />
<ClInclude Include="Network.h" />
<ClInclude Include="StopWatch.h" />
<ClInclude Include="Thread.h" />
<ClInclude Include="Timer.h" />
<ClInclude Include="UDPSocket.h" />
<ClInclude Include="Utils.h" />
<ClInclude Include="Version.h" />
<ClInclude Include="YSFDefines.h" />
<ClInclude Include="YSFReflector.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="Conf.cpp" />
<ClCompile Include="Log.cpp" />
<ClCompile Include="Network.cpp" />
<ClCompile Include="StopWatch.cpp" />
<ClCompile Include="Thread.cpp" />
<ClCompile Include="Timer.cpp" />
<ClCompile Include="UDPSocket.cpp" />
<ClCompile Include="Utils.cpp" />
<ClCompile Include="YSFReflector.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -1,77 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Network.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Timer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="UDPSocket.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Utils.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="YSFDefines.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="YSFReflector.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="StopWatch.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Version.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Log.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Conf.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Thread.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="Network.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Timer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="UDPSocket.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Utils.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="YSFReflector.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="StopWatch.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Log.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Conf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Thread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -1,29 +0,0 @@
FROM debian:buster-slim AS builder
RUN apt-get update && \
apt-get install -y build-essential git
RUN mkdir /code && \
git clone https://github.com/g4klx/YSFClients.git /code && \
cd /code/YSFReflector/ && \
make clean all
FROM debian:buster-slim
ENV REFLECTOR_NAME set_me
ENV REFLECTOR_DESCRIPTION set_me
RUN apt-get update && \
apt-get install -y procps && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \
mkdir /app
COPY --from=builder /code/YSFReflector/YSFReflector.ini /app/YSFReflector.ini
COPY --from=builder /code/YSFReflector/YSFReflector /app/YSFReflector
COPY entrypoint.sh /entrypoint.sh
EXPOSE 42000/udp
ENTRYPOINT ["/entrypoint.sh"]
CMD ["/app/YSFReflector", "/app/YSFReflector.ini"]
HEALTHCHECK CMD ps aux | grep [Y]SFReflector || exit 1

View file

@ -1,25 +0,0 @@
# YSFReflector Docker Image
The `Dockerfile` here is intended to produce an image which will be stored on [Docker Hub](https://hub.docker.com/).
# Requirements
* [Docker](https://docs.docker.com/install/)
* Firewall setup to accept 42000 (UDP)
# Usage
`docker run -e REFLECTOR_NAME=YOUR_NAME_HERE -eREFLECTOR_DESCRIPTION=YOUR_DESCRIPTION_HERE -p 42000:42000/udp neilbartley/ysfreflector:latest`
# How to build
Building isn't required unless you need a newer image or have made changes.
```
cd YSFReflector/docker
YSF_TAG=$(date +'%Y%m%d')-$(git rev-parse --short HEAD)
docker build --rm -t neilbartley/ysfreflector:$YSF_TAG .
docker tag neilbartley/ysfreflector:$YSF_TAG neilbartley/ysfreflector:latest
docker push neilbartley/ysfreflector:$YSF_TAG
docker push neilbartley/ysfreflector:latest
```

View file

@ -1,18 +0,0 @@
#!/bin/bash
# Disable daemon mode
sed -i -e "s/Daemon=1/Daemon=0/g" /app/YSFReflector.ini
# Reflector name and description validation
if [ "${REFLECTOR_NAME}" == "set_me" ] ; then echo "Please set REFLECTOR_NAME environment variable with -e (max 16 characters)"; exit 1 ; fi
if [ ${#REFLECTOR_NAME} -gt 16 ] ; then echo "REFLECTOR_NAME environment variable can be at most 16 characters"; exit 1 ; fi
if [ "${REFLECTOR_DESCRIPTION}" == "set_me" ] ; then echo "Please set REFLECTOR_DESCRIPTION environment variable with -e (min 14 characters)"; exit 1 ; fi
if [ ${#REFLECTOR_DESCRIPTION} -gt 14 ] ; then echo "REFLECTOR_DESCRIPTION environment variable can be at most 14 characters"; exit 1 ; fi
# Reflector name and description replacement in config file
sed -i -e "s/Name=.*/Name=${REFLECTOR_NAME}/g" /app/YSFReflector.ini
sed -i -e "s/Description=.*/Description=${REFLECTOR_DESCRIPTION}/g" /app/YSFReflector.ini
echo "Remember to register your YSFReflector at: https://register.ysfreflector.de"
exec "$@"