Compare commits
401 Commits
ff11c079cc
...
d0638f1f38
Author | SHA1 | Date |
---|---|---|
Jonathan Naylor | d0638f1f38 | |
Jonathan Naylor | 4f89e78549 | |
n7eal | f09db16f9b | |
k7pws | f3cc0a2d3a | |
Jonathan Naylor | 9cabcecc89 | |
Jonathan Naylor | 486455c643 | |
Jonathan Naylor | 30879a0f04 | |
Jonathan Naylor | 7c38895c01 | |
Jonathan Naylor | d82a7b9435 | |
Jonathan Naylor | 968e33740b | |
bduck014 | 77bffe88ad | |
bduck014 | b1218dbc19 | |
Jonathan Naylor | ec6fe93611 | |
Jonathan Naylor | cb8e757ada | |
Alex Bowman | 5bafa7fd95 | |
Jonathan Naylor | a8e242a598 | |
Jonathan Naylor | 9f96725981 | |
maq1017 | a2798ad7c0 | |
Steve Miller | 06d2ee959c | |
Jonathan Naylor | 29c68240fd | |
Alex Bowman | fc32920d30 | |
Jonathan Naylor | b10a554b0b | |
Alex Bowman | 3183f67d1c | |
Jonathan Naylor | 38d6777b16 | |
PU5SMS | 803b85887b | |
Jonathan Naylor | e642ac05cc | |
Matt Fiscus | f215fe4256 | |
mfiscus | 23ac7862d3 | |
Jonathan Naylor | 79c8e1749f | |
Jonathan Naylor | ca951356a1 | |
Jonathan Naylor | d966674fd1 | |
M0JGX | 2740482618 | |
Heonmin Lee | cebdbf136e | |
Jonathan Naylor | c44877a788 | |
Jonathan Naylor | 0ec79c3ddd | |
Jonathan Naylor | fac3e3740f | |
ke8ane | 02cc5efe5d | |
Jonathan Naylor | aabcf022c6 | |
Chris Rowland | 124b852a16 | |
Chris Rowland | a6fe4a16dd | |
Jonathan Naylor | 7a99bb1673 | |
dl9cma | c342ce856b | |
Jonathan Naylor | e73e585049 | |
Inga Muste | 66a2bc7b5b | |
Inga Muste | 5ba0c3d73d | |
Jonathan Naylor | a459aa35d8 | |
Jonathan Naylor | dbdf56dbda | |
Esteban Mackay Q | f543f2de05 | |
Jonathan Naylor | 19363eb9cb | |
mfiscus | 09e6ac1949 | |
Jonathan Naylor | 80a9a3ce07 | |
Jonathan Naylor | 93e5778e21 | |
Jonathan Naylor | 46a1ed4648 | |
Jonathan Naylor | 4516ef92cf | |
W2GLD | 6d36479868 | |
Jonathan Naylor | 048907c5c7 | |
hb9fef | 3597fb3290 | |
modernham | 136d3c6def | |
Jonathan Naylor | 4b284b8be3 | |
Inga Muste | d549b1832c | |
Inga Muste | 0f6503b734 | |
Jonathan Naylor | e607742ee3 | |
M0JGX | 8b1fc4ec93 | |
Jonathan Naylor | 429fc13290 | |
Jonathan Naylor | 3702b95467 | |
Jonathan Naylor | cccf421a07 | |
bg8ioi | dd2e8335f3 | |
k0mgs | 1b374cf412 | |
wb6zsu | 0ba10e2ba6 | |
Jonathan Naylor | 48540dd7be | |
mfiscus | 4e14c2c1c3 | |
Jonathan Naylor | 9ed5f4af16 | |
Jesse Brown | c050e51c88 | |
Jonathan Naylor | fcb4271faf | |
Jonathan Naylor | f31fba111d | |
Scott Evans | 6e4ebfd18e | |
Jonathan Naylor | b77d1997a1 | |
Brock | 77eabf8358 | |
Jonathan Naylor | 5554ccac12 | |
Jonathan Naylor | 52cd8843e3 | |
kd8lbs | 513d29d671 | |
ncerreto | b878f6e8a9 | |
Jonathan Naylor | 04529bb3f7 | |
Jonathan Naylor | 99623a0865 | |
Klaus | 4288c2d0af | |
Jonathan Naylor | a9d576ee03 | |
Jonathan Naylor | 203f15e38f | |
Klaus | 29184f4190 | |
Jonathan Naylor | ac4fb9313b | |
Dave Behnke | fe69122740 | |
Dave Behnke | b5c6f8eced | |
Jonathan Naylor | e93eed8b6a | |
sigintsystems | d219500ca9 | |
Jonathan Naylor | b63b72a76e | |
M0VUB | 6ea9723227 | |
Jonathan Naylor | d8f25f8101 | |
k7pws | 2bdeb655e5 | |
Jonathan Naylor | a4beb6772d | |
M0GLJ | 7cb13b39d0 | |
M0GLJ | c8578216a9 | |
Jonathan Naylor | cdf8334ae5 | |
kd8grn | b57d62f82d | |
Jonathan Naylor | 56de5aa1b9 | |
Jonathan Naylor | 5e96359160 | |
Fabian F | 0f0c5e486b | |
Alex Bowman | 30d6eb050c | |
Jonathan Naylor | 21ba2b683e | |
Ethan Gollehon | e2a32d92c4 | |
Jonathan Naylor | c40ddbc7d9 | |
s-n-vandeneijkel | 4e5cd72cd5 | |
Jonathan Naylor | 00b4cef3b5 | |
bh1nyr | e8a6a2415f | |
Jonathan Naylor | 8995a6d4ac | |
M0JGX | 108a9c37c5 | |
Jonathan Naylor | fac6762be1 | |
Tony Langdon | 92898fc992 | |
Jonathan Naylor | e19b0af41c | |
Dr. George Smart | 8db0401185 | |
Jonathan Naylor | 1c43ec1d9d | |
Inga Muste | d33375496b | |
Jonathan Naylor | 691afb8a87 | |
Jonathan Naylor | ae6d52367f | |
k0mgs | dd31203efa | |
Jonathan Naylor | 8b7a5b6508 | |
Jonathan Naylor | ebc3febf25 | |
BI1LLM | f004f90fbb | |
KO4UYJ | e54ee334a5 | |
Jonathan Naylor | cd704b3fbb | |
Kimberly McBlaze | 64d306cf23 | |
Kimberly McBlaze | 39581936f9 | |
Kimberly McBlaze | 7ecab80eda | |
Jonathan Naylor | b1655028b4 | |
pu4ron | 954ba17fb0 | |
Jonathan Naylor | c5d2643c33 | |
tacoded | 30ad9e8187 | |
Jonathan Naylor | ed1182c208 | |
Jonathan Naylor | 1390ae397f | |
M0GLJ | 8ca56bcc8d | |
Jonathan Naylor | 1745e16239 | |
hb9fef | 38831e4fa7 | |
Jonathan Naylor | aa9ded66ab | |
Jonathan Naylor | a842b8d94f | |
Jonathan Naylor | ff2436d1d5 | |
hb9fef | b14cd2839a | |
Jonathan Naylor | f12f5722a1 | |
Merlinv3 | fa6f7ae711 | |
Jonathan Naylor | 02d71b0594 | |
N2WNS | 77f1499b61 | |
N2WNS | 7e4dc85a87 | |
Jonathan Naylor | 4bf807987c | |
Jonathan Naylor | 345cd4472b | |
tacoded | 99d0c387be | |
Jonathan Naylor | 10326dae87 | |
Jonathan Naylor | b19c842343 | |
ovec-kd8lbs | 8ca14aa3ba | |
Jonathan Naylor | dfc6644610 | |
tacoded | 9528bf4026 | |
Jonathan Naylor | f08ade9bdc | |
BudT | 5e675e9621 | |
Jonathan Naylor | a2350058dc | |
hb9fef | 81fecd0904 | |
Jonathan Naylor | fec2d798a5 | |
W2GLD | ccc229c086 | |
Jonathan Naylor | 6deffb63bb | |
Hubok | 64743ec332 | |
Jonathan Naylor | 2932981833 | |
Jonathan Naylor | 39cae20424 | |
Jonathan Naylor | 7a550e0b74 | |
Jonathan Naylor | 82eb0ca77a | |
Jonathan Naylor | fb963a409b | |
k7pws | 66382679bc | |
Jonathan Naylor | 446f8e0c8f | |
Alex Bowman | 62d322a9d3 | |
Jonathan Naylor | c869f53707 | |
Gametch1018 | accaf1972e | |
Jonathan Naylor | 1ae30481cd | |
Jonathan Naylor | 6e58c6d438 | |
Gametch1018 | 4b739aef08 | |
pu4ron | cf99f5535d | |
Jonathan Naylor | 23071f53d0 | |
dtyo-fla | 934e400c4a | |
Jonathan Naylor | 2ac86631ee | |
Jonathan Naylor | c23122958e | |
Bruno | 74f82009b3 | |
dtyo-fla | 4e5e66eea5 | |
Jonathan Naylor | 8b98ff85d5 | |
dtyo-fla | 9900124f9b | |
Jonathan Naylor | cc7a0be8a1 | |
M0UPM | ba797c6549 | |
Jonathan Naylor | c97a5d22b6 | |
pu4ron | 2c8410deea | |
Jonathan Naylor | 692b87693d | |
maq1017 | c947f04b69 | |
Jonathan Naylor | 2bb92ad441 | |
Jonathan Naylor | 5fa8b33f88 | |
M0GLJ | 4a7b2a9928 | |
Klaus | 6ac8b45e45 | |
Klaus | 672d532035 | |
Jonathan Naylor | 67ed67a27a | |
Jonathan Naylor | b3cfcda190 | |
Jonathan Naylor | 36547c1a3b | |
Pan | 6de929c6f1 | |
Jonathan Naylor | a9c981ac16 | |
Jonathan Naylor | c36635e07c | |
Gareth GM0WUR | 517dda8aef | |
Jonathan Naylor | d95650bf2a | |
Inga Muste | 12b35776da | |
Jonathan Naylor | 64e0fd412b | |
Marco | 197c30c5c6 | |
Jonathan Naylor | 81fba8a961 | |
Inga Muste | 7518ad338f | |
Jonathan Naylor | 3eda9d0a1d | |
Inga Muste | 174aac3eee | |
Inga Muste | d1e5321d77 | |
Inga Muste | b7048420ea | |
Jonathan Naylor | 22730f7233 | |
MW0MWZ | c522eea2fb | |
Jonathan Naylor | 51ab031166 | |
ScottDIrwin | b8623d56d9 | |
Jonathan Naylor | 0ceeb0a6f5 | |
Merlinv3 | 46fc6accac | |
ScottDIrwin | 8bb53473a3 | |
Jonathan Naylor | fcf263c71e | |
Merlinv3 | 0c41a0a224 | |
Jonathan Naylor | 54eb28cae6 | |
Jonathan Naylor | 853e4d1bc7 | |
W2GLD | 409dc92b3a | |
Jonathan Naylor | 6f338caaf1 | |
zsneese | 8310541258 | |
Jonathan Naylor | 4ae6fc10bd | |
Gametch1018 | 093471e0ef | |
Jonathan Naylor | 3c6b79f7c3 | |
Gametch1018 | 40bcd03d5d | |
Jonathan Naylor | 0960b0f92e | |
jriner63 | 6622a01f60 | |
Jonathan Naylor | 91c5fd4784 | |
Rudy | 23b4ee1f69 | |
Jonathan Naylor | ddfd8c9f37 | |
Hubok | bfc1b0dcad | |
Jonathan Naylor | 161f14aa25 | |
bh1nyr | d563205870 | |
bh1nyr | 4e81354dcf | |
bh1nyr | 5067d09571 | |
Jonathan Naylor | a39dfae962 | |
Hubok | 92df779fb0 | |
Jonathan Naylor | 6cfd2d5c8b | |
ku-mi | 915bd9374a | |
Jonathan Naylor | 8c558e4330 | |
bh1nyr | d0643fd2dc | |
bh1nyr | d7d9df82ac | |
bh1nyr | 6313ad1489 | |
bh1nyr | f92e8bfa2c | |
Jonathan Naylor | 4bf08b223c | |
Jonathan Naylor | 2e23c576e0 | |
Jonathan Naylor | 925ac33431 | |
bh1nyr | f862ce8c48 | |
N2KMB | 3ec7c3e84a | |
Jonathan Naylor | 04a6f99025 | |
N2KMB | b88a92beac | |
Jonathan Naylor | 80c11fe7c5 | |
bh1nyr | 2569a6e047 | |
Jonathan Naylor | 81510786a7 | |
Jonathan Naylor | 9830b9c349 | |
Jonathan Naylor | 2ee60e7212 | |
Jonathan Naylor | 253f5ce81b | |
Jonathan Naylor | 0f8cd16694 | |
Hubok | f475ccc077 | |
Jonathan Naylor | 82d3415d83 | |
Jonathan Naylor | ae87e0c207 | |
Rudy | 072d9023ef | |
Jonathan Naylor | c2afdf8654 | |
Kimberly McBlaze | ffbf0dd79e | |
Jonathan Naylor | 598bf8e4b0 | |
Klaus | f4bef14c26 | |
Jonathan Naylor | cd8c451b84 | |
W2GLD | 0a73b231ac | |
Jonathan Naylor | f3b93e904d | |
postmasterd1 | 068c31aacc | |
Jonathan Naylor | 2cbf4e9389 | |
Ryan Tourge N2YQT | 0acd8f65e2 | |
Jonathan Naylor | bd3f4cb16c | |
Inga Muste | 6f4072eff1 | |
Inga Muste | 2b309643cc | |
Jonathan Naylor | d4fcfd2e59 | |
Jay | 9db1622b7e | |
Jonathan Naylor | 73bb0c81c7 | |
David Andrzejewski | 26d7c88744 | |
Jonathan Naylor | da9c8e6a7c | |
David Andrzejewski | 317dd23f7c | |
David Andrzejewski | 69b6266a6f | |
Jonathan Naylor | 00d95a1e0b | |
BI1LLM | a93bd4b17b | |
Jonathan Naylor | 4304b21ed8 | |
Jonathan Naylor | b9c184173d | |
Jonathan Naylor | 7c8f2cb2d0 | |
9W2LWK | 8fea7864c6 | |
Jonathan Naylor | 452282512e | |
Carlos (KP4CA) | 8943305132 | |
Jonathan Naylor | 2aaefd00ec | |
Jonathan Naylor | 20ff57bc3c | |
Jonathan Naylor | 49a980cc4c | |
Jonathan Naylor | e397be0540 | |
Kimberly McBlaze | f3edb9a304 | |
Philip Thompson | 52a629f5d6 | |
Stephan | 42924ffb7a | |
Jonathan Naylor | 996904ad4b | |
Jonathan Naylor | 94417bd634 | |
Carlos (KP4CA) | 11a2d711ae | |
Jonathan Naylor | 4dbc172fc9 | |
Jonathan Naylor | 03c82ca594 | |
Jonathan Naylor | 46760576b2 | |
Jonathan Naylor | 10820e1560 | |
Jonathan Naylor | ae4f722391 | |
Jonathan Naylor | a18090aa21 | |
zsneese | 850bf7dbb6 | |
Philip Thompson | 1d8d36d804 | |
firealarmss | 8d95ecd3d8 | |
Gabriel Huang | 68a510a2fe | |
Stephen Brown | 44b2659ae8 | |
Jonathan Naylor | 138a090080 | |
Jonathan Naylor | 97ee42645e | |
Jonathan Naylor | 82c9df2fab | |
Jonathan Naylor | 61e72cfd58 | |
Jonathan Naylor | 8d46bde2a7 | |
Jonathan Naylor | c722b115d7 | |
Jonathan Naylor | 081d737c02 | |
Jim Nessen | 9dc2c08493 | |
zsneese | 34da1f107b | |
Jay | 29d4c62c39 | |
Gabriel Huang | 3a01488968 | |
Jonathan Naylor | b15be2fe3c | |
Inga Muste | 4e1d83f29d | |
Inga Muste | 5fe32de534 | |
Jonathan Naylor | 0ec92004ae | |
kb5rir | 2e12636f37 | |
Jonathan Naylor | f3efdf6874 | |
Daniel Caujolle-Bert | bd98561201 | |
Daniel Caujolle-Bert | 012456a340 | |
Jonathan Naylor | 46a2d6334d | |
Jonathan Naylor | ec69b5315b | |
Jonathan Naylor | 8d5068f4a8 | |
Jonathan Naylor | bfd80f0c50 | |
Jonathan Naylor | 9742f63e93 | |
Daniel Caujolle-Bert | baa0271237 | |
skyler440 | 7aa94c14bd | |
wb6dtb | 2faf0c040f | |
Jonathan Naylor | d64d84d4cc | |
Daniel Caujolle-Bert | ccc744ec01 | |
skyler440 | fe5bf211f1 | |
Jonathan Naylor | f692301cf6 | |
Jonathan Naylor | 8bdae1a246 | |
f1shs | 2b19b27f53 | |
Jonathan Naylor | 64e338e3cf | |
Inga Muste | e4cd11de76 | |
Jonathan Naylor | 3360f9733f | |
Inga Muste | 6b38a4b89c | |
Inga Muste | 895fac60a9 | |
Jonathan Naylor | 2d54dd2d4e | |
Jonathan Naylor | c50e588d77 | |
Rudy | 762510f559 | |
Rudy | 0f4e1e1f02 | |
Jonathan Naylor | 0f6aa1df51 | |
Inga Muste | 18e65fdee9 | |
Jonathan Naylor | 305b47c85c | |
Inga Muste | 152c79d65a | |
Jonathan Naylor | 0f396fea38 | |
Rudy | 58564aa162 | |
Jonathan Naylor | a625d5eebc | |
Rudy | 66db726fb9 | |
Jonathan Naylor | f7611cc31b | |
David Andrzejewski | 174ce73336 | |
Jonathan Naylor | ba510c70ff | |
Jonathan Naylor | da2426a562 | |
Jonathan Naylor | 6a2449ed53 | |
Jonathan Naylor | 5b66b433ba | |
Jonathan Naylor | 3ded268073 | |
Jonathan Naylor | 3afc189ea8 | |
n9krg | 372056516b | |
BudT | bbacbbbce0 | |
Rudy | 19f5a4e9a6 | |
Rudy | dedf546f56 | |
Rudy | bee98a740b | |
Jonathan Naylor | 397f9c87bf | |
Tony Langdon | ee95516a43 | |
Jonathan Naylor | 69c7f3622a | |
Merlinv3 | 6f4bf10302 | |
Jonathan Naylor | 0225928c4a | |
Rudy | 1d9ba2416f | |
Jonathan Naylor | b914f82b54 | |
elwood99 | 64f96d20cb | |
Jonathan Naylor | 469c5a1b40 | |
9W2LWK | b257d52e51 | |
Jonathan Naylor | 9aa4f51aee | |
Jonathan Naylor | a7f60dded3 | |
Jonathan Naylor | 48b1476147 | |
Jonathan Naylor | 1bee405bcb | |
Jay | 7009f4e71d | |
Jay | 538733bd19 | |
DO1OLI | 09caaa48f7 | |
Jonathan Naylor | 49094b606e | |
N6DOZ | 0fbae781e3 |
|
@ -13,6 +13,8 @@ x64
|
|||
*.user
|
||||
*.VC.db
|
||||
.vs
|
||||
P25Reflector/P25Reflector
|
||||
P25Gateway/P25Gateway
|
||||
P25Parrot/P25Parrot
|
||||
P25Gateway/GitVersion.h
|
||||
P25Parrot/GitVersion.h
|
||||
|
||||
|
|
2
Makefile
2
Makefile
|
@ -1,4 +1,4 @@
|
|||
SUBDIRS = P25Gateway P25Parrot P25Reflector
|
||||
SUBDIRS = P25Gateway P25Parrot
|
||||
CLEANDIRS = $(SUBDIRS:%=clean-%)
|
||||
INSTALLDIRS = $(SUBDIRS:%=install-%)
|
||||
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2010
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31105.61
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "P25Parrot", "P25Parrot\P25Parrot.vcxproj", "{2AE94EAA-FD57-45C9-8555-6425CFA777A3}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "P25Gateway", "P25Gateway\P25Gateway.vcxproj", "{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "P25Reflector", "P25Reflector\P25Reflector.vcxproj", "{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
|
@ -33,14 +31,6 @@ Global
|
|||
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Release|x64.Build.0 = Release|x64
|
||||
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Release|x86.ActiveCfg = Release|Win32
|
||||
{8B7A5406-8560-4B40-ADDA-9B8EBF93E232}.Release|x86.Build.0 = Release|Win32
|
||||
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Debug|x64.Build.0 = Debug|x64
|
||||
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Debug|x86.Build.0 = Debug|Win32
|
||||
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Release|x64.ActiveCfg = Release|x64
|
||||
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Release|x64.Build.0 = Release|x64
|
||||
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Release|x86.ActiveCfg = Release|Win32
|
||||
{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
CC = cc
|
||||
CXX = c++
|
||||
CFLAGS = -g -O3 -Wall -DHAVE_LOG_H -DUDP_SOCKET_MAX=2 -std=c++0x -pthread
|
||||
CFLAGS = -g -O3 -Wall -DHAVE_LOG_H -std=c++0x -pthread
|
||||
LIBS = -lpthread
|
||||
LDFLAGS = -g
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
@ -155,7 +156,7 @@ void CP25Gateway::run()
|
|||
return;
|
||||
}
|
||||
|
||||
// Double check it worked (AKA Paranoia)
|
||||
// Double check it worked (AKA Paranoia)
|
||||
if (setuid(0) != -1) {
|
||||
::fprintf(stderr, "It's possible to regain root - something is wrong!, exiting\n");
|
||||
return;
|
||||
|
@ -301,8 +302,18 @@ void CP25Gateway::run()
|
|||
hangTimer.start();
|
||||
}
|
||||
} else if (currentTG == 0U) {
|
||||
bool poll = false;
|
||||
unsigned char pollReply[11U] = { 0xF0U };
|
||||
std::string callsign = m_conf.getCallsign();
|
||||
|
||||
callsign.resize(10U, ' ');
|
||||
|
||||
// Build poll reply data
|
||||
for (unsigned int i = 0U; i < 10U; i++)
|
||||
pollReply[i + 1U] = callsign.at(i);
|
||||
|
||||
// Don't pass reflector control data through to the MMDVM
|
||||
if (buffer[0U] != 0xF0U && buffer[0U] != 0xF1U) {
|
||||
if ((buffer[0U] != 0xF0U && buffer[0U] != 0xF1U) || (poll = (::memcmp(buffer, pollReply, std::min(11U, len)) == 0))) {
|
||||
// Find the static TG that this audio data belongs to
|
||||
for (std::vector<CStaticTG>::const_iterator it = staticTGs.cbegin(); it != staticTGs.cend(); ++it) {
|
||||
if (CUDPSocket::match(addr, (*it).m_addr)) {
|
||||
|
@ -325,7 +336,8 @@ void CP25Gateway::run()
|
|||
buffer[3U] = (currentTG >> 0) & 0xFFU;
|
||||
}
|
||||
|
||||
localNetwork.write(buffer, len);
|
||||
if (!poll)
|
||||
localNetwork.write(buffer, len);
|
||||
|
||||
LogMessage("Switched to reflector %u due to network activity", currentTG);
|
||||
|
||||
|
@ -347,7 +359,7 @@ void CP25Gateway::run()
|
|||
srcId = (buffer[1U] << 16) & 0xFF0000U;
|
||||
srcId |= (buffer[2U] << 8) & 0x00FF00U;
|
||||
srcId |= (buffer[3U] << 0) & 0x0000FFU;
|
||||
|
||||
|
||||
if (dstTG != currentTG) {
|
||||
if (currentAddrLen > 0U) {
|
||||
std::string callsign = lookup->find(srcId);
|
||||
|
@ -449,7 +461,7 @@ void CP25Gateway::run()
|
|||
if (res > 0) {
|
||||
buffer[res] = '\0';
|
||||
if (::memcmp(buffer + 0U, "TalkGroup", 9U) == 0) {
|
||||
unsigned int tg = (unsigned int)::atoi((char*)(buffer + 9U));
|
||||
unsigned int tg = ((strlen((char*)buffer + 0U) > 10) ? (unsigned int)::atoi((char*)(buffer + 10U)) : 9999);
|
||||
|
||||
if (tg != currentTG) {
|
||||
if (currentAddrLen > 0U) {
|
||||
|
@ -514,6 +526,21 @@ void CP25Gateway::run()
|
|||
voice->linkedTo(currentTG);
|
||||
}
|
||||
}
|
||||
} else if (::memcmp(buffer + 0U, "status", 6U) == 0) {
|
||||
std::string state = std::string("p25:") + ((currentAddrLen > 0) ? "conn" : "disc");
|
||||
remoteSocket->write((unsigned char*)state.c_str(), (unsigned int)state.length(), addr, addrLen);
|
||||
} else if (::memcmp(buffer + 0U, "host", 4U) == 0) {
|
||||
std::string ref;
|
||||
|
||||
if (currentAddrLen > 0) {
|
||||
char buffer[INET6_ADDRSTRLEN];
|
||||
if (getnameinfo((struct sockaddr*)¤tAddr, currentAddrLen, buffer, sizeof(buffer), 0, 0, NI_NUMERICHOST | NI_NUMERICSERV) == 0) {
|
||||
ref = std::string(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
std::string host = std::string("p25:\"") + ((ref.length() == 0) ? "NONE" : ref) + "\"";
|
||||
remoteSocket->write((unsigned char*)host.c_str(), (unsigned int)host.length(), addr, addrLen);
|
||||
} else {
|
||||
CUtils::dump("Invalid remote command received", buffer, res);
|
||||
}
|
||||
|
|
|
@ -6,14 +6,29 @@
|
|||
# 6 XLX045E P25 <-> DMR/DSTAR/YSF/NXDN
|
||||
6 70.44.20.24 41000
|
||||
|
||||
# 38 Thailand P25 Link XLX Nexus
|
||||
38 p2538.freeddns.org 41002
|
||||
|
||||
# XLX137 Module A Link to YSF79655
|
||||
137 p25a.mywire.org 41000
|
||||
|
||||
# 138 P25 PKT THAILAND
|
||||
138 p25138.freeddns.org 41001
|
||||
|
||||
# P25 Link XLX148 Modules X
|
||||
148 p148.hs3tdi.com 41000
|
||||
|
||||
# 149 P25 Link To XLX Nexus Module X
|
||||
149 p25.pwk.ac.th 41000
|
||||
|
||||
# 164 K4FSG Reflector
|
||||
164 reflector.k4fsg.net 41000
|
||||
|
||||
# 202 HELLAS Zone P25
|
||||
202 hellaszone.com 41000
|
||||
|
||||
# 204 Technology First
|
||||
204 w8ufo.hamshack.info 41000
|
||||
# 204 W8UFO P25 Reflector
|
||||
204 41611.asnode.org 41000
|
||||
|
||||
# 214 SPAIN P25 Reflector
|
||||
214 214p25.xreflector.es 41000
|
||||
|
@ -21,21 +36,48 @@
|
|||
# 226 Romania YO P25 Network
|
||||
226 p25.dstar-yo.ro 41000
|
||||
|
||||
# 228 Switzerland - https://project25.ch
|
||||
228 project25.ch 41000
|
||||
|
||||
# 235 DVSPH UK Wide
|
||||
235 p25.dvsph.net 41000
|
||||
|
||||
# 260 HBLink Poland P25
|
||||
260 p25.hblink.pl 41000
|
||||
|
||||
# 304 W8ARA P25
|
||||
304 ara.selfip.net 41000
|
||||
|
||||
# 357 VARG http://www.varg.club
|
||||
357 3.215.215.169 41010
|
||||
|
||||
# 419 Toledo Amateur Digital Association
|
||||
419 tada-p25.ddns.net 41000
|
||||
|
||||
# 420 Super Freq
|
||||
420 hb.superfreqdigital.com 41000
|
||||
420 p25.superfreqdigital.com 41000
|
||||
|
||||
# 445 SuperMag Australia
|
||||
445 p25.Supermag.fishersaudio.com.au 41000
|
||||
|
||||
# 456 Apco25 Ruhrgebiet/NRW Germany
|
||||
456 456.ham-p25.de 41000
|
||||
|
||||
# 530 NZ
|
||||
530 zldigitalreflectors.hopto.org 41000
|
||||
|
||||
# 555 Georgia 900 P25
|
||||
555 georgia900p25.us 41000
|
||||
|
||||
# 556 ARFCOM AR15.com
|
||||
556 reflector.site 41000
|
||||
|
||||
# 621 HRCC LINK
|
||||
621 urf.hrcc.link 41000
|
||||
|
||||
# 666 Brazil PY1IP P25 Reflector - http://tg666.p25.py1ip.com
|
||||
666 p25.py1ip.com 41000
|
||||
|
||||
# 707 Rural Minnesota - Bridge to TGIF707, YSF US RuralMN-707
|
||||
707 707p25.kd0ioe.com 41000
|
||||
|
||||
|
@ -45,35 +87,71 @@
|
|||
# 730 Chile P25 Reflector to BM TG 730
|
||||
730 sdradio.cl 41000
|
||||
|
||||
# 762 W4PFT Multimode Linked to BM TG 312486-Franklin County, GA
|
||||
762 p25.w4pft.com 41000
|
||||
|
||||
# 822 TH-ASL-5508
|
||||
822 p25.xlx822.com 41000
|
||||
822 p25.xlx822.com 41000
|
||||
|
||||
# 841 Team Wave
|
||||
841 mx0wvv.ddns.net 41000
|
||||
|
||||
# 847 Chandler Hams
|
||||
847 xlx847.kk7mnz.com 41000
|
||||
|
||||
# 848 Chandler Hams
|
||||
848 xlx848.kk7mnz.com 41000
|
||||
|
||||
# 858 San Diego, CA
|
||||
858 nz6d.dx40.com 41000
|
||||
|
||||
# 865 K1LNX Multimode Server - Knoxville, TN
|
||||
865 knoxp25.k1lnx.net 41000
|
||||
865 knoxp25.k1lnx.net 41000
|
||||
|
||||
# 891 WNY DMR Network
|
||||
891 p25.wnydmr.network 41000
|
||||
# 891 Western New York Digital Multimode Network - http://wny-digital.network - Buffalo, NY
|
||||
891 p25.wny-digital.network 41000
|
||||
|
||||
# 910 Washington,DC - Virginia - Maryland
|
||||
910 p25.freeddns.org 41000
|
||||
|
||||
# 925 MotoChat
|
||||
925 p25.motochat.eu 41009
|
||||
|
||||
# 926 HamFurs/LoFAR MultiMode Bridge
|
||||
926 urf.kf3rry.org 41000
|
||||
|
||||
# 927 Southern California
|
||||
927 927.org 41000
|
||||
|
||||
# 946 FlagTorchSociety
|
||||
946 xlx.flagandtorchsociety.com 41000
|
||||
|
||||
# 994 The Online Radio Club (Bridged to XLX994)
|
||||
994 misc.openreflector.com 41000
|
||||
|
||||
# 1007 The Harley-Hangout "TGIF TG-1007 Multi-Function Bridge"
|
||||
1007 43773.kb5rir.com 41000
|
||||
1007 43773.kb5rir.com 41003
|
||||
|
||||
# 1402 DuckFar Repeater Group, Chicago
|
||||
1402 duckfarw9bmk.gotdns.com 43000
|
||||
|
||||
# 1701 Sector 001
|
||||
1701 hamsomniac.mooo.com 41001
|
||||
|
||||
# 1928 Motorola Nerd Network
|
||||
1928 216.128.134.7 41000
|
||||
|
||||
# 2044 P25 The Netherlands Main Reflector
|
||||
2044 51.83.46.75 41000
|
||||
|
||||
# 2050 KM4NNO AllStarLink DIU 3000 (Bridged to the P25Link Network).
|
||||
2050 reflector.p25.link 41009
|
||||
|
||||
# 2140 P25 Reflector BM DMR+ Multi
|
||||
2140 164.132.96.157 41000
|
||||
2140 andalucia.xreflector.es 41002
|
||||
|
||||
# 2147 P25 Reflector ANDALUCIA
|
||||
2147 andalucia.xreflector.es 41001
|
||||
|
||||
# 2221 IT PIEDMONT GDO
|
||||
2221 iz1zpj.duckdns.org 41000
|
||||
|
@ -87,6 +165,15 @@
|
|||
# 2265 Baia Mare YO5 P25 Network
|
||||
2265 p25.dstar-yo.ro 41005
|
||||
|
||||
# 2284 Basel Switzerland - https://p25.network
|
||||
2284 p25.network 41000
|
||||
|
||||
# 2345 CQ-North UK
|
||||
2345 p25.cqnorth.org.uk 41000
|
||||
|
||||
# 2350 UK ChatterBOX
|
||||
2350 p252350.freestar.network 41001
|
||||
|
||||
# RU DMR TG2503
|
||||
2503 p25.r1ik.ru 41000
|
||||
|
||||
|
@ -97,11 +184,23 @@
|
|||
3023 ontxlink.hopto.org 41000
|
||||
|
||||
# 3026 Alberta
|
||||
3026 3026.hamshack.info 41000
|
||||
3026 reflector.p25alberta.ca 41000
|
||||
|
||||
# 3120 LKDVM P25
|
||||
3120 lkdvm.xreflector.es 41000
|
||||
|
||||
# 3142 Pennsylvania
|
||||
3142 3.215.215.169 41002
|
||||
|
||||
# 3147 Tennessee
|
||||
3147 p25tn.w4kdg.org 41000
|
||||
|
||||
# 3149 Utah
|
||||
3149 p25.aarthek.net 41000
|
||||
|
||||
# 3160 K6JWN Multimode
|
||||
3160 p25-3160.k6jwn.org 41000
|
||||
|
||||
# 3300 PRadise
|
||||
3300 3300p25.from-pr.com 41000
|
||||
|
||||
|
@ -111,32 +210,83 @@
|
|||
# 3345 Mexico Multimode (Bridged to the P25Link Network).
|
||||
3345 reflector.p25.link 41008
|
||||
|
||||
# 3400 3400 Digital Group (NJ Multimode Reflector)
|
||||
3400 3400.ddns.net 41000
|
||||
|
||||
# 4095 KM4NNO Wave (Bridged to the P25Link Network).
|
||||
4095 reflector.p25.link 41010
|
||||
|
||||
# 4487 448.700 UHF Repeater in Aurora, CO
|
||||
4487 N0oba1.asuscomm.cn 41000
|
||||
|
||||
# 5000 ALL THE COMMS
|
||||
5000 p25.p25stuff.com 41000
|
||||
|
||||
# 5057 VK7 TAS (hosted by VK7HSE)
|
||||
5057 45.248.50.37 41000
|
||||
|
||||
# 6935 Indiana Digital Ham Radio P25 Reflector
|
||||
# 5205 CCARCNSW P25 Bridge
|
||||
5205 5205.p25dvm.com 41000
|
||||
|
||||
# 5658 DuckFar Repeater Group, Chicago
|
||||
5658 duckfarw9bmk.gotdns.com 41000
|
||||
|
||||
# 6395 Indiana Digital Ham Radio P25 Reflector
|
||||
6395 p25ref.nf9k.net 41000
|
||||
|
||||
# 6969 JTF_HV Ham P25
|
||||
6969 69.118.62.100 41000
|
||||
|
||||
# 7144 Chiriqui Link Panama
|
||||
7144 p25-hp3.ddns.net 41000
|
||||
|
||||
# 7160 Peru Digital
|
||||
7160 p25.dmr-peru.pe 41000
|
||||
|
||||
# 7225 MULTIPROTOCOLO ARGENTINA
|
||||
7225 ysfarg.ddns.net 41000
|
||||
|
||||
# 7240 MASTER-SUL Brasil
|
||||
7240 p25.freedmr-brasil.qsl.br 41000
|
||||
|
||||
# 7245 BRASIL Multiprotocolo P25
|
||||
7245 pu4ron.dynv6.net 41000
|
||||
|
||||
# Uruguay Link
|
||||
7487 23.234.230.152 41000
|
||||
|
||||
# 7573 Docksea P25
|
||||
7573 p25.docksea.com 41000
|
||||
|
||||
# 7941 WHITE MOUNTAIN REPEATER ASSOCIATION
|
||||
7941 wmra.mooo.com 41000
|
||||
|
||||
# 8200 Mountain Lakes Regional Amateur Radio Society
|
||||
8200 n2yqt.tourge.net 41000
|
||||
|
||||
# 8207 Houston Area XLX Reflector
|
||||
8207 p25.kd5dfb.net 41000
|
||||
|
||||
# 8208 China P25 Network bridge to P25NX
|
||||
8208 47.105.33.47 41000
|
||||
|
||||
# 8210 Ohio Valley
|
||||
8210 reflector.p25.in 41000
|
||||
|
||||
# 9050 East Coast Reflector
|
||||
9050 45.77.198.235 41000
|
||||
|
||||
# 9480 ICQPODCAST
|
||||
9480 xlx.icqpodcast.com 41001
|
||||
9480 46.101.36.246 41000
|
||||
|
||||
# 9517 M17 Project - M17-M17 C Reflector bridge
|
||||
9517 112.213.34.65 41002
|
||||
|
||||
# 9846 P25 Portal to WW8GM YSF network www.gmarc.org
|
||||
9846 p25.dudetronics.com 41001
|
||||
|
||||
# 10100 World Wide http://www.george-smart.co.uk/p25/
|
||||
10100 m1geo.com 41000
|
||||
# 10100 World Wide http://dvgateway.m1geo.com/
|
||||
10100 dvgateway.m1geo.com 41000
|
||||
|
||||
# 10101 World Wide TAC 1 (Bridged to the P25Link Network).
|
||||
10101 reflector.p25.link 41000
|
||||
|
@ -150,6 +300,9 @@
|
|||
# 10120 CQ-UK
|
||||
10120 81.150.10.62 41000
|
||||
|
||||
# 10169 Dipspit International - N0DIP
|
||||
10169 p25.dipspit.net 41000
|
||||
|
||||
# 10200 North America
|
||||
10200 dvswitch.org 41000
|
||||
|
||||
|
@ -162,17 +315,26 @@
|
|||
# 10203 North America TAC 3 (Bridged to the P25Link Network).
|
||||
10203 reflector.p25.link 41004
|
||||
|
||||
# P25 France
|
||||
10208 m55.evxonline.net 41000
|
||||
# 10207 Arizona 900 P25
|
||||
10207 n6ex.ddns.net 41001
|
||||
|
||||
# P25 Fun Machine WE0FUN Bridge to C4FM, DMR, DStar, NXDN and AllStarLink (Analog) http://www.we0fun.com
|
||||
# 10208 P25 France
|
||||
10208 p25.f5dan.fr 41000
|
||||
|
||||
# 10209 P25 Fun Machine WE0FUN Bridge to C4FM, DMR, DStar, NXDN and AllStarLink (Analog) http://www.we0fun.com
|
||||
10209 p25.we0fun.com 41000
|
||||
|
||||
# 10216 Northeast Ohio
|
||||
10216 xlx216.km8v.com 41000
|
||||
|
||||
# 10255 Southern Ontario
|
||||
10255 ve3rd.hopto.org 41000
|
||||
|
||||
# 10260 Poland
|
||||
10260 80.211.249.221 41000
|
||||
10260 185.174.14.75 41000
|
||||
|
||||
# 10294 SkyHub https://skyhublink.com/connections
|
||||
10294 hub.skyhublink.com 41000
|
||||
|
||||
# 10300 Europe https://p25-eu.n18.de/
|
||||
10300 176.9.1.168 41000
|
||||
|
@ -217,7 +379,7 @@
|
|||
10402 47.104.177.248 41000
|
||||
|
||||
# 10403 Pacific TAC 3 http://ysf.sz790.com:8082/
|
||||
10403 ysf.sz790.com 41000
|
||||
10403 ysf46073.sz790.com 41000
|
||||
|
||||
# 10404 Pacific TAC 4
|
||||
10404 p25tw338.ddns.net 41000
|
||||
|
@ -231,11 +393,11 @@
|
|||
# 10407 Shanghai City, China,bridged to DMR TG 46021
|
||||
10407 p25021.dyndns.org 41000
|
||||
|
||||
# 10421 DL-Nordwest (dl-nordwest.com) by 9V1LH/DG1BGS and DK5BS
|
||||
10421 9v1lh.spdns.org 41000
|
||||
# 10409 Beijing City, China,Miyun-HAM-Club P25 Repeater bridged to DMR TG 46001
|
||||
10409 101.43.186.84 41000
|
||||
|
||||
# 10444 VK64 P25 Group
|
||||
10444 vk64.chiffers.com 41000
|
||||
# 10421 DL-Nordwest (dl-nordwest.com) by 9V1LH/DG1BGS and DK5BS
|
||||
10421 dl-nordwest.com 41000
|
||||
|
||||
# 10472 Shenzhen City, China,bridged to DMR TG 46072
|
||||
10472 14.116.159.221 41000
|
||||
|
@ -243,18 +405,42 @@
|
|||
# 10473 LinAn, China, Fireside Chat Reflector
|
||||
10473 p25.hamdao.com 41000
|
||||
|
||||
# 10512 Shanghai, China, SHLK Reflector
|
||||
10512 bolelk.vicp.net 41000
|
||||
|
||||
# 10666 F5KFF P25 Net in Paris
|
||||
10666 f5kff.hd.free.fr 41000
|
||||
|
||||
# 10700 Australia NSW Bridge to AU NSW YSF
|
||||
10700 p25nsw.gustotech.net 41000
|
||||
|
||||
# 10750 Australian Secondary P25 Reflector
|
||||
10750 clasn-p25.cloudasn.com 41000
|
||||
|
||||
# 10888 Texas
|
||||
10888 29520.asnode.org 41000
|
||||
|
||||
# 10901 P25 Group Culpeper VA
|
||||
10901 Randin.Org 41000
|
||||
|
||||
# 10945 Deutschland DL1BH
|
||||
10945 dl1bh.ddns.net 41000
|
||||
|
||||
# 11069 KK6RQs reflector
|
||||
# 11069 KK6RQ DMR-310551
|
||||
11069 area52.zapto.org 41000
|
||||
|
||||
# 17603 URFM17 Universal Reflector
|
||||
17603 urf.m17.link 41000
|
||||
|
||||
# 20281 GR-KERKYRA-DV
|
||||
20281 greece.freedmr.online 41000
|
||||
|
||||
# 20222 HELLAS-FRN
|
||||
20222 greece-frn.ddns.net 41000
|
||||
|
||||
# 21909 PRIDE - LGBTQIA+ Hams
|
||||
21909 ham.kimberlychase.com 41000
|
||||
|
||||
# 22200 IT HBLINK REFLECTOR
|
||||
22200 p25.hblink.it 41000
|
||||
|
||||
|
@ -267,35 +453,83 @@
|
|||
# 22221 HBLINK IT-DMR REGIONALE LOMBARDIA
|
||||
22221 dagobah.hblink.it 41000
|
||||
|
||||
# 22222 North Carolina NCC-1701
|
||||
22222 NCC-1701-P25.ddns.net 41001
|
||||
|
||||
# 22252 IT MULTIPROTOCOL NETWORK
|
||||
22252 46.226.178.80 41000
|
||||
|
||||
# 22258 D2ALP HBLink Italia
|
||||
22258 94.177.173.53 41000
|
||||
|
||||
# 22487 IT - Italy Centro
|
||||
22487 famiuse.ddns.net 41000
|
||||
|
||||
# 23225 Austria
|
||||
23225 94.199.173.123 41000
|
||||
23225 service.oe9hamnet.at 41000
|
||||
|
||||
# 23426 FreeSTAR UK
|
||||
23426 p25.freestar.network 41000
|
||||
|
||||
# 23456 SHARC Multi Mode System Sherman, ME
|
||||
23456 kc1noc.duckdns.org 41000
|
||||
|
||||
# 23511 LEFARS Multi-Reflector
|
||||
23511 xlxlef.gb7hh.co.uk 41000
|
||||
|
||||
# 23522 GB-PrestonARS-P25
|
||||
23522 23522p25ref.dyndns.org 41000
|
||||
|
||||
# 23551 P25 Scotland
|
||||
23551 p25scotland.ddns.net 41000
|
||||
|
||||
# 23556 DVSPH Multimode
|
||||
23556 xlx600.dvsph.net 41000
|
||||
|
||||
# 23595 OZ-DMR
|
||||
23595 reflector.oz-dmr.uk 41000
|
||||
23595 p25.oz-dmr.network 41000
|
||||
|
||||
# 24033 2 Meter Crew Anti-Net
|
||||
24033 wg5eek.com 41000
|
||||
|
||||
# 25605 Russia Ekaterinburg
|
||||
25605 ysf.386i.ru 41000
|
||||
|
||||
# 25617 Russia Kavkaz
|
||||
25617 kavkaz.qrz.ru 41000
|
||||
|
||||
# 26078 Poland HBLink Network
|
||||
26078 p25.hblink.kutno.pl 41000
|
||||
|
||||
# 25641 Russia P25 Net
|
||||
25641 194.182.85.217 41000
|
||||
|
||||
# 26078 Poland HBLink Network
|
||||
26078 p25.hblink.kutno.pl 41000
|
||||
|
||||
# 26230 German Hannover-XLink
|
||||
26230 p25.hannover-x.link 41000
|
||||
|
||||
# 26285 German Oberbayern Region
|
||||
26285 xlx850.bm262.de 41008
|
||||
|
||||
# 26444 German Inselfreunde Net
|
||||
26444 xlx850.bm262.de 41004
|
||||
|
||||
# 26538 DE-NDS-Ost
|
||||
26538 116.203.223.233 41000
|
||||
|
||||
# 27565 KN4KNG Network
|
||||
27565 139.144.61.167 41000
|
||||
|
||||
# 27566 KN4KNG Network TAC1
|
||||
27566 139.144.61.167 41001
|
||||
|
||||
# 27567 KN4KNG Network TAC2
|
||||
27567 139.144.61.167 41002
|
||||
|
||||
# 27568 KN4KNG Network TAC3
|
||||
27568 139.144.61.167 41003
|
||||
|
||||
# 28299 America-Ragchew
|
||||
28299 65.101.7.51 41000
|
||||
28299 arcp25.duckdns.org 41000
|
||||
|
||||
# 29252 Oklahoma Hamsomniacs
|
||||
29252 hamsomniac.mooo.com 41000
|
||||
|
@ -306,9 +540,15 @@
|
|||
# 31010 Alabama Link
|
||||
31010 alabamalink.radiotechnology.xyz 41000
|
||||
|
||||
# 31044 WNY-DIGITAL
|
||||
31044 p25.wny-digital.network 41002
|
||||
|
||||
# 31057 AF5XP Sulphur,Louisiana
|
||||
31057 af5xp.ddns.net 41000
|
||||
|
||||
# 31059 Vidalia Net P25
|
||||
31059 vidalianet.cbridge.net 41000
|
||||
|
||||
# 31062 Mountain West
|
||||
31062 p25.mw-dmr.net 41000
|
||||
|
||||
|
@ -324,29 +564,41 @@
|
|||
# 31079 ALERT Radio / Multimode P25/DMR
|
||||
31079 927.org 41001
|
||||
|
||||
# 31088 Colorado HD
|
||||
31088 54.191.50.212 41000
|
||||
# 31138 kingsland Ga
|
||||
31138 kingsland.cbridge.net 41000
|
||||
|
||||
# 31092 Connecticut Chat
|
||||
31092 p25.alecwasserman.com 41000
|
||||
# 31177 WESDIG P25 Reflector
|
||||
31177 p25.wesdig.com 41000
|
||||
|
||||
# 31121 First Coast FL
|
||||
31121 dvse.dmrnet.net 41000
|
||||
|
||||
# 31123 Florida Treasure Coast
|
||||
31123 45.152.209.147 41000
|
||||
31123 p25.kg4orq.com 41000
|
||||
|
||||
# 31161 Virginia
|
||||
31161 24.49.15.69 41000
|
||||
|
||||
# 31171 Illinois Link
|
||||
31171 illink.radiotechnology.xyz 41000
|
||||
31171 illink.radiotechnology.xyz 41000
|
||||
|
||||
# 31188 Southern Indiana
|
||||
31188 w9windigital.org 41000
|
||||
|
||||
# 31226 Worldwide Dx Link System
|
||||
31226 192.99.70.1 41000
|
||||
# 31207 Sunflower Net
|
||||
31207 155.138.244.192 41000
|
||||
|
||||
# 31217 Central Illinois Skywarn - Linked to Brandmeister TG 311899
|
||||
31217 tg31217.kd9koo.com 41000
|
||||
|
||||
# 31220 Lucas County Ohio ARES
|
||||
31220 w8mal-dvbridge.hopto.org 41000
|
||||
|
||||
# 31226 Worldwide Chat
|
||||
31226 74.208.163.225 41000
|
||||
|
||||
# 31238 Foxhole Radio Bridged Network
|
||||
31238 p25.foxhole.radio 41000
|
||||
|
||||
# 31257 NEARC
|
||||
31257 p25.w0jay.com 41000
|
||||
|
@ -354,9 +606,27 @@
|
|||
# 31264 XLX625 The BROniverse www.wa8bro.com
|
||||
31264 p25.dudetronics.com 41000
|
||||
|
||||
# 31267 W8LRK Blue Zone - Livingston County Amateur Radio Klub
|
||||
31267 w8lrkp25.dyndns.org 41001
|
||||
|
||||
# 31291 Southwest Missouri (P25/DMR)
|
||||
31291 p25.ddns.me 41001
|
||||
|
||||
# 31297 Southwest Missouri Skywarn (P25/DMR)
|
||||
31297 p25.ddns.me 41003
|
||||
|
||||
# 31313 America's Kansas City Wide (P25/DMR/YSF)
|
||||
31313 p25.ddns.me 41002
|
||||
|
||||
# 31337 SWLA <-> DMR TG 311995 <-> XLX337
|
||||
31337 bridge.kc5jmj.com 41000
|
||||
|
||||
# 31395 Cleveland Skywarn Backbone
|
||||
31395 backbone.ad8g.net 41000
|
||||
|
||||
# 31399 OhioLink Network Crossmode. http://olnradio.digital
|
||||
31399 xlx.kd8grn.net 41000
|
||||
|
||||
# 31340 Central New Jersey
|
||||
31340 cnjham.msmts.com 41000
|
||||
|
||||
|
@ -369,23 +639,35 @@
|
|||
# XLX045A P25 <-> DMR/DSTAR/YSF/NXDN <-> BM TG31425 PA Wide Cross Mode
|
||||
31425 70.44.20.24 41001
|
||||
|
||||
# 31424 SVARC-Shenango Valley Amateur Radio Club- K3WRB
|
||||
31424 p25.n1tvi.net 41000
|
||||
|
||||
# PA Cross Mode (alt), 31426
|
||||
31426 3.215.215.169 41001
|
||||
|
||||
# 31444 RI DIGITAL LINK TG#31444
|
||||
31444 149.28.54.153 41000
|
||||
|
||||
# 31490 Link to DMR TG 314900
|
||||
31490 utah00.utahdrn.org 41000
|
||||
|
||||
# 31497 LifeFlight, UT Statewide - Link to DMR TG 31497
|
||||
31497 45.79.110.170 41000
|
||||
|
||||
# 31555 SE Wisconsin Regional Linked to WiDMR 31555
|
||||
31555 mmdvm-p25.v24bridge.net 41000
|
||||
|
||||
# 31581 KD2UQK Long Island, NY - P25 Reflector
|
||||
# 31581 KD2UQK Long Island, NY - P25 Talkaround
|
||||
31581 kd2uqk.ham-radio-op.net 41000
|
||||
|
||||
# 31582 KO4UYJ & KD2UQK East Coast Reflector P25 Bridge to 9050/27339
|
||||
31582 lnr.ko4uyj.com 41000
|
||||
|
||||
# 31620 Kings of Digital
|
||||
31620 wb5ekup25.duckdns.org 41000
|
||||
|
||||
# 31655 Ham Radio Venture Overland
|
||||
31655 149.248.8.155 41000
|
||||
31655 149.248.8.155 41000
|
||||
|
||||
# 31665 TGIF Network, http://tgif.network
|
||||
31665 tgif.network 41000
|
||||
|
@ -405,29 +687,74 @@
|
|||
# 31888 KG4JPL North-Central Florida
|
||||
31888 p25.kg4jpl.com 41000
|
||||
|
||||
# 31947 K0MGS Western Missouri/KC Metro
|
||||
31947 p25.ddns.me 41000
|
||||
|
||||
# 31983 K8JTK Hub Multimode ILS/DVMIS (K8JTK.org)
|
||||
31983 P25Reflector31983.K8JTK.org 41000
|
||||
|
||||
# 32103 CW-Ops Academy
|
||||
32103 cwops.dyndns.org 41000
|
||||
|
||||
# 33015 KP4CA Digital Network
|
||||
33015 kp4ca-p25.ddns.net 41000
|
||||
|
||||
# 33581 OMISS Group
|
||||
33581 omiss.dyndns.org 41000
|
||||
|
||||
# 37030 RED SKYNET
|
||||
37030 skynet.xreflector.es 41000
|
||||
|
||||
# 37225 Haiti Digital Communications League (HDCL) P25
|
||||
37225 3.215.215.169 41011
|
||||
|
||||
# 37500 Belarus MultiMode Digital Voice Network
|
||||
37500 xlx375.bfrr.by 41000
|
||||
|
||||
# 40721 Fusion Canada Fr
|
||||
40721 38.110.97.161 41000
|
||||
|
||||
# 41120 LONE STAR LINK SYSTEM
|
||||
41120 216.128.136.176 41000
|
||||
|
||||
# 43389 SouthEast Link US
|
||||
43389 p25.lmarc.net 41000
|
||||
|
||||
# 43715 Kazakhstan P25
|
||||
43715 un7bww.svx03.kz 41000
|
||||
|
||||
# 44000 Japan Main P25
|
||||
44000 p25-2.f5.si 41000
|
||||
|
||||
# 44120 Japan P25
|
||||
44120 p25.f5.si 41000
|
||||
|
||||
# 45000 Korea
|
||||
45000 p25.dvham.com 41000
|
||||
|
||||
# 45001 P25-DS5QDR Korea
|
||||
45001 ds5qdr-mst.duckdns.org 41000
|
||||
|
||||
# 46001 P25 Link TG46001, China
|
||||
46001 46001.bh1nyr.net 41000
|
||||
|
||||
# 46010 P25 Link TG46010, Beijing, China
|
||||
46010 46010.bh1nyr.net 41002
|
||||
|
||||
# 46023 P25 Link TG46023 bridge to BM TG46023, Chongqing, China
|
||||
46023 119.3.248.195 41000
|
||||
|
||||
# 46516 P25 Link TG46516, Xuzhou, China
|
||||
46516 46516.bh1nyr.net 41004
|
||||
|
||||
# 46551 China ADEC
|
||||
46551 60.173.209.129 41000
|
||||
|
||||
# 49562 Boredom Breaker
|
||||
49562 146.71.77.238 41000
|
||||
|
||||
# 50210 Bridge to BM TG50210/XLX/YSF/WiresX Malaysia-Net
|
||||
50210 edone.now.im 41000
|
||||
50210 edone.no-ip.com 41000
|
||||
|
||||
# 50525 Bridge to YSF, NXDN and DMR
|
||||
50525 50525.p25dvm.com 41000
|
||||
|
@ -435,18 +762,39 @@
|
|||
# 50535 VK Multimode Link
|
||||
50535 p25tg50535.vkradio.com 41000
|
||||
|
||||
# 50536 FreeSTAR VK
|
||||
50536 p25tg50536.vkradio.com 41001
|
||||
|
||||
# 51502 DX1ACE
|
||||
51502 p25-dx1ace.hopto.org 41000
|
||||
|
||||
# 51503 US Philippines P25 network
|
||||
51503 149.28.201.109 4569
|
||||
51503 45.79.76.10 41000
|
||||
|
||||
# 51526 Omega Communications
|
||||
51526 omega25.ddns.net 41000
|
||||
|
||||
# 51547 KAPIHAN Network
|
||||
51547 p25.kapihan.net 41000
|
||||
|
||||
# 51575 PH-Dumaguete Link (Multimode)
|
||||
51575 140.82.14.24 41000
|
||||
|
||||
# 52072 Phuket
|
||||
52072 xlx727phuketdstar.ddns.net 41000
|
||||
# 52032 P25 Link XLX149 Modules C
|
||||
52032 p52032.pwk.ac.th 41009
|
||||
|
||||
# 52072 Phuket P25 <> FreeDMR <> Echolink
|
||||
52072 203.170.129.69 41000
|
||||
|
||||
# 52138 P25 Link Thailand
|
||||
52138 p2552138.freeddns.org 41000
|
||||
|
||||
# 52149 P25 Link To XLX149 Modules D
|
||||
52149 p52149.pwk.ac.th 41005
|
||||
|
||||
# 52910 XLX Nexus
|
||||
52910 p25x.mywire.org 41000
|
||||
|
||||
# 53099 New Zealand bridge to D-Star, DMR and NXDN
|
||||
53099 203.86.206.49 41000
|
||||
|
||||
|
@ -454,7 +802,20 @@
|
|||
54100 hs1qcj.ddns.net 41000
|
||||
|
||||
# 55100 (WWRARN) World Wide Ragchew Amateur Radio Net
|
||||
55100 140.82.3.34 41000
|
||||
55100 45.63.6.57 41000
|
||||
|
||||
# 60100 K8SDR SignalsEverywhere Experimenters Club
|
||||
60100 p25.signalseverywhere.com 41000
|
||||
60100 p25.signalseverywhere.com 41000
|
||||
|
||||
# 60777 Who Cares ARG (URF239 A) https://whocaresradio.com/reflector
|
||||
60777 urf239.whocaresradio.com 41000
|
||||
|
||||
# 63600 Latvian Digital Voice network
|
||||
63600 xlx.ham.lv 41000
|
||||
|
||||
# 65100 P25 2007DXgroup
|
||||
65100 89.46.75.115 41000
|
||||
|
||||
# 65101 KM4HJJ repeater Pompano, Florida
|
||||
65101 km4hjj-p25.dyndns-server.com 41000
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014,2016,2020 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2009-2014,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
|
||||
|
@ -26,8 +26,8 @@
|
|||
|
||||
CP25Network::CP25Network(unsigned short port, const std::string& callsign, bool debug) :
|
||||
m_callsign(callsign),
|
||||
m_socket(),
|
||||
m_port(port),
|
||||
m_socket4(port),
|
||||
m_socket6(port),
|
||||
m_debug(debug)
|
||||
{
|
||||
assert(port > 0U);
|
||||
|
@ -43,16 +43,17 @@ bool CP25Network::open()
|
|||
{
|
||||
LogInfo("Opening P25 network connection");
|
||||
|
||||
unsigned int index = 0U;
|
||||
sockaddr_storage addr4;
|
||||
addr4.ss_family = AF_INET;
|
||||
|
||||
bool ret1 = m_socket.open(index, PF_INET, "", m_port);
|
||||
if (ret1)
|
||||
index++;
|
||||
bool ret = m_socket4.open(addr4);
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
bool ret2 = m_socket.open(index, PF_INET6, "", m_port);
|
||||
sockaddr_storage addr6;
|
||||
addr6.ss_family = AF_INET6;
|
||||
|
||||
// We're OK as long as we have either IPv4 or IPv6 or both.
|
||||
return ret1 || ret2;
|
||||
return m_socket6.open(addr6);
|
||||
}
|
||||
|
||||
bool CP25Network::write(const unsigned char* data, unsigned int length, const sockaddr_storage& addr, unsigned int addrLen)
|
||||
|
@ -63,7 +64,15 @@ bool CP25Network::write(const unsigned char* data, unsigned int length, const so
|
|||
if (m_debug)
|
||||
CUtils::dump(1U, "P25 Network Data Sent", data, length);
|
||||
|
||||
return m_socket.write(data, length, addr, addrLen);
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET:
|
||||
return m_socket4.write(data, length, addr, addrLen);
|
||||
case AF_INET6:
|
||||
return m_socket6.write(data, length, addr, addrLen);
|
||||
default:
|
||||
LogError("Unknown socket address family - %u", addr.ss_family);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CP25Network::poll(const sockaddr_storage& addr, unsigned int addrLen)
|
||||
|
@ -78,7 +87,15 @@ bool CP25Network::poll(const sockaddr_storage& addr, unsigned int addrLen)
|
|||
if (m_debug)
|
||||
CUtils::dump(1U, "P25 Network Poll Sent", data, 11U);
|
||||
|
||||
return m_socket.write(data, 11U, addr, addrLen);
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET:
|
||||
return m_socket4.write(data, 11U, addr, addrLen);
|
||||
case AF_INET6:
|
||||
return m_socket6.write(data, 11U, addr, addrLen);
|
||||
default:
|
||||
LogError("Unknown socket address family - %u", addr.ss_family);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CP25Network::unlink(const sockaddr_storage& addr, unsigned int addrLen)
|
||||
|
@ -93,7 +110,15 @@ bool CP25Network::unlink(const sockaddr_storage& addr, unsigned int addrLen)
|
|||
if (m_debug)
|
||||
CUtils::dump(1U, "P25 Network Unlink Sent", data, 11U);
|
||||
|
||||
return m_socket.write(data, 11U, addr, addrLen);
|
||||
switch (addr.ss_family) {
|
||||
case AF_INET:
|
||||
return m_socket4.write(data, 11U, addr, addrLen);
|
||||
case AF_INET6:
|
||||
return m_socket6.write(data, 11U, addr, addrLen);
|
||||
default:
|
||||
LogError("Unknown socket address family - %u", addr.ss_family);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CP25Network::read(unsigned char* data, unsigned int length, sockaddr_storage& addr, unsigned int& addrLen)
|
||||
|
@ -101,7 +126,9 @@ unsigned int CP25Network::read(unsigned char* data, unsigned int length, sockadd
|
|||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
int len = m_socket.read(data, length, addr, addrLen);
|
||||
int len = m_socket4.read(data, length, addr, addrLen);
|
||||
if (len <= 0)
|
||||
len = m_socket6.read(data, length, addr, addrLen);
|
||||
if (len <= 0)
|
||||
return 0U;
|
||||
|
||||
|
@ -113,7 +140,8 @@ unsigned int CP25Network::read(unsigned char* data, unsigned int length, sockadd
|
|||
|
||||
void CP25Network::close()
|
||||
{
|
||||
m_socket.close();
|
||||
m_socket4.close();
|
||||
m_socket6.close();
|
||||
|
||||
LogInfo("Closing P25 network connection");
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2009-2014,2016,2020 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2009-2014,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
|
||||
|
@ -42,10 +42,10 @@ public:
|
|||
void close();
|
||||
|
||||
private:
|
||||
std::string m_callsign;
|
||||
CUDPSocket m_socket;
|
||||
unsigned short m_port;
|
||||
bool m_debug;
|
||||
std::string m_callsign;
|
||||
CUDPSocket m_socket4;
|
||||
CUDPSocket m_socket6;
|
||||
bool m_debug;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
@ -34,29 +34,19 @@
|
|||
#endif
|
||||
|
||||
CUDPSocket::CUDPSocket(const std::string& address, unsigned short port) :
|
||||
m_address_save(address),
|
||||
m_port_save(port),
|
||||
m_counter(0U)
|
||||
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 short port) :
|
||||
m_address_save(),
|
||||
m_port_save(port),
|
||||
m_counter(0U)
|
||||
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()
|
||||
|
@ -93,10 +83,10 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockadd
|
|||
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 short port, sockadd
|
|||
|
||||
::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,35 +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 short 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;
|
||||
}
|
||||
|
||||
close(index);
|
||||
m_af = addr.ss_family;
|
||||
|
||||
int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
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
|
||||
|
@ -200,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 %hu", 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)
|
||||
|
@ -266,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)
|
||||
|
@ -283,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)
|
||||
|
@ -294,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 %hu", m_port[index]);
|
||||
LogMessage("Re-opening UDP port on %hu", m_localPort);
|
||||
close();
|
||||
open();
|
||||
}
|
||||
|
@ -302,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;
|
||||
|
@ -346,18 +313,13 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const s
|
|||
|
||||
void CUDPSocket::close()
|
||||
{
|
||||
for (unsigned int i = 0; i < UDP_SOCKET_MAX; i++)
|
||||
close(i);
|
||||
}
|
||||
|
||||
void CUDPSocket::close(const unsigned int index)
|
||||
{
|
||||
if ((index < UDP_SOCKET_MAX) && (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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -50,34 +46,33 @@ public:
|
|||
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 short 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 short port, sockaddr_storage& address, unsigned int& address_length);
|
||||
static int lookup(const std::string& hostName, unsigned short 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;
|
||||
#else
|
||||
int m_fd;
|
||||
#endif
|
||||
sa_family_t m_af;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
|
||||
* Copyright (C) 2015-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 = "20201105";
|
||||
const char* VERSION = "20240129";
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
@ -34,29 +34,19 @@
|
|||
#endif
|
||||
|
||||
CUDPSocket::CUDPSocket(const std::string& address, unsigned short port) :
|
||||
m_address_save(address),
|
||||
m_port_save(port),
|
||||
m_counter(0U)
|
||||
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 short port) :
|
||||
m_address_save(),
|
||||
m_port_save(port),
|
||||
m_counter(0U)
|
||||
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()
|
||||
|
@ -93,10 +83,10 @@ int CUDPSocket::lookup(const std::string& hostname, unsigned short port, sockadd
|
|||
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 short port, sockadd
|
|||
|
||||
::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,35 +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 short 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;
|
||||
}
|
||||
|
||||
close(index);
|
||||
m_af = addr.ss_family;
|
||||
|
||||
int fd = ::socket(addr.ss_family, SOCK_DGRAM, 0);
|
||||
if (fd < 0) {
|
||||
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
|
||||
|
@ -200,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 %hu", 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)
|
||||
|
@ -266,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)
|
||||
|
@ -283,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)
|
||||
|
@ -294,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 %hu", m_port[index]);
|
||||
LogMessage("Re-opening UDP port on %hu", m_localPort);
|
||||
close();
|
||||
open();
|
||||
}
|
||||
|
@ -302,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;
|
||||
|
@ -346,18 +313,13 @@ bool CUDPSocket::write(const unsigned char* buffer, unsigned int length, const s
|
|||
|
||||
void CUDPSocket::close()
|
||||
{
|
||||
for (unsigned int i = 0; i < UDP_SOCKET_MAX; i++)
|
||||
close(i);
|
||||
}
|
||||
|
||||
void CUDPSocket::close(const unsigned int index)
|
||||
{
|
||||
if ((index < UDP_SOCKET_MAX) && (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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -50,34 +46,33 @@ public:
|
|||
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 short 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 short port, sockaddr_storage& address, unsigned int& address_length);
|
||||
static int lookup(const std::string& hostName, unsigned short 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;
|
||||
#else
|
||||
int m_fd;
|
||||
#endif
|
||||
sa_family_t m_af;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,191 +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_ID_LOOKUP,
|
||||
SECTION_LOG,
|
||||
SECTION_NETWORK
|
||||
};
|
||||
|
||||
CConf::CConf(const std::string& file) :
|
||||
m_file(file),
|
||||
m_daemon(false),
|
||||
m_lookupName(),
|
||||
m_lookupTime(0U),
|
||||
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, "[Id Lookup]", 11U) == 0)
|
||||
section = SECTION_ID_LOOKUP;
|
||||
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_ID_LOOKUP) {
|
||||
if (::strcmp(key, "Name") == 0)
|
||||
m_lookupName = value;
|
||||
else if (::strcmp(key, "Time") == 0)
|
||||
m_lookupTime = (unsigned int)::atoi(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 short)::atoi(value);
|
||||
else if (::strcmp(key, "Debug") == 0)
|
||||
m_networkDebug = ::atoi(value) == 1;
|
||||
}
|
||||
}
|
||||
|
||||
::fclose(fp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CConf::getDaemon() const
|
||||
{
|
||||
return m_daemon;
|
||||
}
|
||||
|
||||
std::string CConf::getLookupName() const
|
||||
{
|
||||
return m_lookupName;
|
||||
}
|
||||
|
||||
unsigned int CConf::getLookupTime() const
|
||||
{
|
||||
return m_lookupTime;
|
||||
}
|
||||
|
||||
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 short CConf::getNetworkPort() const
|
||||
{
|
||||
return m_networkPort;
|
||||
}
|
||||
|
||||
bool CConf::getNetworkDebug() const
|
||||
{
|
||||
return m_networkDebug;
|
||||
}
|
|
@ -1,68 +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 Id Lookup section
|
||||
std::string getLookupName() const;
|
||||
unsigned int getLookupTime() 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 short getNetworkPort() const;
|
||||
bool getNetworkDebug() const;
|
||||
|
||||
private:
|
||||
std::string m_file;
|
||||
bool m_daemon;
|
||||
|
||||
std::string m_lookupName;
|
||||
unsigned int m_lookupTime;
|
||||
|
||||
unsigned int m_logDisplayLevel;
|
||||
unsigned int m_logFileLevel;
|
||||
std::string m_logFilePath;
|
||||
std::string m_logFileRoot;
|
||||
bool m_logFileRotate;
|
||||
|
||||
unsigned short m_networkPort;
|
||||
bool m_networkDebug;
|
||||
};
|
||||
|
||||
#endif
|
109242
P25Reflector/DMRIds.dat
109242
P25Reflector/DMRIds.dat
File diff suppressed because it is too large
Load Diff
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "DMRLookup.h"
|
||||
#include "Timer.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cctype>
|
||||
|
||||
CDMRLookup::CDMRLookup(const std::string& filename, unsigned int reloadTime) :
|
||||
CThread(),
|
||||
m_filename(filename),
|
||||
m_reloadTime(reloadTime),
|
||||
m_table(),
|
||||
m_mutex(),
|
||||
m_stop(false)
|
||||
{
|
||||
}
|
||||
|
||||
CDMRLookup::~CDMRLookup()
|
||||
{
|
||||
}
|
||||
|
||||
bool CDMRLookup::read()
|
||||
{
|
||||
bool ret = load();
|
||||
|
||||
if (m_reloadTime > 0U)
|
||||
run();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CDMRLookup::entry()
|
||||
{
|
||||
LogInfo("Started the DMR Id lookup reload thread");
|
||||
|
||||
CTimer timer(1U, 3600U * m_reloadTime);
|
||||
timer.start();
|
||||
|
||||
while (!m_stop) {
|
||||
sleep(1000U);
|
||||
|
||||
timer.clock();
|
||||
if (timer.hasExpired()) {
|
||||
load();
|
||||
timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
LogInfo("Stopped the DMR Id lookup reload thread");
|
||||
}
|
||||
|
||||
void CDMRLookup::stop()
|
||||
{
|
||||
if (m_reloadTime == 0U) {
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
m_stop = true;
|
||||
|
||||
wait();
|
||||
}
|
||||
|
||||
std::string CDMRLookup::find(unsigned int id)
|
||||
{
|
||||
std::string callsign;
|
||||
|
||||
if (id == 0xFFFFFFU)
|
||||
return std::string("ALL");
|
||||
|
||||
m_mutex.lock();
|
||||
|
||||
try {
|
||||
callsign = m_table.at(id);
|
||||
} catch (...) {
|
||||
char text[10U];
|
||||
::sprintf(text, "%u", id);
|
||||
callsign = std::string(text);
|
||||
}
|
||||
|
||||
m_mutex.unlock();
|
||||
|
||||
return callsign;
|
||||
}
|
||||
|
||||
bool CDMRLookup::load()
|
||||
{
|
||||
FILE* fp = ::fopen(m_filename.c_str(), "rt");
|
||||
if (fp == NULL) {
|
||||
LogWarning("Cannot open the Id lookup file - %s", m_filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_mutex.lock();
|
||||
|
||||
// Remove the old entries
|
||||
m_table.clear();
|
||||
|
||||
char buffer[100U];
|
||||
while (::fgets(buffer, 100U, fp) != NULL) {
|
||||
if (buffer[0U] == '#')
|
||||
continue;
|
||||
|
||||
char* p1 = ::strtok(buffer, " \t\r\n");
|
||||
char* p2 = ::strtok(NULL, " \t\r\n");
|
||||
|
||||
if (p1 != NULL && p2 != NULL) {
|
||||
unsigned int id = (unsigned int)::atoi(p1);
|
||||
for (char* p = p2; *p != 0x00U; p++)
|
||||
*p = ::toupper(*p);
|
||||
|
||||
m_table[id] = std::string(p2);
|
||||
}
|
||||
}
|
||||
|
||||
m_mutex.unlock();
|
||||
|
||||
::fclose(fp);
|
||||
|
||||
size_t size = m_table.size();
|
||||
if (size == 0U)
|
||||
return false;
|
||||
|
||||
LogInfo("Loaded %u Ids to the callsign lookup table", size);
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016 by Jonathan Naylor G4KLX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef DMRLookup_H
|
||||
#define DMRLookup_H
|
||||
|
||||
#include "Thread.h"
|
||||
#include "Mutex.h"
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
class CDMRLookup : public CThread {
|
||||
public:
|
||||
CDMRLookup(const std::string& filename, unsigned int reloadTime);
|
||||
virtual ~CDMRLookup();
|
||||
|
||||
bool read();
|
||||
|
||||
virtual void entry();
|
||||
|
||||
std::string find(unsigned int id);
|
||||
|
||||
void stop();
|
||||
|
||||
private:
|
||||
std::string m_filename;
|
||||
unsigned int m_reloadTime;
|
||||
std::unordered_map<unsigned int, std::string> m_table;
|
||||
CMutex m_mutex;
|
||||
bool m_stop;
|
||||
|
||||
bool load();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -1,22 +0,0 @@
|
|||
CC = cc
|
||||
CXX = c++
|
||||
CFLAGS = -g -O3 -Wall -DHAVE_LOG_H -DUDP_SOCKET_MAX=2 -std=c++0x -pthread
|
||||
LIBS = -lpthread
|
||||
LDFLAGS = -g
|
||||
|
||||
OBJECTS = Conf.o DMRLookup.o Log.o Mutex.o Network.o P25Reflector.o StopWatch.o Thread.o Timer.o UDPSocket.o Utils.o
|
||||
|
||||
all: P25Reflector
|
||||
|
||||
P25Reflector: $(OBJECTS)
|
||||
$(CXX) $(OBJECTS) $(CFLAGS) $(LIBS) -o P25Reflector
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
install:
|
||||
install -m 755 P25Reflector /usr/local/bin/
|
||||
|
||||
clean:
|
||||
$(RM) P25Reflector *.o *.d *.bak *~
|
||||
|
|
@ -1,65 +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.
|
||||
*/
|
||||
|
||||
#include "Mutex.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
|
||||
CMutex::CMutex() :
|
||||
m_handle()
|
||||
{
|
||||
m_handle = ::CreateMutex(NULL, FALSE, NULL);
|
||||
}
|
||||
|
||||
CMutex::~CMutex()
|
||||
{
|
||||
::CloseHandle(m_handle);
|
||||
}
|
||||
|
||||
void CMutex::lock()
|
||||
{
|
||||
::WaitForSingleObject(m_handle, INFINITE);
|
||||
}
|
||||
|
||||
void CMutex::unlock()
|
||||
{
|
||||
::ReleaseMutex(m_handle);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
CMutex::CMutex() :
|
||||
m_mutex(PTHREAD_MUTEX_INITIALIZER)
|
||||
{
|
||||
}
|
||||
|
||||
CMutex::~CMutex()
|
||||
{
|
||||
}
|
||||
|
||||
void CMutex::lock()
|
||||
{
|
||||
::pthread_mutex_lock(&m_mutex);
|
||||
}
|
||||
|
||||
void CMutex::unlock()
|
||||
{
|
||||
::pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,46 +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(MUTEX_H)
|
||||
#define MUTEX_H
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <WS2tcpip.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
class CMutex
|
||||
{
|
||||
public:
|
||||
CMutex();
|
||||
~CMutex();
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
|
||||
private:
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
HANDLE m_handle;
|
||||
#else
|
||||
pthread_mutex_t m_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,75 +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 "Network.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
CNetwork::CNetwork(unsigned short port, bool debug) :
|
||||
m_socket(port),
|
||||
m_debug(debug)
|
||||
{
|
||||
}
|
||||
|
||||
CNetwork::~CNetwork()
|
||||
{
|
||||
}
|
||||
|
||||
bool CNetwork::open()
|
||||
{
|
||||
LogInfo("Opening P25 network connection");
|
||||
|
||||
return m_socket.open();
|
||||
}
|
||||
|
||||
bool CNetwork::writeData(const unsigned char* data, unsigned int length, const sockaddr_storage& addr, unsigned int addrLen)
|
||||
{
|
||||
assert(data != NULL);
|
||||
assert(length > 0U);
|
||||
|
||||
if (m_debug)
|
||||
CUtils::dump(1U, "P25 Network Data Sent", data, length);
|
||||
|
||||
return m_socket.write(data, length, 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, "P25 Network Data Received", data, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void CNetwork::close()
|
||||
{
|
||||
m_socket.close();
|
||||
|
||||
LogInfo("Closing P25 network connection");
|
||||
}
|
|
@ -1,45 +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 "UDPSocket.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
class CNetwork {
|
||||
public:
|
||||
CNetwork(unsigned short port, bool debug);
|
||||
~CNetwork();
|
||||
|
||||
bool open();
|
||||
|
||||
bool writeData(const unsigned char* data, unsigned int length, const sockaddr_storage& addr, unsigned int addrLen);
|
||||
|
||||
unsigned int readData(unsigned char* data, unsigned int length, sockaddr_storage& addr, unsigned int& addrLen);
|
||||
|
||||
void close();
|
||||
|
||||
private:
|
||||
CUDPSocket m_socket;
|
||||
bool m_debug;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,363 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2016,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
|
||||
* 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 "P25Reflector.h"
|
||||
#include "StopWatch.h"
|
||||
#include "DMRLookup.h"
|
||||
#include "Network.h"
|
||||
#include "Version.h"
|
||||
#include "Thread.h"
|
||||
#include "Utils.h"
|
||||
#include "Log.h"
|
||||
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#include <WS2tcpip.h>
|
||||
#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 = "P25Reflector.ini";
|
||||
#else
|
||||
const char* DEFAULT_INI_FILE = "/etc/P25Reflector.ini";
|
||||
#endif
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
#include <ctime>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
|
||||
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, "P25Reflector version %s\n", VERSION);
|
||||
return 0;
|
||||
} else if (arg.substr(0, 1) == "-") {
|
||||
::fprintf(stderr, "Usage: P25Reflector [-v|--version] [filename]\n");
|
||||
return 1;
|
||||
} else {
|
||||
iniFile = argv[currentArg];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CP25Reflector* reflector = new CP25Reflector(std::string(iniFile));
|
||||
reflector->run();
|
||||
delete reflector;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CP25Reflector::CP25Reflector(const std::string& file) :
|
||||
m_conf(file),
|
||||
m_repeaters()
|
||||
{
|
||||
CUDPSocket::startup();
|
||||
}
|
||||
|
||||
CP25Reflector::~CP25Reflector()
|
||||
{
|
||||
CUDPSocket::shutdown();
|
||||
}
|
||||
|
||||
void CP25Reflector::run()
|
||||
{
|
||||
bool ret = m_conf.read();
|
||||
if (!ret) {
|
||||
::fprintf(stderr, "P25Reflector: 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, "P25Gateway: 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.getNetworkDebug());
|
||||
|
||||
ret = network.open();
|
||||
if (!ret) {
|
||||
::LogFinalise();
|
||||
return;
|
||||
}
|
||||
|
||||
CDMRLookup* lookup = new CDMRLookup(m_conf.getLookupName(), m_conf.getLookupTime());
|
||||
lookup->read();
|
||||
|
||||
CStopWatch stopWatch;
|
||||
stopWatch.start();
|
||||
|
||||
CTimer dumpTimer(1000U, 120U);
|
||||
dumpTimer.start();
|
||||
|
||||
LogMessage("Starting P25Reflector-%s", VERSION);
|
||||
|
||||
CP25Repeater* current = NULL;
|
||||
bool displayed = false;
|
||||
bool seen64 = false;
|
||||
bool seen65 = false;
|
||||
|
||||
CTimer watchdogTimer(1000U, 0U, 1500U);
|
||||
|
||||
unsigned char lcf = 0U;
|
||||
unsigned int srcId = 0U;
|
||||
unsigned int dstId = 0U;
|
||||
|
||||
for (;;) {
|
||||
unsigned char buffer[200U];
|
||||
sockaddr_storage addr;
|
||||
unsigned int addrLen;
|
||||
|
||||
unsigned int len = network.readData(buffer, 200U, addr, addrLen);
|
||||
if (len > 0U) {
|
||||
CP25Repeater* rpt = findRepeater(addr);
|
||||
|
||||
if (buffer[0U] == 0xF0U) {
|
||||
if (rpt == NULL) {
|
||||
rpt = new CP25Repeater;
|
||||
rpt->m_timer.start();
|
||||
::memcpy(&rpt->m_addr, &addr, sizeof(struct sockaddr_storage));
|
||||
rpt->m_addrLen = addrLen;
|
||||
rpt->m_callsign = std::string((char*)(buffer + 1U), 10U);
|
||||
m_repeaters.push_back(rpt);
|
||||
|
||||
char buff[80U];
|
||||
LogMessage("Adding %s (%s)", rpt->m_callsign.c_str(), CUDPSocket::display(addr, buff, 80U));
|
||||
} else {
|
||||
rpt->m_timer.start();
|
||||
}
|
||||
|
||||
// Return the poll
|
||||
network.writeData(buffer, len, addr, addrLen);
|
||||
} else if (buffer[0U] == 0xF1U && rpt != NULL) {
|
||||
char buff[80U];
|
||||
LogMessage("Removing %s (%s) unlinked", rpt->m_callsign.c_str(), CUDPSocket::display(addr, buff, 80U));
|
||||
|
||||
for (std::vector<CP25Repeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||
if (CUDPSocket::match((*it)->m_addr, rpt->m_addr)) {
|
||||
delete *it;
|
||||
m_repeaters.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (rpt != NULL) {
|
||||
rpt->m_timer.start();
|
||||
|
||||
if (current == NULL) {
|
||||
current = rpt;
|
||||
displayed = false;
|
||||
seen64 = false;
|
||||
seen65 = false;
|
||||
LogMessage("Transmission started from %s", current->m_callsign.c_str());
|
||||
}
|
||||
|
||||
if (current == rpt) {
|
||||
watchdogTimer.start();
|
||||
|
||||
if (buffer[0U] == 0x64U && !seen64) {
|
||||
lcf = buffer[1U];
|
||||
seen64 = true;
|
||||
}
|
||||
|
||||
if (buffer[0U] == 0x65U && !seen65) {
|
||||
dstId = (buffer[1U] << 16) & 0xFF0000U;
|
||||
dstId |= (buffer[2U] << 8) & 0x00FF00U;
|
||||
dstId |= (buffer[3U] << 0) & 0x0000FFU;
|
||||
seen65 = true;
|
||||
}
|
||||
|
||||
if (buffer[0U] == 0x66U && seen64 && seen65 && !displayed) {
|
||||
srcId = (buffer[1U] << 16) & 0xFF0000U;
|
||||
srcId |= (buffer[2U] << 8) & 0x00FF00U;
|
||||
srcId |= (buffer[3U] << 0) & 0x0000FFU;
|
||||
displayed = true;
|
||||
|
||||
std::string callsign = lookup->find(srcId);
|
||||
LogMessage("Transmission from %s at %s to %s%u", callsign.c_str(), current->m_callsign.c_str(), lcf == 0x00U ? "TG " : "", dstId);
|
||||
}
|
||||
|
||||
for (std::vector<CP25Repeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||
if (!CUDPSocket::match(addr, (*it)->m_addr))
|
||||
network.writeData(buffer, len, (*it)->m_addr, (*it)->m_addrLen);
|
||||
}
|
||||
|
||||
if (buffer[0U] == 0x80U) {
|
||||
LogMessage("Received end of transmission");
|
||||
watchdogTimer.stop();
|
||||
current = NULL;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LogMessage("Data received from an unknown source");
|
||||
CUtils::dump(2U, "Data", buffer, len);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int ms = stopWatch.elapsed();
|
||||
stopWatch.start();
|
||||
|
||||
// Remove any repeaters that haven't reported for a while
|
||||
for (std::vector<CP25Repeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it)
|
||||
(*it)->m_timer.clock(ms);
|
||||
|
||||
for (std::vector<CP25Repeater*>::iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||
if ((*it)->m_timer.hasExpired()) {
|
||||
char buff[80U];
|
||||
LogMessage("Removing %s (%s) disappeared", (*it)->m_callsign.c_str(),
|
||||
CUDPSocket::display((*it)->m_addr, buff, 80U));
|
||||
|
||||
delete *it;
|
||||
m_repeaters.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
watchdogTimer.clock(ms);
|
||||
if (watchdogTimer.isRunning() && watchdogTimer.hasExpired()) {
|
||||
LogMessage("Network watchdog has expired");
|
||||
watchdogTimer.stop();
|
||||
current = NULL;
|
||||
}
|
||||
|
||||
dumpTimer.clock(ms);
|
||||
if (dumpTimer.hasExpired()) {
|
||||
dumpRepeaters();
|
||||
dumpTimer.start();
|
||||
}
|
||||
|
||||
if (ms < 5U)
|
||||
CThread::sleep(5U);
|
||||
}
|
||||
|
||||
network.close();
|
||||
|
||||
lookup->stop();
|
||||
|
||||
::LogFinalise();
|
||||
}
|
||||
|
||||
CP25Repeater* CP25Reflector::findRepeater(const sockaddr_storage& addr) const
|
||||
{
|
||||
for (std::vector<CP25Repeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||
if (CUDPSocket::match(addr, (*it)->m_addr))
|
||||
return *it;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CP25Reflector::dumpRepeaters() const
|
||||
{
|
||||
if (m_repeaters.size() == 0U) {
|
||||
LogMessage("No repeaters linked");
|
||||
return;
|
||||
}
|
||||
|
||||
LogMessage("Currently linked repeaters:");
|
||||
|
||||
for (std::vector<CP25Repeater*>::const_iterator it = m_repeaters.begin(); it != m_repeaters.end(); ++it) {
|
||||
char buffer[80U];
|
||||
LogMessage(" %s: %s %u/%u", (*it)->m_callsign.c_str(),
|
||||
CUDPSocket::display((*it)->m_addr, buffer, 80U),
|
||||
(*it)->m_timer.getTimer(),
|
||||
(*it)->m_timer.getTimeout());
|
||||
}
|
||||
}
|
|
@ -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(P25Reflector_H)
|
||||
#define P25Reflector_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 CP25Repeater {
|
||||
public:
|
||||
CP25Repeater() :
|
||||
m_addr(),
|
||||
m_addrLen(0U),
|
||||
m_callsign(),
|
||||
m_timer(1000U, 120U)
|
||||
{
|
||||
}
|
||||
|
||||
sockaddr_storage m_addr;
|
||||
unsigned int m_addrLen;
|
||||
std::string m_callsign;
|
||||
CTimer m_timer;
|
||||
};
|
||||
|
||||
class CP25Reflector
|
||||
{
|
||||
public:
|
||||
CP25Reflector(const std::string& file);
|
||||
~CP25Reflector();
|
||||
|
||||
void run();
|
||||
|
||||
private:
|
||||
CConf m_conf;
|
||||
std::vector<CP25Repeater*> m_repeaters;
|
||||
|
||||
CP25Repeater* findRepeater(const sockaddr_storage& addr) const;
|
||||
void dumpRepeaters() const;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,18 +0,0 @@
|
|||
[General]
|
||||
Daemon=1
|
||||
|
||||
[Id Lookup]
|
||||
Name=DMRIds.dat
|
||||
Time=24
|
||||
|
||||
[Log]
|
||||
# Logging levels, 0=No logging
|
||||
DisplayLevel=1
|
||||
FileLevel=1
|
||||
FilePath=.
|
||||
FileRoot=P25Reflector
|
||||
FileRotate=1
|
||||
|
||||
[Network]
|
||||
Port=41000
|
||||
Debug=0
|
|
@ -1,76 +0,0 @@
|
|||
#!/bin/bash
|
||||
### BEGIN INIT INFO
|
||||
#
|
||||
# Provides: P25Reflector
|
||||
# Required-Start: $all
|
||||
# Required-Stop:
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Example startscript P25Reflector
|
||||
|
||||
#
|
||||
### END INIT INFO
|
||||
## Fill in name of program here.
|
||||
PROG="P25Reflector"
|
||||
PROG_PATH="/usr/local/bin/"
|
||||
PROG_ARGS="/etc/P25Reflector.ini"
|
||||
PIDFILE="/var/run/P25Reflector.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
|
|
@ -1,183 +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>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Conf.h" />
|
||||
<ClInclude Include="DMRLookup.h" />
|
||||
<ClInclude Include="Log.h" />
|
||||
<ClInclude Include="Mutex.h" />
|
||||
<ClInclude Include="Network.h" />
|
||||
<ClInclude Include="P25Reflector.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" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Conf.cpp" />
|
||||
<ClCompile Include="DMRLookup.cpp" />
|
||||
<ClCompile Include="Log.cpp" />
|
||||
<ClCompile Include="Mutex.cpp" />
|
||||
<ClCompile Include="Network.cpp" />
|
||||
<ClCompile Include="P25Reflector.cpp" />
|
||||
<ClCompile Include="StopWatch.cpp" />
|
||||
<ClCompile Include="Thread.cpp" />
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
<ClCompile Include="UDPSocket.cpp" />
|
||||
<ClCompile Include="Utils.cpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>15.0</VCProjectVersion>
|
||||
<ProjectGuid>{C68ABEB3-5CDD-4B26-8D66-77FE81EC6BB5}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>P25Reflector</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>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>HAVE_LOG_H;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>HAVE_LOG_H;_DEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>HAVE_LOG_H;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</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>
|
||||
<PrecompiledHeader>NotUsing</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>HAVE_LOG_H;NDEBUG;_CONSOLE;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -1,86 +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="Conf.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DMRLookup.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Log.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Mutex.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Network.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="P25Reflector.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="StopWatch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Thread.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="Version.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Conf.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DMRLookup.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Log.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Mutex.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Network.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="P25Reflector.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="StopWatch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Thread.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>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -1,57 +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 <WS2tcpip.h>
|
||||
#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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -1,391 +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 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 short 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 short 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 short 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 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 */
|
||||
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->sin_addr, 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->sin6_addr, 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 short 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;
|
||||
}
|
||||
|
||||
close(index);
|
||||
|
||||
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 %hu", 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 %hu", m_port[index]);
|
||||
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 (unsigned int i = 0; i < UDP_SOCKET_MAX; i++)
|
||||
close(i);
|
||||
}
|
||||
|
||||
void CUDPSocket::close(const unsigned int index)
|
||||
{
|
||||
if ((index < UDP_SOCKET_MAX) && (m_fd[index] >= 0)) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
::closesocket(m_fd[index]);
|
||||
#else
|
||||
::close(m_fd[index]);
|
||||
#endif
|
||||
m_fd[index] = -1;
|
||||
}
|
||||
}
|
|
@ -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 short port = 0U);
|
||||
CUDPSocket(unsigned short 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 short 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 short port, sockaddr_storage& address, unsigned int& address_length);
|
||||
static int lookup(const std::string& hostName, unsigned short 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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2015,2016,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
|
||||
* 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 = "20210912";
|
||||
|
||||
#endif
|
|
@ -10,4 +10,4 @@ The MMDVM .ini file should have the IP address and port number of the client in
|
|||
|
||||
They build on 32-bit and 64-bit Linux as well as on Windows using Visual Studio 2017 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.
|
||||
|
|
Loading…
Reference in New Issue